Note tab in character sheet

This commit is contained in:
Clément Pons 2025-10-15 17:01:23 +02:00
parent 72843f2425
commit df9ae95890
5 changed files with 71 additions and 5 deletions

BIN
db.sqlite

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,45 @@
import { eq } from 'drizzle-orm';
import useDatabase from '~/composables/useDatabase';
import { characterTable } from '~/db/schema';
import { CharacterNotesValidation } from '#shared/character.util';
export default defineEventHandler(async (e) => {
const id = getRouterParam(e, "id");
if(!id)
{
setResponseStatus(e, 400);
return;
}
const body = await readValidatedBody(e, CharacterNotesValidation.safeParse);
if(!body.success)
{
console.error(body.error);
setResponseStatus(e, 400);
throw body.error;
}
const db = useDatabase();
const old = db.select({ id: characterTable.id, owner: characterTable.owner }).from(characterTable).where(eq(characterTable.id, parseInt(id, 10))).get();
if(!old)
{
setResponseStatus(e, 404);
return;
}
const session = await getUserSession(e);
if(!session.user || old.owner !== session.user.id || session.user.state !== 1)
{
setResponseStatus(e, 401);
return;
}
db.update(characterTable).set({
public_notes: body.data.public,
private_notes: body.data.private,
}).where(eq(characterTable.id, parseInt(id, 10))).run();
setResponseStatus(e, 200);
return;
});

View File

@ -237,6 +237,10 @@ export const weaponTypeTexts: Record<WeaponType, string> = {
"projectile": "Arme à projectile", "projectile": "Arme à projectile",
}; };
export const CharacterNotesValidation = z.object({
public: z.string().optional(),
private: z.string().optional(),
});
export const CharacterVariablesValidation = z.object({ export const CharacterVariablesValidation = z.object({
health: z.number(), health: z.number(),
mana: z.number(), mana: z.number(),
@ -259,10 +263,7 @@ export const CharacterValidation = z.object({
people: z.string().nullable(), people: z.string().nullable(),
level: z.number().min(1).max(20), level: z.number().min(1).max(20),
aspect: z.number().nullable().optional(), aspect: z.number().nullable().optional(),
notes: z.object({ notes: CharacterNotesValidation,
public: z.string().optional(),
private: z.string().optional(),
}),
training: z.record(z.enum(MAIN_STATS), z.record(z.enum(TRAINING_LEVELS.map(String)), z.number().optional())), training: z.record(z.enum(MAIN_STATS), z.record(z.enum(TRAINING_LEVELS.map(String)), z.number().optional())),
leveling: z.record(z.enum(LEVELS.map(String)), z.number().optional()), leveling: z.record(z.enum(LEVELS.map(String)), z.number().optional()),
abilities: z.record(z.enum(ABILITIES), z.number().optional()), abilities: z.record(z.enum(ABILITIES), z.number().optional()),
@ -371,6 +372,15 @@ export class CharacterCompiler
}) })
} }
} }
saveNotes()
{
useRequestFetch()(`/api/character/${this.character.id}/notes`, {
method: 'POST',
body: this._character.notes,
}).then(() => {}).catch(() => {
Toaster.add({ type: 'error', content: 'Impossible de mettre à jour les données', duration: 5000, timer: true });
});
}
protected add(feature?: string) protected add(feature?: string)
{ {
if(!feature) if(!feature)
@ -1261,6 +1271,14 @@ export class CharacterSheet
const character = this.character.compiled; const character = this.character.compiled;
const publicNotes = new MarkdownEditor();
const privateNotes = new MarkdownEditor();
publicNotes.onChange = (v) => this.character!.character.notes!.public = v;
privateNotes.onChange = (v) => this.character!.character.notes!.private = v;
publicNotes.content = this.character!.character.notes!.public!;
privateNotes.content = this.character!.character.notes!.private!;
this.tabs = tabgroup([ this.tabs = tabgroup([
{ id: 'actions', title: [ text('Actions') ], content: () => this.actionsTab(character) }, { id: 'actions', title: [ text('Actions') ], content: () => this.actionsTab(character) },
@ -1273,7 +1291,10 @@ export class CharacterSheet
] }, ] },
{ id: 'notes', title: [ text('Notes') ], content: () => [ { id: 'notes', title: [ text('Notes') ], content: () => [
div('flex flex-col gap-2', [
div('flex flex-col gap-2 border-b border-light-35 dark:border-dark-35 pb-4', [ div('flex flex-row w-full items-center justify-between', [ span('text-lg font-bold', 'Notes publics'), tooltip(button(icon('radix-icons:paper-plane', { width: 16, height: 16 }), () => this.character!.saveNotes(), 'p-1'), 'Enregistrer', 'right') ]), div('border border-light-35 dark:border-dark-35 p-1', [ publicNotes.dom ]) ]),
div('flex flex-col gap-2', [ span('text-lg font-bold', 'Notes privés'), div('border border-light-35 dark:border-dark-35 p-1', [ privateNotes.dom ]) ]),
])
] }, ] },
], { focused: 'abilities', class: { container: 'flex-1 gap-4 px-4 w-[960px]' } }); ], { focused: 'abilities', class: { container: 'flex-1 gap-4 px-4 w-[960px]' } });
this.container.replaceChildren(div('flex flex-col justify-center gap-1', [ this.container.replaceChildren(div('flex flex-col justify-center gap-1', [