Remove unused components, change zod to v4 and cahnge a few character properties

This commit is contained in:
Clément Pons
2025-08-26 13:21:42 +02:00
parent 5387dc66c3
commit 80a94bee86
60 changed files with 170 additions and 2742 deletions

View File

@@ -127,6 +127,7 @@ function center(touches: TouchList): Position
function distance(touches: TouchList): number
{
const [A, B] = touches;
if(!A || !B) return 0;
return Math.hypot(B.clientX - A.clientX, B.clientY - A.clientY);
}
@@ -172,10 +173,9 @@ export class Node extends EventTarget
{ border: `border-light-40 dark:border-dark-40`, bg: `bg-light-40 dark:bg-dark-40` }
}
}
export class NodeEditable extends Node
{
private static input: HTMLInputElement = dom('input', { class: 'origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] appearance-none bg-transparent outline-4 mb-2 px-2 py-1 font-thin min-w-4', style: { 'max-width': '100%', 'font-size': 'calc(18px * var(--zoom-multiplier))' }, listeners: { click: e => e.stopImmediatePropagation() } });
{
edges: Set<EdgeEditable> = new Set();
private dirty: boolean = false;
@@ -310,7 +310,6 @@ export class Edge extends EventTarget
}
export class EdgeEditable extends Edge
{
private static input: HTMLInputElement = dom('input', { class: 'relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20 -translate-x-1/2 -translate-y-1/2', listeners: { click: e => e.stopImmediatePropagation() } });
private focusing: boolean = false;
private editing: boolean = false;
@@ -879,9 +878,9 @@ export class CanvasEditor extends Canvas
this.pattern.setAttribute("width", (this._zoom * CanvasEditor.SPACING).toFixed(3));
this.pattern.setAttribute("height", (this._zoom * CanvasEditor.SPACING).toFixed(3));
this.pattern.children[0].setAttribute('cx', (this._zoom).toFixed(3));
this.pattern.children[0].setAttribute('cy', (this._zoom).toFixed(3));
this.pattern.children[0].setAttribute('r', (this._zoom).toFixed(3));
this.pattern.children[0]!.setAttribute('cx', (this._zoom).toFixed(3));
this.pattern.children[0]!.setAttribute('cy', (this._zoom).toFixed(3));
this.pattern.children[0]!.setAttribute('r', (this._zoom).toFixed(3));
}
}
override mount()

View File

