You've already forked obsidian-visualiser
Add character selection using campaign visibility and player characters in campaign
This commit is contained in:
@@ -5,6 +5,7 @@ import { div, dom, icon, span, text } from "#shared/dom.util";
|
||||
import { button, loading } from "#shared/components.util";
|
||||
import { CharacterCompiler } from "#shared/character.util";
|
||||
import { tooltip } from "./floating.util";
|
||||
import type { Character } from "~/types/character";
|
||||
|
||||
export const CampaignValidation = z.object({
|
||||
id: z.number(),
|
||||
@@ -27,13 +28,33 @@ async function copyLink()
|
||||
|
||||
*/
|
||||
|
||||
class CharacterPrinter
|
||||
{
|
||||
private compiler?: CharacterCompiler;
|
||||
container: HTMLElement = div('flex flex-col gap-2');
|
||||
constructor(character: number, name: string)
|
||||
{
|
||||
this.container.replaceChildren(div('flex flex-row gap-1', [span(undefined, 'joue'), span('font-bold', name)]), loading('small'));
|
||||
useRequestFetch()(`/api/character/${character}`).then((character) => {
|
||||
if(character)
|
||||
{
|
||||
this.compiler = new CharacterCompiler(character);
|
||||
this.container.replaceChildren(div('flex flex-row gap-1', [span(undefined, 'joue'), span('font-bold', name)]), );
|
||||
}
|
||||
else throw new Error();
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
this.container.replaceChildren(span('text-sm italic text-light-red dark:text-dark-red', 'Données indisponible'));
|
||||
})
|
||||
}
|
||||
}
|
||||
type PlayerState = {
|
||||
status: boolean;
|
||||
statusDOM: HTMLElement;
|
||||
statusTooltip: Text;
|
||||
user: User;
|
||||
user: { id: number, username: string };
|
||||
};
|
||||
function defaultPlayerState(user: User): PlayerState
|
||||
function defaultPlayerState(user: { id: number, username: string }): PlayerState
|
||||
{
|
||||
const statusTooltip = text('Absent');
|
||||
return {
|
||||
@@ -49,16 +70,21 @@ export class CampaignSheet
|
||||
campaign?: Campaign;
|
||||
container: HTMLElement = div('flex flex-1 h-full w-full items-start justify-center');
|
||||
dm!: PlayerState;
|
||||
players!: Array<PlayerState & { characters: CharacterPrinter[] }>
|
||||
constructor(id: string, user: ComputedRef<User | null>)
|
||||
{
|
||||
this.user = user;
|
||||
const load = div("flex justify-center items-center w-full h-full", [ loading('large') ]);
|
||||
this.container.replaceChildren(load);
|
||||
useRequestFetch()(`/api/campaign/${id}`).then(campaign => {
|
||||
useRequestFetch()(`/api/campaign/${id}`).then((campaign) => {
|
||||
if(campaign)
|
||||
{
|
||||
this.campaign = campaign;
|
||||
this.dm = defaultPlayerState(campaign.owner);
|
||||
this.players = campaign.members.map(e => ({
|
||||
...defaultPlayerState(e.member),
|
||||
characters: campaign.characters.filter(_e => _e.character?.owner === e.member.id).map(_e => new CharacterPrinter(_e.character!.id, _e.character!.name)),
|
||||
}));
|
||||
document.title = `d[any] - Campagne ${campaign.name}`;
|
||||
this.render();
|
||||
|
||||
@@ -77,14 +103,19 @@ export class CampaignSheet
|
||||
]));
|
||||
});
|
||||
}
|
||||
render()
|
||||
private render()
|
||||
{
|
||||
const campaign = this.campaign;
|
||||
|
||||
if(!campaign)
|
||||
return;
|
||||
|
||||
this.container.replaceChildren(div('flex flex-col w-full h-full items-center gap-4', [
|
||||
div('flex flex-row gap-8 items-center', [
|
||||
div('text-2xl font-semibold', [text(this.campaign.name)]),
|
||||
div('text-2xl font-semibold', [text(campaign.name)]),
|
||||
div('border border-light-35 dark:border-dark-35 p-1 flex flex-row items-center gap-2', [
|
||||
dom('pre', { class: 'ps-1 w-[400px] truncate' }, [ text(`https://d-any.com/campaign/join/${ encodeURIComponent(this.campaign.link) }`) ]),
|
||||
button(icon('radix-icons:clipboard', { width: 16, height: 16 })),
|
||||
dom('pre', { class: 'ps-1 w-[400px] truncate' }, [ text(`https://d-any.com/campaign/join/${ encodeURIComponent(campaign.link) }`) ]),
|
||||
button(icon('radix-icons:clipboard', { width: 16, height: 16 }), () => {}, 'p-1'),
|
||||
])
|
||||
]),
|
||||
div('flex flex-row gap-4 flex-1', [
|
||||
@@ -93,73 +124,29 @@ export class CampaignSheet
|
||||
div('flex flex-col divide-y divide-light-25 dark:divide-dark-25', [
|
||||
div('flex flex-col py-1 my-1', [
|
||||
div('flex flex-row items-center justify-between', [
|
||||
span(undefined, this.campaign.owner.username),
|
||||
span(undefined, this.dm.user.username),
|
||||
this.dm.statusDOM,
|
||||
])
|
||||
])
|
||||
]),
|
||||
div('flex flex-row items-center gap-4', [ span('text-lg font-bold tracking-tight', 'Joueurs'), span('border-b border-dashed border-light-35 dark:border-dark-35 flex-1') ]),
|
||||
div('flex flex-col divide-y divide-light-25 dark:divide-dark-25',
|
||||
this.campaign.members.length > 0 ? this.campaign.members.map((player: any) => div('flex flex-col py-1 my-1', [
|
||||
this.players.length > 0 ? this.players.map((player) => div('flex flex-col py-1 my-1', [
|
||||
div('flex flex-row items-center justify-between', [
|
||||
span(undefined, player.member.username),
|
||||
undefined,
|
||||
span(undefined, player.user.username),
|
||||
player.statusDOM,
|
||||
]),
|
||||
player.characters.length > 0 ? div('flex flex-col',
|
||||
player.characters.map((character: any) => div('flex flex-row items-center justify-between', [
|
||||
span(undefined, 'joue'), span('text-bold', character.name)
|
||||
player.characters && player.characters.length > 0 ? div('flex flex-col',
|
||||
player.characters.map((character) => div('flex flex-row items-center justify-between', [
|
||||
character.container
|
||||
]))
|
||||
) : span('text-sm italic text-light-70 dark:text-dark-70', 'Pas de personnages'),
|
||||
])) : span('text-sm italic py-2 text-center', 'Invitez des joueurs via le lien'),
|
||||
])) : [span('text-sm italic py-2 text-center', 'Invitez des joueurs via le lien')],
|
||||
)
|
||||
]),
|
||||
div('border-l border-light-35 dark:border-dark-35'),
|
||||
div('flex flex-col divide-y divide-light-25 dark:divide-dark-25 w-[800px]')
|
||||
])
|
||||
]));
|
||||
/*
|
||||
<div class="flex flex-col w-full h-full items-center gap-4" v-else-if="campaign && status === 'success'">
|
||||
<div class="flex flex-row gap-4 flex-1">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row items-center gap-4"><span class="text-lg font-bold tracking-tight flex-1">Maitre de jeu</span><span class="border-b border-dashed border-light-35 dark:border-dark-35 flex-1"></span></div>
|
||||
<div class="flex flex-col divide-y divide-light-25 dark:divide-dark-25 w-64">
|
||||
<div class="flex flex-col py-1 my-1">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<span>{{ campaign.owner.username }}</span>
|
||||
<Tooltip message="Absent" side="right" :delay="0"><span class="rounded-full w-3 h-3 block border-light-50 dark:border-dark-50 border-2 border-dashed"></span></Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-4"><span class="text-lg font-bold tracking-tight">Joueurs</span><span class="border-b border-dashed border-light-35 dark:border-dark-35 w-full"></span></div>
|
||||
<div class="flex flex-col divide-y divide-light-25 dark:divide-dark-25 w-64">
|
||||
<template v-if="campaign.members.length > 0">
|
||||
<div v-for="player of campaign.members" class="flex flex-col py-1 my-1">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<span>{{ player.member?.username }}</span>
|
||||
<Tooltip message="Absent" side="right" :delay="0"><span class="rounded-full w-3 h-3 block border-light-50 dark:border-dark-50 border-2 border-dashed"></span></Tooltip>
|
||||
</div>
|
||||
<template v-if="player.characters.length > 0">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row items-center justify-between" v-for="character of player.characters">
|
||||
<span>joue {{ character.character.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-sm italic text-light-70 dark:text-dark-70">Sans personnage</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-sm italic py-2 text-center">Invitez des joueurs via le lien d'invitation</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-l border-light-35 dark:border-dark-35"></div>
|
||||
<div class="flex flex-col divide-y divide-light-25 dark:divide-dark-25 w-[800px]">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1359,7 +1359,7 @@ export class CharacterSheet
|
||||
readonly: dom("span", {
|
||||
class: "font-bold px-2 border-transparent border cursor-pointer hover:border-light-35 dark:hover:border-dark-35",
|
||||
text: `${character.health - character.variables.health}`,
|
||||
listeners: { click: () => health.readonly.replaceWith(health.edit) },
|
||||
listeners: { click: () => { health.readonly.replaceWith(health.edit); health.edit.select(); health.edit.focus(); } },
|
||||
}),
|
||||
edit: input('text', { defaultValue: (character.health - character.variables.health).toString(), input: (v) => {
|
||||
return v.startsWith('-') || v.startsWith('+') ? v.length === 1 || !isNaN(parseInt(v.substring(1), 10)) : v.length === 0 || !isNaN(parseInt(v, 10));
|
||||
@@ -1370,7 +1370,7 @@ export class CharacterSheet
|
||||
readonly: dom("span", {
|
||||
class: "font-bold px-2 border-transparent border cursor-pointer hover:border-light-35 dark:hover:border-dark-35",
|
||||
text: `${character.mana - character.variables.mana}`,
|
||||
listeners: { click: () => mana.readonly.replaceWith(mana.edit) },
|
||||
listeners: { click: () => { mana.readonly.replaceWith(mana.edit); mana.edit.select(); mana.edit.focus(); } },
|
||||
}),
|
||||
edit: input('text', { defaultValue: (character.mana - character.variables.mana).toString(), input: (v) => {
|
||||
return v.startsWith('-') || v.startsWith('+') ? v.length === 1 || !isNaN(parseInt(v.substring(1), 10)) : v.length === 0 || !isNaN(parseInt(v, 10));
|
||||
|
||||
Reference in New Issue
Block a user