You've already forked obsidian-visualiser
Work in progress: CharacterSheet implementation and FeatureChoice rework
This commit is contained in:
@@ -2,25 +2,16 @@
|
||||
import characterConfig from '#shared/character-config.json';
|
||||
import { Icon } from '@iconify/vue/dist/iconify.js';
|
||||
import PreviewA from '~/components/prose/PreviewA.vue';
|
||||
import { clamp } from '#shared/general.util';
|
||||
import { clamp, unifySlug } from '#shared/general.util';
|
||||
import type { CompiledCharacter, SpellConfig } from '~/types/character';
|
||||
import type { CharacterConfig } from '~/types/character';
|
||||
import { abilityTexts, CharacterCompiler, defaultCharacter, elementTexts, spellTypeTexts } from '#shared/character.util';
|
||||
import { abilityTexts, CharacterCompiler, CharacterSheet, defaultCharacter, elementTexts, spellTypeTexts } from '#shared/character.util';
|
||||
import { getText } from '#shared/i18n';
|
||||
import { fakeA } from '#shared/proses';
|
||||
import { preview } from '#shared/proses';
|
||||
import { div, dom, icon, text } from '#shared/dom.util';
|
||||
import markdown from '#shared/markdown.util';
|
||||
import { button, foldable } from '#shared/components.util';
|
||||
import { fullblocker, tooltip } from '~/shared/floating.util';
|
||||
|
||||
const config = characterConfig as CharacterConfig;
|
||||
|
||||
const id = useRouter().currentRoute.value.params.id;
|
||||
const { user } = useUserSession();
|
||||
|
||||
const { data, status, error } = await useFetch(`/api/character/${id}`);
|
||||
const compiler = new CharacterCompiler(data.value ?? defaultCharacter);
|
||||
const character = ref<CompiledCharacter>(compiler.compiled);
|
||||
/*
|
||||
text-light-red dark:text-dark-red border-light-red dark:border-dark-red bg-light-red dark:bg-dark-red
|
||||
text-light-blue dark:text-dark-blue border-light-blue dark:border-dark-blue bg-light-blue dark:bg-dark-blue
|
||||
@@ -33,76 +24,26 @@ text-light-yellow dark:text-dark-yellow border-light-yellow dark:border-dark-yel
|
||||
text-light-purple dark:text-dark-purple border-light-purple dark:border-dark-purple bg-light-purple dark:bg-dark-purple
|
||||
*/
|
||||
|
||||
function openSpellPanel() {
|
||||
const availableSpells = Object.values(config.spells).filter(spell => {
|
||||
if (spell.rank === 4) return false;
|
||||
if (character.value.spellranks[spell.type] < spell.rank) return false;
|
||||
return true;
|
||||
});
|
||||
const config = characterConfig as CharacterConfig;
|
||||
|
||||
const textAmount = text(character.value.variables.spells.length.toString()), textMax = text(character.value.spellslots.toString());
|
||||
const container = div("border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10 border-l absolute top-0 bottom-0 right-0 w-[10%] data-[state=active]:w-1/2 flex flex-col gap-4 text-light-100 dark:text-dark-100 p-8 transition-[width] transition-delay-[150ms]", [
|
||||
div("flex flex-row justify-between items-center mb-4", [
|
||||
dom("h2", { class: "text-xl font-bold", text: "Ajouter un sort" }),
|
||||
div('flex flex-row gap-4 items-center', [ dom('span', { class: 'italic text-light-70 dark:text-dark-70 text-sm' }, [ textAmount, text(' / '), textMax, text(' sorts maitrisés') ]), tooltip(button(icon("radix-icons:cross-1", { width: 20, height: 20 }), () => {
|
||||
setTimeout(blocker.close, 150);
|
||||
container.setAttribute('data-state', 'inactive');
|
||||
}, "p-1"), "Fermer", "left") ])
|
||||
]),
|
||||
div('flex flex-col divide-y *:py-2 -my-2 overflow-y-auto', availableSpells.map(spell => {
|
||||
let state = character.value.lists.spells?.includes(spell.id) ? 'given' : character.value.variables.spells.includes(spell.id) ? 'choosen' : 'empty';
|
||||
const toggleText = text(state === 'choosen' ? 'Supprimer' : state === 'given' ? 'Inné' : 'Ajouter'), toggleButton = button(toggleText, () => {
|
||||
if(state === 'choosen')
|
||||
{
|
||||
compiler.variable('spells', character.value.variables.spells.filter(e => e !== spell.id));
|
||||
state = 'empty';
|
||||
}
|
||||
else if(state === 'empty')
|
||||
{
|
||||
compiler.variable('spells', [...character.value.variables.spells, spell.id]);
|
||||
state = 'choosen';
|
||||
}
|
||||
character.value = compiler.compiled;
|
||||
toggleText.textContent = state === 'choosen' ? 'Supprimer' : state === 'given' ? 'Inné' : 'Ajouter';
|
||||
textAmount.textContent = character.value.variables.spells.length.toString();
|
||||
}, "px-2 py-1 text-sm font-normal");
|
||||
toggleButton.disabled = state === 'given';
|
||||
return foldable(() => [
|
||||
markdown(spell.effect),
|
||||
], [ div("flex flex-row justify-between gap-2", [
|
||||
dom("span", { class: "text-lg font-bold", text: spell.name }),
|
||||
div("flex flex-row items-center gap-6", [
|
||||
div("flex flex-row text-sm gap-2",
|
||||
spell.elements.map(el =>
|
||||
dom("span", {
|
||||
class: [`border !border-opacity-50 rounded-full !bg-opacity-20 px-2 py-px`, elementTexts[el].class],
|
||||
text: elementTexts[el].text
|
||||
})
|
||||
)
|
||||
),
|
||||
div("flex flex-row text-sm gap-1", [
|
||||
...(spell.rank !== 4 ? [
|
||||
dom("span", { text: `Rang ${spell.rank}` }),
|
||||
text("/"),
|
||||
dom("span", { text: spellTypeTexts[spell.type] }),
|
||||
text("/")
|
||||
] : []),
|
||||
dom("span", { text: `${spell.cost} mana` }),
|
||||
text("/"),
|
||||
dom("span", { text: typeof spell.speed === "string" ? spell.speed : `${spell.speed} minutes` })
|
||||
]),
|
||||
toggleButton,
|
||||
]),
|
||||
]) ], { open: false, class: { container: "px-2 flex flex-col border-light-35 dark:border-dark-35", content: 'py-2' } });
|
||||
}))
|
||||
]);
|
||||
const blocker = fullblocker([ container ], { closeWhenOutside: true });
|
||||
setTimeout(() => container.setAttribute('data-state', 'active'), 1);
|
||||
}
|
||||
const id = useRouter().currentRoute.value.params.id ? unifySlug(useRouter().currentRoute.value.params.id!) : undefined;
|
||||
const { user } = useUserSession();
|
||||
const container = useTemplateRef('container');
|
||||
|
||||
onMounted(() => {
|
||||
queueMicrotask(() => {
|
||||
if(container.value && id)
|
||||
{
|
||||
const character = new CharacterSheet(id, user);
|
||||
container.value.appendChild(character.container);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="status === 'pending'">
|
||||
<div ref="container"></div>
|
||||
<!-- <div v-if="status === 'pending'">
|
||||
<Head>
|
||||
<Title>d[any] - Chargement ...</Title>
|
||||
</Head>
|
||||
@@ -125,9 +66,9 @@ function openSpellPanel() {
|
||||
<span>{{ config.peoples[character.race]?.name ?? 'Peuple inconnu' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col lg:border-l border-light-30 dark:border-dark-30 py-4 ps-4">
|
||||
<span class="flex flex-row items-center gap-2">PV: {{ character.health - character.variables.health }}/{{ character.health }}</span>
|
||||
<span class="flex flex-row items-center gap-2">Mana: {{ character.mana - character.variables.mana }}/{{ character.mana }}</span>
|
||||
<div class="flex flex-row lg:border-l border-light-30 dark:border-dark-30 py-4 ps-4 gap-8">
|
||||
<span class="flex flex-row items-center gap-2 text-3xl font-light">PV: <span class="font-bold px-2 border-transparent border cursor-pointer hover:border-light-35 dark:hover:border-dark-35">{{ character.health - character.variables.health }}</span>/ {{ character.health }}</span>
|
||||
<span class="flex flex-row items-center gap-2 text-3xl font-light">Mana: <span class="font-bold px-2 border-transparent border cursor-pointer hover:border-light-35 dark:hover:border-dark-35">{{ character.mana - character.variables.mana }}</span>/ {{ character.mana }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="self-center">
|
||||
@@ -135,8 +76,8 @@ function openSpellPanel() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col justify-center gap-4 *:py-2">
|
||||
<div class="grid 2xl:grid-cols-10 grid-cols-1 gap-4 items-center border-b border-light-30 dark:border-dark-30 me-4 pe-4">
|
||||
<div class="flex relative justify-between ps-4 gap-2 2xl:col-span-6">
|
||||
<div class="flex flex-row gap-4 items-center border-b border-light-30 dark:border-dark-30 me-4 pe-4 divide-x divide-light-30 dark:divide-dark-30">
|
||||
<div class="flex relative justify-between ps-4 gap-2">
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.strength }}</span><span class="text-sm 2xl:text-base">Force</span></div>
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.dexterity }}</span><span class="text-sm 2xl:text-base">Dextérité</span></div>
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.constitution }}</span><span class="text-sm 2xl:text-base">Constitution</span></div>
|
||||
@@ -145,9 +86,11 @@ function openSpellPanel() {
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.charisma }}</span><span class="text-sm 2xl:text-base">Charisme</span></div>
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">+{{ character.modifier.psyche }}</span><span class="text-sm 2xl:text-base">Psyché</span></div>
|
||||
</div>
|
||||
<div class="flex flex-1 relative 2xl:border-l border-light-30 dark:border-dark-30 ps-4 2xl:col-span-4 flex-row items-center justify-between">
|
||||
<div class="flex flex-1 relative ps-4 flex-row items-center justify-between">
|
||||
<div class="flex flex-col px-2 items-center"><span class="text-2xl font-bold">+{{ character.initiative }}</span><span>Initiative</span></div>
|
||||
<div class="flex flex-col px-2 items-center"><span class="text-2xl font-bold">{{ character.speed === false ? "Aucun déplacement" : `${character.speed} cases` }}</span><span>Course</span></div>
|
||||
</div>
|
||||
<div class="flex flex-1 relative ps-4 flex-row items-center justify-between">
|
||||
<Icon icon="ph:shield-checkered" class="w-8 h-8" />
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">{{ clamp(character.defense.static + character.defense.passivedodge + character.defense.passiveparry, 0, character.defense.hardcap) }}</span><span class="text-sm 2xl:text-base">Passive</span></div>
|
||||
<div class="flex flex-col items-center"><span class="2xl:text-2xl text-xl font-bold">{{ clamp(character.defense.static + character.defense.passivedodge + character.defense.activeparry, 0, character.defense.hardcap) }}</span><span class="text-sm 2xl:text-base">Blocage</span></div>
|
||||
@@ -205,24 +148,24 @@ function openSpellPanel() {
|
||||
<div class="flex flex-col col-span-2">
|
||||
<span class="text-lg font-semibold">Actions</span>
|
||||
<span class="text-sm text-light-70 dark:text-dark-70">Attaquer - Saisir - Faire chuter - Déplacer - Courir - Pas de coté - Lancer un sort - S'interposer - Se transformer - Utiliser un objet - Anticiper une action - Improviser</span>
|
||||
<MarkdownRenderer :content="character.lists.action?.map(e => getText(e))?.join('\n')" :properties="{ tags: { a: fakeA } }" />
|
||||
<MarkdownRenderer :content="character.lists.action?.map(e => getText(e))?.join('\n')" :properties="{ tags: { a: preview } }" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-lg font-semibold">Réactions</span>
|
||||
<span class="text-sm text-light-70 dark:text-dark-70">Parade - Esquive - Saisir une opportunité - Prendre en tenaille - Intercepter - Désarmer</span>
|
||||
<MarkdownRenderer :content="character.lists.reaction?.map(e => getText(e))?.join('\n')" :properties="{ tags: { a: fakeA } }" />
|
||||
<MarkdownRenderer :content="character.lists.reaction?.map(e => getText(e))?.join('\n')" :properties="{ tags: { a: preview } }" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-lg font-semibold">Actions libre</span>
|
||||
<span class="text-sm text-light-70 dark:text-dark-70">Analyser une situation - Communiquer</span>
|
||||
<MarkdownRenderer :content="character.lists.freeaction?.map(e => getText(e))?.join('\n')" :properties="{ tags: { a: fakeA } }" />
|
||||
<MarkdownRenderer :content="character.lists.freeaction?.map(e => getText(e))?.join('\n')" :properties="{ tags: { a: preview } }" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-lg font-semibold">Aptitudes</span>
|
||||
<MarkdownRenderer :content="character.lists.passive?.map(e => getText(e))?.map(e => `> ${e}`).join('\n\n')" :properties="{ tags: { a: fakeA } }" />
|
||||
<MarkdownRenderer :content="character.lists.passive?.map(e => getText(e))?.map(e => `> ${e}`).join('\n\n')" :properties="{ tags: { a: preview } }" />
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
@@ -251,9 +194,7 @@ function openSpellPanel() {
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="inventory" v-if="character.capacity !== false" class="overflow-y-auto max-h-full">
|
||||
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
||||
<MarkdownRenderer :content="character.notes" />
|
||||
</div>
|
||||
|
||||
</TabsContent>
|
||||
<TabsContent value="notes" class="overflow-y-auto max-h-full">
|
||||
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
||||
@@ -269,5 +210,5 @@ function openSpellPanel() {
|
||||
<Title>d[any] - Erreur</Title>
|
||||
</Head>
|
||||
<div>Erreur de chargement</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</template>
|
||||
Reference in New Issue
Block a user