@@ -1417,7 +1417,7 @@
"fire"
],
"cost": 3,
"speed": "10 ",
"speed": 10,
"concentration": false,
"tags": [
"utilitary"
@@ -1474,7 +1474,7 @@
},
{
"id": "t0uorr9gpk3n2325s4bgozwcjlk4g7af",
"name": "No name",
"name": "Glisse gracieuse",
"rank": 1,
"type": "knowledge",
"elements": [
@@ -1538,7 +1538,7 @@
},
{
"id": "p2o6hrfw5fgf22wpm7ocsxh6inhul3b1",
"name": "No name",
"name": "Menace statique",
"rank": 1,
"type": "instinct",
"elements": [
@@ -1554,7 +1554,7 @@
},
{
"id": "31neb3hkr8o2pc6wq5juhkfywqpufi7c",
"name": "No name",
"name": "Vrombissement assourdissant",
"rank": 1,
"type": "instinct",
"elements": [
@@ -1570,7 +1570,7 @@
},
{
"id": "ci60uqd0xv6bvfpaugu5f1m9c0f4b2ta",
"name": "No name",
"name": "Pilier de force",
"rank": 1,
"type": "precision",
"elements": [
@@ -1586,7 +1586,7 @@
},
{
"id": "q8bn095qcyuqk10wru6oe0mdg6ilsqke",
"name": "No name",
"name": "Choc de roche",
"rank": 1,
"type": "precision",
"elements": [
@@ -1618,7 +1618,7 @@
},
{
"id": "1yg0jfxt9tomjk8nfv6refiranzfcmqp",
"name": "No name",
"name": "Peau de pierre",
"rank": 1,
"type": "instinct",
"elements": [
@@ -1641,7 +1641,7 @@
"earth"
],
"cost": null,
"speed": "10 ",
"speed": 10,
"concentration": false,
"tags": [
"utilitary"
@@ -1689,7 +1689,7 @@
"arcana"
],
"cost": 2,
"speed": "1 ",
"speed": 1,
"concentration": false,
"tags": [
"utilitary"
@@ -1705,7 +1705,7 @@
"arcana"
],
"cost": 3,
"speed": "1 ",
"speed": 1,
"concentration": true,
"tags": [
"utilitary"
@@ -1762,7 +1762,7 @@
},
{
"id": "ufggg6m2fbrkb8hsmqmn5p57eow5z4du",
"name": "No name",
"name": "Insaisissable",
"rank": 1,
"type": "precision",
"elements": [
@@ -1785,7 +1785,7 @@
"nature"
],
"cost": 2,
"speed": "1 ",
"speed": 1,
"concentration": false,
"tags": [
"utilitary"
@@ -1794,7 +1794,7 @@
},
{
"id": "ia1l0huseavhkm1uhkea50d4j5isz98a",
"name": "No name",
"name": "Echange d'énergie",
"rank": 1,
"type": "instinct",
"elements": [
@@ -1810,7 +1810,7 @@
},
{
"id": "67cka4v8izu8qdfo2mqulkq26fp99etg",
"name": "No name",
"name": "Corrosion",
"rank": 1,
"type": "precision",
"elements": [
@@ -1826,7 +1826,7 @@
},
{
"id": "6mkmnwb4m28kx4n44yy4st9qut218pwc",
"name": "No name",
"name": "Appel de la nature",
"rank": 1,
"type": "instinct",
"elements": [
@@ -1890,7 +1890,7 @@
},
{
"id": "79l392k10xs5871a26rd5omm7djswuoz",
"name": "No name",
"name": "Visions de terreur",
"rank": 1,
"type": "instinct",
"elements": [
@@ -1922,7 +1922,7 @@
},
{
"id": "ewyy5jeqa5zvffqpa2hxg9ehifg2nwj7",
"name": "No name",
"name": "Manteau de flamme",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -1970,7 +1970,7 @@
},
{
"id": "kxk0yq1qd0b4sl2yyfi9xje6vfkxh0aa",
"name": "No name",
"name": "Gel encombrant",
"rank": 2,
"type": "instinct",
"elements": [
@@ -2034,7 +2034,7 @@
},
{
"id": "54z5hr40pfmsbbeyksgj1ybvdzy2lrg1",
"name": "No name",
"name": "Choc auditif",
"rank": 2,
"type": "instinct",
"elements": [
@@ -2050,7 +2050,7 @@
},
{
"id": "awt4tmkif5valsga4bcbezhjhckm7mxq",
"name": "No name",
"name": "Aura statique",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -2066,7 +2066,7 @@
},
{
"id": "vubi6idvry4vim1oavd9xneakek6jnnq",
"name": "No name",
"name": "Lame de roc",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -2082,7 +2082,7 @@
},
{
"id": "unqrb8i8erotcaqt9g7e2jn6g0go9kfu",
"name": "No name",
"name": "Torgnole rocailleuse",
"rank": 2,
"type": "precision",
"elements": [
@@ -2098,7 +2098,7 @@
},
{
"id": "1o219d03xifhmcf7v5tb6z1n2dfv9cfh",
"name": "No name",
"name": "Faiblesse d'éther",
"rank": 2,
"type": "instinct",
"elements": [
@@ -2162,7 +2162,7 @@
},
{
"id": "ewkikv0f2p1332ic8m8tlf52f6k4mn3u",
"name": "No name",
"name": "Partage d'esprit",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -2178,7 +2178,7 @@
},
{
"id": "xockmmr8iu687kpjw09fua3835gwfzog",
"name": "No name",
"name": "Air chaotique",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -2194,7 +2194,7 @@
},
{
"id": "c3f71icemysqn30kcts3sup4rsq3nx7e",
"name": "No name",
"name": "Bénédiction des vents",
"rank": 2,
"type": "precision",
"elements": [
@@ -2210,7 +2210,7 @@
},
{
"id": "zno89j1hd5jkgafhhar3x5tt17we1rzl",
"name": "No name",
"name": "Pression descendante",
"rank": 2,
"type": "precision",
"elements": [
@@ -2226,7 +2226,7 @@
},
{
"id": "bov1z1ieb4s7gbzbgps21e1pvouohdwk",
"name": "No name",
"name": "Bourrasque opposante",
"rank": 2,
"type": "instinct",
"elements": [
@@ -2242,7 +2242,7 @@
},
{
"id": "p6kpqeqrrhw8iopl9b9jmuxuabtquvps",
"name": "No name",
"name": "Epuisement spontané",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -2258,7 +2258,7 @@
},
{
"id": "kwy42uq39xk85us5ozf0fm9t79041127",
"name": "No name",
"name": "Echange d'énergie supérieur",
"rank": 2,
"type": "instinct",
"elements": [
@@ -2274,7 +2274,7 @@
},
{
"id": "o5xy0qagub9x7hsityncleza1ysrglm2",
"name": "No name",
"name": "Vision dans le noir",
"rank": 2,
"type": "knowledge",
"elements": [
@@ -2402,7 +2402,7 @@
},
{
"id": "bm9ywuo2gdtnzrigr1hg7y4falkrgm10",
"name": "No name",
"name": "Permutation",
"rank": 3,
"type": "instinct",
"elements": [
@@ -2450,7 +2450,7 @@
},
{
"id": "fchuvggmgrh89dyx06kk3433a1wf4u3m",
"name": "No name",
"name": "Erection de matière",
"rank": 3,
"type": "knowledge",
"elements": [
@@ -2466,7 +2466,7 @@
},
{
"id": "kfz4nibuso2um6na7v5z2lc22ng1lgca",
"name": "No name",
"name": "Densité tranchante",
"rank": 3,
"type": "precision",
"elements": [
@@ -2562,7 +2562,7 @@
},
{
"id": "6z02eebtw1p7wlfc4jned3iwo16bb772",
"name": "No name",
"name": "Redirection",
"rank": 3,
"type": "instinct",
"elements": [
@@ -2614,10 +2614,7 @@
"name": "Akkatom",
"description": "",
"stat": "strength",
"alignment": {
"kindness": "good",
"loyalty": "neutral"
},
"alignment": "neutral_good",
"magic": true,
"difficulty": 9,
"physic": {
@@ -2638,10 +2635,7 @@
"name": "Anseilid",
"description": "",
"stat": "intelligence",
"alignment": {
"kindness": "neutral",
"loyalty": "chaotic"
},
"alignment": "chaotic_neutral",
"magic": true,
"difficulty": 13,
"physic": {
@@ -2662,10 +2656,7 @@
"name": "Arsinam",
"description": "",
"stat": "constitution",
"alignment": {
"kindness": "neutral",
"loyalty": "chaotic"
},
"alignment": "chaotic_neutral",
"magic": false,
"difficulty": 8,
"physic": {
@@ -2686,10 +2677,7 @@
"name": "Asnol",
"description": "",
"stat": "intelligence",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": true,
"difficulty": 9,
"physic": {
@@ -2710,10 +2698,7 @@
"name": "Beth'oit",
"description": "",
"stat": "charisma",
"alignment": {
"kindness": "good",
"loyalty": "loyal"
},
"alignment": "loyal_good",
"magic": true,
"difficulty": 9,
"physic": {
@@ -2734,10 +2719,7 @@
"name": "Brukaur",
"description": "",
"stat": "constitution",
"alignment": {
"kindness": "neutral",
"loyalty": "chaotic"
},
"alignment": "chaotic_neutral",
"magic": false,
"difficulty": 9,
"physic": {
@@ -2758,10 +2740,7 @@
"name": "Calderan",
"description": "",
"stat": "intelligence",
"alignment": {
"kindness": "neutral",
"loyalty": "loyal"
},
"alignment": "loyal_neutral",
"magic": true,
"difficulty": 9,
"physic": {
@@ -2782,10 +2761,7 @@
"name": "Dao Tua",
"description": "",
"stat": "charisma",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": false,
"difficulty": 9,
"physic": {
@@ -2806,10 +2782,7 @@
"name": "Digride",
"description": "",
"stat": "dexterity",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -2830,10 +2803,7 @@
"name": "Drinbuur",
"description": "",
"stat": "psyche",
"alignment": {
"kindness": "good",
"loyalty": "neutral"
},
"alignment": "neutral_good",
"magic": true,
"difficulty": 10,
"physic": {
@@ -2854,10 +2824,7 @@
"name": "Franeline",
"description": "",
"stat": "dexterity",
"alignment": {
"kindness": "neutral",
"loyalty": "neutral"
},
"alignment": "neutral_neutral",
"magic": true,
"difficulty": 8,
"physic": {
@@ -2878,10 +2845,7 @@
"name": "Goldreg",
"description": "",
"stat": "psyche",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "loyal_evil",
"magic": false,
"difficulty": 9,
"physic": {
@@ -2902,10 +2866,7 @@
"name": "Hashura",
"description": "",
"stat": "charisma",
"alignment": {
"kindness": "neutral",
"loyalty": "neutral"
},
"alignment": "neutral_neutral",
"magic": true,
"difficulty": 10,
"physic": {
@@ -2926,10 +2887,7 @@
"name": "Incabat",
"description": "",
"stat": "constitution",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": false,
"difficulty": 10,
"physic": {
@@ -2950,10 +2908,7 @@
"name": "Kaha Bii",
"description": "",
"stat": "curiosity",
"alignment": {
"kindness": "good",
"loyalty": "loyal"
},
"alignment": "loyal_good",
"magic": true,
"difficulty": 10,
"physic": {
@@ -2974,10 +2929,7 @@
"name": "Kronian",
"description": "",
"stat": "psyche",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -2998,10 +2950,7 @@
"name": "Kuelid",
"description": "",
"stat": "intelligence",
"alignment": {
"kindness": "neutral",
"loyalty": "loyal"
},
"alignment": "loyal_neutral",
"magic": true,
"difficulty": 9,
"physic": {
@@ -3022,10 +2971,7 @@
"name": "Lonidae",
"description": "",
"stat": "intelligence",
"alignment": {
"kindness": "evil",
"loyalty": "chaotic"
},
"alignment": "chaotic_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3046,10 +2992,7 @@
"name": "Miador",
"description": "",
"stat": "dexterity",
"alignment": {
"kindness": "neutral",
"loyalty": "loyal"
},
"alignment": "loyal_neutral",
"magic": true,
"difficulty": 8,
"physic": {
@@ -3070,10 +3013,7 @@
"name": "Mul'dekar",
"description": "",
"stat": "curiosity",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3094,10 +3034,7 @@
"name": "Nigiak",
"description": "",
"stat": "charisma",
"alignment": {
"kindness": "neutral",
"loyalty": "loyal"
},
"alignment": "loyal_neutral",
"magic": true,
"difficulty": 9,
"physic": {
@@ -3118,10 +3055,7 @@
"name": "Nyelis",
"description": "",
"stat": "curiosity",
"alignment": {
"kindness": "neutral",
"loyalty": "neutral"
},
"alignment": "neutral_neutral",
"magic": true,
"difficulty": 8,
"physic": {
@@ -3142,10 +3076,7 @@
"name": "Onimee",
"description": "",
"stat": "dexterity",
"alignment": {
"kindness": "neutral",
"loyalty": "chaotic"
},
"alignment": "chaotic_neutral",
"magic": false,
"difficulty": 7,
"physic": {
@@ -3166,10 +3097,7 @@
"name": "Othompa",
"description": "",
"stat": "psyche",
"alignment": {
"kindness": "evil",
"loyalty": "neutral"
},
"alignment": "neutral_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3190,10 +3118,7 @@
"name": "Promolide",
"description": "",
"stat": "constitution",
"alignment": {
"kindness": "evil",
"loyalty": "chaotic"
},
"alignment": "chaotic_evil",
"magic": true,
"difficulty": 11,
"physic": {
@@ -3214,10 +3139,7 @@
"name": "Qua'faltar",
"description": "",
"stat": "psyche",
"alignment": {
"kindness": "evil",
"loyalty": "chaotic"
},
"alignment": "chaotic_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3238,10 +3160,7 @@
"name": "Rudnar",
"description": "",
"stat": "dexterity",
"alignment": {
"kindness": "good",
"loyalty": "chaotic"
},
"alignment": "chaotic_good",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3262,10 +3181,7 @@
"name": "Shelfine",
"description": "",
"stat": "intelligence",
"alignment": {
"kindness": "good",
"loyalty": "chaotic"
},
"alignment": "chaotic_good",
"magic": true,
"difficulty": 8,
"physic": {
@@ -3286,10 +3202,7 @@
"name": "Shlahog",
"description": "",
"stat": "strength",
"alignment": {
"kindness": "evil",
"loyalty": "chaotic"
},
"alignment": "chaotic_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3310,10 +3223,7 @@
"name": "Thymeïr",
"description": "",
"stat": "strength",
"alignment": {
"kindness": "evil",
"loyalty": "chaotic"
},
"alignment": "chaotic_evil",
"magic": false,
"difficulty": 10,
"physic": {
@@ -3334,10 +3244,7 @@
"name": "Urdi'rik",
"description": "",
"stat": "constitution",
"alignment": {
"kindness": "evil",
"loyalty": "loyal"
},
"alignment": "loyal_evil",
"magic": true,
"difficulty": 10,
"physic": {
@@ -3358,10 +3265,7 @@
"name": "Vadeaxil",
"description": "",
"stat": "strength",
"alignment": {
"kindness": "neutral",
"loyalty": "neutral"
},
"alignment": "neutral_neutral",
"magic": true,
"difficulty": 8,
"physic": {
@@ -3382,10 +3286,7 @@
"name": "Vernil",
"description": "",
"stat": "curiosity",
"alignment": {
"kindness": "neutral",
"loyalty": "neutral"
},
"alignment": "neutral_neutral",
"magic": false,
"difficulty": 8,
"physic": {
@@ -3406,10 +3307,7 @@
"name": "Yinkovn",
"description": "",
"stat": "psyche",
"alignment": {
"kindness": "neutral",
"loyalty": "neutral"
},
"alignment": "neutral_neutral",
"magic": true,
"difficulty": 9,
"physic": {
@@ -3430,10 +3328,7 @@
"name": "Zaliax",
"description": "",
"stat": "strength",
"alignment": {
"kindness": "evil",
"loyalty": "loyal"
},
"alignment": "loyal_evil",
"magic": false,
"difficulty": 9,
"physic": {
@@ -3454,10 +3349,7 @@
"name": "Zeniom",
"description": "",
"stat": "charisma",
"alignment": {
"kindness": "neutral",
"loyalty": "chaotic"
},
"alignment": "chaotic_neutral",
"magic": true,
"difficulty": 10,
"physic": {

View File

@@ -180,11 +180,10 @@ export const CharacterValidation = z.object({
notes: z.string().nullable().optional(),
health: z.number().default(0),
mana: z.number().default(0),
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()),
abilities: z.record(z.enum(ABILITIES), z.number().optional()),
training: z.record(z.enum(MAIN_STATS), z.record(z.enum(TRAINING_LEVELS.map(String)), z.number())),
leveling: z.record(z.enum(LEVELS.map(String)), z.number()),
abilities: z.record(z.enum(ABILITIES), z.number()),
spells: z.string().array(),
modifiers: z.record(z.enum(MAIN_STATS), z.number().optional()),
choices: z.record(z.string(), z.array(z.number())),
owner: z.number(),
username: z.string().optional(),
@@ -429,7 +428,7 @@ export class CharacterBuilder extends CharacterCompiler
}
private render()
{
this._steps = [
/*this._steps = [
PeoplePicker,
LevelPicker,
TrainingPicker,
@@ -438,9 +437,9 @@ export class CharacterBuilder extends CharacterCompiler
];
this._stepsHeader = this._steps.map((e, i) =>
dom("div", { class: "group flex items-center", }, [
dom("div", { class: "px-2 py-1 border-b border-transparent hover:border-accent-blue disabled:text-light-50 dark:disabled:text-dark-50 disabled:hover:border-transparent group-data-[state=active]:text-accent-blue cursor-pointer", listeners: { click: () => this.display(i) } }, [text(e.name)]),
dom("div", { class: "px-2 py-1 border-b border-transparent hover:border-accent-blue disabled:text-light-50 dark:disabled:text-dark-50 disabled:hover:border-transparent group-data-[state=active]:text-accent-blue cursor-pointer", listeners: { click: () => this.display(i) } }, [text(e.header)]),
])
);
);*/
this._helperText = text("Choisissez un peuple afin de définir la progression de votre personnage au fil des niveaux.")
this._content = dom('div', { class: 'flex-1 outline-none max-w-full w-full overflow-y-auto', attributes: { id: 'characterEditorContainer' } });
this._container.appendChild(div('flex flex-1 flex-col justify-start items-center px-8 w-full h-full overflow-y-hidden', [
@@ -461,15 +460,15 @@ export class CharacterBuilder extends CharacterCompiler
if(step < 0 || step >= this._stepsHeader.length)
return;
if(step !== 0 && this._steps.slice(0, step).some(e => !e.validate(this)))
return;
//if(step !== 0 && this._steps.slice(0, step).some(e => !e.validate(this)))
// return;
this._stepsHeader.forEach(e => e.setAttribute('data-state', 'inactive'));
this._stepsHeader[step]!.setAttribute('data-state', 'active');
//this._stepsHeader.forEach(e => e.setAttribute('data-state', 'inactive'));
//this._stepsHeader[step]!.setAttribute('data-state', 'active');
this._content?.replaceChildren(...(new this._steps[step]!(this)).dom);
//this._content?.replaceChildren(...(new this._steps[step]!(this)).dom);
this._helperText.textContent = this._steps[step]!.description;
//this._helperText.textContent = this._steps[step]!.description;
}
async save(leave: boolean = true)
{
@@ -672,7 +671,7 @@ export class PickableFeature
abstract class BuilderTab {
protected _builder: CharacterBuilder;
protected _content!: Array<Node | string>;
static name: string;
static header: string;
static description: string;
constructor(builder: CharacterBuilder) { this._builder = builder; }
@@ -694,7 +693,7 @@ class PeoplePicker extends BuilderTab
private _activeOption?: HTMLDivElement;
static override name = 'Peuple';
static override header = 'Peuple';
static override description = 'Choisissez un peuple afin de définir la progression de votre personnage au fil des niveaux.';
constructor(builder: CharacterBuilder)
@@ -756,7 +755,7 @@ class LevelPicker extends BuilderTab
private _manaText: Text;
private _options: HTMLDivElement[][];
static override name = 'Niveaux';
static override header = 'Niveaux';
static override description = 'Déterminez la progression de votre personnage en choisissant une option par niveau disponible.';
constructor(builder: CharacterBuilder)
@@ -836,7 +835,7 @@ class TrainingPicker extends BuilderTab
private _statIndicator: HTMLSpanElement;
private _statContainer: HTMLDivElement;
static override name = 'Entrainement';
static override header = 'Entrainement';
static override description = 'Spécialisez votre personnage en attribuant vos points d\'entrainement parmi les 7 branches disponibles.\nChaque paliers de 3 points augmentent votre modifieur.';
constructor(builder: CharacterBuilder)
@@ -914,7 +913,7 @@ class AbilityPicker extends BuilderTab
private _tooltips: Text[] = [];
private _maxs: HTMLElement[] = [];
static override name = 'Compétences';
static override header = 'Compétences';
static override description = 'Diversifiez vos possibilités en affectant vos points dans les différentes compétences disponibles.';
constructor(builder: CharacterBuilder)
@@ -1025,7 +1024,7 @@ class AspectPicker extends BuilderTab
private _options: HTMLDivElement[];
static override name = 'Aspect';
static override header = 'Aspect';
static override description = 'Déterminez l\'Aspect qui vous corresponds et benéficiez de puissants bonus.';
constructor(builder: CharacterBuilder)

View File

@@ -1,9 +1,9 @@
import type { Ability, AspectConfig, CharacterConfig, Feature, FeatureEffect, FeatureItem, MainStat, Resistance, SpellConfig } from "~/types/character";
import type { Ability, AspectConfig, CharacterConfig, Feature, FeatureEffect, FeatureItem, MainStat, Resistance, SpellConfig, TrainingLevel } from "~/types/character";
import { div, dom, icon, text, type NodeChildren } from "#shared/dom.util";
import { MarkdownEditor } from "#shared/editor.util";
import { fakeA } from "#shared/proses";
import { button, combobox, foldable, input, multiselect, numberpicker, select, table, toggle, type Option } from "#shared/components.util";
import { fullblocker, tooltip } from "#shared/floating.util";
import { confirm, contextmenu, fullblocker, tooltip } from "#shared/floating.util";
import { ALIGNMENTS, alignmentTexts, elementTexts, MAIN_STATS, mainStatShortTexts, mainStatTexts, SPELL_ELEMENTS, SPELL_TYPES, spellTypeTexts } from "#shared/character.util";
import characterConfig from "#shared/character-config.json";
import { getID, ID_SIZE } from "#shared/general.util";
@@ -139,14 +139,21 @@ class TrainingEditor extends BuilderTab
this._builder.edit(config.features[option]!).then(e => {
element.replaceChildren(markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }));
});
}, contextmenu: (e) => {
e.preventDefault();
const context = contextmenu(e.clientX, e.clientY, [
dom('div', { class: 'px-2 py-1 border-bottom border-light-35 dark:border-dark-35 cursor-pointer hover:bg-light-40 dark:hover:bg-dark-40 text-light-100 dark:text-dark-100', listeners: { click: () => { context.close(); } } }, [ text('Nouveau avant') ]),
dom('div', { class: 'px-2 py-1 border-bottom border-light-35 dark:border-dark-35 cursor-pointer hover:bg-light-40 dark:hover:bg-dark-40 text-light-100 dark:text-dark-100', listeners: { click: () => { context.close(); } } }, [ text('Nouveau après') ]),
dom('div', { class: 'px-2 py-1 border-bottom border-light-35 dark:border-dark-35 cursor-pointer hover:bg-light-40 dark:hover:bg-dark-40 text-light-100 dark:text-dark-100', listeners: { click: () => { context.close(); confirm('Voulez-vous vraiment supprimer cet element ?').then(e => { if(e) { delete config.training[stat][level[0] as any as TrainingLevel]; /* redraw */ } }) } } }, [ text('Supprimer') ])
], { placement: "right-start", priority: false });
}}}, [ markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }) ]);
return element;
})),
])
}
this._options = MAIN_STATS.reduce((p, v) => { p[v] = statRenderBlock(v); return p; }, {} as Record<MainStat, HTMLDivElement[][]>);
this._statIndicator = dom('span', { class: 'rounded-full w-3 h-3 bg-accent-blue absolute transition-[left] after:content-[attr(data-text)] after:absolute after:-translate-x-1/2 after:top-4 after:p-px after:bg-light-0 dark:after:bg-dark-0 after:text-center' });
this._statContainer = div('relative select-none transition-[left] flex flex-1 flex-row max-w-full', Object.values(this._options).map(e => div('flex flex-shrink-0 flex-col gap-4 relative w-full overflow-y-auto px-8', e.flatMap(_e => [..._e]))));
this._content = [ div("flex flex-1 gap-12 px-2 py-4 justify-center items-center sticky top-0 bg-light-0 dark:bg-dark-0 w-full z-10 min-h-20", [
@@ -197,9 +204,9 @@ class AspectEditor extends BuilderTab
alignment: select(ALIGNMENTS.map(f => ({ text: alignmentTexts[f], value: f })), { change: (value) => aspect.alignment = value, defaultValue: aspect.alignment, class: { container: '!m-0 w-full' } }),
magic: toggle({ defaultValue: aspect.magic, change: (value) => aspect.magic = value, class: { container: '' } }),
difficulty: numberpicker({ min: 6, max: 13, input: (value) => aspect.difficulty = value, defaultValue: aspect.difficulty, class: '!m-0 w-full' }),
physic: div('flex flex-row justify-center gap-2', [ numberpicker({ defaultValue: aspect.physic.min, input: (value) => aspect.physic.min = value }), numberpicker({ defaultValue: aspect.physic.max, input: (value) => aspect.physic.max = value }) ]),
mental: div('flex flex-row justify-center gap-2', [ numberpicker({ defaultValue: aspect.mental.min, input: (value) => aspect.mental.min = value }), numberpicker({ defaultValue: aspect.mental.max, input: (value) => aspect.mental.max = value }) ]),
personality: div('flex flex-row justify-center gap-2', [ numberpicker({ defaultValue: aspect.personality.min, input: (value) => aspect.personality.min = value }), numberpicker({ defaultValue: aspect.personality.max, input: (value) => aspect.personality.max = value }) ]),
physic: div('flex flex-row justify-center', [ numberpicker({ defaultValue: aspect.physic.min, input: (value) => aspect.physic.min = value, class: '!m-0' }), numberpicker({ defaultValue: aspect.physic.max, input: (value) => aspect.physic.max = value, class: '!m-0' }) ]),
mental: div('flex flex-row justify-center', [ numberpicker({ defaultValue: aspect.mental.min, input: (value) => aspect.mental.min = value, class: '!m-0' }), numberpicker({ defaultValue: aspect.mental.max, input: (value) => aspect.mental.max = value, class: '!m-0' }) ]),
personality: div('flex flex-row justify-center', [ numberpicker({ defaultValue: aspect.personality.min, input: (value) => aspect.personality.min = value, class: '!m-0' }), numberpicker({ defaultValue: aspect.personality.max, input: (value) => aspect.personality.max = value, class: '!m-0' }) ]),
action: div('flex flex-row justify-center gap-2', [ button(icon('radix-icons:file-text'), () => {}, 'p-1'), button(icon('radix-icons:trash'), () => remove(aspect), 'p-1') ])
};
}

View File

@@ -4,7 +4,7 @@ import render from "#shared/markdown.util";
import { popper } from "#shared/floating.util";
import { Canvas } from "#shared/canvas.util";
import { Content, iconByType, type LocalContent } from "#shared/content.util";
import { unifySlug } from "#shared/general.util";
import { parsePath, unifySlug } from "#shared/general.util";
import { loading } from "./components.util";
@@ -84,6 +84,7 @@ export const fakeA: Prose = {
])
]);
if(!!overview)
{
const magicKeys = useMagicKeys();