Homebrew manager completed !
This commit is contained in:
parent
80a94bee86
commit
da93fcd82d
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
|
|
@ -52,7 +52,7 @@ export const characterTable = table("character", {
|
|||
id: int().primaryKey({ autoIncrement: true }),
|
||||
name: text().notNull(),
|
||||
owner: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
||||
people: int().notNull(),
|
||||
people: text().notNull(),
|
||||
level: int().notNull().default(1),
|
||||
aspect: int(),
|
||||
notes: text(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
||||
CREATE TABLE `__new_character` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`owner` integer NOT NULL,
|
||||
`people` text NOT NULL,
|
||||
`level` integer DEFAULT 1 NOT NULL,
|
||||
`aspect` integer,
|
||||
`notes` text,
|
||||
`health` integer DEFAULT 0 NOT NULL,
|
||||
`mana` integer DEFAULT 0 NOT NULL,
|
||||
`visibility` text DEFAULT 'private' NOT NULL,
|
||||
`thumbnail` blob,
|
||||
FOREIGN KEY (`owner`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `__new_character`("id", "name", "owner", "people", "level", "aspect", "notes", "health", "mana", "visibility", "thumbnail") SELECT "id", "name", "owner", "people", "level", "aspect", "notes", "health", "mana", "visibility", "thumbnail" FROM `character`;--> statement-breakpoint
|
||||
DROP TABLE `character`;--> statement-breakpoint
|
||||
ALTER TABLE `__new_character` RENAME TO `character`;--> statement-breakpoint
|
||||
PRAGMA foreign_keys=ON;
|
||||
|
|
@ -0,0 +1,810 @@
|
|||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "6651137c-a198-4538-86be-7cb8b88ca998",
|
||||
"prevId": "8f89d284-71da-46ae-a282-538f8a901294",
|
||||
"tables": {
|
||||
"character_abilities": {
|
||||
"name": "character_abilities",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ability": {
|
||||
"name": "ability",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
},
|
||||
"max": {
|
||||
"name": "max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_abilities_character_character_id_fk": {
|
||||
"name": "character_abilities_character_character_id_fk",
|
||||
"tableFrom": "character_abilities",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_abilities_character_ability_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"ability"
|
||||
],
|
||||
"name": "character_abilities_character_ability_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_choices": {
|
||||
"name": "character_choices",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"choice": {
|
||||
"name": "choice",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_choices_character_character_id_fk": {
|
||||
"name": "character_choices_character_character_id_fk",
|
||||
"tableFrom": "character_choices",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_choices_character_id_choice_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"id",
|
||||
"choice"
|
||||
],
|
||||
"name": "character_choices_character_id_choice_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_leveling": {
|
||||
"name": "character_leveling",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"level": {
|
||||
"name": "level",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"choice": {
|
||||
"name": "choice",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_leveling_character_character_id_fk": {
|
||||
"name": "character_leveling_character_character_id_fk",
|
||||
"tableFrom": "character_leveling",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_leveling_character_level_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"level"
|
||||
],
|
||||
"name": "character_leveling_character_level_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_modifiers": {
|
||||
"name": "character_modifiers",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"modifier": {
|
||||
"name": "modifier",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_modifiers_character_character_id_fk": {
|
||||
"name": "character_modifiers_character_character_id_fk",
|
||||
"tableFrom": "character_modifiers",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_modifiers_character_modifier_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"modifier"
|
||||
],
|
||||
"name": "character_modifiers_character_modifier_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_spell": {
|
||||
"name": "character_spell",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_spell_character_character_id_fk": {
|
||||
"name": "character_spell_character_character_id_fk",
|
||||
"tableFrom": "character_spell",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_spell_character_value_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"value"
|
||||
],
|
||||
"name": "character_spell_character_value_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character": {
|
||||
"name": "character",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"owner": {
|
||||
"name": "owner",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"people": {
|
||||
"name": "people",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"level": {
|
||||
"name": "level",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 1
|
||||
},
|
||||
"aspect": {
|
||||
"name": "aspect",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"notes": {
|
||||
"name": "notes",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"health": {
|
||||
"name": "health",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
},
|
||||
"mana": {
|
||||
"name": "mana",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
},
|
||||
"visibility": {
|
||||
"name": "visibility",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'private'"
|
||||
},
|
||||
"thumbnail": {
|
||||
"name": "thumbnail",
|
||||
"type": "blob",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_owner_users_id_fk": {
|
||||
"name": "character_owner_users_id_fk",
|
||||
"tableFrom": "character",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"owner"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_training": {
|
||||
"name": "character_training",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"stat": {
|
||||
"name": "stat",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"level": {
|
||||
"name": "level",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"choice": {
|
||||
"name": "choice",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_training_character_character_id_fk": {
|
||||
"name": "character_training_character_character_id_fk",
|
||||
"tableFrom": "character_training",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_training_character_stat_level_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"stat",
|
||||
"level"
|
||||
],
|
||||
"name": "character_training_character_stat_level_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"email_validation": {
|
||||
"name": "email_validation",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"project_content": {
|
||||
"name": "project_content",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "blob",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"project_files": {
|
||||
"name": "project_files",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"path": {
|
||||
"name": "path",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"owner": {
|
||||
"name": "owner",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"navigable": {
|
||||
"name": "navigable",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": true
|
||||
},
|
||||
"private": {
|
||||
"name": "private",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"order": {
|
||||
"name": "order",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"project_files_path_unique": {
|
||||
"name": "project_files_path_unique",
|
||||
"columns": [
|
||||
"path"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"project_files_owner_users_id_fk": {
|
||||
"name": "project_files_owner_users_id_fk",
|
||||
"tableFrom": "project_files",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"owner"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"user_permissions": {
|
||||
"name": "user_permissions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"permission": {
|
||||
"name": "permission",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"user_permissions_id_users_id_fk": {
|
||||
"name": "user_permissions_id_users_id_fk",
|
||||
"tableFrom": "user_permissions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"user_permissions_id_permission_pk": {
|
||||
"columns": [
|
||||
"id",
|
||||
"permission"
|
||||
],
|
||||
"name": "user_permissions_id_permission_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"user_sessions": {
|
||||
"name": "user_sessions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"user_sessions_user_id_users_id_fk": {
|
||||
"name": "user_sessions_user_id_users_id_fk",
|
||||
"tableFrom": "user_sessions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"user_sessions_id_user_id_pk": {
|
||||
"columns": [
|
||||
"id",
|
||||
"user_id"
|
||||
],
|
||||
"name": "user_sessions_id_user_id_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users_data": {
|
||||
"name": "users_data",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"signin": {
|
||||
"name": "signin",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"lastTimestamp": {
|
||||
"name": "lastTimestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"users_data_id_users_id_fk": {
|
||||
"name": "users_data_id_users_id_fk",
|
||||
"tableFrom": "users_data",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"hash": {
|
||||
"name": "hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"state": {
|
||||
"name": "state",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"users_hash_unique": {
|
||||
"name": "users_hash_unique",
|
||||
"columns": [
|
||||
"hash"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -106,6 +106,13 @@
|
|||
"when": 1753175811770,
|
||||
"tag": "0014_careless_nick_fury",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 15,
|
||||
"version": "6",
|
||||
"when": 1756214160038,
|
||||
"tag": "0015_typical_blade",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -58,6 +58,7 @@ export default defineEventHandler(async (e) => {
|
|||
modifiers: true,
|
||||
spells: true,
|
||||
training: true,
|
||||
choices: true,
|
||||
user: {
|
||||
columns: { username: true }
|
||||
}
|
||||
|
|
@ -80,9 +81,10 @@ export default defineEventHandler(async (e) => {
|
|||
|
||||
training: character.training.reduce((p, v) => { if(!(v.stat in p)) p[v.stat] = []; p[v.stat].push([v.level as TrainingLevel, v.choice]); return p; }, {} as Record<MainStat, DoubleIndex<TrainingLevel>[]>),
|
||||
leveling: character.levels.map(e => [e.level as Level, e.choice] as DoubleIndex<Level>),
|
||||
abilities: group(character.abilities.map(e => ({ ...e, value: [e.value, e.max] as [number, number] })), "ability", "value"),
|
||||
abilities: group(character.abilities, "ability", "value"),
|
||||
spells: character.spells.map(e => e.value),
|
||||
modifiers: group(character.modifiers, "modifier", "value"),
|
||||
choices: character.choices.reduce((p, v) => { p[v.id] ??= []; p[v.id]?.push(v.choice); return p; }, {} as Record<string, number[]>),
|
||||
|
||||
owner: character.owner,
|
||||
username: character.user.username,
|
||||
|
|
|
|||
|
|
@ -1,149 +0,0 @@
|
|||
import useDatabase from '~/composables/useDatabase';
|
||||
import { type Character, type CharacterConfig, type CompiledCharacter, type DoubleIndex, type Level, type MainStat, type TrainingLevel, type TrainingOption } from '~/types/character';
|
||||
import characterData from '#shared/character-config.json';
|
||||
import { group } from '#shared/general.util';
|
||||
import { defaultCharacter, MAIN_STATS } from '#shared/character.util';
|
||||
|
||||
export default defineCachedEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
if(!id)
|
||||
{
|
||||
setResponseStatus(e, 400);
|
||||
return;
|
||||
}
|
||||
|
||||
const db = useDatabase();
|
||||
const character = db.query.characterTable.findFirst({
|
||||
with: {
|
||||
abilities: true,
|
||||
levels: true,
|
||||
modifiers: true,
|
||||
spells: true,
|
||||
training: true,
|
||||
user: {
|
||||
columns: { username: true }
|
||||
}
|
||||
},
|
||||
where: (character, { eq }) => eq(character.id, parseInt(id, 10)),
|
||||
}).sync();
|
||||
|
||||
if(character !== undefined)
|
||||
{
|
||||
return compileCharacter(Object.assign(defaultCharacter, {
|
||||
id: character.id,
|
||||
|
||||
name: character.name,
|
||||
people: character.people,
|
||||
level: character.level,
|
||||
aspect: character.aspect,
|
||||
notes: character.notes,
|
||||
health: character.health,
|
||||
mana: character.mana,
|
||||
|
||||
training: character.training.reduce((p, v) => { if(!(v.stat in p)) p[v.stat] = []; p[v.stat].push([v.level as TrainingLevel, v.choice]); return p; }, {} as Record<MainStat, DoubleIndex<TrainingLevel>[]>),
|
||||
leveling: character.levels.map(e => [e.level as Level, e.choice] as DoubleIndex<Level>),
|
||||
abilities: group(character.abilities.map(e => ({ ...e, value: [e.value, e.max] as [number, number] })), "ability", "value"),
|
||||
spells: character.spells.map(e => e.value),
|
||||
modifiers: group(character.modifiers, "modifier", "value"),
|
||||
|
||||
owner: character.owner,
|
||||
username: character.user.username,
|
||||
visibility: character.visibility,
|
||||
} as Character) as Character);
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
return;
|
||||
}, { name: "character", getKey: (e) => getRouterParam(e, "id") || 'error' });
|
||||
|
||||
function compileCharacter(character: Character & { username?: string }): CompiledCharacter
|
||||
{
|
||||
const config = characterData as CharacterConfig;
|
||||
const race = character.people !== undefined ? config.peoples[character.people] : undefined;
|
||||
const raceOptions = race ? character.leveling!.map(e => race.options[e[0]][e[1]]) : [];
|
||||
const features = Object.entries(config.training).map(e => [e[0], getFeaturesOf(e[0] as MainStat, character.training[e[0] as MainStat])]) as [MainStat, TrainingOption[]][];
|
||||
|
||||
const compiled: CompiledCharacter = {
|
||||
id: character.id,
|
||||
owner: character.owner,
|
||||
username: character.username,
|
||||
name: character.name,
|
||||
health: raceOptions.reduce((p, v) => p + (v.health ?? 0), 0),
|
||||
mana: raceOptions.reduce((p, v) => p + (v.mana ?? 0), 0),
|
||||
race: character.people!,
|
||||
modifier: features.map(e => [e[0], Math.floor((e[1].length - 1) / 3) + (character.modifiers[e[0]] ?? 0)] as [MainStat, number]).reduce((p, v) => { p[v[0]] = v[1]; return p }, {} as Record<MainStat, number>),
|
||||
level: character.level,
|
||||
values: {
|
||||
health: character.health,
|
||||
mana: character.mana
|
||||
},
|
||||
features: {
|
||||
action: [],
|
||||
reaction: [],
|
||||
freeaction: [],
|
||||
passive: [],
|
||||
},
|
||||
abilities: {
|
||||
athletics: 0,
|
||||
acrobatics: 0,
|
||||
intimidation: 0,
|
||||
sleightofhand: 0,
|
||||
stealth: 0,
|
||||
survival: 0,
|
||||
investigation: 0,
|
||||
history: 0,
|
||||
religion: 0,
|
||||
arcana: 0,
|
||||
understanding: 0,
|
||||
perception: 0,
|
||||
performance: 0,
|
||||
medecine: 0,
|
||||
persuasion: 0,
|
||||
animalhandling: 0,
|
||||
deception: 0
|
||||
},
|
||||
spellslots: 0,
|
||||
artslots: 0,
|
||||
spellranks: {
|
||||
instinct: 0,
|
||||
knowledge: 0,
|
||||
precision: 0,
|
||||
arts: 0,
|
||||
},
|
||||
spells: character.spells ?? [],
|
||||
speed: false,
|
||||
defense: {
|
||||
hardcap: Infinity,
|
||||
static: 6,
|
||||
activeparry: 0,
|
||||
activedodge: 0,
|
||||
passiveparry: 0,
|
||||
passivedodge: 0,
|
||||
},
|
||||
mastery: {
|
||||
strength: 0,
|
||||
dexterity: 0,
|
||||
shield: 0,
|
||||
armor: 0,
|
||||
multiattack: 1,
|
||||
magicpower: 0,
|
||||
magicspeed: 0,
|
||||
magicelement: 0,
|
||||
magicinstinct: 0,
|
||||
},
|
||||
resistance: {},//Object.fromEntries(MAIN_STATS.map(e => [e as MainStat, [0, 0]])) as Record<MainStat, [number, number]>,
|
||||
initiative: 0,
|
||||
aspect: "",
|
||||
notes: character.notes ?? "",
|
||||
};
|
||||
|
||||
//features.forEach(e => e[1].forEach(_e => _e.features?.forEach(f => applyFeature(compiled, f))));
|
||||
|
||||
return compiled;
|
||||
}
|
||||
|
||||
export function getFeaturesOf(stat: MainStat, progression: DoubleIndex<TrainingLevel>[]): TrainingOption[]
|
||||
{
|
||||
const config = characterData as CharacterConfig;
|
||||
return progression.map(e => config.training[stat][e[0]][e[1]]);
|
||||
}
|
||||
|
|
@ -745,8 +745,9 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"peoples": [
|
||||
{
|
||||
"peoples": {
|
||||
"e662m19q590kn4dowvssowi1qf8ia7sk": {
|
||||
"id": "e662m19q590kn4dowvssowi1qf8ia7sk",
|
||||
"name": "Humain",
|
||||
"description": "Les humains, originaire d'un tout autre monde, ont subit un cataclysme qui les a projeté dans les terres d'Erina. En tant que civilisation dépourvue de magie, ils sont plus specialisés, gagnant moins de statistiques mais pouvant plus tôt ou plus fréquemment obtenir certains bonus.",
|
||||
"options": {
|
||||
|
|
@ -833,8 +834,75 @@
|
|||
"9q8mf0u06oxxwqltyv58kbavs7qtoouw"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"3v3rwsn9bimpyd2fc95ml8wdrrmfsqb0": {
|
||||
"id": "3v3rwsn9bimpyd2fc95ml8wdrrmfsqb0",
|
||||
"name": "Quplothien",
|
||||
"description": "Quploth est la région du monde abritant le plus de marchands et charlatans. Dû à la sur-désertification de leurs terres, ils ont appris à vivre en troquant les richesses. Leurs cités, denses et prospères, sont peu nombreuses et suscitent un tourisme culturel croissant.",
|
||||
"options": {
|
||||
"1": [
|
||||
"bbuzw6awn2mkb05imdoecxfkc5zuj98i"
|
||||
],
|
||||
"2": [
|
||||
"ub2ws6q8xdbngeouip02umvw2oox9r68"
|
||||
],
|
||||
"3": [
|
||||
"5d7u2jvi4u0nnrzesderha3uo8kb3zjq"
|
||||
],
|
||||
"4": [
|
||||
"8w4jthjrn3l8u4trmj46z6t6ab5rbgk3"
|
||||
],
|
||||
"5": [
|
||||
"z9lux6nlhl8pjhcwst6bnhpn6cq6c77w"
|
||||
],
|
||||
"6": [
|
||||
"dx5khvrhwkhhn8fv4b8pecuh8i5wtwij"
|
||||
],
|
||||
"7": [
|
||||
"pfzopr4oyrsgxg0cbva16zzzly3kke9z"
|
||||
],
|
||||
"8": [
|
||||
"fk0wmg94tlq78khq8zot2o5u4nnxr2gb"
|
||||
],
|
||||
"9": [
|
||||
"u9vv3z280jgzab7pjwe9kexqjlpoxvax"
|
||||
],
|
||||
"10": [
|
||||
"fuxn9ndabr5yl0rrdtilldssmjxso24p"
|
||||
],
|
||||
"11": [
|
||||
"7kdxs6b6j9pqhgm3c8ydp8f9o074vp8q"
|
||||
],
|
||||
"12": [
|
||||
"dwvjqspm8l0gnks6y7u9vty0563u20kd"
|
||||
],
|
||||
"13": [
|
||||
"bmh55yfypfw8rezd16m2cuocrx0kkfl4"
|
||||
],
|
||||
"14": [
|
||||
"hatuas1yl3armteqwjwm1gjpsjp3v97x"
|
||||
],
|
||||
"15": [
|
||||
"0fg543b25uppvollu9oxtowyxjjw1x5a"
|
||||
],
|
||||
"16": [
|
||||
"l770gvirwzfbtfgfl29dxhvdh95f1m71"
|
||||
],
|
||||
"17": [
|
||||
"m1zkviiz3ow1g7rwpkyygmyggphvoz8b"
|
||||
],
|
||||
"18": [
|
||||
"uuc8vci5bk5kkx23a7ks1gu778fmu9w1"
|
||||
],
|
||||
"19": [
|
||||
"fd076hnyjagipaez166p9xp3wtlf5sgw"
|
||||
],
|
||||
"20": [
|
||||
"qcp28eysi3l3n438v41kowisdpq4ht61"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"training": {
|
||||
"strength": {
|
||||
"0": [
|
||||
|
|
@ -9452,6 +9520,106 @@
|
|||
}
|
||||
],
|
||||
"id": "9q8mf0u06oxxwqltyv58kbavs7qtoouw"
|
||||
},
|
||||
"bbuzw6awn2mkb05imdoecxfkc5zuj98i": {
|
||||
"id": "bbuzw6awn2mkb05imdoecxfkc5zuj98i",
|
||||
"description": "Bonjour",
|
||||
"effect": []
|
||||
},
|
||||
"ub2ws6q8xdbngeouip02umvw2oox9r68": {
|
||||
"id": "ub2ws6q8xdbngeouip02umvw2oox9r68",
|
||||
"description": "je",
|
||||
"effect": []
|
||||
},
|
||||
"5d7u2jvi4u0nnrzesderha3uo8kb3zjq": {
|
||||
"id": "5d7u2jvi4u0nnrzesderha3uo8kb3zjq",
|
||||
"description": "suis",
|
||||
"effect": []
|
||||
},
|
||||
"8w4jthjrn3l8u4trmj46z6t6ab5rbgk3": {
|
||||
"id": "8w4jthjrn3l8u4trmj46z6t6ab5rbgk3",
|
||||
"description": "Nicolas",
|
||||
"effect": []
|
||||
},
|
||||
"z9lux6nlhl8pjhcwst6bnhpn6cq6c77w": {
|
||||
"id": "z9lux6nlhl8pjhcwst6bnhpn6cq6c77w",
|
||||
"description": "Sarkozy",
|
||||
"effect": []
|
||||
},
|
||||
"dx5khvrhwkhhn8fv4b8pecuh8i5wtwij": {
|
||||
"id": "dx5khvrhwkhhn8fv4b8pecuh8i5wtwij",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"pfzopr4oyrsgxg0cbva16zzzly3kke9z": {
|
||||
"id": "pfzopr4oyrsgxg0cbva16zzzly3kke9z",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"fk0wmg94tlq78khq8zot2o5u4nnxr2gb": {
|
||||
"id": "fk0wmg94tlq78khq8zot2o5u4nnxr2gb",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"u9vv3z280jgzab7pjwe9kexqjlpoxvax": {
|
||||
"id": "u9vv3z280jgzab7pjwe9kexqjlpoxvax",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"fuxn9ndabr5yl0rrdtilldssmjxso24p": {
|
||||
"id": "fuxn9ndabr5yl0rrdtilldssmjxso24p",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"7kdxs6b6j9pqhgm3c8ydp8f9o074vp8q": {
|
||||
"id": "7kdxs6b6j9pqhgm3c8ydp8f9o074vp8q",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"dwvjqspm8l0gnks6y7u9vty0563u20kd": {
|
||||
"id": "dwvjqspm8l0gnks6y7u9vty0563u20kd",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"bmh55yfypfw8rezd16m2cuocrx0kkfl4": {
|
||||
"id": "bmh55yfypfw8rezd16m2cuocrx0kkfl4",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"hatuas1yl3armteqwjwm1gjpsjp3v97x": {
|
||||
"id": "hatuas1yl3armteqwjwm1gjpsjp3v97x",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"0fg543b25uppvollu9oxtowyxjjw1x5a": {
|
||||
"id": "0fg543b25uppvollu9oxtowyxjjw1x5a",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"l770gvirwzfbtfgfl29dxhvdh95f1m71": {
|
||||
"id": "l770gvirwzfbtfgfl29dxhvdh95f1m71",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"m1zkviiz3ow1g7rwpkyygmyggphvoz8b": {
|
||||
"id": "m1zkviiz3ow1g7rwpkyygmyggphvoz8b",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"uuc8vci5bk5kkx23a7ks1gu778fmu9w1": {
|
||||
"id": "uuc8vci5bk5kkx23a7ks1gu778fmu9w1",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"fd076hnyjagipaez166p9xp3wtlf5sgw": {
|
||||
"id": "fd076hnyjagipaez166p9xp3wtlf5sgw",
|
||||
"description": "",
|
||||
"effect": []
|
||||
},
|
||||
"qcp28eysi3l3n438v41kowisdpq4ht61": {
|
||||
"id": "qcp28eysi3l3n438v41kowisdpq4ht61",
|
||||
"description": "",
|
||||
"effect": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -428,7 +428,7 @@ export class CharacterBuilder extends CharacterCompiler
|
|||
}
|
||||
private render()
|
||||
{
|
||||
/*this._steps = [
|
||||
this._steps = [
|
||||
PeoplePicker,
|
||||
LevelPicker,
|
||||
TrainingPicker,
|
||||
|
|
@ -439,7 +439,7 @@ export class CharacterBuilder extends CharacterCompiler
|
|||
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.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', [
|
||||
|
|
@ -460,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)
|
||||
{
|
||||
|
|
@ -681,7 +681,7 @@ abstract class BuilderTab {
|
|||
};
|
||||
type BuilderTabConstructor = {
|
||||
new (builder: CharacterBuilder): BuilderTab;
|
||||
name: string;
|
||||
header: string;
|
||||
description: string;
|
||||
validate(builder: CharacterBuilder): boolean;
|
||||
}
|
||||
|
|
@ -691,8 +691,6 @@ class PeoplePicker extends BuilderTab
|
|||
private _visibilityInput: HTMLDivElement;
|
||||
private _options: HTMLDivElement[];
|
||||
|
||||
private _activeOption?: HTMLDivElement;
|
||||
|
||||
static override header = 'Peuple';
|
||||
static override description = 'Choisissez un peuple afin de définir la progression de votre personnage au fil des niveaux.';
|
||||
|
||||
|
|
@ -704,16 +702,15 @@ class PeoplePicker extends BuilderTab
|
|||
input: (value) => {
|
||||
this._builder.character.name = value ?? '';
|
||||
document.title = `d[any] - Edition de ${this._builder.character.name || 'nouveau personnage'}`;
|
||||
}
|
||||
}, defaultValue: this._builder.character.name
|
||||
});
|
||||
this._visibilityInput = toggle({ defaultValue: this._builder.character.visibility === "private", change: (value) => this._builder.character.visibility = value ? "private" : "public" });
|
||||
|
||||
this._options = config.peoples.map(
|
||||
this._options = Object.values(config.peoples).map(
|
||||
(people, i) => dom("div", { class: "flex flex-col flex-nowrap gap-2 p-2 border border-light-35 dark:border-dark-35 cursor-pointer hover:border-light-70 dark:hover:border-dark-70 w-[320px]", listeners: { click: () => {
|
||||
this._builder.character.people = i;
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._activeOption?.classList.toggle(e, false));
|
||||
this._activeOption = this._options[i]!;
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._activeOption?.classList.toggle(e, true));
|
||||
this._builder.character.people = people.id;
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._options.forEach(f => f?.classList.toggle(e, false)));
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._options[i]?.classList.toggle(e, true));
|
||||
}
|
||||
} }, [div("h-[320px]"), div("text-xl font-bold text-center", [text(people.name)]), div("w-full border-b border-light-50 dark:border-dark-50"), div("text-wrap word-break", [text(people.description)])]),
|
||||
);
|
||||
|
|
@ -734,13 +731,6 @@ class PeoplePicker extends BuilderTab
|
|||
{
|
||||
this._nameInput.value = this._builder.character.name;
|
||||
this._visibilityInput.setAttribute('data-state', this._builder.character.visibility === "private" ? "checked" : "unchecked");
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._activeOption?.classList.toggle(e, false));
|
||||
|
||||
if(this._builder.character.people !== undefined)
|
||||
{
|
||||
this._activeOption = this._options[this._builder.character.people]!;
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._activeOption?.classList.toggle(e, true));
|
||||
}
|
||||
}
|
||||
static override validate(builder: CharacterBuilder): boolean
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ export function select<T extends NonNullable<any>>(options: Array<{ text: string
|
|||
if(e === undefined)
|
||||
return;
|
||||
|
||||
return dom('div', { listeners: { click: () => {
|
||||
return dom('div', { listeners: { click: (_e) => {
|
||||
textValue.textContent = e.text;
|
||||
settings?.change && settings?.change(e.value);
|
||||
context && context.close && context.close();
|
||||
context && context.close && !_e.ctrlKey && context.close();
|
||||
}, mouseenter: (e) => focus(i) }, class: ['data-[focused]:bg-light-30 dark:data-[focused]:bg-dark-30 text-light-70 dark:text-dark-70 data-[focused]:text-light-100 dark:data-[focused]:text-dark-100 py-1 px-2 cursor-pointer', settings?.class?.option] }, [ text(e.text) ]);
|
||||
});
|
||||
const select = dom('div', { listeners: { click: () => {
|
||||
|
|
@ -116,12 +116,12 @@ export function multiselect<T extends NonNullable<any>>(options: Array<{ text: s
|
|||
if(e === undefined)
|
||||
return;
|
||||
|
||||
const element = dom('div', { listeners: { click: () => {
|
||||
const element = dom('div', { listeners: { click: (_e) => {
|
||||
selection = selection.includes(e.value) ? selection.filter(f => f !== e.value) : [...selection, e.value];
|
||||
textValue.textContent = selection.length > 0 ? ((options.find(f => f?.value === selection[0])?.text ?? '') + (selection.length > 1 ? ` +${selection.length - 1}` : '')) : '';
|
||||
element.toggleAttribute('data-selected', selection.includes(e.value));
|
||||
settings?.change && settings?.change(selection);
|
||||
context && context.close && context.close();
|
||||
context && context.close && !_e.ctrlKey && context.close();
|
||||
}, mouseenter: (e) => focus(i) }, class: ['group flex flex-row justify-between items-center data-[focused]:bg-light-30 dark:data-[focused]:bg-dark-30 text-light-70 dark:text-dark-70 data-[focused]:text-light-100 dark:data-[focused]:text-dark-100 py-1 px-2 cursor-pointer', settings?.class?.option], attributes: { 'data-selected': selection.includes(e.value) } }, [ text(e.text), icon('radix-icons:check', { class: 'hidden group-data-[selected]:block', noobserver: true }) ]);
|
||||
return element;
|
||||
});
|
||||
|
|
@ -240,11 +240,11 @@ export function combobox<T extends NonNullable<any>>(options: Option<T>[], setti
|
|||
}
|
||||
else
|
||||
{
|
||||
return { item: option, dom: dom('div', { listeners: { click: () => {
|
||||
return { item: option, dom: dom('div', { listeners: { click: (_e) => {
|
||||
select.value = option.text;
|
||||
settings?.change && settings?.change(option.value as T);
|
||||
selected = true;
|
||||
hide();
|
||||
!_e.ctrlKey && hide();
|
||||
}, mouseenter: () => focus(option.value) }, class: ['data-[focused]:bg-light-30 dark:data-[focused]:bg-dark-30 text-light-70 dark:text-dark-70 data-[focused]:text-light-100 dark:data-[focused]:text-dark-100 py-1 px-2 cursor-pointer', settings?.class?.option] }, [ option?.render ? option?.render() : text(option.text) ]) };
|
||||
}
|
||||
}
|
||||
|
|
@ -347,10 +347,10 @@ export function numberpicker(settings?: { defaultValue?: number, change?: (value
|
|||
switch(e.key)
|
||||
{
|
||||
case "ArrowUp":
|
||||
validateAndChange(storedValue + (e.shiftKey ? 10 : 1)) && settings?.input && settings.input(storedValue);
|
||||
validateAndChange(storedValue + (e.ctrlKey ? 10 : 1)) && settings?.input && settings.input(storedValue);
|
||||
break;
|
||||
case "ArrowDown":
|
||||
validateAndChange(storedValue - (e.shiftKey ? 10 : 1)) && settings?.input && settings.input(storedValue);
|
||||
validateAndChange(storedValue - (e.ctrlKey ? 10 : 1)) && settings?.input && settings.input(storedValue);
|
||||
break;
|
||||
case "PageUp":
|
||||
settings?.max && validateAndChange(settings.max) && settings?.input && settings.input(storedValue);
|
||||
|
|
@ -371,12 +371,23 @@ export function numberpicker(settings?: { defaultValue?: number, change?: (value
|
|||
return field;
|
||||
}
|
||||
// Open by default
|
||||
export function foldable(content: NodeChildren, title: NodeChildren, settings?: { open?: boolean, class?: { container?: Class, title?: Class, content?: Class, icon?: Class } })
|
||||
export function foldable(content: NodeChildren | (() => NodeChildren), title: NodeChildren, settings?: { open?: boolean, class?: { container?: Class, title?: Class, content?: Class, icon?: Class } })
|
||||
{
|
||||
let _content: NodeChildren;
|
||||
const display = (state: boolean) => {
|
||||
if(state && !_content)
|
||||
{
|
||||
_content = typeof content === 'function' ? content() : content;
|
||||
//@ts-ignore
|
||||
contentContainer.replaceChildren(..._content);
|
||||
}
|
||||
}
|
||||
const contentContainer = div(['hidden group-data-[active]:flex', settings?.class?.content]);
|
||||
const fold = div(['group flex flex-1 w-full flex-col', settings?.class?.container], [
|
||||
div('flex', [ dom('div', { listeners: { click: () => fold.toggleAttribute('data-active') }, class: ['flex justify-center items-center', settings?.class?.icon] }, [ icon('radix-icons:caret-right', { class: 'group-data-[active]:rotate-90 origin-center' }) ]), div(['flex-1', settings?.class?.title], title) ]),
|
||||
div(['hidden group-data-[active]:flex', settings?.class?.content], content),
|
||||
div('flex', [ dom('div', { listeners: { click: () => { display(fold.toggleAttribute('data-active')) } }, class: ['flex justify-center items-center', settings?.class?.icon] }, [ icon('radix-icons:caret-right', { class: 'group-data-[active]:rotate-90 origin-center', noobserver: true }) ]), div(['flex-1', settings?.class?.title], title) ]),
|
||||
contentContainer
|
||||
]);
|
||||
display(settings?.open ?? true);
|
||||
fold.toggleAttribute('data-active', settings?.open ?? true);
|
||||
return fold;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { Ability, AspectConfig, CharacterConfig, Feature, FeatureEffect, FeatureItem, MainStat, Resistance, SpellConfig, TrainingLevel } from "~/types/character";
|
||||
import type { Ability, AspectConfig, CharacterConfig, Feature, FeatureEffect, FeatureItem, Level, MainStat, RaceConfig, 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 { 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 { ALIGNMENTS, alignmentTexts, elementTexts, LEVELS, 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";
|
||||
import renderMarkdown, { renderText } from "#shared/markdown.util";
|
||||
|
|
@ -100,24 +100,73 @@ abstract class BuilderTab {
|
|||
};
|
||||
class PeopleEditor extends BuilderTab
|
||||
{
|
||||
private _options: HTMLDivElement[];
|
||||
|
||||
private _activeOption?: HTMLDivElement;
|
||||
|
||||
constructor(builder: HomebrewBuilder, config: CharacterConfig)
|
||||
{
|
||||
super(builder, config);
|
||||
|
||||
this._options = config.peoples.map(
|
||||
(people, i) => dom("div", { class: "flex flex-col flex-nowrap gap-2 p-2 border border-light-35 dark:border-dark-35 cursor-pointer hover:border-light-70 dark:hover:border-dark-70 w-[320px]", listeners: { click: () => {
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._activeOption?.classList.toggle(e, false));
|
||||
this._activeOption = this._options[i]!;
|
||||
"border-accent-blue outline-2 outline outline-accent-blue".split(" ").forEach(e => this._activeOption?.classList.toggle(e, true));
|
||||
const add = () => {
|
||||
const people: RaceConfig = {
|
||||
id: getID(ID_SIZE),
|
||||
name: '',
|
||||
description: '',
|
||||
options: LEVELS.map(e => {
|
||||
const feature: Feature = {
|
||||
id: getID(ID_SIZE),
|
||||
description: '',
|
||||
effect: [],
|
||||
}
|
||||
} }, [div("h-[320px]"), div("text-xl font-bold text-center", [text(people.name)]), div("w-full border-b border-light-50 dark:border-dark-50"), div("text-wrap word-break", [text(people.description)])]),
|
||||
);
|
||||
config.features[feature.id] = feature;
|
||||
return [e, [feature.id]] as [Level, string[]];
|
||||
}).reduce((p, v) => { p[v[0]] = v[1]; return p }, {} as Record<Level, string[]>)
|
||||
};
|
||||
config.peoples[people.id] = people;
|
||||
(this._content[0] as HTMLDivElement).appendChild(peopleRender(people));
|
||||
}
|
||||
const remove = (people: RaceConfig) => {
|
||||
confirm('Voulez vous vraiment supprimer cet aspect ?').then(e => {
|
||||
if(e)
|
||||
{
|
||||
Object.values(people.options).forEach(e => e.forEach(id => delete config.features[id]));
|
||||
delete config.peoples[people.id];
|
||||
|
||||
this._content = [ div('flex flex-1 gap-4 p-2 overflow-x-auto justify-center', this._options) ];
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
const render = (people: string, level: Level, feature: string) => {
|
||||
let element = dom("div", { class: ["border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-[400px] hover:border-light-50 dark:hover:border-dark-50"], listeners: { click: e => {
|
||||
this._builder.edit(config.features[feature]!).then(e => {
|
||||
element.replaceChildren(markdownUtil(config.features[feature]!.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();
|
||||
const _feature: Feature = { id: getID(ID_SIZE), description: '', effect: [] };
|
||||
config.features[_feature.id] = _feature;
|
||||
config.peoples[people]!.options[level]!.push(_feature.id);
|
||||
element.parentElement?.appendChild(render(people, level, _feature.id));
|
||||
} } }, [ text('Nouveau') ]),
|
||||
config.peoples[people]!.options[level].length > 1 ? 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) {
|
||||
config.peoples[people]!.options[level] = config.peoples[people]!.options[level].filter(e => e !== feature);
|
||||
delete config.features[feature];
|
||||
element.remove();
|
||||
}
|
||||
}) } } }, [ text('Supprimer') ]) : undefined,
|
||||
], { placement: "right-start", priority: false });
|
||||
}}}, [ markdownUtil(config.features[feature]!.description, undefined, { tags: { a: fakeA } }) ]);
|
||||
return element;
|
||||
}
|
||||
const peopleRender = (people: RaceConfig) => {
|
||||
return foldable(() => Object.entries(people.options).flatMap(level => [ div("w-full flex h-px", [div("border-t border-dashed border-light-50 dark:border-dark-50 w-full"), dom('span', { class: "relative" }, [ text(level[0]) ])]),
|
||||
div("flex flex-row gap-4 justify-center", level[1].map((option) => render(people.id, parseInt(level[0], 10) as Level, option))),
|
||||
]), [ input('text', { defaultValue: people.name, input: (value) => people.name = value, class: 'w-32' }), input('text', { defaultValue: people.description, input: (value) => people.description = value, class: 'w-full' }) ], { class: { container: 'gap-2 max-h-full', title: 'flex flex-row', content: 'flex flex-shrink-0 flex-col gap-4 relative w-full overflow-y-auto px-8' }, open: false })
|
||||
}
|
||||
const container = div('flex flex-col gap-2', Object.values(config.peoples).map(peopleRender));
|
||||
this._content = [ div('flex flex-col py-2 gap-2', [ div('w-full flex flex-row-reverse', [ button(icon('radix-icons:plus'), add, 'p-1') ]), container ]) ];
|
||||
}
|
||||
}
|
||||
class TrainingEditor extends BuilderTab
|
||||
|
|
@ -131,24 +180,37 @@ class TrainingEditor extends BuilderTab
|
|||
constructor(builder: HomebrewBuilder, config: CharacterConfig)
|
||||
{
|
||||
super(builder, config);
|
||||
const statRenderBlock = (stat: MainStat) => {
|
||||
return Object.entries(config.training[stat]).map(
|
||||
(level) => [ div("w-full flex h-px", [div("border-t border-dashed border-light-50 dark:border-dark-50 w-full"), dom('span', { class: "relative" }, [ text(level[0]) ])]),
|
||||
div("flex flex-row gap-4 justify-center", level[1].map((option, j) => {
|
||||
const render = (stat: MainStat, level: TrainingLevel, feature: string) => {
|
||||
let element = dom("div", { class: ["border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-[400px] hover:border-light-50 dark:hover:border-dark-50"], listeners: { click: e => {
|
||||
this._builder.edit(config.features[option]!).then(e => {
|
||||
element.replaceChildren(markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }));
|
||||
this._builder.edit(config.features[feature]!).then(e => {
|
||||
element.replaceChildren(markdownUtil(config.features[feature]!.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') ])
|
||||
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();
|
||||
const _feature: Feature = { id: getID(ID_SIZE), description: '', effect: [] };
|
||||
config.features[_feature.id] = _feature;
|
||||
config.training[stat][level].push(_feature.id);
|
||||
element.parentElement?.appendChild(render(stat, level, _feature.id));
|
||||
} } }, [ text('Nouveau') ]),
|
||||
config.training[stat][level].length > 1 ? 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) {
|
||||
config.training[stat][level as any as TrainingLevel] = config.training[stat][level as any as TrainingLevel].filter(e => e !== feature);
|
||||
delete config.features[feature];
|
||||
element.remove();
|
||||
}
|
||||
}) } } }, [ text('Supprimer') ]) : undefined,
|
||||
], { placement: "right-start", priority: false });
|
||||
}}}, [ markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }) ]);
|
||||
}}}, [ markdownUtil(config.features[feature]!.description, undefined, { tags: { a: fakeA } }) ]);
|
||||
return element;
|
||||
})),
|
||||
};
|
||||
const statRenderBlock = (stat: MainStat) => {
|
||||
return Object.entries(config.training[stat]).map(
|
||||
(level) => [ div("w-full flex h-px", [div("border-t border-dashed border-light-50 dark:border-dark-50 w-full"), dom('span', { class: "relative" }, [ text(level[0]) ])]),
|
||||
div("flex flex-row gap-4 justify-center", level[1].map((option) => render(stat, parseInt(level[0], 10) as TrainingLevel, option))),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -229,12 +291,17 @@ class AspectEditor extends BuilderTab
|
|||
content = element;
|
||||
};
|
||||
const remove = (aspect: AspectConfig) => {
|
||||
confirm('Voulez vous vraiment supprimer cet aspect ?').then(e => {
|
||||
if(e)
|
||||
{
|
||||
config.aspects = config.aspects.filter(e => e !== aspect);
|
||||
|
||||
const element = redraw();
|
||||
content.parentElement?.replaceChild(element, content);
|
||||
content = element;
|
||||
}
|
||||
})
|
||||
}
|
||||
const redraw = () => table(config.aspects.map(render), { name: 'Nom', description: 'Description', stat: 'Buff de stat', alignment: 'Alignement', magic: 'Magie', difficulty: 'Difficulté', physic: 'Physique', mental: 'Mental', personality: 'Caractère', action: 'Actions' }, { class: { table: 'flex-1' } });
|
||||
let content = redraw();
|
||||
this._content = [ div('flex px-8 py-4 flex-col gap-4', [ div('flex flex-row-reverse', [ button(icon('radix-icons:plus'), add, 'p-1') ]), content ] ) ];
|
||||
|
|
@ -247,19 +314,15 @@ class SpellEditor extends BuilderTab
|
|||
super(builder, config);
|
||||
|
||||
const render = (spell: SpellConfig) => {
|
||||
return {
|
||||
id: spell.id,
|
||||
name: input('text', { input: (value) => spell.name = value, defaultValue: spell.name, class: '!m-0 w-full' }),
|
||||
rank: select([{ text: 'Rang 1', value: 1 }, { text: 'Rang 2', value: 2 }, { text: 'Rang 3', value: 3 }, { text: 'Spécial', value: 4 }], { change: (value: 1 | 2 | 3 | 4) => spell.rank = value, defaultValue: spell.rank, class: { container: '!m-0 w-full' } }),
|
||||
type: select(SPELL_TYPES.map(f => ({ text: spellTypeTexts[f], value: f })), { change: (value) => spell.type = value, defaultValue: spell.type, class: { container: '!m-0 w-full' } }),
|
||||
cost: numberpicker({ defaultValue: spell.cost, input: (value) => spell.cost = value, class: '!m-0 w-full' }),
|
||||
speed: select<'action' | 'reaction' | number>([{ text: 'Action', value: 'action' }, { text: 'Reaction', value: 'reaction' }, { text: '1 minute', value: 1 }, { text: '10 minutes', value: 10 }], { change: (value) => spell.speed = value, defaultValue: spell.speed, class: { container: '!m-0 w-full' } }),
|
||||
elements: multiselect(SPELL_ELEMENTS.map(f => ({ text: elementTexts[f].text, value: f })), { change: (value) => spell.elements = value, defaultValue: spell.elements, class: { container: '!m-0 w-full' } }),
|
||||
effect: input('text', { input: (value) => spell.effect = value, defaultValue: spell.effect, class: '!m-0 w-full' }),
|
||||
tags: multiselect([{ text: 'Dégâts', value: 'damage' }, { text: 'Buff', value: 'buff' }, { text: 'Debuff', value: 'debuff' }, { text: 'Support', value: 'support' }, { text: 'Tank', value: 'tank' }, { text: 'Mouvement', value: 'movement' }, { text: 'Utilitaire', value: 'utilitary' }], { change: (value) => spell.tags = value, defaultValue: spell.tags, class: { container: '!m-0 w-full' } }),
|
||||
concentration: toggle({ change: (value) => spell.concentration = value, defaultValue: spell.concentration, class: { container: '!m-0' } }),
|
||||
action: div('flex flex-row justify-center gap-2', [ button(icon('radix-icons:trash'), () => remove(spell), 'p-1') ])
|
||||
};
|
||||
return foldable([
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Rang'), select([{ text: 'Rang 1', value: 1 }, { text: 'Rang 2', value: 2 }, { text: 'Rang 3', value: 3 }, { text: 'Spécial', value: 4 }], { change: (value: 1 | 2 | 3 | 4) => spell.rank = value, defaultValue: spell.rank, class: { container: '!m-0 !h-9 w-full' } }), ]),
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Type'), select(SPELL_TYPES.map(f => ({ text: spellTypeTexts[f], value: f })), { change: (value) => spell.type = value, defaultValue: spell.type, class: { container: '!m-0 !h-9 w-full' } }), ]),
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Coût'), numberpicker({ defaultValue: spell.cost, input: (value) => spell.cost = value, class: '!m-0 w-full' }), ]),
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Incantation'), select<'action' | 'reaction' | number>([{ text: 'Action', value: 'action' }, { text: 'Reaction', value: 'reaction' }, { text: '1 minute', value: 1 }, { text: '10 minutes', value: 10 }], { change: (value) => spell.speed = value, defaultValue: spell.speed, class: { container: '!m-0 !h-9 w-full' } }), ]),
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Elements'), multiselect(SPELL_ELEMENTS.map(f => ({ text: elementTexts[f].text, value: f })), { change: (value) => spell.elements = value, defaultValue: spell.elements, class: { container: '!m-0 !h-9 w-full' } }), ]),
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Tags'), multiselect([{ text: 'Dégâts', value: 'damage' }, { text: 'Buff', value: 'buff' }, { text: 'Debuff', value: 'debuff' }, { text: 'Support', value: 'support' }, { text: 'Tank', value: 'tank' }, { text: 'Mouvement', value: 'movement' }, { text: 'Utilitaire', value: 'utilitary' }], { change: (value) => spell.tags = value, defaultValue: spell.tags, class: { container: '!m-0 !h-9 w-full' } }), ]),
|
||||
dom('label', { class: 'flex flex-col items-center justify-start gap-2 flex-1 *:text-center' }, [ text('Concentration'), toggle({ change: (value) => spell.concentration = value, defaultValue: spell.concentration, class: { container: '!m-0 !flex-none' } }), ]),
|
||||
], [ div('gap-4 px-4 flex', [ input('text', { input: (value) => spell.name = value, defaultValue: spell.name, class: '!m-0 w-64' }), input('text', { input: (value) => spell.effect = value, defaultValue: spell.effect, class: '!m-0 w-full' }),div('flex flex-row justify-center gap-2', [ button(icon('radix-icons:trash', { noobserver: true }), () => remove(spell), 'p-1') ]) ]) ], { class: { container: 'border-light-35 dark:border-dark-35 py-1', content: 'gap-2 px-4 py-1 flex items-center *:flex-1' }, open: false });
|
||||
}
|
||||
const add = () => {
|
||||
config.spells.push({
|
||||
|
|
@ -280,13 +343,19 @@ class SpellEditor extends BuilderTab
|
|||
content = element;
|
||||
};
|
||||
const remove = (spell: SpellConfig) => {
|
||||
confirm('Voulez vous vraiment supprimer ce sort ?').then(e => {
|
||||
if(e)
|
||||
{
|
||||
config.spells = config.spells.filter(e => e !== spell);
|
||||
|
||||
const element = redraw();
|
||||
content.parentElement?.replaceChild(element, content);
|
||||
content = element;
|
||||
}
|
||||
const redraw = () => table(config.spells.map(render), { id: 'ID', name: 'Nom', rank: 'Rang', type: 'Type', cost: 'Coût', speed: 'Incantation', elements: 'Elements', effect: 'Effet', tags: 'Tag', concentration: 'Concentration', action: 'Actions' }, { class: { table: 'flex-1' } });
|
||||
});
|
||||
}
|
||||
const redraw = () => div('flex flex-col divide-y', config.spells.map(render));
|
||||
//, { class: { table: 'flex-1' } });
|
||||
let content = redraw();
|
||||
this._content = [ div('flex px-8 py-4 flex-col gap-4', [ div('flex flex-row-reverse', [ button(icon('radix-icons:plus'), add, 'p-1') ]), content ] ) ];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export type Character = {
|
|||
id: number;
|
||||
|
||||
name: string;
|
||||
people?: number;
|
||||
people?: string;
|
||||
level: number;
|
||||
aspect?: number;
|
||||
notes?: string | null;
|
||||
|
|
@ -44,7 +44,7 @@ export type CharacterVariables = {
|
|||
equipment: Array<string>;
|
||||
};
|
||||
export type CharacterConfig = {
|
||||
peoples: RaceConfig[];
|
||||
peoples: Record<string, RaceConfig>;
|
||||
resistances: Record<Resistance, { name: string, statistic: MainStat }>;
|
||||
training: Record<MainStat, Record<TrainingLevel, FeatureID[]>>;
|
||||
abilities: Record<Ability, AbilityConfig>;
|
||||
|
|
@ -72,6 +72,7 @@ export type AbilityConfig = {
|
|||
description: string;
|
||||
};
|
||||
export type RaceConfig = {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
options: Record<Level, FeatureID[]>;
|
||||
|
|
@ -126,7 +127,7 @@ export type CompiledCharacter = {
|
|||
name: string;
|
||||
health: number; //Max
|
||||
mana: number; //Max
|
||||
race: number;
|
||||
race: string;
|
||||
spellslots: number; //Max
|
||||
artslots: number; //Max
|
||||
spellranks: Record<SpellType, 0 | 1 | 2 | 3>;
|
||||
|
|
|
|||
Loading…
Reference in New Issue