From c0d1cea7cb0466ac6f4f5dd738fd65c95deab500 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Thu, 21 Aug 2025 21:00:51 +0800 Subject: [PATCH 001/146] chore(pnpm): Add MobX state tree --- package.json | 5 ++++- pnpm-lock.yaml | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f2e1598..fa5080e 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,8 @@ "i18next-chained-backend": "^4.6.2", "i18next-http-backend": "^3.0.2", "i18next-localstorage-backend": "^4.2.0", + "mobx-react-lite": "^4.1.0", + "mobx-state-tree": "^7.0.2", "normalize.css": "^8.0.1", "pixi.js": "^8.6.6", "rc-dock": "^3.3.0", @@ -60,5 +62,6 @@ "patchedDependencies": { "react-split-pane": "patches/react-split-pane.patch" } - } + }, + "packageManager": "pnpm@10.12.1+sha512.f0dda8580f0ee9481c5c79a1d927b9164f2c478e90992ad268bbb2465a736984391d6333d2c327913578b2804af33474ca554ba29c04a8b13060a717675ae3ac" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a83a45..5cb79f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -55,6 +55,12 @@ importers: i18next-localstorage-backend: specifier: ^4.2.0 version: 4.2.0 + mobx-react-lite: + specifier: ^4.1.0 + version: 4.1.0(mobx@6.13.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + mobx-state-tree: + specifier: ^7.0.2 + version: 7.0.2(mobx@6.13.7)(typescript@5.6.3) normalize.css: specifier: ^8.0.1 version: 8.0.1 @@ -1382,6 +1388,27 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + mobx-react-lite@4.1.0: + resolution: {integrity: sha512-QEP10dpHHBeQNv1pks3WnHRCem2Zp636lq54M2nKO2Sarr13pL4u6diQXf65yzXUn0mkk18SyIDCm9UOJYTi1w==} + peerDependencies: + mobx: ^6.9.0 + react: ^16.8.0 || ^17 || ^18 || ^19 + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + + mobx-state-tree@7.0.2: + resolution: {integrity: sha512-Qmqgo2Ho1/JRTquo0EWw0ZA/k4wTUNPMIBg98ALGN1V/0Gupic7dg4GDYUhNbiLsYHpp48VgpaCDpDIKV+jNkQ==} + peerDependencies: + mobx: ^6.3.0 + + mobx@6.13.7: + resolution: {integrity: sha512-aChaVU/DO5aRPmk1GX8L+whocagUUpBQqoPtJk+cm7UOXUk87J4PeWCh6nNmTTIfEhiR9DI/+FnA8dln/hTK7g==} + mpg123-decoder@1.0.0: resolution: {integrity: sha512-WV+pyuMUhRqv7s8S6p/Ii4KQHdBD1pb3yaABxcKJRsNp+HQ/Y6z2iIBIaOZu0JMHPTOoICYt0REDZ7XfLu+n/g==} @@ -1830,6 +1857,14 @@ packages: peerDependencies: typescript: '>=4.2.0' + ts-essentials@9.4.2: + resolution: {integrity: sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==} + peerDependencies: + typescript: '>=4.1.0' + peerDependenciesMeta: + typescript: + optional: true + tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} @@ -3312,6 +3347,23 @@ snapshots: dependencies: brace-expansion: 2.0.1 + mobx-react-lite@4.1.0(mobx@6.13.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + mobx: 6.13.7 + react: 19.0.0 + use-sync-external-store: 1.4.0(react@19.0.0) + optionalDependencies: + react-dom: 19.0.0(react@19.0.0) + + mobx-state-tree@7.0.2(mobx@6.13.7)(typescript@5.6.3): + dependencies: + mobx: 6.13.7 + ts-essentials: 9.4.2(typescript@5.6.3) + transitivePeerDependencies: + - typescript + + mobx@6.13.7: {} + mpg123-decoder@1.0.0: dependencies: '@wasm-audio-decoders/common': 9.0.5 @@ -3876,6 +3928,10 @@ snapshots: dependencies: typescript: 5.6.3 + ts-essentials@9.4.2(typescript@5.6.3): + optionalDependencies: + typescript: 5.6.3 + tslib@2.6.3: {} type-check@0.4.0: From 34711695e77f339212d2a99d56891853caebe3a5 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 22 Aug 2025 14:54:10 +0800 Subject: [PATCH 002/146] feat: Add simple chart state model --- src/core/models/Chart.ts | 20 ++++++++++++++++++++ src/core/models/JudgeLine.ts | 23 +++++++++++++++++++++++ src/core/models/Note.ts | 9 +++++++++ src/core/state/chartStore.ts | 5 +++++ src/core/utils/model.ts | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 src/core/models/Chart.ts create mode 100644 src/core/models/JudgeLine.ts create mode 100644 src/core/models/Note.ts create mode 100644 src/core/state/chartStore.ts create mode 100644 src/core/utils/model.ts diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts new file mode 100644 index 0000000..2ba9fd1 --- /dev/null +++ b/src/core/models/Chart.ts @@ -0,0 +1,20 @@ +import { v4 as uuid } from 'uuid'; +import { types, Instance } from 'mobx-state-tree'; +import { JudgeLine } from './JudgeLine'; + +export const Chart = types.model('Chart', { + judgelines: types.array(JudgeLine), +}).actions((self) => ({ + addJudgeLine() { + self.judgelines.push({ + id: uuid(), + }); + }, + + removeJudgeLine(id: string) { + const index = self.judgelines.findIndex(e => e.id === id); + if (index >= 0) self.judgelines.splice(index, 1); + } +})); + +export type TChart = Instance; diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts new file mode 100644 index 0000000..75f7d5f --- /dev/null +++ b/src/core/models/JudgeLine.ts @@ -0,0 +1,23 @@ +import { v4 as uuid } from 'uuid'; +import { types, Instance } from 'mobx-state-tree'; +import { Note } from './Note'; +import { BeatArray } from '@/utils/types'; + +export const JudgeLine = types.model('JudgeLine', { + id: types.identifier, + notes: types.array(Note), +}).actions((self) => ({ + addNote(time: BeatArray) { + self.notes.push({ + id: uuid(), + time, + }); + }, + + removeNote(id: string) { + const index = self.notes.findIndex(e => e.id === id); + if (index >= 0) self.notes.splice(index, 1); + } +})); + +export type TJudgeLine = Instance; diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts new file mode 100644 index 0000000..23d0d2e --- /dev/null +++ b/src/core/models/Note.ts @@ -0,0 +1,9 @@ +import { types, Instance } from 'mobx-state-tree'; +import { BeatArray } from '@/core/utils/model'; + +export const Note = types.model('Note', { + id: types.identifier, + time: BeatArray, +}); + +export type TNote = Instance; diff --git a/src/core/state/chartStore.ts b/src/core/state/chartStore.ts new file mode 100644 index 0000000..3db2347 --- /dev/null +++ b/src/core/state/chartStore.ts @@ -0,0 +1,5 @@ +import { Chart, TChart } from '@/core/models/Chart'; + +export const store: TChart = Chart.create({ + judgelines: [], +}); diff --git a/src/core/utils/model.ts b/src/core/utils/model.ts new file mode 100644 index 0000000..0b288c9 --- /dev/null +++ b/src/core/utils/model.ts @@ -0,0 +1,33 @@ +import { types } from 'mobx-state-tree'; +import { BeatArray as TBeatArray } from '../../utils/types'; + +export const BeatArray = types.custom({ + name: 'BeatArray', + + fromSnapshot(value: number[]) { + return [ value[0], value[1], value[2] ]; + }, + + toSnapshot(value: TBeatArray) { + return value; + }, + + isTargetType(value: TBeatArray | number[]) { + return ( + value.length === 3 && + !isNaN(value[0]) && + !isNaN(value[1]) && + !isNaN(value[2]) + ); + }, + + getValidationMessage(snapshot: number[]) { + if (snapshot.length !== 3) return `Invalid array length`; + if ( + isNaN(snapshot[0]) || + isNaN(snapshot[1]) || + isNaN(snapshot[2]) + ) return 'Array contains NaN'; + return ''; + } +}); From 03d2a32977c394d0ca268dd88dd39f6f34415fc9 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 22 Aug 2025 17:46:36 +0800 Subject: [PATCH 003/146] feat(core): Add more chart models --- src/core/models/Chart.ts | 2 +- src/core/models/JudgeLine.ts | 12 ++++++++++-- src/core/models/Keyframe.ts | 14 ++++++++++++++ src/core/models/KeyframeRecord.ts | 32 +++++++++++++++++++++++++++++++ src/core/models/Note.ts | 2 +- src/core/types.ts | 8 ++++++++ src/core/utils/model.ts | 13 +++++++++---- 7 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 src/core/models/Keyframe.ts create mode 100644 src/core/models/KeyframeRecord.ts create mode 100644 src/core/types.ts diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index 2ba9fd1..3d5a1fa 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -17,4 +17,4 @@ export const Chart = types.model('Chart', { } })); -export type TChart = Instance; +export type IChart = Instance; diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index 75f7d5f..3b0e243 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -1,11 +1,19 @@ import { v4 as uuid } from 'uuid'; import { types, Instance } from 'mobx-state-tree'; +import { KeyframeRecord } from './KeyframeRecord'; import { Note } from './Note'; import { BeatArray } from '@/utils/types'; export const JudgeLine = types.model('JudgeLine', { id: types.identifier, - notes: types.array(Note), + keyframes: types.optional(KeyframeRecord, { + positionX: [{ id: uuid(), time: [ 0, 0, 1 ], value: 0 }], + positionY: [{ id: uuid(), time: [ 0, 0, 1 ], value: 0 }], + rotate: [{ id: uuid(), time: [ 0, 0, 1 ], value: 0 }], + alpha: [{ id: uuid(), time: [ 0, 0, 1 ], value: 255 }], + speed: [{ id: uuid(), time: [ 0, 0, 1 ], value: 1 }], + }), + notes: types.optional(types.array(Note), []), }).actions((self) => ({ addNote(time: BeatArray) { self.notes.push({ @@ -20,4 +28,4 @@ export const JudgeLine = types.model('JudgeLine', { } })); -export type TJudgeLine = Instance; +export type IJudgeLine = Instance; diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts new file mode 100644 index 0000000..2e7294f --- /dev/null +++ b/src/core/models/Keyframe.ts @@ -0,0 +1,14 @@ +import { types, getParent, Instance } from 'mobx-state-tree'; +import { BeatArray } from '@/core/utils/model'; + +export const Keyframe = types.model('Keyframe', { + id: types.identifier, + time: BeatArray, + value: types.number, +}).views((self) => ({ + get line() { + return getParent(self, 2); + } +})); + +export type IKeyframe = Instance; diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts new file mode 100644 index 0000000..fd64f16 --- /dev/null +++ b/src/core/models/KeyframeRecord.ts @@ -0,0 +1,32 @@ +import { v4 as uuid } from 'uuid'; +import { types, Instance } from 'mobx-state-tree'; +import { Keyframe as $Keyframe } from './Keyframe'; +import { IArrayType } from 'mobx-state-tree'; +import { KeyframeType } from '../types'; +import { BeatArray } from '@/utils/types'; + +export type $KeyframeRecord = { + [k in KeyframeType]: IArrayType; +}; + +export const KeyframeRecord = types.model('KeyframeRecord', { + positionX: types.array($Keyframe), + positionY: types.array($Keyframe), + rotate: types.array($Keyframe), + alpha: types.array($Keyframe), + speed: types.array($Keyframe), +}).actions((self) => ({ + add(type: T, time: BeatArray, value: number) { + self[type].push({ + id: uuid(), + time, value, + }); + }, + + remove(type: T, id: string) { + const index = self[type].findIndex(e => e.id === id); + if (index >= 0) self[type].splice(index, 1); + }, +})); + +export type IKeyframeRecord = Instance; diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index 23d0d2e..ce49b2e 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -6,4 +6,4 @@ export const Note = types.model('Note', { time: BeatArray, }); -export type TNote = Instance; +export type INote = Instance; diff --git a/src/core/types.ts b/src/core/types.ts new file mode 100644 index 0000000..7883e24 --- /dev/null +++ b/src/core/types.ts @@ -0,0 +1,8 @@ + +export enum KeyframeType { + PositionX = 'positionX', + PositionY = 'positionY', + Rotate = 'rotate', + Alpha = 'alpha', + Speed = 'speed', +}; diff --git a/src/core/utils/model.ts b/src/core/utils/model.ts index 0b288c9..2bce2ea 100644 --- a/src/core/utils/model.ts +++ b/src/core/utils/model.ts @@ -15,19 +15,24 @@ export const BeatArray = types.custom({ isTargetType(value: TBeatArray | number[]) { return ( value.length === 3 && - !isNaN(value[0]) && - !isNaN(value[1]) && - !isNaN(value[2]) + !isNaN(value[0]) && value[0] >= 0 && + !isNaN(value[1]) && value[1] >= 0 && + !isNaN(value[2]) && value[2] >= 1 ); }, getValidationMessage(snapshot: number[]) { - if (snapshot.length !== 3) return `Invalid array length`; + if (snapshot.length !== 3) return 'Invalid array length'; if ( isNaN(snapshot[0]) || isNaN(snapshot[1]) || isNaN(snapshot[2]) ) return 'Array contains NaN'; + if ( + snapshot[0] < 0 || + snapshot[1] < 0 || + snapshot[2] < 1 + ) return 'Array contains invaild number'; return ''; } }); From f38b269847d074ca8d72eb43609daaec37f2c218 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 22 Aug 2025 18:01:26 +0800 Subject: [PATCH 004/146] feat(core/models/Note): Add `line` prop --- src/core/models/Keyframe.ts | 3 ++- src/core/models/Note.ts | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 2e7294f..5e2fe83 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -7,7 +7,8 @@ export const Keyframe = types.model('Keyframe', { value: types.number, }).views((self) => ({ get line() { - return getParent(self, 2); + // TODO: types + return getParent(self, 3); } })); diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index ce49b2e..2f61afe 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -1,9 +1,14 @@ -import { types, Instance } from 'mobx-state-tree'; +import { types, getParent, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; export const Note = types.model('Note', { id: types.identifier, time: BeatArray, -}); +}).views((self) => ({ + get line() { + // TODO: types + return getParent(self, 2); + } +})); export type INote = Instance; From 725043d83b809055235d2e5c56588ef2941cff7e Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 24 Aug 2025 14:25:24 +0800 Subject: [PATCH 005/146] feat(core/models): Add more model props --- src/core/models/BPM.ts | 35 ++++++++++++++++++++++++++++++ src/core/models/Chart.ts | 25 +++++++++++++++++---- src/core/models/JudgeLine.ts | 22 +++++++++---------- src/core/models/Keyframe.ts | 14 ++++++++++-- src/core/models/Note.ts | 42 ++++++++++++++++++++++++++++++++++-- 5 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 src/core/models/BPM.ts diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts new file mode 100644 index 0000000..7ad48f1 --- /dev/null +++ b/src/core/models/BPM.ts @@ -0,0 +1,35 @@ +import { v4 as uuid } from 'uuid'; +import { types, Instance } from 'mobx-state-tree'; +import { BeatArray } from '@/core/utils/model'; +import { BeatArrayToNumber } from '@/utils/math'; + +const BPMNumber = types.custom({ + name: 'BPMNumber', + + fromSnapshot: (value) => value, + toSnapshot: (value) => value, + + isTargetType(value) { + return !isNaN(value) && value > 0; + }, + + getValidationMessage(snapshot) { + if (isNaN(snapshot)) return '\'NaN\' BPM is not allowed'; + if (snapshot <= 0) return 'BPM cannot smaller than 1'; + return ''; + }, +}); + +export const BPM = types.model('Note', { + id: types.optional(types.identifier, uuid), + time: BeatArray, + bpm: BPMNumber, +}).views((self) => ({ + get beat() { + return BeatArrayToNumber(self.time); + } +})); + +export type IBPM = Instance; + +export const sortBPM = (a: IBPM, b: IBPM) => a.beat - b.beat; diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index 3d5a1fa..f76da3d 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,14 +1,31 @@ -import { v4 as uuid } from 'uuid'; import { types, Instance } from 'mobx-state-tree'; +import { BPM, sortBPM } from './BPM'; import { JudgeLine } from './JudgeLine'; +import { BeatArray } from '@/utils/types'; export const Chart = types.model('Chart', { + offset: types.number, + bpm: types.array(BPM), judgelines: types.array(JudgeLine), }).actions((self) => ({ - addJudgeLine() { - self.judgelines.push({ - id: uuid(), + addBPM(time: BeatArray, bpm: number) { + self.bpm.push({ + time, bpm, }); + + self.bpm.sort(sortBPM); + }, + + removeBPM(id: string) { + const index = self.bpm.findIndex(e => e.id === id); + if (index >= 0) { + self.bpm.splice(index, 1); + self.bpm.sort(sortBPM); + } + }, + + addJudgeLine() { + self.judgelines.push({}); }, removeJudgeLine(id: string) { diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index 3b0e243..6a17c99 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -5,21 +5,21 @@ import { Note } from './Note'; import { BeatArray } from '@/utils/types'; export const JudgeLine = types.model('JudgeLine', { - id: types.identifier, + id: types.optional(types.identifier, uuid), keyframes: types.optional(KeyframeRecord, { - positionX: [{ id: uuid(), time: [ 0, 0, 1 ], value: 0 }], - positionY: [{ id: uuid(), time: [ 0, 0, 1 ], value: 0 }], - rotate: [{ id: uuid(), time: [ 0, 0, 1 ], value: 0 }], - alpha: [{ id: uuid(), time: [ 0, 0, 1 ], value: 255 }], - speed: [{ id: uuid(), time: [ 0, 0, 1 ], value: 1 }], + positionX: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], + positionY: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], + rotate: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], + alpha: [{ beat: [ 0, 0, 1 ], value: 255, continuous: false, easing: 1 }], + speed: [{ beat: [ 0, 0, 1 ], value: 1, continuous: false, easing: 1 }], }), notes: types.optional(types.array(Note), []), }).actions((self) => ({ - addNote(time: BeatArray) { - self.notes.push({ - id: uuid(), - time, - }); + addNote(beat: BeatArray) { + // self.notes.push({ + // id: uuid(), + // beat, + // }); }, removeNote(id: string) { diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 5e2fe83..47e5719 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -1,14 +1,24 @@ +import { v4 as uuid } from 'uuid'; import { types, getParent, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; +import { BeatArrayToNumber } from '@/utils/math'; export const Keyframe = types.model('Keyframe', { - id: types.identifier, - time: BeatArray, + id: types.optional(types.identifier, uuid), + beat: BeatArray, value: types.number, + continuous: types.boolean, + easing: types.number, + hasEndValue: types.optional(types.boolean, false), + endValue: types.optional(types.number, 0), }).views((self) => ({ get line() { // TODO: types return getParent(self, 3); + }, + + get beatNum() { + return BeatArrayToNumber(self.beat); } })); diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index 2f61afe..a47c0fe 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -1,13 +1,51 @@ +import { v4 as uuid } from 'uuid'; import { types, getParent, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; +import { BeatArrayToNumber } from '@/utils/math'; +import { NoteType as ENoteType } from '@/Chart/types'; + +const NoteType = types.custom({ + name: 'NoteType', + + fromSnapshot: (value) => value, + toSnapshot: (value) => value, + + isTargetType: (value) => { + return ( + Math.floor(value) === value && ( + value >= 1 && value <= 4 + ) + ); + }, + getValidationMessage: (value) => { + if (Math.floor(value) !== value) return 'Float now allowed'; + if (value < 1 || value > 4) return 'Invaild note type'; + return ''; + } +}); export const Note = types.model('Note', { - id: types.identifier, - time: BeatArray, + id: types.optional(types.identifier, uuid), + type: NoteType, + beat: BeatArray, + positionX: types.number, + speed: types.number, + isAbove: types.boolean, + + holdEndBeat: types.maybe(BeatArray), }).views((self) => ({ get line() { // TODO: types return getParent(self, 2); + }, + + get beatNum() { + return BeatArrayToNumber(self.beat); + }, + + get holdEndBeatNum() { + if (!self.holdEndBeat) return null; + return BeatArrayToNumber(self.holdEndBeat); } })); From 2c68bfb2eb664d442d4c84cb893db242d18b33ca Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 24 Aug 2025 14:27:26 +0800 Subject: [PATCH 006/146] chore(core): Use `nanoid` instead of UUID --- src/core/models/BPM.ts | 4 ++-- src/core/models/JudgeLine.ts | 4 ++-- src/core/models/Keyframe.ts | 4 ++-- src/core/models/Note.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index 7ad48f1..d7e9ba4 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -1,4 +1,4 @@ -import { v4 as uuid } from 'uuid'; +import { nanoid } from 'nanoid'; import { types, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; @@ -21,7 +21,7 @@ const BPMNumber = types.custom({ }); export const BPM = types.model('Note', { - id: types.optional(types.identifier, uuid), + id: types.optional(types.identifier, nanoid), time: BeatArray, bpm: BPMNumber, }).views((self) => ({ diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index 6a17c99..da32038 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -1,11 +1,11 @@ -import { v4 as uuid } from 'uuid'; +import { nanoid } from 'nanoid'; import { types, Instance } from 'mobx-state-tree'; import { KeyframeRecord } from './KeyframeRecord'; import { Note } from './Note'; import { BeatArray } from '@/utils/types'; export const JudgeLine = types.model('JudgeLine', { - id: types.optional(types.identifier, uuid), + id: types.optional(types.identifier, nanoid), keyframes: types.optional(KeyframeRecord, { positionX: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], positionY: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 47e5719..2b6d2c4 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -1,10 +1,10 @@ -import { v4 as uuid } from 'uuid'; +import { nanoid } from 'nanoid'; import { types, getParent, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; export const Keyframe = types.model('Keyframe', { - id: types.optional(types.identifier, uuid), + id: types.optional(types.identifier, nanoid), beat: BeatArray, value: types.number, continuous: types.boolean, diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index a47c0fe..4cf4e7d 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -1,4 +1,4 @@ -import { v4 as uuid } from 'uuid'; +import { nanoid } from 'nanoid'; import { types, getParent, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; @@ -25,7 +25,7 @@ const NoteType = types.custom({ }); export const Note = types.model('Note', { - id: types.optional(types.identifier, uuid), + id: types.optional(types.identifier, nanoid), type: NoteType, beat: BeatArray, positionX: types.number, From d18dac4f24fb643da670f9c77ec6bbe4c26c28b7 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 24 Aug 2025 14:31:16 +0800 Subject: [PATCH 007/146] feat(core/models): Finishing code --- src/core/models/JudgeLine.ts | 17 ++++++++++++----- src/core/models/KeyframeRecord.ts | 12 ++++++++---- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index da32038..e43ebe8 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -3,6 +3,7 @@ import { types, Instance } from 'mobx-state-tree'; import { KeyframeRecord } from './KeyframeRecord'; import { Note } from './Note'; import { BeatArray } from '@/utils/types'; +import { NoteType } from '@/Chart/types'; export const JudgeLine = types.model('JudgeLine', { id: types.optional(types.identifier, nanoid), @@ -15,11 +16,17 @@ export const JudgeLine = types.model('JudgeLine', { }), notes: types.optional(types.array(Note), []), }).actions((self) => ({ - addNote(beat: BeatArray) { - // self.notes.push({ - // id: uuid(), - // beat, - // }); + addNote( + type: NoteType, + beat: BeatArray, + positionX: number, + speed: number, + isAbove: boolean, + holdEndBeat?: BeatArray + ) { + self.notes.push({ + type, beat, positionX, speed, isAbove, holdEndBeat, + }); }, removeNote(id: string) { diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts index fd64f16..4e6e7ff 100644 --- a/src/core/models/KeyframeRecord.ts +++ b/src/core/models/KeyframeRecord.ts @@ -1,4 +1,3 @@ -import { v4 as uuid } from 'uuid'; import { types, Instance } from 'mobx-state-tree'; import { Keyframe as $Keyframe } from './Keyframe'; import { IArrayType } from 'mobx-state-tree'; @@ -16,10 +15,15 @@ export const KeyframeRecord = types.model('KeyframeRecord', { alpha: types.array($Keyframe), speed: types.array($Keyframe), }).actions((self) => ({ - add(type: T, time: BeatArray, value: number) { + add( + type: T, + beat: BeatArray, + value: number, + continuous: boolean, + easing: number, + ) { self[type].push({ - id: uuid(), - time, value, + beat, value, continuous, easing }); }, From 55c1740a1ba48669986cc684fd908d9f768cc48f Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 24 Aug 2025 14:31:30 +0800 Subject: [PATCH 008/146] chore(pnpm): Add nanoid --- package.json | 1 + pnpm-lock.yaml | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/package.json b/package.json index fa5080e..e45b9ce 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "i18next-localstorage-backend": "^4.2.0", "mobx-react-lite": "^4.1.0", "mobx-state-tree": "^7.0.2", + "nanoid": "^5.1.5", "normalize.css": "^8.0.1", "pixi.js": "^8.6.6", "rc-dock": "^3.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5cb79f4..ec0831f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,6 +61,9 @@ importers: mobx-state-tree: specifier: ^7.0.2 version: 7.0.2(mobx@6.13.7)(typescript@5.6.3) + nanoid: + specifier: ^5.1.5 + version: 5.1.5 normalize.css: specifier: ^8.0.1 version: 8.0.1 @@ -1420,6 +1423,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@5.1.5: + resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==} + engines: {node: ^18 || >=20} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -3372,6 +3380,8 @@ snapshots: nanoid@3.3.8: {} + nanoid@5.1.5: {} + natural-compare@1.4.0: {} no-case@3.0.4: From b90eccb59a7c685acd727426576dc2ad2fa533c7 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 24 Aug 2025 14:39:05 +0800 Subject: [PATCH 009/146] fix(core/model): Fix some stupid issues --- src/core/models/BPM.ts | 8 ++++---- src/core/models/Chart.ts | 4 ++-- src/core/models/JudgeLine.ts | 2 ++ src/core/models/Note.ts | 2 +- src/core/state/chartStore.ts | 9 +++++++-- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index d7e9ba4..910c845 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -22,14 +22,14 @@ const BPMNumber = types.custom({ export const BPM = types.model('Note', { id: types.optional(types.identifier, nanoid), - time: BeatArray, + beat: BeatArray, bpm: BPMNumber, }).views((self) => ({ - get beat() { - return BeatArrayToNumber(self.time); + get beatNum() { + return BeatArrayToNumber(self.beat); } })); export type IBPM = Instance; -export const sortBPM = (a: IBPM, b: IBPM) => a.beat - b.beat; +export const sortBPM = (a: IBPM, b: IBPM) => a.beatNum - b.beatNum; diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index f76da3d..a7179f4 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -8,9 +8,9 @@ export const Chart = types.model('Chart', { bpm: types.array(BPM), judgelines: types.array(JudgeLine), }).actions((self) => ({ - addBPM(time: BeatArray, bpm: number) { + addBPM(beat: BeatArray, bpm: number) { self.bpm.push({ - time, bpm, + beat, bpm, }); self.bpm.sort(sortBPM); diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index e43ebe8..b113028 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -24,6 +24,8 @@ export const JudgeLine = types.model('JudgeLine', { isAbove: boolean, holdEndBeat?: BeatArray ) { + console.log('addNote'); + console.log(beat); self.notes.push({ type, beat, positionX, speed, isAbove, holdEndBeat, }); diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index 4cf4e7d..bca1cb2 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -32,7 +32,7 @@ export const Note = types.model('Note', { speed: types.number, isAbove: types.boolean, - holdEndBeat: types.maybe(BeatArray), + holdEndBeat: types.optional(BeatArray, [ 0, 0, 1 ]), }).views((self) => ({ get line() { // TODO: types diff --git a/src/core/state/chartStore.ts b/src/core/state/chartStore.ts index 3db2347..218e868 100644 --- a/src/core/state/chartStore.ts +++ b/src/core/state/chartStore.ts @@ -1,5 +1,10 @@ -import { Chart, TChart } from '@/core/models/Chart'; +import { Chart, IChart } from '@/core/models/Chart'; -export const store: TChart = Chart.create({ +export const store: IChart = Chart.create({ + offset: 0, + bpm: [{ + beat: [ 0, 0, 1 ], + bpm: 120, + }], judgelines: [], }); From d0022c88e065dfc22e51fa68cb66fbbf7e83b6e4 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 24 Aug 2025 15:16:57 +0800 Subject: [PATCH 010/146] fix(core/models/Chart/BPM): Avoid double updating --- src/core/models/BPM.ts | 2 -- src/core/models/Chart.ts | 9 ++------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index 910c845..c7a2bcf 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -31,5 +31,3 @@ export const BPM = types.model('Note', { })); export type IBPM = Instance; - -export const sortBPM = (a: IBPM, b: IBPM) => a.beatNum - b.beatNum; diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index a7179f4..70be2d9 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,5 +1,5 @@ import { types, Instance } from 'mobx-state-tree'; -import { BPM, sortBPM } from './BPM'; +import { BPM } from './BPM'; import { JudgeLine } from './JudgeLine'; import { BeatArray } from '@/utils/types'; @@ -12,16 +12,11 @@ export const Chart = types.model('Chart', { self.bpm.push({ beat, bpm, }); - - self.bpm.sort(sortBPM); }, removeBPM(id: string) { const index = self.bpm.findIndex(e => e.id === id); - if (index >= 0) { - self.bpm.splice(index, 1); - self.bpm.sort(sortBPM); - } + if (index >= 0) self.bpm.splice(index, 1); }, addJudgeLine() { From 9184b772ae2437d138111fb9f8092e3da5156e67 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 25 Aug 2025 19:53:30 +0800 Subject: [PATCH 011/146] refactor(ui/Panel/Timeline): Refactoring with MobX state --- src/core/models/Keyframe.ts | 5 + .../TimelinePanel/LeftPanel/LeftPanel.tsx | 23 ++-- src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx | 24 ++-- .../TimelinePanel/RightPanel/Keyframes.tsx | 112 +++++++++--------- .../TimelinePanel/RightPanel/KeyframesRow.tsx | 98 ++++++--------- .../TimelinePanel/RightPanel/RightPanel.tsx | 55 +++------ src/ui/Panel/TimelinePanel/Timeline.tsx | 29 ++--- src/ui/hooks/useDrag.ts | 17 ++- src/utils/math.ts | 2 + 9 files changed, 169 insertions(+), 196 deletions(-) diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 2b6d2c4..2a1e2e8 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -2,6 +2,7 @@ import { nanoid } from 'nanoid'; import { types, getParent, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; +import { BeatArray as TBeatArray } from '@/utils/types'; export const Keyframe = types.model('Keyframe', { id: types.optional(types.identifier, nanoid), @@ -20,6 +21,10 @@ export const Keyframe = types.model('Keyframe', { get beatNum() { return BeatArrayToNumber(self.beat); } +})).actions((self) => ({ + setBeat(beat: TBeatArray) { + self.beat = beat; + } })); export type IKeyframe = Instance; diff --git a/src/ui/Panel/TimelinePanel/LeftPanel/LeftPanel.tsx b/src/ui/Panel/TimelinePanel/LeftPanel/LeftPanel.tsx index feecfa5..d4e2352 100644 --- a/src/ui/Panel/TimelinePanel/LeftPanel/LeftPanel.tsx +++ b/src/ui/Panel/TimelinePanel/LeftPanel/LeftPanel.tsx @@ -1,8 +1,10 @@ import React from "react"; +import { observer } from 'mobx-react-lite'; import TimelineList from "../List/List"; import ChartJudgeline from "@/Chart/Judgeline"; import LeftPanelHead from "./Head"; import LeftPanelLine from './Line'; +import { IJudgeLine } from "@/core/models/JudgeLine"; import './styles.css'; export type TimelineLeftPanelProps = { @@ -12,7 +14,12 @@ export type TimelineLeftPanelProps = { onLineExpanded: (lineIndex: number, isExpanded: boolean) => void, }; -const TimelineLeftPanel: React.FC = ({ +const TimelineLeftPanel = observer<{ + lines: IJudgeLine[], + expandedLines: string[], + listScrolled: number, + onLineExpanded: (lineIndex: string, isExpanded: boolean) => void, +}>(({ lines, expandedLines, listScrolled, @@ -33,19 +40,19 @@ const TimelineLeftPanel: React.FC = ({ top: -listScrolled }} > - {lines.map((line, index) => { // TODO: Render line props & add right click menu - return ( // TODO: Render line props & add right click menu + onLineExpanded(index, e)} - key={line.id} + isExpanded={expandedLines.includes(line.id)} + onExpandClick={onLineExpanded} /> - })} + ))} ); -}; +}); export default TimelineLeftPanel; diff --git a/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx b/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx index eb4ce81..f32cabd 100644 --- a/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx +++ b/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx @@ -4,33 +4,31 @@ import TimelineList from '../List/List'; import TimelineListItem from '../List/Item'; import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; -import ChartJudgeline from '@/Chart/Judgeline'; +import { IJudgeLine } from '@/core/models/JudgeLine'; -export type TimelineLeftPanelLineProps = { - line: ChartJudgeline, +const TimelineLeftPanelLine: React.FC<{ + line: IJudgeLine, name: string, isExpanded: boolean, - onExpandClick: (isExpanded: boolean) => void -}; - -const TimelineLeftPanelLine: React.FC = ({ + onExpandClick: (lineIndex: string, isExpanded: boolean) => void, +}> = ({ line, name, isExpanded, onExpandClick -}: TimelineLeftPanelLineProps) => { +}) => { const [ , setSelectedItem ] = useSelectedItem()!; const handleLineClicked = useCallback(() => { - setSelectedItem((oldItem) => { - if (oldItem === null) return { line, keyframe: null, note: null }; - else return { ...oldItem, line }; - }); + // setSelectedItem((oldItem) => { + // if (oldItem === null) return { line, keyframe: null, note: null }; + // else return { ...oldItem, line }; + // }); }, [line, setSelectedItem]); return
-
{name}
diff --git a/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx b/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx index 4dabbb4..3b67ff3 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx @@ -1,30 +1,38 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { observer } from 'mobx-react-lite'; import TimelineListItem from '../List/Item'; import { useTempo } from '@/ui/contexts/Tempo'; import { useContext } from './Context'; import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import useDrag from '@/ui/hooks/useDrag'; import { setCSSProperties } from '@/utils/ui'; -import { BeatNumberToArray, GridValue, parseDoublePrecist } from '@/utils/math'; -import ChartKeyframe from '@/Chart/Keyframe'; -import { TChartJudgelineProps } from '@/Chart/JudgelineProps'; +import { BeatNumberToArray, sortByBeat, GridValue, parseDoublePrecist } from '@/utils/math'; +import { IKeyframe } from '@/core/models/Keyframe'; +import { KeyframeType } from '@/core/types'; import { BeatArray, Nullable } from '@/utils/types'; -type KeyframeProps = { - keyframe: ChartKeyframe, - time: number, +const calculateNewBeat = ( + beatNum: number, + x: number, + beatGrid: number, + tempo: number, + tempoGrid: number +) => { + let newValue = GridValue(beatNum + (x / beatGrid / tempo), tempoGrid); + if (newValue < 0) newValue = 0; + return BeatNumberToArray(newValue, tempo); +}; + +const Keyframe = observer<{ + keyframe: IKeyframe, nextTime: Nullable, onSelected: (id: string) => void, onKeyframeMove: (id: string, newBeat: BeatArray) => void, onRightClicked: (id: string) => void, -}; - -const Keyframe: React.FC = ({ +}>(({ keyframe, - time, nextTime, onSelected, - onKeyframeMove, onRightClicked, }) => { const tempo = useTempo(); @@ -32,7 +40,6 @@ const Keyframe: React.FC = ({ const tempoGrid = useMemo(() => parseDoublePrecist(1 / tempo, 6, -1), [tempo]); const beatGrid = useMemo(() => tempoGrid * scale, [tempoGrid, scale]); const [ selectedItem, ] = useSelectedItem()!; - const [ currentTime, setCurrentTime ] = useState(time); const isSelected = () => { if (selectedItem === null) return false; @@ -44,32 +51,30 @@ const Keyframe: React.FC = ({ }; }; - const calculateNewTime = useCallback((x: number) => { - let newValue = GridValue(keyframe.beatNum + (x / beatGrid / tempo), tempoGrid); - if (newValue < 0) newValue = 0; - return newValue; - }, [keyframe, beatGrid, tempo, tempoGrid]); - - const handleDragging = useCallback(({ x }: { x: number }) => { - setCurrentTime(calculateNewTime(x)); - }, [calculateNewTime]); - - const handleDragEnd = useCallback(({ x }: { x: number }) => { - const newTime = calculateNewTime(x); - - setCurrentTime(newTime); - onKeyframeMove(keyframe.id, BeatNumberToArray(newTime, tempo)); - }, [calculateNewTime, keyframe.id, onKeyframeMove, tempo]); + const handleDrag = (_: unknown, { x }: { x: number }) => { + const _grid = ( + x > 0 ? beatGrid : + x < 0 ? -beatGrid : 0 + ); + + keyframe.setBeat(calculateNewBeat( + keyframe.beatNum, + _grid, + beatGrid, + tempo, + tempoGrid + )); + }; const handleSelected = useCallback(() => { - onSelected(keyframe.id); + // onSelected(keyframe.id); }, [keyframe.id, onSelected]); const { onMouseDown } = useDrag({ allowY: false, grid: beatGrid, - onDrag: handleDragging, - onDragEnd: handleDragEnd, + onDrag: handleDrag, + // onDragEnd: handleDragEnd, onClick: handleSelected, }); @@ -78,10 +83,6 @@ const Keyframe: React.FC = ({ else return onMouseDown(e); }, [keyframe.id, onRightClicked, onMouseDown]); - useEffect(() => { - setCurrentTime(time); - }, [time]); - const className = "timeline-content-key" + (isSelected() ? " selected" : ""); return ( @@ -89,7 +90,7 @@ const Keyframe: React.FC = ({
= ({
)} ) -}; +}); -export type TimelineRightPanelKeyframesProps = { - type: keyof TChartJudgelineProps, - keyframes: ChartKeyframe[], +const TimelineRightPanelKeyframes = observer<{ + type: KeyframeType, + keyframes: IKeyframe[], timeRange: [number, number], - onKeyframeSelected: (type: keyof TChartJudgelineProps, id: string) => void, - onDoubleClick: (type: keyof TChartJudgelineProps, clickedPosX: number) => void, - onKeyframeMove: (type: keyof TChartJudgelineProps, id: string, newBeat: BeatArray) => void, - onKeyframeDeleted: (type: keyof TChartJudgelineProps, id: string) => void, -}; - -const TimelineRightPanelKeyframes: React.FC = ({ + onKeyframeSelected: (type: KeyframeType, id: string) => void, + onDoubleClick: (type: KeyframeType, clickedPosX: number) => void, + onKeyframeMove: (type: KeyframeType, id: string, newBeat: BeatArray) => void, + onKeyframeDeleted: (type: KeyframeType, id: string) => void, +}>(({ type, keyframes, timeRange, @@ -125,9 +124,11 @@ const TimelineRightPanelKeyframes: React.FC = onDoubleClick, onKeyframeMove, onKeyframeDeleted, -}: TimelineRightPanelKeyframesProps) => { +}) => { + const _keyframes = keyframes.slice().sort(sortByBeat); + const handleKeyframeSelected = useCallback((id: string) => { - onKeyframeSelected(type, id); + // onKeyframeSelected(type, id); }, [type, onKeyframeSelected]); const onRowDoubleClick = useCallback((e: React.MouseEvent) => { @@ -147,16 +148,15 @@ const TimelineRightPanelKeyframes: React.FC = const keyframesDom = useMemo(() => { const result: React.ReactNode[] = []; - for (let i = 0; i < keyframes.length; i++) { - const keyframe = keyframes[i]; + for (let i = 0; i < _keyframes.length; i++) { + const keyframe = _keyframes[i]; if (keyframe.beatNum < timeRange[0]) continue; if (keyframe.beatNum > timeRange[1]) break; result.push( = } return result; - }, [keyframes, timeRange, handleKeyframeMove, handleKeyframeSelected, handleKeyframeRightClick]); + }, [_keyframes, timeRange, handleKeyframeMove, handleKeyframeSelected, handleKeyframeRightClick]); return ( {keyframesDom} ); -}; +}); export default TimelineRightPanelKeyframes; diff --git a/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx b/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx index 9cf63ea..6a8d2b6 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx @@ -9,6 +9,8 @@ import ChartKeyframe from '@/Chart/Keyframe'; import { BeatArray, Nullable } from '@/utils/types'; import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import { BeatArrayToNumber } from '@/utils/math'; +import { IJudgeLine } from '@/core/models/JudgeLine'; +import { KeyframeType } from '@/core/types'; const getLastKeyframe = (beat: BeatArray, keyframes: ChartKeyframe[]): Nullable => { const time = BeatArrayToNumber(beat); @@ -25,21 +27,18 @@ const getLastKeyframe = (beat: BeatArray, keyframes: ChartKeyframe[]): Nullable< return null; } -type KeyframesRowProps = { - line: ChartJudgeline, +const KeyframesRow: React.FC<{ + line: IJudgeLine, isExpanded: boolean, -}; - -const KeyframesRow: React.FC = ({ +}> = ({ line, isExpanded, }) => { const tempo = useTempo(); const { scale, timeRange } = useContext(); - const [ lineProp, setLineProp ] = useState({ ...line.props }); const [ , setSelectedItem ] = useSelectedItem()!; - const onAddKeyframe = useCallback((type: keyof TChartJudgelineProps, clickedPosX: number) => { + const onAddKeyframe = useCallback((type: KeyframeType, clickedPosX: number) => { const beat = clickedPosX / scale; let beatFloor = Math.floor(beat); let beatSub = Math.round((beat - beatFloor) * tempo); @@ -50,64 +49,43 @@ const KeyframesRow: React.FC = ({ } const beatArr: BeatArray = [ beatFloor, beatSub, tempo ]; - const lastKeyframe = getLastKeyframe(beatArr, line.props[type]); - line.addKeyframe( - type, - beatArr, - lastKeyframe ? lastKeyframe.value : 0, - lastKeyframe ? lastKeyframe.continuous : false, - lastKeyframe ? lastKeyframe.easing : 0 + line.keyframes.add( + type, beatArr, 1, true, 1 ); }, [scale, tempo, line]); - const onKeyframeMove = useCallback((type: keyof TChartJudgelineProps, id: string, newBeat: BeatArray) => { - setSelectedItem((oldItem) => { - if (oldItem !== null) return { ...oldItem, keyframe: null }; - else return null; - }); - line.editKeyframe(type, id, { beat: newBeat }); + const onKeyframeMove = useCallback((type: KeyframeType, id: string, newBeat: BeatArray) => { + // setSelectedItem((oldItem) => { + // if (oldItem !== null) return { ...oldItem, keyframe: null }; + // else return null; + // }); + const keyframe = line.keyframes[type].find(e => e.id === id); + if (!keyframe) return; + + keyframe.beat = newBeat; }, [line, setSelectedItem]); - const onKeyframeDeleted = useCallback((type: keyof TChartJudgelineProps, id: string) => { + const onKeyframeDeleted = useCallback((type: KeyframeType, id: string) => { setSelectedItem((oldItem) => { if (oldItem !== null) return { ...oldItem, keyframe: null }; else return null; }); - line.deleteKeyframe(type, id); + line.keyframes.remove(type, id); }, [line, setSelectedItem]); - const handlePropsUpdate = useCallback(({ - type, - keyframes, - }: { - type: keyof TChartJudgelineProps, - keyframes: ChartKeyframe[], - }) => { - const newProp: Partial = {}; - newProp[type] = keyframes; - setLineProp({ ...lineProp, ...newProp }); - }, [lineProp]); - - const handleKeyframeSelected = useCallback((type: keyof TChartJudgelineProps, id: string) => { - const keyframe = line.findKeyframeById(type, id); + const handleKeyframeSelected = useCallback((type: KeyframeType, id: string) => { + const keyframe = line.keyframes[type].find(e => e.id === id); if (!keyframe) return; - setSelectedItem({ - line, - keyframe: { - type, id - }, - note: null, - }); + // setSelectedItem({ + // line, + // keyframe: { + // type, id + // }, + // note: null, + // }); }, [line, setSelectedItem]); - useEffect(() => { - line.events.on('props.updated', handlePropsUpdate); - return (() => { - line.events.off('props.updated', handlePropsUpdate); - }); - }, [line, handlePropsUpdate]); - const keyframesProps = { timeRange, onKeyframeSelected: handleKeyframeSelected, @@ -120,28 +98,28 @@ const KeyframesRow: React.FC = ({ {isExpanded && <> } diff --git a/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx b/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx index 7b87566..7073b68 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx @@ -1,24 +1,25 @@ import React, { useCallback, useState, useEffect, useMemo, useRef } from 'react'; +import { observer } from 'mobx-react-lite'; import Chart from '@/Chart/Chart'; -import ChartJudgeline from "@/Chart/Judgeline"; import RightPanelProvider from './Context/Provider'; import ScrollBar from '@/ui/components/ScrollBar'; import TimelineList from "../List/List"; import TimelineSeeker from './Seeker'; import RightPanelHead from './Head'; import KeyframesRow from './KeyframesRow'; +import { IJudgeLine } from '@/core/models/JudgeLine'; import './styles.css'; import useResizeEffect from '@/ui/hooks/useResizeEffect'; -export type TimelineRightPanelProps = { - lines: ChartJudgeline[], - expandedLines: number[], +const TimelineRightPanel = observer<{ + lines: IJudgeLine[], + audioOffset: number, + expandedLines: string[], listScrolled: number, onListScroll: (scrolled: number) => void, -}; - -const TimelineRightPanel: React.FC = ({ +}>(({ lines, + audioOffset, expandedLines, listScrolled, onListScroll, @@ -29,23 +30,12 @@ const TimelineRightPanel: React.FC = ({ const contentHeight = useRef(0); const listScrollRef = useRef(0); const [ timeLength, setTimeLength ] = useState(0); - const [ timeOffset, setTimeOffset ] = useState(0); const onSeeked = useCallback((time: number) => { if (!Chart.info) return; Chart.beatNum = time; }, []); - const keyframeRowMemoed = useMemo(() => { - return lines.map((line, index) => { // TODO: Render keyframes - return ; - }); - }, [lines, expandedLines]); - const updateListScroll = useCallback((_scroll: number) => { const scroll = _scroll / 100; const heightDiff = contentHeight.current - containerHeight.current; @@ -56,13 +46,9 @@ const TimelineRightPanel: React.FC = ({ useResizeEffect(({ height }) => { containerHeight.current = height; - updateListScroll(listScrollRef.current); - }, scrollContainerRef); - - useResizeEffect(({ height }) => { contentHeight.current = height; updateListScroll(listScrollRef.current); - }, scrollContentRef); + }, scrollContainerRef); useEffect(() => { const updateTimeLength = () => { @@ -78,17 +64,6 @@ const TimelineRightPanel: React.FC = ({ }); }, []); - useEffect(() => { - const updateTimeOffset = ({ offsetBeat }: { offsetBeat: number }) => { - setTimeOffset(offsetBeat); - }; - - Chart.events.on('offset.updated', updateTimeOffset); - return (() => { - Chart.events.off('offset.updated', updateTimeOffset); - }); - }); - return ( = ({ }} ref={scrollContentRef} > - {keyframeRowMemoed} + {lines.map((line) => ( + + ))}
@@ -131,6 +112,6 @@ const TimelineRightPanel: React.FC = ({ /> ) -}; +}); export default TimelineRightPanel; diff --git a/src/ui/Panel/TimelinePanel/Timeline.tsx b/src/ui/Panel/TimelinePanel/Timeline.tsx index fc6f77b..9442a23 100644 --- a/src/ui/Panel/TimelinePanel/Timeline.tsx +++ b/src/ui/Panel/TimelinePanel/Timeline.tsx @@ -1,32 +1,20 @@ -import { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import SplitPane from 'react-split-pane'; +import { store as ChartStore } from '@/core/state/chartStore'; import TimelineFooter from './Footer'; -import Chart from '@/Chart/Chart'; -import ChartJudgeline from '@/Chart/Judgeline'; import TimelineLeftPanel from './LeftPanel/LeftPanel'; import TimelineRightPanel from './RightPanel/RightPanel'; import './styles.css'; const Timeline: React.FC = () => { - const [ lineList, setLineList ] = useState([]); - const [ expandedLines, setExpandedLines ] = useState([]); + const [ expandedLines, setExpandedLines ] = useState([]); const [ listScrolled, setListScrolled ] = useState(0); - const setLineExpand = (lineId: number, isExpanded: boolean) => { + const setLineExpand = (lineId: string, isExpanded: boolean) => { if (isExpanded) setExpandedLines([ ...expandedLines, lineId ]); else setExpandedLines([ ...expandedLines.filter((e) => e !== lineId) ]); }; - useEffect(() => { - const updateLineList = (newLines: ChartJudgeline[]) => { - setLineList([ ...newLines ]); - }; - Chart.events.on('lines.updated', updateLineList); - return (() => { - Chart.events.off('lines.updated', updateLineList); - }); - }, []); - return (
@@ -42,13 +30,14 @@ const Timeline: React.FC = () => { }} > setLineExpand(id, e)} + onLineExpanded={setLineExpand} /> { leftContent={ <> diff --git a/src/ui/hooks/useDrag.ts b/src/ui/hooks/useDrag.ts index 41dbe94..bd30926 100644 --- a/src/ui/hooks/useDrag.ts +++ b/src/ui/hooks/useDrag.ts @@ -14,13 +14,19 @@ type UseDragProps = { allowX?: boolean, allowY?: boolean, onDragStart?: () => void, - onDrag?: (point: Point) => void, + onDrag?: (point: Point, direction: Point) => void, onDragEnd?: (point: Point) => void, onClick?: () => void, }; const getGrid = (grid: number | Point, type: keyof Point) => typeof grid === 'number' ? grid : grid[type]; +const getDirection = (before: number, after: number) => { + if (before < after) return 1; + if (before > after) return -1; + return 0; +}; + // Thanks to [lil.gui](https://github.com/georgealways/lil-gui/blob/master/src/NumberController.js#L140) // for the drag algorithm @@ -119,7 +125,14 @@ const useDrag = ({ lastDragPos.current.y !== dragDelta.current.y ) ) { - if (onDrag) onDrag(dragDelta.current); + if (onDrag) { + const beforePoint = lastDragPos.current || dragStartPos.current; + + onDrag(dragDelta.current, { + x: getDirection(beforePoint.x, dragDelta.current.x), + y: getDirection(beforePoint.y, dragDelta.current.y) + }); + } lastDragPos.current = { ...dragDelta.current }; } } diff --git a/src/utils/math.ts b/src/utils/math.ts index b94c13d..1414106 100644 --- a/src/utils/math.ts +++ b/src/utils/math.ts @@ -22,6 +22,8 @@ export const BeatNumberToArray = (beat: number, tempo: number): BeatArray => { return [ beatFloor, beatSub, tempo ]; }; +export const sortByBeat = (a: { beat: BeatArray }, b: { beat: BeatArray }) => BeatArrayToNumber(a.beat) - BeatArrayToNumber(b.beat); + export const GridValue = (value: number, grid: number) => ( Math.round(value / grid) * grid ); From 8b87d3053862b1afb12031d196ec0edcc32ab913 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 26 Aug 2025 15:54:30 +0800 Subject: [PATCH 012/146] refactor(ui/Panel/BPMPanel): Refactoring with MobX state --- src/core/models/BPM.ts | 9 ++++++ src/core/models/Chart.ts | 4 +++ src/ui/Panel/BPMPanel/BPMPanel.tsx | 49 ++++++++---------------------- src/ui/Panel/BPMPanel/Item.tsx | 29 ++++++++---------- src/ui/Panel/BPMPanel/List.tsx | 27 ++++++---------- 5 files changed, 49 insertions(+), 69 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index c7a2bcf..65dd434 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -2,6 +2,7 @@ import { nanoid } from 'nanoid'; import { types, Instance } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; +import { BeatArray as TBeatArray } from '@/utils/types'; const BPMNumber = types.custom({ name: 'BPMNumber', @@ -28,6 +29,14 @@ export const BPM = types.model('Note', { get beatNum() { return BeatArrayToNumber(self.beat); } +})).actions((self) => ({ + updateBeat(beat: TBeatArray) { + self.beat = beat; + }, + + updateBPM(bpm: number) { + self.bpm = bpm; + } })); export type IBPM = Instance; diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index 70be2d9..b283827 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -8,6 +8,10 @@ export const Chart = types.model('Chart', { bpm: types.array(BPM), judgelines: types.array(JudgeLine), }).actions((self) => ({ + updateOffset(offset: number) { + self.offset = offset; + }, + addBPM(beat: BeatArray, bpm: number) { self.bpm.push({ beat, bpm, diff --git a/src/ui/Panel/BPMPanel/BPMPanel.tsx b/src/ui/Panel/BPMPanel/BPMPanel.tsx index 01098ae..452f5cf 100644 --- a/src/ui/Panel/BPMPanel/BPMPanel.tsx +++ b/src/ui/Panel/BPMPanel/BPMPanel.tsx @@ -1,49 +1,26 @@ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback } from 'react'; +import { observer } from 'mobx-react-lite'; import { useTranslation } from 'react-i18next'; -import Chart from '@/Chart/Chart'; -import ChartBPM from '@/Chart/BPM'; -import './styles.css'; +import { store as ChartStore } from '@/core/state/chartStore'; import BPMList from './List'; -import { BeatArray } from '@/utils/types'; import NumberInput from '@/ui/components/NumberInput'; +import './styles.css'; +import { BeatArray } from '@/utils/types'; -const BPMPanel = () => { +const BPMPanel = observer(() => { const { t } = useTranslation(); - const [ defaultOffset, setDefaultOffset ] = useState(0); - const [ bpmList, setBPMList ] = useState(Chart.info !== null ? [ ...Chart.bpm ] : []); const handleOffsetUpdate = (value: number) => { - if (!Chart.info) return; - Chart.offset = value; + ChartStore.updateOffset(value); }; - const handleBPMUpdate = useCallback(() => { - setBPMList([ ...Chart.bpm ]); - }, []); - - const handleChartSet = useCallback(() => { - setDefaultOffset(Chart.offset); - handleBPMUpdate(); - }, [handleBPMUpdate]); - const handleAddBPM = useCallback(() => { - if (!Chart.info) return; - const lastBPM = Chart.bpm[Chart.bpm.length - 1]; - const newBeat: BeatArray = [ ...lastBPM.beat ]; + const lastBPM = ChartStore.bpm[ChartStore.bpm.length - 1]; + const newBeat = [ ...lastBPM.beat ] as BeatArray; newBeat[0] += 1; - Chart.addBPM(newBeat, lastBPM.bpm); + ChartStore.addBPM(newBeat, lastBPM.bpm); }, []); - useEffect(() => { - Chart.events.on('loaded', handleChartSet); - Chart.events.on('bpms.updated', handleBPMUpdate); - - return (() => { - Chart.events.off('loaded', handleChartSet); - Chart.events.off('bpms.updated', handleBPMUpdate); - }); - }, [handleChartSet, handleBPMUpdate]); - return (
@@ -52,18 +29,18 @@ const BPMPanel = () => {
- +
); -}; +}); export default BPMPanel; diff --git a/src/ui/Panel/BPMPanel/Item.tsx b/src/ui/Panel/BPMPanel/Item.tsx index 7203e26..5f4f798 100644 --- a/src/ui/Panel/BPMPanel/Item.tsx +++ b/src/ui/Panel/BPMPanel/Item.tsx @@ -1,31 +1,28 @@ -import Chart from '@/Chart/Chart'; -import ChartBPM from "@/Chart/BPM"; +import { observer } from 'mobx-react-lite'; +import { store as ChartStore } from '@/core/state/chartStore'; import BeatInput from '@/ui/components/BeatInput'; import NumberInput from '@/ui/components/NumberInput'; -import { useCallback } from "react"; import { useTranslation } from 'react-i18next'; import { BeatArray } from "@/utils/types"; import { Button } from "@blueprintjs/core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; +import { IBPM } from '@/core/models/BPM'; -type BPMListItemProps = { - bpm: ChartBPM, - onChanged: (beat?: BeatArray, bpm?: number) => void, -}; - -const BPMListItem = ({ +const BPMListItem = observer<{ + bpm: IBPM, +}>(({ bpm, - onChanged, -}: BPMListItemProps) => { +}) => { const { t } = useTranslation(); - const handleUpdate = useCallback((beat?: BeatArray, bpm?: number) => { - onChanged(beat, bpm); - }, [onChanged]); + const handleUpdate = (newBeat?: BeatArray, newBPM?: number) => { + if (newBeat) bpm.updateBeat(newBeat); + if (newBPM) bpm.updateBPM(newBPM); + }; const handleDelete = () => { - Chart.removeBPM(bpm.id); + ChartStore.removeBPM(bpm.id); }; return ( @@ -61,6 +58,6 @@ const BPMListItem = ({
) -}; +}); export default BPMListItem; diff --git a/src/ui/Panel/BPMPanel/List.tsx b/src/ui/Panel/BPMPanel/List.tsx index a586677..08813f0 100644 --- a/src/ui/Panel/BPMPanel/List.tsx +++ b/src/ui/Panel/BPMPanel/List.tsx @@ -1,32 +1,25 @@ -import { useCallback } from "react"; -import Chart from '@/Chart/Chart'; -import ChartBPM from "@/Chart/BPM"; +import { observer } from "mobx-react-lite"; import BPMListItem from "./Item"; -import { BeatArray } from "@/utils/types"; +import { sortByBeat } from "@/utils/math"; +import { IBPM } from "@/core/models/BPM"; -type BPMListProps = { - bpms: ChartBPM[], -}; - -const BPMList = ({ +const BPMList = observer<{ + bpms: IBPM[], +}>(({ bpms -}: BPMListProps) => { - const handleBPMChanged = useCallback((id: string, beat?: BeatArray, bpm?: number) => { - if (!Chart.info) return; - Chart.editBPM(id, beat, bpm); - }, []); +}) => { + const bpmList = bpms.slice().sort(sortByBeat); return (
- {bpms.map((bpm) => ( + {bpmList.map((bpm) => ( handleBPMChanged(bpm.id, newBeat, newBPM)} key={bpm.id} /> ))}
); -}; +}); export default BPMList; From 4cb2216315970b00d89c0e54ebbdd848697e41b0 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 26 Aug 2025 20:14:39 +0800 Subject: [PATCH 013/146] refactor(ui/Panel/NotePanel): Refactoring with MobX state --- src/core/models/Chart.ts | 35 ++- src/core/models/JudgeLine.ts | 25 +- src/core/models/Note.ts | 21 +- src/ui/Panel/NotePanel/Grid.tsx | 12 +- .../NotePanel/NoteContainer/NoteContainer.tsx | 18 +- .../NotePanel/NoteContainer/NoteGraphics.tsx | 245 ++++++++---------- .../Panel/NotePanel/NoteContainer/useWrite.ts | 4 +- src/ui/Panel/NotePanel/NotePanel.tsx | 13 +- src/ui/Panel/NotePanel/styles.css | 9 + src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx | 15 +- .../TimelinePanel/RightPanel/Keyframes.tsx | 48 +--- .../TimelinePanel/RightPanel/KeyframesRow.tsx | 49 +--- 12 files changed, 226 insertions(+), 268 deletions(-) diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index b283827..87091c2 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,12 +1,18 @@ import { types, Instance } from 'mobx-state-tree'; import { BPM } from './BPM'; -import { JudgeLine } from './JudgeLine'; -import { BeatArray } from '@/utils/types'; +import { JudgeLine, IJudgeLine } from './JudgeLine'; +import { IKeyframe, Keyframe } from './Keyframe'; +import { INote, Note } from './Note'; +import { BeatArray, Nullable } from '@/utils/types'; export const Chart = types.model('Chart', { offset: types.number, bpm: types.array(BPM), judgelines: types.array(JudgeLine), + + selectedLine: types.maybeNull(types.reference(JudgeLine)), + selectedKeyframe: types.maybeNull(types.reference(Keyframe)), + selectedNote: types.maybeNull(types.reference(Note)) }).actions((self) => ({ updateOffset(offset: number) { self.offset = offset; @@ -30,6 +36,31 @@ export const Chart = types.model('Chart', { removeJudgeLine(id: string) { const index = self.judgelines.findIndex(e => e.id === id); if (index >= 0) self.judgelines.splice(index, 1); + }, + + setSelectedLine(line: Nullable) { + self.selectedLine = line; + + if (self.selectedKeyframe) self.selectedKeyframe = null; + if (self.selectedNote) self.selectedNote = null; + }, + + setSelectedKeyframe(keyframe: Nullable) { + self.selectedKeyframe = keyframe; + + if (keyframe !== null) { + const keyframeLine = keyframe.line as IJudgeLine; + if (!self.selectedLine || self.selectedLine.id !== keyframeLine.id) self.selectedLine = keyframeLine; + } + }, + + setSelectedNote(note: Nullable) { + self.selectedNote = note; + + if (note !== null) { + const noteLine = note.line as IJudgeLine; + if (!self.selectedLine || self.selectedLine.id !== noteLine.id) self.selectedLine = noteLine; + } } })); diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index b113028..a67eab1 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -2,8 +2,7 @@ import { nanoid } from 'nanoid'; import { types, Instance } from 'mobx-state-tree'; import { KeyframeRecord } from './KeyframeRecord'; import { Note } from './Note'; -import { BeatArray } from '@/utils/types'; -import { NoteType } from '@/Chart/types'; +import { SnapshotIn } from 'mobx-state-tree'; export const JudgeLine = types.model('JudgeLine', { id: types.optional(types.identifier, nanoid), @@ -16,19 +15,15 @@ export const JudgeLine = types.model('JudgeLine', { }), notes: types.optional(types.array(Note), []), }).actions((self) => ({ - addNote( - type: NoteType, - beat: BeatArray, - positionX: number, - speed: number, - isAbove: boolean, - holdEndBeat?: BeatArray - ) { - console.log('addNote'); - console.log(beat); - self.notes.push({ - type, beat, positionX, speed, isAbove, holdEndBeat, - }); + addNote(props: SnapshotIn) { + self.notes.push(props); + }, + + editNote(id: string, props: Partial, 'id'>>) { + const note = self.notes.find(e => e.id === id); + if (!note) return; + + note.updateProps(props); }, removeNote(id: string) { diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index bca1cb2..79ba0cb 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -1,8 +1,9 @@ import { nanoid } from 'nanoid'; -import { types, getParent, Instance } from 'mobx-state-tree'; +import { types, getParent, Instance, SnapshotIn } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; import { NoteType as ENoteType } from '@/Chart/types'; +import { BeatArray as TBeatArray } from '@/utils/types'; const NoteType = types.custom({ name: 'NoteType', @@ -33,6 +34,13 @@ export const Note = types.model('Note', { isAbove: types.boolean, holdEndBeat: types.optional(BeatArray, [ 0, 0, 1 ]), +}).postProcessSnapshot((self) => { + if ( + self.holdEndBeat && + BeatArrayToNumber(self.beat as TBeatArray) > BeatArrayToNumber(self.holdEndBeat as TBeatArray) + ) { + self.holdEndBeat = self.beat; + } }).views((self) => ({ get line() { // TODO: types @@ -44,8 +52,17 @@ export const Note = types.model('Note', { }, get holdEndBeatNum() { - if (!self.holdEndBeat) return null; + if (self.type !== ENoteType.HOLD || !self.holdEndBeat) return BeatArrayToNumber(self.beat); return BeatArrayToNumber(self.holdEndBeat); + }, + + get holdLengthBeatNum() { + if (self.type !== ENoteType.HOLD || !self.holdEndBeat) return 0; + return BeatArrayToNumber(self.holdEndBeat) - BeatArrayToNumber(self.beat); + } +})).actions((self) => ({ + updateProps(props: Omit>, 'id'>) { + Object.assign(self, props); } })); diff --git a/src/ui/Panel/NotePanel/Grid.tsx b/src/ui/Panel/NotePanel/Grid.tsx index 962940c..76b2973 100644 --- a/src/ui/Panel/NotePanel/Grid.tsx +++ b/src/ui/Panel/NotePanel/Grid.tsx @@ -1,23 +1,23 @@ import { useTranslation } from "react-i18next"; -import { useSelectedItem } from "../../contexts/SelectedItem"; +import { observer } from "mobx-react-lite"; +import { store as ChartStore } from '@/core/state/chartStore'; import GridAlignScale from "./AlignScale"; import NoteContainer from "./NoteContainer/NoteContainer"; -const Grid = () => { +const Grid = observer(() => { const { t } = useTranslation(); - const [ selectedItem, ] = useSelectedItem()!; return (
- - {!selectedItem && ( + + {!ChartStore.selectedLine && (
{t('note_panel.no_line_selected')}
)}
); -}; +}); export default Grid; diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx index 114b9a7..dc10aab 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx @@ -3,25 +3,25 @@ import { Application, ApplicationRef, extend } from '@pixi/react'; import { Container, Rectangle, Sprite, Texture } from 'pixi.js'; import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import useResizeEffect from '@/ui/hooks/useResizeEffect'; -import ChartJudgeline from '@/Chart/Judgeline'; import useTimeRange from './TimeRange'; import BeatGraphics from './BeatGraphics'; import NoteGraphics from './NoteGraphics'; import { BeatArray, Nullable } from '@/utils/types'; +import { IJudgeLine } from '@/core/models/JudgeLine'; +import { Note } from '@/core/models/Note'; import { useProps } from '../PropsContext'; import useWrite from './useWrite'; import { ChartNoteProps } from '@/Chart/Note'; import useWheel from './useWheel'; +import { SnapshotIn } from 'mobx-state-tree'; const NOTE_OFFSET = 50; -type NoteContainerProps = { - line: Nullable, -}; - -const NoteContainer = ({ +const NoteContainer: React.FC<{ + line: Nullable, +}> = ({ line, -}: NoteContainerProps) => { +}) => { extend({ Container, Sprite }); const { scale, writeMode } = useProps(); @@ -68,9 +68,9 @@ const NoteContainer = ({ }); }, [setSelectedItem]); - const handleHoldAddStart = useCallback((props: Omit, id: string) => { + const handleHoldAddStart = useCallback((props: SnapshotIn, id: string) => { if (!line) return; - line.addNote(props, id); + line.addNote({ id, ...props }); }, [line]); const handleHoldAdding = useCallback((props: { holdEndBeat: BeatArray }, id: string) => { diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx index fb48c4d..6e9077f 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx @@ -1,16 +1,18 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { extend } from '@pixi/react'; import { Container, EventMode, Sprite, Texture } from 'pixi.js'; +import { observer } from 'mobx-react-lite'; +import { store as ChartStore } from '@/core/state/chartStore'; import { useClockTime } from '@/ui/contexts/Clock'; -import ChartJudgeline from '@/Chart/Judgeline'; import { NoteType } from '@/Chart/types'; -import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import useDrag from '@/ui/hooks/useDrag'; import { useTempo } from '@/ui/contexts/Tempo'; import { useProps } from '../PropsContext'; -import ChartNote from '@/Chart/Note'; -import { BeatArray, Point } from '@/utils/types'; -import { BeatNumberToArray, GridValue } from '@/utils/math'; +import { IJudgeLine } from '@/core/models/JudgeLine'; +import { Note as NoteModel, INote } from '@/core/models/Note'; +import { Point } from '@/utils/types'; +import { BeatNumberToArray, GridValue, sortByBeat } from '@/utils/math'; +import { SnapshotIn } from 'mobx-state-tree'; const NOTE_SCALE = 5000; @@ -20,82 +22,104 @@ const getNoteTexture = (type: NoteType) => { else return 'note-tap'; }; -type NoteProps = { - note: ChartNote, - type: NoteType, - beat: number, +const calculateNewTime = ( + beatNum: number, + y: number, + beatGrid: number, + tempo: number, + tempoGrid: number +) => { + return GridValue(beatNum - (y / beatGrid / tempo), tempoGrid); +}; + +const calculateNewPositionX = ( positionX: number, - holdLength: number, - width: number, - scale: number, - noteScale: number, - onChanged: (id: string, time: BeatArray, timeEnd: BeatArray, positionX: number) => void, - onSelected: (id: string) => void, - onRightClicked: (id: string) => void, + x: number, + widthHalf: number, + alignPercent: number, +) => { + const newValue = GridValue((100 + positionX + (x / widthHalf * 100)) / 2, alignPercent * 100); + return (newValue - 50) * 2; }; -const Note = React.memo(function Note ({ +const Note = observer<{ + note: INote, + widthHalf: number, + scale: number, + noteScale: number, + tempoGrid: number, + beatGrid: number, + alignPercent: number, + alignGrid: number, +}>(({ note, - type, - beat, - positionX, - holdLength, - width, + widthHalf, scale, noteScale, - onChanged, - onSelected, - onRightClicked, -}: NoteProps) { + tempoGrid, + beatGrid, + alignPercent, + alignGrid +}) => { extend({ Container, Sprite }); - const widthHalf = useMemo(() => width / 2, [width]); const tempo = useTempo(); - const { align, writeMode } = useProps(); - const tempoGrid = useMemo(() => 1 / tempo, [tempo]); - const beatGrid = useMemo(() => tempoGrid * scale, [tempoGrid, scale]); - const alignPercent = useMemo(() => 1 / align, [align]); - const alignGrid = useMemo(() => width * alignPercent, [width, alignPercent]); + const { writeMode } = useProps(); const [isDragging, setIsDragging] = useState(false); - const [ time, setTime ] = useState(beat); - const [ posX, setPosX ] = useState(positionX); - const notePosX = (posX / 100) * widthHalf + widthHalf; - const notePosY = time * -scale; - const noteLength = holdLength * scale / noteScale; - - const calculateNewTime = useCallback((y: number) => { - return GridValue(beat - (y / beatGrid / tempo), tempoGrid); - }, [beat, beatGrid, tempo, tempoGrid]); - - const calculateNewPositionX = useCallback((x: number) => { - const newValue = GridValue((100 + positionX + (x / widthHalf * 100)) / 2, alignPercent * 100); - return (newValue - 50) * 2; - }, [positionX, widthHalf, alignPercent]); - - const handleDragging = useCallback(({ x, y }: Point) => { - setTime(calculateNewTime(y)); - setPosX(calculateNewPositionX(x)); - setIsDragging(true); - }, [calculateNewPositionX, calculateNewTime]); + const notePosX = (note.positionX / 100) * widthHalf + widthHalf; + const notePosY = note.beatNum * -scale; + const noteLength = note.holdLengthBeatNum * scale / noteScale; + + const handleDragging = (_: unknown, { x, y }: Point) => { + const positionXGrid = ( + x > 0 ? alignGrid : + x < 0 ? -alignGrid : 0 + ); + const timeGrid = ( + y > 0 ? beatGrid : + y < 0 ? -beatGrid : 0 + ); - const handleDragEnd = useCallback(({ x, y }: Point) => { - const newTime = calculateNewTime(y); - const newPosX = calculateNewPositionX(x); - const newHoldEnd = note.holdEndBeatNum + (newTime - beat); + const updatedProps: Omit>, 'id'> = {}; + + if (positionXGrid !== 0) + updatedProps.positionX = calculateNewPositionX( + note.positionX, + positionXGrid, + widthHalf, + alignPercent + ); + if (timeGrid !== 0) { + const newTime = calculateNewTime( + note.beatNum, + timeGrid, + beatGrid, + tempo, + tempoGrid + ); + const newHoldEnd = note.holdEndBeatNum + (newTime - note.beatNum); + + updatedProps.beat = BeatNumberToArray(newTime, tempo); + updatedProps.holdEndBeat = BeatNumberToArray(newHoldEnd, tempo); + } - setTime(newTime); - setPosX(newPosX); + note.updateProps(updatedProps); + setIsDragging(true); + }; + + const handleDragEnd = () => { setIsDragging(false); - onChanged(note.id, BeatNumberToArray(newTime, tempo), BeatNumberToArray(newHoldEnd, tempo), newPosX); - }, [note.holdEndBeatNum, beat, note.id, onChanged, tempo, calculateNewTime, calculateNewPositionX]); + }; - const handleClicked = useCallback(() => { - onSelected(note.id); - }, [onSelected, note.id]); + const handleClicked = () => { + ChartStore.setSelectedNote(note); + }; - const handleRightClicked = useCallback(() => { - onRightClicked(note.id); - }, [note.id, onRightClicked]); + const handleRightClicked = () => { + const line = note.line as IJudgeLine; + line.removeNote(note.id); + ChartStore.setSelectedNote(null); + }; const { onMouseDown } = useDrag({ grid: { @@ -107,11 +131,6 @@ const Note = React.memo(function Note ({ onClick: handleClicked, }); - useEffect(() => { - setTime(beat); - setPosX(positionX); - }, [beat, positionX]); - const noteEventProps = { x: notePosX, y: notePosY, @@ -124,9 +143,9 @@ const Note = React.memo(function Note ({ }; return (<> - {type !== NoteType.HOLD ? ( + {note.type !== NoteType.HOLD ? ( @@ -153,70 +172,36 @@ const Note = React.memo(function Note ({ ); }); -type NoteGraphicsProps = { +const NoteGraphics = observer<{ timeRangeEnd: number, scale: number, width: number, - line: ChartJudgeline, + line: IJudgeLine, timeOffset?: number, -}; - -const NoteGraphics = ({ +}>(({ timeRangeEnd, scale, width, line, timeOffset = 0 -}: NoteGraphicsProps) => { +}) => { extend({ Container }); - const [ notes, setNotes ] = useState([ ...line.notes ]); - const [ , setSelectedItem ] = useSelectedItem()!; + const notes = line.notes.slice().sort(sortByBeat); + // TODO: Move all rendering props to React.Context (create a context for note panel) const noteScale = width / NOTE_SCALE; + const widthHalf = useMemo(() => width / 2, [width]); + const tempo = useTempo(); + const { align } = useProps(); + const tempoGrid = useMemo(() => 1 / tempo, [tempo]); + const beatGrid = useMemo(() => tempoGrid * scale, [tempoGrid, scale]); + const alignPercent = useMemo(() => 1 / align, [align]); + const alignGrid = useMemo(() => width * alignPercent, [width, alignPercent]); + const currentTime = useClockTime().beat - timeOffset; const timeRange = timeRangeEnd + currentTime; - const handleNoteChanged = useCallback((id: string, time: BeatArray, timeEnd: BeatArray, positionX: number) => { - line.editNote( - id, - { - beat: time, - positionX, - holdEndBeat: timeEnd, - } - ); - }, [line]); - - const handleNoteSelected = useCallback((id: string) => { - setSelectedItem({ - line, - note: { - id, - }, - keyframe: null, - }); - }, [line, setSelectedItem]); - - const updateNote = useCallback((notes: ChartNote[]) => { - setNotes(notes); - }, []); - - const handleNoteDeleted = useCallback((id: string) => { - setSelectedItem((oldItem) => { - if (oldItem !== null) return { ...oldItem, note: null }; - else return null; - }) - line.deleteNote(id); - }, [line, setSelectedItem]); - - useEffect(() => { - line.events.on('notes.updated', updateNote); - return (() => { - line.events.off('notes.updated', updateNote); - }); - }, [line, updateNote]); - const noteSprites = (() => { const result = []; @@ -227,16 +212,14 @@ const NoteGraphics = ({ result.push( ); @@ -250,6 +233,6 @@ const NoteGraphics = ({ {noteSprites} ); -}; +}); export default React.memo(NoteGraphics); diff --git a/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts b/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts index dfad372..47b4448 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts +++ b/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts @@ -1,5 +1,5 @@ import { useCallback, useMemo, useRef } from 'react'; -import { v4 as uuid } from 'uuid'; +import { nanoid } from 'nanoid'; import Chart from '@/Chart/Chart'; import { useProps } from '../PropsContext'; import { useTempo } from '@/ui/contexts/Tempo'; @@ -97,7 +97,7 @@ const useWrite = ({ } else { if (holdPropRef.current === null) { const { clientX, clientY } = e; - const holdID = uuid(); + const holdID = nanoid(); const holdProps = { type: NoteType.HOLD, beat: BeatNumberToArray(beatNum, tempo), diff --git a/src/ui/Panel/NotePanel/NotePanel.tsx b/src/ui/Panel/NotePanel/NotePanel.tsx index 784687c..1541c81 100644 --- a/src/ui/Panel/NotePanel/NotePanel.tsx +++ b/src/ui/Panel/NotePanel/NotePanel.tsx @@ -1,31 +1,28 @@ import { ChangeEvent, useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { store as ChartStore } from '@/core/state/chartStore'; import Grid from './Grid'; import './styles.css'; import PropsContext from './PropsContext'; -import { useSelectedItem } from '../../contexts/SelectedItem'; import { Nullable } from '@/utils/types'; import { NoteType } from '@/Chart/types'; import NumberInput from '@/ui/components/NumberInput'; const NotePanel = () => { const { t } = useTranslation(); - const [, setSelectedItem ] = useSelectedItem()!; const [ writeMode, setWriteMode ] = useState>(null); const [ scale, setScale ] = useState(200); const [ alignCount, setAlighCount ] = useState(8); - const updateWriteMode = useCallback((e: ChangeEvent) => { + const updateWriteMode = (e: ChangeEvent) => { const newMode = parseInt(e.target.value) as (NoteType | -1); if (newMode === -1) setWriteMode(null); else { setWriteMode(newMode); - setSelectedItem((oldItem) => { - if (oldItem !== null) return { ...oldItem, keyframe: null , note: null }; - else return null; - }); + if (ChartStore.selectedNote) ChartStore.setSelectedNote(null); + if (ChartStore.selectedKeyframe) ChartStore.setSelectedKeyframe(null); } - }, [setSelectedItem]); + }; const updateScale = useCallback((scale: number) => { setScale(10 + (scale / 100) * 390); diff --git a/src/ui/Panel/NotePanel/styles.css b/src/ui/Panel/NotePanel/styles.css index d35aa80..8befc7b 100644 --- a/src/ui/Panel/NotePanel/styles.css +++ b/src/ui/Panel/NotePanel/styles.css @@ -25,6 +25,15 @@ overflow: hidden; } +.note-grid-placeholder { + display: block; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2; +} + .note-grid-scale { position: absolute; top: 0; diff --git a/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx b/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx index f32cabd..81cedc0 100644 --- a/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx +++ b/src/ui/Panel/TimelinePanel/LeftPanel/Line.tsx @@ -1,8 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import React, { useCallback } from 'react'; +import React from 'react'; +import { store as ChartStore } from '@/core/state/chartStore'; import TimelineList from '../List/List'; import TimelineListItem from '../List/Item'; -import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; import { IJudgeLine } from '@/core/models/JudgeLine'; @@ -17,14 +17,9 @@ const TimelineLeftPanelLine: React.FC<{ isExpanded, onExpandClick }) => { - const [ , setSelectedItem ] = useSelectedItem()!; - - const handleLineClicked = useCallback(() => { - // setSelectedItem((oldItem) => { - // if (oldItem === null) return { line, keyframe: null, note: null }; - // else return { ...oldItem, line }; - // }); - }, [line, setSelectedItem]); + const handleLineClicked = () => { + ChartStore.setSelectedLine(line); + }; return
diff --git a/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx b/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx index 3b67ff3..ce57004 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/Keyframes.tsx @@ -1,15 +1,15 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { observer } from 'mobx-react-lite'; +import { store as ChartStore } from '@/core/state/chartStore'; import TimelineListItem from '../List/Item'; import { useTempo } from '@/ui/contexts/Tempo'; import { useContext } from './Context'; -import { useSelectedItem } from '@/ui/contexts/SelectedItem'; import useDrag from '@/ui/hooks/useDrag'; import { setCSSProperties } from '@/utils/ui'; import { BeatNumberToArray, sortByBeat, GridValue, parseDoublePrecist } from '@/utils/math'; import { IKeyframe } from '@/core/models/Keyframe'; import { KeyframeType } from '@/core/types'; -import { BeatArray, Nullable } from '@/utils/types'; +import { Nullable } from '@/utils/types'; const calculateNewBeat = ( beatNum: number, @@ -23,33 +23,23 @@ const calculateNewBeat = ( return BeatNumberToArray(newValue, tempo); }; +const isKeyframeSelected = (id: string) => ( + ChartStore.selectedKeyframe && ChartStore.selectedKeyframe.id === id +); + const Keyframe = observer<{ keyframe: IKeyframe, nextTime: Nullable, - onSelected: (id: string) => void, - onKeyframeMove: (id: string, newBeat: BeatArray) => void, onRightClicked: (id: string) => void, }>(({ keyframe, nextTime, - onSelected, onRightClicked, }) => { const tempo = useTempo(); const { scale } = useContext(); const tempoGrid = useMemo(() => parseDoublePrecist(1 / tempo, 6, -1), [tempo]); const beatGrid = useMemo(() => tempoGrid * scale, [tempoGrid, scale]); - const [ selectedItem, ] = useSelectedItem()!; - - const isSelected = () => { - if (selectedItem === null) return false; - if (selectedItem.keyframe === null) return false; - if (selectedItem.keyframe instanceof Array) { - return selectedItem.keyframe.findIndex((e) => e.id === keyframe.id) !== -1; - } else { - return selectedItem.keyframe.id === keyframe.id; - }; - }; const handleDrag = (_: unknown, { x }: { x: number }) => { const _grid = ( @@ -66,9 +56,9 @@ const Keyframe = observer<{ )); }; - const handleSelected = useCallback(() => { - // onSelected(keyframe.id); - }, [keyframe.id, onSelected]); + const handleSelected = () => { + ChartStore.setSelectedKeyframe(keyframe); + }; const { onMouseDown } = useDrag({ allowY: false, @@ -83,7 +73,7 @@ const Keyframe = observer<{ else return onMouseDown(e); }, [keyframe.id, onRightClicked, onMouseDown]); - const className = "timeline-content-key" + (isSelected() ? " selected" : ""); + const className = "timeline-content-key" + (isKeyframeSelected(keyframe.id) ? " selected" : ""); return ( <> @@ -112,35 +102,23 @@ const TimelineRightPanelKeyframes = observer<{ type: KeyframeType, keyframes: IKeyframe[], timeRange: [number, number], - onKeyframeSelected: (type: KeyframeType, id: string) => void, onDoubleClick: (type: KeyframeType, clickedPosX: number) => void, - onKeyframeMove: (type: KeyframeType, id: string, newBeat: BeatArray) => void, onKeyframeDeleted: (type: KeyframeType, id: string) => void, }>(({ type, keyframes, timeRange, - onKeyframeSelected, onDoubleClick, - onKeyframeMove, onKeyframeDeleted, }) => { const _keyframes = keyframes.slice().sort(sortByBeat); - const handleKeyframeSelected = useCallback((id: string) => { - // onKeyframeSelected(type, id); - }, [type, onKeyframeSelected]); - const onRowDoubleClick = useCallback((e: React.MouseEvent) => { const target = e.target as HTMLDivElement; const rect = target.getBoundingClientRect(); onDoubleClick(type, e.clientX - rect.x); }, [type, onDoubleClick]); - const handleKeyframeMove = useCallback((id: string, newBeat: BeatArray) => { - onKeyframeMove(type, id, newBeat); - }, [type, onKeyframeMove]); - const handleKeyframeRightClick = useCallback((id: string) => { onKeyframeDeleted(type, id); }, [type, onKeyframeDeleted]); @@ -157,8 +135,6 @@ const TimelineRightPanelKeyframes = observer<{ @@ -166,7 +142,7 @@ const TimelineRightPanelKeyframes = observer<{ } return result; - }, [_keyframes, timeRange, handleKeyframeMove, handleKeyframeSelected, handleKeyframeRightClick]); + }, [_keyframes, timeRange, handleKeyframeRightClick]); return ( diff --git a/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx b/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx index 6a8d2b6..08834af 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/KeyframesRow.tsx @@ -1,32 +1,13 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback } from 'react'; import TimelineListItem from '../List/Item'; import Keyframes from './Keyframes'; import { useTempo } from '@/ui/contexts/Tempo'; import { useContext } from './Context'; -import ChartJudgeline from '@/Chart/Judgeline'; -import { TChartJudgelineProps } from '@/Chart/JudgelineProps'; -import ChartKeyframe from '@/Chart/Keyframe'; -import { BeatArray, Nullable } from '@/utils/types'; +import { BeatArray } from '@/utils/types'; import { useSelectedItem } from '@/ui/contexts/SelectedItem'; -import { BeatArrayToNumber } from '@/utils/math'; import { IJudgeLine } from '@/core/models/JudgeLine'; import { KeyframeType } from '@/core/types'; -const getLastKeyframe = (beat: BeatArray, keyframes: ChartKeyframe[]): Nullable => { - const time = BeatArrayToNumber(beat); - - for (let i = 0; i < keyframes.length; i++) { - const keyframe = keyframes[i]; - if (keyframe.beatNum < time) continue; - if (keyframe.beatNum > time) { - if (i === 0) break; - return keyframes[i - 1]; - } - } - - return null; -} - const KeyframesRow: React.FC<{ line: IJudgeLine, isExpanded: boolean, @@ -54,17 +35,6 @@ const KeyframesRow: React.FC<{ ); }, [scale, tempo, line]); - const onKeyframeMove = useCallback((type: KeyframeType, id: string, newBeat: BeatArray) => { - // setSelectedItem((oldItem) => { - // if (oldItem !== null) return { ...oldItem, keyframe: null }; - // else return null; - // }); - const keyframe = line.keyframes[type].find(e => e.id === id); - if (!keyframe) return; - - keyframe.beat = newBeat; - }, [line, setSelectedItem]); - const onKeyframeDeleted = useCallback((type: KeyframeType, id: string) => { setSelectedItem((oldItem) => { if (oldItem !== null) return { ...oldItem, keyframe: null }; @@ -73,24 +43,9 @@ const KeyframesRow: React.FC<{ line.keyframes.remove(type, id); }, [line, setSelectedItem]); - const handleKeyframeSelected = useCallback((type: KeyframeType, id: string) => { - const keyframe = line.keyframes[type].find(e => e.id === id); - if (!keyframe) return; - - // setSelectedItem({ - // line, - // keyframe: { - // type, id - // }, - // note: null, - // }); - }, [line, setSelectedItem]); - const keyframesProps = { timeRange, - onKeyframeSelected: handleKeyframeSelected, onDoubleClick: onAddKeyframe, - onKeyframeMove, onKeyframeDeleted, }; From 9269b9bf0b53dc925948e249fe589c8431083ce0 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Wed, 27 Aug 2025 17:50:23 +0800 Subject: [PATCH 014/146] refactor(ui/Panel/EditPanel): Refactoring with MobX state --- src/core/models/JudgeLine.ts | 8 +- src/core/models/Keyframe.ts | 9 +- src/core/models/KeyframeRecord.ts | 55 +++++-- src/core/models/Note.ts | 28 +--- src/core/types.ts | 7 + src/ui/Panel/EditPanel/EditPanel.tsx | 151 ++++-------------- src/ui/Panel/EditPanel/List.tsx | 7 +- src/ui/Panel/EditPanel/builder.ts | 23 +-- src/ui/Panel/EditPanel/types.ts | 12 ++ .../NotePanel/NoteContainer/NoteContainer.tsx | 17 +- .../Panel/NotePanel/NoteContainer/useWrite.ts | 18 ++- src/ui/Panel/NotePanel/NotePanel.tsx | 24 +-- src/ui/Panel/NotePanel/PropsContext.ts | 2 +- .../TimelinePanel/RightPanel/Keyframes.tsx | 16 +- 14 files changed, 156 insertions(+), 221 deletions(-) diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index a67eab1..331754f 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -6,13 +6,7 @@ import { SnapshotIn } from 'mobx-state-tree'; export const JudgeLine = types.model('JudgeLine', { id: types.optional(types.identifier, nanoid), - keyframes: types.optional(KeyframeRecord, { - positionX: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], - positionY: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], - rotate: [{ beat: [ 0, 0, 1 ], value: 0, continuous: false, easing: 1 }], - alpha: [{ beat: [ 0, 0, 1 ], value: 255, continuous: false, easing: 1 }], - speed: [{ beat: [ 0, 0, 1 ], value: 1, continuous: false, easing: 1 }], - }), + keyframes: types.optional(KeyframeRecord, {}), notes: types.optional(types.array(Note), []), }).actions((self) => ({ addNote(props: SnapshotIn) { diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 2a1e2e8..7c388bb 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -1,11 +1,12 @@ import { nanoid } from 'nanoid'; -import { types, getParent, Instance } from 'mobx-state-tree'; +import { types, getParent, Instance, SnapshotIn } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; -import { BeatArray as TBeatArray } from '@/utils/types'; +import { KeyframeType } from '../types'; export const Keyframe = types.model('Keyframe', { id: types.optional(types.identifier, nanoid), + type: types.enumeration('KeyframeType', Object.values(KeyframeType)), beat: BeatArray, value: types.number, continuous: types.boolean, @@ -22,8 +23,8 @@ export const Keyframe = types.model('Keyframe', { return BeatArrayToNumber(self.beat); } })).actions((self) => ({ - setBeat(beat: TBeatArray) { - self.beat = beat; + updateProps(props: Partial, 'id' | 'type'>>) { + Object.assign(self, props); } })); diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts index 4e6e7ff..d70ddc6 100644 --- a/src/core/models/KeyframeRecord.ts +++ b/src/core/models/KeyframeRecord.ts @@ -1,33 +1,58 @@ import { types, Instance } from 'mobx-state-tree'; -import { Keyframe as $Keyframe } from './Keyframe'; -import { IArrayType } from 'mobx-state-tree'; +import { Keyframe } from './Keyframe'; import { KeyframeType } from '../types'; import { BeatArray } from '@/utils/types'; -export type $KeyframeRecord = { - [k in KeyframeType]: IArrayType; -}; - export const KeyframeRecord = types.model('KeyframeRecord', { - positionX: types.array($Keyframe), - positionY: types.array($Keyframe), - rotate: types.array($Keyframe), - alpha: types.array($Keyframe), - speed: types.array($Keyframe), + positionX: types.optional(types.array(Keyframe), [{ + type: KeyframeType.PositionX, + beat: [ 0, 0, 1 ], + value: 0, + continuous: false, + easing: 1, + }]), + positionY: types.optional(types.array(Keyframe), [{ + type: KeyframeType.PositionY, + beat: [ 0, 0, 1 ], + value: 0, + continuous: false, + easing: 1, + }]), + rotate: types.optional(types.array(Keyframe), [{ + type: KeyframeType.Rotate, + beat: [ 0, 0, 1 ], + value: 0, + continuous: false, + easing: 1, + }]), + alpha: types.optional(types.array(Keyframe), [{ + type: KeyframeType.Alpha, + beat: [ 0, 0, 1 ], + value: 255, + continuous: false, + easing: 1, + }]), + speed: types.optional(types.array(Keyframe), [{ + type: KeyframeType.Speed, + beat: [ 0, 0, 1 ], + value: 1, + continuous: false, + easing: 1, + }]), }).actions((self) => ({ - add( - type: T, + add( + type: KeyframeType, beat: BeatArray, value: number, continuous: boolean, easing: number, ) { self[type].push({ - beat, value, continuous, easing + type, beat, value, continuous, easing }); }, - remove(type: T, id: string) { + remove(type: KeyframeType, id: string) { const index = self[type].findIndex(e => e.id === id); if (index >= 0) self[type].splice(index, 1); }, diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index 79ba0cb..e23ee02 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -2,32 +2,12 @@ import { nanoid } from 'nanoid'; import { types, getParent, Instance, SnapshotIn } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; -import { NoteType as ENoteType } from '@/Chart/types'; +import { NoteType } from '../types'; import { BeatArray as TBeatArray } from '@/utils/types'; -const NoteType = types.custom({ - name: 'NoteType', - - fromSnapshot: (value) => value, - toSnapshot: (value) => value, - - isTargetType: (value) => { - return ( - Math.floor(value) === value && ( - value >= 1 && value <= 4 - ) - ); - }, - getValidationMessage: (value) => { - if (Math.floor(value) !== value) return 'Float now allowed'; - if (value < 1 || value > 4) return 'Invaild note type'; - return ''; - } -}); - export const Note = types.model('Note', { id: types.optional(types.identifier, nanoid), - type: NoteType, + type: types.enumeration('NoteType', Object.values(NoteType)), beat: BeatArray, positionX: types.number, speed: types.number, @@ -52,12 +32,12 @@ export const Note = types.model('Note', { }, get holdEndBeatNum() { - if (self.type !== ENoteType.HOLD || !self.holdEndBeat) return BeatArrayToNumber(self.beat); + if (self.type !== NoteType.Hold || !self.holdEndBeat) return BeatArrayToNumber(self.beat); return BeatArrayToNumber(self.holdEndBeat); }, get holdLengthBeatNum() { - if (self.type !== ENoteType.HOLD || !self.holdEndBeat) return 0; + if (self.type !== NoteType.Hold || !self.holdEndBeat) return 0; return BeatArrayToNumber(self.holdEndBeat) - BeatArrayToNumber(self.beat); } })).actions((self) => ({ diff --git a/src/core/types.ts b/src/core/types.ts index 7883e24..2e611aa 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -6,3 +6,10 @@ export enum KeyframeType { Alpha = 'alpha', Speed = 'speed', }; + +export enum NoteType { + Tap = 'tap', + Drag = 'drag', + Hold = 'hold', + Flick = 'flick', +}; diff --git a/src/ui/Panel/EditPanel/EditPanel.tsx b/src/ui/Panel/EditPanel/EditPanel.tsx index fd9abb2..de32e46 100644 --- a/src/ui/Panel/EditPanel/EditPanel.tsx +++ b/src/ui/Panel/EditPanel/EditPanel.tsx @@ -1,134 +1,49 @@ -import { useCallback, useEffect, useState } from 'react'; +import { observer } from 'mobx-react-lite'; import { useTranslation } from 'react-i18next'; -import { useSelectedItem } from '../../contexts/SelectedItem'; +import { store as ChartStore } from '@/core/state/chartStore'; import List from './List'; -import { BeatArray, Nullable } from '@/utils/types'; -import ChartKeyframe, { TChartKeyframe } from '@/Chart/Keyframe'; -import ChartNote, { ChartNoteProps } from '@/Chart/Note'; import { KeyframePanelBuilderSingle, NotePanelBuilderSingle } from './builder'; -import { TChartJudgelineProps } from '@/Chart/JudgelineProps'; +import { UpdatedProps, UpdatedKeyframeProps, UpdatedNoteProps } from './types'; import './styles.css'; - -type ItemKeyframeSub = { - type: keyof TChartJudgelineProps, - keyframe: ChartKeyframe, -} - -type ItemKeyframe = { - type: 'keyframe', - item: ItemKeyframeSub | ItemKeyframeSub[], -}; - -type ItemNote = { - type: 'note', - item: ChartNote | ChartNote[], -}; - -type Item = ItemKeyframe | ItemNote; - -const EditPanel: React.FC = () => { +// TODO: Multi-select +// TODO: Edit list follows update +const EditPanel = observer(() => { const { t } = useTranslation(); - const [ selectedItem, ] = useSelectedItem()!; - const [ item, setItem ] = useState>(null); - const [ id, setId ] = useState>(null); - - const handleValueChanged = useCallback((newProp: Record) => { - if (!selectedItem || !item) return; - - const { line } = selectedItem; - if (item.type === 'note') { - if (item.item instanceof Array) { - // TODO: Multi note edit - } else { - line.editNote( - item.item.id, - newProp as unknown as ChartNoteProps - ); - } - } - - if (item.type === 'keyframe') { - if (item.item instanceof Array) { - // TODO: Multi keyframe edit - } else { - line.editKeyframe( - item.item.type, - item.item.keyframe.id, - newProp as unknown as TChartKeyframe - ); - } - } - }, [item, selectedItem]); - - useEffect(() => { - if ( - !selectedItem || ( - selectedItem.note === null && - selectedItem.keyframe === null - ) - ) { - setItem(null); - setId(null); - return; - } - - const { line } = selectedItem; - if (selectedItem.keyframe !== null) { - if (selectedItem.keyframe instanceof Array) { - // TODO: Multi keyframe edit - } else { - const keyframe = line.findKeyframeById(selectedItem.keyframe.type, selectedItem.keyframe.id); - if (!keyframe) return; - setItem({ - type: 'keyframe', - item: { - type: selectedItem.keyframe.type, - keyframe, - }, - }); - setId(keyframe.id); - } - } + const handleValueChanged = (newProp: UpdatedProps) => { + if (ChartStore.selectedNote) + return ChartStore.selectedNote.updateProps(newProp as UpdatedNoteProps); + if (ChartStore.selectedKeyframe) + return ChartStore.selectedKeyframe.updateProps(newProp as UpdatedKeyframeProps); - if (selectedItem.note !== null) { - if (selectedItem.note instanceof Array) { - // TODO: Multi note edit - } else { - const note = line.findNoteById(selectedItem.note.id); - if (!note) return; - setItem({ type: 'note', item: note }); - setId(note.id); - } - } - }, [selectedItem]); + console.log(newProp); + }; return (
- {item ? ( - - ): ( -
- {t('edit_panel.placeholder')} -
+ {( + ChartStore.selectedNote ? ( + + ) : + ChartStore.selectedKeyframe ? ( + + ) : ( +
+ {t('edit_panel.placeholder')} +
+ ) )}
) -}; +}); export default EditPanel; diff --git a/src/ui/Panel/EditPanel/List.tsx b/src/ui/Panel/EditPanel/List.tsx index c346e44..64c2bc9 100644 --- a/src/ui/Panel/EditPanel/List.tsx +++ b/src/ui/Panel/EditPanel/List.tsx @@ -6,11 +6,12 @@ import InputNumber, { NumberProps } from "./Item/Number"; import { StringProps } from "./Item/String"; import InputBeat, { BeatProps } from "./Item/Beat"; import { BeatArray } from "@/utils/types"; +import { UpdatedProps, UpdatedPropsKey } from "./types"; type PropsMovedDefault = 'label' | 'onChanged'; type EditPanelItemBase = { - key: string, + key: UpdatedPropsKey, label: string, type: 'number' | 'string' | 'boolean' | 'dropdown' | 'beat', i18n: string, @@ -46,7 +47,7 @@ export type EditPanelItem = EditPanelItemNumber | EditPanelItemString | EditPane type EditPanelListProps = { id: string, items: EditPanelItem[], - onChanged: (newProp: Record) => void, + onChanged: (newProp: UpdatedProps) => void, }; const EditPanelList = ({ @@ -56,7 +57,7 @@ const EditPanelList = ({ }: EditPanelListProps) => { const { t } = useTranslation(); - const handleValueChanged = useCallback((key: string, value: string | number | boolean | BeatArray) => { + const handleValueChanged = useCallback((key: UpdatedPropsKey, value: string | number | boolean | BeatArray) => { const newProp: Record = {}; newProp[key] = value; diff --git a/src/ui/Panel/EditPanel/builder.ts b/src/ui/Panel/EditPanel/builder.ts index ceb3ca8..b2614fe 100644 --- a/src/ui/Panel/EditPanel/builder.ts +++ b/src/ui/Panel/EditPanel/builder.ts @@ -1,10 +1,11 @@ -import ChartNote from "@/Chart/Note"; import { EditPanelItem } from "./List"; import { EasingNames } from "@/utils/easings"; -import { NoteType } from "@/Chart/types"; -import ChartKeyframe from "@/Chart/Keyframe"; +import { NoteType } from "@/core/types"; +import { KeyframeType } from "@/core/types"; +import { IKeyframe } from "@/core/models/Keyframe"; +import { INote } from "@/core/models/Note"; -export const KeyframePanelBuilderSingle = (keyframe: ChartKeyframe): EditPanelItem[] => { +export const KeyframePanelBuilderSingle = (keyframe: IKeyframe): EditPanelItem[] => { const valueItem: EditPanelItem = { label: 'Value', i18n: 'keyframe.value', @@ -37,13 +38,13 @@ export const KeyframePanelBuilderSingle = (keyframe: ChartKeyframe): EditPanelIt } ]; - if (keyframe.type === 'alpha') { + if (keyframe.type === KeyframeType.Alpha) { valueItem.props.min = 0; valueItem.props.max = 255; valueItem.props.step = 1; } - if (keyframe.type !== 'speed') result.push({ + if (keyframe.type !== KeyframeType.Speed) result.push({ label: 'Easing', i18n: 'keyframe.easing', type: 'dropdown', @@ -63,7 +64,7 @@ export const KeyframePanelBuilderSingle = (keyframe: ChartKeyframe): EditPanelIt return result; }; -export const NotePanelBuilderSingle = (note: ChartNote): EditPanelItem[] => ([ +export const NotePanelBuilderSingle = (note: INote): EditPanelItem[] => ([ { label: 'Type', i18n: 'common.type', @@ -74,19 +75,19 @@ export const NotePanelBuilderSingle = (note: ChartNote): EditPanelItem[] => ([ options: [ { label: 'Tap', - value: NoteType.TAP, + value: NoteType.Tap, }, { label: 'Drag', - value: NoteType.DRAG, + value: NoteType.Drag, }, { label: 'Hold', - value: NoteType.HOLD, + value: NoteType.Hold, }, { label: 'Flick', - value: NoteType.FLICK, + value: NoteType.Flick, }, ], defaultValue: note.type, diff --git a/src/ui/Panel/EditPanel/types.ts b/src/ui/Panel/EditPanel/types.ts index 434a12a..b07aa92 100644 --- a/src/ui/Panel/EditPanel/types.ts +++ b/src/ui/Panel/EditPanel/types.ts @@ -1,6 +1,18 @@ +import { SnapshotIn } from 'mobx-state-tree'; +import { Note } from '@/core/models/Note'; +import { Keyframe } from '@/core/models/Keyframe'; export type PanelItemPropsBase = { label: string, onChanged: (newValue: T) => void, defaultValue?: T, }; + + +export type UpdatedNoteProps = Partial, 'id'>>; + +export type UpdatedKeyframeProps = Partial, 'id' | 'type'>>; + +export type UpdatedProps = Partial; + +export type UpdatedPropsKey = (keyof UpdatedNoteProps | keyof UpdatedKeyframeProps) & string; diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx index dc10aab..5790a43 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteContainer.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useRef, useState } from 'react'; import { Application, ApplicationRef, extend } from '@pixi/react'; import { Container, Rectangle, Sprite, Texture } from 'pixi.js'; -import { useSelectedItem } from '@/ui/contexts/SelectedItem'; +import { store as ChartStore } from '@/core/state/chartStore'; import useResizeEffect from '@/ui/hooks/useResizeEffect'; import useTimeRange from './TimeRange'; import BeatGraphics from './BeatGraphics'; @@ -9,11 +9,10 @@ import NoteGraphics from './NoteGraphics'; import { BeatArray, Nullable } from '@/utils/types'; import { IJudgeLine } from '@/core/models/JudgeLine'; import { Note } from '@/core/models/Note'; +import { SnapshotIn } from 'mobx-state-tree'; import { useProps } from '../PropsContext'; import useWrite from './useWrite'; -import { ChartNoteProps } from '@/Chart/Note'; import useWheel from './useWheel'; -import { SnapshotIn } from 'mobx-state-tree'; const NOTE_OFFSET = 50; @@ -29,7 +28,6 @@ const NoteContainer: React.FC<{ return NOTE_OFFSET / scale; }, [scale])(); - const [, setSelectedItem ] = useSelectedItem()!; const containerRef = useRef>(null); const appRef = useRef>(null); const hitAreaRef = useRef>(null); @@ -61,12 +59,9 @@ const NoteContainer: React.FC<{ hitRectangle.height = height; }, []); - const handleEmptySelect = useCallback(() => { - setSelectedItem((oldItem) => { - if (oldItem !== null) return { ...oldItem, note: null }; - else return null; - }); - }, [setSelectedItem]); + const handleEmptySelect = () => { + ChartStore.setSelectedNote(null); + }; const handleHoldAddStart = useCallback((props: SnapshotIn, id: string) => { if (!line) return; @@ -78,7 +73,7 @@ const NoteContainer: React.FC<{ line.editNote(id, props); }, [line]); - const handleNewNoteAdded = useCallback((props: Omit) => { + const handleNewNoteAdded = useCallback((props: SnapshotIn) => { if (!line) return; line.addNote(props); }, [line]); diff --git a/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts b/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts index 47b4448..040c53f 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts +++ b/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts @@ -6,9 +6,11 @@ import { useTempo } from '@/ui/contexts/Tempo'; import { BeatArrayToNumber, BeatNumberToArray, GridValue, parseDoublePrecist } from '@/utils/math'; import { Point as PixiPoint } from 'pixi.js'; import { Point } from '@/utils/types'; -import { ChartNoteProps } from '@/Chart/Note'; -import { NoteType } from '@/Chart/types'; +import { Note } from '@/core/models/Note'; +import { NoteType } from '@/core/types'; import { BeatArray, Nullable } from '@/utils/types'; +import { SnapshotIn } from 'mobx-state-tree'; + type PixiPointEvent = MouseEvent & { screen: PixiPoint, @@ -17,9 +19,9 @@ type PixiPointEvent = MouseEvent & { type WriteProps = { width: number, height: number, - onAddStart: (props: Omit, id: string) => void, + onAddStart: (props: SnapshotIn, id: string) => void, onAdding: (props: { holdEndBeat: BeatArray }, id: string) => void, - onAdded: (props: Omit) => void, + onAdded: (props: SnapshotIn) => void, timeOffset?: number, }; @@ -39,7 +41,7 @@ const useWrite = ({ const widthHalf = useMemo(() => width / 2, [width]); const posDiff = useRef>(null); - const holdPropRef = useRef>>(null); + const holdPropRef = useRef>>(null); const holdIDRef = useRef>(null); const holdLastEndRef = useRef(NaN); @@ -62,7 +64,7 @@ const useWrite = ({ const posY = e.clientY - posDiff.current.y; const beatNum = posToTime(posY); - if (BeatArrayToNumber(holdPropRef.current.beat) > beatNum) return; + if (BeatArrayToNumber(holdPropRef.current.beat as BeatArray) > beatNum) return; if (beatNum !== holdLastEndRef.current) { onAdding({ holdEndBeat: BeatNumberToArray(beatNum, tempo) }, holdIDRef.current); holdLastEndRef.current = beatNum; @@ -86,7 +88,7 @@ const useWrite = ({ const posX = posToPositionX(x); const beatNum = posToTime(y); - if (writeMode !== NoteType.HOLD) { + if (writeMode !== NoteType.Hold) { onAdded({ type: writeMode, beat: BeatNumberToArray(beatNum, tempo), @@ -99,7 +101,7 @@ const useWrite = ({ const { clientX, clientY } = e; const holdID = nanoid(); const holdProps = { - type: NoteType.HOLD, + type: NoteType.Hold, beat: BeatNumberToArray(beatNum, tempo), positionX: posX, speed: 1, diff --git a/src/ui/Panel/NotePanel/NotePanel.tsx b/src/ui/Panel/NotePanel/NotePanel.tsx index 1541c81..51dd734 100644 --- a/src/ui/Panel/NotePanel/NotePanel.tsx +++ b/src/ui/Panel/NotePanel/NotePanel.tsx @@ -5,7 +5,7 @@ import Grid from './Grid'; import './styles.css'; import PropsContext from './PropsContext'; import { Nullable } from '@/utils/types'; -import { NoteType } from '@/Chart/types'; +import { NoteType } from '@/core/types'; import NumberInput from '@/ui/components/NumberInput'; const NotePanel = () => { @@ -15,8 +15,8 @@ const NotePanel = () => { const [ alignCount, setAlighCount ] = useState(8); const updateWriteMode = (e: ChangeEvent) => { - const newMode = parseInt(e.target.value) as (NoteType | -1); - if (newMode === -1) setWriteMode(null); + const newMode = e.target.value as (NoteType | 'select'); + if (newMode === 'select') setWriteMode(null); else { setWriteMode(newMode); if (ChartStore.selectedNote) ChartStore.setSelectedNote(null); @@ -36,7 +36,7 @@ const NotePanel = () => {
) -}; +}); export default EditPanel; diff --git a/src/ui/Panel/EditPanel/Item/Beat.tsx b/src/ui/Panel/EditPanel/Item/Beat.tsx index f11650f..6efa954 100644 --- a/src/ui/Panel/EditPanel/Item/Beat.tsx +++ b/src/ui/Panel/EditPanel/Item/Beat.tsx @@ -2,7 +2,6 @@ import Container from './Container'; import BeatInput from '@/ui/components/BeatInput'; import { PanelItemPropsBase } from '../types'; import { BeatArray } from '@/utils/types'; -import { useCallback, useState } from 'react'; import { BeatArrayToNumber } from '@/utils/math'; export type BeatProps = PanelItemPropsBase; @@ -12,19 +11,16 @@ const EditPanelBeat = ({ onChanged, defaultValue, }: BeatProps) => { - const [ value, setValue ] = useState(defaultValue ?? [ 0, 0, 1 ]); - - const handleInput = useCallback((newBeat: BeatArray) => { + const handleInput = (newBeat: BeatArray) => { if (isNaN(BeatArrayToNumber(newBeat))) return; - setValue(newBeat); onChanged(newBeat); - }, [onChanged]); + }; return ( ) diff --git a/src/ui/Panel/EditPanel/Item/Number.tsx b/src/ui/Panel/EditPanel/Item/Number.tsx index 9f421c2..9f32c41 100644 --- a/src/ui/Panel/EditPanel/Item/Number.tsx +++ b/src/ui/Panel/EditPanel/Item/Number.tsx @@ -2,7 +2,6 @@ import Container from './Container'; import Input from '@/ui/components/NumberInput'; import Slider from '../Input/Slider'; import { PanelItemPropsBase } from "../types"; -import { useCallback, useState } from 'react'; export type NumberProps = PanelItemPropsBase & { min?: number, @@ -22,21 +21,14 @@ const EditPanelNumber = ({ placeholder, useSlider, }: NumberProps) => { - const [ value, setValue ] = useState(defaultValue ?? (min ?? 0)); - - const handleValueChanged = useCallback((newVal: number) => { - setValue(newVal); - onChanged(newVal); - }, [onChanged]); - const inputDom = ( ); @@ -48,8 +40,8 @@ const EditPanelNumber = ({ min={min} max={max} step={step} - defaultValue={value} - onChanged={handleValueChanged} + defaultValue={defaultValue ?? (min ?? 0)} + onChanged={onChanged} /> {inputDom} diff --git a/src/ui/components/BeatInput.tsx b/src/ui/components/BeatInput.tsx index fa9354c..fd41f65 100644 --- a/src/ui/components/BeatInput.tsx +++ b/src/ui/components/BeatInput.tsx @@ -4,21 +4,28 @@ import { useCallback } from 'react'; type BeatInputProps = { beat: BeatArray, - onInput: (beat: BeatArray) => void, + onChanged: (beat: BeatArray) => void, className?: string, }; const BeatInput = ({ beat, - onInput, + onChanged, className, }: BeatInputProps) => { const handleInput = useCallback((index: 0 | 1 | 2, value: number) => { const result: BeatArray = [ ...beat ]; result[index] = value; if (index === 0 || index === 1) result[index] -= 1; - onInput(result); - }, [beat, onInput]); + + if (result[1] === result[2]) { + result[0] += 1; + result[1] = 0; + } + + console.log(result); + onChanged(result); + }, [beat, onChanged]); return (
@@ -27,7 +34,7 @@ const BeatInput = ({ step={1} dragStep={0.2} defaultValue={beat[0] + 1} - onInput={(e) => handleInput(0, e)} + onChanged={(e) => handleInput(0, e)} /> : handleInput(1, e)} + onChanged={(e) => handleInput(1, e)} /> / handleInput(2, e)} + onChanged={(e) => handleInput(2, e)} />
); From bfd2ab424a2021371fafc8a0e0beb753daf50fa3 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 29 Aug 2025 23:14:36 +0800 Subject: [PATCH 019/146] fix(state/runtimeStore/selection): Fix logic stuff --- src/state/runtimeStore/selection.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/state/runtimeStore/selection.ts b/src/state/runtimeStore/selection.ts index a01ef4d..490c460 100644 --- a/src/state/runtimeStore/selection.ts +++ b/src/state/runtimeStore/selection.ts @@ -24,9 +24,11 @@ export const createSelectionState: StateCreator = (set) setSelectedKeyframe: (keyframeId) => set(() => ({ selectedKeyframeId: keyframeId, + selectedNoteId: null, })), setSelectedNote: (noteId) => set(() => ({ selectedNoteId: noteId, + selectedKeyframeId: null, })), }); From 573376b544c173e27f224773125aef00cb829326 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 30 Aug 2025 01:07:07 +0800 Subject: [PATCH 020/146] refactor(ui/components/NumberInput): Loopable number input --- src/ui/components/BeatInput.tsx | 34 ++++--- src/ui/components/NumberInput.tsx | 145 ++++++++++-------------------- src/utils/math.ts | 15 ++++ 3 files changed, 86 insertions(+), 108 deletions(-) diff --git a/src/ui/components/BeatInput.tsx b/src/ui/components/BeatInput.tsx index fd41f65..d8ec85a 100644 --- a/src/ui/components/BeatInput.tsx +++ b/src/ui/components/BeatInput.tsx @@ -1,6 +1,7 @@ +import { useRef, useCallback, useEffect } from 'react'; import Input from '@/ui/components/NumberInput'; +import { normalizeBeatArray } from '@/utils/math'; import { BeatArray } from '@/utils/types'; -import { useCallback } from 'react'; type BeatInputProps = { beat: BeatArray, @@ -13,26 +14,35 @@ const BeatInput = ({ onChanged, className, }: BeatInputProps) => { + const beatRef = useRef(beat); + const handleInput = useCallback((index: 0 | 1 | 2, value: number) => { - const result: BeatArray = [ ...beat ]; + const result: BeatArray = [ ...beatRef.current ]; result[index] = value; if (index === 0 || index === 1) result[index] -= 1; - if (result[1] === result[2]) { - result[0] += 1; - result[1] = 0; - } - - console.log(result); - onChanged(result); + onChanged(normalizeBeatArray(result)); }, [beat, onChanged]); + const handleLoop = (direction: 1 | -1, value: number) => { + const result: BeatArray = [ ...beatRef.current ]; + + result[0] += direction; + if (direction === 1) result[1] = 0; + else result[1] = result[2] - 1; + + onChanged(normalizeBeatArray(result)); + }; + + useEffect(() => { + beatRef.current = beat; + }, [beat]); + return (
handleInput(0, e)} /> @@ -41,15 +51,15 @@ const BeatInput = ({ min={1} max={beat[2]} step={1} - dragStep={0.2} defaultValue={beat[1] + 1} + allowLoop onChanged={(e) => handleInput(1, e)} + onLoop={handleLoop} /> / handleInput(2, e)} /> diff --git a/src/ui/components/NumberInput.tsx b/src/ui/components/NumberInput.tsx index c7f870c..4c49191 100644 --- a/src/ui/components/NumberInput.tsx +++ b/src/ui/components/NumberInput.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useRef, useState } from 'react'; +import useDrag from '../hooks/useDrag'; import { setDragStyle } from '@/utils/ui'; import { Nullable } from '@/utils/types'; @@ -19,8 +20,10 @@ type NumberInputProps = { dragStep?: number, defaultValue?: number, placeholder?: string, + allowLoop?: boolean, onChanged?: (newValue: number) => void, onInput?: (newValue: number) => void, + onLoop?: (loopDirection: 1 | -1, afterLoopValue: number) => void, className?: string, style?: React.CSSProperties, }; @@ -32,8 +35,10 @@ const NumberInput = ({ dragStep, defaultValue, placeholder, + allowLoop, onChanged, onInput, + onLoop, className, style }: NumberInputProps) => { @@ -42,6 +47,7 @@ const NumberInput = ({ const inputRef = useRef>(null); const lastChanged = useRef(defaultValue ?? (min ?? 0)); const lastInput = useRef(defaultValue ?? (min ?? 0)); + const _allowLoop = min !== (void 0) && max !== (void 0) && allowLoop && onLoop; const clampValue = useCallback((newValue: number) => { if (min !== (void 0) && newValue < min) return min; @@ -68,26 +74,39 @@ const NumberInput = ({ return snapValue(clampValue(value)); }, [clampValue, snapValue]); - const handleChanged = useCallback((e: React.ChangeEvent) => { - const target = e.target as HTMLInputElement; - const value = parseFloat(target.value); - + const handleValueChanged = useCallback((value: number) => { if (!isNaN(value)) { - setValue(value); + let _value = snapValue(value); + let loopDirection: 1 | 0 | -1 = 0; + + if (_allowLoop) { + if (_value > max) { + _value = min; + loopDirection = 1; + } else if (_value < min) { + _value = max; + loopDirection = -1; + } + } + _value = clampValue(_value); - const _value = clampSnapValue(value); if (lastChanged.current !== _value) { - if (onChanged) onChanged(_value); lastChanged.current = _value; + if (onLoop && loopDirection !== 0) onLoop(loopDirection, _value); + else if (onChanged) onChanged(_value); + setValue(_value); } } else { setValue(null); } - }, [onChanged, clampSnapValue]); + }, [min, max, _allowLoop, onChanged, onLoop, snapValue, clampValue]); - const handleChangeEnd = useCallback(() => { - if (isDragTesting.current) return; + const handleChanged = (e: React.ChangeEvent) => { + const target = e.target as HTMLInputElement; + handleValueChanged(parseFloat(target.value)); + }; + const handleChangeEnd = useCallback(() => { const _value = clampSnapValue(value ?? lastInput.current); setValue(_value); @@ -102,90 +121,26 @@ const NumberInput = ({ if (e.key === 'Enter') inputRef.current.blur(); }, []); - // Handle dragging - const isDragging = useRef(false); - const isDragTesting = useRef(false); - const dragStartValue = useRef(lastInput.current); - const dragStartPosX = useRef(NaN); - const dragStartPosY = useRef(NaN); - const dragPrevPosY = useRef(NaN); - const dragDelta = useRef(NaN); - - const handleMouseUp = useCallback(() => { - if (!isDragging.current) return; - if (!isNaN(dragDelta.current)) handleChangeEnd(); - - isDragging.current = false; - isDragTesting.current = false; - - dragStartPosX.current = NaN; - dragStartPosY.current = NaN; - dragPrevPosY.current = NaN; - - dragDelta.current = NaN; - setDragStyle(); - }, [handleChangeEnd]); - - const handleMouseMove = useCallback((e: MouseEvent) => { - if (!isDragging.current) return; - if (!inputRef.current) return; - - if (isDragTesting.current) { - const dx = e.clientX - dragStartPosX.current; - const dy = e.clientY - dragStartPosY.current; - - if (Math.abs(dy) > DRAG_THRESH) { - e.preventDefault(); - inputRef.current.blur(); - isDragTesting.current = false; - setDragStyle('vertical'); - - } else if (Math.abs(dx) > DRAG_THRESH) { - handleMouseUp(); - } - } else { - if (isNaN(dragDelta.current)) dragDelta.current = 0; - - const dy = e.clientY - dragPrevPosY.current; - dragDelta.current -= dy * (dragStep ?? step ?? getDragStep(min, max)); - - if (max !== (void 0) && dragStartValue.current + dragDelta.current > max) { - dragDelta.current = max - dragStartValue.current; - } else if (min !== (void 0) && dragStartValue.current + dragDelta.current < min) { - dragDelta.current = min - dragStartValue.current; - } - - const dragValue = clampSnapValue(parseFloat((dragDelta.current + dragStartValue.current).toPrecision(10))); - if (dragValue !== lastChanged.current) { - setValue(dragValue); - if (onChanged) onChanged(dragValue); - lastChanged.current = dragValue; - } - - dragPrevPosY.current = e.clientY; - } - }, [min, max, dragStep, step, onChanged, handleMouseUp, clampSnapValue]); - - const handleMouseDown = useCallback((e: React.MouseEvent) => { - isDragging.current = true; - isDragTesting.current = true; - dragStartValue.current = value ?? defaultValue ?? (min ?? 0); - - dragStartPosX.current = e.clientX; - dragStartPosY.current = e.clientY; - dragPrevPosY.current = e.clientY; - }, [defaultValue, min, value]); - - useEffect(() => { - window.addEventListener('mousemove', handleMouseMove); - window.addEventListener('mouseup', handleMouseUp); - - return (() => { - window.removeEventListener('mousemove', handleMouseMove); - window.removeEventListener('mouseup', handleMouseUp); - }); - }, [handleMouseMove, handleMouseUp]); + const handleDragStart = useCallback(() => { + if (inputRef.current) inputRef.current.blur(); + }, []); + const handleDragging = (_: unknown, { y }: { y: number }) => { + const direction = ( + y < 0 ? 1 : + y > 0 ? -1 : 0 + ); + handleValueChanged(snapValue(lastChanged.current + (dragStep ?? step ?? getDragStep(min, max)) * direction)); + }; + + const { onMouseDown } = useDrag({ + grid: 5, + allowX: false, + allowY: true, + onDragStart: handleDragStart, + onDrag: handleDragging, + }); + useEffect(() => { if (defaultValue === (void 0)) return; setValue(clampSnapValue(defaultValue)); @@ -194,15 +149,13 @@ const NumberInput = ({ return ( { + const result: BeatArray = [ ...array ]; + + if (result[0] < 0) result[0] = 0; + if (result[1] < 0) result[1] = 0; + if (result[2] < 1) result[2] = 1; + + if (result[1] === result[2]) { + result[0] += 1; + result[1] = 0; + } + + return result; +}; From f011b15e19a985a4389eff11687c1127a5b5c694 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 1 Sep 2025 14:24:41 +0800 Subject: [PATCH 021/146] feat(core/models): Add metadata model --- src/core/models/Chart.ts | 3 +++ src/core/models/Metadata.ts | 17 +++++++++++++++++ src/core/state/chartStore.ts | 1 + 3 files changed, 21 insertions(+) create mode 100644 src/core/models/Metadata.ts diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index b6980ef..eb497a3 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,9 +1,12 @@ import { types, Instance } from 'mobx-state-tree'; +import { Metadata } from './Metadata'; import { BPM } from './BPM'; import { JudgeLine } from './JudgeLine'; import { BeatArray } from '@/utils/types'; export const Chart = types.model('Chart', { + // TODO: remove `maybeNull`? + metadata: types.maybeNull(Metadata), offset: types.number, bpm: types.array(BPM), judgelines: types.array(JudgeLine), diff --git a/src/core/models/Metadata.ts b/src/core/models/Metadata.ts new file mode 100644 index 0000000..51b95be --- /dev/null +++ b/src/core/models/Metadata.ts @@ -0,0 +1,17 @@ +import { types, Instance, SnapshotIn } from 'mobx-state-tree'; + +export const Metadata = types.model('Metadata', { + name: types.optional(types.string, 'Untitled'), + artist: types.optional(types.string, 'Unknown'), + illustration: types.optional(types.string, 'Unknown'), + level: types.optional(types.string, 'SP Lv.?'), + designer: types.optional(types.string, 'Unknown'), + musicFile: types.string, + backgroundFile: types.string, +}).actions((self) => ({ + updateProps(props: Partial, 'musicFile' | 'backgroundFile'>>) { + Object.assign(self, props); + } +})); + +export type IMetadata = Instance; diff --git a/src/core/state/chartStore.ts b/src/core/state/chartStore.ts index 218e868..3cce48c 100644 --- a/src/core/state/chartStore.ts +++ b/src/core/state/chartStore.ts @@ -1,6 +1,7 @@ import { Chart, IChart } from '@/core/models/Chart'; export const store: IChart = Chart.create({ + metadata: null, offset: 0, bpm: [{ beat: [ 0, 0, 1 ], From 53d158696c579362f4d1634ffd4a356adc615ffe Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 1 Sep 2025 16:09:52 +0800 Subject: [PATCH 022/146] feat: File loader & cache --- package.json | 2 ++ pnpm-lock.yaml | 31 +++++++++++++++++++++++++++ src/runtime/resources/cache.ts | 20 +++++++++++++++++ src/runtime/resources/loader/audio.ts | 13 +++++++++++ src/runtime/resources/loader/image.ts | 15 +++++++++++++ src/runtime/resources/loader/index.ts | 29 +++++++++++++++++++++++++ 6 files changed, 110 insertions(+) create mode 100644 src/runtime/resources/cache.ts create mode 100644 src/runtime/resources/loader/audio.ts create mode 100644 src/runtime/resources/loader/image.ts create mode 100644 src/runtime/resources/loader/index.ts diff --git a/package.json b/package.json index 845bce4..58c4a2c 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", + "@phifans/audio": "^0.0.7", "@pixi/react": "8.0.0", "@types/node": "^22.10.5", "audio-decode": "^2.2.2", @@ -35,6 +36,7 @@ "nanoid": "^5.1.5", "normalize.css": "^8.0.1", "pixi.js": "^8.6.6", + "quick-lru": "^7.1.0", "rc-dock": "^3.3.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3bc152..ad8c3fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,9 @@ importers: '@fortawesome/react-fontawesome': specifier: ^0.2.2 version: 0.2.2(@fortawesome/fontawesome-svg-core@6.7.2)(react@19.0.0) + '@phifans/audio': + specifier: ^0.0.7 + version: 0.0.7 '@pixi/react': specifier: 8.0.0 version: 8.0.0(@types/react@19.0.7)(pixi.js@8.6.6)(react@19.0.0) @@ -70,6 +73,9 @@ importers: pixi.js: specifier: ^8.6.6 version: 8.6.6 + quick-lru: + specifier: ^7.1.0 + version: 7.1.0 rc-dock: specifier: ^3.3.0 version: 3.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -409,6 +415,9 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@phifans/audio@0.0.7': + resolution: {integrity: sha512-w/OfBMWjQ0H7MPrnQxG/grS3JUE1nCiiut9QBtf2hNO33J5I1aLsb9MY+NQptfst54A7KpMiE1wcE1Nb3Czf2A==} + '@pixi/colord@2.9.6': resolution: {integrity: sha512-nezytU2pw587fQstUu1AsJZDVEynjskwOL+kibwcdxsMBFqPsFFNA7xl0ii/gXuDi6M0xj3mfRJj8pBSc2jCfA==} @@ -692,6 +701,9 @@ packages: '@types/react@19.0.7': resolution: {integrity: sha512-MoFsEJKkAtZCrC1r6CM8U22GzhG7u2Wir8ons/aCKH6MBdD1ibV24zOSSkdZVUKqN5i396zG5VKLYZ3yaUZdLA==} + '@types/setimmediate@1.0.4': + resolution: {integrity: sha512-rWPw1drMVf5zInxNpgH3nn/h6KkWqwgLT2y/ciAYQ16RAsbXOXe0AmtZ/HyzwPNw+r4GMJuI7IV7YNKO7Fs/xA==} + '@types/spark-md5@3.0.5': resolution: {integrity: sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg==} @@ -1565,6 +1577,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-lru@7.1.0: + resolution: {integrity: sha512-Pzd/4IFnTb8E+I1P5rbLQoqpUHcXKg48qTYKi4EANg+sTPwGFEMOcYGiiZz6xuQcOMZP7MPsrdAPx+16Q8qahg==} + engines: {node: '>=18'} + rc-align@4.0.15: resolution: {integrity: sha512-wqJtVH60pka/nOX7/IspElA8gjPNQKIx/ZqJ6heATCkXpe1Zg4cPVrMD2vC96wjsFFL8WsmhPbx9tdMo1qqlIA==} peerDependencies: @@ -1784,6 +1800,9 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} @@ -2236,6 +2255,12 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.18.0 + '@phifans/audio@0.0.7': + dependencies: + '@types/setimmediate': 1.0.4 + audio-decode: 2.2.2 + setimmediate: 1.0.5 + '@pixi/colord@2.9.6': {} '@pixi/react@8.0.0(@types/react@19.0.7)(pixi.js@8.6.6)(react@19.0.0)': @@ -2431,6 +2456,8 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/setimmediate@1.0.4': {} + '@types/spark-md5@3.0.5': {} '@typescript-eslint/eslint-plugin@8.18.2(@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3))(eslint@9.17.0)(typescript@5.6.3)': @@ -3553,6 +3580,8 @@ snapshots: queue-microtask@1.2.3: {} + quick-lru@7.1.0: {} + rc-align@4.0.15(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime': 7.26.0 @@ -3850,6 +3879,8 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.0.0 + setimmediate@1.0.5: {} + shallowequal@1.1.0: {} shebang-command@2.0.0: diff --git a/src/runtime/resources/cache.ts b/src/runtime/resources/cache.ts new file mode 100644 index 0000000..3dade3a --- /dev/null +++ b/src/runtime/resources/cache.ts @@ -0,0 +1,20 @@ +import QuickLRU from 'quick-lru'; +import { Clip } from '@phifans/audio'; +import { Sprite } from 'pixi.js'; + +export const audioCache = new QuickLRU({ + maxSize: 100, + onEviction: (_key, clip) => { + clip.destroy(); + }, +}); + +export const imageCache = new QuickLRU({ + maxSize: 50, + onEviction: (_key, sprite) => { + sprite.destroy({ + texture: true, + textureSource: true, + }); + }, +}); diff --git a/src/runtime/resources/loader/audio.ts b/src/runtime/resources/loader/audio.ts new file mode 100644 index 0000000..e4af41c --- /dev/null +++ b/src/runtime/resources/loader/audio.ts @@ -0,0 +1,13 @@ +import { Clip } from '@phifans/audio'; +import { audioCache } from '../cache'; + +export const loadAudio = (file: File | Blob, filename?: string) => new Promise((res, rej) => { + Clip.from(file) + .then((clip) => { + const _filename = (file as File).name ?? filename; + + audioCache.set(_filename, clip); + res(clip); + }) + .catch(e => rej(e)); +}); diff --git a/src/runtime/resources/loader/image.ts b/src/runtime/resources/loader/image.ts new file mode 100644 index 0000000..2f4dfdb --- /dev/null +++ b/src/runtime/resources/loader/image.ts @@ -0,0 +1,15 @@ +import { Texture, Sprite } from 'pixi.js'; +import { imageCache } from '../cache'; + +export const loadImage = (file: Blob | File, filename?: string) => new Promise((res, rej) => { + window.createImageBitmap(file) + .then((bitmap) => { + const texture = Texture.from(bitmap); + const sprite = Sprite.from(texture); + const _filename = (file as File).name ?? filename; + + imageCache.set(_filename, sprite); + res(sprite); + }) + .catch(e => rej(e)); +}); diff --git a/src/runtime/resources/loader/index.ts b/src/runtime/resources/loader/index.ts new file mode 100644 index 0000000..3f90e82 --- /dev/null +++ b/src/runtime/resources/loader/index.ts @@ -0,0 +1,29 @@ +import { loadImage } from './image'; +import { loadAudio } from './audio'; + +export const loadFile = (files: File[]) => new Promise<{ + successed: string[], failed: string[] +}>(async (res) => { + const filesSuccessed: string[] = []; + const filesFailed: string[] = []; + + for (const file of files) { + (await new Promise(() => { + throw new Error('Promice chain'); + }).catch(async () => { + await loadImage(file); + filesSuccessed.push(file.name); + }).catch(async () => { + await loadAudio(file); + filesSuccessed.push(file.name); + }).catch(() => { + console.warn(`Unsupported file: ${file.name}`); + filesFailed.push(file.name); + })); + } + + res({ + successed: filesSuccessed, + failed: filesFailed, + }); +}); From e29085f5ff1f27bef35a080d682293c202b3754d Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 1 Sep 2025 16:24:20 +0800 Subject: [PATCH 023/146] style(runtime/resources/loader): Rename function --- src/runtime/resources/loader/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/resources/loader/index.ts b/src/runtime/resources/loader/index.ts index 3f90e82..f2a0352 100644 --- a/src/runtime/resources/loader/index.ts +++ b/src/runtime/resources/loader/index.ts @@ -1,7 +1,7 @@ import { loadImage } from './image'; import { loadAudio } from './audio'; -export const loadFile = (files: File[]) => new Promise<{ +export const loadFiles = (files: File[]) => new Promise<{ successed: string[], failed: string[] }>(async (res) => { const filesSuccessed: string[] = []; From ef6fcfd9be042519856adeeedb18ecb45a7498b4 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 1 Sep 2025 16:36:35 +0800 Subject: [PATCH 024/146] feat(core/models): Finish metadata creation / update --- src/core/models/Chart.ts | 11 ++++++++++- src/core/models/Metadata.ts | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index eb497a3..464cace 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,4 +1,4 @@ -import { types, Instance } from 'mobx-state-tree'; +import { types, Instance, SnapshotIn } from 'mobx-state-tree'; import { Metadata } from './Metadata'; import { BPM } from './BPM'; import { JudgeLine } from './JudgeLine'; @@ -11,6 +11,15 @@ export const Chart = types.model('Chart', { bpm: types.array(BPM), judgelines: types.array(JudgeLine), }).actions((self) => ({ + updateMetadata(metadata: SnapshotIn) { + if (self.metadata === null) self.metadata = Metadata.create(metadata); + else self.metadata.updateProps(metadata); + }, + + removeMetadata() { + self.metadata = null; + }, + updateOffset(offset: number) { self.offset = offset; }, diff --git a/src/core/models/Metadata.ts b/src/core/models/Metadata.ts index 51b95be..baba832 100644 --- a/src/core/models/Metadata.ts +++ b/src/core/models/Metadata.ts @@ -9,7 +9,7 @@ export const Metadata = types.model('Metadata', { musicFile: types.string, backgroundFile: types.string, }).actions((self) => ({ - updateProps(props: Partial, 'musicFile' | 'backgroundFile'>>) { + updateProps(props: Partial>) { Object.assign(self, props); } })); From 9eae65eade37aabc47ad977ad2b8cc2a63b72883 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 1 Sep 2025 18:22:12 +0800 Subject: [PATCH 025/146] refactor: Refactoring audio system With some dev code --- src/runtime/audio/bus.ts | 8 ++ src/runtime/audio/state.ts | 75 +++++++++++++++++++ src/runtime/audio/ticker.ts | 19 +++++ src/ui/App.tsx | 33 +++++++- src/ui/Panel/PreviewPanel/Controller.tsx | 7 +- src/ui/Panel/TimelinePanel/LeftPanel/Head.tsx | 13 +--- .../TimelinePanel/LeftPanel/TimeLabel.tsx | 18 +++++ 7 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 src/runtime/audio/bus.ts create mode 100644 src/runtime/audio/state.ts create mode 100644 src/runtime/audio/ticker.ts create mode 100644 src/ui/Panel/TimelinePanel/LeftPanel/TimeLabel.tsx diff --git a/src/runtime/audio/bus.ts b/src/runtime/audio/bus.ts new file mode 100644 index 0000000..06f1b4f --- /dev/null +++ b/src/runtime/audio/bus.ts @@ -0,0 +1,8 @@ +import { Bus } from '@phifans/audio'; + +export const bus = new Bus(); + +export const channelMusic = bus.createChannel('music'); + +export const channelEffect = bus.createChannel('effect'); +channelEffect.startTick(); diff --git a/src/runtime/audio/state.ts b/src/runtime/audio/state.ts new file mode 100644 index 0000000..3e80ce0 --- /dev/null +++ b/src/runtime/audio/state.ts @@ -0,0 +1,75 @@ +/** + * XXX: Should this state be seperated? + */ +import { createStore } from 'zustand/vanilla'; +import { useStore } from 'zustand'; +import { onPatch } from 'mobx-state-tree'; +import { channelMusic } from './bus'; +import { ticker } from './ticker'; +import { store as ChartStore } from '@/core/state/chartStore'; +import { audioCache } from '@/runtime/resources/cache'; +import { SnapshotIn } from 'mobx-state-tree'; +import { Clip } from '@phifans/audio'; +import { Nullable } from '@/utils/types'; +import { Metadata } from '@/core/models/Metadata'; + +type RuntimeAudioStore = { + musicClip: Nullable, + duration: number, + currentTime: number, +}; + +export const runtimeAudioStore = createStore(() => ({ + musicClip: null, + duration: 0, + currentTime: 0, +})); + +const applyNewClip = (clip?: Clip) => { + if (!clip) { + console.error('You must load audio file(s) before loading a chart file!'); + return; + } + + const { + musicClip: oldClip + } = runtimeAudioStore.getState(); + + if (oldClip) { + oldClip.stop(); + oldClip.channel = null; + } + clip.channel = channelMusic; + + runtimeAudioStore.setState({ + musicClip: clip, + duration: clip.duration, + currentTime: 0, + }); + if (!ticker.started) ticker.start(); +}; + +// Listen to chart metadata changes +onPatch(ChartStore, (patch) => { + if (!patch.path.startsWith('/metadata')) return; + + if (patch.path === '/metadata' && patch.op === 'replace') { + const value = patch.value as Nullable>>; + + if (!value) return; + if (!value.musicFile) return; + + applyNewClip(audioCache.get(value.musicFile)); + } + + if (patch.path === '/metadata/musicFile' && patch.op === 'replace') { + const value = patch.value as string | undefined; + if (!value) return; + + applyNewClip(audioCache.get(value)); + } +}); + +export const useRuntimeAudioStore = ( + selector: (state: RuntimeAudioStore) => U +) => useStore(runtimeAudioStore, selector); diff --git a/src/runtime/audio/ticker.ts b/src/runtime/audio/ticker.ts new file mode 100644 index 0000000..b6dc84b --- /dev/null +++ b/src/runtime/audio/ticker.ts @@ -0,0 +1,19 @@ +import { Ticker } from 'pixi.js'; +import { runtimeAudioStore } from './state'; + +export const ticker = new Ticker(); + +ticker.stop(); +ticker.autoStart = false; +ticker.minFPS = ticker.maxFPS = 30; + +ticker.add(() => { + const { + musicClip + } = runtimeAudioStore.getState(); + if (!musicClip) return; + + runtimeAudioStore.setState({ + currentTime: musicClip.currentTime, + }); +}); diff --git a/src/ui/App.tsx b/src/ui/App.tsx index ac3dfcd..f2e20b8 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -12,21 +12,44 @@ import { ChartExported } from '@/Chart/Chart'; import NumberInput from './components/NumberInput'; import TopBar from './Bar/TopBar/TopBar'; import DialogProvider from './contexts/Dialog/Provider'; +import { loadFiles } from '@/runtime/resources/loader'; +import { store as ChartStore } from '@/core/state/chartStore'; +import { audioCache } from '@/runtime/resources/cache'; +import '@/runtime/audio/state'; function App() { const dockRef = useRef>(null); const [ tempo, setTempo ] = useState(4); let importedMusic: Nullable = null; - const onImportAudio = () => { - PopupReadFiles(false) + const onImportFiles = () => { + PopupReadFiles(true) .then((files) => { if (!files || files.length === 0) return; - importedMusic = files[0]; + return loadFiles([ ...files ]); + }) + .then((result) => { + console.log(result); }) .catch((e) => console.error(e)); }; + const onApplyTestMetadata = () => { + let audioFile: string = ''; + + for (const [ name ] of audioCache.entriesDescending()) { + if (!audioFile) { + audioFile = name; + break; + } + } + + ChartStore.updateMetadata({ + musicFile: audioFile, + backgroundFile: 'tHisIsATestFileNamePleaseRemove' + }); + }; + const onCreateChart = () => { if (!importedMusic) return; if (Chart.info) return; @@ -97,7 +120,9 @@ function App() {
- + + + diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index 08edaa0..ddf8771 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -1,9 +1,11 @@ import { useMemo } from 'react'; +import { useRuntimeAudioStore } from '@/runtime/audio/state'; import Chart from '@/Chart/Chart'; import { useTempo } from '../../contexts/Tempo'; import { GridValue } from '@/utils/math'; const PreviewController = () => { + const musicClip = useRuntimeAudioStore((s) => s.musicClip); const tempo = useTempo(); const tempoGrid = useMemo(() => 1 / tempo, [tempo]); @@ -33,8 +35,9 @@ const PreviewController = () => { >Prev tempo
); From aab802c616700aa3f8bb029029e5aa4846e5df18 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 2 Sep 2025 17:18:20 +0800 Subject: [PATCH 030/146] refactor(ui/Panel/BPMPanel/Item): Update with `BeatInput` --- src/ui/Panel/BPMPanel/Item.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ui/Panel/BPMPanel/Item.tsx b/src/ui/Panel/BPMPanel/Item.tsx index 5f4f798..19ba578 100644 --- a/src/ui/Panel/BPMPanel/Item.tsx +++ b/src/ui/Panel/BPMPanel/Item.tsx @@ -7,7 +7,8 @@ import { BeatArray } from "@/utils/types"; import { Button } from "@blueprintjs/core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; -import { IBPM } from '@/core/models/BPM'; +import { SnapshotIn } from 'mobx-state-tree'; +import { BPM, IBPM } from '@/core/models/BPM'; const BPMListItem = observer<{ bpm: IBPM, @@ -17,8 +18,10 @@ const BPMListItem = observer<{ const { t } = useTranslation(); const handleUpdate = (newBeat?: BeatArray, newBPM?: number) => { - if (newBeat) bpm.updateBeat(newBeat); - if (newBPM) bpm.updateBPM(newBPM); + const props: Partial, 'id'>> = {}; + if (newBeat) props.beat = newBeat; + if (newBPM) props.bpm = newBPM; + bpm.updateProps(props); }; const handleDelete = () => { From 5024eac0f8e77699e738496e4faa9cf032e2ec63 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 2 Sep 2025 17:31:23 +0800 Subject: [PATCH 031/146] feat(core/model/chart): Add BPM cache and some dev code --- src/core/models/BPM.ts | 17 ++-- src/core/models/Chart.ts | 25 +++++- src/core/state/chartStore.ts | 4 - src/core/timeline/bpm.ts | 87 +++++++++++++++++++ src/core/types.ts | 8 ++ src/runtime/audio/bindChart.ts | 7 +- src/runtime/audio/state.ts | 11 ++- src/runtime/audio/ticker.ts | 2 + .../TimelinePanel/RightPanel/RightPanel.tsx | 30 ++----- .../Panel/TimelinePanel/RightPanel/Seeker.tsx | 4 +- 10 files changed, 155 insertions(+), 40 deletions(-) create mode 100644 src/core/timeline/bpm.ts diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index 65dd434..b86d9d9 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -1,8 +1,8 @@ import { nanoid } from 'nanoid'; -import { types, Instance } from 'mobx-state-tree'; +import { types, getParent, Instance, SnapshotIn } from 'mobx-state-tree'; +import { IChart } from './Chart'; import { BeatArray } from '@/core/utils/model'; import { BeatArrayToNumber } from '@/utils/math'; -import { BeatArray as TBeatArray } from '@/utils/types'; const BPMNumber = types.custom({ name: 'BPMNumber', @@ -21,7 +21,7 @@ const BPMNumber = types.custom({ }, }); -export const BPM = types.model('Note', { +export const BPM = types.model('BPM', { id: types.optional(types.identifier, nanoid), beat: BeatArray, bpm: BPMNumber, @@ -30,13 +30,12 @@ export const BPM = types.model('Note', { return BeatArrayToNumber(self.beat); } })).actions((self) => ({ - updateBeat(beat: TBeatArray) { - self.beat = beat; - }, + updateProps(props: Partial, 'id'>>) { + Object.assign(self, props); - updateBPM(bpm: number) { - self.bpm = bpm; - } + const chart = getParent(self, 2) as IChart; + chart.updateBPMCache(); + }, })); export type IBPM = Instance; diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index 464cace..84b10f3 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,16 +1,29 @@ import { types, Instance, SnapshotIn } from 'mobx-state-tree'; +import { calculateBPMCache } from '../timeline/bpm'; import { Metadata } from './Metadata'; import { BPM } from './BPM'; import { JudgeLine } from './JudgeLine'; import { BeatArray } from '@/utils/types'; +import { BPMCache } from '../types'; export const Chart = types.model('Chart', { // TODO: remove `maybeNull`? metadata: types.maybeNull(Metadata), offset: types.number, - bpm: types.array(BPM), + bpm: types.optional(types.array(BPM), [{ + beat: [ 0, 0, 1 ], + bpm: 120, + }]), judgelines: types.array(JudgeLine), -}).actions((self) => ({ +}).volatile(() => ({ + bpmCache: [{ + startTime: 0, + endTime: Infinity, + startBeat: 0, + endBeat: Infinity, + timePerBeat: 0.5, + }] as BPMCache[], +})).actions((self) => ({ updateMetadata(metadata: SnapshotIn) { if (self.metadata === null) self.metadata = Metadata.create(metadata); else self.metadata.updateProps(metadata); @@ -28,11 +41,15 @@ export const Chart = types.model('Chart', { self.bpm.push({ beat, bpm, }); + + self.bpmCache = calculateBPMCache(self.bpm); }, removeBPM(id: string) { const index = self.bpm.findIndex(e => e.id === id); if (index >= 0) self.bpm.splice(index, 1); + + self.bpmCache = calculateBPMCache(self.bpm); }, addJudgeLine() { @@ -43,6 +60,10 @@ export const Chart = types.model('Chart', { const index = self.judgelines.findIndex(e => e.id === id); if (index >= 0) self.judgelines.splice(index, 1); }, + + updateBPMCache() { + self.bpmCache = calculateBPMCache(self.bpm); + } })); export type IChart = Instance; diff --git a/src/core/state/chartStore.ts b/src/core/state/chartStore.ts index 3cce48c..ea75006 100644 --- a/src/core/state/chartStore.ts +++ b/src/core/state/chartStore.ts @@ -3,9 +3,5 @@ import { Chart, IChart } from '@/core/models/Chart'; export const store: IChart = Chart.create({ metadata: null, offset: 0, - bpm: [{ - beat: [ 0, 0, 1 ], - bpm: 120, - }], judgelines: [], }); diff --git a/src/core/timeline/bpm.ts b/src/core/timeline/bpm.ts new file mode 100644 index 0000000..c0b179e --- /dev/null +++ b/src/core/timeline/bpm.ts @@ -0,0 +1,87 @@ +import { store as ChartStore } from '../state/chartStore'; +import { sortByBeat, parseDoublePrecist } from '@/utils/math'; +import { IBPM } from '../models/BPM'; +import { BPMCache } from '../types'; + +export const calculateBPMCache = (bpms: IBPM[]): BPMCache[] => { + const _bpms = bpms.slice().sort(sortByBeat); + const result: BPMCache[] = []; + + for (const bpm of _bpms) { + const timePerBeat = parseDoublePrecist(60 / bpm.bpm, 6, -1); + + if (result.length === 0) { + result.push({ + startTime: 0, + endTime: NaN, + startBeat: 0, + endBeat: NaN, + timePerBeat, + }); + continue; + } + + const lastBpmCache = result[result.length - 1]!; + result.push({ + startTime: parseDoublePrecist(( + lastBpmCache.startTime + (lastBpmCache.timePerBeat * (bpm.beatNum - lastBpmCache.startBeat)) + ), 6, -1), + endTime: NaN, + startBeat: bpm.beatNum, + endBeat: NaN, + timePerBeat, + }); + } + + if (result.length === 1) { + result[result.length - 1].endTime = Infinity; + result[result.length - 1].endBeat = Infinity; + } else { + for (let i = 0; i < result.length; i++) { + const bpm = result[i]; + const bpmNext = result[i + 1]; + + if (bpmNext) { + bpm.endTime = bpmNext.startTime; + bpm.endBeat = bpmNext.startBeat; + } else { + bpm.endTime = Infinity; + bpm.endBeat = Infinity; + } + } + } + + return result; +}; + +export const getBeatByTime = (time: number) => { + const bpms = ChartStore.bpmCache; + let result = NaN; + + for (const bpm of bpms) { + if (bpm.endTime < time) continue; + if (bpm.startTime > time) break; + + result = parseDoublePrecist(( + bpm.startBeat + (time - bpm.startTime) / bpm.timePerBeat + ), 6, -1); + } + + return result; +}; + +export const getTimeByBeat = (beat: number) => { + const bpms = ChartStore.bpmCache; + let result = NaN; + + for (const bpm of bpms) { + if (bpm.endBeat < beat) continue; + if (bpm.startBeat > beat) break; + + result = parseDoublePrecist(( + bpm.startTime + (beat - bpm.startBeat) * bpm.timePerBeat + ), 6, -1); + } + + return result; +}; diff --git a/src/core/types.ts b/src/core/types.ts index 2e611aa..f3c9957 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -1,4 +1,12 @@ +export type BPMCache = { + startTime: number, + endTime: number, + startBeat: number, + endBeat: number, + timePerBeat: number, +}; + export enum KeyframeType { PositionX = 'positionX', PositionY = 'positionY', diff --git a/src/runtime/audio/bindChart.ts b/src/runtime/audio/bindChart.ts index 6888745..a69864f 100644 --- a/src/runtime/audio/bindChart.ts +++ b/src/runtime/audio/bindChart.ts @@ -3,6 +3,7 @@ import { channelMusic } from './bus'; import { runtimeAudioStore, runtimeAudioTimeStore } from './state'; import { ticker } from './ticker'; import { store as ChartStore } from '@/core/state/chartStore'; +import { getBeatByTime } from '@/core/timeline/bpm'; import { audioCache } from '@/runtime/resources/cache'; import { SnapshotIn } from 'mobx-state-tree'; import { Clip } from '@phifans/audio'; @@ -29,8 +30,12 @@ const applyNewClip = (clip?: Clip) => { musicClip: clip, status: -1, duration: clip.duration, + durationBeat: getBeatByTime(clip.duration), + }); + runtimeAudioTimeStore.setState({ + currentTime: 0, + currentBeat: 0, }); - runtimeAudioTimeStore.setState({ currentTime: 0 }); if (!ticker.started) ticker.start(); }; diff --git a/src/runtime/audio/state.ts b/src/runtime/audio/state.ts index b257a21..d3a516c 100644 --- a/src/runtime/audio/state.ts +++ b/src/runtime/audio/state.ts @@ -11,6 +11,7 @@ type RuntimeAudioStore = { musicClip: Nullable, status: -1 | 0 | 1, duration: number, + durationBeat: number, play: () => void, pause: () => void, @@ -22,6 +23,7 @@ export const runtimeAudioStore = createStore((set, get) => ({ musicClip: null, status: -1, duration: 0, + durationBeat: 0, play() { const { musicClip } = get(); @@ -53,8 +55,12 @@ export const runtimeAudioStore = createStore((set, get) => ({ }, })); -export const runtimeAudioTimeStore = createStore<{ currentTime: number }>(() => ({ +export const runtimeAudioTimeStore = createStore<{ + currentTime: number, + currentBeat: number, +}>(() => ({ currentTime: 0, + currentBeat: 0, })); export const useRuntimeAudioStore = ( @@ -63,3 +69,6 @@ export const useRuntimeAudioStore = ( export const useRuntimeAudioTime = () => useStore(runtimeAudioTimeStore, (s) => s.currentTime); + +export const useRuntimeAudioBeat = () => + useStore(runtimeAudioTimeStore, (s) => s.currentBeat); diff --git a/src/runtime/audio/ticker.ts b/src/runtime/audio/ticker.ts index fedb3a5..4d38461 100644 --- a/src/runtime/audio/ticker.ts +++ b/src/runtime/audio/ticker.ts @@ -1,4 +1,5 @@ import { Ticker } from 'pixi.js'; +import { getBeatByTime } from '@/core/timeline/bpm'; import { runtimeAudioStore, runtimeAudioTimeStore } from './state'; export const ticker = new Ticker(); @@ -14,5 +15,6 @@ ticker.add(() => { runtimeAudioTimeStore.setState({ currentTime: musicClip.currentTime, + currentBeat: getBeatByTime(musicClip.currentTime), }); }); diff --git a/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx b/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx index 7073b68..5c633db 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/RightPanel.tsx @@ -1,6 +1,7 @@ -import React, { useCallback, useState, useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useRef } from 'react'; import { observer } from 'mobx-react-lite'; -import Chart from '@/Chart/Chart'; +import { useRuntimeAudioStore } from '@/runtime/audio/state'; +import { getTimeByBeat } from '@/core/timeline/bpm'; import RightPanelProvider from './Context/Provider'; import ScrollBar from '@/ui/components/ScrollBar'; import TimelineList from "../List/List"; @@ -29,11 +30,12 @@ const TimelineRightPanel = observer<{ const containerHeight = useRef(0); const contentHeight = useRef(0); const listScrollRef = useRef(0); - const [ timeLength, setTimeLength ] = useState(0); + + const durationBeat = useRuntimeAudioStore((s) => s.durationBeat); + const seekMusic = useRuntimeAudioStore((s) => s.seek); const onSeeked = useCallback((time: number) => { - if (!Chart.info) return; - Chart.beatNum = time; + seekMusic(getTimeByBeat(time)); }, []); const updateListScroll = useCallback((_scroll: number) => { @@ -50,22 +52,8 @@ const TimelineRightPanel = observer<{ updateListScroll(listScrollRef.current); }, scrollContainerRef); - useEffect(() => { - const updateTimeLength = () => { - setTimeLength(Chart.beatDuration); - }; - - Chart.events.once('music.loaded', updateTimeLength); - Chart.events.on('bpms.updated', updateTimeLength); - - return (() => { - Chart.events.off('music.loaded', updateTimeLength); - Chart.events.off('bpms.updated', updateTimeLength); - }); - }, []); - return ( - + @@ -107,7 +95,7 @@ const TimelineRightPanel = observer<{ />
diff --git a/src/ui/Panel/TimelinePanel/RightPanel/Seeker.tsx b/src/ui/Panel/TimelinePanel/RightPanel/Seeker.tsx index 96cfb5c..0cbb0de 100644 --- a/src/ui/Panel/TimelinePanel/RightPanel/Seeker.tsx +++ b/src/ui/Panel/TimelinePanel/RightPanel/Seeker.tsx @@ -1,5 +1,5 @@ import React, { useRef } from 'react'; -import { useClockTime } from '@/ui/contexts/Clock'; +import { useRuntimeAudioBeat } from '@/runtime/audio/state'; import { useContext } from '../RightPanel/Context'; import useDrag from '@/ui/hooks/useDrag'; import { Point } from '@/utils/types'; @@ -13,7 +13,7 @@ const TimelineSeeker: React.FC = ({ timeLength, onSeek, }: TimelineSeekerProps) => { - const { beat } = useClockTime(); + const beat = useRuntimeAudioBeat(); const { scale } = useContext(); const handleStartTime = useRef(NaN); From 217443cebc1ca4e776afa96453ad0914d00412cf Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 2 Sep 2025 17:31:48 +0800 Subject: [PATCH 032/146] refactor(core/utils): Using `normalizeBeatArray` for BeatArray model type --- src/core/utils/model.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/core/utils/model.ts b/src/core/utils/model.ts index 90612aa..44ae18f 100644 --- a/src/core/utils/model.ts +++ b/src/core/utils/model.ts @@ -1,23 +1,16 @@ import { types } from 'mobx-state-tree'; -import { BeatArrayToNumber } from '@/utils/math'; +import { normalizeBeatArray, BeatArrayToNumber } from '@/utils/math'; import { BeatArray as TBeatArray } from '../../utils/types'; export const BeatArray = types.custom({ name: 'BeatArray', fromSnapshot(value: number[]) { - const result: TBeatArray = [ value[0], value[1], value[2] ]; - - if (result[1] === result[2]) { - result[0] += 1; - result[1] = 0; - } - - return result; + return normalizeBeatArray([ value[0], value[1], value[2] ]); }, toSnapshot(value: TBeatArray) { - return value; + return [ ...value ]; }, isTargetType(value: TBeatArray | number[]) { From 714c5432fdae8f4ca2bcc4c3a502a20fc575e7da Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 2 Sep 2025 18:39:07 +0800 Subject: [PATCH 033/146] style(core/models/Chart): Small tweaks --- src/core/models/BPM.ts | 7 +++++++ src/core/models/Chart.ts | 17 ++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index b86d9d9..8319e7c 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -30,9 +30,16 @@ export const BPM = types.model('BPM', { return BeatArrayToNumber(self.beat); } })).actions((self) => ({ + afterCreate() { + this.updateParentBPMCache(); + }, + updateProps(props: Partial, 'id'>>) { Object.assign(self, props); + this.updateParentBPMCache(); + }, + updateParentBPMCache() { const chart = getParent(self, 2) as IChart; chart.updateBPMCache(); }, diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index 84b10f3..fd82401 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -16,14 +16,12 @@ export const Chart = types.model('Chart', { }]), judgelines: types.array(JudgeLine), }).volatile(() => ({ - bpmCache: [{ - startTime: 0, - endTime: Infinity, - startBeat: 0, - endBeat: Infinity, - timePerBeat: 0.5, - }] as BPMCache[], + bpmCache: [] as BPMCache[], })).actions((self) => ({ + afterCreate() { + this.updateBPMCache(); + }, + updateMetadata(metadata: SnapshotIn) { if (self.metadata === null) self.metadata = Metadata.create(metadata); else self.metadata.updateProps(metadata); @@ -41,15 +39,12 @@ export const Chart = types.model('Chart', { self.bpm.push({ beat, bpm, }); - - self.bpmCache = calculateBPMCache(self.bpm); }, removeBPM(id: string) { const index = self.bpm.findIndex(e => e.id === id); if (index >= 0) self.bpm.splice(index, 1); - - self.bpmCache = calculateBPMCache(self.bpm); + this.updateBPMCache(); }, addJudgeLine() { From 462bfb744a861aaae9fe752560319b422376ee61 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Wed, 3 Sep 2025 16:23:10 +0800 Subject: [PATCH 034/146] feat(ui/Panel/NotePanel): Use runtime audio clock TODO: A better way for NotePanel getting current time --- src/ui/Panel/NotePanel/NoteContainer/BeatGraphics.tsx | 4 ++-- src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx | 4 ++-- src/ui/Panel/NotePanel/NotePanel.tsx | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ui/Panel/NotePanel/NoteContainer/BeatGraphics.tsx b/src/ui/Panel/NotePanel/NoteContainer/BeatGraphics.tsx index 19b6db1..e145d27 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/BeatGraphics.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/BeatGraphics.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from "react"; import { extend } from "@pixi/react"; import { Container, Sprite, Texture } from 'pixi.js'; -import { useClockTime } from "@/ui/contexts/Clock"; +import { useRuntimeAudioBeat } from "@/runtime/audio/state"; import { parseDoublePrecist } from "@/utils/math"; import { getScaleColor } from "@/utils/tempo"; import { useTempo } from "@/ui/contexts/Tempo"; @@ -77,7 +77,7 @@ const BeatGraphics = ({ extend({ Container }); const tempo = useTempo(); - const currentTime = useClockTime().beat - timeOffset; + const currentTime = useRuntimeAudioBeat() - timeOffset; const timeRangeStart = Math.floor(currentTime); const _timeOffset = useMemo(() => Math.ceil(timeOffset * 2), [timeOffset]); const scaleCount = useMemo(() => Math.ceil(timeRangeEnd + _timeOffset), [timeRangeEnd, _timeOffset]); diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx index 726f8f6..ad0f05c 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx @@ -3,7 +3,7 @@ import { extend } from '@pixi/react'; import { Container, EventMode, Sprite, Texture } from 'pixi.js'; import { observer } from 'mobx-react-lite'; import { useRuntimeStore } from '@/state/runtimeStore'; -import { useClockTime } from '@/ui/contexts/Clock'; +import { useRuntimeAudioBeat } from '@/runtime/audio/state'; import { NoteType } from '@/core/types'; import useDrag from '@/ui/hooks/useDrag'; import { useTempo } from '@/ui/contexts/Tempo'; @@ -204,7 +204,7 @@ const NoteGraphics = observer<{ const alignPercent = useMemo(() => 1 / align, [align]); const alignGrid = useMemo(() => width * alignPercent, [width, alignPercent]); - const currentTime = useClockTime().beat - timeOffset; + const currentTime = useRuntimeAudioBeat() - timeOffset; const timeRange = timeRangeEnd + currentTime; const noteSprites = (() => { diff --git a/src/ui/Panel/NotePanel/NotePanel.tsx b/src/ui/Panel/NotePanel/NotePanel.tsx index f0f1320..bb636d2 100644 --- a/src/ui/Panel/NotePanel/NotePanel.tsx +++ b/src/ui/Panel/NotePanel/NotePanel.tsx @@ -14,8 +14,6 @@ const NotePanel = () => { const [ scale, setScale ] = useState(200); const [ alignCount, setAlighCount ] = useState(8); - const selectedNoteId = useRuntimeStore((s) => s.selectedNoteId); - const selectedKeyframeId = useRuntimeStore((s) => s.selectedKeyframeId); const setSelectedNote = useRuntimeStore((s) => s.setSelectedNote); const setSelectedKeyframe = useRuntimeStore((s) => s.setSelectedKeyframe); @@ -24,8 +22,8 @@ const NotePanel = () => { if (newMode === 'select') setWriteMode(null); else { setWriteMode(newMode); - if (selectedNoteId) setSelectedNote(null); - if (selectedKeyframeId) setSelectedKeyframe(null); + setSelectedNote(null); + setSelectedKeyframe(null); } }; From 5fd449cf772a6ad0322726ec24984849a38d4757 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Wed, 3 Sep 2025 16:36:12 +0800 Subject: [PATCH 035/146] feat(runtime/audio/bindChart): Update audio duration beat when chart BPM updated --- src/runtime/audio/bindChart.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/runtime/audio/bindChart.ts b/src/runtime/audio/bindChart.ts index a69864f..3fbfd87 100644 --- a/src/runtime/audio/bindChart.ts +++ b/src/runtime/audio/bindChart.ts @@ -41,21 +41,25 @@ const applyNewClip = (clip?: Clip) => { // Listen to chart metadata changes onPatch(ChartStore, (patch) => { - if (!patch.path.startsWith('/metadata')) return; - if (patch.path === '/metadata' && patch.op === 'replace') { const value = patch.value as Nullable>>; if (!value) return; if (!value.musicFile) return; - applyNewClip(audioCache.get(value.musicFile)); + return applyNewClip(audioCache.get(value.musicFile)); } if (patch.path === '/metadata/musicFile' && patch.op === 'replace') { const value = patch.value as string | undefined; if (!value) return; - applyNewClip(audioCache.get(value)); + return applyNewClip(audioCache.get(value)); + } + + if (patch.path.startsWith('/bpm')) { + const { musicClip } = runtimeAudioStore.getState(); + if (!musicClip) return; + return runtimeAudioStore.setState({ durationBeat: getBeatByTime(musicClip.duration) }); } }); From 7c6ca8b89e3024476dce4367f60db82f007ef349 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Wed, 3 Sep 2025 18:56:37 +0800 Subject: [PATCH 036/146] Refactor: Add a simple new preview renderer --- src/renderer/preview/app.ts | 3 + src/renderer/preview/classes/Application.ts | 107 ++++++++++++++++++++ src/renderer/preview/classes/JudgeLine.ts | 23 +++++ src/renderer/types.ts | 12 +++ src/ui/Panel/PreviewPanel/Canvas.tsx | 95 ++++------------- 5 files changed, 164 insertions(+), 76 deletions(-) create mode 100644 src/renderer/preview/app.ts create mode 100644 src/renderer/preview/classes/Application.ts create mode 100644 src/renderer/preview/classes/JudgeLine.ts create mode 100644 src/renderer/types.ts diff --git a/src/renderer/preview/app.ts b/src/renderer/preview/app.ts new file mode 100644 index 0000000..65a7ef0 --- /dev/null +++ b/src/renderer/preview/app.ts @@ -0,0 +1,3 @@ +import { PreviewApplication } from './classes/Application'; + +export const app = new PreviewApplication(); diff --git a/src/renderer/preview/classes/Application.ts b/src/renderer/preview/classes/Application.ts new file mode 100644 index 0000000..1545197 --- /dev/null +++ b/src/renderer/preview/classes/Application.ts @@ -0,0 +1,107 @@ +import { Application, Container } from 'pixi.js'; +import { onPatch, SnapshotOut } from 'mobx-state-tree'; +import { store as ChartStore } from '@/core/state/chartStore'; +import { JudgeLineSprite } from './JudgeLine'; +import { ApplicationOptions } from 'pixi.js'; +import { IJsonPatch } from 'mobx-state-tree'; +import { JudgeLine } from '@/core/models/JudgeLine'; +import { PreviewSize } from '@/renderer/types'; + +const JudgeLinePathReg = /^\/judgelines\/(\d+)$/; + +export class PreviewApplication extends Application { + private containerGame = new Container(); + private containerUI = new Container(); + + private size: PreviewSize = { + width: 0, + height: 0, + widthHalf: 0, + heightHalf: 0, + noteScale: 0, + lineScale: 0, + heightPercent: 0, + }; + + private lines: JudgeLineSprite[] = []; + private onInitCallbacks: (() => void)[] = []; + + constructor(rendererOptions: Partial = {}) { + super(); + + this.init({ + hello: true, + ...rendererOptions, + }).then(() => { + this.triggerInitCallback(); + + this.stage.addChild(this.containerGame); + this.stage.addChild(this.containerUI); + }); + + onPatch(ChartStore, (patch) => this.handleChartPatch(patch)); + } + + $resize(width: number, height: number) { + if (!this.renderer) return; + + this.renderer.resize(width, height); + this.calculatePreviewSize(width, height); + this.render(); + } + + addOnInitCallback(callback: () => void) { + this.onInitCallbacks.push(callback); + + return (() => { + this.onInitCallbacks = this.onInitCallbacks.filter(e => e !== callback); + }); + } + + private handleChartPatch(patch: IJsonPatch) { + if (!patch.path.startsWith('/judgelines')) return; + + if (JudgeLinePathReg.test(patch.path)) { + const [ , idStr ] = JudgeLinePathReg.exec(patch.path)!; + const id = parseInt(idStr); + const lineState = patch.value as SnapshotOut; + + if (patch.op === 'add') { + const lineSprite = new JudgeLineSprite(lineState.id, this.containerGame); + lineSprite.resize(this.size); + this.lines[id] = lineSprite; + } + return; + } + } + + private triggerInitCallback() { + for (const cb of this.onInitCallbacks) { + cb(); + } + } + + private calculatePreviewSize(width: number, height: number) { + const { size } = this; + + size.width = width; + size.height = height; + + size.widthHalf = size.width / 2; + size.heightHalf = size.height / 2; + + size.noteScale = size.width / 8080; + size.lineScale = size.width > size.height * 0.75 ? size.height / 18.75 : size.width / 14.0625 + + size.heightPercent = size.height / 1080; + + // Apply size to containers + this.containerGame.x = size.widthHalf; + this.containerGame.y = size.heightHalf; + + // Apply size to lines + for (const line of this.lines) { + line.resize(size); + } + } +}; diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts new file mode 100644 index 0000000..994d6fa --- /dev/null +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -0,0 +1,23 @@ +import { Sprite, Texture, Container } from 'pixi.js'; +import { PreviewSize } from '@/renderer/types'; + +const LineWidthBase = 4000; +const LineHeightBase = 18.75 * 0.008; + +export class JudgeLineSprite extends Sprite { + private readonly id: string; + + constructor(id: string, container: Container) { + super(Texture.WHITE); + + this.anchor.set(0.5); + container.addChild(this); + + this.id = id; + } + + resize(size: PreviewSize) { + this.scale.x = Math.round(LineWidthBase * (size.width / 1350)); + this.scale.y = Math.round(size.lineScale * LineHeightBase); + } +} diff --git a/src/renderer/types.ts b/src/renderer/types.ts new file mode 100644 index 0000000..e23f05d --- /dev/null +++ b/src/renderer/types.ts @@ -0,0 +1,12 @@ + +export type PreviewSize = { + width: number, + height: number, + widthHalf: number, + heightHalf: number, + + noteScale: number, + lineScale: number, + + heightPercent: number, +}; diff --git a/src/ui/Panel/PreviewPanel/Canvas.tsx b/src/ui/Panel/PreviewPanel/Canvas.tsx index 7552ec0..ad61424 100644 --- a/src/ui/Panel/PreviewPanel/Canvas.tsx +++ b/src/ui/Panel/PreviewPanel/Canvas.tsx @@ -1,96 +1,39 @@ -import { Application, ApplicationRef, extend } from '@pixi/react'; -import { Container, Rectangle } from 'pixi.js'; -import { useCallback, useEffect, useRef } from 'react'; -import Chart from '@/Chart/Chart'; -import { CalculateRendererSize } from '@/utils/renderer'; -import { Nullable, RendererSize } from '@/utils/types'; - -const ZeroSizeRectangle = new Rectangle(0, 0, 0, 0); +import { useEffect, useRef } from 'react'; +import useResizeEffect from '@/ui/hooks/useResizeEffect'; +import { app as previewApp } from '@/renderer/preview/app'; const PreviewCanvas = () => { - extend({ Container }); - - const containerRef = useRef>(null); - const appRef = useRef>(null); - const appContainerRef = useRef>(null); - const sizeRef = useRef(CalculateRendererSize(1, 1)); - - const handleResize = useCallback(() => { - const containerDom = containerRef.current; - if (!containerDom) return; - const { clientWidth, clientHeight } = containerDom; - - if (!appRef.current) return; - const app = appRef.current.getApplication(); - if (!app) return; - - app.resize(); - const size = CalculateRendererSize(clientWidth, clientHeight); - sizeRef.current = size; - Chart.resize(size); - }, []); + const containerRef = useRef(null); - const handleChartChanged = () => { - if (!Chart.info) return; - if (!appContainerRef.current) return; + const handleAppendCanvas = () => { + if (!containerRef.current) return; + if (!previewApp.renderer) return; - const container = appContainerRef.current; - if (container.children.length !== 0) { - for (const child of container.children) { - container.removeChild(child); - } - } + if (previewApp.canvas.parentElement) + previewApp.canvas.parentElement.removeChild(previewApp.canvas); - Chart.resize(sizeRef.current); - container.addChild(Chart.container); + containerRef.current.appendChild(previewApp.canvas); }; useEffect(() => { if (!containerRef.current) return; + if (previewApp.renderer) return handleAppendCanvas(); - handleResize(); - const resize = new ResizeObserver(() => { - handleResize(); - }); - resize.observe(containerRef.current); - - return (() => { - resize.disconnect(); - }) - }, [handleResize]); - - useEffect(() => { - Chart.events.on('loaded', handleChartChanged); - return (() => { - Chart.events.off('loaded', handleChartChanged); + return previewApp.addOnInitCallback(() => { + handleAppendCanvas(); }); }, []); + useResizeEffect((size) => { + previewApp.$resize(size.width, size.height); + }, containerRef); + return (
- { - handleResize(); - }} - ref={appRef} - > - - - -
- ) + >
+ ); }; export default PreviewCanvas; From d747cd5bf7f6b9167cc83a1b0bb5fe85be8c5d80 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Wed, 3 Sep 2025 22:12:27 +0800 Subject: [PATCH 037/146] feat(ui/Panel/PreviewPanel): Resize canvas when initialized --- src/ui/Panel/PreviewPanel/Canvas.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/Panel/PreviewPanel/Canvas.tsx b/src/ui/Panel/PreviewPanel/Canvas.tsx index ad61424..ac243a6 100644 --- a/src/ui/Panel/PreviewPanel/Canvas.tsx +++ b/src/ui/Panel/PreviewPanel/Canvas.tsx @@ -13,6 +13,7 @@ const PreviewCanvas = () => { previewApp.canvas.parentElement.removeChild(previewApp.canvas); containerRef.current.appendChild(previewApp.canvas); + previewApp.$resize(containerRef.current.clientWidth, containerRef.current.clientHeight); }; useEffect(() => { From e7ec1321a117963f6b295b9955daef92acbc47e1 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Wed, 3 Sep 2025 23:20:25 +0800 Subject: [PATCH 038/146] feat(core/models): Add real time cache --- src/core/models/Chart.ts | 5 +++++ src/core/models/JudgeLine.ts | 5 +++++ src/core/models/Keyframe.ts | 12 ++++++++++++ src/core/models/KeyframeRecord.ts | 8 ++++++++ src/core/models/Note.ts | 19 +++++++++++++++++-- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index fd82401..f19e4da 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -58,6 +58,11 @@ export const Chart = types.model('Chart', { updateBPMCache() { self.bpmCache = calculateBPMCache(self.bpm); + this.updateTimeCache(); + }, + + updateTimeCache() { + for (const line of self.judgelines) line.updateTimeCache(); } })); diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index 331754f..0331153 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -23,6 +23,11 @@ export const JudgeLine = types.model('JudgeLine', { removeNote(id: string) { const index = self.notes.findIndex(e => e.id === id); if (index >= 0) self.notes.splice(index, 1); + }, + + updateTimeCache() { + self.keyframes.updateTimeCache(); + for (const n of self.notes) n.updateTimeCache(); } })); diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 7c388bb..29c8902 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -1,6 +1,7 @@ import { nanoid } from 'nanoid'; import { types, getParent, Instance, SnapshotIn } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; +import { getTimeByBeat } from '../timeline/bpm'; import { BeatArrayToNumber } from '@/utils/math'; import { KeyframeType } from '../types'; @@ -22,9 +23,20 @@ export const Keyframe = types.model('Keyframe', { get beatNum() { return BeatArrayToNumber(self.beat); } +})).volatile(() => ({ + time: 0, })).actions((self) => ({ + afterCreate() { + this.updateTimeCache(); + }, + updateProps(props: Partial, 'id' | 'type'>>) { Object.assign(self, props); + this.updateTimeCache(); + }, + + updateTimeCache() { + self.time = getTimeByBeat(self.beatNum); } })); diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts index d70ddc6..7961050 100644 --- a/src/core/models/KeyframeRecord.ts +++ b/src/core/models/KeyframeRecord.ts @@ -56,6 +56,14 @@ export const KeyframeRecord = types.model('KeyframeRecord', { const index = self[type].findIndex(e => e.id === id); if (index >= 0) self[type].splice(index, 1); }, + + updateTimeCache() { + for (const k of self.positionX) k.updateTimeCache(); + for (const k of self.positionY) k.updateTimeCache(); + for (const k of self.rotate) k.updateTimeCache(); + for (const k of self.alpha) k.updateTimeCache(); + for (const k of self.speed) k.updateTimeCache(); + }, })); export type IKeyframeRecord = Instance; diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index e23ee02..d40538c 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -1,7 +1,8 @@ import { nanoid } from 'nanoid'; import { types, getParent, Instance, SnapshotIn } from 'mobx-state-tree'; import { BeatArray } from '@/core/utils/model'; -import { BeatArrayToNumber } from '@/utils/math'; +import { getTimeByBeat } from '../timeline/bpm'; +import { BeatArrayToNumber, parseDoublePrecist } from '@/utils/math'; import { NoteType } from '../types'; import { BeatArray as TBeatArray } from '@/utils/types'; @@ -14,7 +15,11 @@ export const Note = types.model('Note', { isAbove: types.boolean, holdEndBeat: types.optional(BeatArray, [ 0, 0, 1 ]), -}).postProcessSnapshot((self) => { +}).volatile(() => ({ + time: 0, + holdEndTime: 0, + holdLengthTime: 0, +})).postProcessSnapshot((self) => { if ( self.holdEndBeat && BeatArrayToNumber(self.beat as TBeatArray) > BeatArrayToNumber(self.holdEndBeat as TBeatArray) @@ -41,8 +46,18 @@ export const Note = types.model('Note', { return BeatArrayToNumber(self.holdEndBeat) - BeatArrayToNumber(self.beat); } })).actions((self) => ({ + afterCreate() { + this.updateTimeCache(); + }, + updateProps(props: Omit>, 'id'>) { Object.assign(self, props); + }, + + updateTimeCache() { + self.time = getTimeByBeat(self.beatNum); + self.holdEndTime = self.type === NoteType.Hold ? getTimeByBeat(self.holdEndBeatNum) : self.time; + self.holdLengthTime = parseDoublePrecist(self.holdEndTime - self.time, 6, -1); } })); From 70ef0b44dfc18af465405f264fce5750adf7f75b Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Thu, 4 Sep 2025 16:59:18 +0800 Subject: [PATCH 039/146] feat(renderer/preview/classes/JudgeLine): Add sorted keyframes cache --- src/renderer/preview/classes/Application.ts | 7 ++- src/renderer/preview/classes/JudgeLine.ts | 53 +++++++++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/renderer/preview/classes/Application.ts b/src/renderer/preview/classes/Application.ts index 1545197..10e93b3 100644 --- a/src/renderer/preview/classes/Application.ts +++ b/src/renderer/preview/classes/Application.ts @@ -1,10 +1,9 @@ import { Application, Container } from 'pixi.js'; -import { onPatch, SnapshotOut } from 'mobx-state-tree'; +import { onPatch } from 'mobx-state-tree'; import { store as ChartStore } from '@/core/state/chartStore'; import { JudgeLineSprite } from './JudgeLine'; import { ApplicationOptions } from 'pixi.js'; import { IJsonPatch } from 'mobx-state-tree'; -import { JudgeLine } from '@/core/models/JudgeLine'; import { PreviewSize } from '@/renderer/types'; const JudgeLinePathReg = /^\/judgelines\/(\d+)$/; @@ -64,10 +63,10 @@ export class PreviewApplication extends Application { if (JudgeLinePathReg.test(patch.path)) { const [ , idStr ] = JudgeLinePathReg.exec(patch.path)!; const id = parseInt(idStr); - const lineState = patch.value as SnapshotOut; + const lineState = ChartStore.judgelines[id]; if (patch.op === 'add') { - const lineSprite = new JudgeLineSprite(lineState.id, this.containerGame); + const lineSprite = new JudgeLineSprite(lineState, this.containerGame); lineSprite.resize(this.size); this.lines[id] = lineSprite; } diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts index 994d6fa..3fa0526 100644 --- a/src/renderer/preview/classes/JudgeLine.ts +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -1,23 +1,70 @@ import { Sprite, Texture, Container } from 'pixi.js'; +import { onPatch } from 'mobx-state-tree'; +import { IDisposer, IJsonPatch } from 'mobx-state-tree'; +import { IJudgeLine } from '@/core/models/JudgeLine'; +import { IKeyframe } from '@/core/models/Keyframe'; import { PreviewSize } from '@/renderer/types'; +import { KeyframeType } from '@/core/types'; + +type $KeyframeCaches = { + [K in KeyframeType]: IKeyframe[]; +} const LineWidthBase = 4000; const LineHeightBase = 18.75 * 0.008; +const KeyframeTypeReg = /^\/keyframes\/([a-zA-Z]+)/; + export class JudgeLineSprite extends Sprite { - private readonly id: string; + private readonly state: IJudgeLine; + private readonly patchDisposer: IDisposer; + + readonly keyframes: $KeyframeCaches = { + [KeyframeType.PositionX]: [], + [KeyframeType.PositionY]: [], + [KeyframeType.Rotate]: [], + [KeyframeType.Alpha]: [], + [KeyframeType.Speed]: [] + }; - constructor(id: string, container: Container) { + constructor(state: IJudgeLine, container: Container) { super(Texture.WHITE); + this.state = state; + this.updateAllKeyframesCache(); + this.anchor.set(0.5); container.addChild(this); - this.id = id; + this.patchDisposer = onPatch(this.state, (p) => this.handlePatch(p)); } resize(size: PreviewSize) { this.scale.x = Math.round(LineWidthBase * (size.width / 1350)); this.scale.y = Math.round(size.lineScale * LineHeightBase); } + + $destroy() { + this.patchDisposer(); + } + + private handlePatch(patch: IJsonPatch) { + if (KeyframeTypeReg.test(patch.path)) { + const type = patch.path.match(KeyframeTypeReg)![1] as KeyframeType; + this.updateKeyframesCache(type); + return; + } + } + + private updateKeyframesCache(type: KeyframeType) { + this.keyframes[type] = this.state.keyframes[type].slice().sort((a, b) => a.time - b.time); + } + + private updateAllKeyframesCache() { + this.updateKeyframesCache(KeyframeType.PositionX); + this.updateKeyframesCache(KeyframeType.PositionY); + this.updateKeyframesCache(KeyframeType.Rotate); + this.updateKeyframesCache(KeyframeType.Alpha); + this.updateKeyframesCache(KeyframeType.Speed); + } } From 079e6cc401b092a8780dde9bf9a693b249230199 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Thu, 4 Sep 2025 17:35:54 +0800 Subject: [PATCH 040/146] feat(renderer/preview): Make line move --- src/renderer/preview/classes/Application.ts | 14 +++++++++ src/renderer/preview/ticker.ts | 33 +++++++++++++++++++++ src/renderer/utils.ts | 32 ++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/renderer/preview/ticker.ts create mode 100644 src/renderer/utils.ts diff --git a/src/renderer/preview/classes/Application.ts b/src/renderer/preview/classes/Application.ts index 10e93b3..97be599 100644 --- a/src/renderer/preview/classes/Application.ts +++ b/src/renderer/preview/classes/Application.ts @@ -1,10 +1,14 @@ import { Application, Container } from 'pixi.js'; import { onPatch } from 'mobx-state-tree'; import { store as ChartStore } from '@/core/state/chartStore'; +import { runtimeAudioStore } from '@/runtime/audio/state'; +import { UpdateRendererTick } from '../ticker'; import { JudgeLineSprite } from './JudgeLine'; import { ApplicationOptions } from 'pixi.js'; import { IJsonPatch } from 'mobx-state-tree'; +import { Clip } from '@phifans/audio'; import { PreviewSize } from '@/renderer/types'; +import { Nullable } from '@/utils/types'; const JudgeLinePathReg = /^\/judgelines\/(\d+)$/; @@ -22,6 +26,7 @@ export class PreviewApplication extends Application { heightPercent: 0, }; + private musicClip: Nullable = null; private lines: JudgeLineSprite[] = []; private onInitCallbacks: (() => void)[] = []; @@ -36,9 +41,18 @@ export class PreviewApplication extends Application { this.stage.addChild(this.containerGame); this.stage.addChild(this.containerUI); + + this.ticker.add(() => { + UpdateRendererTick( + this.size, + this.lines, + this.musicClip, + ); + }); }); onPatch(ChartStore, (patch) => this.handleChartPatch(patch)); + runtimeAudioStore.subscribe((s) => this.musicClip = s.musicClip); } $resize(width: number, height: number) { diff --git a/src/renderer/preview/ticker.ts b/src/renderer/preview/ticker.ts new file mode 100644 index 0000000..3a6add8 --- /dev/null +++ b/src/renderer/preview/ticker.ts @@ -0,0 +1,33 @@ +import { Clip } from '@phifans/audio'; +import { calculateLineValue } from '../utils'; +import { Nullable } from '@/utils/types'; +import { JudgeLineSprite } from './classes/JudgeLine'; +import { PreviewSize } from '../types'; + +export const UpdateRendererTick = ( + size: PreviewSize, + lines: JudgeLineSprite[], + clip: Nullable +) => { + if (lines.length === 0) return; + if (clip === null) return; + + const { + widthHalf, + heightHalf, + } = size; + const { currentTime } = clip; + + for (const line of lines) { + const { keyframes } = line; + + const lineSpeed = calculateLineValue(currentTime, keyframes.speed, 1); + const linePosX = calculateLineValue(currentTime, keyframes.positionX, 0); + const linePosY = calculateLineValue(currentTime, keyframes.positionY, 0); + const lineRotate = calculateLineValue(currentTime, keyframes.rotate, 0); + const lineAlpha = calculateLineValue(currentTime, keyframes.alpha, 255); + + line.x = linePosX / 100 * widthHalf; + line.y = linePosY / -100 * heightHalf; + } +}; diff --git a/src/renderer/utils.ts b/src/renderer/utils.ts new file mode 100644 index 0000000..e115de5 --- /dev/null +++ b/src/renderer/utils.ts @@ -0,0 +1,32 @@ +import Easings from '@/utils/easings'; +import { IKeyframe } from '@/core/models/Keyframe'; + +export const calculateLineValue = (time: number, keyframes: IKeyframe[], defaultValue = 0) => { + const { length } = keyframes; + let lastKeyframeValue = defaultValue; + + for (let i = 0; i < length; i++) { + const keyframe = keyframes[i]; + const keyframeNext = keyframes[i + 1]; + + if (time === keyframe.time) return keyframe.value; + + if (keyframe.time > time) { + if (i === 0) break; + return keyframes[i - 1].value; + } + if (keyframe.time < time) { + if (!keyframeNext || !keyframeNext.continuous || keyframeNext.time <= time) { + lastKeyframeValue = keyframe.value; + continue; + } + + const timePercentEnd = Easings[keyframeNext.easing]( + (time - keyframe.time) / (keyframeNext.time - keyframe.time) + ); + return keyframe.value * (1 - timePercentEnd) + keyframeNext.value * timePercentEnd; + } + } + + return lastKeyframeValue; +}; From 91318e40f54cc15a4c06507a9a0fa3fa513c2cd3 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Thu, 4 Sep 2025 18:32:45 +0800 Subject: [PATCH 041/146] feat(renderer/preview/classes/JudgeLine): Calculate floor position --- src/renderer/preview/classes/JudgeLine.ts | 62 ++++++++++++++++++++++- src/renderer/types.ts | 5 ++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts index 3fa0526..0a89848 100644 --- a/src/renderer/preview/classes/JudgeLine.ts +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -3,8 +3,10 @@ import { onPatch } from 'mobx-state-tree'; import { IDisposer, IJsonPatch } from 'mobx-state-tree'; import { IJudgeLine } from '@/core/models/JudgeLine'; import { IKeyframe } from '@/core/models/Keyframe'; -import { PreviewSize } from '@/renderer/types'; +import { FloorPosition, PreviewSize } from '@/renderer/types'; import { KeyframeType } from '@/core/types'; +import { calculateLineValue } from '@/renderer/utils'; +import { parseDoublePrecist } from '@/utils/math'; type $KeyframeCaches = { [K in KeyframeType]: IKeyframe[]; @@ -19,6 +21,7 @@ export class JudgeLineSprite extends Sprite { private readonly state: IJudgeLine; private readonly patchDisposer: IDisposer; + readonly floorPositions: FloorPosition[] = []; readonly keyframes: $KeyframeCaches = { [KeyframeType.PositionX]: [], [KeyframeType.PositionY]: [], @@ -56,8 +59,65 @@ export class JudgeLineSprite extends Sprite { } } + private updateFloorPositions() { + const keyframes = this.keyframes.speed; + this.floorPositions.length = 0; + + for (let i = 0; i < keyframes.length; i++) { + const keyframe = keyframes[i]; + const nextKeyframe = keyframes[i + 1]; + + if (!nextKeyframe || !nextKeyframe.continuous || nextKeyframe.value === keyframe.value) { + this.floorPositions.push({ + time: keyframe.time, + value: NaN, + }); + continue; + } + + const beatBetween = nextKeyframe.beatNum - keyframe.beatNum; + for (let i = 0, count = Math.ceil(beatBetween / 0.125); i < count; i++) { + const beatPercent = i / count; + const currentTime = keyframe.time * (1 - beatPercent) + nextKeyframe.time * beatPercent; + + this.floorPositions.push({ + time: currentTime, + value: NaN, + }); + } + + this.floorPositions.push({ + time: nextKeyframe.time, + value: NaN, + }); + } + + this.floorPositions.sort((a, b) => a.time - b.time); + if (this.floorPositions[0].time > 0) { + this.floorPositions.unshift({ + time: 0, + value: NaN, + }); + } + + let currentFloorPosition = parseDoublePrecist(( + this.floorPositions[0].time * calculateLineValue(this.floorPositions[0].time, keyframes, 1) + ), 3, -1); + for (let i = 0; i < this.floorPositions.length; i++) { + const event = this.floorPositions[i]; + const eventNext = this.floorPositions[i + 1]; + + event.value = currentFloorPosition; + + if (eventNext) currentFloorPosition = parseDoublePrecist(currentFloorPosition + ( + (eventNext.time - event.time) + calculateLineValue(event.time, keyframes, 1) + ), 3, -1); + } + } + private updateKeyframesCache(type: KeyframeType) { this.keyframes[type] = this.state.keyframes[type].slice().sort((a, b) => a.time - b.time); + if (type === KeyframeType.Speed) this.updateFloorPositions(); } private updateAllKeyframesCache() { diff --git a/src/renderer/types.ts b/src/renderer/types.ts index e23f05d..40d762d 100644 --- a/src/renderer/types.ts +++ b/src/renderer/types.ts @@ -10,3 +10,8 @@ export type PreviewSize = { heightPercent: number, }; + +export type FloorPosition = { + time: number, + value: number, +}; From 2d560a1dc8a32e26e25fcf69814282f9867774d7 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Thu, 4 Sep 2025 18:45:42 +0800 Subject: [PATCH 042/146] refactor(runtime/resources): Cache `Texture` instead of `Sprite` --- src/renderer/preview/classes/Application.ts | 3 ++- src/renderer/preview/classes/JudgeLine.ts | 6 +++--- src/runtime/resources/cache.ts | 11 ++++------- src/runtime/resources/loader/image.ts | 9 ++++----- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/renderer/preview/classes/Application.ts b/src/renderer/preview/classes/Application.ts index 97be599..0686c40 100644 --- a/src/renderer/preview/classes/Application.ts +++ b/src/renderer/preview/classes/Application.ts @@ -80,8 +80,9 @@ export class PreviewApplication extends Application { const lineState = ChartStore.judgelines[id]; if (patch.op === 'add') { - const lineSprite = new JudgeLineSprite(lineState, this.containerGame); + const lineSprite = new JudgeLineSprite(lineState); lineSprite.resize(this.size); + this.containerGame.addChild(lineSprite); this.lines[id] = lineSprite; } return; diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts index 0a89848..edd0d9a 100644 --- a/src/renderer/preview/classes/JudgeLine.ts +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -1,4 +1,4 @@ -import { Sprite, Texture, Container } from 'pixi.js'; +import { Sprite, Texture } from 'pixi.js'; import { onPatch } from 'mobx-state-tree'; import { IDisposer, IJsonPatch } from 'mobx-state-tree'; import { IJudgeLine } from '@/core/models/JudgeLine'; @@ -30,14 +30,13 @@ export class JudgeLineSprite extends Sprite { [KeyframeType.Speed]: [] }; - constructor(state: IJudgeLine, container: Container) { + constructor(state: IJudgeLine) { super(Texture.WHITE); this.state = state; this.updateAllKeyframesCache(); this.anchor.set(0.5); - container.addChild(this); this.patchDisposer = onPatch(this.state, (p) => this.handlePatch(p)); } @@ -49,6 +48,7 @@ export class JudgeLineSprite extends Sprite { $destroy() { this.patchDisposer(); + this.destroy(); } private handlePatch(patch: IJsonPatch) { diff --git a/src/runtime/resources/cache.ts b/src/runtime/resources/cache.ts index 3dade3a..a9cad23 100644 --- a/src/runtime/resources/cache.ts +++ b/src/runtime/resources/cache.ts @@ -1,6 +1,6 @@ import QuickLRU from 'quick-lru'; import { Clip } from '@phifans/audio'; -import { Sprite } from 'pixi.js'; +import { Texture } from 'pixi.js'; export const audioCache = new QuickLRU({ maxSize: 100, @@ -9,12 +9,9 @@ export const audioCache = new QuickLRU({ }, }); -export const imageCache = new QuickLRU({ +export const imageCache = new QuickLRU({ maxSize: 50, - onEviction: (_key, sprite) => { - sprite.destroy({ - texture: true, - textureSource: true, - }); + onEviction: (_key, texture) => { + texture.destroy(true); }, }); diff --git a/src/runtime/resources/loader/image.ts b/src/runtime/resources/loader/image.ts index 2f4dfdb..62b1220 100644 --- a/src/runtime/resources/loader/image.ts +++ b/src/runtime/resources/loader/image.ts @@ -1,15 +1,14 @@ -import { Texture, Sprite } from 'pixi.js'; +import { Texture } from 'pixi.js'; import { imageCache } from '../cache'; -export const loadImage = (file: Blob | File, filename?: string) => new Promise((res, rej) => { +export const loadImage = (file: Blob | File, filename?: string) => new Promise((res, rej) => { window.createImageBitmap(file) .then((bitmap) => { const texture = Texture.from(bitmap); - const sprite = Sprite.from(texture); const _filename = (file as File).name ?? filename; - imageCache.set(_filename, sprite); - res(sprite); + imageCache.set(_filename, texture); + res(texture); }) .catch(e => rej(e)); }); From dfef90df310ca7d4c2355755eecfddd2843a6111 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Thu, 4 Sep 2025 21:58:10 +0800 Subject: [PATCH 043/146] Refactor: Use dockview instead of rc-dock --- package.json | 2 +- pnpm-lock.yaml | 259 +++++---------------------------- src/ui/App.tsx | 33 ++--- src/ui/Panel/Components.tsx | 18 +++ src/ui/Panel/DefaultLayout.tsx | 56 +++++++ src/ui/Panel/PanelDock.tsx | 209 +++++++++++++------------- src/ui/styles/index.css | 3 - 7 files changed, 232 insertions(+), 348 deletions(-) create mode 100644 src/ui/Panel/Components.tsx create mode 100644 src/ui/Panel/DefaultLayout.tsx diff --git a/package.json b/package.json index 58c4a2c..2e503f6 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@pixi/react": "8.0.0", "@types/node": "^22.10.5", "audio-decode": "^2.2.2", + "dockview": "^4.7.1", "eventemitter3": "^5.0.1", "hotkeys-js": "^3.13.9", "i18next": "^24.2.3", @@ -37,7 +38,6 @@ "normalize.css": "^8.0.1", "pixi.js": "^8.6.6", "quick-lru": "^7.1.0", - "rc-dock": "^3.3.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-i18next": "^15.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad8c3fb..c1a01c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,6 +37,9 @@ importers: audio-decode: specifier: ^2.2.2 version: 2.2.2 + dockview: + specifier: ^4.7.1 + version: 4.7.1(react@19.0.0) eventemitter3: specifier: ^5.0.1 version: 5.0.1 @@ -76,9 +79,6 @@ importers: quick-lru: specifier: ^7.1.0 version: 7.1.0 - rc-dock: - specifier: ^3.3.0 - version: 3.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: specifier: ^19.0.0 version: 19.0.0 @@ -464,51 +464,61 @@ packages: resolution: {integrity: sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.34.7': resolution: {integrity: sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.34.7': resolution: {integrity: sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.34.7': resolution: {integrity: sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.34.7': resolution: {integrity: sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.34.7': resolution: {integrity: sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.34.7': resolution: {integrity: sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.34.7': resolution: {integrity: sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.34.7': resolution: {integrity: sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.34.7': resolution: {integrity: sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.34.7': resolution: {integrity: sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==} @@ -548,24 +558,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.10.3': resolution: {integrity: sha512-L07/4zKnIY2S/00bE+Yn3oEHkyGjWmGGE8Ta4luVCL+00s04EIwMoE1Hc8E8xFB5zLew5ViKFc5kNb5YZ/tRFQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.10.3': resolution: {integrity: sha512-cvTCekY4u0fBIDNfhv/2UxcOXqH4XJE2iNxKuQejS5KIapFJwrZ+fRQ2lha3+yopI/d2p96BlBEWTAcBzeTntw==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.10.3': resolution: {integrity: sha512-h9kUOTrSSpY9JNc41a+NMAwK62USk/pvNE9Fi/Pfoklmlf9j9j8gRCitqvHpmZcEF4PPIsoMdiGetDipTwvWlw==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.10.3': resolution: {integrity: sha512-iHOmLYkZYn3r1Ff4rfyczdrYGt/wVIWyY0t8swsO9o1TE+zmucGFZuYZzgj3ng8Kp4sojJrydAGz8TINQZDBzQ==} @@ -623,24 +637,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tauri-apps/cli-linux-arm64-musl@2.2.7': resolution: {integrity: sha512-+8HZ+txff/Y3YjAh80XcLXcX8kpGXVdr1P8AfjLHxHdS6QD4Md+acSxGTTNbplmHuBaSHJvuTvZf9tU1eDCTDg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tauri-apps/cli-linux-x64-gnu@2.2.7': resolution: {integrity: sha512-ahlSnuCnUntblp9dG7/w5ZWZOdzRFi3zl0oScgt7GF4KNAOEa7duADsxPA4/FT2hLRa0SvpqtD4IYFvCxoVv3Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tauri-apps/cli-linux-x64-musl@2.2.7': resolution: {integrity: sha512-+qKAWnJRSX+pjjRbKAQgTdFY8ecdcu8UdJ69i7wn3ZcRn2nMMzOO2LOMOTQV42B7/Q64D1pIpmZj9yblTMvadA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tauri-apps/cli-win32-arm64-msvc@2.2.7': resolution: {integrity: sha512-aa86nRnrwT04u9D9fhf5JVssuAZlUCCc8AjqQjqODQjMd4BMA2+d4K9qBMpEG/1kVh95vZaNsLogjEaqSTTw4A==} @@ -840,9 +858,6 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -943,13 +958,18 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + dockview-core@4.7.1: + resolution: {integrity: sha512-Tia3vYHtqACMZTiZv86yQOabwKj5KrBhQqlSr7qXV0qmmRSZ8dNbaU63LIHYFprST7JgHupIm9JVES+OhqMoTQ==} + + dockview@4.7.1: + resolution: {integrity: sha512-DgMzSKNjDvZzIQjFfAV6I6EDkqe40Sjz1Qgyf88KG4U1Kgp/bIIEDSLpz65BsW5ZD9Qi3y18TCISYTgsNvU9TA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dom-align@1.12.4: - resolution: {integrity: sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==} - dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} @@ -1377,9 +1397,6 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1581,80 +1598,6 @@ packages: resolution: {integrity: sha512-Pzd/4IFnTb8E+I1P5rbLQoqpUHcXKg48qTYKi4EANg+sTPwGFEMOcYGiiZz6xuQcOMZP7MPsrdAPx+16Q8qahg==} engines: {node: '>=18'} - rc-align@4.0.15: - resolution: {integrity: sha512-wqJtVH60pka/nOX7/IspElA8gjPNQKIx/ZqJ6heATCkXpe1Zg4cPVrMD2vC96wjsFFL8WsmhPbx9tdMo1qqlIA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-dock@3.3.0: - resolution: {integrity: sha512-9rQAzHSLAdQz1ZpPqQGkZKlAt4YI6gNYjuqqpY6hIWBFDhVPccs0jYr7L7PP3OpmliZ/R60LgHfLFbrL9l+Tlg==} - peerDependencies: - react: '>=17.0.0' - react-dom: '>=17.0.0' - - rc-dropdown@4.0.1: - resolution: {integrity: sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==} - peerDependencies: - react: '>=16.11.0' - react-dom: '>=16.11.0' - - rc-menu@9.6.4: - resolution: {integrity: sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-menu@9.8.4: - resolution: {integrity: sha512-lmw2j8I2fhdIzHmC9ajfImfckt0WDb2KVJJBBRIsxPEw2kGkEfjLMUoB1NgiNT/Q5cC8PdjGOGQjHJIJMwyNMw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-motion@2.9.5: - resolution: {integrity: sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-new-window@0.1.13: - resolution: {integrity: sha512-KqANLQVfgNcfs+R4ntpzV5ELyqXMlAUimdSfFHapk2VwsoZX3y+BK2RjFBFb7q865yqAshP87g0PbIPqblKVTg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-overflow@1.4.1: - resolution: {integrity: sha512-3MoPQQPV1uKyOMVNd6SZfONi+f3st0r8PksexIdBTeIYbMX0Jr+k7pHEDvsXtR4BpCv90/Pv2MovVNhktKrwvw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-resize-observer@1.4.3: - resolution: {integrity: sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-tabs@11.16.1: - resolution: {integrity: sha512-bR7Dap23YyfzZQwtKomhiFEFzZuE7WaKWo+ypNRSGB9PDKSc6tM12VP8LWYkvmmQHthgwP0WRN8nFbSJWuqLYw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-trigger@5.3.4: - resolution: {integrity: sha512-mQv+vas0TwKcjAO2izNPkqR4j86OemLRmvL2nOzdP9OWNWA1ivoTt5hzFqYNW9zACwmTezRiN8bttrC7cZzYSw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-util@5.44.3: - resolution: {integrity: sha512-q6KCcOFk3rv/zD3MckhJteZxb0VjAIFuf622B7ElK4vfrZdAzs16XR5p3VTdy3+U5jfJU5ACz4QnhLSuAGe5dA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - react-dom@19.0.0: resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} peerDependencies: @@ -1679,9 +1622,6 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} @@ -1738,9 +1678,6 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - resize-observer-polyfill@1.5.1: - resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1803,9 +1740,6 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2658,8 +2592,6 @@ snapshots: balanced-match@1.0.2: {} - bowser@2.11.0: {} - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2791,12 +2723,17 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + dockview-core@4.7.1: {} + + dockview@4.7.1(react@19.0.0): + dependencies: + dockview-core: 4.7.1 + react: 19.0.0 + doctrine@2.1.0: dependencies: esutils: 2.0.3 - dom-align@1.12.4: {} - dom-helpers@5.2.1: dependencies: '@babel/runtime': 7.26.0 @@ -3376,8 +3313,6 @@ snapshots: lodash.merge@4.6.2: {} - lodash@4.17.21: {} - loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -3582,122 +3517,6 @@ snapshots: quick-lru@7.1.0: {} - rc-align@4.0.15(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - dom-align: 1.12.4 - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - resize-observer-polyfill: 1.5.1 - - rc-dock@3.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - classnames: 2.5.1 - lodash: 4.17.21 - rc-dropdown: 4.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-menu: 9.8.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-new-window: 0.1.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-tabs: 11.16.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-dropdown@4.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-trigger: 5.3.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-menu@9.6.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-motion: 2.9.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-overflow: 1.4.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-trigger: 5.3.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - shallowequal: 1.1.0 - - rc-menu@9.8.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-motion: 2.9.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-overflow: 1.4.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-trigger: 5.3.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-motion@2.9.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-new-window@0.1.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - bowser: 2.11.0 - classnames: 2.5.1 - lodash: 4.17.21 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-overflow@1.4.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-resize-observer: 1.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-resize-observer@1.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - resize-observer-polyfill: 1.5.1 - - rc-tabs@11.16.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-dropdown: 4.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-menu: 9.6.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-resize-observer: 1.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-trigger@5.3.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - classnames: 2.5.1 - rc-align: 4.0.15(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-motion: 2.9.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - rc-util: 5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - rc-util@5.44.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-is: 18.3.1 - react-dom@19.0.0(react@19.0.0): dependencies: react: 19.0.0 @@ -3716,8 +3535,6 @@ snapshots: react-is@16.13.1: {} - react-is@18.3.1: {} - react-lifecycles-compat@3.0.4: {} react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): @@ -3785,8 +3602,6 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - resize-observer-polyfill@1.5.1: {} - resolve-from@4.0.0: {} resolve@2.0.0-next.5: @@ -3881,8 +3696,6 @@ snapshots: setimmediate@1.0.5: {} - shallowequal@1.1.0: {} - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 diff --git a/src/ui/App.tsx b/src/ui/App.tsx index f2e20b8..fc32c36 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -3,11 +3,10 @@ import Chart from '@/Chart/Chart'; import PanelDock from './Panel/PanelDock'; import { PopupReadFiles, ReadFileAsText } from '@/utils/file'; import { Nullable } from '@/utils/types'; -import { useCallback, useRef, useState } from 'react'; +import { useCallback, useState } from 'react'; import AppBar from './Bar/AppBar'; import SettingsProvider from './contexts/Settings/Provider'; -import DockLayout from 'rc-dock'; -import SettingsPanel from './Panel/SettingsPanel/SettingsPanel'; +import { DockviewApi } from 'dockview'; import { ChartExported } from '@/Chart/Chart'; import NumberInput from './components/NumberInput'; import TopBar from './Bar/TopBar/TopBar'; @@ -18,7 +17,7 @@ import { audioCache } from '@/runtime/resources/cache'; import '@/runtime/audio/state'; function App() { - const dockRef = useRef>(null); + const [ dockviewApi, setDockviewApi ] = useState(); const [ tempo, setTempo ] = useState(4); let importedMusic: Nullable = null; @@ -100,18 +99,15 @@ function App() { setTempo(tempo); }, []); - const showSettingsPanel = () => { - const dock = dockRef.current; - if (!dock) return; - if (dock.find('settings-panel')) return; - - dock.dockMove({ - id: 'settings-panel', - title: 'Settings', - cached: true, - closable: true, - content: (), - }, null, 'float'); + const showSettingsPanel = (api?: DockviewApi) => { + if (!api) return; + const panel = api.getPanel('settingsPanel'); + if (panel) { + api.addFloatingGroup(panel, { + width: 400, + height: 300 + }); + } }; return ( @@ -129,13 +125,14 @@ function App() {
|
- +
diff --git a/src/ui/Panel/Components.tsx b/src/ui/Panel/Components.tsx new file mode 100644 index 0000000..06f386a --- /dev/null +++ b/src/ui/Panel/Components.tsx @@ -0,0 +1,18 @@ +import { IDockviewPanelProps } from 'dockview'; +import NotePanel from './NotePanel/NotePanel'; +import PreviewPanel from './PreviewPanel/PreviewPanel'; +import Timeline from './TimelinePanel/Timeline'; +import EditPanel from './EditPanel/EditPanel'; +import BPMPanel from './BPMPanel/BPMPanel'; +import SettingsPanel from './SettingsPanel/SettingsPanel'; + +const Components = { + notePanel: (_: IDockviewPanelProps) => , + previewPanel: (_: IDockviewPanelProps) => , + timeline: (_: IDockviewPanelProps) => , + editPanel: (_: IDockviewPanelProps) => , + bpmPanel: (_: IDockviewPanelProps) => , + settingsPanel: (_: IDockviewPanelProps) => , +}; + +export default Components; \ No newline at end of file diff --git a/src/ui/Panel/DefaultLayout.tsx b/src/ui/Panel/DefaultLayout.tsx new file mode 100644 index 0000000..c4588be --- /dev/null +++ b/src/ui/Panel/DefaultLayout.tsx @@ -0,0 +1,56 @@ +import { DockviewApi } from 'dockview'; + +const DefaultLayout = (api: DockviewApi) => { + console.log('Creating default layout'); + api.clear(); + + const timeline = api.addPanel({ + id: 'timeline', + component: 'timeline', + title: 'Timeline', + }); + + const notePanel = api.addPanel({ + id: 'note-panel', + component: 'notePanel', + title: 'Note panel', + initialWidth: 300, + position: { + referencePanel: timeline, + direction: 'above' + }, + }); + + const previewPanel = api.addPanel({ + id: 'live-preview', + component: 'previewPanel', + title: 'Live preview', + position: { + referencePanel: notePanel, + direction: 'right' + }, + }); + + const editPanel = api.addPanel({ + id: 'edit-panel', + component: 'editPanel', + title: 'Edit panel', + position: { + referencePanel: previewPanel, + direction: 'right' + }, + }); + + const bpmPanel = api.addPanel({ + id: 'bpm-panel', + component: 'bpmPanel', + title: 'BPM', + position: { + referencePanel: editPanel + }, + }); + + notePanel.api.setActive(); +}; + +export default DefaultLayout; \ No newline at end of file diff --git a/src/ui/Panel/PanelDock.tsx b/src/ui/Panel/PanelDock.tsx index 5215687..a6ec8b9 100644 --- a/src/ui/Panel/PanelDock.tsx +++ b/src/ui/Panel/PanelDock.tsx @@ -1,109 +1,112 @@ -import DockLayout, { LayoutData } from 'rc-dock'; -import NotePanel from './NotePanel/NotePanel'; -import PreviewPanel from './PreviewPanel/PreviewPanel'; -import Timeline from './TimelinePanel/Timeline'; -import EditPanel from './EditPanel/EditPanel'; -import BPMPanel from './BPMPanel/BPMPanel'; +import { useEffect, useState } from 'react'; +import { + DockviewReact, + DockviewReadyEvent, + DockviewApi, +} from 'dockview'; +import 'dockview/dist/styles/dockview.css'; +import Components from './Components'; +import DefaultLayout from './DefaultLayout'; import SelectedItemProvider from '../contexts/SelectedItem/Provider'; import ClockTimeProvider from '../contexts/Clock/Provider'; -import { Ref } from 'react'; - -const dockLayout: LayoutData = { - dockbox: { - mode: 'vertical', - children: [ - { - mode: 'horizontal', - children: [ - { - mode: 'vertical', - children: [ - { - mode: 'horizontal', - children: [ - { - size: 60, - tabs: [ - { - id: 'note-panel', - title: 'Note panel', - cached: true, - content: (), - } - ] - }, - { - tabs: [ - { - id: 'live-preview', - title: 'Live preview', - cached: true, - content: () - } - ] - }, - ] - }, - ] - }, - { - size: 60, - tabs: [ - { - id: 'edit-panel', - title: 'Edit panel', - cached: true, - content: (), - }, - { - id: 'bpm-panel', - title: 'BPM', - cached: true, - content: () - } - ] - } - ] - }, - { - size: 80, - tabs: [ - { - id: 'timeline', - title: 'Timeline', - cached: true, - content: () - } - ] - } - ] - }, -}; -type PanelDockProps = { - ref?: Ref, -}; +const PanelDock = (props: { api: DockviewApi | undefined, setApi: (api: DockviewApi) => void, theme?: string }) => { + const { api, setApi } = props; + + const [panels, setPanels] = useState([]); + const [groups, setGroups] = useState([]); + + const [activePanel, setActivePanel] = useState(); + const [activeGroup, setActiveGroup] = useState(); + + const onReady = (event: DockviewReadyEvent) => { + setApi(event.api); + setPanels([]); + setGroups([]); + setActivePanel(undefined); + setActiveGroup(undefined); + }; + + useEffect(() => { + if (!api) { + return; + } + + const disposables = [ + api.onDidAddPanel((event) => { + setPanels((_) => [..._, event.id]); + }), + api.onDidActivePanelChange((event) => { + setActivePanel(event?.id); + }), + api.onDidRemovePanel((event) => { + setPanels((_) => { + const next = [..._]; + next.splice( + next.findIndex((x) => x === event.id), + 1 + ); + + return next; + }); + }), + + api.onDidAddGroup((event) => { + setGroups((_) => [..._, event.id]); + }), + + api.onDidRemoveGroup((event) => { + setGroups((_) => { + const next = [..._]; + next.splice( + next.findIndex((x) => x === event.id), + 1 + ); + + return next; + }); + }), + api.onDidActiveGroupChange((event) => { + setActiveGroup(event?.id); + }), + ]; + + let success = false; + + const state = localStorage.getItem('layout-state'); + if (state) { + try { + api.fromJSON(JSON.parse(state)); + success = true; + } catch { + localStorage.removeItem('layout-state'); + } + } + + if (!success) { + DefaultLayout(api); + } + + DefaultLayout(api); + + return disposables.forEach((disposable) => disposable.dispose()); + }, [api]); -const PanelDock = ({ - ref -}: PanelDockProps) => { - return ( -
- - - - - -
- ); + return ( +
+ + + + + +
+ ); }; -export default PanelDock; +export default PanelDock; \ No newline at end of file diff --git a/src/ui/styles/index.css b/src/ui/styles/index.css index be7ca0c..cf9fb10 100644 --- a/src/ui/styles/index.css +++ b/src/ui/styles/index.css @@ -1,9 +1,6 @@ /* Default global color vars */ @import url('./colors.css'); -/* Default look of `rc-docs` */ -@import url('rc-dock/dist/rc-dock.css'); - /* Default look of BlueprintJS */ @import url('normalize.css'); @import url('@blueprintjs/core/lib/css/blueprint.css'); From a16658e3efa4e9b18ef8b994f037e664ea391018 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Thu, 4 Sep 2025 22:05:02 +0800 Subject: [PATCH 044/146] feat(ui/Panel): Fix Setting panel --- src/ui/App.tsx | 17 +++++++++-------- src/ui/Panel/DefaultLayout.tsx | 2 +- src/ui/Panel/PanelDock.tsx | 2 -- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index fc32c36..f9346a9 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -99,14 +99,15 @@ function App() { setTempo(tempo); }, []); - const showSettingsPanel = (api?: DockviewApi) => { - if (!api) return; - const panel = api.getPanel('settingsPanel'); + const showSettingsPanel = () => { + if (!dockviewApi) return; + const panel = dockviewApi.addPanel({ + id: 'settings', + component: 'settingsPanel', + title: 'Settings' + }); if (panel) { - api.addFloatingGroup(panel, { - width: 400, - height: 300 - }); + dockviewApi.addFloatingGroup(panel); } }; @@ -125,7 +126,7 @@ function App() {
|
- +
diff --git a/src/ui/Panel/DefaultLayout.tsx b/src/ui/Panel/DefaultLayout.tsx index c4588be..698024b 100644 --- a/src/ui/Panel/DefaultLayout.tsx +++ b/src/ui/Panel/DefaultLayout.tsx @@ -50,7 +50,7 @@ const DefaultLayout = (api: DockviewApi) => { }, }); - notePanel.api.setActive(); + previewPanel.api.setActive(); }; export default DefaultLayout; \ No newline at end of file diff --git a/src/ui/Panel/PanelDock.tsx b/src/ui/Panel/PanelDock.tsx index a6ec8b9..f1db9e8 100644 --- a/src/ui/Panel/PanelDock.tsx +++ b/src/ui/Panel/PanelDock.tsx @@ -87,8 +87,6 @@ const PanelDock = (props: { api: DockviewApi | undefined, setApi: (api: Dockview DefaultLayout(api); } - DefaultLayout(api); - return disposables.forEach((disposable) => disposable.dispose()); }, [api]); From 197d6b3c5608538c5dc295da0796e8708e5d018a Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 5 Sep 2025 16:57:43 +0800 Subject: [PATCH 045/146] refactor(core): Move `FloorPosition` cache to model volatile --- src/core/models/JudgeLine.ts | 74 ++++++++++++++- src/core/types.ts | 5 + src/core/utils/easings.ts | 174 +++++++++++++++++++++++++++++++++++ src/core/utils/math.ts | 41 +++++++++ 4 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 src/core/utils/easings.ts create mode 100644 src/core/utils/math.ts diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index 0331153..197c889 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -1,14 +1,28 @@ import { nanoid } from 'nanoid'; import { types, Instance } from 'mobx-state-tree'; +import { calculateLineValue } from '../utils/math'; import { KeyframeRecord } from './KeyframeRecord'; +import { parseDoublePrecist } from '@/utils/math'; import { Note } from './Note'; import { SnapshotIn } from 'mobx-state-tree'; +import { IKeyframe } from './Keyframe'; +import { KeyframeType } from '../types'; +import { FloorPosition } from '../types'; export const JudgeLine = types.model('JudgeLine', { id: types.optional(types.identifier, nanoid), keyframes: types.optional(KeyframeRecord, {}), notes: types.optional(types.array(Note), []), -}).actions((self) => ({ +}).volatile(() => ({ + keyframesCache: { + [KeyframeType.PositionX]: [] as IKeyframe[], + [KeyframeType.PositionY]: [] as IKeyframe[], + [KeyframeType.Rotate]: [] as IKeyframe[], + [KeyframeType.Alpha]: [] as IKeyframe[], + [KeyframeType.Speed]: [] as IKeyframe[], + }, + floorPositions: [] as FloorPosition[], +})).actions((self) => ({ addNote(props: SnapshotIn) { self.notes.push(props); }, @@ -24,6 +38,64 @@ export const JudgeLine = types.model('JudgeLine', { const index = self.notes.findIndex(e => e.id === id); if (index >= 0) self.notes.splice(index, 1); }, + + updateFloorPosition() { + const keyframes = self.keyframesCache.speed; + + self.floorPositions.length = 0; + + for (let i = 0; i < keyframes.length; i++) { + const keyframe = keyframes[i]; + const keyframeNext = keyframes[i + 1]; + + if (!keyframeNext || !keyframeNext.continuous || keyframeNext.value === keyframe.value) { + self.floorPositions.push({ + time: keyframe.time, + value: NaN, + }); + continue; + } + + const beatCount = Math.ceil((keyframeNext.beatNum - keyframe.beatNum) / 0.125); + for (let j = 0; j < beatCount; j++) { + const beatPercent = j / beatCount; + const currentTime = keyframe.time * (1 - beatPercent) + keyframeNext.time * beatPercent; + + self.floorPositions.push({ + time: currentTime, + value: NaN, + }); + } + + self.floorPositions.push({ + time: keyframeNext.time, + value: NaN, + }); + } + + self.floorPositions.sort((a, b) => a.time - b.time); + if (self.floorPositions[0].time > 0) { + self.floorPositions[0].time = 0; + } + + let currentFloorPosition = parseDoublePrecist(( + self.floorPositions[0].time * calculateLineValue(self.floorPositions[0].time, keyframes) + ), 3, -1); + for (let i = 0; i < self.floorPositions.length; i++) { + const event = self.floorPositions[i]; + const eventNext = self.floorPositions[i + 1]; + + event.value = currentFloorPosition; + if (eventNext) currentFloorPosition = parseDoublePrecist(currentFloorPosition + ( + (eventNext.time - event.time) + calculateLineValue(event.time, keyframes) + ), 3, -1); + } + }, + + updateKeyframeCache(type: KeyframeType) { + self.keyframesCache[type] = self.keyframes[type].slice().sort((a, b) => a.time - b.time); + if (type === KeyframeType.Speed) this.updateFloorPosition(); + }, updateTimeCache() { self.keyframes.updateTimeCache(); diff --git a/src/core/types.ts b/src/core/types.ts index f3c9957..d1bb6c6 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -7,6 +7,11 @@ export type BPMCache = { timePerBeat: number, }; +export type FloorPosition = { + time: number, + value: number, +}; + export enum KeyframeType { PositionX = 'positionX', PositionY = 'positionY', diff --git a/src/core/utils/easings.ts b/src/core/utils/easings.ts new file mode 100644 index 0000000..1e01be6 --- /dev/null +++ b/src/core/utils/easings.ts @@ -0,0 +1,174 @@ + +type EasingFn = (x: number) => number; + +/** + * All these easings comes from https://easings.net/ + * @see https://easings.net/ + */ +const Easings: EasingFn[] = [ + /** 0: Linear */ + (x) => x, + /** 1: In Sine */ + (x) => 1 - Math.cos((x * Math.PI) / 2), + /** 2: Out Sine */ + (x) => Math.sin((x * Math.PI) / 2), + /** 3: In Out Sine */ + (x) => -(Math.cos(Math.PI * x) - 1) / 2, + /** 4: In Quad */ + (x) => x * x, + /** 5: Out Quad */ + (x) => 1 - (1 - x) * (1 - x), + /** 6: In Out Quad */ + (x) => x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2, + /** 7: In Cubic */ + (x) => x * x * x, + /** 8: Out Cubic */ + (x) => 1 - Math.pow(1 - x, 3), + /** 9: In Out Cubic */ + (x) => x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2, + /** 10: In Quart */ + (x) => x * x * x * x, + /** 11: Out Quart */ + (x) => 1 - Math.pow(1 - x, 4), + /** 12: In Out Quart */ + (x) => x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2, + /** 13: In Quint */ + (x) => x * x * x * x * x, + /** 14: Out Quint */ + (x) => 1 - Math.pow(1 - x, 5), + /** 15: In Out Quint */ + (x) => x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2, + /** 16: In Expo */ + (x) => x === 0 ? 0 : Math.pow(2, 10 * x - 10), + /** 17: Out Expo */ + (x) => x === 1 ? 1 : 1 - Math.pow(2, -10 * x), + /** 18: In Out Expo */ + (x) => (x === 0 + ? 0 + : x === 1 + ? 1 + : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 + : (2 - Math.pow(2, -20 * x + 10)) / 2), + /** 19: In Circ */ + (x) => 1 - Math.sqrt(1 - Math.pow(x, 2)), + /** 20: Out Circ */ + (x) => Math.sqrt(1 - Math.pow(x - 1, 2)), + /** 21: In Out Circ */ + (x) => (x < 0.5 + ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2 + : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2), + /** 22: In Back */ + (x) => { + const c1 = 1.70158; + const c3 = c1 + 1; + + return c3 * x * x * x - c1 * x * x + }, + /** 23: Out Back */ + (x) => { + const c1 = 1.70158; + const c3 = c1 + 1; + + return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2); + }, + /** 24: In Out Back */ + (x) => { + const c1 = 1.70158; + const c2 = c1 * 1.525; + + return x < 0.5 + ? (Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2 + : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2; + }, + /** 25: In Elastic */ + (x) => { + const c4 = (2 * Math.PI) / 3; + + return x === 0 + ? 0 + : x === 1 + ? 1 + : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4); + }, + /** 26: Out Elastic */ + (x) => { + const c4 = (2 * Math.PI) / 3; + + return x === 0 + ? 0 + : x === 1 + ? 1 + : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1; + }, + /** 27: In Out Elastic */ + (x) => { + const c5 = (2 * Math.PI) / 4.5; + + return x === 0 + ? 0 + : x === 1 + ? 1 + : x < 0.5 + ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2 + : (Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5)) / 2 + 1; + }, + /** 28: In Bounce */ + (x) => 1 - Easings[29](1 - x), + /** 29: Out Bounce */ + (x) => { + const n1 = 7.5625; + const d1 = 2.75; + + if (x < 1 / d1) { + return n1 * x * x; + } else if (x < 2 / d1) { + return n1 * (x -= 1.5 / d1) * x + 0.75; + } else if (x < 2.5 / d1) { + return n1 * (x -= 2.25 / d1) * x + 0.9375; + } else { + return n1 * (x -= 2.625 / d1) * x + 0.984375; + } + }, + /** 30: In Out Bounce */ + (x) => (x < 0.5 + ? (1 - Easings[29](1 - 2 * x)) / 2 + : (1 + Easings[29](2 * x - 1)) / 2) +]; + +const EasingNames: string[] = [ + 'Linear', + 'In Sine', + 'Out Sine', + 'In Out Sine', + 'In Quad', + 'Out Quad', + 'In Out Quad', + 'In Cubic', + 'Out Cubic', + 'In Out Cubic', + 'In Quart', + 'Out Quart', + 'In Out Quart', + 'In Quint', + 'Out Quint', + 'In Out Quint', + 'In Expo', + 'Out Expo', + 'In Out Expo', + 'In Circ', + 'Out Circ', + 'In Out Circ', + 'In Back', + 'Out Back', + 'In Out Back', + 'In Elastic', + 'Out Elastic', + 'In Out Elastic', + 'In Bounce', + 'Out Bounce', + 'In Out Bounce', +]; + +export default Easings; +export { EasingNames }; +export type { Easings }; diff --git a/src/core/utils/math.ts b/src/core/utils/math.ts new file mode 100644 index 0000000..345e268 --- /dev/null +++ b/src/core/utils/math.ts @@ -0,0 +1,41 @@ +import Easings from './easings'; +import { IKeyframe } from '../models/Keyframe'; +import { FloorPosition } from '../types'; + +export const calculateLineValue = (time: number, keyframes: IKeyframe[]) => { + let min = 0, max = keyframes.length - 1; + + while (min <= max) { + const mid = (min + max) >> 1; + if (keyframes[mid].time <= time) min = mid + 1; + else max = mid - 1; + } + + const index = Math.max(0, min - 1); + const keyframe = keyframes[index]; + const keyframeNext = keyframes[index + 1]; + const startValue = keyframe.hasEndValue ? keyframe.endValue : keyframe.value; + + if (!keyframeNext || !keyframeNext.continuous || keyframeNext.value === startValue) { + return keyframe.value; + } + + const timePercentEnd = Easings[keyframeNext.easing]( + (time - keyframe.time) / (keyframeNext.time - keyframe.time) + ); + + return startValue * (1 - timePercentEnd) * keyframeNext.value * timePercentEnd; +}; + +export const calculateFloorPosition = (time: number, floorPositions: FloorPosition[], speed: number = 1) => { + let min = 0, max = floorPositions.length - 1; + + while (min <= max) { + const mid = (min + max) >> 1; + if (floorPositions[mid].time <= time) min = mid + 1; + else max = mid - 1; + } + + const fPos = floorPositions[Math.max(0, min - 1)]; + return fPos.value + (time - fPos.time) * speed; +}; From 84b85d446f814eda34d6bab09bc9c966faf55815 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 5 Sep 2025 18:50:13 +0800 Subject: [PATCH 046/146] refactor(core/models): Code tweaks --- src/core/models/BPM.ts | 2 +- src/core/models/Chart.ts | 6 +++--- src/core/models/JudgeLine.ts | 4 ++-- src/core/models/Keyframe.ts | 2 +- src/core/models/KeyframeRecord.ts | 4 ++-- src/core/models/Note.ts | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index 8319e7c..0ac992f 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -30,7 +30,7 @@ export const BPM = types.model('BPM', { return BeatArrayToNumber(self.beat); } })).actions((self) => ({ - afterCreate() { + afterAttach() { this.updateParentBPMCache(); }, diff --git a/src/core/models/Chart.ts b/src/core/models/Chart.ts index f19e4da..6d4ee52 100644 --- a/src/core/models/Chart.ts +++ b/src/core/models/Chart.ts @@ -1,4 +1,4 @@ -import { types, Instance, SnapshotIn } from 'mobx-state-tree'; +import { types, Instance, SnapshotIn, destroy } from 'mobx-state-tree'; import { calculateBPMCache } from '../timeline/bpm'; import { Metadata } from './Metadata'; import { BPM } from './BPM'; @@ -43,7 +43,7 @@ export const Chart = types.model('Chart', { removeBPM(id: string) { const index = self.bpm.findIndex(e => e.id === id); - if (index >= 0) self.bpm.splice(index, 1); + if (index >= 0) destroy(self.bpm[index]); this.updateBPMCache(); }, @@ -53,7 +53,7 @@ export const Chart = types.model('Chart', { removeJudgeLine(id: string) { const index = self.judgelines.findIndex(e => e.id === id); - if (index >= 0) self.judgelines.splice(index, 1); + if (index >= 0) destroy(self.judgelines[index]); }, updateBPMCache() { diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index 197c889..d8d72b4 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -1,5 +1,5 @@ import { nanoid } from 'nanoid'; -import { types, Instance } from 'mobx-state-tree'; +import { types, Instance, destroy } from 'mobx-state-tree'; import { calculateLineValue } from '../utils/math'; import { KeyframeRecord } from './KeyframeRecord'; import { parseDoublePrecist } from '@/utils/math'; @@ -36,7 +36,7 @@ export const JudgeLine = types.model('JudgeLine', { removeNote(id: string) { const index = self.notes.findIndex(e => e.id === id); - if (index >= 0) self.notes.splice(index, 1); + if (index >= 0) destroy(self.notes[index]); }, updateFloorPosition() { diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 29c8902..c60a58b 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -26,7 +26,7 @@ export const Keyframe = types.model('Keyframe', { })).volatile(() => ({ time: 0, })).actions((self) => ({ - afterCreate() { + afterAttach() { this.updateTimeCache(); }, diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts index 7961050..c483543 100644 --- a/src/core/models/KeyframeRecord.ts +++ b/src/core/models/KeyframeRecord.ts @@ -1,4 +1,4 @@ -import { types, Instance } from 'mobx-state-tree'; +import { types, Instance, destroy } from 'mobx-state-tree'; import { Keyframe } from './Keyframe'; import { KeyframeType } from '../types'; import { BeatArray } from '@/utils/types'; @@ -54,7 +54,7 @@ export const KeyframeRecord = types.model('KeyframeRecord', { remove(type: KeyframeType, id: string) { const index = self[type].findIndex(e => e.id === id); - if (index >= 0) self[type].splice(index, 1); + if (index >= 0) destroy(self[type][index]); }, updateTimeCache() { diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index d40538c..f18f0cd 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -46,7 +46,7 @@ export const Note = types.model('Note', { return BeatArrayToNumber(self.holdEndBeat) - BeatArrayToNumber(self.beat); } })).actions((self) => ({ - afterCreate() { + afterAttach() { this.updateTimeCache(); }, From 33716db334a103817e9a6c0c2c84a14e99170982 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Fri, 5 Sep 2025 19:18:48 +0800 Subject: [PATCH 047/146] refactor: Make lines moving (again) --- src/core/models/JudgeLine.ts | 12 +++ src/core/models/Keyframe.ts | 13 ++- src/core/models/KeyframeRecord.ts | 9 +- src/core/utils/math.ts | 2 +- src/renderer/preview/classes/JudgeLine.ts | 100 +--------------------- src/renderer/preview/ticker.ts | 16 ++-- 6 files changed, 45 insertions(+), 107 deletions(-) diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index d8d72b4..cae720e 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -23,6 +23,10 @@ export const JudgeLine = types.model('JudgeLine', { }, floorPositions: [] as FloorPosition[], })).actions((self) => ({ + afterCreate() { + this.updateKeyframeCaches(); + }, + addNote(props: SnapshotIn) { self.notes.push(props); }, @@ -97,6 +101,14 @@ export const JudgeLine = types.model('JudgeLine', { if (type === KeyframeType.Speed) this.updateFloorPosition(); }, + updateKeyframeCaches() { + this.updateKeyframeCache(KeyframeType.PositionX); + this.updateKeyframeCache(KeyframeType.PositionY); + this.updateKeyframeCache(KeyframeType.Rotate); + this.updateKeyframeCache(KeyframeType.Alpha); + this.updateKeyframeCache(KeyframeType.Speed); + }, + updateTimeCache() { self.keyframes.updateTimeCache(); for (const n of self.notes) n.updateTimeCache(); diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index c60a58b..31fd7ec 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -4,6 +4,7 @@ import { BeatArray } from '@/core/utils/model'; import { getTimeByBeat } from '../timeline/bpm'; import { BeatArrayToNumber } from '@/utils/math'; import { KeyframeType } from '../types'; +import { IJudgeLine } from './JudgeLine'; export const Keyframe = types.model('Keyframe', { id: types.optional(types.identifier, nanoid), @@ -32,11 +33,21 @@ export const Keyframe = types.model('Keyframe', { updateProps(props: Partial, 'id' | 'type'>>) { Object.assign(self, props); - this.updateTimeCache(); + if ( + props.beat !== (void 0) && + (self.type === KeyframeType.Speed && (props.value !== (void 0) || props.continuous !== (void 0))) + ) { + this.updateTimeCache(); + this.updateLineCache(); + } }, updateTimeCache() { self.time = getTimeByBeat(self.beatNum); + }, + + updateLineCache() { + (getParent(self, 3) as IJudgeLine).updateKeyframeCache(self.type); } })); diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts index c483543..a46b36c 100644 --- a/src/core/models/KeyframeRecord.ts +++ b/src/core/models/KeyframeRecord.ts @@ -1,5 +1,6 @@ -import { types, Instance, destroy } from 'mobx-state-tree'; +import { types, Instance, destroy, getParent } from 'mobx-state-tree'; import { Keyframe } from './Keyframe'; +import { IJudgeLine } from './JudgeLine'; import { KeyframeType } from '../types'; import { BeatArray } from '@/utils/types'; @@ -50,11 +51,15 @@ export const KeyframeRecord = types.model('KeyframeRecord', { self[type].push({ type, beat, value, continuous, easing }); + (getParent(self) as IJudgeLine).updateKeyframeCache(type); }, remove(type: KeyframeType, id: string) { const index = self[type].findIndex(e => e.id === id); - if (index >= 0) destroy(self[type][index]); + if (index >= 0) { + destroy(self[type][index]); + (getParent(self) as IJudgeLine).updateKeyframeCache(type); + } }, updateTimeCache() { diff --git a/src/core/utils/math.ts b/src/core/utils/math.ts index 345e268..35444fa 100644 --- a/src/core/utils/math.ts +++ b/src/core/utils/math.ts @@ -24,7 +24,7 @@ export const calculateLineValue = (time: number, keyframes: IKeyframe[]) => { (time - keyframe.time) / (keyframeNext.time - keyframe.time) ); - return startValue * (1 - timePercentEnd) * keyframeNext.value * timePercentEnd; + return startValue * (1 - timePercentEnd) + keyframeNext.value * timePercentEnd; }; export const calculateFloorPosition = (time: number, floorPositions: FloorPosition[], speed: number = 1) => { diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts index edd0d9a..24b4829 100644 --- a/src/renderer/preview/classes/JudgeLine.ts +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -2,39 +2,19 @@ import { Sprite, Texture } from 'pixi.js'; import { onPatch } from 'mobx-state-tree'; import { IDisposer, IJsonPatch } from 'mobx-state-tree'; import { IJudgeLine } from '@/core/models/JudgeLine'; -import { IKeyframe } from '@/core/models/Keyframe'; -import { FloorPosition, PreviewSize } from '@/renderer/types'; -import { KeyframeType } from '@/core/types'; -import { calculateLineValue } from '@/renderer/utils'; -import { parseDoublePrecist } from '@/utils/math'; - -type $KeyframeCaches = { - [K in KeyframeType]: IKeyframe[]; -} +import { PreviewSize } from '@/renderer/types'; const LineWidthBase = 4000; const LineHeightBase = 18.75 * 0.008; -const KeyframeTypeReg = /^\/keyframes\/([a-zA-Z]+)/; - export class JudgeLineSprite extends Sprite { - private readonly state: IJudgeLine; + readonly state: IJudgeLine; private readonly patchDisposer: IDisposer; - readonly floorPositions: FloorPosition[] = []; - readonly keyframes: $KeyframeCaches = { - [KeyframeType.PositionX]: [], - [KeyframeType.PositionY]: [], - [KeyframeType.Rotate]: [], - [KeyframeType.Alpha]: [], - [KeyframeType.Speed]: [] - }; - constructor(state: IJudgeLine) { super(Texture.WHITE); this.state = state; - this.updateAllKeyframesCache(); this.anchor.set(0.5); @@ -51,80 +31,8 @@ export class JudgeLineSprite extends Sprite { this.destroy(); } + // TODO: Listen to note changes private handlePatch(patch: IJsonPatch) { - if (KeyframeTypeReg.test(patch.path)) { - const type = patch.path.match(KeyframeTypeReg)![1] as KeyframeType; - this.updateKeyframesCache(type); - return; - } - } - - private updateFloorPositions() { - const keyframes = this.keyframes.speed; - this.floorPositions.length = 0; - - for (let i = 0; i < keyframes.length; i++) { - const keyframe = keyframes[i]; - const nextKeyframe = keyframes[i + 1]; - - if (!nextKeyframe || !nextKeyframe.continuous || nextKeyframe.value === keyframe.value) { - this.floorPositions.push({ - time: keyframe.time, - value: NaN, - }); - continue; - } - - const beatBetween = nextKeyframe.beatNum - keyframe.beatNum; - for (let i = 0, count = Math.ceil(beatBetween / 0.125); i < count; i++) { - const beatPercent = i / count; - const currentTime = keyframe.time * (1 - beatPercent) + nextKeyframe.time * beatPercent; - - this.floorPositions.push({ - time: currentTime, - value: NaN, - }); - } - - this.floorPositions.push({ - time: nextKeyframe.time, - value: NaN, - }); - } - - this.floorPositions.sort((a, b) => a.time - b.time); - if (this.floorPositions[0].time > 0) { - this.floorPositions.unshift({ - time: 0, - value: NaN, - }); - } - - let currentFloorPosition = parseDoublePrecist(( - this.floorPositions[0].time * calculateLineValue(this.floorPositions[0].time, keyframes, 1) - ), 3, -1); - for (let i = 0; i < this.floorPositions.length; i++) { - const event = this.floorPositions[i]; - const eventNext = this.floorPositions[i + 1]; - - event.value = currentFloorPosition; - - if (eventNext) currentFloorPosition = parseDoublePrecist(currentFloorPosition + ( - (eventNext.time - event.time) + calculateLineValue(event.time, keyframes, 1) - ), 3, -1); - } - } - - private updateKeyframesCache(type: KeyframeType) { - this.keyframes[type] = this.state.keyframes[type].slice().sort((a, b) => a.time - b.time); - if (type === KeyframeType.Speed) this.updateFloorPositions(); - } - - private updateAllKeyframesCache() { - this.updateKeyframesCache(KeyframeType.PositionX); - this.updateKeyframesCache(KeyframeType.PositionY); - this.updateKeyframesCache(KeyframeType.Rotate); - this.updateKeyframesCache(KeyframeType.Alpha); - this.updateKeyframesCache(KeyframeType.Speed); + return; } } diff --git a/src/renderer/preview/ticker.ts b/src/renderer/preview/ticker.ts index 3a6add8..8c90f7f 100644 --- a/src/renderer/preview/ticker.ts +++ b/src/renderer/preview/ticker.ts @@ -1,5 +1,5 @@ import { Clip } from '@phifans/audio'; -import { calculateLineValue } from '../utils'; +import { calculateLineValue } from '@/core/utils/math'; import { Nullable } from '@/utils/types'; import { JudgeLineSprite } from './classes/JudgeLine'; import { PreviewSize } from '../types'; @@ -19,15 +19,17 @@ export const UpdateRendererTick = ( const { currentTime } = clip; for (const line of lines) { - const { keyframes } = line; + const { keyframesCache } = line.state; - const lineSpeed = calculateLineValue(currentTime, keyframes.speed, 1); - const linePosX = calculateLineValue(currentTime, keyframes.positionX, 0); - const linePosY = calculateLineValue(currentTime, keyframes.positionY, 0); - const lineRotate = calculateLineValue(currentTime, keyframes.rotate, 0); - const lineAlpha = calculateLineValue(currentTime, keyframes.alpha, 255); + const lineSpeed = calculateLineValue(currentTime, keyframesCache.speed); + const linePosX = calculateLineValue(currentTime, keyframesCache.positionX); + const linePosY = calculateLineValue(currentTime, keyframesCache.positionY); + const lineRotate = calculateLineValue(currentTime, keyframesCache.rotate); + const lineAlpha = calculateLineValue(currentTime, keyframesCache.alpha); line.x = linePosX / 100 * widthHalf; line.y = linePosY / -100 * heightHalf; + line.angle = lineRotate; + line.alpha = lineAlpha / 255; } }; From 517e4f37fb339d8fec57ef225f351ae9c3b737a5 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 01:40:53 +0800 Subject: [PATCH 048/146] chore: Revert changes to `1cba32a` ah shit here we go again --- src/core/models/BPM.ts | 2 +- src/core/models/JudgeLine.ts | 86 +------------------ src/core/models/Keyframe.ts | 15 +--- src/core/models/KeyframeRecord.ts | 9 +- src/core/models/Note.ts | 2 +- src/core/types.ts | 5 -- src/renderer/preview/classes/JudgeLine.ts | 100 +++++++++++++++++++++- src/renderer/preview/ticker.ts | 14 +-- src/renderer/utils.ts | 61 +++++++------ 9 files changed, 145 insertions(+), 149 deletions(-) diff --git a/src/core/models/BPM.ts b/src/core/models/BPM.ts index 0ac992f..8319e7c 100644 --- a/src/core/models/BPM.ts +++ b/src/core/models/BPM.ts @@ -30,7 +30,7 @@ export const BPM = types.model('BPM', { return BeatArrayToNumber(self.beat); } })).actions((self) => ({ - afterAttach() { + afterCreate() { this.updateParentBPMCache(); }, diff --git a/src/core/models/JudgeLine.ts b/src/core/models/JudgeLine.ts index cae720e..432a2d4 100644 --- a/src/core/models/JudgeLine.ts +++ b/src/core/models/JudgeLine.ts @@ -1,32 +1,14 @@ import { nanoid } from 'nanoid'; import { types, Instance, destroy } from 'mobx-state-tree'; -import { calculateLineValue } from '../utils/math'; import { KeyframeRecord } from './KeyframeRecord'; -import { parseDoublePrecist } from '@/utils/math'; import { Note } from './Note'; import { SnapshotIn } from 'mobx-state-tree'; -import { IKeyframe } from './Keyframe'; -import { KeyframeType } from '../types'; -import { FloorPosition } from '../types'; export const JudgeLine = types.model('JudgeLine', { id: types.optional(types.identifier, nanoid), keyframes: types.optional(KeyframeRecord, {}), notes: types.optional(types.array(Note), []), -}).volatile(() => ({ - keyframesCache: { - [KeyframeType.PositionX]: [] as IKeyframe[], - [KeyframeType.PositionY]: [] as IKeyframe[], - [KeyframeType.Rotate]: [] as IKeyframe[], - [KeyframeType.Alpha]: [] as IKeyframe[], - [KeyframeType.Speed]: [] as IKeyframe[], - }, - floorPositions: [] as FloorPosition[], -})).actions((self) => ({ - afterCreate() { - this.updateKeyframeCaches(); - }, - +}).actions((self) => ({ addNote(props: SnapshotIn) { self.notes.push(props); }, @@ -42,72 +24,6 @@ export const JudgeLine = types.model('JudgeLine', { const index = self.notes.findIndex(e => e.id === id); if (index >= 0) destroy(self.notes[index]); }, - - updateFloorPosition() { - const keyframes = self.keyframesCache.speed; - - self.floorPositions.length = 0; - - for (let i = 0; i < keyframes.length; i++) { - const keyframe = keyframes[i]; - const keyframeNext = keyframes[i + 1]; - - if (!keyframeNext || !keyframeNext.continuous || keyframeNext.value === keyframe.value) { - self.floorPositions.push({ - time: keyframe.time, - value: NaN, - }); - continue; - } - - const beatCount = Math.ceil((keyframeNext.beatNum - keyframe.beatNum) / 0.125); - for (let j = 0; j < beatCount; j++) { - const beatPercent = j / beatCount; - const currentTime = keyframe.time * (1 - beatPercent) + keyframeNext.time * beatPercent; - - self.floorPositions.push({ - time: currentTime, - value: NaN, - }); - } - - self.floorPositions.push({ - time: keyframeNext.time, - value: NaN, - }); - } - - self.floorPositions.sort((a, b) => a.time - b.time); - if (self.floorPositions[0].time > 0) { - self.floorPositions[0].time = 0; - } - - let currentFloorPosition = parseDoublePrecist(( - self.floorPositions[0].time * calculateLineValue(self.floorPositions[0].time, keyframes) - ), 3, -1); - for (let i = 0; i < self.floorPositions.length; i++) { - const event = self.floorPositions[i]; - const eventNext = self.floorPositions[i + 1]; - - event.value = currentFloorPosition; - if (eventNext) currentFloorPosition = parseDoublePrecist(currentFloorPosition + ( - (eventNext.time - event.time) + calculateLineValue(event.time, keyframes) - ), 3, -1); - } - }, - - updateKeyframeCache(type: KeyframeType) { - self.keyframesCache[type] = self.keyframes[type].slice().sort((a, b) => a.time - b.time); - if (type === KeyframeType.Speed) this.updateFloorPosition(); - }, - - updateKeyframeCaches() { - this.updateKeyframeCache(KeyframeType.PositionX); - this.updateKeyframeCache(KeyframeType.PositionY); - this.updateKeyframeCache(KeyframeType.Rotate); - this.updateKeyframeCache(KeyframeType.Alpha); - this.updateKeyframeCache(KeyframeType.Speed); - }, updateTimeCache() { self.keyframes.updateTimeCache(); diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 31fd7ec..29c8902 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -4,7 +4,6 @@ import { BeatArray } from '@/core/utils/model'; import { getTimeByBeat } from '../timeline/bpm'; import { BeatArrayToNumber } from '@/utils/math'; import { KeyframeType } from '../types'; -import { IJudgeLine } from './JudgeLine'; export const Keyframe = types.model('Keyframe', { id: types.optional(types.identifier, nanoid), @@ -27,27 +26,17 @@ export const Keyframe = types.model('Keyframe', { })).volatile(() => ({ time: 0, })).actions((self) => ({ - afterAttach() { + afterCreate() { this.updateTimeCache(); }, updateProps(props: Partial, 'id' | 'type'>>) { Object.assign(self, props); - if ( - props.beat !== (void 0) && - (self.type === KeyframeType.Speed && (props.value !== (void 0) || props.continuous !== (void 0))) - ) { - this.updateTimeCache(); - this.updateLineCache(); - } + this.updateTimeCache(); }, updateTimeCache() { self.time = getTimeByBeat(self.beatNum); - }, - - updateLineCache() { - (getParent(self, 3) as IJudgeLine).updateKeyframeCache(self.type); } })); diff --git a/src/core/models/KeyframeRecord.ts b/src/core/models/KeyframeRecord.ts index a46b36c..c483543 100644 --- a/src/core/models/KeyframeRecord.ts +++ b/src/core/models/KeyframeRecord.ts @@ -1,6 +1,5 @@ -import { types, Instance, destroy, getParent } from 'mobx-state-tree'; +import { types, Instance, destroy } from 'mobx-state-tree'; import { Keyframe } from './Keyframe'; -import { IJudgeLine } from './JudgeLine'; import { KeyframeType } from '../types'; import { BeatArray } from '@/utils/types'; @@ -51,15 +50,11 @@ export const KeyframeRecord = types.model('KeyframeRecord', { self[type].push({ type, beat, value, continuous, easing }); - (getParent(self) as IJudgeLine).updateKeyframeCache(type); }, remove(type: KeyframeType, id: string) { const index = self[type].findIndex(e => e.id === id); - if (index >= 0) { - destroy(self[type][index]); - (getParent(self) as IJudgeLine).updateKeyframeCache(type); - } + if (index >= 0) destroy(self[type][index]); }, updateTimeCache() { diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index f18f0cd..d40538c 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -46,7 +46,7 @@ export const Note = types.model('Note', { return BeatArrayToNumber(self.holdEndBeat) - BeatArrayToNumber(self.beat); } })).actions((self) => ({ - afterAttach() { + afterCreate() { this.updateTimeCache(); }, diff --git a/src/core/types.ts b/src/core/types.ts index d1bb6c6..f3c9957 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -7,11 +7,6 @@ export type BPMCache = { timePerBeat: number, }; -export type FloorPosition = { - time: number, - value: number, -}; - export enum KeyframeType { PositionX = 'positionX', PositionY = 'positionY', diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts index 24b4829..e03c9a5 100644 --- a/src/renderer/preview/classes/JudgeLine.ts +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -2,19 +2,39 @@ import { Sprite, Texture } from 'pixi.js'; import { onPatch } from 'mobx-state-tree'; import { IDisposer, IJsonPatch } from 'mobx-state-tree'; import { IJudgeLine } from '@/core/models/JudgeLine'; -import { PreviewSize } from '@/renderer/types'; +import { IKeyframe } from '@/core/models/Keyframe'; +import { FloorPosition, PreviewSize } from '@/renderer/types'; +import { KeyframeType } from '@/core/types'; +import { calculateLineValue } from '@/renderer/utils'; +import { parseDoublePrecist } from '@/utils/math'; + +type $KeyframeCaches = { + [K in KeyframeType]: IKeyframe[]; +} const LineWidthBase = 4000; const LineHeightBase = 18.75 * 0.008; +const KeyframeTypeReg = /^\/keyframes\/([a-zA-Z]+)/; + export class JudgeLineSprite extends Sprite { - readonly state: IJudgeLine; + private readonly state: IJudgeLine; private readonly patchDisposer: IDisposer; + readonly floorPositions: FloorPosition[] = []; + readonly keyframes: $KeyframeCaches = { + [KeyframeType.PositionX]: [], + [KeyframeType.PositionY]: [], + [KeyframeType.Rotate]: [], + [KeyframeType.Alpha]: [], + [KeyframeType.Speed]: [] + }; + constructor(state: IJudgeLine) { super(Texture.WHITE); this.state = state; + this.updateAllKeyframesCache(); this.anchor.set(0.5); @@ -31,8 +51,80 @@ export class JudgeLineSprite extends Sprite { this.destroy(); } - // TODO: Listen to note changes private handlePatch(patch: IJsonPatch) { - return; + if (KeyframeTypeReg.test(patch.path)) { + const type = patch.path.match(KeyframeTypeReg)![1] as KeyframeType; + this.updateKeyframesCache(type); + return; + } + } + + private updateFloorPositions() { + const keyframes = this.keyframes.speed; + this.floorPositions.length = 0; + + for (let i = 0; i < keyframes.length; i++) { + const keyframe = keyframes[i]; + const nextKeyframe = keyframes[i + 1]; + + if (!nextKeyframe || !nextKeyframe.continuous || nextKeyframe.value === keyframe.value) { + this.floorPositions.push({ + time: keyframe.time, + value: NaN, + }); + continue; + } + + const beatBetween = nextKeyframe.beatNum - keyframe.beatNum; + for (let i = 0, count = Math.ceil(beatBetween / 0.125); i < count; i++) { + const beatPercent = i / count; + const currentTime = keyframe.time * (1 - beatPercent) + nextKeyframe.time * beatPercent; + + this.floorPositions.push({ + time: currentTime, + value: NaN, + }); + } + + this.floorPositions.push({ + time: nextKeyframe.time, + value: NaN, + }); + } + + this.floorPositions.sort((a, b) => a.time - b.time); + if (this.floorPositions[0].time > 0) { + this.floorPositions.unshift({ + time: 0, + value: NaN, + }); + } + + let currentFloorPosition = parseDoublePrecist(( + this.floorPositions[0].time * calculateLineValue(this.floorPositions[0].time, keyframes) + ), 3, -1); + for (let i = 0; i < this.floorPositions.length; i++) { + const event = this.floorPositions[i]; + const eventNext = this.floorPositions[i + 1]; + + event.value = currentFloorPosition; + + if (eventNext) currentFloorPosition = parseDoublePrecist(currentFloorPosition + ( + (eventNext.time - event.time) + calculateLineValue(event.time, keyframes) + ), 3, -1); + } + } + + private updateKeyframesCache(type: KeyframeType) { + this.keyframes[type] = this.state.keyframes[type].slice().sort((a, b) => a.time - b.time); + if (type === KeyframeType.Speed) this.updateFloorPositions(); + } + + private updateAllKeyframesCache() { + this.updateKeyframesCache(KeyframeType.PositionX); + this.updateKeyframesCache(KeyframeType.PositionY); + this.updateKeyframesCache(KeyframeType.Rotate); + this.updateKeyframesCache(KeyframeType.Alpha); + this.updateKeyframesCache(KeyframeType.Speed); } } diff --git a/src/renderer/preview/ticker.ts b/src/renderer/preview/ticker.ts index 8c90f7f..6906938 100644 --- a/src/renderer/preview/ticker.ts +++ b/src/renderer/preview/ticker.ts @@ -1,5 +1,5 @@ import { Clip } from '@phifans/audio'; -import { calculateLineValue } from '@/core/utils/math'; +import { calculateLineValue } from '../utils'; import { Nullable } from '@/utils/types'; import { JudgeLineSprite } from './classes/JudgeLine'; import { PreviewSize } from '../types'; @@ -19,13 +19,13 @@ export const UpdateRendererTick = ( const { currentTime } = clip; for (const line of lines) { - const { keyframesCache } = line.state; + const { keyframes } = line; - const lineSpeed = calculateLineValue(currentTime, keyframesCache.speed); - const linePosX = calculateLineValue(currentTime, keyframesCache.positionX); - const linePosY = calculateLineValue(currentTime, keyframesCache.positionY); - const lineRotate = calculateLineValue(currentTime, keyframesCache.rotate); - const lineAlpha = calculateLineValue(currentTime, keyframesCache.alpha); + const lineSpeed = calculateLineValue(currentTime, keyframes.speed); + const linePosX = calculateLineValue(currentTime, keyframes.positionX); + const linePosY = calculateLineValue(currentTime, keyframes.positionY); + const lineRotate = calculateLineValue(currentTime, keyframes.rotate); + const lineAlpha = calculateLineValue(currentTime, keyframes.alpha); line.x = linePosX / 100 * widthHalf; line.y = linePosY / -100 * heightHalf; diff --git a/src/renderer/utils.ts b/src/renderer/utils.ts index e115de5..3d62735 100644 --- a/src/renderer/utils.ts +++ b/src/renderer/utils.ts @@ -1,32 +1,41 @@ import Easings from '@/utils/easings'; import { IKeyframe } from '@/core/models/Keyframe'; +import { FloorPosition } from './types'; -export const calculateLineValue = (time: number, keyframes: IKeyframe[], defaultValue = 0) => { - const { length } = keyframes; - let lastKeyframeValue = defaultValue; - - for (let i = 0; i < length; i++) { - const keyframe = keyframes[i]; - const keyframeNext = keyframes[i + 1]; - - if (time === keyframe.time) return keyframe.value; - - if (keyframe.time > time) { - if (i === 0) break; - return keyframes[i - 1].value; - } - if (keyframe.time < time) { - if (!keyframeNext || !keyframeNext.continuous || keyframeNext.time <= time) { - lastKeyframeValue = keyframe.value; - continue; - } - - const timePercentEnd = Easings[keyframeNext.easing]( - (time - keyframe.time) / (keyframeNext.time - keyframe.time) - ); - return keyframe.value * (1 - timePercentEnd) + keyframeNext.value * timePercentEnd; - } +export const calculateLineValue = (time: number, keyframes: IKeyframe[]) => { + let min = 0, max = keyframes.length - 1; + + while (min <= max) { + const mid = (min + max) >> 1; + if (keyframes[mid].time <= time) min = mid + 1; + else max = mid - 1; + } + + const index = Math.max(0, min - 1); + const keyframe = keyframes[index]; + const keyframeNext = keyframes[index + 1]; + const startValue = keyframe.hasEndValue ? keyframe.endValue : keyframe.value; + + if (!keyframeNext || !keyframeNext.continuous || keyframeNext.value === startValue) { + return keyframe.value; + } + + const timePercentEnd = Easings[keyframeNext.easing]( + (time - keyframe.time) / (keyframeNext.time - keyframe.time) + ); + + return startValue * (1 - timePercentEnd) + keyframeNext.value * timePercentEnd; +}; + +export const calculateFloorPosition = (time: number, floorPositions: FloorPosition[], speed: number = 1) => { + let min = 0, max = floorPositions.length - 1; + + while (min <= max) { + const mid = (min + max) >> 1; + if (floorPositions[mid].time <= time) min = mid + 1; + else max = mid - 1; } - return lastKeyframeValue; + const fPos = floorPositions[Math.max(0, min - 1)]; + return fPos.value + (time - fPos.time) * speed; }; From 50da6d652bbbffae523c34042132ee88e9f2cb5d Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 15:15:54 +0800 Subject: [PATCH 049/146] refactor(renderer/preview): Only updates keyframes cache when necessary --- src/core/models/Keyframe.ts | 2 +- src/core/models/Note.ts | 4 ++++ src/renderer/preview/classes/JudgeLine.ts | 19 +++++++++++++++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/core/models/Keyframe.ts b/src/core/models/Keyframe.ts index 29c8902..8ae97e1 100644 --- a/src/core/models/Keyframe.ts +++ b/src/core/models/Keyframe.ts @@ -32,7 +32,7 @@ export const Keyframe = types.model('Keyframe', { updateProps(props: Partial, 'id' | 'type'>>) { Object.assign(self, props); - this.updateTimeCache(); + if (props.beat !== (void 0)) this.updateTimeCache(); }, updateTimeCache() { diff --git a/src/core/models/Note.ts b/src/core/models/Note.ts index d40538c..6ac154b 100644 --- a/src/core/models/Note.ts +++ b/src/core/models/Note.ts @@ -52,6 +52,10 @@ export const Note = types.model('Note', { updateProps(props: Omit>, 'id'>) { Object.assign(self, props); + if ( + props.beat !== (void 0) || + props.holdEndBeat !== (void 0) + ) this.updateTimeCache(); }, updateTimeCache() { diff --git a/src/renderer/preview/classes/JudgeLine.ts b/src/renderer/preview/classes/JudgeLine.ts index e03c9a5..fcf3ea4 100644 --- a/src/renderer/preview/classes/JudgeLine.ts +++ b/src/renderer/preview/classes/JudgeLine.ts @@ -1,8 +1,9 @@ import { Sprite, Texture } from 'pixi.js'; import { onPatch } from 'mobx-state-tree'; +import { SnapshotOut } from 'mobx-state-tree'; import { IDisposer, IJsonPatch } from 'mobx-state-tree'; import { IJudgeLine } from '@/core/models/JudgeLine'; -import { IKeyframe } from '@/core/models/Keyframe'; +import { Keyframe, IKeyframe } from '@/core/models/Keyframe'; import { FloorPosition, PreviewSize } from '@/renderer/types'; import { KeyframeType } from '@/core/types'; import { calculateLineValue } from '@/renderer/utils'; @@ -15,7 +16,7 @@ type $KeyframeCaches = { const LineWidthBase = 4000; const LineHeightBase = 18.75 * 0.008; -const KeyframeTypeReg = /^\/keyframes\/([a-zA-Z]+)/; +const KeyframeTypeReg = /^\/keyframes\/([a-zA-Z]+)(?:\/(\d+))?(?:\/([a-zA-Z]+))?$/; export class JudgeLineSprite extends Sprite { private readonly state: IJudgeLine; @@ -53,8 +54,18 @@ export class JudgeLineSprite extends Sprite { private handlePatch(patch: IJsonPatch) { if (KeyframeTypeReg.test(patch.path)) { - const type = patch.path.match(KeyframeTypeReg)![1] as KeyframeType; - this.updateKeyframesCache(type); + const matches = patch.path.match(KeyframeTypeReg)!; + const type = matches[1] as KeyframeType; + const keyframeIndex = matches[2] as string | undefined; + const prop = matches[3] as keyof SnapshotOut | undefined; + + if ( + (patch.op !== 'replace' || keyframeIndex === (void 0)) || + type === KeyframeType.Speed || + prop === 'beat' + ) { + this.updateKeyframesCache(type); + } return; } } From c6b03d66a2dd2e96eae7d0b0ff522d881a393100 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 15:25:50 +0800 Subject: [PATCH 050/146] refactor(core): Refactoring BPM cache --- src/core/timeline/bpm.ts | 68 ++++++++++++++-------------------------- src/core/types.ts | 6 ++-- 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/core/timeline/bpm.ts b/src/core/timeline/bpm.ts index c0b179e..54fd80c 100644 --- a/src/core/timeline/bpm.ts +++ b/src/core/timeline/bpm.ts @@ -12,10 +12,8 @@ export const calculateBPMCache = (bpms: IBPM[]): BPMCache[] => { if (result.length === 0) { result.push({ - startTime: 0, - endTime: NaN, - startBeat: 0, - endBeat: NaN, + time: 0, + beat: 0, timePerBeat, }); continue; @@ -23,65 +21,45 @@ export const calculateBPMCache = (bpms: IBPM[]): BPMCache[] => { const lastBpmCache = result[result.length - 1]!; result.push({ - startTime: parseDoublePrecist(( - lastBpmCache.startTime + (lastBpmCache.timePerBeat * (bpm.beatNum - lastBpmCache.startBeat)) + time: parseDoublePrecist(( + lastBpmCache.beat + (lastBpmCache.timePerBeat * (bpm.beatNum - lastBpmCache.beat)) ), 6, -1), - endTime: NaN, - startBeat: bpm.beatNum, - endBeat: NaN, + beat: bpm.beatNum, timePerBeat, }); } - if (result.length === 1) { - result[result.length - 1].endTime = Infinity; - result[result.length - 1].endBeat = Infinity; - } else { - for (let i = 0; i < result.length; i++) { - const bpm = result[i]; - const bpmNext = result[i + 1]; - - if (bpmNext) { - bpm.endTime = bpmNext.startTime; - bpm.endBeat = bpmNext.startBeat; - } else { - bpm.endTime = Infinity; - bpm.endBeat = Infinity; - } - } - } - return result; }; export const getBeatByTime = (time: number) => { const bpms = ChartStore.bpmCache; - let result = NaN; + let min = 0, max = bpms.length - 1; - for (const bpm of bpms) { - if (bpm.endTime < time) continue; - if (bpm.startTime > time) break; - - result = parseDoublePrecist(( - bpm.startBeat + (time - bpm.startTime) / bpm.timePerBeat - ), 6, -1); + while (min <= max) { + const mid = (min + max) >> 1; + if (bpms[mid].time <= time) min = mid + 1; + else max = mid - 1; } - return result; + const result = bpms[Math.max(0, min - 1)]; + return parseDoublePrecist(( + result.beat + (time - result.time) / result.timePerBeat + ), 6, -1); }; export const getTimeByBeat = (beat: number) => { const bpms = ChartStore.bpmCache; - let result = NaN; + let min = 0, max = bpms.length - 1; - for (const bpm of bpms) { - if (bpm.endBeat < beat) continue; - if (bpm.startBeat > beat) break; - - result = parseDoublePrecist(( - bpm.startTime + (beat - bpm.startBeat) * bpm.timePerBeat - ), 6, -1); + while (min <= max) { + const mid = (min + max) >> 1; + if (bpms[mid].beat <= beat) min = mid + 1; + else max = mid - 1; } - return result; + const result = bpms[Math.max(0, min - 1)]; + return parseDoublePrecist(( + result.time + (beat - result.beat) * result.timePerBeat + ), 6, -1); }; diff --git a/src/core/types.ts b/src/core/types.ts index f3c9957..0dd4fb6 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -1,9 +1,7 @@ export type BPMCache = { - startTime: number, - endTime: number, - startBeat: number, - endBeat: number, + time: number, + beat: number, timePerBeat: number, }; From 58cb421b3d2679cac6da2a0eeedfcb84ac30bb03 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 16:34:55 +0800 Subject: [PATCH 051/146] fix(runtime/audio/state): Fix status update issue --- package.json | 1 + pnpm-lock.yaml | 3 +++ src/main.ts | 3 ++- src/runtime/audio/state.ts | 6 +++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 2e503f6..9441ded 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "react-dom": "^19.0.0", "react-i18next": "^15.4.1", "react-split-pane": "^0.1.92", + "setimmediate": "^1.0.5", "spark-md5": "^3.0.2", "uuid": "^11.0.4", "zustand": "^5.0.8" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1a01c0..3fe635e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,6 +91,9 @@ importers: react-split-pane: specifier: ^0.1.92 version: 0.1.92(patch_hash=15b3bc41b3c9ea6e7a5c245069978ef071c4655082c4e9b0e14eb5d4eb57da5c)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + setimmediate: + specifier: ^1.0.5 + version: 1.0.5 spark-md5: specifier: ^3.0.2 version: 3.0.2 diff --git a/src/main.ts b/src/main.ts index 6e2214d..eda0a66 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,2 +1,3 @@ -import './App/App'; +// import './App/App'; +import 'setimmediate'; // TODO: This is a workaround for upstream @phifans/audio import './ui'; diff --git a/src/runtime/audio/state.ts b/src/runtime/audio/state.ts index d3a516c..c06fa6e 100644 --- a/src/runtime/audio/state.ts +++ b/src/runtime/audio/state.ts @@ -30,7 +30,7 @@ export const runtimeAudioStore = createStore((set, get) => ({ if (!musicClip) return; if (musicClip.status !== 1) musicClip.play(); else musicClip.pause(); - set({ status: musicClip.status }); + setImmediate(() => set({ status: musicClip.status })); // TODO: This is a workaround for upstream @phifans/audio }, pause() { @@ -38,14 +38,14 @@ export const runtimeAudioStore = createStore((set, get) => ({ if (!musicClip) return; if (musicClip.status === 1) musicClip.pause(); else musicClip.play(); - set({ status: musicClip.status }); + setImmediate(() => set({ status: musicClip.status })); // TODO: This is a workaround for upstream @phifans/audio }, stop() { const { musicClip } = get(); if (!musicClip) return; musicClip.stop(); - set({ status: musicClip.status }); + setImmediate(() => set({ status: musicClip.status })); // TODO: This is a workaround for upstream @phifans/audio }, seek(seconds: number) { From e71e890d0d24460dc20ce4ca1dac548e04939579 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 17:04:17 +0800 Subject: [PATCH 052/146] feat: Add `zen-fs` storage layer --- package.json | 2 + pnpm-lock.yaml | 165 ++++++++++++++++++++++++++---- src/main.ts | 1 + src/storage/adapters/indexeddb.ts | 7 ++ src/storage/init.ts | 14 +++ 5 files changed, 171 insertions(+), 18 deletions(-) create mode 100644 src/storage/adapters/indexeddb.ts create mode 100644 src/storage/init.ts diff --git a/package.json b/package.json index 9441ded..00fd0ff 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "@phifans/audio": "^0.0.7", "@pixi/react": "8.0.0", "@types/node": "^22.10.5", + "@zenfs/core": "^2.4.0", + "@zenfs/dom": "^1.2.4", "audio-decode": "^2.2.2", "dockview": "^4.7.1", "eventemitter3": "^5.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fe635e..63c9dbf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,12 @@ importers: '@types/node': specifier: ^22.10.5 version: 22.10.5 + '@zenfs/core': + specifier: ^2.4.0 + version: 2.4.0 + '@zenfs/dom': + specifier: ^1.2.4 + version: 1.2.4(@zenfs/core@2.4.0)(kerium@1.3.6)(utilium@2.5.4) audio-decode: specifier: ^2.2.2 version: 2.2.2 @@ -467,61 +473,51 @@ packages: resolution: {integrity: sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.34.7': resolution: {integrity: sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.34.7': resolution: {integrity: sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.34.7': resolution: {integrity: sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.34.7': resolution: {integrity: sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.34.7': resolution: {integrity: sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.34.7': resolution: {integrity: sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.34.7': resolution: {integrity: sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.34.7': resolution: {integrity: sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.34.7': resolution: {integrity: sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.34.7': resolution: {integrity: sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==} @@ -561,28 +557,24 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-musl@1.10.3': resolution: {integrity: sha512-L07/4zKnIY2S/00bE+Yn3oEHkyGjWmGGE8Ta4luVCL+00s04EIwMoE1Hc8E8xFB5zLew5ViKFc5kNb5YZ/tRFQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-x64-gnu@1.10.3': resolution: {integrity: sha512-cvTCekY4u0fBIDNfhv/2UxcOXqH4XJE2iNxKuQejS5KIapFJwrZ+fRQ2lha3+yopI/d2p96BlBEWTAcBzeTntw==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-musl@1.10.3': resolution: {integrity: sha512-h9kUOTrSSpY9JNc41a+NMAwK62USk/pvNE9Fi/Pfoklmlf9j9j8gRCitqvHpmZcEF4PPIsoMdiGetDipTwvWlw==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-win32-arm64-msvc@1.10.3': resolution: {integrity: sha512-iHOmLYkZYn3r1Ff4rfyczdrYGt/wVIWyY0t8swsO9o1TE+zmucGFZuYZzgj3ng8Kp4sojJrydAGz8TINQZDBzQ==} @@ -640,28 +632,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@tauri-apps/cli-linux-arm64-musl@2.2.7': resolution: {integrity: sha512-+8HZ+txff/Y3YjAh80XcLXcX8kpGXVdr1P8AfjLHxHdS6QD4Md+acSxGTTNbplmHuBaSHJvuTvZf9tU1eDCTDg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@tauri-apps/cli-linux-x64-gnu@2.2.7': resolution: {integrity: sha512-ahlSnuCnUntblp9dG7/w5ZWZOdzRFi3zl0oScgt7GF4KNAOEa7duADsxPA4/FT2hLRa0SvpqtD4IYFvCxoVv3Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@tauri-apps/cli-linux-x64-musl@2.2.7': resolution: {integrity: sha512-+qKAWnJRSX+pjjRbKAQgTdFY8ecdcu8UdJ69i7wn3ZcRn2nMMzOO2LOMOTQV42B7/Q64D1pIpmZj9yblTMvadA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@tauri-apps/cli-win32-arm64-msvc@2.2.7': resolution: {integrity: sha512-aa86nRnrwT04u9D9fhf5JVssuAZlUCCc8AjqQjqODQjMd4BMA2+d4K9qBMpEG/1kVh95vZaNsLogjEaqSTTw4A==} @@ -709,6 +697,9 @@ packages: '@types/node@22.10.5': resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + '@types/node@24.3.1': + resolution: {integrity: sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==} + '@types/react-dom@19.0.3': resolution: {integrity: sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==} peerDependencies: @@ -796,6 +787,26 @@ packages: resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} + '@xterm/xterm@5.5.0': + resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==} + + '@zenfs/core@2.4.0': + resolution: {integrity: sha512-Ik1qM9xkP6lisNwR0zWaTXXuvM4Ef9yQRvYjJGqKGJv7fLsdwXS3tclbHkfvd9YkqlpxC6ac6am9oe7AWgepEA==} + engines: {node: '>= 18'} + hasBin: true + + '@zenfs/dom@1.2.4': + resolution: {integrity: sha512-ftCviemTnU8W0yON8zKS1cUopCMRRq6+edWD9MwXR349h0wfeTsnXBhv7/ctLWpDorWe2nUXIHAvNAJvj32eqA==} + engines: {node: '>= 22'} + peerDependencies: + '@zenfs/core': ^2.3.11 + kerium: ^1.3.4 + utilium: ^2.5.0 + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -861,6 +872,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -871,6 +885,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + call-bind-apply-helpers@1.0.1: resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} @@ -1085,9 +1102,17 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1236,6 +1261,9 @@ packages: typescript: optional: true + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1386,6 +1414,9 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + kerium@1.3.6: + resolution: {integrity: sha512-TEMYweNOPW79LOGV9G26biypM2q96s4iJYxcWMg3IxUzRUIFGFfWIxS7Yx2eREKfhLINcNNXGUa0OR6ONS9Dgg==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1411,6 +1442,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + memium@0.3.8: + resolution: {integrity: sha512-spMrGHK7zNVBCZ2nhXxABC1yBtfe3HqUwEHD8j7oVMaLU+eqLrDoTZzMhx6bphw2/yA1EwOEdgeECtSfwRHk4w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1584,6 +1618,10 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -1670,6 +1708,10 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -1705,6 +1747,9 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -1799,6 +1844,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1874,6 +1922,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -1888,6 +1939,11 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + utilium@2.5.4: + resolution: {integrity: sha512-JeuMqv+yc2AGo0A3vVIiEwrYQcE/8SXftnvUq0HK0wnAmHtPCMZ/vln7nmNF9G63Qw9egijnTx3TxzdWZKYBmA==} + engines: {node: '>=22.0.0'} + hasBin: true + uuid@11.0.4: resolution: {integrity: sha512-IzL6VtTTYcAhA/oghbFJ1Dkmqev+FpQWnCBaKq/gUluLxliWvO8DPFWfIviRmYbtaavtSQe4WBL++rFjdcGWEg==} hasBin: true @@ -2381,6 +2437,10 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/node@24.3.1': + dependencies: + undici-types: 7.10.0 + '@types/react-dom@19.0.3(@types/react@19.0.7)': dependencies: '@types/react': 19.0.7 @@ -2500,6 +2560,29 @@ snapshots: '@xmldom/xmldom@0.8.10': {} + '@xterm/xterm@5.5.0': + optional: true + + '@zenfs/core@2.4.0': + dependencies: + '@types/node': 24.3.1 + buffer: 6.0.3 + eventemitter3: 5.0.1 + kerium: 1.3.6 + memium: 0.3.8 + readable-stream: 4.7.0 + utilium: 2.5.4 + + '@zenfs/dom@1.2.4(@zenfs/core@2.4.0)(kerium@1.3.6)(utilium@2.5.4)': + dependencies: + '@zenfs/core': 2.4.0 + kerium: 1.3.6 + utilium: 2.5.4 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -2595,6 +2678,8 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2608,6 +2693,11 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + call-bind-apply-helpers@1.0.1: dependencies: es-errors: 1.3.0 @@ -2979,8 +3069,12 @@ snapshots: esutils@2.0.3: {} + event-target-shim@5.0.1: {} + eventemitter3@5.0.1: {} + events@3.3.0: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -3141,6 +3235,8 @@ snapshots: optionalDependencies: typescript: 5.6.3 + ieee754@1.2.1: {} + ignore@5.3.2: {} import-fresh@3.3.0: @@ -3301,6 +3397,10 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + kerium@1.3.6: + dependencies: + utilium: 2.5.4 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3326,6 +3426,11 @@ snapshots: math-intrinsics@1.1.0: {} + memium@0.3.8: + dependencies: + kerium: 1.3.6 + utilium: 2.5.4 + merge2@1.4.1: {} micromatch@4.0.8: @@ -3504,6 +3609,8 @@ snapshots: prelude-ls@1.2.1: {} + process@0.11.10: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -3583,6 +3690,14 @@ snapshots: react@19.0.0: {} + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -3652,6 +3767,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -3788,6 +3905,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -3870,6 +3991,8 @@ snapshots: undici-types@6.20.0: {} + undici-types@7.10.0: {} + upper-case-first@2.0.2: dependencies: tslib: 2.6.3 @@ -3886,6 +4009,12 @@ snapshots: dependencies: react: 19.0.0 + utilium@2.5.4: + dependencies: + eventemitter3: 5.0.1 + optionalDependencies: + '@xterm/xterm': 5.5.0 + uuid@11.0.4: {} vite@6.0.9(@types/node@22.10.5): diff --git a/src/main.ts b/src/main.ts index eda0a66..dd223d6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,4 @@ // import './App/App'; import 'setimmediate'; // TODO: This is a workaround for upstream @phifans/audio +import '@/storage/init'; import './ui'; diff --git a/src/storage/adapters/indexeddb.ts b/src/storage/adapters/indexeddb.ts new file mode 100644 index 0000000..ed4de1d --- /dev/null +++ b/src/storage/adapters/indexeddb.ts @@ -0,0 +1,7 @@ +import { IndexedDB as Engine } from '@zenfs/dom'; +import { MountConfiguration } from '@zenfs/core'; + +export const IndexedDB: MountConfiguration = { + backend: Engine, + storeName: 'phifans-editor-storage', +}; diff --git a/src/storage/init.ts b/src/storage/init.ts new file mode 100644 index 0000000..e18bcae --- /dev/null +++ b/src/storage/init.ts @@ -0,0 +1,14 @@ +import { configureSingle } from '@zenfs/core'; +import * as fs from '@zenfs/core/promises'; +import { IndexedDB } from './adapters/indexeddb'; + +// TODO: Native adapters +await configureSingle(IndexedDB).then(async () => { + if (!(await fs.exists('/charts'))) { + await fs.mkdir('/charts'); + } + + if (!(await fs.exists('/skins'))) { + await fs.mkdir('/skins'); + } +}); From a87ca45513fa0614eb78f642e3949525cdd629f3 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sat, 6 Sep 2025 03:18:46 +0800 Subject: [PATCH 053/146] refactor(ui): Using @chakra/ui now Finished `Preview Panel` & `BPM Panel` --- package.json | 5 + pnpm-lock.yaml | 2313 +++++++++++++++++++- src/components/ui/color-mode.tsx | 108 + src/components/ui/provider.tsx | 15 + src/components/ui/slider.tsx | 82 + src/components/ui/toaster.tsx | 43 + src/components/ui/tooltip.tsx | 46 + src/ui/Panel/BPMPanel/BPMPanel.tsx | 54 +- src/ui/Panel/BPMPanel/Item.tsx | 64 +- src/ui/Panel/BPMPanel/List.tsx | 19 +- src/ui/Panel/BPMPanel/styles.css | 57 - src/ui/Panel/PreviewPanel/Canvas.tsx | 6 +- src/ui/Panel/PreviewPanel/Controller.tsx | 81 +- src/ui/Panel/PreviewPanel/PreviewPanel.tsx | 14 +- src/ui/Panel/PreviewPanel/styles.css | 48 - src/ui/components/BeatInput.tsx | 9 +- src/ui/components/NumberInput.tsx | 30 +- src/ui/index.tsx | 5 +- 18 files changed, 2677 insertions(+), 322 deletions(-) create mode 100644 src/components/ui/color-mode.tsx create mode 100644 src/components/ui/provider.tsx create mode 100644 src/components/ui/slider.tsx create mode 100644 src/components/ui/toaster.tsx create mode 100644 src/components/ui/tooltip.tsx delete mode 100644 src/ui/Panel/BPMPanel/styles.css delete mode 100644 src/ui/Panel/PreviewPanel/styles.css diff --git a/package.json b/package.json index 9441ded..7af060c 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ }, "dependencies": { "@blueprintjs/core": "^5.16.4", + "@chakra-ui/react": "^3.26.0", + "@emotion/react": "^11.14.0", "@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.2", @@ -35,12 +37,14 @@ "mobx-react-lite": "^4.1.0", "mobx-state-tree": "^7.0.2", "nanoid": "^5.1.5", + "next-themes": "^0.4.6", "normalize.css": "^8.0.1", "pixi.js": "^8.6.6", "quick-lru": "^7.1.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-i18next": "^15.4.1", + "react-icons": "^5.5.0", "react-split-pane": "^0.1.92", "setimmediate": "^1.0.5", "spark-md5": "^3.0.2", @@ -48,6 +52,7 @@ "zustand": "^5.0.8" }, "devDependencies": { + "@chakra-ui/cli": "^3.26.0", "@eslint/js": "^9.17.0", "@tauri-apps/cli": "^2.2.7", "@types/react": "^19.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fe635e..459d477 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,6 +16,12 @@ importers: '@blueprintjs/core': specifier: ^5.16.4 version: 5.16.4(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@chakra-ui/react': + specifier: ^3.26.0 + version: 3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@emotion/react': + specifier: ^11.14.0 + version: 11.14.0(@types/react@19.0.7)(react@19.0.0) '@fortawesome/fontawesome-svg-core': specifier: ^6.7.2 version: 6.7.2 @@ -70,6 +76,9 @@ importers: nanoid: specifier: ^5.1.5 version: 5.1.5 + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) normalize.css: specifier: ^8.0.1 version: 8.0.1 @@ -88,6 +97,9 @@ importers: react-i18next: specifier: ^15.4.1 version: 15.4.1(i18next@24.2.3(typescript@5.6.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-icons: + specifier: ^5.5.0 + version: 5.5.0(react@19.0.0) react-split-pane: specifier: ^0.1.92 version: 0.1.92(patch_hash=15b3bc41b3c9ea6e7a5c245069978ef071c4655082c4e9b0e14eb5d4eb57da5c)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -104,6 +116,9 @@ importers: specifier: ^5.0.8 version: 5.0.8(@types/react@19.0.7)(react@19.0.0)(use-sync-external-store@1.4.0(react@19.0.0)) devDependencies: + '@chakra-ui/cli': + specifier: ^3.26.0 + version: 3.26.0(@chakra-ui/react@3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)) '@eslint/js': specifier: ^9.17.0 version: 9.17.0 @@ -121,7 +136,7 @@ importers: version: 3.0.5 '@vitejs/plugin-react-swc': specifier: ^3.5.0 - version: 3.7.2(vite@6.0.9(@types/node@22.10.5)) + version: 3.7.2(@swc/helpers@0.5.17)(vite@6.0.9(@types/node@22.10.5)) eslint: specifier: ^9.17.0 version: 9.17.0 @@ -149,6 +164,41 @@ importers: packages: + '@ark-ui/react@5.22.0': + resolution: {integrity: sha512-cH3xVhKRn0ZsP2Jg2RZAziI38obIfTMC3Q6ZWtWeYL5k9fq6K8sa1XjdJclBRSD0vYYvR1ynHG9ThicWKKANtQ==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.3': + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/runtime@7.26.0': resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} engines: {node: '>=6.9.0'} @@ -157,6 +207,18 @@ packages: resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.3': + resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + '@blueprintjs/colors@5.1.5': resolution: {integrity: sha512-IUZvQLsQmfqumTTzeb5oQLnvskJcQYKcitzhDm5+iTWl42Jn5oyUqPDW96ubH/pfWoQGHzBp91ujq6KREl4GHQ==} @@ -181,156 +243,375 @@ packages: '@types/react': optional: true + '@chakra-ui/cli@3.26.0': + resolution: {integrity: sha512-BAnuzUCael9vjvq6bvNpX/UWJFu2I+pIfPqKT3I7ejo/c5JM6IDDqZQp7cs+10e0S4MXH743R/TfnVU96OOPBw==} + hasBin: true + peerDependencies: + '@chakra-ui/react': '>=3.0.0-next.0' + + '@chakra-ui/react@3.26.0': + resolution: {integrity: sha512-VuhFMLklzrjTWIst1B+uQggxOn9+GxVd+0LHLtsQKA+JtKUDqNfKymeWlb1/pKrmqH184+gwZJRjTtr6/+0cIQ==} + peerDependencies: + '@emotion/react': '>=11' + react: '>=18' + react-dom: '>=18' + + '@clack/core@0.5.0': + resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + + '@clack/prompts@0.11.0': + resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/is-prop-valid@1.4.0': + resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@esbuild/aix-ppc64@0.24.2': resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.24.2': resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.24.2': resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.24.2': resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.24.2': resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.24.2': resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.24.2': resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.24.2': resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.24.2': resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.24.2': resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.24.2': resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.24.2': resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.24.2': resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.24.2': resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.24.2': resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.24.2': resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.24.2': resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.24.2': resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.24.2': resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.24.2': resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.24.2': resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.24.2': resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.24.2': resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.24.2': resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.24.2': resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eshaz/web-worker@1.2.2': resolution: {integrity: sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==} @@ -368,6 +649,15 @@ packages: resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@fortawesome/fontawesome-common-types@6.7.2': resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} engines: {node: '>=6'} @@ -406,6 +696,29 @@ packages: resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} + '@internationalized/date@3.8.2': + resolution: {integrity: sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA==} + + '@internationalized/number@3.6.4': + resolution: {integrity: sha512-P+/h+RDaiX8EGt3shB9AYM1+QgkvHmJ5rKi4/59k4sg9g58k9rqsRW0WxRO7jCoHyvVbFRRFKmVTdFYdehrxHg==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -418,6 +731,9 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@pandacss/is-valid-prop@0.54.0': + resolution: {integrity: sha512-UhRgg1k9VKRCBAHl+XUK3lvN0k9bYifzYGZOqajDid4L1DyU813A1L0ZwN4iV9WX5TX3PfUugqtgG9LnIeFGBQ==} + '@phifans/audio@0.0.7': resolution: {integrity: sha512-w/OfBMWjQ0H7MPrnQxG/grS3JUE1nCiiut9QBtf2hNO33J5I1aLsb9MY+NQptfst54A7KpMiE1wcE1Nb3Czf2A==} @@ -430,6 +746,10 @@ packages: pixi.js: ^8.2.6 react: '>=19.0.0' + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} @@ -538,6 +858,10 @@ packages: cpu: [x64] os: [win32] + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + '@swc/core-darwin-arm64@1.10.3': resolution: {integrity: sha512-LFFCxAUKBy69AUE+01rgazQcafIXrYs6tBa9SyKPR51ft6Tp66dAVrWg9MTykaWskuXEe80LPUvUw1ga3bOH3A==} engines: {node: '>=10'} @@ -614,6 +938,9 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@swc/types@0.1.17': resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} @@ -694,9 +1021,15 @@ packages: resolution: {integrity: sha512-O7Vrdn6mlzfm9iKhGiVs1TibrNXhNjkwguTpFkkU2awZG/5ssOYidXU6RVZMqOFOvW6IQfN0nDbhvtqoNYse/w==} engines: {node: '>=18'} + '@types/cli-table@0.3.4': + resolution: {integrity: sha512-GsALrTL69mlwbAw/MHF1IPTadSLZQnsxe7a80G8l4inN/iEXCOcVeT/S7aRc6hbhqzL9qZ314kHPDQnQ3ev+HA==} + '@types/css-font-loading-module@0.0.12': resolution: {integrity: sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==} + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/earcut@2.1.4': resolution: {integrity: sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==} @@ -706,9 +1039,15 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@22.10.5': resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/react-dom@19.0.3': resolution: {integrity: sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==} peerDependencies: @@ -775,6 +1114,11 @@ packages: resolution: {integrity: sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@visulima/boxen@2.0.2': + resolution: {integrity: sha512-eqm/OzwETl1Zd5ehW5CUXhYf8tqb+seBCkHBKXh1rEMS94n+OhyCY0KAlZv/17qPoN73WT2nGDN9SdYlvoWbTQ==} + engines: {node: '>=20.18 <=24.x'} + os: [darwin, linux, win32] + '@vitejs/plugin-react-swc@3.7.2': resolution: {integrity: sha512-y0byko2b2tSVVf5Gpng1eEhX1OvPC7x8yns1Fx8jDzlJp4LS6CMkCPfLw47cjyoMrshQDoQw4qcgjsU9VvlCew==} peerDependencies: @@ -796,6 +1140,225 @@ packages: resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} + '@zag-js/accordion@1.22.1': + resolution: {integrity: sha512-P3jsauxnAGKBhuqs9gdivjEiSu7N7KnKRlgWlIpyti35askz8swHsqxsfkc2ASs9tcPKnPvuZDHIxXmJmZSLuQ==} + + '@zag-js/anatomy@1.22.1': + resolution: {integrity: sha512-I5OvOuJBt6hEqbpqVkWCOEoDfGMnKuLx+S0h7Un5SyAwnif3F1dSqDYujU28bCy8FtKs36vsq/izxufXyiXSEg==} + + '@zag-js/angle-slider@1.22.1': + resolution: {integrity: sha512-Nitjwwo2NVUEK+PabDnOfqizErnFIZZKThtcpQikAhE1J4MX3H128MANu1hJXNkvVYXyZmhTvzjt6XZc2j7YyQ==} + + '@zag-js/aria-hidden@1.22.1': + resolution: {integrity: sha512-vPfAE35BfYPS1UbYRcNw8/kMl7uayE7LyRncK/gPMnoQMjmEKW0nXmD5WlCHFLdGX9WFGYTIde8k4U8ay+oqcg==} + + '@zag-js/async-list@1.22.1': + resolution: {integrity: sha512-/evBfhDW3Rj3An5fHW8SYINM/pkxeOe/Uk7rRlBreHVn2PdAay4sj1gax4hlUUFEbqyvBgbHpR/atwfdxSuWYQ==} + + '@zag-js/auto-resize@1.22.1': + resolution: {integrity: sha512-O+tKmqwLko74DCmwdouxBZqEtIQB6Rt2pyXdlyBXLB7UnYXEIvEUzf8XK39I5AHXp6NlLqx77GtLn1qiBtKrkQ==} + + '@zag-js/avatar@1.22.1': + resolution: {integrity: sha512-SAz9XaFD8jg4LODkS51s6KrNcYF/PvAcRkCE9TDiuiCeFdgB6+JFKBNk0iM9og8Tk4Doe/3qIA/I12qKNW9pAw==} + + '@zag-js/carousel@1.22.1': + resolution: {integrity: sha512-bFbCRe5xarBtD3NnozHmCmrGJ+nLRhqLQFq+RG13fl1hlhUJaJ5AsS7e8L1r2ZLdbVVrsB0lUuW/ocfJ/G4MSw==} + + '@zag-js/checkbox@1.22.1': + resolution: {integrity: sha512-A/cZb89Aeb2k/KGl3ITS2fuLBXwq6Rnq9aFirfKs/UHrY16fopRbRjfqOxF6wm8lWoFk3gqmRGgybo8qsIfxog==} + + '@zag-js/clipboard@1.22.1': + resolution: {integrity: sha512-rKTPRKvLtcJ1c/CDvnWDRpqAteFS20UQe+mQpO83ACMCRZAfkXP3UOzBL53mh59+LIVlDxgZbMlwRiNiqqKhmA==} + + '@zag-js/collapsible@1.22.1': + resolution: {integrity: sha512-vKfDe/fzm3ndDfaueqW/XgGaWCHVD8MuLFtRRyv3jX3ubdNYn5R/j7ftQURdYyqRlPI3Si50FWSAtOqtvs4y9Q==} + + '@zag-js/collection@1.22.1': + resolution: {integrity: sha512-jjeSKALTH3iK2vTI6uAh2NCtS9n+e2r1cGERKCfNkbt86U6VSp9xiXqalUsEI4ovNIPcgg0+/nzixoVwFO1Vgg==} + + '@zag-js/color-picker@1.22.1': + resolution: {integrity: sha512-vUx8Ef0CZ/VPARIPh2ur76HH1AL3FVObNgtX64kPNUDUI+Z/L/q6CBfIeGcElVQ/Y6QowrqAXjVyPGArmmohmw==} + + '@zag-js/color-utils@1.22.1': + resolution: {integrity: sha512-Bee1KvYOV0yWQbODN+O2zPmdUaH+rymEmIHLfKNipPo5GVmxWqAe8oTQDyquzsUtoPE5MFgW5avg8tgSlCFcBA==} + + '@zag-js/combobox@1.22.1': + resolution: {integrity: sha512-N4tGTmezfHGaKB0+aDB5yMuVzBv2ShgsAx1uizom6ElcvlYD2rsQTr3xLc4wyOR7fx0z6fFDo1+63/Dt3y0t4A==} + + '@zag-js/core@1.22.1': + resolution: {integrity: sha512-4BNrwO9Tadq2Z0d2xSSQs4O/o3OarEHzXM2FQqx46vrwSE57qUghnZex429ZQ51fuk8AL5Lowt26a9JxE9sVPg==} + + '@zag-js/date-picker@1.22.1': + resolution: {integrity: sha512-ja482LloO7AGfFYXTfGV+qV484QWUM1cnF3hWtROd4Vdx/NONwn0w7TEJH+XbO3HaoUC5XpeacWLFQugGCsRjg==} + peerDependencies: + '@internationalized/date': '>=3.0.0' + + '@zag-js/date-utils@1.22.1': + resolution: {integrity: sha512-OWIWxihfFFyQDEaA35a/Fdfp3+GyGUgTUbutMD3BrbnPjKNLm0RyvAgZiq0zPTY7CzpYRbZ2J98GDU+CTERCjA==} + peerDependencies: + '@internationalized/date': '>=3.0.0' + + '@zag-js/dialog@1.22.1': + resolution: {integrity: sha512-b5KwMPYKc9RenZwxrAAHu6aHPz7tqPy4Mxa/YR5zo1pXBV4amA7u2xnqyncRaK65Z7y5QKmpmDuBp+0PnXxNIA==} + + '@zag-js/dismissable@1.22.1': + resolution: {integrity: sha512-0DzbykJu9QoXYw4Zcjte69Mtk6ThNRCXWxxCKBf930V8Bw3Ha7vfY5bgdb4RFT5K+BQP3E8vLT+PzIaDINn2Xw==} + + '@zag-js/dom-query@1.22.1': + resolution: {integrity: sha512-mtvGj2z3rkl40mkjd+QwoOHvxqpiOkY4mtVjzNzgzcbVtUN63Mz7giW8OZB+KLy37hwFX0B8JfiQncU8IOHNpw==} + + '@zag-js/editable@1.22.1': + resolution: {integrity: sha512-NY7VeKYuNLQzi+yZYmWliif0Qd/2PTKtDeqtnVypv8XSHqTbVeS2N9dqTru1g4RP+eGQWx0za12hjmCVU4DuMQ==} + + '@zag-js/file-upload@1.22.1': + resolution: {integrity: sha512-4iKpqxVLafLbQejcPoZcygtNURsezIlWRigHvVPd2pLsXPa8erbdcEZ8X4QvGp77xcW2QTkuSxB+BSCrEEAotA==} + + '@zag-js/file-utils@1.22.1': + resolution: {integrity: sha512-cZAJ5MAZCe7IfHfN+3xSNb9e6mA812U8BPJr/jNPN+qLQh/PkQDwKaGM33o2Me50r18iGTAswEkETnaFZt3wkw==} + + '@zag-js/floating-panel@1.22.1': + resolution: {integrity: sha512-YGjLoYt2xSk4pkTgsR0z/7U7V5OdaicSOZa0HDtskH4MkKPxQxrgf2G4e8dNsw8hnQwfVuoc0RGPGW0BArVr6A==} + + '@zag-js/focus-trap@1.22.1': + resolution: {integrity: sha512-6W9cG0LEVICt0srVfWSpamKzsnRxXMdl3gV+GQ5HvkCCk1Sw6Io4tc3QvSSvaWcfyhM07feerOsa2ah7qiT/ig==} + + '@zag-js/focus-visible@1.22.1': + resolution: {integrity: sha512-TuBEux3UTivo9VXPPe79q9JfTwaP/uIshL1KPifg51ofGYesWjMGeE5S5MAuaSzUmH9+3CpnwP7h7f65s3D0kw==} + + '@zag-js/highlight-word@1.22.1': + resolution: {integrity: sha512-mcPg4/ED3MNDzj5b3t4EEIKkvdyvVUJ9pqbyRUoj76KI+ZWXXJIw5PNAkG5vUVVUXKKjfzPVninIqWv1Bh9Bvg==} + + '@zag-js/hover-card@1.22.1': + resolution: {integrity: sha512-sGcWASPrt0f8oOpBdyDyka0Mkya4TdlBEOvB9qOvnkcIX2bc6YFUtWQN1L1M/K6nv8D0wSZK0p18JBaqGlHmBQ==} + + '@zag-js/i18n-utils@1.22.1': + resolution: {integrity: sha512-45KUYB9tu1br6NmgtaNW9NviozYCYUxJ8aZTI/Y6vKotXK/Pn3bIlaiOaq4Zel7TalGYT8gVnwgPe2E6H5sqTg==} + + '@zag-js/interact-outside@1.22.1': + resolution: {integrity: sha512-+iZ3xHC9+jVo2FCC4B9c9ntcXv19shVOqQGDr2cD30Hwmwtm9kCOdVydMqv3Lp3UhR8a105MXEVUAKg53WbCoA==} + + '@zag-js/json-tree-utils@1.22.1': + resolution: {integrity: sha512-z/15CTtXJHGUvecAAlPnUAaAK83Wxh5WlW9qEpgXlXdB5k7gnWVzH4qN9vDwlSShyZgqaFVqn+muxqaCTYv8Zg==} + + '@zag-js/listbox@1.22.1': + resolution: {integrity: sha512-M017Oq0s9PRR5ZwlJkmLhQHucEta/DZ5eHl/t+9yQqHnYRwWKo2ZXLyXquC1wihbHk81E0a1veDw8vBYpfRovA==} + + '@zag-js/live-region@1.22.1': + resolution: {integrity: sha512-xjrlCbcgIw+iXxSXnjXAv+WX9r/bMwp4HOIxWOD99360XvatQ2ZGhLH9lfixiXeHLvm6hjWsP92MjYefSLDFSA==} + + '@zag-js/menu@1.22.1': + resolution: {integrity: sha512-a5pgQgcpVTVyY6JM8k1WGqelHVKSPwV2CwOv2oGjHWXIr2fpRCAKqZRtytE5PvUP/CZArk8bCjatmgOWe1RdPQ==} + + '@zag-js/number-input@1.22.1': + resolution: {integrity: sha512-E4DROYvSo5TFJMkSmnq+f75wSTL/N7SK6MR8ssNlA2oQp69iVWXhIlFLe4knekX02QJzK1MF97aVU332kAYTeQ==} + + '@zag-js/pagination@1.22.1': + resolution: {integrity: sha512-Jeix+sXcfMPm5jer2W4PHSUCgu9a11aC/AOBk6dkxbX8XL23fYXJu5YyOVVq0iQIDWzX4Uij1N/vBha64ARmcA==} + + '@zag-js/password-input@1.22.1': + resolution: {integrity: sha512-EcCH0V2tbJbexy62nVDUXCMg/XVEcd0PGcBgUfziyaLlDnJz2HWkfe0MzpEiidJwfJfhvvf2DapX9mAyqzZhhw==} + + '@zag-js/pin-input@1.22.1': + resolution: {integrity: sha512-tyI5mVi+zmsDEVuZZTOA7fVyxxGwmD8A2snF6nRkFK11o5xnnZaXt44Z7XrPeljTMSLKt+rdF0y/9Q05Auc4tg==} + + '@zag-js/popover@1.22.1': + resolution: {integrity: sha512-27VVkhaEOtiHJYj2j++AzYlAzpMcW0ED05TV9wIT1q0EYzASWxweSBajbnCiQf9TIYzCImDiNVDaCMl5D+TamQ==} + + '@zag-js/popper@1.22.1': + resolution: {integrity: sha512-vBI5WpvE/3ugsimjZaNisOwcECiYfzc+3LIJwaU8od62kInZ1XF6m096BvV7JGwP0FjkMPJrgjcv7weDtY2iDQ==} + + '@zag-js/presence@1.22.1': + resolution: {integrity: sha512-9+pkKnjcHbNxk/80HzLdDjpiKGV/I208wAe0Njmej6q6Z79ED6cb7tXiOgAS7w/ZLWxwQW7B9oMJ3guVflBHwQ==} + + '@zag-js/progress@1.22.1': + resolution: {integrity: sha512-2U1IJLb1mhBLEgac8x8qaEv3qgr+pHdw6pn9mCCJVBcyFaSqliWps6X+vi+qKokFLrpjCjdAKuuf48ItNfFFcw==} + + '@zag-js/qr-code@1.22.1': + resolution: {integrity: sha512-HIRlNsPNcp5buiTZx7DrX/gCtouGAH4VJc8Q6HBUkaBbiiijVEuYN0aNAjZIdm2pDtrh4KaYjMPuIH8IrV554Q==} + + '@zag-js/radio-group@1.22.1': + resolution: {integrity: sha512-eqvY1y/Ui4nQOU8XE9tGShOCbI/YdSHFeH/tDJe2Yy+1kqO4bENxFJ3R1P097KusJgeb2SYzhID27whUslOq7g==} + + '@zag-js/rating-group@1.22.1': + resolution: {integrity: sha512-QxBK+hpfkQ4yFHUr1YOSwEQ3LuTrdS32J9zV8UyHu8HbgwzfR7L8ZAa1PUUmG65tupzua2pbn1NioOkMvDmBOQ==} + + '@zag-js/react@1.22.1': + resolution: {integrity: sha512-TcIKkNo9EFel+d92nb7104voKJNDiMkqq9nn7Ozq/TE8A62JPf5zk8y8zqoxTbGDTTk+tDjW7Sm1IKb4r6rX4w==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@zag-js/rect-utils@1.22.1': + resolution: {integrity: sha512-jtI03SR9kF0AcBffoFI/TKXn5KyhjNCtsGlqbWw0dKbhWTNy1v432FDC5opmmnH8W5LjjWebIzo4QtO5+632QQ==} + + '@zag-js/remove-scroll@1.22.1': + resolution: {integrity: sha512-2TrS8ljp8SADX5xRB/+KGBCBYbYTeH0k5IEalG2rt8ReNyNAW1JfCrm53KCVoCg9YmxKF3MrxPgPT83MNFsJhQ==} + + '@zag-js/scroll-area@1.22.1': + resolution: {integrity: sha512-BuWKGR3n1yMktYqfTx+U9iwpXkJJhDXW4yin7u/lLMAE0DXR4byyo8aollCkuzZdZbK7NmUG2zVQHUMZ1QaR6w==} + + '@zag-js/scroll-snap@1.22.1': + resolution: {integrity: sha512-kctqJiteALaavoHEpYBDSPgUErIdwAoY5jcrU4Mq5L8FjtI4tSNr8BWcXzSBK2UVqaKN+vDo+PDcj7XIXTUQJA==} + + '@zag-js/select@1.22.1': + resolution: {integrity: sha512-sWq0RqlJvmj0heJDpfS3OfM1ynSSCW+fYY5v3T/QyH4qneqB8OJjgh8EEBaHlOkbqv/oBsk855U8/o6jegfUxw==} + + '@zag-js/signature-pad@1.22.1': + resolution: {integrity: sha512-iD8tBCHSmRI6kdtHO8dNRZrfjGTxfWgweLlNXKu5JV2JkzPBhDCxpthHI9k8LJ0cgUM5/EW4HdEpjO9h47FsaA==} + + '@zag-js/slider@1.22.1': + resolution: {integrity: sha512-aricrX99r21RAS9TyPNTJL8gE8mNRSQMy7TIXTa9aoeRjN0Cf6+PSksKfmPdP9l249/nplGqvC25Ck7XUVJn6A==} + + '@zag-js/splitter@1.22.1': + resolution: {integrity: sha512-ZMuFlVvqO2WYD7AECEB51iiFpN7A30Q28NfkIVR98xugwUX1OJq1IizKRSbLgC/LmseHPp3OvotxjZX6FqkK4Q==} + + '@zag-js/steps@1.22.1': + resolution: {integrity: sha512-eJCHbHG9aGAbzb/IQCqpmk6fmwSmIfocAxNKVTljroD6OHkBtqgaZQVS3q4xyjz61nB/d/0ZlsvpCVjm1EhwBw==} + + '@zag-js/store@1.22.1': + resolution: {integrity: sha512-KrMWi/Fa4cqOjx2zDSMIu6vztFYik+V3K6VPWRVONM4FkboLpTqAEayzwgTTNqMK9iYYZIYjhiPhAVLW9iLuBg==} + + '@zag-js/switch@1.22.1': + resolution: {integrity: sha512-ipmBHEqtcrPYr5WS5Juj5dt4GFIqr81NYVNe8RHMW8jIHgHhRCRj3TokGXVlZ7HdseCKTTNNrcvRFBr1sJBbOw==} + + '@zag-js/tabs@1.22.1': + resolution: {integrity: sha512-B0WHW36uuR+pu/24X0yI4eyvSwo7WmqOc5C3ohZHOf03zkmMJdtMtVQSotKr7qhGMt5updCgs68MR7jAmmc1Lw==} + + '@zag-js/tags-input@1.22.1': + resolution: {integrity: sha512-/56pCeSIW+g+ish3Gjed7iNcPSbQEsBCBsCn6FU/JfjwyhLM0sAtn1vkE/eR92hvDX3klV12XzEMBGe4Egr3GQ==} + + '@zag-js/time-picker@1.22.1': + resolution: {integrity: sha512-7fqCtyDbuaelffLZ8q9infns+HQKqFMjL4k2V5zALAWdYu2NzvlMYHgj2Ue9AI4VI5QaE1nnwV6hxwS4Zpglvg==} + peerDependencies: + '@internationalized/date': '>=3.0.0' + + '@zag-js/timer@1.22.1': + resolution: {integrity: sha512-VmXnXjecuF4tXFdBRuMHxO8mQX3/vxagE4vx0M0gKwbGoGrXnhYGvULiPL3RlJj8OR8pIfYuP2lbCrt8XM625A==} + + '@zag-js/toast@1.22.1': + resolution: {integrity: sha512-cxcfbMftA//ggOAlxG3q04WZVL/mMVklvtQ2rSyj3oRmnwocJPYXtJzKIRazWBjji3u3BOA+ZeOI1AcGrfp/TQ==} + + '@zag-js/toggle-group@1.22.1': + resolution: {integrity: sha512-StxnGsPwzB60pGHTD7sNOqIMXjEPMl3lYQk0i2F5MIQWlTRkYdp4ivh73xBRYVtqK15gqacuWXw87EDzKcNwcA==} + + '@zag-js/toggle@1.22.1': + resolution: {integrity: sha512-KK9VK8ZkA/ep7KxQFaeVE/zHVm90fkp9q6q4inyQkUdURUg0vovTFI3c5q/c1zm9/g51vbNf5qCXWU4m9sQK8A==} + + '@zag-js/tooltip@1.22.1': + resolution: {integrity: sha512-0ub0p22CzYnaXv0prAnWNjqUBkdw4nO4yGk5qntaodajpLNQ4gSdq7Hj4afHzJqwbKAkwb3KzJFqcqIm9Y/dfw==} + + '@zag-js/tour@1.22.1': + resolution: {integrity: sha512-VhHC65NgBaCjlVsw1M4Me0P6PCtmD9oi9gRzN2fEUESdpM/QT5Yw6PAAPP1AEo5okv+V2rRBgSKOu9ZyYHa+IQ==} + + '@zag-js/tree-view@1.22.1': + resolution: {integrity: sha512-AQmOn1mB+nLJEaq0xdSVnTI8Vt3nB3OweqdB12jkbdIOcWI9eY0RfhiNHC0k0mgAw+dMjyn84op/gOd9VVdtmA==} + + '@zag-js/types@1.22.1': + resolution: {integrity: sha512-lvpDSMR96e7H7TdwOiVpMzj6css5Ydix1nBi7BlmjME6v5OPR0KZwVDGD6h5UtTeVjPq8dPaqM8TJWw+QwbQSw==} + + '@zag-js/utils@1.22.1': + resolution: {integrity: sha512-VXY4gjHaTENHW+wjnKKENZ2jcaW0vnG2a5lYEMuZR4dpNCKH217yFr/bCNrI44y2s1W3LWhWmpEjfZluP6udYg==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -806,13 +1369,36 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -858,9 +1444,17 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -871,6 +1465,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + bundle-n-require@1.1.2: + resolution: {integrity: sha512-bEk2jakVK1ytnZ9R2AAiZEeK/GxPUM8jvcRxHZXifZDMcjkI4EG/GlsJ2YGSVYT9y/p/gA9/0yDY8rCGsSU6Tg==} + call-bind-apply-helpers@1.0.1: resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} @@ -900,9 +1497,17 @@ packages: change-case@4.1.2: resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + cli-table@0.3.11: + resolution: {integrity: sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==} + engines: {node: '>= 0.2.0'} + codec-parser@2.5.0: resolution: {integrity: sha512-Ru9t80fV8B0ZiixQl8xhMTLru+dzuis/KQld32/x5T/+3LwZb0/YvQdSKytX9JqCnRdiupvAvyYJINKrXieziQ==} @@ -913,12 +1518,31 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colors@1.0.3: + resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} + engines: {node: '>=0.1.90'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + cross-fetch@4.0.0: resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} @@ -929,6 +1553,10 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -950,6 +1578,15 @@ packages: supports-color: optional: true + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -986,6 +1623,18 @@ packages: earcut@2.2.4: resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + es-abstract@1.23.9: resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} @@ -1022,6 +1671,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + engines: {node: '>=18'} + hasBin: true + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1095,15 +1749,26 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fastq@1.18.0: resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1112,6 +1777,9 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1126,6 +1794,14 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1161,6 +1837,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -1173,6 +1853,10 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1210,12 +1894,19 @@ packages: header-case@2.0.4: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hotkeys-js@3.13.9: resolution: {integrity: sha512-3TRCj9u9KUH6cKo25w4KIdBfdBfNRjfUwrljCLDC2XhmPDG0SjAZFcFZekpUZFmXzfYoGhFDcdx2gX/vUVtztQ==} html-parse-stringify@3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + i18next-browser-languagedetector@8.0.4: resolution: {integrity: sha512-f3frU3pIxD50/Tz20zx9TD9HobKYg47fmAETb117GKGPrhwcSSPJDoCposXlVycVebQ9GQohC3Efbpq7/nnJ5w==} @@ -1240,6 +1931,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -1256,6 +1951,9 @@ packages: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-async-function@2.1.0: resolution: {integrity: sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==} engines: {node: '>= 0.4'} @@ -1264,6 +1962,10 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-boolean-object@1.2.1: resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} engines: {node: '>= 0.4'} @@ -1292,6 +1994,10 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-generator-function@1.1.0: resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} @@ -1366,6 +2072,9 @@ packages: peerDependencies: react: '>=18.0' + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1373,9 +2082,17 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1393,6 +2110,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1400,6 +2120,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + look-it-up@2.1.0: + resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1407,6 +2130,9 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1426,6 +2152,10 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + mobx-react-lite@4.1.0: resolution: {integrity: sha512-QEP10dpHHBeQNv1pks3WnHRCem2Zp636lq54M2nKO2Sarr13pL4u6diQXf65yzXUn0mkk18SyIDCm9UOJYTi1w==} peerDependencies: @@ -1453,6 +2183,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.8: resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1466,9 +2199,24 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-eval@2.0.0: + resolution: {integrity: sha512-Ap+L9HznXAVeJj3TJ1op6M6bg5xtTq8L5CU/PJxtkhea/DrIxdTknGKIECKd/v/Lgql95iuMAYvIzBNd0pmcMg==} + engines: {node: '>= 4'} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -1478,10 +2226,18 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-wav@0.0.2: resolution: {integrity: sha512-M6Rm/bbG6De/gKGxOpeOobx/dnGuP0dz40adqx38boqHhlWssBJZgLCPBNtb9NkrmnKYiV04xELq+R6PFOnoLA==} engines: {node: '>=4.4.0'} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + normalize.css@8.0.1: resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==} @@ -1535,6 +2291,12 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -1542,6 +2304,10 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + parse-svg-path@0.1.2: resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==} @@ -1555,6 +2321,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1562,6 +2332,21 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + + perfect-freehand@1.2.2: + resolution: {integrity: sha512-eh31l019WICQ03pkF3FSzHxB8n07ItqIQ++G5UV8JX0zVOXzgTGCqnRR0jJ2h9U8/2uW4W4mtGJELt9kEV0CFQ==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1569,6 +2354,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + pixi.js@8.6.6: resolution: {integrity: sha512-o5pw7G2yuIrnBx0G4npBlmFp+XGNcapI/Ufs62rRj/4XKxc1Zo74YJr/BtEXcXTraTKd+pQvYOLvnfxRjxBMvQ==} @@ -1584,9 +2373,20 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-compare@3.0.1: + resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} + + proxy-memoize@3.0.1: + resolution: {integrity: sha512-VDdG/VYtOgdGkWJx7y0o7p+zArSf2383Isci8C+BP3YXgMYDoPd3cCBjw0JdWb6YBb9sFiOPbAADDVTPJnh+9g==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1622,6 +2422,11 @@ packages: react-native: optional: true + react-icons@5.5.0: + resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==} + peerDependencies: + react: '*' + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -1670,6 +2475,10 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -1685,6 +2494,11 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true @@ -1716,6 +2530,9 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -1767,9 +2584,20 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + simple-yenc@1.0.4: resolution: {integrity: sha512-5gvxpSd79e9a3V4QDYUqnqxeD4HGlhCakVpb6gMnDD7lexJggSBJRBO5h52y/iJrdXRilX9UCuDaIJhSWm5OWw==} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -1777,9 +2605,21 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + spark-md5@3.0.2: resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string.prototype.matchall@4.0.12: resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} @@ -1799,10 +2639,26 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1811,6 +2667,13 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1832,9 +2695,15 @@ packages: typescript: optional: true + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1874,12 +2743,19 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} upper-case@2.0.2: resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} + uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1939,6 +2815,10 @@ packages: warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -1970,10 +2850,25 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zustand@5.0.8: resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} engines: {node: '>=12.20.0'} @@ -1994,6 +2889,103 @@ packages: snapshots: + '@ark-ui/react@5.22.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@internationalized/date': 3.8.2 + '@zag-js/accordion': 1.22.1 + '@zag-js/anatomy': 1.22.1 + '@zag-js/angle-slider': 1.22.1 + '@zag-js/async-list': 1.22.1 + '@zag-js/auto-resize': 1.22.1 + '@zag-js/avatar': 1.22.1 + '@zag-js/carousel': 1.22.1 + '@zag-js/checkbox': 1.22.1 + '@zag-js/clipboard': 1.22.1 + '@zag-js/collapsible': 1.22.1 + '@zag-js/collection': 1.22.1 + '@zag-js/color-picker': 1.22.1 + '@zag-js/color-utils': 1.22.1 + '@zag-js/combobox': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/date-picker': 1.22.1(@internationalized/date@3.8.2) + '@zag-js/date-utils': 1.22.1(@internationalized/date@3.8.2) + '@zag-js/dialog': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/editable': 1.22.1 + '@zag-js/file-upload': 1.22.1 + '@zag-js/file-utils': 1.22.1 + '@zag-js/floating-panel': 1.22.1 + '@zag-js/focus-trap': 1.22.1 + '@zag-js/highlight-word': 1.22.1 + '@zag-js/hover-card': 1.22.1 + '@zag-js/i18n-utils': 1.22.1 + '@zag-js/json-tree-utils': 1.22.1 + '@zag-js/listbox': 1.22.1 + '@zag-js/menu': 1.22.1 + '@zag-js/number-input': 1.22.1 + '@zag-js/pagination': 1.22.1 + '@zag-js/password-input': 1.22.1 + '@zag-js/pin-input': 1.22.1 + '@zag-js/popover': 1.22.1 + '@zag-js/presence': 1.22.1 + '@zag-js/progress': 1.22.1 + '@zag-js/qr-code': 1.22.1 + '@zag-js/radio-group': 1.22.1 + '@zag-js/rating-group': 1.22.1 + '@zag-js/react': 1.22.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@zag-js/scroll-area': 1.22.1 + '@zag-js/select': 1.22.1 + '@zag-js/signature-pad': 1.22.1 + '@zag-js/slider': 1.22.1 + '@zag-js/splitter': 1.22.1 + '@zag-js/steps': 1.22.1 + '@zag-js/switch': 1.22.1 + '@zag-js/tabs': 1.22.1 + '@zag-js/tags-input': 1.22.1 + '@zag-js/time-picker': 1.22.1(@internationalized/date@3.8.2) + '@zag-js/timer': 1.22.1 + '@zag-js/toast': 1.22.1 + '@zag-js/toggle': 1.22.1 + '@zag-js/toggle-group': 1.22.1 + '@zag-js/tooltip': 1.22.1 + '@zag-js/tour': 1.22.1 + '@zag-js/tree-view': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/parser@7.28.3': + dependencies: + '@babel/types': 7.28.2 + '@babel/runtime@7.26.0': dependencies: regenerator-runtime: 0.14.1 @@ -2002,6 +2994,29 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + + '@babel/traverse@7.28.3': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.3 + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@blueprintjs/colors@5.1.5': dependencies: tslib: 2.6.3 @@ -2033,81 +3048,277 @@ snapshots: optionalDependencies: '@types/react': 19.0.7 + '@chakra-ui/cli@3.26.0(@chakra-ui/react@3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))': + dependencies: + '@chakra-ui/react': 3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@clack/prompts': 0.11.0 + '@pandacss/is-valid-prop': 0.54.0 + '@types/cli-table': 0.3.4 + '@types/debug': 4.1.12 + '@visulima/boxen': 2.0.2 + bundle-n-require: 1.1.2 + chokidar: 3.6.0 + cli-table: 0.3.11 + commander: 12.1.0 + debug: 4.4.1 + globby: 14.1.0 + https-proxy-agent: 7.0.6 + look-it-up: 2.1.0 + node-fetch: 3.3.2 + package-manager-detector: 1.3.0 + prettier: 3.6.2 + scule: 1.3.0 + sucrase: 3.35.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@chakra-ui/react@3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@ark-ui/react': 5.22.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@19.0.7)(react@19.0.0) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/utils': 1.4.2 + '@pandacss/is-valid-prop': 0.54.0 + csstype: 3.1.3 + fast-safe-stringify: 2.1.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + + '@clack/core@0.5.0': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.11.0': + dependencies: + '@clack/core': 0.5.0 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/runtime': 7.26.10 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@1.4.0': + dependencies: + '@emotion/memoize': 0.9.0 + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.10 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.1.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + dependencies: + react: 19.0.0 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + '@esbuild/aix-ppc64@0.24.2': optional: true + '@esbuild/aix-ppc64@0.25.9': + optional: true + '@esbuild/android-arm64@0.24.2': optional: true + '@esbuild/android-arm64@0.25.9': + optional: true + '@esbuild/android-arm@0.24.2': optional: true + '@esbuild/android-arm@0.25.9': + optional: true + '@esbuild/android-x64@0.24.2': optional: true + '@esbuild/android-x64@0.25.9': + optional: true + '@esbuild/darwin-arm64@0.24.2': optional: true + '@esbuild/darwin-arm64@0.25.9': + optional: true + '@esbuild/darwin-x64@0.24.2': optional: true + '@esbuild/darwin-x64@0.25.9': + optional: true + '@esbuild/freebsd-arm64@0.24.2': optional: true + '@esbuild/freebsd-arm64@0.25.9': + optional: true + '@esbuild/freebsd-x64@0.24.2': optional: true + '@esbuild/freebsd-x64@0.25.9': + optional: true + '@esbuild/linux-arm64@0.24.2': optional: true + '@esbuild/linux-arm64@0.25.9': + optional: true + '@esbuild/linux-arm@0.24.2': optional: true + '@esbuild/linux-arm@0.25.9': + optional: true + '@esbuild/linux-ia32@0.24.2': optional: true + '@esbuild/linux-ia32@0.25.9': + optional: true + '@esbuild/linux-loong64@0.24.2': optional: true + '@esbuild/linux-loong64@0.25.9': + optional: true + '@esbuild/linux-mips64el@0.24.2': optional: true + '@esbuild/linux-mips64el@0.25.9': + optional: true + '@esbuild/linux-ppc64@0.24.2': optional: true + '@esbuild/linux-ppc64@0.25.9': + optional: true + '@esbuild/linux-riscv64@0.24.2': optional: true + '@esbuild/linux-riscv64@0.25.9': + optional: true + '@esbuild/linux-s390x@0.24.2': optional: true + '@esbuild/linux-s390x@0.25.9': + optional: true + '@esbuild/linux-x64@0.24.2': optional: true + '@esbuild/linux-x64@0.25.9': + optional: true + '@esbuild/netbsd-arm64@0.24.2': optional: true + '@esbuild/netbsd-arm64@0.25.9': + optional: true + '@esbuild/netbsd-x64@0.24.2': optional: true + '@esbuild/netbsd-x64@0.25.9': + optional: true + '@esbuild/openbsd-arm64@0.24.2': optional: true + '@esbuild/openbsd-arm64@0.25.9': + optional: true + '@esbuild/openbsd-x64@0.24.2': optional: true + '@esbuild/openbsd-x64@0.25.9': + optional: true + + '@esbuild/openharmony-arm64@0.25.9': + optional: true + '@esbuild/sunos-x64@0.24.2': optional: true + '@esbuild/sunos-x64@0.25.9': + optional: true + '@esbuild/win32-arm64@0.24.2': optional: true + '@esbuild/win32-arm64@0.25.9': + optional: true + '@esbuild/win32-ia32@0.24.2': optional: true + '@esbuild/win32-ia32@0.25.9': + optional: true + '@esbuild/win32-x64@0.24.2': optional: true + '@esbuild/win32-x64@0.25.9': + optional: true + '@eshaz/web-worker@1.2.2': {} '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0)': @@ -2151,6 +3362,17 @@ snapshots: dependencies: levn: 0.4.1 + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/utils@0.2.10': {} + '@fortawesome/fontawesome-common-types@6.7.2': {} '@fortawesome/fontawesome-svg-core@6.7.2': @@ -2180,6 +3402,37 @@ snapshots: '@humanwhocodes/retry@0.4.1': {} + '@internationalized/date@3.8.2': + dependencies: + '@swc/helpers': 0.5.17 + + '@internationalized/number@3.6.4': + dependencies: + '@swc/helpers': 0.5.17 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2192,6 +3445,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.18.0 + '@pandacss/is-valid-prop@0.54.0': {} + '@phifans/audio@0.0.7': dependencies: '@types/setimmediate': 1.0.4 @@ -2209,6 +3464,9 @@ snapshots: transitivePeerDependencies: - '@types/react' + '@pkgjs/parseargs@0.11.0': + optional: true + '@popperjs/core@2.11.8': {} '@rollup/rollup-android-arm-eabi@4.34.7': @@ -2268,6 +3526,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.34.7': optional: true + '@sindresorhus/merge-streams@2.3.0': {} + '@swc/core-darwin-arm64@1.10.3': optional: true @@ -2298,7 +3558,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.10.3': optional: true - '@swc/core@1.10.3': + '@swc/core@1.10.3(@swc/helpers@0.5.17)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.17 @@ -2313,9 +3573,14 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.10.3 '@swc/core-win32-ia32-msvc': 1.10.3 '@swc/core-win32-x64-msvc': 1.10.3 + '@swc/helpers': 0.5.17 '@swc/counter@0.1.3': {} + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + '@swc/types@0.1.17': dependencies: '@swc/counter': 0.1.3 @@ -2369,136 +3634,661 @@ snapshots: '@thi.ng/errors@2.5.22': {} + '@types/cli-table@0.3.4': {} + '@types/css-font-loading-module@0.0.12': {} + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + '@types/earcut@2.1.4': {} '@types/estree@1.0.6': {} - '@types/json-schema@7.0.15': {} + '@types/json-schema@7.0.15': {} + + '@types/ms@2.1.0': {} + + '@types/node@22.10.5': + dependencies: + undici-types: 6.20.0 + + '@types/parse-json@4.0.2': {} + + '@types/react-dom@19.0.3(@types/react@19.0.7)': + dependencies: + '@types/react': 19.0.7 + + '@types/react-reconciler@0.28.9(@types/react@19.0.7)': + dependencies: + '@types/react': 19.0.7 + + '@types/react@19.0.7': + dependencies: + csstype: 3.1.3 + + '@types/setimmediate@1.0.4': {} + + '@types/spark-md5@3.0.5': {} + + '@typescript-eslint/eslint-plugin@8.18.2(@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3))(eslint@9.17.0)(typescript@5.6.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.18.2(eslint@9.17.0)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.18.2 + '@typescript-eslint/type-utils': 8.18.2(eslint@9.17.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.18.2(eslint@9.17.0)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.18.2 + eslint: 9.17.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.4.3(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.18.2 + '@typescript-eslint/types': 8.18.2 + '@typescript-eslint/typescript-estree': 8.18.2(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.18.2 + debug: 4.4.0 + eslint: 9.17.0 + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.18.2': + dependencies: + '@typescript-eslint/types': 8.18.2 + '@typescript-eslint/visitor-keys': 8.18.2 + + '@typescript-eslint/type-utils@8.18.2(eslint@9.17.0)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.18.2(typescript@5.6.3) + '@typescript-eslint/utils': 8.18.2(eslint@9.17.0)(typescript@5.6.3) + debug: 4.4.0 + eslint: 9.17.0 + ts-api-utils: 1.4.3(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.18.2': {} + + '@typescript-eslint/typescript-estree@8.18.2(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 8.18.2 + '@typescript-eslint/visitor-keys': 8.18.2 + debug: 4.4.0 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.4.3(typescript@5.6.3) + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.18.2(eslint@9.17.0)(typescript@5.6.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) + '@typescript-eslint/scope-manager': 8.18.2 + '@typescript-eslint/types': 8.18.2 + '@typescript-eslint/typescript-estree': 8.18.2(typescript@5.6.3) + eslint: 9.17.0 + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.18.2': + dependencies: + '@typescript-eslint/types': 8.18.2 + eslint-visitor-keys: 4.2.0 + + '@visulima/boxen@2.0.2': {} + + '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.17)(vite@6.0.9(@types/node@22.10.5))': + dependencies: + '@swc/core': 1.10.3(@swc/helpers@0.5.17) + vite: 6.0.9(@types/node@22.10.5) + transitivePeerDependencies: + - '@swc/helpers' + + '@wasm-audio-decoders/common@9.0.5': + dependencies: + '@eshaz/web-worker': 1.2.2 + simple-yenc: 1.0.4 + + '@wasm-audio-decoders/flac@0.2.5': + dependencies: + '@wasm-audio-decoders/common': 9.0.5 + codec-parser: 2.5.0 + + '@wasm-audio-decoders/ogg-vorbis@0.1.16': + dependencies: + '@wasm-audio-decoders/common': 9.0.5 + codec-parser: 2.5.0 + + '@webgpu/types@0.1.53': {} + + '@xmldom/xmldom@0.8.10': {} + + '@zag-js/accordion@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/anatomy@1.22.1': {} + + '@zag-js/angle-slider@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/rect-utils': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/aria-hidden@1.22.1': {} + + '@zag-js/async-list@1.22.1': + dependencies: + '@zag-js/core': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/auto-resize@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + + '@zag-js/avatar@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/carousel@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/scroll-snap': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/checkbox@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-visible': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/clipboard@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/collapsible@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/collection@1.22.1': + dependencies: + '@zag-js/utils': 1.22.1 + + '@zag-js/color-picker@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/color-utils': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/color-utils@1.22.1': + dependencies: + '@zag-js/utils': 1.22.1 + + '@zag-js/combobox@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/aria-hidden': 1.22.1 + '@zag-js/collection': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/core@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/date-picker@1.22.1(@internationalized/date@3.8.2)': + dependencies: + '@internationalized/date': 3.8.2 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/date-utils': 1.22.1(@internationalized/date@3.8.2) + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/live-region': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/date-utils@1.22.1(@internationalized/date@3.8.2)': + dependencies: + '@internationalized/date': 3.8.2 + + '@zag-js/dialog@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/aria-hidden': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-trap': 1.22.1 + '@zag-js/remove-scroll': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/dismissable@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + '@zag-js/interact-outside': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/dom-query@1.22.1': + dependencies: + '@zag-js/types': 1.22.1 + + '@zag-js/editable@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/interact-outside': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/file-upload@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/file-utils': 1.22.1 + '@zag-js/i18n-utils': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/file-utils@1.22.1': + dependencies: + '@zag-js/i18n-utils': 1.22.1 + + '@zag-js/floating-panel@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/rect-utils': 1.22.1 + '@zag-js/store': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/focus-trap@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + + '@zag-js/focus-visible@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + + '@zag-js/highlight-word@1.22.1': {} + + '@zag-js/hover-card@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/i18n-utils@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + + '@zag-js/interact-outside@1.22.1': + dependencies: + '@zag-js/dom-query': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/json-tree-utils@1.22.1': {} + + '@zag-js/listbox@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/collection': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-visible': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/live-region@1.22.1': {} + + '@zag-js/menu@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/rect-utils': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/number-input@1.22.1': + dependencies: + '@internationalized/number': 3.6.4 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/pagination@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@types/node@22.10.5': + '@zag-js/password-input@1.22.1': dependencies: - undici-types: 6.20.0 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@types/react-dom@19.0.3(@types/react@19.0.7)': + '@zag-js/pin-input@1.22.1': dependencies: - '@types/react': 19.0.7 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@types/react-reconciler@0.28.9(@types/react@19.0.7)': + '@zag-js/popover@1.22.1': dependencies: - '@types/react': 19.0.7 + '@zag-js/anatomy': 1.22.1 + '@zag-js/aria-hidden': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-trap': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/remove-scroll': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@types/react@19.0.7': + '@zag-js/popper@1.22.1': dependencies: - csstype: 3.1.3 + '@floating-ui/dom': 1.7.4 + '@zag-js/dom-query': 1.22.1 + '@zag-js/utils': 1.22.1 - '@types/setimmediate@1.0.4': {} + '@zag-js/presence@1.22.1': + dependencies: + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 - '@types/spark-md5@3.0.5': {} + '@zag-js/progress@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@typescript-eslint/eslint-plugin@8.18.2(@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3))(eslint@9.17.0)(typescript@5.6.3)': + '@zag-js/qr-code@1.22.1': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.18.2(eslint@9.17.0)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 8.18.2 - '@typescript-eslint/type-utils': 8.18.2(eslint@9.17.0)(typescript@5.6.3) - '@typescript-eslint/utils': 8.18.2(eslint@9.17.0)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.18.2 - eslint: 9.17.0 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.6.3) - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + proxy-memoize: 3.0.1 + uqr: 0.1.2 + + '@zag-js/radio-group@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-visible': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/rating-group@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/react@1.22.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@zag-js/core': 1.22.1 + '@zag-js/store': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) - '@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3)': + '@zag-js/rect-utils@1.22.1': {} + + '@zag-js/remove-scroll@1.22.1': dependencies: - '@typescript-eslint/scope-manager': 8.18.2 - '@typescript-eslint/types': 8.18.2 - '@typescript-eslint/typescript-estree': 8.18.2(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 8.18.2 - debug: 4.4.0 - eslint: 9.17.0 - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color + '@zag-js/dom-query': 1.22.1 - '@typescript-eslint/scope-manager@8.18.2': + '@zag-js/scroll-area@1.22.1': dependencies: - '@typescript-eslint/types': 8.18.2 - '@typescript-eslint/visitor-keys': 8.18.2 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@typescript-eslint/type-utils@8.18.2(eslint@9.17.0)(typescript@5.6.3)': + '@zag-js/scroll-snap@1.22.1': dependencies: - '@typescript-eslint/typescript-estree': 8.18.2(typescript@5.6.3) - '@typescript-eslint/utils': 8.18.2(eslint@9.17.0)(typescript@5.6.3) - debug: 4.4.0 - eslint: 9.17.0 - ts-api-utils: 1.4.3(typescript@5.6.3) - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color + '@zag-js/dom-query': 1.22.1 - '@typescript-eslint/types@8.18.2': {} + '@zag-js/select@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/collection': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@typescript-eslint/typescript-estree@8.18.2(typescript@5.6.3)': + '@zag-js/signature-pad@1.22.1': dependencies: - '@typescript-eslint/types': 8.18.2 - '@typescript-eslint/visitor-keys': 8.18.2 - debug: 4.4.0 - fast-glob: 3.3.2 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@5.6.3) - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + perfect-freehand: 1.2.2 - '@typescript-eslint/utils@8.18.2(eslint@9.17.0)(typescript@5.6.3)': + '@zag-js/slider@1.22.1': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) - '@typescript-eslint/scope-manager': 8.18.2 - '@typescript-eslint/types': 8.18.2 - '@typescript-eslint/typescript-estree': 8.18.2(typescript@5.6.3) - eslint: 9.17.0 - typescript: 5.6.3 - transitivePeerDependencies: - - supports-color + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@typescript-eslint/visitor-keys@8.18.2': + '@zag-js/splitter@1.22.1': dependencies: - '@typescript-eslint/types': 8.18.2 - eslint-visitor-keys: 4.2.0 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@vitejs/plugin-react-swc@3.7.2(vite@6.0.9(@types/node@22.10.5))': + '@zag-js/steps@1.22.1': dependencies: - '@swc/core': 1.10.3 - vite: 6.0.9(@types/node@22.10.5) - transitivePeerDependencies: - - '@swc/helpers' + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@wasm-audio-decoders/common@9.0.5': + '@zag-js/store@1.22.1': dependencies: - '@eshaz/web-worker': 1.2.2 - simple-yenc: 1.0.4 + proxy-compare: 3.0.1 - '@wasm-audio-decoders/flac@0.2.5': + '@zag-js/switch@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-visible': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/tabs@1.22.1': dependencies: - '@wasm-audio-decoders/common': 9.0.5 - codec-parser: 2.5.0 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@wasm-audio-decoders/ogg-vorbis@0.1.16': + '@zag-js/tags-input@1.22.1': dependencies: - '@wasm-audio-decoders/common': 9.0.5 - codec-parser: 2.5.0 + '@zag-js/anatomy': 1.22.1 + '@zag-js/auto-resize': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/interact-outside': 1.22.1 + '@zag-js/live-region': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 - '@webgpu/types@0.1.53': {} + '@zag-js/time-picker@1.22.1(@internationalized/date@3.8.2)': + dependencies: + '@internationalized/date': 3.8.2 + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/timer@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/toast@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/toggle-group@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/toggle@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/tooltip@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-visible': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/tour@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dismissable': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/focus-trap': 1.22.1 + '@zag-js/interact-outside': 1.22.1 + '@zag-js/popper': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/tree-view@1.22.1': + dependencies: + '@zag-js/anatomy': 1.22.1 + '@zag-js/collection': 1.22.1 + '@zag-js/core': 1.22.1 + '@zag-js/dom-query': 1.22.1 + '@zag-js/types': 1.22.1 + '@zag-js/utils': 1.22.1 + + '@zag-js/types@1.22.1': + dependencies: + csstype: 3.1.3 - '@xmldom/xmldom@0.8.10': {} + '@zag-js/utils@1.22.1': {} acorn-jsx@5.3.2(acorn@8.14.0): dependencies: @@ -2506,6 +4296,8 @@ snapshots: acorn@8.14.0: {} + agent-base@7.1.4: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -2513,10 +4305,23 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-regex@5.0.1: {} + + ansi-regex@6.2.0: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + argparse@2.0.1: {} array-buffer-byte-length@1.0.2: @@ -2593,8 +4398,16 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.26.10 + cosmiconfig: 7.1.0 + resolve: 1.22.10 + balanced-match@1.0.2: {} + binary-extensions@2.3.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2608,6 +4421,11 @@ snapshots: dependencies: fill-range: 7.1.1 + bundle-n-require@1.1.2: + dependencies: + esbuild: 0.25.9 + node-eval: 2.0.0 + call-bind-apply-helpers@1.0.1: dependencies: es-errors: 1.3.0 @@ -2658,8 +4476,24 @@ snapshots: snake-case: 3.0.4 tslib: 2.6.3 + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + classnames@2.5.1: {} + cli-table@0.3.11: + dependencies: + colors: 1.0.3 + codec-parser@2.5.0: {} color-convert@2.0.1: @@ -2668,6 +4502,12 @@ snapshots: color-name@1.1.4: {} + colors@1.0.3: {} + + commander@12.1.0: {} + + commander@4.1.1: {} + concat-map@0.0.1: {} constant-case@3.0.4: @@ -2676,6 +4516,16 @@ snapshots: tslib: 2.6.3 upper-case: 2.0.2 + convert-source-map@1.9.0: {} + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + cross-fetch@4.0.0: dependencies: node-fetch: 2.7.0 @@ -2690,6 +4540,8 @@ snapshots: csstype@3.1.3: {} + data-uri-to-buffer@4.0.1: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.3 @@ -2712,6 +4564,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.1: + dependencies: + ms: 2.1.3 + deep-is@0.1.4: {} define-data-property@1.1.4: @@ -2739,7 +4595,7 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.26.10 csstype: 3.1.3 dot-case@3.0.4: @@ -2755,6 +4611,16 @@ snapshots: earcut@2.2.4: {} + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + es-abstract@1.23.9: dependencies: array-buffer-byte-length: 1.0.2 @@ -2881,6 +4747,35 @@ snapshots: '@esbuild/win32-ia32': 0.24.2 '@esbuild/win32-x64': 0.24.2 + esbuild@0.25.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 + escape-string-regexp@4.0.0: {} eslint-plugin-react-hooks@5.1.0(eslint@9.17.0): @@ -2991,14 +4886,29 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} + fast-safe-stringify@2.1.1: {} + fastq@1.18.0: dependencies: reusify: 1.0.4 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -3007,6 +4917,8 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-root@1.1.0: {} + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -3023,6 +4935,15 @@ snapshots: dependencies: is-callable: 1.2.7 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + fsevents@2.3.3: optional: true @@ -3071,6 +4992,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + globals@14.0.0: {} globals@15.14.0: {} @@ -3080,6 +5010,15 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + gopd@1.2.0: {} graphemer@1.4.0: {} @@ -3111,12 +5050,23 @@ snapshots: capital-case: 1.0.4 tslib: 2.6.3 + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + hotkeys-js@3.13.9: {} html-parse-stringify@3.0.1: dependencies: void-elements: 3.1.0 + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + i18next-browser-languagedetector@8.0.4: dependencies: '@babel/runtime': 7.26.0 @@ -3143,6 +5093,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.5: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -3162,6 +5114,8 @@ snapshots: call-bound: 1.0.3 get-intrinsic: 1.2.7 + is-arrayish@0.2.1: {} + is-async-function@2.1.0: dependencies: call-bound: 1.0.3 @@ -3173,6 +5127,10 @@ snapshots: dependencies: has-bigints: 1.1.0 + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-boolean-object@1.2.1: dependencies: call-bound: 1.0.3 @@ -3201,6 +5159,8 @@ snapshots: dependencies: call-bound: 1.0.3 + is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.1.0: dependencies: call-bound: 1.0.3 @@ -3282,14 +5242,24 @@ snapshots: transitivePeerDependencies: - '@types/react' + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + js-tokens@4.0.0: {} js-yaml@4.1.0: dependencies: argparse: 2.0.1 + jsesc@3.1.0: {} + json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -3310,12 +5280,16 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lines-and-columns@1.2.4: {} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + look-it-up@2.1.0: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -3324,6 +5298,8 @@ snapshots: dependencies: tslib: 2.6.3 + lru-cache@10.4.3: {} + math-intrinsics@1.1.0: {} merge2@1.4.1: {} @@ -3341,6 +5317,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minipass@7.1.2: {} + mobx-react-lite@4.1.0(mobx@6.13.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: mobx: 6.13.7 @@ -3364,23 +5342,48 @@ snapshots: ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.8: {} nanoid@5.1.5: {} natural-compare@1.4.0: {} + next-themes@0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + no-case@3.0.4: dependencies: lower-case: 2.0.2 tslib: 2.6.3 + node-domexception@1.0.0: {} + + node-eval@2.0.0: + dependencies: + path-is-absolute: 1.0.1 + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-wav@0.0.2: {} + normalize-path@3.0.0: {} + normalize.css@8.0.1: {} object-assign@4.1.1: {} @@ -3451,6 +5454,10 @@ snapshots: dependencies: p-limit: 3.1.0 + package-json-from-dist@1.0.1: {} + + package-manager-detector@1.3.0: {} + param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -3460,6 +5467,13 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parse-svg-path@0.1.2: {} pascal-case@3.1.2: @@ -3474,14 +5488,29 @@ snapshots: path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-type@4.0.0: {} + + path-type@6.0.0: {} + + perfect-freehand@1.2.2: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} + pirates@4.0.7: {} + pixi.js@8.6.6: dependencies: '@pixi/colord': 2.9.6 @@ -3504,12 +5533,20 @@ snapshots: prelude-ls@1.2.1: {} + prettier@3.6.2: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + proxy-compare@3.0.1: {} + + proxy-memoize@3.0.1: + dependencies: + proxy-compare: 3.0.1 + punycode@2.3.1: {} qoa-format@1.0.1: @@ -3536,6 +5573,10 @@ snapshots: optionalDependencies: react-dom: 19.0.0(react@19.0.0) + react-icons@5.5.0(react@19.0.0): + dependencies: + react: 19.0.0 + react-is@16.13.1: {} react-lifecycles-compat@3.0.4: {} @@ -3567,7 +5608,7 @@ snapshots: react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.26.10 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -3583,6 +5624,10 @@ snapshots: react@19.0.0: {} + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -3607,6 +5652,12 @@ snapshots: resolve-from@4.0.0: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@2.0.0-next.5: dependencies: is-core-module: 2.16.1 @@ -3665,6 +5716,8 @@ snapshots: scheduler@0.25.0: {} + scule@1.3.0: {} + semver@6.3.1: {} semver@7.6.3: {} @@ -3733,8 +5786,14 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + signal-exit@4.1.0: {} + simple-yenc@1.0.4: {} + sisteransi@1.0.5: {} + + slash@5.1.0: {} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -3742,8 +5801,22 @@ snapshots: source-map-js@1.2.1: {} + source-map@0.5.7: {} + spark-md5@3.0.2: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + string.prototype.matchall@4.0.12: dependencies: call-bind: 1.0.8 @@ -3788,14 +5861,42 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.2.0 + strip-json-comments@3.1.1: {} + stylis@4.2.0: {} + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + ts-interface-checker: 0.1.13 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -3810,8 +5911,12 @@ snapshots: optionalDependencies: typescript: 5.6.3 + ts-interface-checker@0.1.13: {} + tslib@2.6.3: {} + tslib@2.8.1: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -3870,6 +5975,8 @@ snapshots: undici-types@6.20.0: {} + unicorn-magic@0.3.0: {} + upper-case-first@2.0.2: dependencies: tslib: 2.6.3 @@ -3878,6 +5985,8 @@ snapshots: dependencies: tslib: 2.6.3 + uqr@0.1.2: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -3903,6 +6012,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + web-streams-polyfill@3.3.3: {} + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: @@ -3956,8 +6067,24 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + yaml@1.10.2: {} + yocto-queue@0.1.0: {} + zod@3.25.76: {} + zustand@5.0.8(@types/react@19.0.7)(react@19.0.0)(use-sync-external-store@1.4.0(react@19.0.0)): optionalDependencies: '@types/react': 19.0.7 diff --git a/src/components/ui/color-mode.tsx b/src/components/ui/color-mode.tsx new file mode 100644 index 0000000..899313b --- /dev/null +++ b/src/components/ui/color-mode.tsx @@ -0,0 +1,108 @@ +"use client" + +import type { IconButtonProps, SpanProps } from "@chakra-ui/react" +import { ClientOnly, IconButton, Skeleton, Span } from "@chakra-ui/react" +import { ThemeProvider, useTheme } from "next-themes" +import type { ThemeProviderProps } from "next-themes" +import * as React from "react" +import { LuMoon, LuSun } from "react-icons/lu" + +export interface ColorModeProviderProps extends ThemeProviderProps {} + +export function ColorModeProvider(props: ColorModeProviderProps) { + return ( + + ) +} + +export type ColorMode = "light" | "dark" + +export interface UseColorModeReturn { + colorMode: ColorMode + setColorMode: (colorMode: ColorMode) => void + toggleColorMode: () => void +} + +export function useColorMode(): UseColorModeReturn { + const { resolvedTheme, setTheme, forcedTheme } = useTheme() + const colorMode = forcedTheme || resolvedTheme + const toggleColorMode = () => { + setTheme(resolvedTheme === "dark" ? "light" : "dark") + } + return { + colorMode: colorMode as ColorMode, + setColorMode: setTheme, + toggleColorMode, + } +} + +export function useColorModeValue(light: T, dark: T) { + const { colorMode } = useColorMode() + return colorMode === "dark" ? dark : light +} + +export function ColorModeIcon() { + const { colorMode } = useColorMode() + return colorMode === "dark" ? : +} + +interface ColorModeButtonProps extends Omit {} + +export const ColorModeButton = React.forwardRef< + HTMLButtonElement, + ColorModeButtonProps +>(function ColorModeButton(props, ref) { + const { toggleColorMode } = useColorMode() + return ( + }> + + + + + ) +}) + +export const LightMode = React.forwardRef( + function LightMode(props, ref) { + return ( + + ) + }, +) + +export const DarkMode = React.forwardRef( + function DarkMode(props, ref) { + return ( + + ) + }, +) diff --git a/src/components/ui/provider.tsx b/src/components/ui/provider.tsx new file mode 100644 index 0000000..fd0331b --- /dev/null +++ b/src/components/ui/provider.tsx @@ -0,0 +1,15 @@ +"use client" + +import { ChakraProvider, defaultSystem } from "@chakra-ui/react" +import { + ColorModeProvider, + type ColorModeProviderProps, +} from "./color-mode" + +export function Provider(props: ColorModeProviderProps) { + return ( + + + + ) +} diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx new file mode 100644 index 0000000..55a7283 --- /dev/null +++ b/src/components/ui/slider.tsx @@ -0,0 +1,82 @@ +import { Slider as ChakraSlider, For, HStack } from "@chakra-ui/react" +import * as React from "react" + +export interface SliderProps extends ChakraSlider.RootProps { + marks?: Array + label?: React.ReactNode + showValue?: boolean +} + +export const Slider = React.forwardRef( + function Slider(props, ref) { + const { marks: marksProp, label, showValue, ...rest } = props + const value = props.defaultValue ?? props.value + + const marks = marksProp?.map((mark) => { + if (typeof mark === "number") return { value: mark, label: undefined } + return mark + }) + + const hasMarkLabel = !!marks?.some((mark) => mark.label) + + return ( + + {label && !showValue && ( + {label} + )} + {label && showValue && ( + + {label} + + + )} + + + + + + + + + ) + }, +) + +function SliderThumbs(props: { value?: number[] }) { + const { value } = props + return ( + + {(_, index) => ( + + + + )} + + ) +} + +interface SliderMarksProps { + marks?: Array +} + +const SliderMarks = React.forwardRef( + function SliderMarks(props, ref) { + const { marks } = props + if (!marks?.length) return null + + return ( + + {marks.map((mark, index) => { + const value = typeof mark === "number" ? mark : mark.value + const label = typeof mark === "number" ? undefined : mark.label + return ( + + + {label} + + ) + })} + + ) + }, +) diff --git a/src/components/ui/toaster.tsx b/src/components/ui/toaster.tsx new file mode 100644 index 0000000..5d70a35 --- /dev/null +++ b/src/components/ui/toaster.tsx @@ -0,0 +1,43 @@ +"use client" + +import { + Toaster as ChakraToaster, + Portal, + Spinner, + Stack, + Toast, + createToaster, +} from "@chakra-ui/react" + +export const toaster = createToaster({ + placement: "bottom-end", + pauseOnPageIdle: true, +}) + +export const Toaster = () => { + return ( + + + {(toast) => ( + + {toast.type === "loading" ? ( + + ) : ( + + )} + + {toast.title && {toast.title}} + {toast.description && ( + {toast.description} + )} + + {toast.action && ( + {toast.action.label} + )} + {toast.closable && } + + )} + + + ) +} diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx new file mode 100644 index 0000000..0129778 --- /dev/null +++ b/src/components/ui/tooltip.tsx @@ -0,0 +1,46 @@ +import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react" +import * as React from "react" + +export interface TooltipProps extends ChakraTooltip.RootProps { + showArrow?: boolean + portalled?: boolean + portalRef?: React.RefObject + content: React.ReactNode + contentProps?: ChakraTooltip.ContentProps + disabled?: boolean +} + +export const Tooltip = React.forwardRef( + function Tooltip(props, ref) { + const { + showArrow, + children, + disabled, + portalled = true, + content, + contentProps, + portalRef, + ...rest + } = props + + if (disabled) return children + + return ( + + {children} + + + + {showArrow && ( + + + + )} + {content} + + + + + ) + }, +) diff --git a/src/ui/Panel/BPMPanel/BPMPanel.tsx b/src/ui/Panel/BPMPanel/BPMPanel.tsx index 452f5cf..0e0d28d 100644 --- a/src/ui/Panel/BPMPanel/BPMPanel.tsx +++ b/src/ui/Panel/BPMPanel/BPMPanel.tsx @@ -4,8 +4,10 @@ import { useTranslation } from 'react-i18next'; import { store as ChartStore } from '@/core/state/chartStore'; import BPMList from './List'; import NumberInput from '@/ui/components/NumberInput'; -import './styles.css'; import { BeatArray } from '@/utils/types'; +import { Box, Button, Grid, GridItem, Text, Separator, ScrollArea } from "@chakra-ui/react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faPlus } from "@fortawesome/free-solid-svg-icons"; const BPMPanel = observer(() => { const { t } = useTranslation(); @@ -22,24 +24,38 @@ const BPMPanel = observer(() => { }, []); return ( -
-
-
-
{t('common.offset')}
-
- -
-
-
- -
- -
-
+ + + + + + {t('common.offset')} + + + + + + + + + + + + + + + ); }); diff --git a/src/ui/Panel/BPMPanel/Item.tsx b/src/ui/Panel/BPMPanel/Item.tsx index 19ba578..2b7c5ba 100644 --- a/src/ui/Panel/BPMPanel/Item.tsx +++ b/src/ui/Panel/BPMPanel/Item.tsx @@ -4,7 +4,7 @@ import BeatInput from '@/ui/components/BeatInput'; import NumberInput from '@/ui/components/NumberInput'; import { useTranslation } from 'react-i18next'; import { BeatArray } from "@/utils/types"; -import { Button } from "@blueprintjs/core"; +import { Button, Grid, GridItem, Text } from "@chakra-ui/react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import { SnapshotIn } from 'mobx-state-tree'; @@ -29,37 +29,41 @@ const BPMListItem = observer<{ }; return ( -
-
-
-
{t('common.time')}
-
- handleUpdate(e)} - className='bpm-input-beat' - /> -
-
-
-
BPM
-
- handleUpdate((void 0), e)} - /> -
-
-
-
- -
-
+ + + BPM + + + handleUpdate((void 0), e)} + /> + + ) }); diff --git a/src/ui/Panel/BPMPanel/List.tsx b/src/ui/Panel/BPMPanel/List.tsx index 08813f0..5651cc8 100644 --- a/src/ui/Panel/BPMPanel/List.tsx +++ b/src/ui/Panel/BPMPanel/List.tsx @@ -2,6 +2,7 @@ import { observer } from "mobx-react-lite"; import BPMListItem from "./Item"; import { sortByBeat } from "@/utils/math"; import { IBPM } from "@/core/models/BPM"; +import { Stack, For, StackSeparator } from "@chakra-ui/react"; const BPMList = observer<{ bpms: IBPM[], @@ -11,14 +12,16 @@ const BPMList = observer<{ const bpmList = bpms.slice().sort(sortByBeat); return ( -
- {bpmList.map((bpm) => ( - - ))} -
+ } p="2"> + + {(bpm) => ( + + )} + + ); }); diff --git a/src/ui/Panel/BPMPanel/styles.css b/src/ui/Panel/BPMPanel/styles.css deleted file mode 100644 index 44a3dc7..0000000 --- a/src/ui/Panel/BPMPanel/styles.css +++ /dev/null @@ -1,57 +0,0 @@ -.bpm-panel { - display: flex; - width: 100%; - height: 100%; - overflow: hidden; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; -} - -.bpm-offset { - padding: 8px; - padding-bottom: 0; -} - -.bpm-list { - overflow-x: hidden; - overflow-y: auto; - flex: 1; -} - -.bpm-list-item { - display: flex; - padding: 8px; - border-bottom: 1px solid var(--border-primary-color); - box-sizing: border-box; - align-items: center; -} -.bpm-list-item:last-child { - border-bottom: unset; -} -.bpm-list-item .bpm-props { - flex: 1; -} - -.bpm-prop { - display: flex; - flex-direction: row; - align-items: center; - flex-wrap: nowrap; -} - -.bpm-prop .bpm-prop-name { - flex: 0.4; -} - -.bpm-prop .bpm-prop-input { - flex: 0.6; -} - -.bpm-offset .bpm-prop .bpm-prop-name { - flex: 0.354; -} - -.bpm-offset .bpm-prop .bpm-prop-input { - flex: 0.646; -} diff --git a/src/ui/Panel/PreviewPanel/Canvas.tsx b/src/ui/Panel/PreviewPanel/Canvas.tsx index ac243a6..ded8a14 100644 --- a/src/ui/Panel/PreviewPanel/Canvas.tsx +++ b/src/ui/Panel/PreviewPanel/Canvas.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef } from 'react'; import useResizeEffect from '@/ui/hooks/useResizeEffect'; import { app as previewApp } from '@/renderer/preview/app'; +import { Box } from '@chakra-ui/react'; const PreviewCanvas = () => { const containerRef = useRef(null); @@ -30,10 +31,9 @@ const PreviewCanvas = () => { }, containerRef); return ( -
+ > ); }; diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index d4a2776..2141f3a 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -1,4 +1,5 @@ import { useMemo } from 'react'; +import { Slider, Button, Stack, Center, HStack } from '@chakra-ui/react'; import { useRuntimeAudioStore } from '@/runtime/audio/state'; import Chart from '@/Chart/Chart'; import { useTempo } from '../../contexts/Tempo'; @@ -11,45 +12,47 @@ const PreviewController = () => { return ( <> -
- -
-
-
- - - - - -
-
+ + + + + + + + + +
+ + + + + + + +
+
); }; diff --git a/src/ui/Panel/PreviewPanel/PreviewPanel.tsx b/src/ui/Panel/PreviewPanel/PreviewPanel.tsx index 53946c6..020f9cf 100644 --- a/src/ui/Panel/PreviewPanel/PreviewPanel.tsx +++ b/src/ui/Panel/PreviewPanel/PreviewPanel.tsx @@ -1,17 +1,17 @@ import PreviewCanvas from './Canvas'; import PreviewController from './Controller'; -import './styles.css'; +import { Box, Stack } from '@chakra-ui/react'; const PreviewPanel = () => { return ( -
-
+ + -
-
+ + -
-
+ + ); }; diff --git a/src/ui/Panel/PreviewPanel/styles.css b/src/ui/Panel/PreviewPanel/styles.css deleted file mode 100644 index 871614d..0000000 --- a/src/ui/Panel/PreviewPanel/styles.css +++ /dev/null @@ -1,48 +0,0 @@ -.live-preview { - position: relative; - display: flex; - width: 100%; - height: 100%; - overflow: hidden; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; -} - -.live-preview .preview-canvas { - position: relative; - flex: 1; -} - -.live-preview .preview-canvas .canvas-container { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; -} - -.live-preview .preview-controller { - display: flex; - width: 100%; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; -} - -.preview-controller .control-actions { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - justify-content: space-between; -} - -.control-actions .control-group.control-group-center { - display: flex; - flex-direction: row; - justify-content: center; - flex-wrap: nowrap; - flex: 1; -} diff --git a/src/ui/components/BeatInput.tsx b/src/ui/components/BeatInput.tsx index aea8376..d3dc1c0 100644 --- a/src/ui/components/BeatInput.tsx +++ b/src/ui/components/BeatInput.tsx @@ -1,5 +1,6 @@ import { useRef, useCallback, useEffect } from 'react'; import Input from '@/ui/components/NumberInput'; +import { HStack } from '@chakra-ui/react'; import { normalizeBeatArray } from '@/utils/math'; import { BeatArray } from '@/utils/types'; @@ -49,7 +50,7 @@ const BeatInput = ({ }, [beat]); return ( -
+ handleChanged(0, e)} onInput={(e) => handleInput(0, e)} /> - : + : handleInput(1, e)} /> - / + / handleChanged(2, e)} onInput={(e) => handleInput(2, e)} /> -
+ ); }; diff --git a/src/ui/components/NumberInput.tsx b/src/ui/components/NumberInput.tsx index 1c2dda3..f4c7590 100644 --- a/src/ui/components/NumberInput.tsx +++ b/src/ui/components/NumberInput.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import useDrag from '../hooks/useDrag'; import { ChangeEventHandler, KeyboardEventHandler } from 'react'; import { Nullable } from '@/utils/types'; +import { NumberInput as NumInput } from '@chakra-ui/react'; const getDragStep = (min?: number, max?: number) => { if (min !== (void 0) && max !== (void 0)) return (max - min) / 1000; @@ -153,19 +154,22 @@ const NumberInput = ({ }, [defaultValue]); return ( - + + + + ) }; diff --git a/src/ui/index.tsx b/src/ui/index.tsx index 31bd70b..1ed927f 100644 --- a/src/ui/index.tsx +++ b/src/ui/index.tsx @@ -1,3 +1,4 @@ +import { Provider } from "@/components/ui/provider" import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import '@/i18n' @@ -6,6 +7,8 @@ import App from './App.tsx' createRoot(document.getElementById('root')!).render( - + + + , ) From bc3aaaf56a9008daee421c3a661d7a3307f8af2c Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sat, 6 Sep 2025 17:28:40 +0800 Subject: [PATCH 054/146] refactor(ui): Refactored Edit Panel --- src/ui/Panel/BPMPanel/BPMPanel.tsx | 2 +- src/ui/Panel/EditPanel/EditPanel.tsx | 14 +++++++----- src/ui/Panel/EditPanel/Input/Input.tsx | 4 +++- src/ui/Panel/EditPanel/Item/Beat.tsx | 2 +- src/ui/Panel/EditPanel/Item/Boolean.tsx | 19 ++++++++------- src/ui/Panel/EditPanel/Item/Container.tsx | 27 ++++++++++++---------- src/ui/Panel/EditPanel/Item/Dropdown.tsx | 28 +++++++++++++---------- src/ui/Panel/EditPanel/Item/Number.tsx | 18 +++++++++++---- src/ui/Panel/EditPanel/List.tsx | 6 ++--- src/ui/Panel/PreviewPanel/Controller.tsx | 25 +++++++++++++++----- 10 files changed, 90 insertions(+), 55 deletions(-) diff --git a/src/ui/Panel/BPMPanel/BPMPanel.tsx b/src/ui/Panel/BPMPanel/BPMPanel.tsx index 0e0d28d..4826b51 100644 --- a/src/ui/Panel/BPMPanel/BPMPanel.tsx +++ b/src/ui/Panel/BPMPanel/BPMPanel.tsx @@ -47,7 +47,7 @@ const BPMPanel = observer(() => { - + diff --git a/src/ui/Panel/EditPanel/EditPanel.tsx b/src/ui/Panel/EditPanel/EditPanel.tsx index cd0b5e3..d8a9487 100644 --- a/src/ui/Panel/EditPanel/EditPanel.tsx +++ b/src/ui/Panel/EditPanel/EditPanel.tsx @@ -5,10 +5,10 @@ import { useRuntimeStore } from '@/state/runtimeStore'; import { store as ChartStore } from '@/core/state/chartStore'; import List from './List'; import { KeyframePanelBuilderSingle, NotePanelBuilderSingle } from './builder'; +import { Box, Text, AbsoluteCenter } from '@chakra-ui/react'; import { Note } from '@/core/models/Note'; import { Keyframe } from '@/core/models/Keyframe'; import { UpdatedProps, UpdatedKeyframeProps, UpdatedNoteProps } from './types'; -import './styles.css'; // TODO: Multi-select const EditPanel = observer(() => { @@ -28,7 +28,7 @@ const EditPanel = observer(() => { }; return ( -
+ {( selectedNote ? ( { onChanged={handleValueChanged} /> ) : ( -
- {t('edit_panel.placeholder')} -
+ + + {t('edit_panel.placeholder')} + + ) )} -
+
) }); diff --git a/src/ui/Panel/EditPanel/Input/Input.tsx b/src/ui/Panel/EditPanel/Input/Input.tsx index b79ce2d..3884f90 100644 --- a/src/ui/Panel/EditPanel/Input/Input.tsx +++ b/src/ui/Panel/EditPanel/Input/Input.tsx @@ -1,5 +1,6 @@ import { Nullable } from "@/utils/types"; import { useCallback, useEffect, useRef, useState } from "react"; +import { Input } from "@chakra-ui/react"; type InputProps = { placeholder?: string, @@ -43,7 +44,8 @@ const EditPanelInput = ({ }, [defaultValue]); return ( - + ; @@ -9,18 +10,20 @@ const EditPanelBoolean = ({ onChanged, defaultValue, }: BooleanProps) => { - const handleInput = useCallback((e: React.ChangeEvent) => { - const target = e.target as HTMLInputElement; - onChanged(target.checked); + const handleInput = useCallback((e: { checked: string | boolean }) => { + onChanged(e.checked as boolean); }, [onChanged]); return ( - - + + onCheckedChange={handleInput} + my="2" + > + + + ); }; diff --git a/src/ui/Panel/EditPanel/Item/Container.tsx b/src/ui/Panel/EditPanel/Item/Container.tsx index a82d394..7d64c20 100644 --- a/src/ui/Panel/EditPanel/Item/Container.tsx +++ b/src/ui/Panel/EditPanel/Item/Container.tsx @@ -1,3 +1,5 @@ +import { Field, Grid, GridItem } from '@chakra-ui/react'; + type ItemContainerProps = { title: string, children: React.ReactNode, @@ -7,23 +9,24 @@ type ItemContainerProps = { const EditPanelItemContainer = ({ title, - children, - className, - useLabel, + children }: ItemContainerProps) => { const childrenDom = ( - <> -
{title}
-
{children}
- + + + {title} + + {children} + ); return ( - <> - {useLabel ? - : -
{childrenDom}
} - + {childrenDom} ); }; diff --git a/src/ui/Panel/EditPanel/Item/Dropdown.tsx b/src/ui/Panel/EditPanel/Item/Dropdown.tsx index 65a0d59..50f4c46 100644 --- a/src/ui/Panel/EditPanel/Item/Dropdown.tsx +++ b/src/ui/Panel/EditPanel/Item/Dropdown.tsx @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import Container from './Container'; import { PanelItemPropsBase } from '../types'; +import { NativeSelect } from "@chakra-ui/react" export type DropdownPropsBase = PanelItemPropsBase & { type?: 'string' | 'number', @@ -39,18 +40,21 @@ const EditPanelDropdown = ({ return ( - + + + {options.map((option) => { + return + })} + + + ); }; diff --git a/src/ui/Panel/EditPanel/Item/Number.tsx b/src/ui/Panel/EditPanel/Item/Number.tsx index 9f32c41..ec473c3 100644 --- a/src/ui/Panel/EditPanel/Item/Number.tsx +++ b/src/ui/Panel/EditPanel/Item/Number.tsx @@ -1,6 +1,6 @@ import Container from './Container'; import Input from '@/ui/components/NumberInput'; -import Slider from '../Input/Slider'; +import { Slider } from '@chakra-ui/react'; import { PanelItemPropsBase } from "../types"; export type NumberProps = PanelItemPropsBase & { @@ -36,13 +36,21 @@ const EditPanelNumber = ({ {min !== (void 0) && max !== (void 0) && useSlider ? ( <> - + defaultValue={[defaultValue ?? (min ?? 0)]} + onValueChange={(e) => onChanged(e.value[0])} + > + + + + + + + {inputDom} ) : inputDom} diff --git a/src/ui/Panel/EditPanel/List.tsx b/src/ui/Panel/EditPanel/List.tsx index 64c2bc9..b71c349 100644 --- a/src/ui/Panel/EditPanel/List.tsx +++ b/src/ui/Panel/EditPanel/List.tsx @@ -7,6 +7,7 @@ import { StringProps } from "./Item/String"; import InputBeat, { BeatProps } from "./Item/Beat"; import { BeatArray } from "@/utils/types"; import { UpdatedProps, UpdatedPropsKey } from "./types"; +import { Stack } from "@chakra-ui/react"; type PropsMovedDefault = 'label' | 'onChanged'; @@ -66,10 +67,9 @@ const EditPanelList = ({ }, [onChanged]); return ( -
+ {items.map((item) => { const itemKey = `${id}.${item.key}`; - if (item.type === 'beat') return ( handleValueChanged(item.key, e)} key={itemKey} /> ); @@ -84,7 +84,7 @@ const EditPanelList = ({ ); return null; })} -
+ ); }; diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index 2141f3a..d695b8c 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -4,9 +4,12 @@ import { useRuntimeAudioStore } from '@/runtime/audio/state'; import Chart from '@/Chart/Chart'; import { useTempo } from '../../contexts/Tempo'; import { GridValue } from '@/utils/math'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faPlay, faPause, faStepForward, faStepBackward, faFastBackward, faFastForward } from "@fortawesome/free-solid-svg-icons"; const PreviewController = () => { - const playClip = useRuntimeAudioStore((s) => s.play); + const currentStatus = useRuntimeAudioStore((s) => s.status); + const playClip = useRuntimeAudioStore((s) => s.status === 1 ? s.play : s.pause); const tempo = useTempo(); const tempoGrid = useMemo(() => 1 / tempo, [tempo]); @@ -28,28 +31,38 @@ const PreviewController = () => { if (!Chart.info) return; Chart.beatNum = GridValue(Chart.beatNum - 1, 1); }} - >Prev beat + > + + + > + + + > + + + > + + + > + + From c2db48ec24d58c19b3407986f4763d068651794f Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 18:08:23 +0800 Subject: [PATCH 055/146] feat(runtime): Add `unstorage` database layer --- package.json | 2 + pnpm-lock.yaml | 196 +++++++++++++++++++++ src/runtime/database/adatpers/indexeddb.ts | 5 + src/runtime/database/index.ts | 7 + 4 files changed, 210 insertions(+) create mode 100644 src/runtime/database/adatpers/indexeddb.ts create mode 100644 src/runtime/database/index.ts diff --git a/package.json b/package.json index 00fd0ff..79df4a0 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "i18next-chained-backend": "^4.6.2", "i18next-http-backend": "^3.0.2", "i18next-localstorage-backend": "^4.2.0", + "idb-keyval": "^6.2.2", "mobx-react-lite": "^4.1.0", "mobx-state-tree": "^7.0.2", "nanoid": "^5.1.5", @@ -46,6 +47,7 @@ "react-split-pane": "^0.1.92", "setimmediate": "^1.0.5", "spark-md5": "^3.0.2", + "unstorage": "^1.17.1", "uuid": "^11.0.4", "zustand": "^5.0.8" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 63c9dbf..866f644 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -67,6 +67,9 @@ importers: i18next-localstorage-backend: specifier: ^4.2.0 version: 4.2.0 + idb-keyval: + specifier: ^6.2.2 + version: 6.2.2 mobx-react-lite: specifier: ^4.1.0 version: 4.1.0(mobx@6.13.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -103,6 +106,9 @@ importers: spark-md5: specifier: ^3.0.2 version: 3.0.2 + unstorage: + specifier: ^1.17.1 + version: 1.17.1(idb-keyval@6.2.2) uuid: specifier: ^11.0.4 version: 11.0.4 @@ -824,6 +830,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -917,6 +927,10 @@ packages: change-case@4.1.2: resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -936,6 +950,9 @@ packages: constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + cross-fetch@4.0.0: resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} @@ -943,6 +960,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -978,6 +998,12 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + dockview-core@4.7.1: resolution: {integrity: sha512-Tia3vYHtqACMZTiZv86yQOabwKj5KrBhQqlSr7qXV0qmmRSZ8dNbaU63LIHYFprST7JgHupIm9JVES+OhqMoTQ==} @@ -1205,6 +1231,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + h3@1.15.4: + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -1261,6 +1290,9 @@ packages: typescript: optional: true + idb-keyval@6.2.2: + resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1280,6 +1312,9 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -1438,6 +1473,9 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1503,6 +1541,9 @@ packages: no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -1512,10 +1553,17 @@ packages: encoding: optional: true + node-mock-http@1.0.3: + resolution: {integrity: sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==} + node-wav@0.0.2: resolution: {integrity: sha512-M6Rm/bbG6De/gKGxOpeOobx/dnGuP0dz40adqx38boqHhlWssBJZgLCPBNtb9NkrmnKYiV04xELq+R6PFOnoLA==} engines: {node: '>=4.4.0'} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + normalize.css@8.0.1: resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==} @@ -1547,6 +1595,9 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + ofetch@1.4.1: + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + ogg-opus-decoder@1.6.14: resolution: {integrity: sha512-RQpk9yFl/mqXFwcgf1BrEYWL92HZk++aU1fOO8mPZ1+1DUYbJdpdUQEFfbPE1xcBkRGU3p75DjEO+EDMNeikFQ==} @@ -1639,6 +1690,9 @@ packages: resolution: {integrity: sha512-Pzd/4IFnTb8E+I1P5rbLQoqpUHcXKg48qTYKi4EANg+sTPwGFEMOcYGiiZz6xuQcOMZP7MPsrdAPx+16Q8qahg==} engines: {node: '>=18'} + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + react-dom@19.0.0: resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} peerDependencies: @@ -1712,6 +1766,10 @@ packages: resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -1915,16 +1973,84 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} undici-types@7.10.0: resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + unstorage@1.17.1: + resolution: {integrity: sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -2600,6 +2726,11 @@ snapshots: dependencies: color-convert: 2.0.1 + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + argparse@2.0.1: {} array-buffer-byte-length@1.0.2: @@ -2748,6 +2879,10 @@ snapshots: snake-case: 3.0.4 tslib: 2.6.3 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + classnames@2.5.1: {} codec-parser@2.5.0: {} @@ -2766,6 +2901,8 @@ snapshots: tslib: 2.6.3 upper-case: 2.0.2 + cookie-es@1.2.2: {} + cross-fetch@4.0.0: dependencies: node-fetch: 2.7.0 @@ -2778,6 +2915,10 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + csstype@3.1.3: {} data-view-buffer@1.0.2: @@ -2816,6 +2957,10 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.4: {} + + destr@2.0.5: {} + dockview-core@4.7.1: {} dockview@4.7.1(react@19.0.0): @@ -3178,6 +3323,18 @@ snapshots: graphemer@1.4.0: {} + h3@1.15.4: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.3 + radix3: 1.1.2 + ufo: 1.6.1 + uncrypto: 0.1.3 + has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -3235,6 +3392,8 @@ snapshots: optionalDependencies: typescript: 5.6.3 + idb-keyval@6.2.2: {} + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -3252,6 +3411,8 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + iron-webcrypto@1.2.1: {} + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -3424,6 +3585,8 @@ snapshots: dependencies: tslib: 2.6.3 + lru-cache@10.4.3: {} + math-intrinsics@1.1.0: {} memium@0.3.8: @@ -3480,12 +3643,18 @@ snapshots: lower-case: 2.0.2 tslib: 2.6.3 + node-fetch-native@1.6.7: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-mock-http@1.0.3: {} + node-wav@0.0.2: {} + normalize-path@3.0.0: {} + normalize.css@8.0.1: {} object-assign@4.1.1: {} @@ -3523,6 +3692,12 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + ofetch@1.4.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.1 + ogg-opus-decoder@1.6.14: dependencies: '@wasm-audio-decoders/common': 9.0.5 @@ -3627,6 +3802,8 @@ snapshots: quick-lru@7.1.0: {} + radix3@1.1.2: {} + react-dom@19.0.0(react@19.0.0): dependencies: react: 19.0.0 @@ -3698,6 +3875,8 @@ snapshots: process: 0.11.10 string_decoder: 1.3.0 + readdirp@4.1.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -3982,6 +4161,8 @@ snapshots: typescript@5.6.3: {} + ufo@1.6.1: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.3 @@ -3989,10 +4170,25 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + uncrypto@0.1.3: {} + undici-types@6.20.0: {} undici-types@7.10.0: {} + unstorage@1.17.1(idb-keyval@6.2.2): + dependencies: + anymatch: 3.1.3 + chokidar: 4.0.3 + destr: 2.0.5 + h3: 1.15.4 + lru-cache: 10.4.3 + node-fetch-native: 1.6.7 + ofetch: 1.4.1 + ufo: 1.6.1 + optionalDependencies: + idb-keyval: 6.2.2 + upper-case-first@2.0.2: dependencies: tslib: 2.6.3 diff --git a/src/runtime/database/adatpers/indexeddb.ts b/src/runtime/database/adatpers/indexeddb.ts new file mode 100644 index 0000000..1c0b90c --- /dev/null +++ b/src/runtime/database/adatpers/indexeddb.ts @@ -0,0 +1,5 @@ +import indexedDBDriver from 'unstorage/drivers/indexedb'; + +export const IndexedDB = () => { + return indexedDBDriver({ base: 'phifans-editor' }); +}; diff --git a/src/runtime/database/index.ts b/src/runtime/database/index.ts new file mode 100644 index 0000000..8e0be00 --- /dev/null +++ b/src/runtime/database/index.ts @@ -0,0 +1,7 @@ +import { createStorage } from 'unstorage'; +import { IndexedDB } from './adatpers/indexeddb'; + +// TODO: Native adapters +export const database = createStorage({ + driver: IndexedDB(), +}); From 09f62ad6c47aab68c32d34f5f2c07da7c2b6a6be Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 19:28:26 +0800 Subject: [PATCH 056/146] feat(runtime): Add a base skin loader --- package.json | 1 + pnpm-lock.yaml | 80 +++++++++++++++++++++++++++ src/runtime/resources/loader/audio.ts | 1 + src/runtime/resources/loader/image.ts | 1 + src/runtime/skin/consts.ts | 14 +++++ src/runtime/skin/importer.ts | 27 +++++++++ src/runtime/skin/types.ts | 7 +++ src/runtime/skin/utils.ts | 14 +++++ 8 files changed, 145 insertions(+) create mode 100644 src/runtime/skin/consts.ts create mode 100644 src/runtime/skin/importer.ts create mode 100644 src/runtime/skin/types.ts create mode 100644 src/runtime/skin/utils.ts diff --git a/package.json b/package.json index 79df4a0..e68916b 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "i18next-http-backend": "^3.0.2", "i18next-localstorage-backend": "^4.2.0", "idb-keyval": "^6.2.2", + "jszip": "^3.10.1", "mobx-react-lite": "^4.1.0", "mobx-state-tree": "^7.0.2", "nanoid": "^5.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 866f644..9e79846 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,6 +70,9 @@ importers: idb-keyval: specifier: ^6.2.2 version: 6.2.2 + jszip: + specifier: ^3.10.1 + version: 3.10.1 mobx-react-lite: specifier: ^4.1.0 version: 4.1.0(mobx@6.13.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -953,6 +956,9 @@ packages: cookie-es@1.2.2: resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cross-fetch@4.0.0: resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} @@ -1300,6 +1306,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -1308,6 +1317,9 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -1411,6 +1423,9 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -1449,6 +1464,9 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + kerium@1.3.6: resolution: {integrity: sha512-TEMYweNOPW79LOGV9G26biypM2q96s4iJYxcWMg3IxUzRUIFGFfWIxS7Yx2eREKfhLINcNNXGUa0OR6ONS9Dgg==} @@ -1459,6 +1477,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1620,6 +1641,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -1669,6 +1693,9 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -1762,6 +1789,9 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@4.7.0: resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1805,6 +1835,9 @@ packages: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -1902,6 +1935,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -2065,6 +2101,9 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utilium@2.5.4: resolution: {integrity: sha512-JeuMqv+yc2AGo0A3vVIiEwrYQcE/8SXftnvUq0HK0wnAmHtPCMZ/vln7nmNF9G63Qw9egijnTx3TxzdWZKYBmA==} engines: {node: '>=22.0.0'} @@ -2903,6 +2942,8 @@ snapshots: cookie-es@1.2.2: {} + core-util-is@1.0.3: {} + cross-fetch@4.0.0: dependencies: node-fetch: 2.7.0 @@ -3398,6 +3439,8 @@ snapshots: ignore@5.3.2: {} + immediate@3.0.6: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -3405,6 +3448,8 @@ snapshots: imurmurhash@0.1.4: {} + inherits@2.0.4: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -3517,6 +3562,8 @@ snapshots: call-bound: 1.0.3 get-intrinsic: 1.2.7 + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} @@ -3558,6 +3605,13 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + kerium@1.3.6: dependencies: utilium: 2.5.4 @@ -3571,6 +3625,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -3731,6 +3789,8 @@ snapshots: dependencies: p-limit: 3.1.0 + pako@1.0.11: {} + param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -3784,6 +3844,8 @@ snapshots: prelude-ls@1.2.1: {} + process-nextick-args@2.0.1: {} + process@0.11.10: {} prop-types@15.8.1: @@ -3867,6 +3929,16 @@ snapshots: react@19.0.0: {} + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@4.7.0: dependencies: abort-controller: 3.0.0 @@ -3946,6 +4018,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-push-apply@1.0.0: @@ -4084,6 +4158,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -4205,6 +4283,8 @@ snapshots: dependencies: react: 19.0.0 + util-deprecate@1.0.2: {} + utilium@2.5.4: dependencies: eventemitter3: 5.0.1 diff --git a/src/runtime/resources/loader/audio.ts b/src/runtime/resources/loader/audio.ts index e4af41c..a1613a8 100644 --- a/src/runtime/resources/loader/audio.ts +++ b/src/runtime/resources/loader/audio.ts @@ -6,6 +6,7 @@ export const loadAudio = (file: File | Blob, filename?: string) => new Promise { const _filename = (file as File).name ?? filename; + if (audioCache.has(_filename)) audioCache.delete(_filename); audioCache.set(_filename, clip); res(clip); }) diff --git a/src/runtime/resources/loader/image.ts b/src/runtime/resources/loader/image.ts index 62b1220..7bd0c24 100644 --- a/src/runtime/resources/loader/image.ts +++ b/src/runtime/resources/loader/image.ts @@ -7,6 +7,7 @@ export const loadImage = (file: Blob | File, filename?: string) => new Promise new Promise(async (res, rej) => { + const zip = await JSZip.loadAsync(zipFile); + + const metaFile = zip.file('skin.json'); + if (!metaFile) return rej('Not a valid skin file'); + + const metaString = await metaFile.async('string'); + if (!checkMetaValidation(metaString)) return rej('Not a valid skin file'); + + const metaJson = JSON.parse(metaString) as SkinMeta; + const pendingFiles = await Promise.all( + SkinFiles.map((filename) => { + const file = zip.file(filename); + if (!file) return null; + return file.async('blob').then(b => new File([b], `skin:${filename}`)); + }).filter(e => e !== null) + ); + + await loadFiles(pendingFiles); + res(metaJson); +}); diff --git a/src/runtime/skin/types.ts b/src/runtime/skin/types.ts new file mode 100644 index 0000000..7d48968 --- /dev/null +++ b/src/runtime/skin/types.ts @@ -0,0 +1,7 @@ + +export type SkinMeta = { + name: string, + author: string, + version: string, + homepage?: string, +}; diff --git a/src/runtime/skin/utils.ts b/src/runtime/skin/utils.ts new file mode 100644 index 0000000..87249ec --- /dev/null +++ b/src/runtime/skin/utils.ts @@ -0,0 +1,14 @@ +import { SkinMeta } from './types'; + +export const checkMetaValidation = (metaString: string) => { + try { + const json = JSON.parse(metaString) as SkinMeta; + return ( + json.name !== (void 0) && + json.author !== (void 0) && + json.version !== (void 0) + ); + } catch (_) { + return false; + } +}; From c8124480b02d9a8ee0a1ccd8824f478dcfd68bd9 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 19:48:51 +0800 Subject: [PATCH 057/146] feat(runtime/skin/importer): Save skin files to fs --- src/runtime/skin/importer.ts | 54 ++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index 9729ea5..8563d92 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -1,27 +1,47 @@ import JSZip from 'jszip'; +import * as fs from '@zenfs/core/promises'; import { loadFiles } from '../resources/loader'; import { checkMetaValidation } from './utils'; import { SkinFiles } from './consts'; import { SkinMeta } from './types'; -export const importFromZip = (zipFile: Blob | string) => new Promise(async (res, rej) => { - const zip = await JSZip.loadAsync(zipFile); +/** + * Import a skin from a zip file and save them to storage. + * @param zipFile {Blob | string} + * @returns {Promise} + */ +export const importFromZip = (zipFile: Blob | string): Promise => + new Promise(async (res, rej) => { + const zip = await JSZip.loadAsync(zipFile); - const metaFile = zip.file('skin.json'); - if (!metaFile) return rej('Not a valid skin file'); + const metaFile = zip.file('skin.json'); + if (!metaFile) return rej('Not a valid skin file'); - const metaString = await metaFile.async('string'); - if (!checkMetaValidation(metaString)) return rej('Not a valid skin file'); + const metaString = await metaFile.async('string'); + if (!checkMetaValidation(metaString)) return rej('Not a valid skin file'); - const metaJson = JSON.parse(metaString) as SkinMeta; - const pendingFiles = await Promise.all( - SkinFiles.map((filename) => { - const file = zip.file(filename); - if (!file) return null; - return file.async('blob').then(b => new File([b], `skin:${filename}`)); - }).filter(e => e !== null) - ); + const metaJson = JSON.parse(metaString) as SkinMeta; + const folderName = metaJson.name + .replace(/[\/\\?%*:|"<>]/g, '') + .replace(/[\x00-\x1F\x7F]/g, '') + .trim(); + if (!folderName) return rej('Invalid skin name'); + if (!(await fs.exists(`/skins/${folderName}`))) await fs.mkdir(`/skins/${folderName}`); - await loadFiles(pendingFiles); - res(metaJson); -}); + const pendingBuffers = await Promise.all( + SkinFiles.map((filename) => { + const file = zip.file(filename); + if (!file) return null; + return file.async('uint8array').then(b => ({ filename, buffer: b })); + }).filter(e => e !== null) + ); + + await loadFiles(pendingBuffers.map((e) => new File([e.buffer], e.filename))); + await Promise.all( + pendingBuffers.map((e) => ( + fs.writeFile(`/skins/${folderName}/${e.filename}`, e.buffer) + )) + ); + + res(metaJson); + }); From d5180825cc20d0de3f63ad70ecb5e0aed783bf43 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 19:57:18 +0800 Subject: [PATCH 058/146] refactor(runtime/skin/importer): Rename skin folder name --- src/runtime/skin/importer.ts | 8 +++----- src/runtime/skin/utils.ts | 6 ++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index 8563d92..92ccf7a 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -1,7 +1,7 @@ import JSZip from 'jszip'; import * as fs from '@zenfs/core/promises'; import { loadFiles } from '../resources/loader'; -import { checkMetaValidation } from './utils'; +import { checkMetaValidation, getSkinFolderName } from './utils'; import { SkinFiles } from './consts'; import { SkinMeta } from './types'; @@ -21,10 +21,8 @@ export const importFromZip = (zipFile: Blob | string): Promise => if (!checkMetaValidation(metaString)) return rej('Not a valid skin file'); const metaJson = JSON.parse(metaString) as SkinMeta; - const folderName = metaJson.name - .replace(/[\/\\?%*:|"<>]/g, '') - .replace(/[\x00-\x1F\x7F]/g, '') - .trim(); + const folderName = getSkinFolderName(metaJson); + if (!folderName) return rej('Invalid skin name'); if (!(await fs.exists(`/skins/${folderName}`))) await fs.mkdir(`/skins/${folderName}`); diff --git a/src/runtime/skin/utils.ts b/src/runtime/skin/utils.ts index 87249ec..742f763 100644 --- a/src/runtime/skin/utils.ts +++ b/src/runtime/skin/utils.ts @@ -12,3 +12,9 @@ export const checkMetaValidation = (metaString: string) => { return false; } }; + +export const getSkinFolderName = (meta: SkinMeta) => + `${meta.author} - ${meta.name}` + .replace(/[\/\\?%*:|"<>]/g, '') + .replace(/[\x00-\x1F\x7F]/g, '') + .trim(); From f796fca0e55489b9347c59185b3d60b3e26b94fe Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 20:16:11 +0800 Subject: [PATCH 059/146] fix(runtime/skin/importer): Fix type issue --- src/runtime/skin/importer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index 92ccf7a..ef22706 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -30,14 +30,14 @@ export const importFromZip = (zipFile: Blob | string): Promise => SkinFiles.map((filename) => { const file = zip.file(filename); if (!file) return null; - return file.async('uint8array').then(b => ({ filename, buffer: b })); + return file.async('arraybuffer').then(b => ({ filename, buffer: b })); }).filter(e => e !== null) ); await loadFiles(pendingBuffers.map((e) => new File([e.buffer], e.filename))); await Promise.all( pendingBuffers.map((e) => ( - fs.writeFile(`/skins/${folderName}/${e.filename}`, e.buffer) + fs.writeFile(`/skins/${folderName}/${e.filename}`, new Uint8Array(e.buffer)) )) ); From 480aea1f59784ceeb888bee0a271aedf8e98aaae Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 20:44:13 +0800 Subject: [PATCH 060/146] feat(runtime/skin/importer): Save skin info to database --- src/runtime/skin/importer.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index ef22706..13582f8 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -1,5 +1,6 @@ import JSZip from 'jszip'; import * as fs from '@zenfs/core/promises'; +import { db } from '../database'; import { loadFiles } from '../resources/loader'; import { checkMetaValidation, getSkinFolderName } from './utils'; import { SkinFiles } from './consts'; @@ -22,9 +23,7 @@ export const importFromZip = (zipFile: Blob | string): Promise => const metaJson = JSON.parse(metaString) as SkinMeta; const folderName = getSkinFolderName(metaJson); - if (!folderName) return rej('Invalid skin name'); - if (!(await fs.exists(`/skins/${folderName}`))) await fs.mkdir(`/skins/${folderName}`); const pendingBuffers = await Promise.all( SkinFiles.map((filename) => { @@ -33,6 +32,10 @@ export const importFromZip = (zipFile: Blob | string): Promise => return file.async('arraybuffer').then(b => ({ filename, buffer: b })); }).filter(e => e !== null) ); + if (pendingBuffers.length <= 0) return rej('No skin file(s) found'); + + if (!(await fs.exists(`/skins/${folderName}`))) await fs.mkdir(`/skins/${folderName}`); + if (!(await db.has('skins'))) await db.setItem('skins', []); await loadFiles(pendingBuffers.map((e) => new File([e.buffer], e.filename))); await Promise.all( @@ -41,5 +44,13 @@ export const importFromZip = (zipFile: Blob | string): Promise => )) ); + const skinsList = (await db.get('skins'))!; + const oldIndex = skinsList.findIndex(e => e.name === metaJson.name && e.author === metaJson.author); + if (oldIndex >= 0) + Object.assign(skinsList[oldIndex], metaJson); + else + skinsList.push(metaJson); + await db.set('skins', skinsList); + res(metaJson); }); From 6cb3351bf071942d6142c5547ac136d3b4fc4765 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 20:44:59 +0800 Subject: [PATCH 061/146] refactor(runtime/database): Tweak code --- src/runtime/database/adatpers/indexeddb.ts | 8 +++++--- src/runtime/database/index.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/runtime/database/adatpers/indexeddb.ts b/src/runtime/database/adatpers/indexeddb.ts index 1c0b90c..d2d8d8f 100644 --- a/src/runtime/database/adatpers/indexeddb.ts +++ b/src/runtime/database/adatpers/indexeddb.ts @@ -1,5 +1,7 @@ import indexedDBDriver from 'unstorage/drivers/indexedb'; -export const IndexedDB = () => { - return indexedDBDriver({ base: 'phifans-editor' }); -}; +export const IndexedDB = () => + indexedDBDriver({ + dbName: 'phifans-editor-database', + storeName: 'database', + }); diff --git a/src/runtime/database/index.ts b/src/runtime/database/index.ts index 8e0be00..63d3c44 100644 --- a/src/runtime/database/index.ts +++ b/src/runtime/database/index.ts @@ -1,7 +1,14 @@ import { createStorage } from 'unstorage'; import { IndexedDB } from './adatpers/indexeddb'; +import { SkinMeta } from '../skin/types'; + +type DatabaseStructure = { + items: { + skins: SkinMeta[], + } +}; // TODO: Native adapters -export const database = createStorage({ +export const db = createStorage({ driver: IndexedDB(), }); From a38a47e7f863193196a2e92142e66c36e670aec8 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 20:55:49 +0800 Subject: [PATCH 062/146] feat(runtime): Add initializer --- public/skin-default.zip | Bin 0 -> 187032 bytes public/skin/note-drag-highlight.png | Bin 24750 -> 0 bytes public/skin/note-drag.png | Bin 2151 -> 0 bytes public/skin/note-flick-highlight.png | Bin 51672 -> 0 bytes public/skin/note-flick.png | Bin 7346 -> 0 bytes public/skin/note-hold-body-highlight.png | Bin 185821 -> 0 bytes public/skin/note-hold-body.png | Bin 406251 -> 0 bytes public/skin/note-hold-end.png | Bin 1366 -> 0 bytes public/skin/note-hold-head-highlight.png | Bin 13447 -> 0 bytes public/skin/note-hold-head.png | Bin 11283 -> 0 bytes public/skin/note-tap-highlight.png | Bin 29702 -> 0 bytes public/skin/note-tap.png | Bin 3413 -> 0 bytes public/skin/skin-bundle.json | 49 ----------------------- src/main.ts | 4 ++ src/runtime/init.ts | 13 ++++++ 15 files changed, 17 insertions(+), 49 deletions(-) create mode 100644 public/skin-default.zip delete mode 100644 public/skin/note-drag-highlight.png delete mode 100644 public/skin/note-drag.png delete mode 100644 public/skin/note-flick-highlight.png delete mode 100644 public/skin/note-flick.png delete mode 100644 public/skin/note-hold-body-highlight.png delete mode 100644 public/skin/note-hold-body.png delete mode 100644 public/skin/note-hold-end.png delete mode 100644 public/skin/note-hold-head-highlight.png delete mode 100644 public/skin/note-hold-head.png delete mode 100644 public/skin/note-tap-highlight.png delete mode 100644 public/skin/note-tap.png delete mode 100644 public/skin/skin-bundle.json create mode 100644 src/runtime/init.ts diff --git a/public/skin-default.zip b/public/skin-default.zip new file mode 100644 index 0000000000000000000000000000000000000000..d05fee01ec38fbed9f554d6fba66c36dda3f3e10 GIT binary patch literal 187032 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
VHB0~tKo3|ZiOWOJ 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 z%0A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 PK!jxNMEu?AOw9iRV%-Bz diff --git a/public/skin/note-drag.png b/public/skin/note-drag.png deleted file mode 100644 index ffa0e067ec70e5e60ab9a55128eb50ee84e75676..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2151 zcmX|CdpKKp8a`dC=?<#xGcGNv`zWU4L0vma*rLRkXzS7}t)OmoSxT%3LT5W=I$EYR z8k;oCjFQSIEk#XSTA`K(>n@rUEpcfQBtb$F`#WLwk6h0AzVp8C_kQ2`es?bVd24-k z>@x_0w0uyW{t%?b1^-<8aju51_Zvk&L*?GDur7%qW}KgXU!pM#+1MH=!5b#VQc z8>nC$1RZ3;pM5>aPof|QA@}h-7np$+a2ZKgCv_@ z!8`TPiSy~!e5zAP9eLR`p?Gb3y>x3Cbln! zk@Kv{eP)C_$qh7~yiD&XyQs+ZQISpj5Nt!~s5&xzS&0u|j}QKMymof8KPP~lOVOtA z#Wc~T7a)6JABsS;?y@xT6nsNY;*7TV%;#5>QQinu?_4uRR?AeBnmCL?kO__O; z)jTC95Th`@URY;>0^wmRy@p7~B6M`2o8EgV&}twJ6_;1lOC6NPWSEDb5=*yGMtv3Y zpF}gt*Xxz>25ugi8EPi{xpV>zcdF=6zk zA-l)<6Z+BScsz+_scZhW%^Xh}JiY^Z8y;zc>B=68z{yh^xBMF$%m0dOeRIIMh0*FF zn3G0qb%OTSSnvw`etXYF_LLv4TL<3jc(HrAv-5GZw+hq8Htw8MZ=Vx)--eP77HV3V~g} z8X!TLyV8xnTRG)hm$U|45*Ghs+1%N5Mv6A5Q;=E7Qn78b!&n8%SMqq0Q%$c-KFz%jcLG2abiYnr>7`0kc}H+4 zmWdIjjgeKD>`~{!?9To6bf=&2zw`5PLu*5~By4@-Uj`!bh{V->~@9x`_9^AjdnUnsyna``%U1{lE8 z75gj%tq99LUKv&;z=}a-L$4dQm$aQB=oROhD?yu%bwKtI!`-?N-M0cUZON8tM6K!e zUko5<(UWDqa&F86&#E4yYH^?2F*1X%@RhZkX5H*ILkODL|Gv16)KfzSukrUXd){c@ zK-p|RqA>OTlpdPag3^K@=}y)KEC219-kA34?6E-nhGw$s=~~+&i+&4A( z%$A>M^;Fq$(87WlvoqsfZXc@ayBK+txN%Dxf-YL}?w9(WwTc-oA}5Yh+*uWFjwNmD znxq}|4;C|HK`U1@xLA66w&a9j7C5uphMiy$KR1N9#`KWe5cs3DHJQ^PiyQup-5
L?0-7hQ%mN3mIYgLDEi(nh|*1kfWRJ%W7YMxQT$zW8y2Z8)6b!JkXI z?3y({b5%aowv~lgOV|Ycg4M#4d>$n3PBP0+7&9-%9JJDp2K(fUdTWltcYC&@QDh5J z_TC33e{SG${(={q%LSqaH#_{W2f#orb#aDLJOpq|?`}PV@z!??+qUIIJO!StI)d}2 zX*Cx+7azykb_&6C1UXM`+Y)U+tVu`g)$>QJPbjpq4$6WT!aRuWE`&Kh;WuEX07dyE zy5&Q}ppa$_7++Og8~C13F_OpWrTS>sod&q@vnir4h(6$1M;)9OO^c!8jQEMmH3G%{ z&H-afyab}-I^y#R>ZE~#1P0HzcQ_r7Csa?tqaO_{{yT=HM|IqbT>>$D_0+YLdQMjA z86rF>Nni4QD78MDD5Y}#Em<{!y_l_xR~;KsE1cN2N~`qLSg`T+BY=%0I(%9T-xPGI zxYQ~@n^yfD;G4(jR5q+W`TBQUZYY*+2H#X`v~zB;Tbe!QH3@pO2a9rUgiEP~OR)+n z24}0Qb*LAnASK=l8h`XRn$mhJDXRUkqzy1eqCQDBM diff --git a/public/skin/note-flick-highlight.png b/public/skin/note-flick-highlight.png deleted file mode 100644 index 978699322f0dc0f79d9bbc840f0b32d8a2f5db88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51672 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%0D7t%-4Jp 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 diff --git a/public/skin/note-flick.png b/public/skin/note-flick.png deleted file mode 100644 index 323a3ba8977c1ff625d39de178b6a68e4a706824..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7346 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

=X68eODW%Hcp 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𝔱n_*RF(#J&|-NErZ&L3-aZ3&A1OxO)ru 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 !=(*>_jD@A#A|_}+{@8}PntGS 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Ġ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 z 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 diff --git a/public/skin/note-hold-end.png b/public/skin/note-hold-end.png deleted file mode 100644 index d947abad8ac6350f8a9341f9e992427c58cba383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1366 zcmYjRdpMM76rUdC?xB&v2w_PsYuhv^w=rT|hK6SC!zdAHnTeT+$z^jbmq{*dVUWAZ zC2A|*Oe+lolajt=hZ$7^A&gHqNXN2{B zwji)CrEGH4@LKnDTz5lhyJnqTe$3S}a3FSVf+Ovw5f1ekwB4(cw!?*4su9I09@y*2 z(I11tTafk=UkYd(97GB+5&snjehbn{sdYYvNqP!BiVKu@z(9n%D^XX_VgmX|K4IX(U4QGpG^KZ7KrKkrWXfOZB)Zv2v5bfvwi774NcliVITg}s<{J`E z@Dgj~z%0KR_AG!FvTQ(PJ!d(GjU-D3ccS{x#{fSzG-ei0po5x=0h&~tICLM_`<<;L z@YbZtik)acUKQVdlo7xkcIC$1fR?_qJw6}JhvXYMYg<~FUa1BTy%&(M#;nd6iEyun zJ_)|53+%ieKKTwexFs6n68yw}*ljhX&zV{ZaLkS4RpyjNxRjLu@s+WUxSPk zziA{EL3g*X@M0hgN$^(QQ^LuM_$TkaeEAH^cdk#9_V!!0aPM?89c6E`ioc*1HQ0_9 zJR(U76d2)uj*x5xO#@ud9(+nC!f0*!S*YMqAO`!ArGH{TxOu01L50N_;(GEr3`Mn} znSAv1r9M*zF9e820&4Ll+%fXZ^uAc(oKjiLPo^H1N^8JFaA$a-oAZ}h%2|1jwQ^+>Y77x$ zmmj;Q<>_Q#3s?R<>WdfE5JYktUP?)7T*b)pPpLGkEKD-M;>3qbI+B1=nJXRkvpix-GT!0S(1{ zk@x#<;-~avNY|K!8TzODnF`51uM6jxJHwVz$ph%}mn@x-FVZwM4{|7EU1a0vn*b)8 zhNe~Z0%676_CN{k22h=Ja)0ENi8ZSPRJ8W_1|8ASdXeV?qMzNnsSrbEcs(UA0F&?a zuuHk&*nCO^{H(Ik9R;;t_f6h@pWPY7_ z)nY5Nr(b&d2dd@EAs0qQNoVh`EtC(Ck@A5e|EKFkv}I#|K?omiQ?>Hc5#sB?Je-PS z)$URUJ%b)o=KBzEv2boDD^;bnX%lDFA&hE{HY@8kS2tgj(3oy>PD>afC?q$-D|**j zEUWjKYJHX4jt7PI$4gPAleUa1XG`jlib{v$lI!|4H7hj%5+2n$aaBGOS{(3sCAtcK Oa0t9R0oRH>nf@Qyy~h0j diff --git a/public/skin/note-hold-head-highlight.png b/public/skin/note-hold-head-highlight.png deleted file mode 100644 index 3210e6c3775c13ddc60f17d784e12152c4936f68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13447 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 diff --git a/public/skin/note-tap-highlight.png b/public/skin/note-tap-highlight.png deleted file mode 100644 index ee94efbc8519e2454412a7495e43763ad63d3f58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29702 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 l39DV+MzR9;zbl`an|;pOXPvVTbOH|Nw& diff --git a/public/skin/skin-bundle.json b/public/skin/skin-bundle.json deleted file mode 100644 index c29e4f8..0000000 --- a/public/skin/skin-bundle.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "skin-default", - "assets": [ - { - "alias": "note-tap", - "src": "skin/note-tap.png" - }, - { - "alias": "note-tap-highlight", - "src": "skin/note-tap-highlight.png" - }, - { - "alias": "note-drag", - "src": "skin/note-drag.png" - }, - { - "alias": "note-drag-highlight", - "src": "skin/note-drag-highlight.png" - }, - { - "alias": "note-hold-head", - "src": "skin/note-hold-head.png" - }, - { - "alias": "note-hold-head-highlight", - "src": "skin/note-hold-head-highlight.png" - }, - { - "alias": "note-hold-body", - "src": "skin/note-hold-body.png" - }, - { - "alias": "note-hold-body-highlight", - "src": "skin/note-hold-body-highlight.png" - }, - { - "alias": "note-hold-end", - "src": "skin/note-hold-end.png" - }, - { - "alias": "note-flick", - "src": "skin/note-flick.png" - }, - { - "alias": "note-flick-highlight", - "src": "skin/note-flick-highlight.png" - } - ] -} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index dd223d6..d47d383 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,8 @@ // import './App/App'; import 'setimmediate'; // TODO: This is a workaround for upstream @phifans/audio import '@/storage/init'; +import { runtimeInit } from './runtime/init'; + +await runtimeInit(); + import './ui'; diff --git a/src/runtime/init.ts b/src/runtime/init.ts new file mode 100644 index 0000000..e5a403f --- /dev/null +++ b/src/runtime/init.ts @@ -0,0 +1,13 @@ +import { db } from './database'; +import { importFromZip } from './skin/importer'; + +export const runtimeInit = () => new Promise(async (res) => { + // Init skins + const skins = await db.get('skins'); + if (!skins || skins.length <= 0) + await fetch('./skin-default.zip') + .then(e => e.blob()) + .then((e) => importFromZip(e)); + + res(); +}); From d17d92561b90f0c969c6b9cce48f7e797481bf9c Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 20:56:11 +0800 Subject: [PATCH 063/146] fix(runtime/skin/importer): Fix input type --- src/runtime/skin/importer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index 13582f8..c4f88d8 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -11,7 +11,7 @@ import { SkinMeta } from './types'; * @param zipFile {Blob | string} * @returns {Promise} */ -export const importFromZip = (zipFile: Blob | string): Promise => +export const importFromZip = (zipFile: Blob): Promise => new Promise(async (res, rej) => { const zip = await JSZip.loadAsync(zipFile); From 228e434c54443e95052e33fbd1bb8b5a09e77c62 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 21:27:23 +0800 Subject: [PATCH 064/146] feat(runtime/skin): Add skin loader --- src/runtime/init.ts | 3 +++ src/runtime/skin/loader.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/runtime/skin/loader.ts diff --git a/src/runtime/init.ts b/src/runtime/init.ts index e5a403f..ed2f36b 100644 --- a/src/runtime/init.ts +++ b/src/runtime/init.ts @@ -1,4 +1,5 @@ import { db } from './database'; +import { loadSkin } from './skin/loader'; import { importFromZip } from './skin/importer'; export const runtimeInit = () => new Promise(async (res) => { @@ -8,6 +9,8 @@ export const runtimeInit = () => new Promise(async (res) => { await fetch('./skin-default.zip') .then(e => e.blob()) .then((e) => importFromZip(e)); + else + await loadSkin(skins[0].name, skins[0].author); res(); }); diff --git a/src/runtime/skin/loader.ts b/src/runtime/skin/loader.ts new file mode 100644 index 0000000..f960b8c --- /dev/null +++ b/src/runtime/skin/loader.ts @@ -0,0 +1,30 @@ +import * as fs from '@zenfs/core/promises'; +import { db } from '../database'; +import { loadFiles } from '../resources/loader'; +import { getSkinFolderName } from './utils'; +import { SkinFiles } from './consts'; +import { SkinMeta } from './types'; + +/** + * Load imported skin + * @param name + * @param author + */ +export const loadSkin = (name: string, author?: string) => new Promise(async (res, rej) => { + const skins = await db.get('skins'); + if (!skins || skins.length <= 0) return rej('No skin stored'); + + const skinIndex = skins.findIndex(e => e.name === name && (author === (void 0) || e.author === author)); + if (skinIndex === -1) return rej('No such skin found'); + + const folderName = getSkinFolderName(skins[skinIndex]); + const pendingBuffers = await Promise.all( + SkinFiles.map((filename) => + fs.readFile(`/skins/${folderName}/${filename}`) + .then((b) => ({ filename, buffer: b })) + ) + ); + + await loadFiles(pendingBuffers.map((e) => new File([e.buffer as unknown as ArrayBuffer], `skin:${e.filename}`))); + res(skins[skinIndex]); +}); From c479dbd8a872b3d37f72b3228d358dc0f2251258 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 21:27:44 +0800 Subject: [PATCH 065/146] feat(ui/Panel/NotePanel): Use skins from loaded cache --- .../NotePanel/NoteContainer/NoteGraphics.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx index ad0f05c..237592c 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx @@ -4,6 +4,7 @@ import { Container, EventMode, Sprite, Texture } from 'pixi.js'; import { observer } from 'mobx-react-lite'; import { useRuntimeStore } from '@/state/runtimeStore'; import { useRuntimeAudioBeat } from '@/runtime/audio/state'; +import { imageCache } from '@/runtime/resources/cache'; import { NoteType } from '@/core/types'; import useDrag from '@/ui/hooks/useDrag'; import { useTempo } from '@/ui/contexts/Tempo'; @@ -16,10 +17,10 @@ import { SnapshotIn } from 'mobx-state-tree'; const NOTE_SCALE = 5000; -const getNoteTexture = (type: NoteType) => { - if (type === NoteType.Hold) return 'note-drag'; - else if (type === NoteType.Flick) return 'note-flick'; - else return 'note-tap'; +const getNoteTexture = (type: NoteType, withHL: boolean = false) => { + if (type === NoteType.Drag) return imageCache.get(`skin:Drag${withHL ? 'HL' : ''}.png`); + else if (type === NoteType.Flick) return imageCache.get(`skin:Flick${withHL ? 'HL' : ''}.png`); + else return imageCache.get(`skin:Tap${withHL ? 'HL' : ''}.png`); }; const calculateNewTime = ( @@ -148,25 +149,25 @@ const Note = observer<{ return (<> {note.type !== NoteType.Hold ? ( ): ( From 92e08c25ab09c4d77cb0dd60b075df9be7aa841c Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sat, 6 Sep 2025 21:28:49 +0800 Subject: [PATCH 066/146] feat(runtime/skin/importer): Load after import --- src/runtime/skin/importer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index c4f88d8..63c1d8b 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -11,7 +11,7 @@ import { SkinMeta } from './types'; * @param zipFile {Blob | string} * @returns {Promise} */ -export const importFromZip = (zipFile: Blob): Promise => +export const importFromZip = (zipFile: Blob, loadAfterImport = true): Promise => new Promise(async (res, rej) => { const zip = await JSZip.loadAsync(zipFile); @@ -37,12 +37,12 @@ export const importFromZip = (zipFile: Blob): Promise => if (!(await fs.exists(`/skins/${folderName}`))) await fs.mkdir(`/skins/${folderName}`); if (!(await db.has('skins'))) await db.setItem('skins', []); - await loadFiles(pendingBuffers.map((e) => new File([e.buffer], e.filename))); await Promise.all( pendingBuffers.map((e) => ( fs.writeFile(`/skins/${folderName}/${e.filename}`, new Uint8Array(e.buffer)) )) ); + if (loadAfterImport) await loadFiles(pendingBuffers.map((e) => new File([e.buffer], e.filename))); const skinsList = (await db.get('skins'))!; const oldIndex = skinsList.findIndex(e => e.name === metaJson.name && e.author === metaJson.author); From a67c683eb3f5e84d05fddc1cd9300807fb070086 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 05:22:00 +0800 Subject: [PATCH 067/146] refactor(ui): Refactored Settings Panel & Polish --- src/ui/Panel/EditPanel/Item/Combobox.tsx | 83 ++++++++++++++++++++ src/ui/Panel/EditPanel/Item/Select.tsx | 80 +++++++++++++++++++ src/ui/Panel/EditPanel/List.tsx | 22 +++++- src/ui/Panel/EditPanel/builder.ts | 4 +- src/ui/Panel/EditPanel/styles.css | 55 ------------- src/ui/Panel/SettingsPanel/Item.tsx | 30 ++----- src/ui/Panel/SettingsPanel/Rendering.tsx | 34 ++++---- src/ui/Panel/SettingsPanel/SettingsPanel.tsx | 22 +++--- src/ui/Panel/SettingsPanel/styles.css | 11 --- 9 files changed, 223 insertions(+), 118 deletions(-) create mode 100644 src/ui/Panel/EditPanel/Item/Combobox.tsx create mode 100644 src/ui/Panel/EditPanel/Item/Select.tsx delete mode 100644 src/ui/Panel/EditPanel/styles.css delete mode 100644 src/ui/Panel/SettingsPanel/styles.css diff --git a/src/ui/Panel/EditPanel/Item/Combobox.tsx b/src/ui/Panel/EditPanel/Item/Combobox.tsx new file mode 100644 index 0000000..d80ae80 --- /dev/null +++ b/src/ui/Panel/EditPanel/Item/Combobox.tsx @@ -0,0 +1,83 @@ +import Container from './Container'; +import { PanelItemPropsBase } from '../types'; +import { Portal, Combobox, useFilter, useListCollection, createListCollection } from "@chakra-ui/react" + +export type ComboboxPropsBase = PanelItemPropsBase & { + type?: 'string' | 'number', + options: { + value: string | number, + label: string, + disabled?: boolean, + }[], +}; + +export type ComboboxPropsNumber = ComboboxPropsBase & { + type: 'number', + onChanged: (newValue: number) => void, + options: { + value: number, + label: string, + disabled?: boolean, + }[], + defaultValue?: number, +}; + +export type ComboboxProps = ComboboxPropsBase | ComboboxPropsNumber; + +const EditPanelCombobox = ({ + label, + options, + type = 'string', + onChanged, + defaultValue, +}: ComboboxProps) => { + const { contains } = useFilter({ sensitivity: "base" }) + const { collection, filter } = useListCollection({ + initialItems: options, + filter: contains, + }) + + const handleValueChanged = (e: string) => { + if (type === 'number') { + const newValue = parseFloat(e); + if (isNaN(newValue)) return; + onChanged(newValue); + } else { + onChanged(e); + } + }; + + return ( + + handleValueChanged(e.value[0])} + defaultValue={[defaultValue as string]} + onInputValueChange={(e) => filter(e.inputValue)} + > + + + + + + + + + + No items found + {collection.items.map((item: any) => ( + + {item.label} + + + ))} + + + + + + ); +}; + +export default EditPanelCombobox; diff --git a/src/ui/Panel/EditPanel/Item/Select.tsx b/src/ui/Panel/EditPanel/Item/Select.tsx new file mode 100644 index 0000000..38866e4 --- /dev/null +++ b/src/ui/Panel/EditPanel/Item/Select.tsx @@ -0,0 +1,80 @@ +import Container from './Container'; +import { PanelItemPropsBase } from '../types'; +import { Portal, Select, createListCollection } from "@chakra-ui/react" + +export type SelectPropsBase = PanelItemPropsBase & { + type?: 'string' | 'number', + options: { + value: string | number, + label: string, + disabled?: boolean, + }[], +}; + +export type SelectPropsNumber = SelectPropsBase & { + type: 'number', + onChanged: (newValue: number) => void, + options: { + value: number, + label: string, + disabled?: boolean, + }[], + defaultValue?: number, +}; + +export type SelectProps = SelectPropsBase | SelectPropsNumber; + +const EditPanelSelect = ({ + label, + options, + type = 'string', + onChanged, + defaultValue, +}: SelectProps) => { + const editOptions = createListCollection({items: options}) + + const handleValueChanged = (e: string) => { + if (type === 'number') { + const newValue = parseFloat(e); + if (isNaN(newValue)) return; + onChanged(newValue); + } else { + onChanged(e); + } + }; + + return ( + + handleValueChanged(e.value[0])} + defaultValue={[defaultValue as string]} + > + + + + + + + + + + + + + {editOptions.items.map((editOption: any) => ( + + {editOption.label} + + + ))} + + + + + + ); +}; + +export default EditPanelSelect; diff --git a/src/ui/Panel/EditPanel/List.tsx b/src/ui/Panel/EditPanel/List.tsx index b71c349..49cf575 100644 --- a/src/ui/Panel/EditPanel/List.tsx +++ b/src/ui/Panel/EditPanel/List.tsx @@ -2,6 +2,8 @@ import { useCallback } from "react"; import { useTranslation } from "react-i18next"; import InputBoolean, { BooleanProps } from "./Item/Boolean"; import InputDropdown, { DropdownProps } from "./Item/Dropdown"; +import InputSelect, { SelectProps } from "./Item/Select"; +import InputCombobox, { ComboboxProps } from "./Item/Combobox"; import InputNumber, { NumberProps } from "./Item/Number"; import { StringProps } from "./Item/String"; import InputBeat, { BeatProps } from "./Item/Beat"; @@ -14,7 +16,7 @@ type PropsMovedDefault = 'label' | 'onChanged'; type EditPanelItemBase = { key: UpdatedPropsKey, label: string, - type: 'number' | 'string' | 'boolean' | 'dropdown' | 'beat', + type: 'number' | 'string' | 'boolean' | 'dropdown' | 'select' | 'combobox' | 'beat', i18n: string, }; @@ -38,12 +40,22 @@ type EditPanelItemDropdown = EditPanelItemBase & { props: Omit, }; +type EditPanelItemSelect = EditPanelItemBase & { + type:'select', + props: Omit, +}; + +type EditPanelItemCombobox = EditPanelItemBase & { + type: 'combobox', + props: Omit, +}; + type EditPanelItemBeat = EditPanelItemBase & { type: 'beat', props: Omit, }; -export type EditPanelItem = EditPanelItemNumber | EditPanelItemString | EditPanelItemBoolean | EditPanelItemDropdown | EditPanelItemBeat; +export type EditPanelItem = EditPanelItemNumber | EditPanelItemString | EditPanelItemBoolean | EditPanelItemDropdown | EditPanelItemSelect | EditPanelItemCombobox | EditPanelItemBeat; type EditPanelListProps = { id: string, @@ -82,6 +94,12 @@ const EditPanelList = ({ if (item.type === 'dropdown') return ( handleValueChanged(item.key, e)} key={itemKey} /> ); + if (item.type === 'select') return ( + handleValueChanged(item.key, e)} key={itemKey} /> + ); + if (item.type === 'combobox') return ( + handleValueChanged(item.key, e)} key={itemKey} /> + ); return null; })} diff --git a/src/ui/Panel/EditPanel/builder.ts b/src/ui/Panel/EditPanel/builder.ts index b2614fe..14d0373 100644 --- a/src/ui/Panel/EditPanel/builder.ts +++ b/src/ui/Panel/EditPanel/builder.ts @@ -47,7 +47,7 @@ export const KeyframePanelBuilderSingle = (keyframe: IKeyframe): EditPanelItem[] if (keyframe.type !== KeyframeType.Speed) result.push({ label: 'Easing', i18n: 'keyframe.easing', - type: 'dropdown', + type: 'combobox', key: 'easing', props: { type: 'number', @@ -68,7 +68,7 @@ export const NotePanelBuilderSingle = (note: INote): EditPanelItem[] => ([ { label: 'Type', i18n: 'common.type', - type: 'dropdown', + type: 'select', key: 'type', props: { type: 'number', diff --git a/src/ui/Panel/EditPanel/styles.css b/src/ui/Panel/EditPanel/styles.css deleted file mode 100644 index a9c6d20..0000000 --- a/src/ui/Panel/EditPanel/styles.css +++ /dev/null @@ -1,55 +0,0 @@ -.edit-panel { - position: relative; - width: 100%; - min-height: 40px; - height: 100%; - overflow-x: hidden; - overflow-y: auto; -} - -.edit-panel-placeholder { - position: absolute; - top: 50%; - width: 100%; - text-align: center; - transform: translateY(-50%); -} - -.edit-panel-item { - display: flex; - margin: 4px 0px; - width: 100%; -} - -.edit-panel-item .edit-panel-item-label { - display: block; - flex: 0.4; -} - -.edit-panel-item .edit-panel-item-input { - display: block; - flex: 0.6; -} - -.edit-panel-slider { - --value-percent: 0; - - position: relative; - display: block; - height: 24px; - border: 1px solid var(--border-secondary-color); - border-radius: 4px; - overflow: hidden; - cursor: ew-resize; -} - -.edit-panel-slider::before { - content: ''; - position: absolute; - top: 0px; - left: calc(var(--value-percent) * 100%); - width: 2px; - height: 100%; - transform: translateX(-50%); - background: var(--background-primary-color); -} diff --git a/src/ui/Panel/SettingsPanel/Item.tsx b/src/ui/Panel/SettingsPanel/Item.tsx index 51894cd..98468ce 100644 --- a/src/ui/Panel/SettingsPanel/Item.tsx +++ b/src/ui/Panel/SettingsPanel/Item.tsx @@ -1,35 +1,21 @@ -import { Card, FormGroup, Intent } from '@blueprintjs/core'; +import { Card } from '@chakra-ui/react'; type SettingsItemProps = { label: string, - children: React.ReactNode, - labelInfo?: string, - helperText?: string, - intent?: Intent, - disabled?: boolean, + children: React.ReactNode }; const SettingsItem = ({ label, - children, - labelInfo, - helperText, - intent, - disabled, + children }: SettingsItemProps) => { return ( - - + + + {label} {children} - - + + ); }; diff --git a/src/ui/Panel/SettingsPanel/Rendering.tsx b/src/ui/Panel/SettingsPanel/Rendering.tsx index b1bc7c7..29ab7e4 100644 --- a/src/ui/Panel/SettingsPanel/Rendering.tsx +++ b/src/ui/Panel/SettingsPanel/Rendering.tsx @@ -1,4 +1,4 @@ -import { CardList, Slider } from '@blueprintjs/core'; +import { Stack, Slider } from '@chakra-ui/react'; import Settings from '@/Settings/Settings'; import Item from './Item'; import { useSettings } from '@/ui/contexts/Settings'; @@ -12,20 +12,26 @@ const SettingsRendering = () => { }; return ( - - + + updateNoteScale(e.value[0])} > - - - + + + + + + + + + ); }; diff --git a/src/ui/Panel/SettingsPanel/SettingsPanel.tsx b/src/ui/Panel/SettingsPanel/SettingsPanel.tsx index 32429e2..3f9878a 100644 --- a/src/ui/Panel/SettingsPanel/SettingsPanel.tsx +++ b/src/ui/Panel/SettingsPanel/SettingsPanel.tsx @@ -1,19 +1,17 @@ -import { Tab, Tabs } from '@blueprintjs/core'; +import { Tabs } from '@chakra-ui/react'; import SettingsRendering from './Rendering'; -import './styles.css'; const SettingsPanel = () => { return ( - - } /> - + + + Rendering + + + + + ); }; -export default SettingsPanel; +export default SettingsPanel; \ No newline at end of file diff --git a/src/ui/Panel/SettingsPanel/styles.css b/src/ui/Panel/SettingsPanel/styles.css deleted file mode 100644 index 34132a8..0000000 --- a/src/ui/Panel/SettingsPanel/styles.css +++ /dev/null @@ -1,11 +0,0 @@ -.settings-panel { - width: 100%; - max-height: 100%; - overflow: hidden; -} - -.settings-panel .bp5-tab-panel { - width: 100%; - overflow-y: auto; - flex: 1; -} \ No newline at end of file From a0b249af42ef9b6974e1a7d8a478eb8358eb8b62 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 05:29:57 +0800 Subject: [PATCH 068/146] fix(ui): Bring back `useLabel` --- src/ui/Panel/EditPanel/Item/Boolean.tsx | 2 +- src/ui/Panel/EditPanel/Item/Combobox.tsx | 2 +- src/ui/Panel/EditPanel/Item/Container.tsx | 9 +++++---- src/ui/Panel/EditPanel/Item/Dropdown.tsx | 2 +- src/ui/Panel/EditPanel/Item/Number.tsx | 2 +- src/ui/Panel/EditPanel/Item/Select.tsx | 2 +- src/ui/Panel/EditPanel/Item/String.tsx | 2 +- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ui/Panel/EditPanel/Item/Boolean.tsx b/src/ui/Panel/EditPanel/Item/Boolean.tsx index 2f968fe..f67a5e8 100644 --- a/src/ui/Panel/EditPanel/Item/Boolean.tsx +++ b/src/ui/Panel/EditPanel/Item/Boolean.tsx @@ -15,7 +15,7 @@ const EditPanelBoolean = ({ }, [onChanged]); return ( - + + { const childrenDom = ( - {title} + {useLabel ? {title} : {title}} {children} ); return ( - {childrenDom} + useLabel ? {childrenDom} : {childrenDom} ); }; diff --git a/src/ui/Panel/EditPanel/Item/Dropdown.tsx b/src/ui/Panel/EditPanel/Item/Dropdown.tsx index 50f4c46..00fe3b2 100644 --- a/src/ui/Panel/EditPanel/Item/Dropdown.tsx +++ b/src/ui/Panel/EditPanel/Item/Dropdown.tsx @@ -39,7 +39,7 @@ const EditPanelDropdown = ({ }, [type, onChanged]); return ( - + + {min !== (void 0) && max !== (void 0) && useSlider ? ( <> + { return ( - + Date: Sun, 7 Sep 2025 05:31:02 +0800 Subject: [PATCH 069/146] fix(ui/Panel/EditPanel): typo i guess --- src/ui/Panel/EditPanel/Item/Combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/Panel/EditPanel/Item/Combobox.tsx b/src/ui/Panel/EditPanel/Item/Combobox.tsx index c0ebb4d..6784eeb 100644 --- a/src/ui/Panel/EditPanel/Item/Combobox.tsx +++ b/src/ui/Panel/EditPanel/Item/Combobox.tsx @@ -1,6 +1,6 @@ import Container from './Container'; import { PanelItemPropsBase } from '../types'; -import { Portal, Combobox, useFilter, useListCollection, createListCollection } from "@chakra-ui/react" +import { Portal, Combobox, useFilter, useListCollection } from "@chakra-ui/react" export type ComboboxPropsBase = PanelItemPropsBase & { type?: 'string' | 'number', From 8f237d67524ca8dd21d91540ed404e17db71270c Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 17:23:46 +0800 Subject: [PATCH 070/146] refactor(ui): Refactor Note Panel --- src/ui/Panel/NotePanel/BottomBar.tsx | 55 +++++++++++++++++ src/ui/Panel/NotePanel/NotePanel.tsx | 92 +++------------------------- src/ui/Panel/NotePanel/TopBar.tsx | 53 ++++++++++++++++ 3 files changed, 117 insertions(+), 83 deletions(-) create mode 100644 src/ui/Panel/NotePanel/BottomBar.tsx create mode 100644 src/ui/Panel/NotePanel/TopBar.tsx diff --git a/src/ui/Panel/NotePanel/BottomBar.tsx b/src/ui/Panel/NotePanel/BottomBar.tsx new file mode 100644 index 0000000..01c6d9f --- /dev/null +++ b/src/ui/Panel/NotePanel/BottomBar.tsx @@ -0,0 +1,55 @@ +import { Flex, Slider, HStack, Text } from '@chakra-ui/react'; +import { useTranslation } from 'react-i18next'; +import NumberInput from '@/ui/components/NumberInput'; + +type BottomBarProps = { + onScaleChange: (scale: number) => void, + onAlignChange: (align: number) => void, +}; + +const BottomBar = ({ + onScaleChange, + onAlignChange, +}: BottomBarProps) => { + const { t } = useTranslation(); + + return ( + + + {t('common.scale')} + onScaleChange(e.value[0])} + > + + + + + + + + + + + + {t('common.align')} + + + + ); +}; + +export default BottomBar; \ No newline at end of file diff --git a/src/ui/Panel/NotePanel/NotePanel.tsx b/src/ui/Panel/NotePanel/NotePanel.tsx index bb636d2..baff268 100644 --- a/src/ui/Panel/NotePanel/NotePanel.tsx +++ b/src/ui/Panel/NotePanel/NotePanel.tsx @@ -1,15 +1,15 @@ -import { ChangeEvent, useCallback, useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useCallback, useState } from 'react'; import { useRuntimeStore } from '@/state/runtimeStore'; import Grid from './Grid'; import './styles.css'; import PropsContext from './PropsContext'; import { Nullable } from '@/utils/types'; import { NoteType } from '@/core/types'; -import NumberInput from '@/ui/components/NumberInput'; +import TopBar, { EditModeType } from './TopBar'; +import BottomBar from './BottomBar'; +import { Stack } from '@chakra-ui/react'; const NotePanel = () => { - const { t } = useTranslation(); const [ writeMode, setWriteMode ] = useState>(null); const [ scale, setScale ] = useState(200); const [ alignCount, setAlighCount ] = useState(8); @@ -17,8 +17,7 @@ const NotePanel = () => { const setSelectedNote = useRuntimeStore((s) => s.setSelectedNote); const setSelectedKeyframe = useRuntimeStore((s) => s.setSelectedKeyframe); - const updateWriteMode = (e: ChangeEvent) => { - const newMode = e.target.value as (NoteType | 'select'); + const updateWriteMode = (newMode: EditModeType) => { if (newMode === 'select') setWriteMode(null); else { setWriteMode(newMode); @@ -32,57 +31,8 @@ const NotePanel = () => { }, []); return ( -

-
-
- {t('note_panel.mode_select.title')} - - - - - -
-
+ + { }}> -
- - -
-
+ + ); }; diff --git a/src/ui/Panel/NotePanel/TopBar.tsx b/src/ui/Panel/NotePanel/TopBar.tsx new file mode 100644 index 0000000..8c0adc6 --- /dev/null +++ b/src/ui/Panel/NotePanel/TopBar.tsx @@ -0,0 +1,53 @@ +import { NoteType } from '@/core/types'; +import { useTranslation } from 'react-i18next'; +import { Flex, HStack, RadioGroup, For, Text } from '@chakra-ui/react'; + +export type EditModeType = NoteType | 'select'; + +type TopBarProps = { + writeMode: EditModeType, + onChange: (newMode: EditModeType) => void, +}; + +const TopBar = ({ + writeMode, + onChange, +}: TopBarProps) => { + const { t } = useTranslation(); + const radioItems = [ + { label: t('note_panel.mode_select.select'), value: 'select' }, + { label: t('note.type.tap'), value: NoteType.Tap }, + { label: t('note.type.hold'), value: NoteType.Hold }, + { label: t('note.type.drag'), value: NoteType.Drag }, + { label: t('note.type.flick'), value: NoteType.Flick }, + ] + + return ( + + + {t('note_panel.mode_select.title')} + onChange(e.value as EditModeType)} + > + + + {item => ( + + + + {item.label} + + )} + + + + + + ); +}; + + +export default TopBar; \ No newline at end of file From 69e9aa995c7e9c8640326f9885071bd59a98fb40 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 7 Sep 2025 18:45:26 +0800 Subject: [PATCH 071/146] refactor(runtime/resources/cache): Refactoring cache system --- src/runtime/audio/bindChart.ts | 6 +- src/runtime/resources/cache.ts | 23 ++++---- src/runtime/resources/class.ts | 57 +++++++++++++++++++ src/runtime/resources/loader/audio.ts | 6 +- src/runtime/resources/loader/image.ts | 6 +- src/ui/App.tsx | 24 ++++++-- .../NotePanel/NoteContainer/NoteGraphics.tsx | 14 ++--- 7 files changed, 102 insertions(+), 34 deletions(-) create mode 100644 src/runtime/resources/class.ts diff --git a/src/runtime/audio/bindChart.ts b/src/runtime/audio/bindChart.ts index 3fbfd87..d7c2399 100644 --- a/src/runtime/audio/bindChart.ts +++ b/src/runtime/audio/bindChart.ts @@ -4,7 +4,7 @@ import { runtimeAudioStore, runtimeAudioTimeStore } from './state'; import { ticker } from './ticker'; import { store as ChartStore } from '@/core/state/chartStore'; import { getBeatByTime } from '@/core/timeline/bpm'; -import { audioCache } from '@/runtime/resources/cache'; +import { runtimeCache } from '@/runtime/resources/cache'; import { SnapshotIn } from 'mobx-state-tree'; import { Clip } from '@phifans/audio'; import { Metadata } from '@/core/models/Metadata'; @@ -47,14 +47,14 @@ onPatch(ChartStore, (patch) => { if (!value) return; if (!value.musicFile) return; - return applyNewClip(audioCache.get(value.musicFile)); + return applyNewClip(runtimeCache.get(value.musicFile) as Clip | undefined); } if (patch.path === '/metadata/musicFile' && patch.op === 'replace') { const value = patch.value as string | undefined; if (!value) return; - return applyNewClip(audioCache.get(value)); + return applyNewClip(runtimeCache.get(value) as Clip | undefined); } if (patch.path.startsWith('/bpm')) { diff --git a/src/runtime/resources/cache.ts b/src/runtime/resources/cache.ts index a9cad23..ad7bf9b 100644 --- a/src/runtime/resources/cache.ts +++ b/src/runtime/resources/cache.ts @@ -1,17 +1,16 @@ -import QuickLRU from 'quick-lru'; import { Clip } from '@phifans/audio'; import { Texture } from 'pixi.js'; +import { LRUCache } from './class'; -export const audioCache = new QuickLRU({ - maxSize: 100, - onEviction: (_key, clip) => { - clip.destroy(); - }, -}); +type CacheItem = Texture | Clip; -export const imageCache = new QuickLRU({ - maxSize: 50, - onEviction: (_key, texture) => { - texture.destroy(true); - }, +export const runtimeCache = new LRUCache({ + maxSize: 100, + onEviction(_key, item) { + if (item instanceof Texture) { + return item.destroy(true); + } else { + return item.destroy(); + } + } }); diff --git a/src/runtime/resources/class.ts b/src/runtime/resources/class.ts new file mode 100644 index 0000000..5dac254 --- /dev/null +++ b/src/runtime/resources/class.ts @@ -0,0 +1,57 @@ +import QuickLRU, { Options } from 'quick-lru'; + +const SkinKeyReg = /^skin\d+:/; + +export class LRUCache extends QuickLRU { + private readonly _onEviction?: (key: KeyType, value: ValueType) => void; + + constructor(options: Options) { + super(options); + + this._onEviction = options.onEviction; + } + + /** + * Destroy an item. This will also call `onEviction` if set. + */ + destroy(key: KeyType) { + const item = this.get(key); + if (!item) return false; + + if (typeof this._onEviction === 'function') { + this._onEviction(key, item); + } + + return this.delete(key); + } + + /** + * Destroy all items. This will also call `onEviction` if set. + */ + destroyAll() { + for (const [ key, item ] of this.entriesAscending()) { + if (typeof this._onEviction === 'function') { + this._onEviction(key, item); + } + } + + return this.clear(); + } + + /** + * Destroy all items except `skin\d+:`. This will also call `onEviction` if set. + */ + destroyAllWithoutSkin() { + for (const [ key ] of this.entriesAscending()) { + if (SkinKeyReg.test(key)) return; + this.destroy(key); + } + } + + destroySkins() { + for (const [ key ] of this.entriesAscending()) { + if (!SkinKeyReg.test(key)) return; + this.destroy(key); + } + } +} diff --git a/src/runtime/resources/loader/audio.ts b/src/runtime/resources/loader/audio.ts index a1613a8..d4543ff 100644 --- a/src/runtime/resources/loader/audio.ts +++ b/src/runtime/resources/loader/audio.ts @@ -1,13 +1,13 @@ import { Clip } from '@phifans/audio'; -import { audioCache } from '../cache'; +import { runtimeCache } from '../cache'; export const loadAudio = (file: File | Blob, filename?: string) => new Promise((res, rej) => { Clip.from(file) .then((clip) => { const _filename = (file as File).name ?? filename; - if (audioCache.has(_filename)) audioCache.delete(_filename); - audioCache.set(_filename, clip); + if (runtimeCache.has(_filename)) runtimeCache.destroy(_filename); + runtimeCache.set(_filename, clip); res(clip); }) .catch(e => rej(e)); diff --git a/src/runtime/resources/loader/image.ts b/src/runtime/resources/loader/image.ts index 7bd0c24..e3819db 100644 --- a/src/runtime/resources/loader/image.ts +++ b/src/runtime/resources/loader/image.ts @@ -1,5 +1,5 @@ import { Texture } from 'pixi.js'; -import { imageCache } from '../cache'; +import { runtimeCache } from '../cache'; export const loadImage = (file: Blob | File, filename?: string) => new Promise((res, rej) => { window.createImageBitmap(file) @@ -7,8 +7,8 @@ export const loadImage = (file: Blob | File, filename?: string) => new Promise rej(e)); diff --git a/src/ui/App.tsx b/src/ui/App.tsx index f9346a9..3983869 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -2,10 +2,12 @@ import TempoContext from './contexts/Tempo'; import Chart from '@/Chart/Chart'; import PanelDock from './Panel/PanelDock'; import { PopupReadFiles, ReadFileAsText } from '@/utils/file'; +import { Clip } from '@phifans/audio'; import { Nullable } from '@/utils/types'; import { useCallback, useState } from 'react'; import AppBar from './Bar/AppBar'; import SettingsProvider from './contexts/Settings/Provider'; +import { importFromZip } from '@/runtime/skin/importer'; import { DockviewApi } from 'dockview'; import { ChartExported } from '@/Chart/Chart'; import NumberInput from './components/NumberInput'; @@ -13,7 +15,7 @@ import TopBar from './Bar/TopBar/TopBar'; import DialogProvider from './contexts/Dialog/Provider'; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; -import { audioCache } from '@/runtime/resources/cache'; +import { runtimeCache } from '@/runtime/resources/cache'; import '@/runtime/audio/state'; function App() { @@ -36,8 +38,8 @@ function App() { const onApplyTestMetadata = () => { let audioFile: string = ''; - for (const [ name ] of audioCache.entriesDescending()) { - if (!audioFile) { + for (const [ name, item ] of runtimeCache.entriesDescending()) { + if (!audioFile && item instanceof Clip) { audioFile = name; break; } @@ -49,6 +51,18 @@ function App() { }); }; + const onImportSkin = () => { + PopupReadFiles(true) + .then((files) => { + if (!files || files.length === 0) return; + return importFromZip(files[0]); + }) + .then((result) => { + console.log(result); + }) + .catch((e) => console.error(e)); + }; + const onCreateChart = () => { if (!importedMusic) return; if (Chart.info) return; @@ -120,9 +134,7 @@ function App() { - - - + |
diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx index 237592c..1a2fff3 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx @@ -4,7 +4,7 @@ import { Container, EventMode, Sprite, Texture } from 'pixi.js'; import { observer } from 'mobx-react-lite'; import { useRuntimeStore } from '@/state/runtimeStore'; import { useRuntimeAudioBeat } from '@/runtime/audio/state'; -import { imageCache } from '@/runtime/resources/cache'; +import { runtimeCache } from '@/runtime/resources/cache'; import { NoteType } from '@/core/types'; import useDrag from '@/ui/hooks/useDrag'; import { useTempo } from '@/ui/contexts/Tempo'; @@ -18,9 +18,9 @@ import { SnapshotIn } from 'mobx-state-tree'; const NOTE_SCALE = 5000; const getNoteTexture = (type: NoteType, withHL: boolean = false) => { - if (type === NoteType.Drag) return imageCache.get(`skin:Drag${withHL ? 'HL' : ''}.png`); - else if (type === NoteType.Flick) return imageCache.get(`skin:Flick${withHL ? 'HL' : ''}.png`); - else return imageCache.get(`skin:Tap${withHL ? 'HL' : ''}.png`); + if (type === NoteType.Drag) return runtimeCache.get(`skin:Drag${withHL ? 'HL' : ''}.png`) as Texture | undefined; + else if (type === NoteType.Flick) return runtimeCache.get(`skin:Flick${withHL ? 'HL' : ''}.png`) as Texture | undefined; + else return runtimeCache.get(`skin:Tap${withHL ? 'HL' : ''}.png`) as Texture | undefined; }; const calculateNewTime = ( @@ -156,18 +156,18 @@ const Note = observer<{ ): ( From 134737ab9bbba3b88c9b705ebbf06e680d96776d Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 7 Sep 2025 18:55:42 +0800 Subject: [PATCH 072/146] feat(runtime/skin): Add state --- src/runtime/init.ts | 11 ++-- src/runtime/skin/importer.ts | 19 +++--- src/runtime/skin/state.ts | 63 +++++++++++++++++++ .../NotePanel/NoteContainer/NoteGraphics.tsx | 21 ++++--- 4 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 src/runtime/skin/state.ts diff --git a/src/runtime/init.ts b/src/runtime/init.ts index ed2f36b..9c91ed5 100644 --- a/src/runtime/init.ts +++ b/src/runtime/init.ts @@ -1,16 +1,19 @@ import { db } from './database'; -import { loadSkin } from './skin/loader'; +import { skinStore } from './skin/state'; import { importFromZip } from './skin/importer'; export const runtimeInit = () => new Promise(async (res) => { // Init skins const skins = await db.get('skins'); - if (!skins || skins.length <= 0) + const { selectSkin } = skinStore.getState(); + if (!skins || skins.length <= 0) { await fetch('./skin-default.zip') .then(e => e.blob()) .then((e) => importFromZip(e)); - else - await loadSkin(skins[0].name, skins[0].author); + } else { + skinStore.setState({ skins }); + await selectSkin(skins[0].name, skins[0].author); + } res(); }); diff --git a/src/runtime/skin/importer.ts b/src/runtime/skin/importer.ts index 63c1d8b..0265633 100644 --- a/src/runtime/skin/importer.ts +++ b/src/runtime/skin/importer.ts @@ -1,7 +1,7 @@ import JSZip from 'jszip'; import * as fs from '@zenfs/core/promises'; import { db } from '../database'; -import { loadFiles } from '../resources/loader'; +import { skinStore } from './state'; import { checkMetaValidation, getSkinFolderName } from './utils'; import { SkinFiles } from './consts'; import { SkinMeta } from './types'; @@ -13,6 +13,7 @@ import { SkinMeta } from './types'; */ export const importFromZip = (zipFile: Blob, loadAfterImport = true): Promise => new Promise(async (res, rej) => { + const { skins, selectSkin } = skinStore.getState(); const zip = await JSZip.loadAsync(zipFile); const metaFile = zip.file('skin.json'); @@ -29,7 +30,7 @@ export const importFromZip = (zipFile: Blob, loadAfterImport = true): Promise { const file = zip.file(filename); if (!file) return null; - return file.async('arraybuffer').then(b => ({ filename, buffer: b })); + return file.async('uint8array').then(b => ({ filename, buffer: b })); }).filter(e => e !== null) ); if (pendingBuffers.length <= 0) return rej('No skin file(s) found'); @@ -39,18 +40,18 @@ export const importFromZip = (zipFile: Blob, loadAfterImport = true): Promise ( - fs.writeFile(`/skins/${folderName}/${e.filename}`, new Uint8Array(e.buffer)) + fs.writeFile(`/skins/${folderName}/${e.filename}`, e.buffer) )) ); - if (loadAfterImport) await loadFiles(pendingBuffers.map((e) => new File([e.buffer], e.filename))); - const skinsList = (await db.get('skins'))!; - const oldIndex = skinsList.findIndex(e => e.name === metaJson.name && e.author === metaJson.author); + const oldIndex = skins.findIndex(e => e.name === metaJson.name && e.author === metaJson.author); if (oldIndex >= 0) - Object.assign(skinsList[oldIndex], metaJson); + Object.assign(skins[oldIndex], metaJson); else - skinsList.push(metaJson); - await db.set('skins', skinsList); + skins.push(metaJson); + await db.set('skins', skins); + skinStore.setState({ skins }); + if (loadAfterImport) await selectSkin(metaJson.name, metaJson.author); res(metaJson); }); diff --git a/src/runtime/skin/state.ts b/src/runtime/skin/state.ts new file mode 100644 index 0000000..c47b6e0 --- /dev/null +++ b/src/runtime/skin/state.ts @@ -0,0 +1,63 @@ +import { createStore } from 'zustand/vanilla'; +import { useStore } from 'zustand'; +import * as fs from '@zenfs/core/promises'; +import { getSkinFolderName } from './utils'; +import { loadFiles } from '../resources/loader'; +import { SkinFiles } from './consts'; +import { SkinMeta } from './types'; +import { Nullable } from '@/utils/types'; +import { runtimeCache } from '../resources/cache'; + +type SkinStore = { + skins: SkinMeta[], + currentSkin: Nullable, + skinCount: number, + + selectSkin: (name: string, author?: string) => Promise, +}; + +export const skinStore = createStore((set, get) => ({ + skins: [], + currentSkin: null, + skinCount: -1, + + selectSkin(name: string, author?: string) { + return new Promise(async (res, rej) => { + const { skins, skinCount } = get(); + if (!skins || skins.length <= 0) return rej('No skin stored'); + + const skinIndex = skins.findIndex(e => e.name === name && (author === (void 0) || e.author === author)); + if (skinIndex === -1) return rej('No such skin found'); + + const folderName = getSkinFolderName(skins[skinIndex]); + const pendingBuffers = await Promise.all( + SkinFiles.map((filename) => + fs.readFile(`/skins/${folderName}/${filename}`) + .then((b) => ({ filename, buffer: b })) + ) + ); + + const missingFiles = SkinFiles.filter((e) => pendingBuffers.findIndex(h => h.filename === e) === -1); + if (skinCount < 0 && missingFiles.length > 0) return rej('Missing files in default skin'); + + missingFiles.forEach((filename) => { + const file = runtimeCache.peek(`skin${skinCount}:${filename}`); + if (!file) return; + + runtimeCache.set(`skin${skinCount + 1}:${filename}`, file); + runtimeCache.delete(`skin${skinCount}:${filename}`); + }); + + await loadFiles(pendingBuffers.map((e) => new File([e.buffer as unknown as ArrayBuffer], `skin${skinCount + 1}:${e.filename}`))); + set({ + currentSkin: skins[skinIndex], + skinCount: (skinCount + 1), + }); + res(skins[skinIndex]); + }); + }, +})); + +export const useSkinStore = ( + selector: (state: SkinStore) => U +) => useStore(skinStore, selector); diff --git a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx index 1a2fff3..5ffaf6b 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx +++ b/src/ui/Panel/NotePanel/NoteContainer/NoteGraphics.tsx @@ -5,6 +5,7 @@ import { observer } from 'mobx-react-lite'; import { useRuntimeStore } from '@/state/runtimeStore'; import { useRuntimeAudioBeat } from '@/runtime/audio/state'; import { runtimeCache } from '@/runtime/resources/cache'; +import { useSkinStore } from '@/runtime/skin/state'; import { NoteType } from '@/core/types'; import useDrag from '@/ui/hooks/useDrag'; import { useTempo } from '@/ui/contexts/Tempo'; @@ -17,10 +18,13 @@ import { SnapshotIn } from 'mobx-state-tree'; const NOTE_SCALE = 5000; -const getNoteTexture = (type: NoteType, withHL: boolean = false) => { - if (type === NoteType.Drag) return runtimeCache.get(`skin:Drag${withHL ? 'HL' : ''}.png`) as Texture | undefined; - else if (type === NoteType.Flick) return runtimeCache.get(`skin:Flick${withHL ? 'HL' : ''}.png`) as Texture | undefined; - else return runtimeCache.get(`skin:Tap${withHL ? 'HL' : ''}.png`) as Texture | undefined; +const getNoteTexture = (type: NoteType, skinCount = 0, withHL: boolean = false) => { + let skinName = `skin${skinCount}:Tap${withHL ? 'HL' : ''}.png`; + + if (type === NoteType.Drag) skinName = `skin${skinCount}:Drag${withHL ? 'HL' : ''}.png`; + else if (type === NoteType.Flick) skinName = `skin${skinCount}:Flick${withHL ? 'HL' : ''}.png`; + + return runtimeCache.get(skinName) as Texture | undefined; }; const calculateNewTime = ( @@ -73,6 +77,7 @@ const Note = observer<{ const noteLength = note.holdLengthBeatNum * scale / noteScale; const setSelectedNote = useRuntimeStore((s) => s.setSelectedNote); + const skinCount = useSkinStore(s => s.skinCount); const handleDragging = (_: unknown, { x, y }: Point) => { const positionXGrid = ( @@ -149,25 +154,25 @@ const Note = observer<{ return (<> {note.type !== NoteType.Hold ? ( ): ( From d5846c25b14677d03f3b2196db64cffaa1275a89 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Sun, 7 Sep 2025 19:30:52 +0800 Subject: [PATCH 073/146] feat(runtime/skin/state): Destroy old skin when change --- src/runtime/skin/loader.ts | 30 ------------------------------ src/runtime/skin/state.ts | 6 ++++++ 2 files changed, 6 insertions(+), 30 deletions(-) delete mode 100644 src/runtime/skin/loader.ts diff --git a/src/runtime/skin/loader.ts b/src/runtime/skin/loader.ts deleted file mode 100644 index f960b8c..0000000 --- a/src/runtime/skin/loader.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as fs from '@zenfs/core/promises'; -import { db } from '../database'; -import { loadFiles } from '../resources/loader'; -import { getSkinFolderName } from './utils'; -import { SkinFiles } from './consts'; -import { SkinMeta } from './types'; - -/** - * Load imported skin - * @param name - * @param author - */ -export const loadSkin = (name: string, author?: string) => new Promise(async (res, rej) => { - const skins = await db.get('skins'); - if (!skins || skins.length <= 0) return rej('No skin stored'); - - const skinIndex = skins.findIndex(e => e.name === name && (author === (void 0) || e.author === author)); - if (skinIndex === -1) return rej('No such skin found'); - - const folderName = getSkinFolderName(skins[skinIndex]); - const pendingBuffers = await Promise.all( - SkinFiles.map((filename) => - fs.readFile(`/skins/${folderName}/${filename}`) - .then((b) => ({ filename, buffer: b })) - ) - ); - - await loadFiles(pendingBuffers.map((e) => new File([e.buffer as unknown as ArrayBuffer], `skin:${e.filename}`))); - res(skins[skinIndex]); -}); diff --git a/src/runtime/skin/state.ts b/src/runtime/skin/state.ts index c47b6e0..0ffca5d 100644 --- a/src/runtime/skin/state.ts +++ b/src/runtime/skin/state.ts @@ -49,10 +49,16 @@ export const skinStore = createStore((set, get) => ({ }); await loadFiles(pendingBuffers.map((e) => new File([e.buffer as unknown as ArrayBuffer], `skin${skinCount + 1}:${e.filename}`))); + set({ currentSkin: skins[skinIndex], skinCount: (skinCount + 1), }); + + for (const [ name ] of runtimeCache.entriesAscending()) { + if (name.startsWith(`skin${skinCount}:`)) runtimeCache.destroy(name); + } + res(skins[skinIndex]); }); }, From 8357a733d8bd9ea33d2de3a4697909060b079ff8 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 20:46:16 +0800 Subject: [PATCH 074/146] refactor(ui): Refactor Menu Bar --- package.json | 2 + pnpm-lock.yaml | 763 +++++++++++++++++- src/ui/App.tsx | 87 +- src/ui/Bar/ActivityBar.tsx | 26 + src/ui/Bar/AppBar.tsx | 19 - .../{TopBar/Menu/File => }/CreateProject.tsx | 9 +- src/ui/Bar/Menu.tsx | 158 ++++ src/ui/Bar/TopBar/Menu/File/File.tsx | 21 - src/ui/Bar/TopBar/Menu/Menu.tsx | 11 - src/ui/Bar/TopBar/TopBar.tsx | 12 - src/ui/Bar/styles.css | 10 - src/ui/Panel/BPMPanel/BPMPanel.tsx | 2 +- src/ui/Panel/BPMPanel/Item.tsx | 2 +- src/ui/Panel/PanelDock.tsx | 2 +- src/ui/Panel/PreviewPanel/Controller.tsx | 14 +- src/ui/Panel/SettingsPanel/SettingsPanel.tsx | 2 +- src/ui/index.tsx | 5 +- src/ui/styles/index.css | 218 +---- 18 files changed, 985 insertions(+), 378 deletions(-) create mode 100644 src/ui/Bar/ActivityBar.tsx delete mode 100644 src/ui/Bar/AppBar.tsx rename src/ui/Bar/{TopBar/Menu/File => }/CreateProject.tsx (93%) create mode 100644 src/ui/Bar/Menu.tsx delete mode 100644 src/ui/Bar/TopBar/Menu/File/File.tsx delete mode 100644 src/ui/Bar/TopBar/Menu/Menu.tsx delete mode 100644 src/ui/Bar/TopBar/TopBar.tsx delete mode 100644 src/ui/Bar/styles.css diff --git a/package.json b/package.json index 7af060c..c56f854 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@fortawesome/react-fontawesome": "^0.2.2", "@phifans/audio": "^0.0.7", "@pixi/react": "8.0.0", + "@radix-ui/react-menubar": "^1.1.16", "@types/node": "^22.10.5", "audio-decode": "^2.2.2", "dockview": "^4.7.1", @@ -48,6 +49,7 @@ "react-split-pane": "^0.1.92", "setimmediate": "^1.0.5", "spark-md5": "^3.0.2", + "styled-components": "^6.1.19", "uuid": "^11.0.4", "zustand": "^5.0.8" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 459d477..e81a1e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,6 +37,9 @@ importers: '@pixi/react': specifier: 8.0.0 version: 8.0.0(@types/react@19.0.7)(pixi.js@8.6.6)(react@19.0.0) + '@radix-ui/react-menubar': + specifier: ^1.1.16 + version: 1.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@types/node': specifier: ^22.10.5 version: 22.10.5 @@ -109,6 +112,9 @@ importers: spark-md5: specifier: ^3.0.2 version: 3.0.2 + styled-components: + specifier: ^6.1.19 + version: 6.1.19(react-dom@19.0.0(react@19.0.0))(react@19.0.0) uuid: specifier: ^11.0.4 version: 11.0.4 @@ -271,9 +277,15 @@ packages: '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + '@emotion/is-prop-valid@1.2.2': + resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} + '@emotion/is-prop-valid@1.4.0': resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} + '@emotion/memoize@0.8.1': + resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + '@emotion/memoize@0.9.0': resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} @@ -295,6 +307,9 @@ packages: '@emotion/unitless@0.10.0': resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + '@emotion/unitless@0.8.1': + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: @@ -655,6 +670,12 @@ packages: '@floating-ui/dom@1.7.4': resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} @@ -753,6 +774,272 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menubar@1.1.16': + resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rollup/rollup-android-arm-eabi@4.34.7': resolution: {integrity: sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==} cpu: [arm] @@ -1067,6 +1354,9 @@ packages: '@types/spark-md5@3.0.5': resolution: {integrity: sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg==} + '@types/stylis@4.2.5': + resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} + '@typescript-eslint/eslint-plugin@8.18.2': resolution: {integrity: sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1402,6 +1692,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -1487,6 +1781,9 @@ packages: camel-case@4.1.2: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + camelize@1.0.1: + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} + capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -1550,6 +1847,13 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-color-keywords@1.0.0: + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} + + css-to-react-native@3.2.0: + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1598,6 +1902,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dockview-core@4.7.1: resolution: {integrity: sha512-Tia3vYHtqACMZTiZv86yQOabwKj5KrBhQqlSr7qXV0qmmRSZ8dNbaU63LIHYFprST7JgHupIm9JVES+OhqMoTQ==} @@ -1821,6 +2128,10 @@ packages: resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -2365,6 +2676,13 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.2: resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} engines: {node: ^10 || ^12 || >=14} @@ -2446,6 +2764,26 @@ packages: peerDependencies: react: ^19.0.0 + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-split-pane@0.1.92: resolution: {integrity: sha512-GfXP1xSzLMcLJI5BM36Vh7GgZBpy+U/X0no+VM3fxayv+p1Jly5HpMofZJraeaMl73b3hvlr+N9zJKvLB/uz9w==} peerDependencies: @@ -2455,6 +2793,16 @@ packages: react-style-proptype@3.2.2: resolution: {integrity: sha512-ywYLSjNkxKHiZOqNlso9PZByNEY+FTyh3C+7uuziK0xFXu9xzdyfHwg4S9iyiRRoPCR4k2LqaBBsWVmSBwCWYQ==} + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -2560,6 +2908,9 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2651,9 +3002,19 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + styled-components@6.1.19: + resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} + engines: {node: '>= 16'} + peerDependencies: + react: '>= 16.8.0' + react-dom: '>= 16.8.0' + stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + stylis@4.3.2: + resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -2698,6 +3059,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} @@ -2759,6 +3123,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.4.0: resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} peerDependencies: @@ -3124,10 +3508,16 @@ snapshots: '@emotion/hash@0.9.2': {} + '@emotion/is-prop-valid@1.2.2': + dependencies: + '@emotion/memoize': 0.8.1 + '@emotion/is-prop-valid@1.4.0': dependencies: '@emotion/memoize': 0.9.0 + '@emotion/memoize@0.8.1': {} + '@emotion/memoize@0.9.0': {} '@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0)': @@ -3158,6 +3548,8 @@ snapshots: '@emotion/unitless@0.10.0': {} + '@emotion/unitless@0.8.1': {} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': dependencies: react: 19.0.0 @@ -3371,6 +3763,12 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 + '@floating-ui/react-dom@2.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + '@floating-ui/utils@0.2.10': {} '@fortawesome/fontawesome-common-types@6.7.2': {} @@ -3469,6 +3867,249 @@ snapshots: '@popperjs/core@2.11.8': {} + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-context@1.1.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-direction@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-id@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + aria-hidden: 1.2.6 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-remove-scroll: 2.7.1(@types/react@19.0.7)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/rect': 1.1.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-slot@1.2.3(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/rect@1.1.1': {} + '@rollup/rollup-android-arm-eabi@4.34.7': optional: true @@ -3672,6 +4313,8 @@ snapshots: '@types/spark-md5@3.0.5': {} + '@types/stylis@4.2.5': {} + '@typescript-eslint/eslint-plugin@8.18.2(@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3))(eslint@9.17.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -4324,6 +4967,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.3 @@ -4448,12 +5095,14 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.6.3 + tslib: 2.8.1 + + camelize@1.0.1: {} capital-case@1.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 upper-case-first: 2.0.2 chalk@4.1.2: @@ -4474,7 +5123,7 @@ snapshots: path-case: 3.0.4 sentence-case: 3.0.4 snake-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 chokidar@3.6.0: dependencies: @@ -4513,7 +5162,7 @@ snapshots: constant-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 upper-case: 2.0.2 convert-source-map@1.9.0: {} @@ -4538,6 +5187,14 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-color-keywords@1.0.0: {} + + css-to-react-native@3.2.0: + dependencies: + camelize: 1.0.1 + css-color-keywords: 1.0.0 + postcss-value-parser: 4.2.0 + csstype@3.1.3: {} data-uri-to-buffer@4.0.1: {} @@ -4582,6 +5239,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + detect-node-es@1.1.0: {} + dockview-core@4.7.1: {} dockview@4.7.1(react@19.0.0): @@ -4601,7 +5260,7 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 dunder-proto@1.0.1: dependencies: @@ -4973,6 +5632,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -5048,7 +5709,7 @@ snapshots: header-case@2.0.4: dependencies: capital-case: 1.0.4 - tslib: 2.6.3 + tslib: 2.8.1 hoist-non-react-statics@3.3.2: dependencies: @@ -5296,7 +5957,7 @@ snapshots: lower-case@2.0.2: dependencies: - tslib: 2.6.3 + tslib: 2.8.1 lru-cache@10.4.3: {} @@ -5362,7 +6023,7 @@ snapshots: no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.6.3 + tslib: 2.8.1 node-domexception@1.0.0: {} @@ -5461,7 +6122,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 parent-module@1.0.1: dependencies: @@ -5479,12 +6140,12 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 path-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 path-exists@4.0.0: {} @@ -5525,6 +6186,14 @@ snapshots: possible-typed-array-names@1.0.0: {} + postcss-value-parser@4.2.0: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.2: dependencies: nanoid: 3.3.8 @@ -5594,6 +6263,25 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-remove-scroll-bar@2.3.8(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + + react-remove-scroll@2.7.1(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.0.7)(react@19.0.0) + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.0.7)(react@19.0.0) + use-sidecar: 1.1.3(@types/react@19.0.7)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + react-split-pane@0.1.92(patch_hash=15b3bc41b3c9ea6e7a5c245069978ef071c4655082c4e9b0e14eb5d4eb57da5c)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: prop-types: 15.8.1 @@ -5606,6 +6294,14 @@ snapshots: dependencies: prop-types: 15.8.1 + react-style-singleton@2.2.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + get-nonce: 1.0.1 + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime': 7.26.10 @@ -5618,7 +6314,7 @@ snapshots: react-uid@2.4.0(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 - tslib: 2.6.3 + tslib: 2.8.1 optionalDependencies: '@types/react': 19.0.7 @@ -5725,7 +6421,7 @@ snapshots: sentence-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 upper-case-first: 2.0.2 set-function-length@1.2.2: @@ -5752,6 +6448,8 @@ snapshots: setimmediate@1.0.5: {} + shallowequal@1.1.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -5797,7 +6495,7 @@ snapshots: snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 source-map-js@1.2.1: {} @@ -5871,8 +6569,24 @@ snapshots: strip-json-comments@3.1.1: {} + styled-components@6.1.19(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@emotion/is-prop-valid': 1.2.2 + '@emotion/unitless': 0.8.1 + '@types/stylis': 4.2.5 + css-to-react-native: 3.2.0 + csstype: 3.1.3 + postcss: 8.4.49 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + shallowequal: 1.1.0 + stylis: 4.3.2 + tslib: 2.6.2 + stylis@4.2.0: {} + stylis@4.3.2: {} + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -5913,6 +6627,8 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@2.6.2: {} + tslib@2.6.3: {} tslib@2.8.1: {} @@ -5979,11 +6695,11 @@ snapshots: upper-case-first@2.0.2: dependencies: - tslib: 2.6.3 + tslib: 2.8.1 upper-case@2.0.2: dependencies: - tslib: 2.6.3 + tslib: 2.8.1 uqr@0.1.2: {} @@ -5991,6 +6707,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + + use-sidecar@1.1.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + use-sync-external-store@1.4.0(react@19.0.0): dependencies: react: 19.0.0 diff --git a/src/ui/App.tsx b/src/ui/App.tsx index f9346a9..7d3232f 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,31 +1,35 @@ +import { ChakraProvider, createSystem, defaultConfig, defineConfig } from "@chakra-ui/react" +import { ColorModeProvider } from "@/components/ui/color-mode" import TempoContext from './contexts/Tempo'; import Chart from '@/Chart/Chart'; import PanelDock from './Panel/PanelDock'; import { PopupReadFiles, ReadFileAsText } from '@/utils/file'; import { Nullable } from '@/utils/types'; import { useCallback, useState } from 'react'; -import AppBar from './Bar/AppBar'; import SettingsProvider from './contexts/Settings/Provider'; import { DockviewApi } from 'dockview'; import { ChartExported } from '@/Chart/Chart'; -import NumberInput from './components/NumberInput'; -import TopBar from './Bar/TopBar/TopBar'; import DialogProvider from './contexts/Dialog/Provider'; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; import { audioCache } from '@/runtime/resources/cache'; +import Menu from './Bar/Menu'; +import ActivityBar from './Bar/ActivityBar'; import '@/runtime/audio/state'; +const config = defineConfig({}); +const system = createSystem(defaultConfig, config); + function App() { - const [ dockviewApi, setDockviewApi ] = useState(); - const [ tempo, setTempo ] = useState(4); + const [dockviewApi, setDockviewApi] = useState(); + const [tempo, setTempo] = useState(4); let importedMusic: Nullable = null; const onImportFiles = () => { PopupReadFiles(true) .then((files) => { if (!files || files.length === 0) return; - return loadFiles([ ...files ]); + return loadFiles([...files]); }) .then((result) => { console.log(result); @@ -36,7 +40,7 @@ function App() { const onApplyTestMetadata = () => { let audioFile: string = ''; - for (const [ name ] of audioCache.entriesDescending()) { + for (const [name] of audioCache.entriesDescending()) { if (!audioFile) { audioFile = name; break; @@ -86,7 +90,7 @@ function App() { const chartJson = Chart.json!; const chartText = JSON.stringify(chartJson, null, 4); - const chartBlob = new Blob([ chartText ], { type: 'text/json' }); + const chartBlob = new Blob([chartText], { type: 'text/json' }); const chartUrl = URL.createObjectURL(chartBlob); const downloadDom = document.createElement('a'); @@ -112,50 +116,31 @@ function App() { }; return ( - <> - - - -
- - - - - - -
- | -
- -
- -
- - + + + + - - -
- -
-
- - - + + + + + + + + ); } diff --git a/src/ui/Bar/ActivityBar.tsx b/src/ui/Bar/ActivityBar.tsx new file mode 100644 index 0000000..1963d77 --- /dev/null +++ b/src/ui/Bar/ActivityBar.tsx @@ -0,0 +1,26 @@ +import NumberInput from '@/ui/components/NumberInput'; +import { HStack, Text } from '@chakra-ui/react'; + +type ActivityBarProps = { + handleTempoUpdate: (tempo: number) => void, +}; + +const ActivityBar = ({ handleTempoUpdate }: ActivityBarProps) => { + return ( + + Set tempo: 1/ + + + ); +}; + +export default ActivityBar; \ No newline at end of file diff --git a/src/ui/Bar/AppBar.tsx b/src/ui/Bar/AppBar.tsx deleted file mode 100644 index e60f8a3..0000000 --- a/src/ui/Bar/AppBar.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import './styles.css'; - -type AppBarProps = { - className?: string, - children?: React.ReactNode, -}; - -const AppBar = ({ - className, - children -}: AppBarProps) => { - return ( -
- {children} -
- ); -}; - -export default AppBar; diff --git a/src/ui/Bar/TopBar/Menu/File/CreateProject.tsx b/src/ui/Bar/CreateProject.tsx similarity index 93% rename from src/ui/Bar/TopBar/Menu/File/CreateProject.tsx rename to src/ui/Bar/CreateProject.tsx index ed8edc5..da66445 100644 --- a/src/ui/Bar/TopBar/Menu/File/CreateProject.tsx +++ b/src/ui/Bar/CreateProject.tsx @@ -1,4 +1,4 @@ -import { Button, DialogBody, DialogFooter, FileInput, FormGroup, MenuItem } from '@blueprintjs/core'; +import { Button, DialogBody, DialogFooter, FileInput, FormGroup } from '@blueprintjs/core'; import { useRef } from 'react'; import Chart from '@/Chart/Chart'; import ProjectPanel from '@/ui/Panel/ProjectPanel/ProjectPanel'; @@ -13,7 +13,7 @@ type ProjectMeta = ChartInfo & { background: File, }; -const CreateProject = () => { +const CreateProject = ({ Hachimi }: any) => { const { show: showDialog, close: closeDialog } = useDialog(); const newProjectMeta = useRef>({}); @@ -130,10 +130,7 @@ const CreateProject = () => { }; return ( - + Create Project ); }; diff --git a/src/ui/Bar/Menu.tsx b/src/ui/Bar/Menu.tsx new file mode 100644 index 0000000..e728f85 --- /dev/null +++ b/src/ui/Bar/Menu.tsx @@ -0,0 +1,158 @@ +import { faCaretRight } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { SystemContext } from '@chakra-ui/react'; +import CreateProject from "./CreateProject"; +import styled from "styled-components"; +import * as Menubar from "@radix-ui/react-menubar"; + +export type MenuType = { + system: SystemContext, + onImportFiles: () => void, + onApplyTestMetadata: () => void, + onUnsetMetadata: () => void, + onCreateChart: () => void, + onLoadChart: () => void, + onExportChart: () => void, + showSettingsPanel: () => void, +}; + +const Menu = ({ + system, + onImportFiles, + onApplyTestMetadata, + onUnsetMetadata, + onCreateChart, + onLoadChart, + onExportChart, + showSettingsPanel, +}: MenuType) => { + const Root = styled(Menubar.Root)(system.css({ + display: "flex", + layerStyle: "fill.subtle", + })); + + const Menu = styled(Menubar.Menu)(system.css({})); + + const Trigger = styled(Menubar.Trigger)(system.css({ + layerStyle: "fill.subtle", + textStyle: "sm", + px: "3", + py: "1", + gap: "2", + alignItems: "center", + justifyContent: "space-between", + display: "flex", + lineHeight: "1.5", + outline: "none", + userSelect: "none", + "&[data-highlighted]": { layerStyle: "fill.muted" }, + "&[data-state='open']": { layerStyle: "fill.muted" }, + "&:hover": { layerStyle: "fill.muted" } + })); + + const Portal = styled(Menubar.Portal)(system.css({})); + const Sub = styled(Menubar.Sub)(system.css({})); + + const MenubarContent = system.css({ + minW: "40", + layerStyle: "fill.subtle", + p: "3", + }); + + const Content = styled(Menubar.Content)(MenubarContent); + const SubContent = styled(Menubar.SubContent)(MenubarContent); + + const MenuItem = system.css({ + all: "unset", + textStyle: "sm", + lineHeight: "2", + alignItems: "center", + justifyContent: "space-between", + display: "flex", + px: "3", + position: "relative", + userSelect: "none", + "&[data-highlighted]": { layerStyle: "fill.muted" }, + "&[data-state='open']": { layerStyle: "fill.muted" }, + "&:hover": { layerStyle: "fill.muted" } + }); + + const Item = styled(Menubar.Item)(MenuItem); + const SubTrigger = styled(Menubar.SubTrigger)(MenuItem); + + const Separator = styled(Menubar.Separator)(system.css({ + height: "1px", + backgroundColor: "border", + margin: "2", + })); + + const RightSlotIcon = styled(FontAwesomeIcon)(system.css({ + marginLeft: "auto", + paddingLeft: "2", + color: "text", + })); + + return ( + + + File + + + Import files + Export files + + + + + Chart + + + + + Create chart + Load chart + Export chart + + + + + + + + + Edit + + + Undo + Redo + + + + Metadata + + + + + Apply Test Metadata + Unset Metadata + + + + + Settings + + + + + ); +}; + +export default Menu; diff --git a/src/ui/Bar/TopBar/Menu/File/File.tsx b/src/ui/Bar/TopBar/Menu/File/File.tsx deleted file mode 100644 index d56206b..0000000 --- a/src/ui/Bar/TopBar/Menu/File/File.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Button, Menu, Popover } from '@blueprintjs/core'; -import CreateProject from './CreateProject'; - -const MenuFile = () => { - return ( - - -
- )} - usePortal={false} - lazy={true} - minimal - > - diff --git a/src/ui/Panel/BPMPanel/Item.tsx b/src/ui/Panel/BPMPanel/Item.tsx index 2b7c5ba..2a20c46 100644 --- a/src/ui/Panel/BPMPanel/Item.tsx +++ b/src/ui/Panel/BPMPanel/Item.tsx @@ -47,7 +47,7 @@ const BPMListItem = observer<{ /> - diff --git a/src/ui/Panel/PanelDock.tsx b/src/ui/Panel/PanelDock.tsx index f1db9e8..afd3377 100644 --- a/src/ui/Panel/PanelDock.tsx +++ b/src/ui/Panel/PanelDock.tsx @@ -99,7 +99,7 @@ const PanelDock = (props: { api: DockviewApi | undefined, setApi: (api: Dockview onReady={onReady} className={props.theme || "dockview-theme-abyss"} disableFloatingGroups={false} - singleTabMode="fullwidth" + singleTabMode="default" /> diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index d695b8c..079c418 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -15,7 +15,7 @@ const PreviewController = () => { return ( <> - + @@ -25,8 +25,8 @@ const PreviewController = () => {
- - - - - - -
- + + + + + + {t('common.offset')} + + + + + + + + + + + + + + + ); }); diff --git a/src/ui/Panel/BPMPanel/Item.tsx b/src/ui/Panel/BPMPanel/Item.tsx index 19ba578..2b7c5ba 100644 --- a/src/ui/Panel/BPMPanel/Item.tsx +++ b/src/ui/Panel/BPMPanel/Item.tsx @@ -4,7 +4,7 @@ import BeatInput from '@/ui/components/BeatInput'; import NumberInput from '@/ui/components/NumberInput'; import { useTranslation } from 'react-i18next'; import { BeatArray } from "@/utils/types"; -import { Button } from "@blueprintjs/core"; +import { Button, Grid, GridItem, Text } from "@chakra-ui/react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import { SnapshotIn } from 'mobx-state-tree'; @@ -29,37 +29,41 @@ const BPMListItem = observer<{ }; return ( -
-
-
-
{t('common.time')}
-
- handleUpdate(e)} - className='bpm-input-beat' - /> -
-
-
-
BPM
-
- handleUpdate((void 0), e)} - /> -
-
-
-
- -
-
+ + + BPM + + + handleUpdate((void 0), e)} + /> + + ) }); diff --git a/src/ui/Panel/BPMPanel/List.tsx b/src/ui/Panel/BPMPanel/List.tsx index 08813f0..5651cc8 100644 --- a/src/ui/Panel/BPMPanel/List.tsx +++ b/src/ui/Panel/BPMPanel/List.tsx @@ -2,6 +2,7 @@ import { observer } from "mobx-react-lite"; import BPMListItem from "./Item"; import { sortByBeat } from "@/utils/math"; import { IBPM } from "@/core/models/BPM"; +import { Stack, For, StackSeparator } from "@chakra-ui/react"; const BPMList = observer<{ bpms: IBPM[], @@ -11,14 +12,16 @@ const BPMList = observer<{ const bpmList = bpms.slice().sort(sortByBeat); return ( -
- {bpmList.map((bpm) => ( - - ))} -
+ } p="2"> + + {(bpm) => ( + + )} + + ); }); diff --git a/src/ui/Panel/BPMPanel/styles.css b/src/ui/Panel/BPMPanel/styles.css deleted file mode 100644 index 44a3dc7..0000000 --- a/src/ui/Panel/BPMPanel/styles.css +++ /dev/null @@ -1,57 +0,0 @@ -.bpm-panel { - display: flex; - width: 100%; - height: 100%; - overflow: hidden; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; -} - -.bpm-offset { - padding: 8px; - padding-bottom: 0; -} - -.bpm-list { - overflow-x: hidden; - overflow-y: auto; - flex: 1; -} - -.bpm-list-item { - display: flex; - padding: 8px; - border-bottom: 1px solid var(--border-primary-color); - box-sizing: border-box; - align-items: center; -} -.bpm-list-item:last-child { - border-bottom: unset; -} -.bpm-list-item .bpm-props { - flex: 1; -} - -.bpm-prop { - display: flex; - flex-direction: row; - align-items: center; - flex-wrap: nowrap; -} - -.bpm-prop .bpm-prop-name { - flex: 0.4; -} - -.bpm-prop .bpm-prop-input { - flex: 0.6; -} - -.bpm-offset .bpm-prop .bpm-prop-name { - flex: 0.354; -} - -.bpm-offset .bpm-prop .bpm-prop-input { - flex: 0.646; -} diff --git a/src/ui/Panel/PreviewPanel/Canvas.tsx b/src/ui/Panel/PreviewPanel/Canvas.tsx index ac243a6..ded8a14 100644 --- a/src/ui/Panel/PreviewPanel/Canvas.tsx +++ b/src/ui/Panel/PreviewPanel/Canvas.tsx @@ -1,6 +1,7 @@ import { useEffect, useRef } from 'react'; import useResizeEffect from '@/ui/hooks/useResizeEffect'; import { app as previewApp } from '@/renderer/preview/app'; +import { Box } from '@chakra-ui/react'; const PreviewCanvas = () => { const containerRef = useRef(null); @@ -30,10 +31,9 @@ const PreviewCanvas = () => { }, containerRef); return ( -
+ > ); }; diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index d4a2776..2141f3a 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -1,4 +1,5 @@ import { useMemo } from 'react'; +import { Slider, Button, Stack, Center, HStack } from '@chakra-ui/react'; import { useRuntimeAudioStore } from '@/runtime/audio/state'; import Chart from '@/Chart/Chart'; import { useTempo } from '../../contexts/Tempo'; @@ -11,45 +12,47 @@ const PreviewController = () => { return ( <> -
- -
-
-
- - - - - -
-
+ + + + + + + + + +
+ + + + + + + +
+
); }; diff --git a/src/ui/Panel/PreviewPanel/PreviewPanel.tsx b/src/ui/Panel/PreviewPanel/PreviewPanel.tsx index 53946c6..020f9cf 100644 --- a/src/ui/Panel/PreviewPanel/PreviewPanel.tsx +++ b/src/ui/Panel/PreviewPanel/PreviewPanel.tsx @@ -1,17 +1,17 @@ import PreviewCanvas from './Canvas'; import PreviewController from './Controller'; -import './styles.css'; +import { Box, Stack } from '@chakra-ui/react'; const PreviewPanel = () => { return ( -
-
+ + -
-
+ + -
-
+ + ); }; diff --git a/src/ui/Panel/PreviewPanel/styles.css b/src/ui/Panel/PreviewPanel/styles.css deleted file mode 100644 index 871614d..0000000 --- a/src/ui/Panel/PreviewPanel/styles.css +++ /dev/null @@ -1,48 +0,0 @@ -.live-preview { - position: relative; - display: flex; - width: 100%; - height: 100%; - overflow: hidden; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; -} - -.live-preview .preview-canvas { - position: relative; - flex: 1; -} - -.live-preview .preview-canvas .canvas-container { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - overflow: hidden; -} - -.live-preview .preview-controller { - display: flex; - width: 100%; - flex-direction: column; - align-items: stretch; - flex-wrap: nowrap; -} - -.preview-controller .control-actions { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - justify-content: space-between; -} - -.control-actions .control-group.control-group-center { - display: flex; - flex-direction: row; - justify-content: center; - flex-wrap: nowrap; - flex: 1; -} diff --git a/src/ui/components/BeatInput.tsx b/src/ui/components/BeatInput.tsx index aea8376..d3dc1c0 100644 --- a/src/ui/components/BeatInput.tsx +++ b/src/ui/components/BeatInput.tsx @@ -1,5 +1,6 @@ import { useRef, useCallback, useEffect } from 'react'; import Input from '@/ui/components/NumberInput'; +import { HStack } from '@chakra-ui/react'; import { normalizeBeatArray } from '@/utils/math'; import { BeatArray } from '@/utils/types'; @@ -49,7 +50,7 @@ const BeatInput = ({ }, [beat]); return ( -
+ handleChanged(0, e)} onInput={(e) => handleInput(0, e)} /> - : + : handleInput(1, e)} /> - / + / handleChanged(2, e)} onInput={(e) => handleInput(2, e)} /> -
+ ); }; diff --git a/src/ui/components/NumberInput.tsx b/src/ui/components/NumberInput.tsx index 1c2dda3..f4c7590 100644 --- a/src/ui/components/NumberInput.tsx +++ b/src/ui/components/NumberInput.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import useDrag from '../hooks/useDrag'; import { ChangeEventHandler, KeyboardEventHandler } from 'react'; import { Nullable } from '@/utils/types'; +import { NumberInput as NumInput } from '@chakra-ui/react'; const getDragStep = (min?: number, max?: number) => { if (min !== (void 0) && max !== (void 0)) return (max - min) / 1000; @@ -153,19 +154,22 @@ const NumberInput = ({ }, [defaultValue]); return ( - + + + + ) }; diff --git a/src/ui/index.tsx b/src/ui/index.tsx index 31bd70b..1ed927f 100644 --- a/src/ui/index.tsx +++ b/src/ui/index.tsx @@ -1,3 +1,4 @@ +import { Provider } from "@/components/ui/provider" import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import '@/i18n' @@ -6,6 +7,8 @@ import App from './App.tsx' createRoot(document.getElementById('root')!).render( - + + + , ) From 703bfb56b195393b0dea75271c4dba914b9ac655 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sat, 6 Sep 2025 17:28:40 +0800 Subject: [PATCH 083/146] refactor(ui): Refactored Edit Panel --- src/ui/Panel/BPMPanel/BPMPanel.tsx | 2 +- src/ui/Panel/EditPanel/EditPanel.tsx | 14 +++++++----- src/ui/Panel/EditPanel/Input/Input.tsx | 4 +++- src/ui/Panel/EditPanel/Item/Beat.tsx | 2 +- src/ui/Panel/EditPanel/Item/Boolean.tsx | 19 ++++++++------- src/ui/Panel/EditPanel/Item/Container.tsx | 27 ++++++++++++---------- src/ui/Panel/EditPanel/Item/Dropdown.tsx | 28 +++++++++++++---------- src/ui/Panel/EditPanel/Item/Number.tsx | 18 +++++++++++---- src/ui/Panel/EditPanel/List.tsx | 6 ++--- src/ui/Panel/PreviewPanel/Controller.tsx | 25 +++++++++++++++----- 10 files changed, 90 insertions(+), 55 deletions(-) diff --git a/src/ui/Panel/BPMPanel/BPMPanel.tsx b/src/ui/Panel/BPMPanel/BPMPanel.tsx index 0e0d28d..4826b51 100644 --- a/src/ui/Panel/BPMPanel/BPMPanel.tsx +++ b/src/ui/Panel/BPMPanel/BPMPanel.tsx @@ -47,7 +47,7 @@ const BPMPanel = observer(() => { - + diff --git a/src/ui/Panel/EditPanel/EditPanel.tsx b/src/ui/Panel/EditPanel/EditPanel.tsx index cd0b5e3..d8a9487 100644 --- a/src/ui/Panel/EditPanel/EditPanel.tsx +++ b/src/ui/Panel/EditPanel/EditPanel.tsx @@ -5,10 +5,10 @@ import { useRuntimeStore } from '@/state/runtimeStore'; import { store as ChartStore } from '@/core/state/chartStore'; import List from './List'; import { KeyframePanelBuilderSingle, NotePanelBuilderSingle } from './builder'; +import { Box, Text, AbsoluteCenter } from '@chakra-ui/react'; import { Note } from '@/core/models/Note'; import { Keyframe } from '@/core/models/Keyframe'; import { UpdatedProps, UpdatedKeyframeProps, UpdatedNoteProps } from './types'; -import './styles.css'; // TODO: Multi-select const EditPanel = observer(() => { @@ -28,7 +28,7 @@ const EditPanel = observer(() => { }; return ( -
+ {( selectedNote ? ( { onChanged={handleValueChanged} /> ) : ( -
- {t('edit_panel.placeholder')} -
+ + + {t('edit_panel.placeholder')} + + ) )} -
+
) }); diff --git a/src/ui/Panel/EditPanel/Input/Input.tsx b/src/ui/Panel/EditPanel/Input/Input.tsx index b79ce2d..3884f90 100644 --- a/src/ui/Panel/EditPanel/Input/Input.tsx +++ b/src/ui/Panel/EditPanel/Input/Input.tsx @@ -1,5 +1,6 @@ import { Nullable } from "@/utils/types"; import { useCallback, useEffect, useRef, useState } from "react"; +import { Input } from "@chakra-ui/react"; type InputProps = { placeholder?: string, @@ -43,7 +44,8 @@ const EditPanelInput = ({ }, [defaultValue]); return ( - + ; @@ -9,18 +10,20 @@ const EditPanelBoolean = ({ onChanged, defaultValue, }: BooleanProps) => { - const handleInput = useCallback((e: React.ChangeEvent) => { - const target = e.target as HTMLInputElement; - onChanged(target.checked); + const handleInput = useCallback((e: { checked: string | boolean }) => { + onChanged(e.checked as boolean); }, [onChanged]); return ( - - + + onCheckedChange={handleInput} + my="2" + > + + + ); }; diff --git a/src/ui/Panel/EditPanel/Item/Container.tsx b/src/ui/Panel/EditPanel/Item/Container.tsx index a82d394..7d64c20 100644 --- a/src/ui/Panel/EditPanel/Item/Container.tsx +++ b/src/ui/Panel/EditPanel/Item/Container.tsx @@ -1,3 +1,5 @@ +import { Field, Grid, GridItem } from '@chakra-ui/react'; + type ItemContainerProps = { title: string, children: React.ReactNode, @@ -7,23 +9,24 @@ type ItemContainerProps = { const EditPanelItemContainer = ({ title, - children, - className, - useLabel, + children }: ItemContainerProps) => { const childrenDom = ( - <> -
{title}
-
{children}
- + + + {title} + + {children} + ); return ( - <> - {useLabel ? - : -
{childrenDom}
} - + {childrenDom} ); }; diff --git a/src/ui/Panel/EditPanel/Item/Dropdown.tsx b/src/ui/Panel/EditPanel/Item/Dropdown.tsx index 65a0d59..50f4c46 100644 --- a/src/ui/Panel/EditPanel/Item/Dropdown.tsx +++ b/src/ui/Panel/EditPanel/Item/Dropdown.tsx @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import Container from './Container'; import { PanelItemPropsBase } from '../types'; +import { NativeSelect } from "@chakra-ui/react" export type DropdownPropsBase = PanelItemPropsBase & { type?: 'string' | 'number', @@ -39,18 +40,21 @@ const EditPanelDropdown = ({ return ( - + + + {options.map((option) => { + return + })} + + + ); }; diff --git a/src/ui/Panel/EditPanel/Item/Number.tsx b/src/ui/Panel/EditPanel/Item/Number.tsx index 9f32c41..ec473c3 100644 --- a/src/ui/Panel/EditPanel/Item/Number.tsx +++ b/src/ui/Panel/EditPanel/Item/Number.tsx @@ -1,6 +1,6 @@ import Container from './Container'; import Input from '@/ui/components/NumberInput'; -import Slider from '../Input/Slider'; +import { Slider } from '@chakra-ui/react'; import { PanelItemPropsBase } from "../types"; export type NumberProps = PanelItemPropsBase & { @@ -36,13 +36,21 @@ const EditPanelNumber = ({ {min !== (void 0) && max !== (void 0) && useSlider ? ( <> - + defaultValue={[defaultValue ?? (min ?? 0)]} + onValueChange={(e) => onChanged(e.value[0])} + > + + + + + + + {inputDom} ) : inputDom} diff --git a/src/ui/Panel/EditPanel/List.tsx b/src/ui/Panel/EditPanel/List.tsx index 64c2bc9..b71c349 100644 --- a/src/ui/Panel/EditPanel/List.tsx +++ b/src/ui/Panel/EditPanel/List.tsx @@ -7,6 +7,7 @@ import { StringProps } from "./Item/String"; import InputBeat, { BeatProps } from "./Item/Beat"; import { BeatArray } from "@/utils/types"; import { UpdatedProps, UpdatedPropsKey } from "./types"; +import { Stack } from "@chakra-ui/react"; type PropsMovedDefault = 'label' | 'onChanged'; @@ -66,10 +67,9 @@ const EditPanelList = ({ }, [onChanged]); return ( -
+ {items.map((item) => { const itemKey = `${id}.${item.key}`; - if (item.type === 'beat') return ( handleValueChanged(item.key, e)} key={itemKey} /> ); @@ -84,7 +84,7 @@ const EditPanelList = ({ ); return null; })} -
+ ); }; diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index 2141f3a..d695b8c 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -4,9 +4,12 @@ import { useRuntimeAudioStore } from '@/runtime/audio/state'; import Chart from '@/Chart/Chart'; import { useTempo } from '../../contexts/Tempo'; import { GridValue } from '@/utils/math'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faPlay, faPause, faStepForward, faStepBackward, faFastBackward, faFastForward } from "@fortawesome/free-solid-svg-icons"; const PreviewController = () => { - const playClip = useRuntimeAudioStore((s) => s.play); + const currentStatus = useRuntimeAudioStore((s) => s.status); + const playClip = useRuntimeAudioStore((s) => s.status === 1 ? s.play : s.pause); const tempo = useTempo(); const tempoGrid = useMemo(() => 1 / tempo, [tempo]); @@ -28,28 +31,38 @@ const PreviewController = () => { if (!Chart.info) return; Chart.beatNum = GridValue(Chart.beatNum - 1, 1); }} - >Prev beat + > + + + > + + + > + + + > + + + > + + From 695b66fb313095027daa64c28f74a39e572af765 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 05:22:00 +0800 Subject: [PATCH 084/146] refactor(ui): Refactored Settings Panel & Polish --- src/ui/Panel/EditPanel/Item/Combobox.tsx | 83 ++++++++++++++++++++ src/ui/Panel/EditPanel/Item/Select.tsx | 80 +++++++++++++++++++ src/ui/Panel/EditPanel/List.tsx | 22 +++++- src/ui/Panel/EditPanel/builder.ts | 4 +- src/ui/Panel/EditPanel/styles.css | 55 ------------- src/ui/Panel/SettingsPanel/Item.tsx | 30 ++----- src/ui/Panel/SettingsPanel/Rendering.tsx | 34 ++++---- src/ui/Panel/SettingsPanel/SettingsPanel.tsx | 22 +++--- src/ui/Panel/SettingsPanel/styles.css | 11 --- 9 files changed, 223 insertions(+), 118 deletions(-) create mode 100644 src/ui/Panel/EditPanel/Item/Combobox.tsx create mode 100644 src/ui/Panel/EditPanel/Item/Select.tsx delete mode 100644 src/ui/Panel/EditPanel/styles.css delete mode 100644 src/ui/Panel/SettingsPanel/styles.css diff --git a/src/ui/Panel/EditPanel/Item/Combobox.tsx b/src/ui/Panel/EditPanel/Item/Combobox.tsx new file mode 100644 index 0000000..d80ae80 --- /dev/null +++ b/src/ui/Panel/EditPanel/Item/Combobox.tsx @@ -0,0 +1,83 @@ +import Container from './Container'; +import { PanelItemPropsBase } from '../types'; +import { Portal, Combobox, useFilter, useListCollection, createListCollection } from "@chakra-ui/react" + +export type ComboboxPropsBase = PanelItemPropsBase & { + type?: 'string' | 'number', + options: { + value: string | number, + label: string, + disabled?: boolean, + }[], +}; + +export type ComboboxPropsNumber = ComboboxPropsBase & { + type: 'number', + onChanged: (newValue: number) => void, + options: { + value: number, + label: string, + disabled?: boolean, + }[], + defaultValue?: number, +}; + +export type ComboboxProps = ComboboxPropsBase | ComboboxPropsNumber; + +const EditPanelCombobox = ({ + label, + options, + type = 'string', + onChanged, + defaultValue, +}: ComboboxProps) => { + const { contains } = useFilter({ sensitivity: "base" }) + const { collection, filter } = useListCollection({ + initialItems: options, + filter: contains, + }) + + const handleValueChanged = (e: string) => { + if (type === 'number') { + const newValue = parseFloat(e); + if (isNaN(newValue)) return; + onChanged(newValue); + } else { + onChanged(e); + } + }; + + return ( + + handleValueChanged(e.value[0])} + defaultValue={[defaultValue as string]} + onInputValueChange={(e) => filter(e.inputValue)} + > + + + + + + + + + + No items found + {collection.items.map((item: any) => ( + + {item.label} + + + ))} + + + + + + ); +}; + +export default EditPanelCombobox; diff --git a/src/ui/Panel/EditPanel/Item/Select.tsx b/src/ui/Panel/EditPanel/Item/Select.tsx new file mode 100644 index 0000000..38866e4 --- /dev/null +++ b/src/ui/Panel/EditPanel/Item/Select.tsx @@ -0,0 +1,80 @@ +import Container from './Container'; +import { PanelItemPropsBase } from '../types'; +import { Portal, Select, createListCollection } from "@chakra-ui/react" + +export type SelectPropsBase = PanelItemPropsBase & { + type?: 'string' | 'number', + options: { + value: string | number, + label: string, + disabled?: boolean, + }[], +}; + +export type SelectPropsNumber = SelectPropsBase & { + type: 'number', + onChanged: (newValue: number) => void, + options: { + value: number, + label: string, + disabled?: boolean, + }[], + defaultValue?: number, +}; + +export type SelectProps = SelectPropsBase | SelectPropsNumber; + +const EditPanelSelect = ({ + label, + options, + type = 'string', + onChanged, + defaultValue, +}: SelectProps) => { + const editOptions = createListCollection({items: options}) + + const handleValueChanged = (e: string) => { + if (type === 'number') { + const newValue = parseFloat(e); + if (isNaN(newValue)) return; + onChanged(newValue); + } else { + onChanged(e); + } + }; + + return ( + + handleValueChanged(e.value[0])} + defaultValue={[defaultValue as string]} + > + + + + + + + + + + + + + {editOptions.items.map((editOption: any) => ( + + {editOption.label} + + + ))} + + + + + + ); +}; + +export default EditPanelSelect; diff --git a/src/ui/Panel/EditPanel/List.tsx b/src/ui/Panel/EditPanel/List.tsx index b71c349..49cf575 100644 --- a/src/ui/Panel/EditPanel/List.tsx +++ b/src/ui/Panel/EditPanel/List.tsx @@ -2,6 +2,8 @@ import { useCallback } from "react"; import { useTranslation } from "react-i18next"; import InputBoolean, { BooleanProps } from "./Item/Boolean"; import InputDropdown, { DropdownProps } from "./Item/Dropdown"; +import InputSelect, { SelectProps } from "./Item/Select"; +import InputCombobox, { ComboboxProps } from "./Item/Combobox"; import InputNumber, { NumberProps } from "./Item/Number"; import { StringProps } from "./Item/String"; import InputBeat, { BeatProps } from "./Item/Beat"; @@ -14,7 +16,7 @@ type PropsMovedDefault = 'label' | 'onChanged'; type EditPanelItemBase = { key: UpdatedPropsKey, label: string, - type: 'number' | 'string' | 'boolean' | 'dropdown' | 'beat', + type: 'number' | 'string' | 'boolean' | 'dropdown' | 'select' | 'combobox' | 'beat', i18n: string, }; @@ -38,12 +40,22 @@ type EditPanelItemDropdown = EditPanelItemBase & { props: Omit, }; +type EditPanelItemSelect = EditPanelItemBase & { + type:'select', + props: Omit, +}; + +type EditPanelItemCombobox = EditPanelItemBase & { + type: 'combobox', + props: Omit, +}; + type EditPanelItemBeat = EditPanelItemBase & { type: 'beat', props: Omit, }; -export type EditPanelItem = EditPanelItemNumber | EditPanelItemString | EditPanelItemBoolean | EditPanelItemDropdown | EditPanelItemBeat; +export type EditPanelItem = EditPanelItemNumber | EditPanelItemString | EditPanelItemBoolean | EditPanelItemDropdown | EditPanelItemSelect | EditPanelItemCombobox | EditPanelItemBeat; type EditPanelListProps = { id: string, @@ -82,6 +94,12 @@ const EditPanelList = ({ if (item.type === 'dropdown') return ( handleValueChanged(item.key, e)} key={itemKey} /> ); + if (item.type === 'select') return ( + handleValueChanged(item.key, e)} key={itemKey} /> + ); + if (item.type === 'combobox') return ( + handleValueChanged(item.key, e)} key={itemKey} /> + ); return null; })} diff --git a/src/ui/Panel/EditPanel/builder.ts b/src/ui/Panel/EditPanel/builder.ts index 2f32b30..47b190a 100644 --- a/src/ui/Panel/EditPanel/builder.ts +++ b/src/ui/Panel/EditPanel/builder.ts @@ -47,7 +47,7 @@ export const KeyframePanelBuilderSingle = (keyframe: IKeyframe): EditPanelItem[] if (keyframe.type !== KeyframeType.Speed) result.push({ label: 'Easing', i18n: 'keyframe.easing', - type: 'dropdown', + type: 'combobox', key: 'easing', props: { type: 'number', @@ -68,7 +68,7 @@ export const NotePanelBuilderSingle = (note: INote): EditPanelItem[] => ([ { label: 'Type', i18n: 'common.type', - type: 'dropdown', + type: 'select', key: 'type', props: { type: 'string', diff --git a/src/ui/Panel/EditPanel/styles.css b/src/ui/Panel/EditPanel/styles.css deleted file mode 100644 index a9c6d20..0000000 --- a/src/ui/Panel/EditPanel/styles.css +++ /dev/null @@ -1,55 +0,0 @@ -.edit-panel { - position: relative; - width: 100%; - min-height: 40px; - height: 100%; - overflow-x: hidden; - overflow-y: auto; -} - -.edit-panel-placeholder { - position: absolute; - top: 50%; - width: 100%; - text-align: center; - transform: translateY(-50%); -} - -.edit-panel-item { - display: flex; - margin: 4px 0px; - width: 100%; -} - -.edit-panel-item .edit-panel-item-label { - display: block; - flex: 0.4; -} - -.edit-panel-item .edit-panel-item-input { - display: block; - flex: 0.6; -} - -.edit-panel-slider { - --value-percent: 0; - - position: relative; - display: block; - height: 24px; - border: 1px solid var(--border-secondary-color); - border-radius: 4px; - overflow: hidden; - cursor: ew-resize; -} - -.edit-panel-slider::before { - content: ''; - position: absolute; - top: 0px; - left: calc(var(--value-percent) * 100%); - width: 2px; - height: 100%; - transform: translateX(-50%); - background: var(--background-primary-color); -} diff --git a/src/ui/Panel/SettingsPanel/Item.tsx b/src/ui/Panel/SettingsPanel/Item.tsx index 51894cd..98468ce 100644 --- a/src/ui/Panel/SettingsPanel/Item.tsx +++ b/src/ui/Panel/SettingsPanel/Item.tsx @@ -1,35 +1,21 @@ -import { Card, FormGroup, Intent } from '@blueprintjs/core'; +import { Card } from '@chakra-ui/react'; type SettingsItemProps = { label: string, - children: React.ReactNode, - labelInfo?: string, - helperText?: string, - intent?: Intent, - disabled?: boolean, + children: React.ReactNode }; const SettingsItem = ({ label, - children, - labelInfo, - helperText, - intent, - disabled, + children }: SettingsItemProps) => { return ( - - + + + {label} {children} - - + + ); }; diff --git a/src/ui/Panel/SettingsPanel/Rendering.tsx b/src/ui/Panel/SettingsPanel/Rendering.tsx index b1bc7c7..29ab7e4 100644 --- a/src/ui/Panel/SettingsPanel/Rendering.tsx +++ b/src/ui/Panel/SettingsPanel/Rendering.tsx @@ -1,4 +1,4 @@ -import { CardList, Slider } from '@blueprintjs/core'; +import { Stack, Slider } from '@chakra-ui/react'; import Settings from '@/Settings/Settings'; import Item from './Item'; import { useSettings } from '@/ui/contexts/Settings'; @@ -12,20 +12,26 @@ const SettingsRendering = () => { }; return ( - - + + updateNoteScale(e.value[0])} > - - - + + + + + + + + + ); }; diff --git a/src/ui/Panel/SettingsPanel/SettingsPanel.tsx b/src/ui/Panel/SettingsPanel/SettingsPanel.tsx index 32429e2..3f9878a 100644 --- a/src/ui/Panel/SettingsPanel/SettingsPanel.tsx +++ b/src/ui/Panel/SettingsPanel/SettingsPanel.tsx @@ -1,19 +1,17 @@ -import { Tab, Tabs } from '@blueprintjs/core'; +import { Tabs } from '@chakra-ui/react'; import SettingsRendering from './Rendering'; -import './styles.css'; const SettingsPanel = () => { return ( - - } /> - + + + Rendering + + + + + ); }; -export default SettingsPanel; +export default SettingsPanel; \ No newline at end of file diff --git a/src/ui/Panel/SettingsPanel/styles.css b/src/ui/Panel/SettingsPanel/styles.css deleted file mode 100644 index 34132a8..0000000 --- a/src/ui/Panel/SettingsPanel/styles.css +++ /dev/null @@ -1,11 +0,0 @@ -.settings-panel { - width: 100%; - max-height: 100%; - overflow: hidden; -} - -.settings-panel .bp5-tab-panel { - width: 100%; - overflow-y: auto; - flex: 1; -} \ No newline at end of file From cfd1ba7e3e8e4b178849b47f56c22013dc210f01 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 05:29:57 +0800 Subject: [PATCH 085/146] fix(ui): Bring back `useLabel` --- src/ui/Panel/EditPanel/Item/Boolean.tsx | 2 +- src/ui/Panel/EditPanel/Item/Combobox.tsx | 2 +- src/ui/Panel/EditPanel/Item/Container.tsx | 9 +++++---- src/ui/Panel/EditPanel/Item/Dropdown.tsx | 2 +- src/ui/Panel/EditPanel/Item/Number.tsx | 2 +- src/ui/Panel/EditPanel/Item/Select.tsx | 2 +- src/ui/Panel/EditPanel/Item/String.tsx | 2 +- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ui/Panel/EditPanel/Item/Boolean.tsx b/src/ui/Panel/EditPanel/Item/Boolean.tsx index 2f968fe..f67a5e8 100644 --- a/src/ui/Panel/EditPanel/Item/Boolean.tsx +++ b/src/ui/Panel/EditPanel/Item/Boolean.tsx @@ -15,7 +15,7 @@ const EditPanelBoolean = ({ }, [onChanged]); return ( - + + { const childrenDom = ( - {title} + {useLabel ? {title} : {title}} {children} ); return ( - {childrenDom} + useLabel ? {childrenDom} : {childrenDom} ); }; diff --git a/src/ui/Panel/EditPanel/Item/Dropdown.tsx b/src/ui/Panel/EditPanel/Item/Dropdown.tsx index 50f4c46..00fe3b2 100644 --- a/src/ui/Panel/EditPanel/Item/Dropdown.tsx +++ b/src/ui/Panel/EditPanel/Item/Dropdown.tsx @@ -39,7 +39,7 @@ const EditPanelDropdown = ({ }, [type, onChanged]); return ( - + + {min !== (void 0) && max !== (void 0) && useSlider ? ( <> + { return ( - + Date: Sun, 7 Sep 2025 05:31:02 +0800 Subject: [PATCH 086/146] fix(ui/Panel/EditPanel): typo i guess --- src/ui/Panel/EditPanel/Item/Combobox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/Panel/EditPanel/Item/Combobox.tsx b/src/ui/Panel/EditPanel/Item/Combobox.tsx index c0ebb4d..6784eeb 100644 --- a/src/ui/Panel/EditPanel/Item/Combobox.tsx +++ b/src/ui/Panel/EditPanel/Item/Combobox.tsx @@ -1,6 +1,6 @@ import Container from './Container'; import { PanelItemPropsBase } from '../types'; -import { Portal, Combobox, useFilter, useListCollection, createListCollection } from "@chakra-ui/react" +import { Portal, Combobox, useFilter, useListCollection } from "@chakra-ui/react" export type ComboboxPropsBase = PanelItemPropsBase & { type?: 'string' | 'number', From 091bead8b9e85fb1a21f59dccdd47b46e28adc0a Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 17:23:46 +0800 Subject: [PATCH 087/146] refactor(ui): Refactor Note Panel --- src/ui/Panel/NotePanel/BottomBar.tsx | 55 +++++++++++++++++ src/ui/Panel/NotePanel/NotePanel.tsx | 92 +++------------------------- src/ui/Panel/NotePanel/TopBar.tsx | 53 ++++++++++++++++ 3 files changed, 117 insertions(+), 83 deletions(-) create mode 100644 src/ui/Panel/NotePanel/BottomBar.tsx create mode 100644 src/ui/Panel/NotePanel/TopBar.tsx diff --git a/src/ui/Panel/NotePanel/BottomBar.tsx b/src/ui/Panel/NotePanel/BottomBar.tsx new file mode 100644 index 0000000..01c6d9f --- /dev/null +++ b/src/ui/Panel/NotePanel/BottomBar.tsx @@ -0,0 +1,55 @@ +import { Flex, Slider, HStack, Text } from '@chakra-ui/react'; +import { useTranslation } from 'react-i18next'; +import NumberInput from '@/ui/components/NumberInput'; + +type BottomBarProps = { + onScaleChange: (scale: number) => void, + onAlignChange: (align: number) => void, +}; + +const BottomBar = ({ + onScaleChange, + onAlignChange, +}: BottomBarProps) => { + const { t } = useTranslation(); + + return ( + + + {t('common.scale')} + onScaleChange(e.value[0])} + > + + + + + + + + + + + + {t('common.align')} + + + + ); +}; + +export default BottomBar; \ No newline at end of file diff --git a/src/ui/Panel/NotePanel/NotePanel.tsx b/src/ui/Panel/NotePanel/NotePanel.tsx index bb636d2..baff268 100644 --- a/src/ui/Panel/NotePanel/NotePanel.tsx +++ b/src/ui/Panel/NotePanel/NotePanel.tsx @@ -1,15 +1,15 @@ -import { ChangeEvent, useCallback, useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useCallback, useState } from 'react'; import { useRuntimeStore } from '@/state/runtimeStore'; import Grid from './Grid'; import './styles.css'; import PropsContext from './PropsContext'; import { Nullable } from '@/utils/types'; import { NoteType } from '@/core/types'; -import NumberInput from '@/ui/components/NumberInput'; +import TopBar, { EditModeType } from './TopBar'; +import BottomBar from './BottomBar'; +import { Stack } from '@chakra-ui/react'; const NotePanel = () => { - const { t } = useTranslation(); const [ writeMode, setWriteMode ] = useState>(null); const [ scale, setScale ] = useState(200); const [ alignCount, setAlighCount ] = useState(8); @@ -17,8 +17,7 @@ const NotePanel = () => { const setSelectedNote = useRuntimeStore((s) => s.setSelectedNote); const setSelectedKeyframe = useRuntimeStore((s) => s.setSelectedKeyframe); - const updateWriteMode = (e: ChangeEvent) => { - const newMode = e.target.value as (NoteType | 'select'); + const updateWriteMode = (newMode: EditModeType) => { if (newMode === 'select') setWriteMode(null); else { setWriteMode(newMode); @@ -32,57 +31,8 @@ const NotePanel = () => { }, []); return ( -
-
-
- {t('note_panel.mode_select.title')} - - - - - -
-
+ + { }}> -
- - -
-
+ + ); }; diff --git a/src/ui/Panel/NotePanel/TopBar.tsx b/src/ui/Panel/NotePanel/TopBar.tsx new file mode 100644 index 0000000..8c0adc6 --- /dev/null +++ b/src/ui/Panel/NotePanel/TopBar.tsx @@ -0,0 +1,53 @@ +import { NoteType } from '@/core/types'; +import { useTranslation } from 'react-i18next'; +import { Flex, HStack, RadioGroup, For, Text } from '@chakra-ui/react'; + +export type EditModeType = NoteType | 'select'; + +type TopBarProps = { + writeMode: EditModeType, + onChange: (newMode: EditModeType) => void, +}; + +const TopBar = ({ + writeMode, + onChange, +}: TopBarProps) => { + const { t } = useTranslation(); + const radioItems = [ + { label: t('note_panel.mode_select.select'), value: 'select' }, + { label: t('note.type.tap'), value: NoteType.Tap }, + { label: t('note.type.hold'), value: NoteType.Hold }, + { label: t('note.type.drag'), value: NoteType.Drag }, + { label: t('note.type.flick'), value: NoteType.Flick }, + ] + + return ( + + + {t('note_panel.mode_select.title')} + onChange(e.value as EditModeType)} + > + + + {item => ( + + + + {item.label} + + )} + + + + + + ); +}; + + +export default TopBar; \ No newline at end of file From 7491791681aa62a3adb1a58f442c29350a652855 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Sun, 7 Sep 2025 20:46:16 +0800 Subject: [PATCH 088/146] refactor(ui): Refactor Menu Bar --- package.json | 2 + pnpm-lock.yaml | 763 +++++++++++++++++- src/ui/Bar/ActivityBar.tsx | 26 + src/ui/Bar/AppBar.tsx | 19 - .../{TopBar/Menu/File => }/CreateProject.tsx | 9 +- src/ui/Bar/Menu.tsx | 158 ++++ src/ui/Bar/TopBar/Menu/File/File.tsx | 21 - src/ui/Bar/TopBar/Menu/Menu.tsx | 11 - src/ui/Bar/TopBar/TopBar.tsx | 12 - src/ui/Bar/styles.css | 10 - src/ui/Panel/BPMPanel/BPMPanel.tsx | 2 +- src/ui/Panel/BPMPanel/Item.tsx | 2 +- src/ui/Panel/PanelDock.tsx | 2 +- src/ui/Panel/PreviewPanel/Controller.tsx | 14 +- src/ui/Panel/SettingsPanel/SettingsPanel.tsx | 2 +- src/ui/index.tsx | 5 +- src/ui/styles/index.css | 218 +---- 17 files changed, 949 insertions(+), 327 deletions(-) create mode 100644 src/ui/Bar/ActivityBar.tsx delete mode 100644 src/ui/Bar/AppBar.tsx rename src/ui/Bar/{TopBar/Menu/File => }/CreateProject.tsx (93%) create mode 100644 src/ui/Bar/Menu.tsx delete mode 100644 src/ui/Bar/TopBar/Menu/File/File.tsx delete mode 100644 src/ui/Bar/TopBar/Menu/Menu.tsx delete mode 100644 src/ui/Bar/TopBar/TopBar.tsx delete mode 100644 src/ui/Bar/styles.css diff --git a/package.json b/package.json index 9274625..2cc1db5 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@fortawesome/react-fontawesome": "^0.2.2", "@phifans/audio": "^0.0.7", "@pixi/react": "8.0.0", + "@radix-ui/react-menubar": "^1.1.16", "@types/node": "^22.10.5", "@zenfs/core": "^2.4.0", "@zenfs/dom": "^1.2.4", @@ -53,6 +54,7 @@ "setimmediate": "^1.0.5", "spark-md5": "^3.0.2", "unstorage": "^1.17.1", + "styled-components": "^6.1.19", "uuid": "^11.0.4", "zustand": "^5.0.8" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 459d477..e81a1e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,6 +37,9 @@ importers: '@pixi/react': specifier: 8.0.0 version: 8.0.0(@types/react@19.0.7)(pixi.js@8.6.6)(react@19.0.0) + '@radix-ui/react-menubar': + specifier: ^1.1.16 + version: 1.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@types/node': specifier: ^22.10.5 version: 22.10.5 @@ -109,6 +112,9 @@ importers: spark-md5: specifier: ^3.0.2 version: 3.0.2 + styled-components: + specifier: ^6.1.19 + version: 6.1.19(react-dom@19.0.0(react@19.0.0))(react@19.0.0) uuid: specifier: ^11.0.4 version: 11.0.4 @@ -271,9 +277,15 @@ packages: '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + '@emotion/is-prop-valid@1.2.2': + resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} + '@emotion/is-prop-valid@1.4.0': resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} + '@emotion/memoize@0.8.1': + resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + '@emotion/memoize@0.9.0': resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} @@ -295,6 +307,9 @@ packages: '@emotion/unitless@0.10.0': resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + '@emotion/unitless@0.8.1': + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: @@ -655,6 +670,12 @@ packages: '@floating-ui/dom@1.7.4': resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} @@ -753,6 +774,272 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menubar@1.1.16': + resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rollup/rollup-android-arm-eabi@4.34.7': resolution: {integrity: sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==} cpu: [arm] @@ -1067,6 +1354,9 @@ packages: '@types/spark-md5@3.0.5': resolution: {integrity: sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg==} + '@types/stylis@4.2.5': + resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} + '@typescript-eslint/eslint-plugin@8.18.2': resolution: {integrity: sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1402,6 +1692,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -1487,6 +1781,9 @@ packages: camel-case@4.1.2: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + camelize@1.0.1: + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} + capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -1550,6 +1847,13 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-color-keywords@1.0.0: + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} + + css-to-react-native@3.2.0: + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1598,6 +1902,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dockview-core@4.7.1: resolution: {integrity: sha512-Tia3vYHtqACMZTiZv86yQOabwKj5KrBhQqlSr7qXV0qmmRSZ8dNbaU63LIHYFprST7JgHupIm9JVES+OhqMoTQ==} @@ -1821,6 +2128,10 @@ packages: resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -2365,6 +2676,13 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.2: resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} engines: {node: ^10 || ^12 || >=14} @@ -2446,6 +2764,26 @@ packages: peerDependencies: react: ^19.0.0 + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-split-pane@0.1.92: resolution: {integrity: sha512-GfXP1xSzLMcLJI5BM36Vh7GgZBpy+U/X0no+VM3fxayv+p1Jly5HpMofZJraeaMl73b3hvlr+N9zJKvLB/uz9w==} peerDependencies: @@ -2455,6 +2793,16 @@ packages: react-style-proptype@3.2.2: resolution: {integrity: sha512-ywYLSjNkxKHiZOqNlso9PZByNEY+FTyh3C+7uuziK0xFXu9xzdyfHwg4S9iyiRRoPCR4k2LqaBBsWVmSBwCWYQ==} + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -2560,6 +2908,9 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2651,9 +3002,19 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + styled-components@6.1.19: + resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} + engines: {node: '>= 16'} + peerDependencies: + react: '>= 16.8.0' + react-dom: '>= 16.8.0' + stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + stylis@4.3.2: + resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -2698,6 +3059,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} @@ -2759,6 +3123,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.4.0: resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} peerDependencies: @@ -3124,10 +3508,16 @@ snapshots: '@emotion/hash@0.9.2': {} + '@emotion/is-prop-valid@1.2.2': + dependencies: + '@emotion/memoize': 0.8.1 + '@emotion/is-prop-valid@1.4.0': dependencies: '@emotion/memoize': 0.9.0 + '@emotion/memoize@0.8.1': {} + '@emotion/memoize@0.9.0': {} '@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0)': @@ -3158,6 +3548,8 @@ snapshots: '@emotion/unitless@0.10.0': {} + '@emotion/unitless@0.8.1': {} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': dependencies: react: 19.0.0 @@ -3371,6 +3763,12 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 + '@floating-ui/react-dom@2.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + '@floating-ui/utils@0.2.10': {} '@fortawesome/fontawesome-common-types@6.7.2': {} @@ -3469,6 +3867,249 @@ snapshots: '@popperjs/core@2.11.8': {} + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-context@1.1.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-direction@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-id@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + aria-hidden: 1.2.6 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-remove-scroll: 2.7.1(@types/react@19.0.7)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/rect': 1.1.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + '@types/react-dom': 19.0.3(@types/react@19.0.7) + + '@radix-ui/react-slot@1.2.3(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.0.7)(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.0.7)(react@19.0.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.7)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.7 + + '@radix-ui/rect@1.1.1': {} + '@rollup/rollup-android-arm-eabi@4.34.7': optional: true @@ -3672,6 +4313,8 @@ snapshots: '@types/spark-md5@3.0.5': {} + '@types/stylis@4.2.5': {} + '@typescript-eslint/eslint-plugin@8.18.2(@typescript-eslint/parser@8.18.2(eslint@9.17.0)(typescript@5.6.3))(eslint@9.17.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -4324,6 +4967,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.3 @@ -4448,12 +5095,14 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.6.3 + tslib: 2.8.1 + + camelize@1.0.1: {} capital-case@1.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 upper-case-first: 2.0.2 chalk@4.1.2: @@ -4474,7 +5123,7 @@ snapshots: path-case: 3.0.4 sentence-case: 3.0.4 snake-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 chokidar@3.6.0: dependencies: @@ -4513,7 +5162,7 @@ snapshots: constant-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 upper-case: 2.0.2 convert-source-map@1.9.0: {} @@ -4538,6 +5187,14 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-color-keywords@1.0.0: {} + + css-to-react-native@3.2.0: + dependencies: + camelize: 1.0.1 + css-color-keywords: 1.0.0 + postcss-value-parser: 4.2.0 + csstype@3.1.3: {} data-uri-to-buffer@4.0.1: {} @@ -4582,6 +5239,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + detect-node-es@1.1.0: {} + dockview-core@4.7.1: {} dockview@4.7.1(react@19.0.0): @@ -4601,7 +5260,7 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 dunder-proto@1.0.1: dependencies: @@ -4973,6 +5632,8 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -5048,7 +5709,7 @@ snapshots: header-case@2.0.4: dependencies: capital-case: 1.0.4 - tslib: 2.6.3 + tslib: 2.8.1 hoist-non-react-statics@3.3.2: dependencies: @@ -5296,7 +5957,7 @@ snapshots: lower-case@2.0.2: dependencies: - tslib: 2.6.3 + tslib: 2.8.1 lru-cache@10.4.3: {} @@ -5362,7 +6023,7 @@ snapshots: no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.6.3 + tslib: 2.8.1 node-domexception@1.0.0: {} @@ -5461,7 +6122,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 parent-module@1.0.1: dependencies: @@ -5479,12 +6140,12 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 path-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 path-exists@4.0.0: {} @@ -5525,6 +6186,14 @@ snapshots: possible-typed-array-names@1.0.0: {} + postcss-value-parser@4.2.0: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.2: dependencies: nanoid: 3.3.8 @@ -5594,6 +6263,25 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-remove-scroll-bar@2.3.8(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + + react-remove-scroll@2.7.1(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.0.7)(react@19.0.0) + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.0.7)(react@19.0.0) + use-sidecar: 1.1.3(@types/react@19.0.7)(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.7 + react-split-pane@0.1.92(patch_hash=15b3bc41b3c9ea6e7a5c245069978ef071c4655082c4e9b0e14eb5d4eb57da5c)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: prop-types: 15.8.1 @@ -5606,6 +6294,14 @@ snapshots: dependencies: prop-types: 15.8.1 + react-style-singleton@2.2.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + get-nonce: 1.0.1 + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime': 7.26.10 @@ -5618,7 +6314,7 @@ snapshots: react-uid@2.4.0(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 - tslib: 2.6.3 + tslib: 2.8.1 optionalDependencies: '@types/react': 19.0.7 @@ -5725,7 +6421,7 @@ snapshots: sentence-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 upper-case-first: 2.0.2 set-function-length@1.2.2: @@ -5752,6 +6448,8 @@ snapshots: setimmediate@1.0.5: {} + shallowequal@1.1.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -5797,7 +6495,7 @@ snapshots: snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.6.3 + tslib: 2.8.1 source-map-js@1.2.1: {} @@ -5871,8 +6569,24 @@ snapshots: strip-json-comments@3.1.1: {} + styled-components@6.1.19(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@emotion/is-prop-valid': 1.2.2 + '@emotion/unitless': 0.8.1 + '@types/stylis': 4.2.5 + css-to-react-native: 3.2.0 + csstype: 3.1.3 + postcss: 8.4.49 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + shallowequal: 1.1.0 + stylis: 4.3.2 + tslib: 2.6.2 + stylis@4.2.0: {} + stylis@4.3.2: {} + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -5913,6 +6627,8 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@2.6.2: {} + tslib@2.6.3: {} tslib@2.8.1: {} @@ -5979,11 +6695,11 @@ snapshots: upper-case-first@2.0.2: dependencies: - tslib: 2.6.3 + tslib: 2.8.1 upper-case@2.0.2: dependencies: - tslib: 2.6.3 + tslib: 2.8.1 uqr@0.1.2: {} @@ -5991,6 +6707,21 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + + use-sidecar@1.1.3(@types/react@19.0.7)(react@19.0.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.0.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.0.7 + use-sync-external-store@1.4.0(react@19.0.0): dependencies: react: 19.0.0 diff --git a/src/ui/Bar/ActivityBar.tsx b/src/ui/Bar/ActivityBar.tsx new file mode 100644 index 0000000..1963d77 --- /dev/null +++ b/src/ui/Bar/ActivityBar.tsx @@ -0,0 +1,26 @@ +import NumberInput from '@/ui/components/NumberInput'; +import { HStack, Text } from '@chakra-ui/react'; + +type ActivityBarProps = { + handleTempoUpdate: (tempo: number) => void, +}; + +const ActivityBar = ({ handleTempoUpdate }: ActivityBarProps) => { + return ( + + Set tempo: 1/ + + + ); +}; + +export default ActivityBar; \ No newline at end of file diff --git a/src/ui/Bar/AppBar.tsx b/src/ui/Bar/AppBar.tsx deleted file mode 100644 index e60f8a3..0000000 --- a/src/ui/Bar/AppBar.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import './styles.css'; - -type AppBarProps = { - className?: string, - children?: React.ReactNode, -}; - -const AppBar = ({ - className, - children -}: AppBarProps) => { - return ( -
- {children} -
- ); -}; - -export default AppBar; diff --git a/src/ui/Bar/TopBar/Menu/File/CreateProject.tsx b/src/ui/Bar/CreateProject.tsx similarity index 93% rename from src/ui/Bar/TopBar/Menu/File/CreateProject.tsx rename to src/ui/Bar/CreateProject.tsx index ed8edc5..da66445 100644 --- a/src/ui/Bar/TopBar/Menu/File/CreateProject.tsx +++ b/src/ui/Bar/CreateProject.tsx @@ -1,4 +1,4 @@ -import { Button, DialogBody, DialogFooter, FileInput, FormGroup, MenuItem } from '@blueprintjs/core'; +import { Button, DialogBody, DialogFooter, FileInput, FormGroup } from '@blueprintjs/core'; import { useRef } from 'react'; import Chart from '@/Chart/Chart'; import ProjectPanel from '@/ui/Panel/ProjectPanel/ProjectPanel'; @@ -13,7 +13,7 @@ type ProjectMeta = ChartInfo & { background: File, }; -const CreateProject = () => { +const CreateProject = ({ Hachimi }: any) => { const { show: showDialog, close: closeDialog } = useDialog(); const newProjectMeta = useRef>({}); @@ -130,10 +130,7 @@ const CreateProject = () => { }; return ( - + Create Project ); }; diff --git a/src/ui/Bar/Menu.tsx b/src/ui/Bar/Menu.tsx new file mode 100644 index 0000000..e728f85 --- /dev/null +++ b/src/ui/Bar/Menu.tsx @@ -0,0 +1,158 @@ +import { faCaretRight } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { SystemContext } from '@chakra-ui/react'; +import CreateProject from "./CreateProject"; +import styled from "styled-components"; +import * as Menubar from "@radix-ui/react-menubar"; + +export type MenuType = { + system: SystemContext, + onImportFiles: () => void, + onApplyTestMetadata: () => void, + onUnsetMetadata: () => void, + onCreateChart: () => void, + onLoadChart: () => void, + onExportChart: () => void, + showSettingsPanel: () => void, +}; + +const Menu = ({ + system, + onImportFiles, + onApplyTestMetadata, + onUnsetMetadata, + onCreateChart, + onLoadChart, + onExportChart, + showSettingsPanel, +}: MenuType) => { + const Root = styled(Menubar.Root)(system.css({ + display: "flex", + layerStyle: "fill.subtle", + })); + + const Menu = styled(Menubar.Menu)(system.css({})); + + const Trigger = styled(Menubar.Trigger)(system.css({ + layerStyle: "fill.subtle", + textStyle: "sm", + px: "3", + py: "1", + gap: "2", + alignItems: "center", + justifyContent: "space-between", + display: "flex", + lineHeight: "1.5", + outline: "none", + userSelect: "none", + "&[data-highlighted]": { layerStyle: "fill.muted" }, + "&[data-state='open']": { layerStyle: "fill.muted" }, + "&:hover": { layerStyle: "fill.muted" } + })); + + const Portal = styled(Menubar.Portal)(system.css({})); + const Sub = styled(Menubar.Sub)(system.css({})); + + const MenubarContent = system.css({ + minW: "40", + layerStyle: "fill.subtle", + p: "3", + }); + + const Content = styled(Menubar.Content)(MenubarContent); + const SubContent = styled(Menubar.SubContent)(MenubarContent); + + const MenuItem = system.css({ + all: "unset", + textStyle: "sm", + lineHeight: "2", + alignItems: "center", + justifyContent: "space-between", + display: "flex", + px: "3", + position: "relative", + userSelect: "none", + "&[data-highlighted]": { layerStyle: "fill.muted" }, + "&[data-state='open']": { layerStyle: "fill.muted" }, + "&:hover": { layerStyle: "fill.muted" } + }); + + const Item = styled(Menubar.Item)(MenuItem); + const SubTrigger = styled(Menubar.SubTrigger)(MenuItem); + + const Separator = styled(Menubar.Separator)(system.css({ + height: "1px", + backgroundColor: "border", + margin: "2", + })); + + const RightSlotIcon = styled(FontAwesomeIcon)(system.css({ + marginLeft: "auto", + paddingLeft: "2", + color: "text", + })); + + return ( + + + File + + + Import files + Export files + + + + + Chart + + + + + Create chart + Load chart + Export chart + + + + + + + + + Edit + + + Undo + Redo + + + + Metadata + + + + + Apply Test Metadata + Unset Metadata + + + + + Settings + + + + + ); +}; + +export default Menu; diff --git a/src/ui/Bar/TopBar/Menu/File/File.tsx b/src/ui/Bar/TopBar/Menu/File/File.tsx deleted file mode 100644 index d56206b..0000000 --- a/src/ui/Bar/TopBar/Menu/File/File.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Button, Menu, Popover } from '@blueprintjs/core'; -import CreateProject from './CreateProject'; - -const MenuFile = () => { - return ( - - - - )} - usePortal={false} - lazy={true} - minimal - > -
diff --git a/src/ui/Panel/BPMPanel/Item.tsx b/src/ui/Panel/BPMPanel/Item.tsx index 2b7c5ba..2a20c46 100644 --- a/src/ui/Panel/BPMPanel/Item.tsx +++ b/src/ui/Panel/BPMPanel/Item.tsx @@ -47,7 +47,7 @@ const BPMListItem = observer<{ /> - diff --git a/src/ui/Panel/PanelDock.tsx b/src/ui/Panel/PanelDock.tsx index f1db9e8..afd3377 100644 --- a/src/ui/Panel/PanelDock.tsx +++ b/src/ui/Panel/PanelDock.tsx @@ -99,7 +99,7 @@ const PanelDock = (props: { api: DockviewApi | undefined, setApi: (api: Dockview onReady={onReady} className={props.theme || "dockview-theme-abyss"} disableFloatingGroups={false} - singleTabMode="fullwidth" + singleTabMode="default" /> diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index d695b8c..079c418 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -15,7 +15,7 @@ const PreviewController = () => { return ( <> - + @@ -25,8 +25,8 @@ const PreviewController = () => {
- - - - - - - - - - - | -
- -
- - - - + + + + - - -
- -
-
- - - + + + + + + + + ); } diff --git a/src/ui/Bar/Menu.tsx b/src/ui/Bar/Menu.tsx index ad65fd7..da37b5f 100644 --- a/src/ui/Bar/Menu.tsx +++ b/src/ui/Bar/Menu.tsx @@ -14,6 +14,7 @@ export type MenuType = { onLoadChart: () => void, onExportChart: () => void, showSettingsPanel: () => void, + onImportSkin: () => void, }; const Menu = ({ @@ -25,6 +26,7 @@ const Menu = ({ onLoadChart, onExportChart, showSettingsPanel, + onImportSkin, }: MenuType) => { const Root = styled(Menubar.Root)(system.css({ display: "flex", @@ -157,6 +159,7 @@ const Menu = ({ + Load skin Settings From 90636cadbbd5cd083eefb39512baf15ccd09dfff Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Mon, 8 Sep 2025 16:50:34 +0800 Subject: [PATCH 092/146] fix(ui/App): oops --- src/ui/App.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 140e615..808840e 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -4,15 +4,17 @@ import TempoContext from './contexts/Tempo'; import Chart from '@/Chart/Chart'; import PanelDock from './Panel/PanelDock'; import { PopupReadFiles, ReadFileAsText } from '@/utils/file'; +import { Clip } from '@phifans/audio'; import { Nullable } from '@/utils/types'; import { useCallback, useState } from 'react'; import SettingsProvider from './contexts/Settings/Provider'; +import { importFromZip } from '@/runtime/skin/importer'; import { DockviewApi } from 'dockview'; import { ChartExported } from '@/Chart/Chart'; import DialogProvider from './contexts/Dialog/Provider'; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; -import { audioCache } from '@/runtime/resources/cache'; +import { runtimeCache } from '@/runtime/resources/cache'; import Menu from './Bar/Menu'; import ActivityBar from './Bar/ActivityBar'; import '@/runtime/audio/state'; From a5a5763df2fa87ba24da4f0dc9918701df93b014 Mon Sep 17 00:00:00 2001 From: IcedDog <34804287+IcedDog@users.noreply.github.com> Date: Mon, 8 Sep 2025 18:50:38 +0800 Subject: [PATCH 093/146] refactor(ui): Create Project Panel --- package.json | 3 +- pnpm-lock.yaml | 270 --------------------- src/ui/App.tsx | 53 ++-- src/ui/Bar/CreateProject.tsx | 171 ++++++++----- src/ui/Bar/Menu.tsx | 8 +- src/ui/Panel/ProjectPanel/Input.tsx | 22 +- src/ui/Panel/ProjectPanel/ProjectPanel.tsx | 10 +- src/ui/contexts/Dialog/Provider.tsx | 100 +++++--- src/ui/contexts/Dialog/index.ts | 12 - src/ui/contexts/Dialog/types.ts | 8 - src/ui/styles/index.css | 1 - 11 files changed, 215 insertions(+), 443 deletions(-) delete mode 100644 src/ui/contexts/Dialog/index.ts delete mode 100644 src/ui/contexts/Dialog/types.ts diff --git a/package.json b/package.json index 2cc1db5..a467360 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "preview": "vite preview --config vite.config.web.ts" }, "dependencies": { - "@blueprintjs/core": "^5.16.4", "@chakra-ui/react": "^3.26.0", "@emotion/react": "^11.14.0", "@fortawesome/fontawesome-svg-core": "^6.7.2", @@ -53,8 +52,8 @@ "react-split-pane": "^0.1.92", "setimmediate": "^1.0.5", "spark-md5": "^3.0.2", - "unstorage": "^1.17.1", "styled-components": "^6.1.19", + "unstorage": "^1.17.1", "uuid": "^11.0.4", "zustand": "^5.0.8" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5496ce5..a12c9a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,9 +13,6 @@ importers: .: dependencies: - '@blueprintjs/core': - specifier: ^5.16.4 - version: 5.16.4(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@chakra-ui/react': specifier: ^3.26.0 version: 3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -240,30 +237,6 @@ packages: resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} engines: {node: '>=6.9.0'} - '@blueprintjs/colors@5.1.5': - resolution: {integrity: sha512-IUZvQLsQmfqumTTzeb5oQLnvskJcQYKcitzhDm5+iTWl42Jn5oyUqPDW96ubH/pfWoQGHzBp91ujq6KREl4GHQ==} - - '@blueprintjs/core@5.16.4': - resolution: {integrity: sha512-jgy3UJNDWPBdNn8nf2pDgzSKDJABVG4i1OPrcFJlOQl117UWMJD28/hAtyBQG1e+/6AE0a678Ko1aBmK4aWp6Q==} - hasBin: true - peerDependencies: - '@types/react': ^16.14.41 || 17 || 18 - react: ^16.8 || 17 || 18 - react-dom: ^16.8 || 17 || 18 - peerDependenciesMeta: - '@types/react': - optional: true - - '@blueprintjs/icons@5.17.1': - resolution: {integrity: sha512-jdwrfDb5N0KCKGFFaJn5KrQj0ZX1hqEXHor9ewsdrSgVGOzVCg9OJ/GYVjy85McHNhN9bYyYaH+8dxablEoYRA==} - peerDependencies: - '@types/react': ^16.14.41 || 17 || 18 - react: ^16.8 || 17 || 18 - react-dom: ^16.8 || 17 || 18 - peerDependenciesMeta: - '@types/react': - optional: true - '@chakra-ui/cli@3.26.0': resolution: {integrity: sha512-BAnuzUCael9vjvq6bvNpX/UWJFu2I+pIfPqKT3I7ejo/c5JM6IDDqZQp7cs+10e0S4MXH743R/TfnVU96OOPBw==} hasBin: true @@ -786,9 +759,6 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@radix-ui/primitive@1.1.3': resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} @@ -1822,22 +1792,13 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camel-case@4.1.2: - resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} - camelize@1.0.1: resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - capital-case@1.0.4: - resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - change-case@4.1.2: - resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -1846,9 +1807,6 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - cli-table@0.3.11: resolution: {integrity: sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==} engines: {node: '>= 0.2.0'} @@ -1878,9 +1836,6 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - constant-case@3.0.4: - resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} - convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -1980,12 +1935,6 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - - dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2276,9 +2225,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - header-case@2.0.4: - resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} - hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -2539,9 +2485,6 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2620,9 +2563,6 @@ packages: react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -2724,9 +2664,6 @@ packages: pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - param-case@3.0.4: - resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2738,12 +2675,6 @@ packages: parse-svg-path@0.1.2: resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==} - pascal-case@3.1.2: - resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} - - path-case@3.0.4: - resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2850,9 +2781,6 @@ packages: peerDependencies: react: ^19.0.0 - react-fast-compare@3.2.2: - resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - react-i18next@15.4.1: resolution: {integrity: sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw==} peerDependencies: @@ -2877,13 +2805,6 @@ packages: react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} - react-popper@2.3.0: - resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} - peerDependencies: - '@popperjs/core': ^2.0.0 - react: ^16.8.0 || ^17 || ^18 - react-dom: ^16.8.0 || ^17 || ^18 - react-reconciler@0.31.0: resolution: {integrity: sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==} engines: {node: '>=0.10.0'} @@ -2929,22 +2850,6 @@ packages: '@types/react': optional: true - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - - react-uid@2.4.0: - resolution: {integrity: sha512-+MVs/25NrcZuGrmlVRWPOSsbS8y72GJOBsR7d68j3/wqOrRBF52U29XAw4+XSelw0Vm6s5VmGH5mCbTCPGVCVg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - react@19.0.0: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} @@ -3033,9 +2938,6 @@ packages: engines: {node: '>=10'} hasBin: true - sentence-case@3.0.4: - resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3092,9 +2994,6 @@ packages: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} - snake-case@3.0.4: - resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3211,9 +3110,6 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tslib@2.6.3: - resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -3331,12 +3227,6 @@ packages: uploadthing: optional: true - upper-case-first@2.0.2: - resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} - - upper-case@2.0.2: - resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} - uqr@0.1.2: resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} @@ -3424,9 +3314,6 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} - warning@4.0.3: - resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -3629,37 +3516,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@blueprintjs/colors@5.1.5': - dependencies: - tslib: 2.6.3 - - '@blueprintjs/core@5.16.4(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@blueprintjs/colors': 5.1.5 - '@blueprintjs/icons': 5.17.1(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@popperjs/core': 2.11.8 - classnames: 2.5.1 - normalize.css: 8.0.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-uid: 2.4.0(@types/react@19.0.7)(react@19.0.0) - tslib: 2.6.3 - use-sync-external-store: 1.4.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.7 - - '@blueprintjs/icons@5.17.1(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - change-case: 4.1.2 - classnames: 2.5.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - tslib: 2.6.3 - optionalDependencies: - '@types/react': 19.0.7 - '@chakra-ui/cli@3.26.0(@chakra-ui/react@3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0))': dependencies: '@chakra-ui/react': 3.26.0(@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -4093,8 +3949,6 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@popperjs/core@2.11.8': {} - '@radix-ui/primitive@1.1.3': {} '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.7))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': @@ -5354,39 +5208,13 @@ snapshots: callsites@3.1.0: {} - camel-case@4.1.2: - dependencies: - pascal-case: 3.1.2 - tslib: 2.8.1 - camelize@1.0.1: {} - capital-case@1.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - upper-case-first: 2.0.2 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - change-case@4.1.2: - dependencies: - camel-case: 4.1.2 - capital-case: 1.0.4 - constant-case: 3.0.4 - dot-case: 3.0.4 - header-case: 2.0.4 - no-case: 3.0.4 - param-case: 3.0.4 - pascal-case: 3.1.2 - path-case: 3.0.4 - sentence-case: 3.0.4 - snake-case: 3.0.4 - tslib: 2.8.1 - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -5403,8 +5231,6 @@ snapshots: dependencies: readdirp: 4.1.2 - classnames@2.5.1: {} - cli-table@0.3.11: dependencies: colors: 1.0.3 @@ -5425,12 +5251,6 @@ snapshots: concat-map@0.0.1: {} - constant-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - upper-case: 2.0.2 - convert-source-map@1.9.0: {} cookie-es@1.2.2: {} @@ -5530,16 +5350,6 @@ snapshots: dependencies: esutils: 2.0.3 - dom-helpers@5.2.1: - dependencies: - '@babel/runtime': 7.26.10 - csstype: 3.1.3 - - dot-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.1 @@ -6000,11 +5810,6 @@ snapshots: dependencies: function-bind: 1.1.2 - header-case@2.0.4: - dependencies: - capital-case: 1.0.4 - tslib: 2.8.1 - hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 @@ -6276,10 +6081,6 @@ snapshots: dependencies: js-tokens: 4.0.0 - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 - lru-cache@10.4.3: {} math-intrinsics@1.1.0: {} @@ -6346,11 +6147,6 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 - node-domexception@1.0.0: {} node-eval@2.0.0: @@ -6457,11 +6253,6 @@ snapshots: pako@1.0.11: {} - param-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 - parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -6475,16 +6266,6 @@ snapshots: parse-svg-path@0.1.2: {} - pascal-case@3.1.2: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - - path-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 - path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -6575,8 +6356,6 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 - react-fast-compare@3.2.2: {} - react-i18next@15.4.1(i18next@24.2.3(typescript@5.6.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime': 7.26.0 @@ -6594,14 +6373,6 @@ snapshots: react-lifecycles-compat@3.0.4: {} - react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@popperjs/core': 2.11.8 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-fast-compare: 3.2.2 - warning: 4.0.3 - react-reconciler@0.31.0(react@19.0.0): dependencies: react: 19.0.0 @@ -6646,22 +6417,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.7 - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@babel/runtime': 7.26.10 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - react-uid@2.4.0(@types/react@19.0.7)(react@19.0.0): - dependencies: - react: 19.0.0 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.0.7 - react@19.0.0: {} readable-stream@2.3.8: @@ -6786,12 +6541,6 @@ snapshots: semver@7.6.3: {} - sentence-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - upper-case-first: 2.0.2 - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -6860,11 +6609,6 @@ snapshots: slash@5.1.0: {} - snake-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 - source-map-js@1.2.1: {} source-map@0.5.7: {} @@ -7005,8 +6749,6 @@ snapshots: tslib@2.6.2: {} - tslib@2.6.3: {} - tslib@2.8.1: {} type-check@0.4.0: @@ -7088,14 +6830,6 @@ snapshots: optionalDependencies: idb-keyval: 6.2.2 - upper-case-first@2.0.2: - dependencies: - tslib: 2.8.1 - - upper-case@2.0.2: - dependencies: - tslib: 2.8.1 - uqr@0.1.2: {} uri-js@4.4.1: @@ -7142,10 +6876,6 @@ snapshots: void-elements@3.1.0: {} - warning@4.0.3: - dependencies: - loose-envify: 1.4.0 - web-streams-polyfill@3.3.3: {} webidl-conversions@3.0.1: {} diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 808840e..b3f71ea 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -11,7 +11,7 @@ import SettingsProvider from './contexts/Settings/Provider'; import { importFromZip } from '@/runtime/skin/importer'; import { DockviewApi } from 'dockview'; import { ChartExported } from '@/Chart/Chart'; -import DialogProvider from './contexts/Dialog/Provider'; +import { DialogProvider } from "./contexts/Dialog/Provider"; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; import { runtimeCache } from '@/runtime/resources/cache'; @@ -23,15 +23,15 @@ const config = defineConfig({}); const system = createSystem(defaultConfig, config); function App() { - const [ dockviewApi, setDockviewApi ] = useState(); - const [ tempo, setTempo ] = useState(4); + const [dockviewApi, setDockviewApi] = useState(); + const [tempo, setTempo] = useState(4); let importedMusic: Nullable = null; const onImportFiles = () => { PopupReadFiles(true) .then((files) => { if (!files || files.length === 0) return; - return loadFiles([ ...files ]); + return loadFiles([...files]); }) .then((result) => { console.log(result); @@ -42,7 +42,7 @@ function App() { const onApplyTestMetadata = () => { let audioFile: string = ''; - for (const [ name, item ] of runtimeCache.entriesDescending()) { + for (const [name, item] of runtimeCache.entriesDescending()) { if (!audioFile && item instanceof Clip) { audioFile = name; break; @@ -104,7 +104,7 @@ function App() { const chartJson = Chart.json!; const chartText = JSON.stringify(chartJson, null, 4); - const chartBlob = new Blob([ chartText ], { type: 'text/json' }); + const chartBlob = new Blob([chartText], { type: 'text/json' }); const chartUrl = URL.createObjectURL(chartBlob); const downloadDom = document.createElement('a'); @@ -132,28 +132,27 @@ function App() { return ( - - - + + + - - - - - - + + + + ); diff --git a/src/ui/Bar/CreateProject.tsx b/src/ui/Bar/CreateProject.tsx index da66445..699b46e 100644 --- a/src/ui/Bar/CreateProject.tsx +++ b/src/ui/Bar/CreateProject.tsx @@ -1,8 +1,10 @@ -import { Button, DialogBody, DialogFooter, FileInput, FormGroup } from '@blueprintjs/core'; +import { Button, Dialog, Stack, Field, FileUpload, Input, InputGroup, CloseButton } from "@chakra-ui/react"; +import { openDialog, closeDialog, waitForExitDialog } from "@/ui/contexts/Dialog/Provider"; +import ProjectPanel from '@/ui/Panel/ProjectPanel/ProjectPanel'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faMusic, faImage } from "@fortawesome/free-solid-svg-icons"; import { useRef } from 'react'; import Chart from '@/Chart/Chart'; -import ProjectPanel from '@/ui/Panel/ProjectPanel/ProjectPanel'; -import { useDialog } from '@/ui/contexts/Dialog'; import { ChartInfo } from '@/Chart/types'; import { Nullable } from '@/utils/types'; @@ -14,12 +16,11 @@ type ProjectMeta = ChartInfo & { }; const CreateProject = ({ Hachimi }: any) => { - const { show: showDialog, close: closeDialog } = useDialog(); const newProjectMeta = useRef>({}); - const updateNewProjectMeta = (metaOrFile: Nullable, fileType?: ProjectFile) => { + const updateNewProjectMeta = (metaOrFile: Nullable, fileType?: ProjectFile) => { if (!metaOrFile) return; - if (!(metaOrFile instanceof FileList)) { + if (!(metaOrFile instanceof Array)) { newProjectMeta.current = { ...newProjectMeta.current, ...metaOrFile, @@ -34,8 +35,9 @@ const CreateProject = ({ Hachimi }: any) => { newProjectMeta.current[fileType] = file; }; - const createProject = () => { - closeDialog(); + const createProject = async () => { + closeDialog({ id: "create-project" }); + await waitForExitDialog({ id: "create-project" }); const projectMeta: ChartInfo & Partial = { name: 'Untitled', @@ -47,36 +49,28 @@ const CreateProject = ({ Hachimi }: any) => { }; if (!projectMeta.music) { - showDialog({ + openDialog({ + id: "create-project-error", title: 'Error', - onClose: closeDialog, - children: ( - <> - No music file selected - Close - } - /> - + description: 'No music file selected', + footer: ( + + + ) }); return; } if (!projectMeta.background) { - showDialog({ + openDialog({ + id: "create-project-error", title: 'Error', - onClose: closeDialog, - children: ( - <> - No background file selected - Close - } - /> - + description: 'No background file selected', + footer: ( + + + ) }); return; @@ -86,46 +80,91 @@ const CreateProject = ({ Hachimi }: any) => { } const handleOpenDialog = () => { - showDialog({ + openDialog({ + id: "create-project", title: 'Create Project', - onClose: closeDialog, - children: ( - <> - - + + Music File + updateNewProjectMeta(e.files, "music")} > - updateNewProjectMeta((e.target as HTMLInputElement).files, 'music')} - fill - /> - - - + + } + endElement={ + + + + } + > + + + + + + + + + + + Background Image File + updateNewProjectMeta(e.files, "background")} > - updateNewProjectMeta((e.target as HTMLInputElement).files, 'background')} - fill - /> - - - - - - - - - )} - /> + + + } + endElement={ + + + + } + > + + + + + + + + + + + + ), + footer: ( + <> + + + + - ) + ), + closeButton: true }); }; diff --git a/src/ui/Bar/Menu.tsx b/src/ui/Bar/Menu.tsx index da37b5f..509289f 100644 --- a/src/ui/Bar/Menu.tsx +++ b/src/ui/Bar/Menu.tsx @@ -117,11 +117,11 @@ const Menu = ({ Import files Export files - + Chart - + @@ -149,7 +149,7 @@ const Menu = ({ Metadata - + @@ -159,7 +159,7 @@ const Menu = ({ - Load skin + Load skin Settings diff --git a/src/ui/Panel/ProjectPanel/Input.tsx b/src/ui/Panel/ProjectPanel/Input.tsx index c159599..6274689 100644 --- a/src/ui/Panel/ProjectPanel/Input.tsx +++ b/src/ui/Panel/ProjectPanel/Input.tsx @@ -1,4 +1,4 @@ -import { FormGroup, InputGroup } from '@blueprintjs/core'; +import { Field, Input } from "@chakra-ui/react" import { ChartInfo } from '@/Chart/types'; import { FormEvent } from 'react'; @@ -27,18 +27,16 @@ const ProjectInput = ({ }; return ( - - + { label } + - + { sublabel } + ); }; diff --git a/src/ui/Panel/ProjectPanel/ProjectPanel.tsx b/src/ui/Panel/ProjectPanel/ProjectPanel.tsx index ea0db38..a2c1698 100644 --- a/src/ui/Panel/ProjectPanel/ProjectPanel.tsx +++ b/src/ui/Panel/ProjectPanel/ProjectPanel.tsx @@ -1,3 +1,4 @@ +import { Stack } from "@chakra-ui/react" import { useState } from 'react'; import { ChartInfo } from '@/Chart/types'; import ProjectInput from './Input'; @@ -33,12 +34,7 @@ const ProjectPanel = ({ }; return ( -
+ -
+ ); }; diff --git a/src/ui/contexts/Dialog/Provider.tsx b/src/ui/contexts/Dialog/Provider.tsx index 9e1293c..8dc35b0 100644 --- a/src/ui/contexts/Dialog/Provider.tsx +++ b/src/ui/contexts/Dialog/Provider.tsx @@ -1,39 +1,71 @@ -import { useState } from 'react'; -import DialogContext from '.'; -import { $DialogProps } from './types'; -import { Dialog } from '@blueprintjs/core'; +import { Dialog, CloseButton, Portal, createOverlay } from "@chakra-ui/react" -type DialogProviderProps = { - children: React.ReactNode, +interface DialogProps { + id?: string + title?: string + description?: string + content?: React.ReactNode + footer?: React.ReactNode + closeButton?: boolean +} + +const dialog = createOverlay((props) => { + const { id, title, description, content, footer, closeButton, ...rest } = props + return ( + + + + + + {title && ( + + {title} + + )} + + {description && ( + {description} + )} + {content} + + {footer && ( + + {footer} + + )} + {closeButton && ( + + + + )} + + + + + ); +}); + +export const DialogProvider = () => { + // @ts-expect-error why?????? + return ; +}; + +export const openDialog = (props: DialogProps) => { + dialog.open(props.id || "default", props); +}; + +export const closeDialog = (props?: DialogProps, value?: any) => { + dialog.close(props ? props.id || "default" : "default", value || undefined); +}; + +export const updateDialog = (props: DialogProps) => { + dialog.update(props.id || "default", props); }; -const DialogProvider = ({ - children -}: DialogProviderProps) => { - const [ dialogProps, setDialogProps ] = useState<$DialogProps>({}); - const [ isOpen, setIsOpen ] = useState(false); - - const openDialog = () => setIsOpen(true); - const closeDialog = () => setIsOpen(false); - - const showDialog = (props: $DialogProps) => { - setDialogProps(props); - openDialog(); - }; - - return ( - - {children} - - - ) +export const removeDialog = (props?: DialogProps) => { + dialog.remove(props ? props.id || "default" : "default"); }; -export default DialogProvider; +export const waitForExitDialog = (props: DialogProps) => { + return dialog.waitForExit(props.id || "default"); +}; \ No newline at end of file diff --git a/src/ui/contexts/Dialog/index.ts b/src/ui/contexts/Dialog/index.ts deleted file mode 100644 index d6cfe93..0000000 --- a/src/ui/contexts/Dialog/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { createContext, useContext } from 'react'; -import { $DialogProps, DialogContextProps } from './types'; - -const uninitFn = (props: $DialogProps) => void props; - -const DialogContext = createContext({ - show: uninitFn, - close: () => void 0, -}); - -export const useDialog = () => useContext(DialogContext); -export default DialogContext; diff --git a/src/ui/contexts/Dialog/types.ts b/src/ui/contexts/Dialog/types.ts deleted file mode 100644 index b5bdda1..0000000 --- a/src/ui/contexts/Dialog/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { DialogProps } from '@blueprintjs/core'; - -export type $DialogProps = Omit; - -export type DialogContextProps = { - show: (props: $DialogProps) => void, - close: () => void, -}; diff --git a/src/ui/styles/index.css b/src/ui/styles/index.css index dca9683..bc81687 100644 --- a/src/ui/styles/index.css +++ b/src/ui/styles/index.css @@ -3,7 +3,6 @@ /* Default look of BlueprintJS */ @import url('normalize.css'); -@import url('@blueprintjs/core/lib/css/blueprint.css'); @import url('./components.css'); From e5bf6df8e568de09ee4d158c3281070d5ccd8871 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 8 Sep 2025 21:09:17 +0800 Subject: [PATCH 094/146] fix(ui/components/NumberInput): Fix wrong props --- src/ui/components/NumberInput.tsx | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/ui/components/NumberInput.tsx b/src/ui/components/NumberInput.tsx index f4c7590..aa2a152 100644 --- a/src/ui/components/NumberInput.tsx +++ b/src/ui/components/NumberInput.tsx @@ -1,8 +1,8 @@ import { useEffect, useMemo, useRef, useState } from 'react'; +import { NumberInput as NumInput } from '@chakra-ui/react'; import useDrag from '../hooks/useDrag'; -import { ChangeEventHandler, KeyboardEventHandler } from 'react'; +import { KeyboardEventHandler } from 'react'; import { Nullable } from '@/utils/types'; -import { NumberInput as NumInput } from '@chakra-ui/react'; const getDragStep = (min?: number, max?: number) => { if (min !== (void 0) && max !== (void 0)) return (max - min) / 1000; @@ -107,11 +107,6 @@ const NumberInput = ({ if (onInput) onInput(valueRef.current); }; - const handleChangeEvent: ChangeEventHandler = (e) => { - const value = e.target.value; - handleValueChange(parseFloat(value)); - }; - const handleBlur = () => { if (isDraggingStartRef.current) { isDraggingStartRef.current = false; @@ -154,19 +149,22 @@ const NumberInput = ({ }, [defaultValue]); return ( - + handleValueChange(e.valueAsNumber)} + onKeyDown={handleKeyDown} + className={className} + style={inputStyle} + > From 3f66715d08b7dfb3821ec42542309ac2cebff23c Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 8 Sep 2025 21:20:35 +0800 Subject: [PATCH 095/146] refactor(ui/contexts): Remove unused contexts --- src/ui/Panel/PanelDock.tsx | 20 ++++----- src/ui/contexts/Clock/Provider.tsx | 40 ------------------ src/ui/contexts/Clock/index.ts | 13 ------ src/ui/contexts/SelectedItem/Provider.tsx | 51 ----------------------- src/ui/contexts/SelectedItem/index.ts | 29 ------------- 5 files changed, 7 insertions(+), 146 deletions(-) delete mode 100644 src/ui/contexts/Clock/Provider.tsx delete mode 100644 src/ui/contexts/Clock/index.ts delete mode 100644 src/ui/contexts/SelectedItem/Provider.tsx delete mode 100644 src/ui/contexts/SelectedItem/index.ts diff --git a/src/ui/Panel/PanelDock.tsx b/src/ui/Panel/PanelDock.tsx index afd3377..7eb369e 100644 --- a/src/ui/Panel/PanelDock.tsx +++ b/src/ui/Panel/PanelDock.tsx @@ -7,8 +7,6 @@ import { import 'dockview/dist/styles/dockview.css'; import Components from './Components'; import DefaultLayout from './DefaultLayout'; -import SelectedItemProvider from '../contexts/SelectedItem/Provider'; -import ClockTimeProvider from '../contexts/Clock/Provider'; const PanelDock = (props: { api: DockviewApi | undefined, setApi: (api: DockviewApi) => void, theme?: string }) => { const { api, setApi } = props; @@ -92,17 +90,13 @@ const PanelDock = (props: { api: DockviewApi | undefined, setApi: (api: Dockview return (
- - - - - +
); }; diff --git a/src/ui/contexts/Clock/Provider.tsx b/src/ui/contexts/Clock/Provider.tsx deleted file mode 100644 index a540631..0000000 --- a/src/ui/contexts/Clock/Provider.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { useEffect, useState } from 'react'; -import { Ticker } from 'pixi.js'; -import ClockTimeContext from '.'; -import Chart from '@/Chart/Chart'; - -export type ClockTimeProviderProps = { - children: React.ReactNode, -}; - -const ClockTimeProvider: React.FC = ({ - children -}: ClockTimeProviderProps) => { - const [ time, setTime ] = useState(0); - const [ beat, setBeat ] = useState(0); - const [ beatOffset, setBeatOffset ] = useState(0); - - useEffect(() => { - const ticker = Ticker.shared; - const updateTime = () => { - setTime(Chart.time); - setBeat(Chart.beatNum); - setBeatOffset(Chart.offsetBeat); - }; - ticker.add(updateTime); - - return (() => { - ticker.remove(updateTime); - }); - }, []); - - return - {children} - -}; - -export default ClockTimeProvider; diff --git a/src/ui/contexts/Clock/index.ts b/src/ui/contexts/Clock/index.ts deleted file mode 100644 index 78d0c10..0000000 --- a/src/ui/contexts/Clock/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createContext, useContext } from 'react'; - -type ClockTime = { - time: number, - beat: number, - beatOffset:number, -}; - -const ClockTimeContext = createContext({ time: 0, beat: 0, beatOffset: 0 }); - -export const useClockTime = () => useContext(ClockTimeContext); - -export default ClockTimeContext; diff --git a/src/ui/contexts/SelectedItem/Provider.tsx b/src/ui/contexts/SelectedItem/Provider.tsx deleted file mode 100644 index 006cd37..0000000 --- a/src/ui/contexts/SelectedItem/Provider.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useCallback, useEffect, useState } from 'react'; -import SelectedItemContext from '.'; -import { SelectedItem } from '.'; -import { Nullable } from '@/utils/types'; - -type SelectedItemProviderProps = { - children: React.ReactNode, -}; - -const SelectedItemProvider = ({ - children -}: SelectedItemProviderProps) => { - const [ item, setItem ] = useState(null); - - const unsetItem = useCallback((e: MouseEvent) => { - if (!item) return; - - const target = e.target as Nullable; - if (!target) return; - if ( - target.closest('.timeline-panel-head-right') || - target.closest('.edit-panel') - ) return; - - const parentDom = target.parentElement; - if (parentDom) { - if ( - parentDom.closest('.timeline-time-seeker') || - parentDom.closest('.edit-panel') || - parentDom.closest('.note-panel') - ) return; - } - - if (!target.classList.contains('timeline-content-key')) return setItem(null); - }, [item]); - - useEffect(() => { - document.addEventListener('mousedown', unsetItem); - return (() => { - document.removeEventListener('mousedown', unsetItem); - }); - }, [unsetItem]); - - return ( - - {children} - - ); -}; - -export default SelectedItemProvider; diff --git a/src/ui/contexts/SelectedItem/index.ts b/src/ui/contexts/SelectedItem/index.ts deleted file mode 100644 index 69fa085..0000000 --- a/src/ui/contexts/SelectedItem/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createContext, useContext } from 'react'; -import { Nullable } from '@/utils/types'; -import ChartJudgeline from '@/Chart/Judgeline'; -import { TChartJudgelineProps } from '@/Chart/JudgelineProps'; - -export type SelectedKeyframe = { - type: keyof TChartJudgelineProps, - id: string, -}; - -export type SelectedNote = { - id: string, -}; - -export type SelectedItem = Nullable<{ - line: ChartJudgeline, - keyframe: Nullable, - note: Nullable, -}>; - -export type TSelectedItemContext = Nullable< - [ SelectedItem, React.Dispatch> ] ->; - -const SelectedItemContext = createContext(null); - -export const useSelectedItem = () => useContext(SelectedItemContext); - -export default SelectedItemContext; From fa9212a19990c7045e9769f72f94ef88764bd458 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 8 Sep 2025 22:53:42 +0800 Subject: [PATCH 096/146] style(ui/Bar): Moving file --- src/ui/Bar/{Menu.tsx => MenuBar/MenuBar.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/ui/Bar/{Menu.tsx => MenuBar/MenuBar.tsx} (100%) diff --git a/src/ui/Bar/Menu.tsx b/src/ui/Bar/MenuBar/MenuBar.tsx similarity index 100% rename from src/ui/Bar/Menu.tsx rename to src/ui/Bar/MenuBar/MenuBar.tsx From e6b55b1aee6db0dfbceb1f803cbda6af8ec89c1a Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Mon, 8 Sep 2025 22:57:54 +0800 Subject: [PATCH 097/146] refactor(ui): Seperating theme system --- src/ui/App.tsx | 52 ++++++++++++++++----------------------- src/ui/index.tsx | 5 +++- src/ui/theme/Provider.tsx | 15 +++++++++++ src/ui/theme/config.ts | 5 ++++ src/ui/theme/system.ts | 4 +++ 5 files changed, 49 insertions(+), 32 deletions(-) create mode 100644 src/ui/theme/Provider.tsx create mode 100644 src/ui/theme/config.ts create mode 100644 src/ui/theme/system.ts diff --git a/src/ui/App.tsx b/src/ui/App.tsx index b3f71ea..0759174 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,5 +1,3 @@ -import { ChakraProvider, createSystem, defaultConfig, defineConfig } from "@chakra-ui/react" -import { ColorModeProvider } from "@/components/ui/color-mode" import TempoContext from './contexts/Tempo'; import Chart from '@/Chart/Chart'; import PanelDock from './Panel/PanelDock'; @@ -15,13 +13,10 @@ import { DialogProvider } from "./contexts/Dialog/Provider"; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; import { runtimeCache } from '@/runtime/resources/cache'; -import Menu from './Bar/Menu'; +import MenuBar from './Bar/MenuBar/MenuBar'; import ActivityBar from './Bar/ActivityBar'; import '@/runtime/audio/state'; -const config = defineConfig({}); -const system = createSystem(defaultConfig, config); - function App() { const [dockviewApi, setDockviewApi] = useState(); const [tempo, setTempo] = useState(4); @@ -130,31 +125,26 @@ function App() { }; return ( - - - - - - - - - - - - + + + + + + + + ); } diff --git a/src/ui/index.tsx b/src/ui/index.tsx index 31bd70b..9152e52 100644 --- a/src/ui/index.tsx +++ b/src/ui/index.tsx @@ -1,11 +1,14 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import { ThemeProvider } from './theme/Provider.tsx' import '@/i18n' import './styles/index.css' import App from './App.tsx' createRoot(document.getElementById('root')!).render( - + + + , ) diff --git a/src/ui/theme/Provider.tsx b/src/ui/theme/Provider.tsx new file mode 100644 index 0000000..f5dfad9 --- /dev/null +++ b/src/ui/theme/Provider.tsx @@ -0,0 +1,15 @@ +import { ChakraProvider } from '@chakra-ui/react'; +import { themeSystem } from './system'; +import React from 'react'; + +type ThemeProviderProps = { + children: React.ReactNode; +}; + +export const ThemeProvider = ({ children }: ThemeProviderProps) => { + return ( + + {children} + + ); +}; diff --git a/src/ui/theme/config.ts b/src/ui/theme/config.ts new file mode 100644 index 0000000..4d0db16 --- /dev/null +++ b/src/ui/theme/config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from '@chakra-ui/react'; + +export const themeConfig = defineConfig({ + // TODO +}); diff --git a/src/ui/theme/system.ts b/src/ui/theme/system.ts new file mode 100644 index 0000000..3c9b58d --- /dev/null +++ b/src/ui/theme/system.ts @@ -0,0 +1,4 @@ +import { defaultConfig, createSystem } from '@chakra-ui/react'; +import { themeConfig } from './config'; + +export const themeSystem = createSystem(defaultConfig, themeConfig); \ No newline at end of file From 3f1cac7c39720edadac244939e0fd07e75d3a66d Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 00:05:10 +0800 Subject: [PATCH 098/146] refactor(ui/Bar/AppBar): Refactoring app bar --- src/ui/App.tsx | 61 +++++++-- src/ui/Bar/MenuBar/Entry.tsx | 30 +++++ src/ui/Bar/MenuBar/Item.tsx | 52 ++++++++ src/ui/Bar/MenuBar/List.tsx | 60 +++++++++ src/ui/Bar/MenuBar/MenuBar.tsx | 205 ++++++------------------------- src/ui/Bar/MenuBar/Separator.tsx | 15 +++ src/ui/Bar/MenuBar/style.ts | 18 +++ src/ui/Bar/MenuBar/types.ts | 13 ++ 8 files changed, 277 insertions(+), 177 deletions(-) create mode 100644 src/ui/Bar/MenuBar/Entry.tsx create mode 100644 src/ui/Bar/MenuBar/Item.tsx create mode 100644 src/ui/Bar/MenuBar/List.tsx create mode 100644 src/ui/Bar/MenuBar/Separator.tsx create mode 100644 src/ui/Bar/MenuBar/style.ts create mode 100644 src/ui/Bar/MenuBar/types.ts diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 0759174..a14571b 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -13,7 +13,7 @@ import { DialogProvider } from "./contexts/Dialog/Provider"; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; import { runtimeCache } from '@/runtime/resources/cache'; -import MenuBar from './Bar/MenuBar/MenuBar'; +import { MenuBar } from './Bar/MenuBar/MenuBar'; import ActivityBar from './Bar/ActivityBar'; import '@/runtime/audio/state'; @@ -127,14 +127,57 @@ function App() { return ( = ({ + label, + items, +}) => { + return ( + + + {label} + + + + ); +}; diff --git a/src/ui/Bar/MenuBar/Item.tsx b/src/ui/Bar/MenuBar/Item.tsx new file mode 100644 index 0000000..766a1f8 --- /dev/null +++ b/src/ui/Bar/MenuBar/Item.tsx @@ -0,0 +1,52 @@ +import styled from 'styled-components'; +import { Item, Sub, SubTrigger } from '@radix-ui/react-menubar'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCaretRight } from '@fortawesome/free-solid-svg-icons'; +import { menuItem } from './style'; +import { themeSystem } from '@/ui/theme/system'; +import { MenuBarList } from './List'; +import { MenuItemProps } from '@chakra-ui/react'; +import { MenuItem } from './types'; + +const ItemWrapper = styled(Item)(menuItem); +const SubTriggerWrapper = styled(SubTrigger)(menuItem); + +const RightSlotIcon = styled(FontAwesomeIcon)(themeSystem.css({ + marginLeft: 'auto', + paddingLeft: '2', + color: 'text', +})); + +// TODO: Hotkey +type MenuBarItemProps = MenuItemProps & { + depth: number, + items?: MenuItem[], +}; + +export const MenuBarItem: React.FC = ({ + children, + depth, + items, + ...rest +}) => { + if (items) { + return ( + + + {children} + + + + + ); + } else { + return ( + + {children} + + ); + } +}; diff --git a/src/ui/Bar/MenuBar/List.tsx b/src/ui/Bar/MenuBar/List.tsx new file mode 100644 index 0000000..89aff63 --- /dev/null +++ b/src/ui/Bar/MenuBar/List.tsx @@ -0,0 +1,60 @@ +import { Portal, Content, SubContent } from '@radix-ui/react-menubar'; +import styled from 'styled-components'; +import { themeSystem } from '@/ui/theme/system'; +import { MenuBarItem } from './Item'; +import { MenuItem } from './types'; +import { MenubarContentProps } from '@radix-ui/react-menubar'; +import { MenuSeparator } from './Separator'; + +const menuContentStyle = themeSystem.css({ + minW: '40', + layerStyle: 'fill.subtle', + p: '3', +}); + +type MenuBarListProps = { + items: MenuItem[], + depth: number, +}; + +const ContentWrapper = styled(Content)(menuContentStyle); +const SubContentWrapper = styled(SubContent)(menuContentStyle); + +export const MenuBarList: React.FC = ({ + items, + depth, +}) => { + const ContentDom = depth === 0 ? ContentWrapper : SubContentWrapper; + + const contentProps: MenubarContentProps = {}; + if (depth === 0) { + contentProps.align = 'start'; + contentProps.sideOffset = 5; + contentProps.alignOffset = -3; + } else { + contentProps.alignOffset = -5; + } + + return ( + + + {items.map((item, index) => ( + item.type && item.type === 'separator' ? ( + + ) : ( + + ) + ))} + + + ); +}; diff --git a/src/ui/Bar/MenuBar/MenuBar.tsx b/src/ui/Bar/MenuBar/MenuBar.tsx index 509289f..dddfedd 100644 --- a/src/ui/Bar/MenuBar/MenuBar.tsx +++ b/src/ui/Bar/MenuBar/MenuBar.tsx @@ -1,171 +1,40 @@ -import { faCaretRight } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { SystemContext } from '@chakra-ui/react'; -import CreateProject from "./CreateProject"; -import styled from "styled-components"; -import * as Menubar from "@radix-ui/react-menubar"; - -export type MenuType = { - system: SystemContext, - onImportFiles: () => void, - onApplyTestMetadata: () => void, - onUnsetMetadata: () => void, - onCreateChart: () => void, - onLoadChart: () => void, - onExportChart: () => void, - showSettingsPanel: () => void, - onImportSkin: () => void, +import styled from 'styled-components'; +import { Root } from '@radix-ui/react-menubar'; +import { themeSystem } from '@/ui/theme/system'; +import { MenuBarEntry } from './Entry'; +import { MenuEntry } from './types'; + +const RootWraper = styled(Root)(themeSystem.css({ + display: 'flex', + layerStyle: 'fill.subtle', +})); + +const Icon = styled.img(themeSystem.css({ + width: '0.7rem', + mx: '4', + my: 'auto', + alignSelf: 'center', + justifySelf: 'center', + borderRadius: '50%', +})); + +type MenuBarProps = { + entries: MenuEntry[], }; -const Menu = ({ - system, - onImportFiles, - onApplyTestMetadata, - onUnsetMetadata, - onCreateChart, - onLoadChart, - onExportChart, - showSettingsPanel, - onImportSkin, -}: MenuType) => { - const Root = styled(Menubar.Root)(system.css({ - display: "flex", - layerStyle: "fill.subtle", - })); - - const Menu = styled(Menubar.Menu)(system.css({})); - - const Trigger = styled(Menubar.Trigger)(system.css({ - layerStyle: "fill.subtle", - textStyle: "sm", - px: "3", - py: "1", - gap: "2", - alignItems: "center", - justifyContent: "space-between", - display: "flex", - lineHeight: "1.5", - outline: "none", - userSelect: "none", - "&[data-highlighted]": { layerStyle: "fill.muted" }, - "&[data-state='open']": { layerStyle: "fill.muted" }, - "&:hover": { layerStyle: "fill.muted" } - })); - - const Portal = styled(Menubar.Portal)(system.css({})); - const Sub = styled(Menubar.Sub)(system.css({})); - - const MenubarContent = system.css({ - minW: "40", - layerStyle: "fill.subtle", - p: "3", - }); - - const Content = styled(Menubar.Content)(MenubarContent); - const SubContent = styled(Menubar.SubContent)(MenubarContent); - - const MenuItem = system.css({ - all: "unset", - textStyle: "sm", - lineHeight: "2", - alignItems: "center", - justifyContent: "space-between", - display: "flex", - px: "3", - position: "relative", - userSelect: "none", - "&[data-highlighted]": { layerStyle: "fill.muted" }, - "&[data-state='open']": { layerStyle: "fill.muted" }, - "&:hover": { layerStyle: "fill.muted" } - }); - - const Item = styled(Menubar.Item)(MenuItem); - const SubTrigger = styled(Menubar.SubTrigger)(MenuItem); - - const Separator = styled(Menubar.Separator)(system.css({ - height: "1px", - backgroundColor: "border", - margin: "2", - })); - - const RightSlotIcon = styled(FontAwesomeIcon)(system.css({ - marginLeft: "auto", - paddingLeft: "2", - color: "text", - })); - - const Icon = styled.img(system.css({ - width: "0.7rem", - mx: "4", - my: "auto", - alignSelf: "center", - justifySelf: "center", - borderRadius: "50%", - })); - - return ( - - - - File - - - Import files - Export files - - - - - Chart - - - - - Create chart - Load chart - Export chart - - - - - - - - - Edit - - - Undo - Redo - - - - Metadata - - - - - Apply Test Metadata - Unset Metadata - - - - - Load skin - Settings - - - - - ); +export const MenuBar: React.FC = ({ + entries +}) => { + return ( + + + {entries.map((entry) => ( + + ))} + + ); }; - -export default Menu; diff --git a/src/ui/Bar/MenuBar/Separator.tsx b/src/ui/Bar/MenuBar/Separator.tsx new file mode 100644 index 0000000..c04fa88 --- /dev/null +++ b/src/ui/Bar/MenuBar/Separator.tsx @@ -0,0 +1,15 @@ +import styled from 'styled-components'; +import { Separator } from '@radix-ui/react-menubar'; +import { themeSystem } from '@/ui/theme/system'; + +const SeparatorWrapper = styled(Separator)(themeSystem.css({ + height: '1px', + backgroundColor: 'border', + margin: '2', +})); + +export const MenuSeparator = () => { + return ( + + ); +}; diff --git a/src/ui/Bar/MenuBar/style.ts b/src/ui/Bar/MenuBar/style.ts new file mode 100644 index 0000000..a15b164 --- /dev/null +++ b/src/ui/Bar/MenuBar/style.ts @@ -0,0 +1,18 @@ +import { themeSystem } from '@/ui/theme/system'; + +export const menuItem = themeSystem.css({ + layerStyle: 'fill.subtle', + textStyle: 'sm', + px: '3', + py: '1', + gap: '2', + alignItems: 'center', + justifyContent: 'space-between', + display: 'flex', + lineHeight: '1.5', + outline: 'none', + userSelect: 'none', + '&[data-highlighted]': { layerStyle: 'fill.muted' }, + '&[data-state="open"]': { layerStyle: 'fill.muted' }, + '&:hover': { layerStyle: 'fill.muted' } +}); diff --git a/src/ui/Bar/MenuBar/types.ts b/src/ui/Bar/MenuBar/types.ts new file mode 100644 index 0000000..5e87b3d --- /dev/null +++ b/src/ui/Bar/MenuBar/types.ts @@ -0,0 +1,13 @@ + +export type MenuItem = { + type?: string, + key: string, + label: string, + hotkey?: string, // TODO + onClick?: () => void, // XXX + items?: MenuItem[], // XXX +} & { type?: 'separator' }; + +export type MenuEntry = Partial> & Omit & { + items: MenuItem[], +}; From d083e11ef4a949d8ba1346f2f8a50a06880a4e12 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 00:06:23 +0800 Subject: [PATCH 099/146] feat: Remove old BlueprintJS class in HTML --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index ce498f1..bb45323 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,12 @@ - + PhiFans Editor - +
From 0ab14bacc81e320a3eca11338aea889bcdcc27d4 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 16:00:08 +0800 Subject: [PATCH 100/146] style: Moving file --- src/ui/{Bar/CreateProject.tsx => dialogs/createProject.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/ui/{Bar/CreateProject.tsx => dialogs/createProject.tsx} (100%) diff --git a/src/ui/Bar/CreateProject.tsx b/src/ui/dialogs/createProject.tsx similarity index 100% rename from src/ui/Bar/CreateProject.tsx rename to src/ui/dialogs/createProject.tsx From 9ad41644a31ed56d1e6c73169c47ab9069b038e9 Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 17:13:34 +0800 Subject: [PATCH 101/146] refactor(ui): Rename `DialogContext` to `DialogOverlay` --- src/state/runtimeStore/project.ts | 15 ++++++ src/ui/App.tsx | 8 +++- src/ui/contexts/Dialog/Provider.tsx | 71 ----------------------------- src/ui/index.tsx | 2 + src/ui/overlays/dialog.tsx | 49 ++++++++++++++++++++ 5 files changed, 72 insertions(+), 73 deletions(-) create mode 100644 src/state/runtimeStore/project.ts delete mode 100644 src/ui/contexts/Dialog/Provider.tsx create mode 100644 src/ui/overlays/dialog.tsx diff --git a/src/state/runtimeStore/project.ts b/src/state/runtimeStore/project.ts new file mode 100644 index 0000000..d4ce26e --- /dev/null +++ b/src/state/runtimeStore/project.ts @@ -0,0 +1,15 @@ +import { StateCreator } from 'zustand'; + +export interface ProjectState { + isEditable: boolean; + + setIsEditable: (isEditable: boolean) => void; +}; + +export const createProjectState: StateCreator = (set) => ({ + isEditable: false, + + setIsEditable: (isEditable) => set(({ + isEditable + })), +}); diff --git a/src/ui/App.tsx b/src/ui/App.tsx index a14571b..494a501 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -9,7 +9,7 @@ import SettingsProvider from './contexts/Settings/Provider'; import { importFromZip } from '@/runtime/skin/importer'; import { DockviewApi } from 'dockview'; import { ChartExported } from '@/Chart/Chart'; -import { DialogProvider } from "./contexts/Dialog/Provider"; +import { showCreateProjectDialog } from './dialogs/createProject'; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; import { runtimeCache } from '@/runtime/resources/cache'; @@ -132,6 +132,11 @@ function App() { key: 'file', label: 'File', items: [ + { + key: 'file.create', + label: 'Create...', + onClick: () => showCreateProjectDialog(), + }, { key: 'file.open', label: 'Open', @@ -186,7 +191,6 @@ function App() { />
-
); } diff --git a/src/ui/contexts/Dialog/Provider.tsx b/src/ui/contexts/Dialog/Provider.tsx deleted file mode 100644 index 8dc35b0..0000000 --- a/src/ui/contexts/Dialog/Provider.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Dialog, CloseButton, Portal, createOverlay } from "@chakra-ui/react" - -interface DialogProps { - id?: string - title?: string - description?: string - content?: React.ReactNode - footer?: React.ReactNode - closeButton?: boolean -} - -const dialog = createOverlay((props) => { - const { id, title, description, content, footer, closeButton, ...rest } = props - return ( - - - - - - {title && ( - - {title} - - )} - - {description && ( - {description} - )} - {content} - - {footer && ( - - {footer} - - )} - {closeButton && ( - - - - )} - - - - - ); -}); - -export const DialogProvider = () => { - // @ts-expect-error why?????? - return ; -}; - -export const openDialog = (props: DialogProps) => { - dialog.open(props.id || "default", props); -}; - -export const closeDialog = (props?: DialogProps, value?: any) => { - dialog.close(props ? props.id || "default" : "default", value || undefined); -}; - -export const updateDialog = (props: DialogProps) => { - dialog.update(props.id || "default", props); -}; - -export const removeDialog = (props?: DialogProps) => { - dialog.remove(props ? props.id || "default" : "default"); -}; - -export const waitForExitDialog = (props: DialogProps) => { - return dialog.waitForExit(props.id || "default"); -}; \ No newline at end of file diff --git a/src/ui/index.tsx b/src/ui/index.tsx index 9152e52..0a8e050 100644 --- a/src/ui/index.tsx +++ b/src/ui/index.tsx @@ -1,6 +1,7 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import { ThemeProvider } from './theme/Provider.tsx' +import { dialog } from './overlays/dialog.tsx' import '@/i18n' import './styles/index.css' import App from './App.tsx' @@ -9,6 +10,7 @@ createRoot(document.getElementById('root')!).render( + , ) diff --git a/src/ui/overlays/dialog.tsx b/src/ui/overlays/dialog.tsx new file mode 100644 index 0000000..fb53a84 --- /dev/null +++ b/src/ui/overlays/dialog.tsx @@ -0,0 +1,49 @@ +import { Dialog, CloseButton, Portal, createOverlay } from "@chakra-ui/react"; +import { DialogRootProps } from "@chakra-ui/react"; + +type $DialogRootProps = Omit; + +type DialogProps = { + title?: string + description?: string + content?: React.ReactNode + footer?: React.ReactNode + closeButton?: boolean +}; + +export const dialog = createOverlay((props) => { + const { title, description, content, footer, closeButton, ...rest } = props; + + return ( + + + + + + {title && ( + + {title} + + )} + + {description && ( + {description} + )} + {content} + + {footer && ( + + {footer} + + )} + {closeButton && ( + + + + )} + + + + + ); +}); From df0512f665dae0dbbc359a2ccc4539e78c58a26e Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 17:27:29 +0800 Subject: [PATCH 102/146] refactor(ui): Refactoring create project dialog --- src/ui/Panel/ProjectPanel/Input.tsx | 9 +- src/ui/Panel/ProjectPanel/ProjectPanel.tsx | 30 +-- src/ui/dialogs/createProject.tsx | 249 ++++++++++----------- 3 files changed, 136 insertions(+), 152 deletions(-) diff --git a/src/ui/Panel/ProjectPanel/Input.tsx b/src/ui/Panel/ProjectPanel/Input.tsx index 6274689..ab9d012 100644 --- a/src/ui/Panel/ProjectPanel/Input.tsx +++ b/src/ui/Panel/ProjectPanel/Input.tsx @@ -1,11 +1,14 @@ import { Field, Input } from "@chakra-ui/react" -import { ChartInfo } from '@/Chart/types'; import { FormEvent } from 'react'; +import { SnapshotIn } from "mobx-state-tree"; +import { Metadata } from "@/core/models/Metadata"; + +type TMetadata = Omit, 'musicFile' | 'backgroundFile'>; type ProjectInputProps = { - type: keyof ChartInfo, + type: keyof TMetadata, label: string, - onInput: (key: keyof ChartInfo, value: string) => void, + onInput: (key: K, value: TMetadata[K]) => void, sublabel?: string, placeholder?: string, defaultValue?: string, diff --git a/src/ui/Panel/ProjectPanel/ProjectPanel.tsx b/src/ui/Panel/ProjectPanel/ProjectPanel.tsx index a2c1698..06f2b0a 100644 --- a/src/ui/Panel/ProjectPanel/ProjectPanel.tsx +++ b/src/ui/Panel/ProjectPanel/ProjectPanel.tsx @@ -1,18 +1,21 @@ import { Stack } from "@chakra-ui/react" import { useState } from 'react'; -import { ChartInfo } from '@/Chart/types'; import ProjectInput from './Input'; +import { SnapshotIn } from "mobx-state-tree"; +import { Metadata } from "@/core/models/Metadata"; + +type TMetadata = Omit, 'musicFile' | 'backgroundFile'>; type ProjectPanelProps = { - project?: ChartInfo, - onChanged?: (newInfo: ChartInfo) => void, + project?: TMetadata, + onChanged?: (newMetadata: TMetadata) => void, }; const ProjectPanel = ({ project: defaultProject, onChanged, }: ProjectPanelProps) => { - const [ project, setProject ] = useState({ + const [ project, setProject ] = useState({ name: '', artist: '', illustration: '', @@ -21,11 +24,10 @@ const ProjectPanel = ({ ...(defaultProject ?? {}) }); - const handleInfoInput = (key: keyof ChartInfo, value: string) => { - setProject((prj) => { - prj[key] = value; - return prj - }); + const handleInfoUpdate: (key: K, value: TMetadata[K]) => void = (key, value) => { + setProject(() => ({ + [key]: value, + })); }; const handleInputBlur = () => { @@ -39,7 +41,7 @@ const ProjectPanel = ({ type='name' label='Name' placeholder='Song name' - onInput={handleInfoInput} + onInput={handleInfoUpdate} onBlur={handleInputBlur} /> @@ -47,7 +49,7 @@ const ProjectPanel = ({ type='artist' label='Artist' placeholder='Song artist' - onInput={handleInfoInput} + onInput={handleInfoUpdate} onBlur={handleInputBlur} /> @@ -55,7 +57,7 @@ const ProjectPanel = ({ type='illustration' label='Illustrator' placeholder='Background illustrator' - onInput={handleInfoInput} + onInput={handleInfoUpdate} onBlur={handleInputBlur} /> @@ -63,7 +65,7 @@ const ProjectPanel = ({ type='level' label='Level' placeholder='SP Lv.?' - onInput={handleInfoInput} + onInput={handleInfoUpdate} onBlur={handleInputBlur} /> @@ -71,7 +73,7 @@ const ProjectPanel = ({ type='designer' label='Designer' placeholder='Song charter' - onInput={handleInfoInput} + onInput={handleInfoUpdate} onBlur={handleInputBlur} /> diff --git a/src/ui/dialogs/createProject.tsx b/src/ui/dialogs/createProject.tsx index 699b46e..3dda636 100644 --- a/src/ui/dialogs/createProject.tsx +++ b/src/ui/dialogs/createProject.tsx @@ -1,56 +1,45 @@ import { Button, Dialog, Stack, Field, FileUpload, Input, InputGroup, CloseButton } from "@chakra-ui/react"; -import { openDialog, closeDialog, waitForExitDialog } from "@/ui/contexts/Dialog/Provider"; +import { dialog } from "../overlays/dialog"; import ProjectPanel from '@/ui/Panel/ProjectPanel/ProjectPanel'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faMusic, faImage } from "@fortawesome/free-solid-svg-icons"; -import { useRef } from 'react'; -import Chart from '@/Chart/Chart'; -import { ChartInfo } from '@/Chart/types'; -import { Nullable } from '@/utils/types'; +import { SnapshotIn } from "mobx-state-tree"; +import { Metadata } from "@/core/models/Metadata"; -type ProjectFile = 'music' | 'background'; - -type ProjectMeta = ChartInfo & { +type TMetadata = Omit, 'musicFile' | 'backgroundFile'>; +type TMetadataWithFile = TMetadata & { music: File, background: File, }; -const CreateProject = ({ Hachimi }: any) => { - const newProjectMeta = useRef>({}); +export const showCreateProjectDialog = () => { + const metadata: Partial = { + name: 'Untitled', + artist: 'Unknown', + illustration: 'Unknown', + level: 'SP Lv.?', + designer: 'Unknown', + }; - const updateNewProjectMeta = (metaOrFile: Nullable, fileType?: ProjectFile) => { - if (!metaOrFile) return; - if (!(metaOrFile instanceof Array)) { - newProjectMeta.current = { - ...newProjectMeta.current, - ...metaOrFile, - }; - return; - } + const handleUpdateMetadata = (newMetadata: TMetadata) => { + Object.assign(metadata, newMetadata); + }; - if (!fileType) return; - if (metaOrFile.length !== 1) return; - const file = metaOrFile[0]; + const handleUpdateFile = (key: K, files: File[]) => { + const [ file ] = files; + if (!file) return; - newProjectMeta.current[fileType] = file; + Object.assign(metadata, { + [key]: file, + }); }; - const createProject = async () => { - closeDialog({ id: "create-project" }); - await waitForExitDialog({ id: "create-project" }); + const handleProjectCreate = async () => { + dialog.close('create-project'); + await dialog.waitForExit('create-project'); - const projectMeta: ChartInfo & Partial = { - name: 'Untitled', - artist: 'Unknown', - illustration: 'Unknown', - level: 'SP Lv.?', - designer: 'Unknown', - ...newProjectMeta.current, - }; - - if (!projectMeta.music) { - openDialog({ - id: "create-project-error", + if (!metadata.music) { + dialog.open('create-project-error', { title: 'Error', description: 'No music file selected', footer: ( @@ -62,9 +51,8 @@ const CreateProject = ({ Hachimi }: any) => { return; } - if (!projectMeta.background) { - openDialog({ - id: "create-project-error", + if (!metadata.background) { + dialog.open("create-project-error", { title: 'Error', description: 'No background file selected', footer: ( @@ -76,101 +64,92 @@ const CreateProject = ({ Hachimi }: any) => { return; } - Chart.create(projectMeta as ProjectMeta); - } + + }; - const handleOpenDialog = () => { - openDialog({ - id: "create-project", - title: 'Create Project', - content: ( - - - Music File - updateNewProjectMeta(e.files, "music")} + dialog.open("create-project", { + title: 'Create Project', + content: ( + + + Music File + handleUpdateFile('music', e.files)} + > + + + } + endElement={ + + + + } > - - - } - endElement={ - - - - } - > - - - - - - - - - - - Background Image File - updateNewProjectMeta(e.files, "background")} + + + + + + + + + + + Background Image File + handleUpdateFile('background', e.files)} + > + + + } + endElement={ + + + + } > - - - } - endElement={ - - - - } - > - - - - - - - - - - - - ), - footer: ( - <> - - - - - - ), - closeButton: true - }); - }; - - return ( - Create Project - ); + + + + + + + + + + + + ), + footer: ( + <> + + + + + + ), + closeButton: true + }); }; - -export default CreateProject; From 9e2f32dcf00585df5077c1dd34a7659fdd89ff5e Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 17:51:13 +0800 Subject: [PATCH 103/146] refactor(ui/dialogs/createProject): Finishing create project dialog --- src/ui/dialogs/createProject.tsx | 51 ++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/ui/dialogs/createProject.tsx b/src/ui/dialogs/createProject.tsx index 3dda636..9b70b45 100644 --- a/src/ui/dialogs/createProject.tsx +++ b/src/ui/dialogs/createProject.tsx @@ -3,8 +3,11 @@ import { dialog } from "../overlays/dialog"; import ProjectPanel from '@/ui/Panel/ProjectPanel/ProjectPanel'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faMusic, faImage } from "@fortawesome/free-solid-svg-icons"; -import { SnapshotIn } from "mobx-state-tree"; +import { loadFiles } from "@/runtime/resources/loader"; +import { store as ChartStore } from "@/core/state/chartStore"; +import { applySnapshot, SnapshotIn } from "mobx-state-tree"; import { Metadata } from "@/core/models/Metadata"; +import { Chart } from "@/core/models/Chart"; type TMetadata = Omit, 'musicFile' | 'backgroundFile'>; type TMetadataWithFile = TMetadata & { @@ -12,6 +15,15 @@ type TMetadataWithFile = TMetadata & { background: File, }; +const NewChart: SnapshotIn = { + offset: 0, + judgelines: [ + { + notes: [], + } + ], +}; + export const showCreateProjectDialog = () => { const metadata: Partial = { name: 'Untitled', @@ -64,7 +76,42 @@ export const showCreateProjectDialog = () => { return; } - + dialog.open("create-project-loading", { + title: 'Loading', + description: 'Processing files...', // TODO: Progress circle + closeButton: false, + }); + + const loadFileResult = await loadFiles([ metadata.music, metadata.background ]); + if (loadFileResult.failed.includes(metadata.music.name)) { + dialog.close('create-project-loading'); + await dialog.waitForExit('create-project-loading'); + + dialog.open("create-project-error", { + title: 'Error', + description: `Failed to load audio file: ${metadata.music.name}`, + footer: ( + + + + ) + }); + } + + const _metadata: SnapshotIn & { music?: File, background?: File } = { + ...metadata, + musicFile: metadata.music.name, + backgroundFile: metadata.background.name, + }; + delete _metadata.music; + delete _metadata.background; + + applySnapshot(ChartStore, { + ...NewChart, + metadata: _metadata, + }); + + dialog.close('create-project-loading'); }; dialog.open("create-project", { From c3976b7feace561afa8670ce4f50fb009a4dc80f Mon Sep 17 00:00:00 2001 From: Misa Liu Date: Tue, 9 Sep 2025 18:02:18 +0800 Subject: [PATCH 104/146] Remove old codes --- src/App/App.ts | 22 - src/App/Hotkeys.ts | 29 -- src/Assets/Assets.ts | 40 -- src/Audio/Audio.ts | 71 --- src/Audio/Channel.ts | 55 -- src/Audio/Clip.ts | 149 ------ src/Audio/Clock.ts | 50 -- src/Audio/utils.ts | 33 -- src/Chart/BPM.ts | 55 -- src/Chart/BPMList.ts | 118 ----- src/Chart/Chart.ts | 482 ------------------ src/Chart/History/History.ts | 25 - src/Chart/History/types.ts | 49 -- src/Chart/Judgeline.ts | 388 -------------- src/Chart/JudgelineProps.ts | 61 --- src/Chart/Keyframe.ts | 60 --- src/Chart/Note.ts | 164 ------ src/Chart/Tick.ts | 116 ----- src/Chart/types.ts | 34 -- src/Database/Database.ts | 16 - src/Database/Engine.ts | 182 ------- src/Database/types.ts | 9 - src/Settings/Settings.ts | 47 -- src/Settings/types.tsx | 4 - src/Storage/File.ts | 59 --- src/Storage/Storage.ts | 41 -- src/Storage/types.ts | 32 -- src/ui/App.tsx | 53 +- .../Panel/NotePanel/NoteContainer/useWheel.ts | 8 +- .../Panel/NotePanel/NoteContainer/useWrite.ts | 4 +- src/ui/Panel/PreviewPanel/Controller.tsx | 13 +- src/ui/Panel/SettingsPanel/Rendering.tsx | 9 +- src/ui/contexts/Settings/Provider.tsx | 33 -- src/ui/contexts/Settings/index.ts | 8 - src/utils/file.ts | 34 +- 35 files changed, 13 insertions(+), 2540 deletions(-) delete mode 100644 src/App/App.ts delete mode 100644 src/App/Hotkeys.ts delete mode 100644 src/Assets/Assets.ts delete mode 100644 src/Audio/Audio.ts delete mode 100644 src/Audio/Channel.ts delete mode 100644 src/Audio/Clip.ts delete mode 100644 src/Audio/Clock.ts delete mode 100644 src/Audio/utils.ts delete mode 100644 src/Chart/BPM.ts delete mode 100644 src/Chart/BPMList.ts delete mode 100644 src/Chart/Chart.ts delete mode 100644 src/Chart/History/History.ts delete mode 100644 src/Chart/History/types.ts delete mode 100644 src/Chart/Judgeline.ts delete mode 100644 src/Chart/JudgelineProps.ts delete mode 100644 src/Chart/Keyframe.ts delete mode 100644 src/Chart/Note.ts delete mode 100644 src/Chart/Tick.ts delete mode 100644 src/Chart/types.ts delete mode 100644 src/Database/Database.ts delete mode 100644 src/Database/Engine.ts delete mode 100644 src/Database/types.ts delete mode 100644 src/Settings/Settings.ts delete mode 100644 src/Settings/types.tsx delete mode 100644 src/Storage/File.ts delete mode 100644 src/Storage/Storage.ts delete mode 100644 src/Storage/types.ts delete mode 100644 src/ui/contexts/Settings/Provider.tsx delete mode 100644 src/ui/contexts/Settings/index.ts diff --git a/src/App/App.ts b/src/App/App.ts deleted file mode 100644 index c8d4a38..0000000 --- a/src/App/App.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { EventEmitter } from "eventemitter3"; -import Audio, { Audio as AudioClass } from "@/Audio/Audio"; -import Chart, { ChartExported } from "@/Chart/Chart"; -import Assets, { AssetsManager } from '@/Assets/Assets'; -import { Hotkeys } from './Hotkeys'; -import { ChartInfo } from "@/Chart/types"; -import { Nullable } from "@/utils/types"; -import { Ticker } from "pixi.js"; -import { ImportChart } from "@/utils/file"; - -export class App { - readonly audio: AudioClass = Audio; - readonly assets: AssetsManager = Assets; - readonly events = new EventEmitter(); - readonly hotkeys = new Hotkeys(this.events); - private currentChart: Nullable = null; -} - -const app = new App(); -export default app; - -console.log(app); diff --git a/src/App/Hotkeys.ts b/src/App/Hotkeys.ts deleted file mode 100644 index 297c1b7..0000000 --- a/src/App/Hotkeys.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { EventEmitter } from 'eventemitter3'; -import hotkeys from 'hotkeys-js'; - -export class Hotkeys { - keymap: { [key: string]: string }; - event: EventEmitter; - - constructor(e: EventEmitter) { - this.keymap = {}; - this.event = e; - } - - add(key: string, id: string) { - this.keymap[key] = id; - hotkeys(key, (event: KeyboardEvent,) => { - event.preventDefault(); - this.event.emit(id); - }); - } - - remove(key: string) { - hotkeys.unbind(key); - delete this.keymap[key]; - } - - on(id: string, callback: () => void) { - this.event.on(id, callback); - } -} \ No newline at end of file diff --git a/src/Assets/Assets.ts b/src/Assets/Assets.ts deleted file mode 100644 index 5b3d813..0000000 --- a/src/Assets/Assets.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Assets } from 'pixi.js'; -import AudioClip from '@/Audio/Clip'; -import { AssetsBundle, Texture, UnresolvedAsset } from 'pixi.js'; - -const loadDefaultAssetsTexture = (): Promise> => new Promise(async (res, rej) => { - try { - const result: Record = {}; - const defaultBundle = (await (await fetch('skin/skin-bundle.json')).json()) as AssetsBundle; - await Assets.init({ manifest: { bundles: [ defaultBundle ] } }); - const bundleResult = await Assets.loadBundle('skin-default') as Record; - - for (const asset of (defaultBundle.assets as UnresolvedAsset[])) { - if (!asset.alias) continue; - result[asset.alias as string] = bundleResult[asset.alias as string]; - } - - res(result); - } catch (e) { - rej(e); - } -}); - -class AssetsManager { - readonly textures: Record = {}; - readonly sounds: Record = {}; - - constructor() { - loadDefaultAssetsTexture() - .then((e) => { - for (const name in e) { - this.textures[name] = e[name]; - } - }) - .catch(e => {throw e}); - } -} - -const assets = new AssetsManager(); -export default assets; -export { AssetsManager }; diff --git a/src/Audio/Audio.ts b/src/Audio/Audio.ts deleted file mode 100644 index 93aedba..0000000 --- a/src/Audio/Audio.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Ticker } from 'pixi.js'; -import AudioClock from './Clock'; -import AudioChannel from './Channel'; -import AudioClip from './Clip'; -import { resumeAudioCtx } from './utils'; - -const AudioCtx = window.AudioContext; -const GlobalAudioCtx = new AudioCtx({ latencyHint: 'interactive' }); -const GlobalAudioTicker = new Ticker(); -const GlobalAudioClock = new AudioClock(GlobalAudioCtx, GlobalAudioTicker, GlobalAudioCtx.baseLatency); - -export class Audio { - readonly audioCtx: AudioContext; - readonly clock: AudioClock; - - readonly masterGain: GainNode; - readonly channels: { - music: AudioChannel, - effect: AudioChannel, - }; - - constructor() { - this.audioCtx = GlobalAudioCtx; - this.clock = GlobalAudioClock; - - this.masterGain = this.audioCtx.createGain(); - this.masterGain.connect(this.audioCtx.destination); - this.channels = { - music: new AudioChannel(this, GlobalAudioTicker), - effect: new AudioChannel(this, GlobalAudioTicker), - }; - } - - static from(buffer: AudioBuffer) { - return new AudioClip(GlobalAudioCtx, GlobalAudioClock, buffer); - } - - get masterVolume() { - return this.masterGain.gain.value; - } - - set masterVolume(volume: number) { - this.masterGain.gain.value = volume; - } -} - -const audio = new Audio(); -export default audio; - -// Automatically resume AudioContext -const _resumeAudio = () => { - resumeAudioCtx(GlobalAudioCtx).catch(() => void 0); -}; -const handleWindowLoaded = () => { - window.removeEventListener('load', handleWindowLoaded); - - if (GlobalAudioCtx.state === 'running') return; - window.addEventListener('pointerdown', _resumeAudio); - window.addEventListener('pointerover', _resumeAudio); - window.addEventListener('pointerleave', _resumeAudio); -}; - -GlobalAudioCtx.addEventListener('statechange', () => { - if (GlobalAudioCtx.state !== 'running') return; - - console.info('[Audio]', 'Resume audio success'); - window.removeEventListener('pointerdown', _resumeAudio); - window.removeEventListener('pointerover', _resumeAudio); - window.removeEventListener('pointerleave', _resumeAudio); -}); -window.addEventListener('load', handleWindowLoaded); diff --git a/src/Audio/Channel.ts b/src/Audio/Channel.ts deleted file mode 100644 index 54e70dd..0000000 --- a/src/Audio/Channel.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Ticker } from 'pixi.js'; -import { Audio } from './Audio'; -import AudioClip from './Clip'; - -export default class AudioChannel { - private readonly audioCtx: AudioContext; - private readonly ticker: Ticker; - readonly gain: GainNode; - readonly playlist: Array = []; - - private isTickerStarted = false; - - constructor(audio: Audio, ticker: Ticker) { - this.audioCtx = audio.audioCtx; - this.ticker = ticker; - - this.gain = this.audioCtx.createGain(); - this.gain.connect(audio.masterGain); - - this.calcTick = this.calcTick.bind(this); - } - - startTicker() { - if (this.isTickerStarted) return; - // eslint-disable-next-line @typescript-eslint/unbound-method - this.ticker.add(this.calcTick); - this.isTickerStarted = true; - } - - stopTicker() { - if (!this.isTickerStarted) return; - // eslint-disable-next-line @typescript-eslint/unbound-method - this.ticker.remove(this.calcTick); - this.isTickerStarted = false; - } - - private calcTick() { - while(this.playlist.length > 0) { - const audio = this.playlist.shift()!; - const buffer = this.audioCtx.createBufferSource(); - - buffer.buffer = audio.source; - buffer.connect(this.gain); - buffer.start(); - } - } - - get volume() { - return this.gain.gain.value; - } - - set volume(value: number) { - this.gain.gain.value = value; - } -} diff --git a/src/Audio/Clip.ts b/src/Audio/Clip.ts deleted file mode 100644 index 7c0d7d0..0000000 --- a/src/Audio/Clip.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { Nullable } from '@/utils/types'; -import AudioChannel from './Channel'; -import AudioClock from './Clock'; -import Audio from './Audio'; -import { ReadFileAsAudioBuffer } from '@/utils/file'; - -export enum EAudioClipStatus { - STOP = 0, - PLAY = 1, - PAUSE = 2, -} - -export default class AudioClip { - readonly source: AudioBuffer; - - private _timeOffset: number = 0; - private _channel: Nullable = null; - private buffer?: AudioBufferSourceNode; - private readonly audioCtx: AudioContext; - readonly clock: AudioClock; - - status: EAudioClipStatus = EAudioClipStatus.STOP; - startTime: number = NaN; - pauseTime: number = NaN; - - constructor(audioCtx: AudioContext, clock: AudioClock, audioBuffer: AudioBuffer, channel: Nullable = null) { - this.source = audioBuffer; - this._channel = channel; - - this.audioCtx = audioCtx; - this.clock = clock; - } - - static from(file: Blob, channel?: AudioChannel): Promise {return new Promise((res, rej) => { - ReadFileAsAudioBuffer(file) - .then((buffer) => res(new AudioClip(Audio.audioCtx, Audio.clock, buffer, channel))) - .catch((e) => rej(e)); - })} - - play() { - if (!this._channel) throw new Error('Cannot play a clip directly without any channel'); - if (this.status === EAudioClipStatus.PLAY) return; - - this.buffer = this.audioCtx.createBufferSource(); - this.buffer.buffer = this.source; - this.buffer.connect(this._channel.gain); - - if (isNaN(this.pauseTime)) { - this.startTime = this.clock.time; - this.buffer.start(0, 0); - } else { - const pausedTime = this.pauseTime - this.startTime; - this.startTime = this.clock.time - pausedTime; - this.buffer.start(0, pausedTime); - } - - this.pauseTime = NaN; - this.status = EAudioClipStatus.PLAY; - this.buffer.onended = () => this.stop(); - } - - pause() { - if (this.status !== EAudioClipStatus.PLAY) return; - - this.disconnectBuffer(); - this.pauseTime = this.clock.time; - this.status = EAudioClipStatus.PAUSE; - } - - stop() { - if (this.status === EAudioClipStatus.STOP) return; - - this.disconnectBuffer(); - this.startTime = NaN; - this.pauseTime = NaN; - this.status = EAudioClipStatus.STOP; - } - - /** - * - * @param {number} time Seek seconds - */ - seek(time: number) { - let _time = time + this._timeOffset; - if (_time < 0) _time = 0; - - if (this.status === EAudioClipStatus.STOP) { - const currentTime = this.clock.time; - this.startTime = currentTime - _time; - this.pauseTime = currentTime; - return; - } - - const isPlayingBefore = this.status === EAudioClipStatus.PLAY; - this.pause(); - this.startTime = this.pauseTime - _time; - - if (this.startTime > this.pauseTime) this.startTime = this.pauseTime; - if (isPlayingBefore) this.play(); - } - - destroy() { - if (!this._channel) return; - this.stop(); - } - - get channel() { - return this._channel; - } - - set channel(channel: Nullable) { - this._channel = channel; - } - - get time() { - if (isNaN(this.startTime)) return -this._timeOffset; - else if (isNaN(this.pauseTime)) return this.clock.time - this.startTime - this._timeOffset; - else return this.pauseTime - this.startTime - this._timeOffset; - } - - get duration() { - return this.source.duration - this._timeOffset; - } - - get timeOffset() { - return this._timeOffset; - } - - set timeOffset(offset: number) { - this._timeOffset = offset; - } - - get speed() { - return this.buffer ? this.buffer.playbackRate.value : 1; - } - - set speed(value: number) { - if (this.buffer) this.buffer.playbackRate.value = value; - } - - private disconnectBuffer() { - if (!this.buffer) return; - - this.buffer.stop(); - this.buffer.disconnect(); - this.buffer.onended = null; - this.buffer = (void 0); - } -} diff --git a/src/Audio/Clock.ts b/src/Audio/Clock.ts deleted file mode 100644 index 202b0bc..0000000 --- a/src/Audio/Clock.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Ticker } from 'pixi.js'; -import { resumeAudioCtx } from './utils'; - -export default class AudioClock { - /** - * The current audio time. - */ - public time: number = 0; - - private offsets: number[] = []; - private sum: number = 0; - - private readonly audioCtx: AudioContext; - private readonly ticker: Ticker; - private readonly baseOffset; - - constructor(audioCtx: AudioContext, ticker: Ticker, baseOffset: number = 0) { - this.audioCtx = audioCtx; - this.ticker = ticker; - this.baseOffset = baseOffset; - - this.calcTick = this.calcTick.bind(this); - this.init().catch(() => void 0); - } - - private async init() { - this.audioCtx.addEventListener('statechange', () => { - // eslint-disable-next-line @typescript-eslint/unbound-method - if (this.audioCtx.state === 'running') this.ticker.add(this.calcTick); - }); - - await resumeAudioCtx(this.audioCtx); - this.ticker.start(); - } - - private calcTick() { - const { audioCtx, baseOffset, offsets } = this; - const realTime = performance.now() / 1000; - const delta = realTime - audioCtx.currentTime - baseOffset; - - offsets.push(delta); - this.sum += delta; - - while(offsets.length > 60) { - this.sum -= offsets.shift()!; - } - - this.time = realTime - this.sum / offsets.length; - } -} diff --git a/src/Audio/utils.ts b/src/Audio/utils.ts deleted file mode 100644 index 822f030..0000000 --- a/src/Audio/utils.ts +++ /dev/null @@ -1,33 +0,0 @@ - -/** - * Resume an AudioContext. - * @link https://github.com/bemusic/bemuse/blob/master/bemuse/src/sampling-master/index.js#L276 - * @param audioCtx - * @returns {Promise} Return false if resume failed - */ -export const resumeAudioCtx = (audioCtx: AudioContext): Promise => { - if (audioCtx.state === 'running') return new Promise((res) => res(true)); - - console.info('[Audio]', 'Try resuming audio...'); - - const gain = audioCtx.createGain(); - const osc = audioCtx.createOscillator(); - - osc.frequency.value = 440; - - osc.start(audioCtx.currentTime + 0.1); - osc.stop(audioCtx.currentTime + 0.1); - - gain.connect(audioCtx.destination); - gain.disconnect(); - - return new Promise((res) => { - audioCtx.resume() - .then(() => res(true)) - .catch((e) => { - res(false); - console.error('[Audio]', 'Failed to resume audio'); - console.error(e); - }); - }); -}; diff --git a/src/Chart/BPM.ts b/src/Chart/BPM.ts deleted file mode 100644 index d3e5aa6..0000000 --- a/src/Chart/BPM.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { v4 as uuid } from 'uuid'; -import { BeatArrayToNumber, parseDoublePrecist } from '@/utils/math'; -import { BeatArray } from '@/utils/types'; - -export type ChartBPMExported = { - beat: BeatArray, - bpm: number, -}; - -export default class ChartBPM { - /** Internal property */ - readonly id: string; - - beat: BeatArray; - beatNum: number; - bpm: number; - - time: number ; - timePerBeat: number; - endBeat: BeatArray; - endBeatNum: number; - endTime: number; - - constructor(beat: BeatArray, bpm: number, id = uuid()) { - if (BeatArrayToNumber(beat) < 0) throw new Error('Cannot set a negative beat to BPM!'); - if (bpm <= 0) throw new Error('Cannot set a zero/negative BPM!'); - - this.id = id; - this.beat = beat; - this.beatNum = BeatArrayToNumber(this.beat); - this.bpm = bpm; - - /** - * NOTE: These will be generated by BPMList automatically, - * please do not edit them manually! - */ - this.time = NaN; - this.timePerBeat = parseDoublePrecist(60 / this.bpm, 6, -1); - this.endBeat = [ Infinity, 0, 1 ]; - this.endBeatNum = Infinity; - this.endTime = Infinity; - } - - update() { - this.beatNum = BeatArrayToNumber(this.beat); - this.timePerBeat = parseDoublePrecist(60 / this.bpm, 6, -1); - } - - get json(): ChartBPMExported { - return { - beat: this.beat, - bpm: this.bpm, - }; - } -} diff --git a/src/Chart/BPMList.ts b/src/Chart/BPMList.ts deleted file mode 100644 index 8384a2a..0000000 --- a/src/Chart/BPMList.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { BeatArrayToNumber, parseDoublePrecist } from '@/utils/math'; -import ChartBPM, { ChartBPMExported } from './BPM'; -import { BeatArray } from '@/utils/types'; - -const BPMSortFn = (a: ChartBPM, b: ChartBPM) => BeatArrayToNumber(a.beat) - BeatArrayToNumber(b.beat); - -export default class ChartBPMList extends Array { - add(beat: BeatArray, bpm: number) { - const newBPM = new ChartBPM(beat, bpm); - this.push(newBPM); - this.calcRealTime(); - return newBPM; - } - - remove(id: string) { - if (this.length === 1) return; - - const bpmIndex = this.findIndex((e) => e.id === id); - if (bpmIndex === -1) return; - const oldBPM = this[bpmIndex]; - - this.splice(bpmIndex, 1); - this.calcRealTime(); - return oldBPM; - } - - edit(id: string, newBPM?: number, newBeat?: BeatArray) { - const bpm = this.findByID(id); - if (!bpm) return; - - if (newBPM) bpm.bpm = newBPM; - if (newBeat) bpm.beat = newBeat; - - bpm.update(); - this.calcRealTime(); - return bpm; - } - - findByID(id: string) { - const bpm = this.find((e) => e.id === id); - return bpm; - } - - findByTime(beat: BeatArray) { - const beatNum = BeatArrayToNumber(beat); - const bpm = this.find((e) => e.beatNum === beatNum); - return bpm; - } - - getRealTime(beat: BeatArray | number) { - if (typeof beat === 'number') return this.getRealTimeByBeatNum(beat); - else return this.getRealTimeByBeatNum(BeatArrayToNumber(beat)); - } - - timeToBeatNum(time: number) { - if (this.length === 1 || time < 0) return parseDoublePrecist(time / this[0].timePerBeat, 6, -1); - - for (const bpm of this) { - if (bpm.endTime <= time) continue; - if (bpm.time > time) break; - - return parseDoublePrecist(bpm.beatNum + (time - bpm.time) / bpm.timePerBeat, 6, -1); - } - - throw new Error(`Cannot found beat number for time ${time}`); - } - - private calcRealTime() { - this.sort(BPMSortFn); - if (BeatArrayToNumber(this[0].beat) !== 0) { - this[0].beat = [ 0, 0, 1 ]; - this[0].beatNum = 0; - } - - let currentTimePerBeat = this[0].timePerBeat; - let bpmChangedBeat = 0; - let bpmChangedTime = 0; - - for (let i = 0; i < this.length; i++) { - const bpm = this[i]; - const bpmNext = this[i + 1]; - - bpmChangedTime = parseDoublePrecist(bpmChangedTime + ( - currentTimePerBeat * (bpm.beatNum - bpmChangedBeat) - ), 6, -1); - bpmChangedBeat = parseDoublePrecist(bpmChangedBeat + ( - bpm.beatNum - bpmChangedBeat - ), 6, -1); - currentTimePerBeat = bpm.timePerBeat; - - bpm.time = bpmChangedTime; - bpm.endBeat = bpmNext ? bpmNext.beat : [ Infinity, 0, 1 ]; - bpm.endBeatNum = bpmNext ? BeatArrayToNumber(bpmNext.beat) : Infinity; - bpm.endTime = bpmNext ? parseDoublePrecist(bpm.time + ( - bpm.timePerBeat * (bpm.endBeatNum - bpm.beatNum) - ), 6, -1) : Infinity; - } - } - - get json(): ChartBPMExported[] { - return this.map((e) => e.json); - } - - private getRealTimeByBeatNum(beat: number) { - if (!isFinite(beat)) return beat; - if (this.length <= 0) return parseDoublePrecist(beat * 0.5, 6, -1); - if (this.length === 1 || beat < 0) return parseDoublePrecist((beat - this[0].beatNum) * this[0].timePerBeat, 6, -1); - - for (const bpm of this) { - if (bpm.endBeatNum <= beat) continue; - if (bpm.beatNum > beat) break; - - return parseDoublePrecist(bpm.time + (beat - bpm.beatNum) * bpm.timePerBeat, 6, -1); - } - - throw new Error(`Cannot found BPM for beat ${JSON.stringify(beat)}`); - } -} diff --git a/src/Chart/Chart.ts b/src/Chart/Chart.ts deleted file mode 100644 index 1c8db70..0000000 --- a/src/Chart/Chart.ts +++ /dev/null @@ -1,482 +0,0 @@ -import { Container, Sprite, Texture, Ticker } from 'pixi.js'; -import { EventEmitter } from 'eventemitter3'; -import { v4 as uuid } from 'uuid'; -import Audio from '@/Audio/Audio'; -import AudioClip, { EAudioClipStatus } from '@/Audio/Clip'; -import Database from '@/Database/Database'; -import StorageFile from '@/Storage/File'; -import ChartBPMList from './BPMList'; -import ChartJudgeline, { ChartJudgelineExported } from './Judgeline'; -import ChartNote from './Note'; -import ChartTick from './Tick'; -import { ChartBookmark, ChartInfo, ChartInfoWithFile } from './types'; -import { BeatArray, Nullable, RendererSize } from '@/utils/types'; -import { CalculateRendererSize } from '@/utils/renderer'; -import { ChartBPMExported } from './BPM'; -import ChartHistory from './History/History'; -import { TChartJudgelineProps } from './JudgelineProps'; -import { ChartKeyframeExported } from './Keyframe'; -import { TProject } from '@/Database/types'; -import { ReadFileAsText } from '@/utils/file'; -import { TStorageFile } from '@/Storage/types'; - -type $ChartInfo = ChartInfoWithFile & { - id: string, -}; - -export type ChartExported = { - info: ChartInfo, - offset: number, - bpm: ChartBPMExported[], - lines: ChartJudgelineExported[], -}; - -class Chart { - // Chart data - bpm: ChartBPMList = new ChartBPMList(); - lines: ChartJudgeline[] = []; - notes: ChartNote[] = []; - - _offset: number = 0; - offsetBeat: number = 0; - - bookmarks: ChartBookmark[] = []; - histories: ChartHistory = new ChartHistory(this); - - rendererSize = CalculateRendererSize(1, 1); - readonly container = new Container(); - - readonly events = new EventEmitter(); - readonly ticker: Ticker; - readonly tick = ChartTick.bind(this); - - // Resources - private _info: Nullable<$ChartInfo> = null; - private _id: Nullable = null; - private _music: Nullable = null; - private _background: Nullable = null; - - constructor() { - // Init ticker - this.ticker = new Ticker(); - this.ticker.stop(); - this.ticker.add(this.tick); - } - - create(infoWithFile: ChartInfoWithFile) { - if (this._info !== null) return; - - this._info = { - ...infoWithFile, - id: uuid(), - }; - this._id = null; - - this.addBPM([ 0, 0, 1 ], 120, false, false); - this.addLine(true, false); - - this.loadFiles(); - this.events.emit('loaded', this); - } - - load(infoWithFile: ChartInfoWithFile, chartJson: ChartExported, projectID = uuid(), chartID = uuid()) { - if (this._info !== null) return; - - const addKeyframesToLine = (line: ChartJudgeline, type: keyof TChartJudgelineProps, keyframes: ChartKeyframeExported[]) => { - for (const keyframe of keyframes) { - line.addKeyframe(type, keyframe.beat, keyframe.value, keyframe.continuous, keyframe.easing); - } - }; - - this._info = { - ...infoWithFile, - id: projectID, - }; - this._id = chartID; - this._offset = chartJson.offset / 1000; - - for (const bpm of chartJson.bpm) { - this.addBPM(bpm.beat, bpm.bpm, false, false); - } - - for (const line of chartJson.lines) { - const newLine = this.addLine(false, false)!; - - for (const _name in line.props) { - const name = _name as keyof TChartJudgelineProps; - addKeyframesToLine(newLine, name, line.props[name]); - newLine.updateProp(name, true); - } - - newLine.calcFloorPositions(); - - for (const note of line.notes) { - newLine.addNote({ - ...note - }); - } - } - - this.loadFiles(); - this.events.emit('loaded', this); - } - - saveToDatabase(): Promise> {return new Promise(async (res) => { - if (!this._info) return res(null); - - const oldProject = await Database.project.get(this._info.id); - if (oldProject) { - const projectInfo: ChartInfo & Partial<$ChartInfo> & Partial = { - ...oldProject, - ...this._info, - }; - - delete projectInfo.music; - delete projectInfo.background; - - await StorageFile.update(this._id!, new Blob([ JSON.stringify(this.json) ])); - await Database.project.update(projectInfo.id!, projectInfo as TProject); - - return res(projectInfo as TProject); - } else { - const { id: musicID } = await StorageFile.add(this._info.music); - const { id: backgroundID } = await StorageFile.add(this._info.background); - const { id: chartID } = await StorageFile.add(new Blob([ JSON.stringify(this.json) ])); - - this._id = chartID; - - const projectInfo: ChartInfo & Partial<$ChartInfo> & Partial = { ...this._info }; - - delete projectInfo.music; - delete projectInfo.background; - - projectInfo.chartID = chartID; - projectInfo.musicID = musicID; - projectInfo.backgroundID = backgroundID; - projectInfo.filesID = uuid(); // TODO - - await Database.project.add(projectInfo as TProject); - return res(projectInfo as TProject); - } - })} - - clear() { - if (!this._info) return; - - this.ticker.stop(); - - this._music?.destroy(); - this._background?.destroy(); - - this._music = null; - this._background = null; - this._info = null; - this._id = null; - - this.bpm.length = 0; - this.lines.length = 0; - - this.events.emit('clear', null); - } - - loadFromDatabase(projectID: string) {return new Promise(async (res, rej) => { - if (this._info !== null) return res(null); - - const projectMeta = await Database.project.get(projectID); - if (!projectMeta) return rej(`No project found: ${projectID}`); - - const musicFile = await StorageFile.get(projectMeta.musicID) as Nullable; - if (!musicFile) return rej(`No file found: ${projectMeta.musicID}`); - - const backgroundFile = await StorageFile.get(projectMeta.backgroundID) as Nullable; - if (!backgroundFile) return rej(`No file found: ${projectMeta.backgroundID}`); - - const chartFile = await StorageFile.get(projectMeta.chartID) as Nullable; - if (!chartFile) return rej(`No file found: ${projectMeta.chartID}`); - - // TODO: Extra files - - const chartText = await ReadFileAsText(chartFile.blob); - const chartJson = JSON.parse(chartText) as ChartExported; - - this.load({ - name: projectMeta.name, - artist: projectMeta.artist, - illustration: projectMeta.illustration, - level: projectMeta.level, - designer: projectMeta.designer, - music: musicFile.blob, - background: backgroundFile.blob, - }, chartJson, projectMeta.id, projectMeta.chartID); - res(this); - })} - - async play() { - if (!this._info) return; - await this.waitAudio(); - this._music!.play(); - } - - async pause() { - if (!this._info) return; - await this.waitAudio(); - this._music!.pause(); - } - - async playOrPause() { - if (!this._info) return; - await this.waitAudio(); - if (this._music!.status === EAudioClipStatus.PLAY) this._music!.pause(); - else this._music!.play(); - } - - async stop() { - if (!this._info) return; - await this.waitAudio(); - this._music!.stop(); - } - - addLine(addDefaultKeyframes = true, addToHistory = true) { - if (!this._info) return; - const newLine = new ChartJudgeline(this, addDefaultKeyframes); - this.lines.push(newLine); - this.container.addChild(newLine.sprite); - if (addToHistory) this.histories.add({ - name: 'line', - action: 'add', - id: newLine.id, - after: newLine.json, - }); - - this.events.emit('lines.added', newLine); - this.events.emit('lines.updated', this.lines); - - return newLine; - } - - removeLine(id: string, emit = true, addToHistory = true) { - if (!this._info) return; - const lineIndex = this.lines.findIndex((e) => e.id === id); - if (lineIndex === -1) return; - - const line = this.lines[lineIndex]; - line.destroy(); - this.lines.splice(lineIndex, 1); - if (addToHistory) this.histories.add({ - name: 'line', - action: 'delete', - id: line.id, - before: line.json, - }); - - if (emit) { - this.events.emit('lines.removed', line); - this.events.emit('lines.updated', [ ...this.lines ]); - } - } - - addBPM(time: BeatArray, bpm: number, emit = true, addToHistory = true) { - if (!this._info) return; - const newBPM = this.bpm.add(time, bpm); - if (addToHistory) this.histories.add({ - name: 'bpm', - action: 'add', - id: newBPM.id, - after: newBPM.json, - }); - - this.updateLinesTime(); - this.updateOffsetBeat(); - if (emit) this.events.emit('bpms.updated', [ ...this.bpm ]); - } - - editBPM(id: string, newBeat?: BeatArray, newBPM?: number, emit = true) { - if (!this._info) return; - this.bpm.edit(id, newBPM, newBeat); - this.updateLinesTime(); - this.updateOffsetBeat(); - if (emit) this.events.emit('bpms.updated', [ ...this.bpm ]); - } - - removeBPM(id: string, emit = true, addToHistory = true) { - if (!this._info) return; - const oldBPM = this.bpm.remove(id); - if (!oldBPM) return; - if (addToHistory) this.histories.add({ - name: 'bpm', - action: 'delete', - id: oldBPM.id, - before: oldBPM.json, - }) - - this.updateLinesTime(); - this.updateOffsetBeat(); - if (emit) this.events.emit('bpms.updated', [ ...this.bpm ]); - } - - resize(size: RendererSize) { - this.rendererSize = size; - - this.container.position.set( - size.widthRealHalf, - size.heightHalf - ); - - for (const line of this.lines) { - line.resize(size); - } - } - - updateOffsetBeat() { - if (!this._info) return; - if (this.bpm.length <= 0) return; - - const offsetBeat = this.bpm.timeToBeatNum(this._offset); - if (this.offsetBeat === offsetBeat) return; - - this.offsetBeat = offsetBeat; - this.events.emit('offset.updated', { offset: this.offset, offsetBeat: offsetBeat }); - } - - get info(): Nullable { - if (!this._info) return null; - - const chartInfo: Partial & ChartInfo = { ...this._info }; - - delete chartInfo.music; - delete chartInfo.background; - - return chartInfo; - } - - get files() { - if (!this._info) return null; - - return { - music: this._info.music, - background: this._info.background, - chart: new Blob([ JSON.stringify(this.json) ]), - }; - } - - get json(): Nullable { - if (this._info === null) return null; - - return { - info: this.info!, - offset: this.offset, - bpm: this.bpm.json, - lines: this.lines.map((e) => e.json), - }; - } - - get status() { - if (!this._info) return EAudioClipStatus.STOP; - return this._music ? this._music.status : EAudioClipStatus.STOP; - } - - get time() { - if (!this._info) return 0; - return this._music ? this._music.time : 0; - } - - set time(time: number) { - if (!this._info) return; - this.waitAudio() - .then(() => this._music!.seek(time)) - .catch(() => void 0); - } - - get duration() { - if (!this._info) return 0; - return this._music ? this._music.duration : 0; - } - - get beatNum() { - if (!this._info) return 0; - return this.bpm.timeToBeatNum(this.time); - } - - set beatNum(beatNum: number) { - if (!this._info) return; - this.waitAudio() - .then(() => this._music!.seek(this.bpm.getRealTime(beatNum))) - .catch(() => void 0); - } - - get beatDuration() { - if (!this._info) return 0; - return this.bpm.timeToBeatNum(this.duration); - } - - get offset() { - if (!this._info) return 0; - return this._offset * 1000; - } - - set offset(offset: number) { - const _offset = offset / 1000; - this._offset = _offset; - - this.updateOffsetBeat(); - this.waitAudio() - .then((clip) => { - clip.timeOffset = _offset; - }) - .catch(() => void 0); - } - - private loadFiles() { - if (!this._info) return; - - AudioClip.from(this._info.music, Audio.channels.music) - .then((clip) => { - clip.timeOffset = this._offset; - this._music = clip; - - this.updateOffsetBeat(); - this.ticker.start(); - this.events.emit('music.loaded', this._music); - }) - .catch((e) => { throw e }); - - createImageBitmap(this._info.background) - .then((bitmap) => { - this._background = Sprite.from(Texture.from(bitmap)); - this._background.anchor.set(0.5); - - this.events.emit('background.loaded', this._background); - }) - .catch((e) => { throw e }); - } - - private waitAudio(): Promise {return new Promise((res) => { - if (this._music) return res(this._music); - const clockId = setInterval(() => { - if (!this._music) return; - res(this._music); - clearInterval(clockId); - }, 200); - })} - - private updateLinesTime() { - for (const line of this.lines) { - line.updateProp('speed', true); - line.updateProp('positionX', true); - line.updateProp('positionY', true); - line.updateProp('rotate', true); - line.updateProp('alpha', true); - - line.calcFloorPositions(); - for (const note of line.notes) { - line.calcNoteTime(note); - } - } - } -} - -const chart = new Chart(); -console.log(chart); - -export default chart; -export { Chart }; diff --git a/src/Chart/History/History.ts b/src/Chart/History/History.ts deleted file mode 100644 index 6af3e73..0000000 --- a/src/Chart/History/History.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Chart from '../Chart'; -import { HistoryType } from './types'; - -class ChartHistory extends Array { - readonly chart: Chart; - currentIndex = 0; - - constructor(chart: Chart, histories?: HistoryType[]) { - super(); - - this.chart = chart; - if (histories) this.push(...histories); - } - - add(action: HistoryType) { - this.unshift(action); - this.currentIndex = 0; - // TODO: History count in settings - if (this.length > 20) this.length = 20; - } - - -} - -export default ChartHistory; diff --git a/src/Chart/History/types.ts b/src/Chart/History/types.ts deleted file mode 100644 index ddaff85..0000000 --- a/src/Chart/History/types.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ChartBPMExported } from "../BPM"; -import { ChartJudgelineExported } from "../Judgeline"; -import { TChartJudgelineProps } from "../JudgelineProps"; -import { ChartKeyframeExported } from "../Keyframe"; -import { ChartNoteExported } from "../Note"; - - -export type HistoryBaseAdd = { - id: string, - action: 'add', - after: Partial, -}; - -export type HistoryBaseEdit = { - id: string, - action: 'edit', - before: Partial, - after: Partial, -}; - -export type HistoryBaseDelete = { - id: string, - action: 'delete', - before: Partial, -}; - -export type HistoryBase = HistoryBaseAdd | HistoryBaseEdit | HistoryBaseDelete; - - -export type HistoryBPM = HistoryBase & { - name: 'bpm', -}; - -export type HistoryLine = HistoryBase & { - name: 'line', -}; - -export type HistoryKeyframe = HistoryBase & { - name: 'keyframe', - type: keyof TChartJudgelineProps, - lineID: string, -}; - -export type HistoryNote = HistoryBase & { - name: 'note', - lineID: string, -}; - -export type HistoryType = HistoryBPM | HistoryLine | HistoryKeyframe | HistoryNote; diff --git a/src/Chart/Judgeline.ts b/src/Chart/Judgeline.ts deleted file mode 100644 index 0525b72..0000000 --- a/src/Chart/Judgeline.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { v4 as uuid } from 'uuid'; -import { EventEmitter } from 'eventemitter3'; -import { BeatArray, RendererSize } from '@/utils/types'; -import JudgelineProps, { ChartJudgelinePropsExported, TChartJudgelineProps } from './JudgelineProps'; -import ChartKeyframe, { TChartKeyframe } from './Keyframe'; -import Note, { ChartNoteExported, ChartNoteProps } from './Note'; -import { BeatArrayToNumber, parseDoublePrecist } from '@/utils/math'; -import { getLinePropValue } from '@/utils/chart'; -import { Container, Sprite, Texture } from 'pixi.js'; -import Chart from './Chart'; -import { FloorPosition, NoteType } from './types'; - -const PropsSortFn = (a: ChartKeyframe, b: ChartKeyframe) => a.beatNum - b.beatNum; - -export type ChartJudgelineExported = { - props: ChartJudgelinePropsExported, - notes: ChartNoteExported[], -}; - -export default class ChartJudgeline { - /** Internal property */ - readonly id: string; - readonly chart: Chart; - - props: JudgelineProps; - floorPositions: FloorPosition[] = []; - notes: Note[] = []; - - // Used for live preview - _speed: number = 1; - _posX: number = 0; - _posY: number = 0; - _alpha: number = 1; - _rotate: number = 0; - - _fPos: number = 0; - _realPosX: number = 0; - _realPosY: number = 0; - _radian: number = 0; - _cosr: number = 0; - _sinr: number = 0; - - readonly events: EventEmitter = new EventEmitter(); - sprite!: Sprite; - - constructor(chart: Chart, addDefaultKeyframes = true, id = uuid()) { - this.id = id; - this.chart = chart; - - this.props = new JudgelineProps(addDefaultKeyframes); - - if (addDefaultKeyframes) { - this.updateProp('speed', true); - this.updateProp('positionX', true); - this.updateProp('positionY', true); - this.updateProp('rotate', true); - this.updateProp('alpha', true); - - this.calcFloorPositions(); - } - - this.createSprite(); - } - - addKeyframe( - type: keyof TChartJudgelineProps, - beat: BeatArray, - value: number, - continuous: boolean, - easing: number - ) { - const keyframeArr = this.props[type]; - if (!keyframeArr || !(keyframeArr instanceof Array)) throw new Error(`No such type: ${type}`); - if (this.findKeyframeByBeat(type, beat)) return; - - const newKeyframe = new ChartKeyframe(type, beat, value, continuous, easing); - keyframeArr.push(newKeyframe); - - this.updateProp(type); - if (type === 'speed') { - this.calcFloorPositions(); - this.updateNotesFloorPosition(); - } - - this.events.emit('props.updated', { type, keyframes: [ ...keyframeArr ] }); - } - - editKeyframe( - type: keyof TChartJudgelineProps, - id: string, - newProps: Partial = {} - ) { - const keyframeArr = this.props[type]; - if (!keyframeArr || !(keyframeArr instanceof Array)) throw new Error(`No such type: ${type}`); - - const keyframe = this.findKeyframeById(type, id); - if (!keyframe) throw new Error(`Cannot find keyframe ID: "${id}" for props ${type}`); - if (newProps.beat && this.findKeyframeByBeat(type, newProps.beat)) return; - - const prevKeyframe = keyframeArr.find((e) => e.nextKeyframe && e.nextKeyframe.id === keyframe.id); - if (prevKeyframe) prevKeyframe.nextKeyframe = null; - - for (const name in newProps) { - // XXX: This sucks - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - keyframe[name] = newProps[name]; - } - - keyframe.beatNum = BeatArrayToNumber(keyframe.beat); - keyframe.time = this.chart.bpm.getRealTime(keyframe.beat); - - this.updateProp(type); - if (type === 'speed') { - this.calcFloorPositions(); - this.updateNotesFloorPosition(); - } - - this.events.emit('props.updated', { type, keyframes: [ ...keyframeArr ] }); - } - - deleteKeyframe(type: keyof TChartJudgelineProps, id: string) { - const keyframeArr = this.props[type]; - if (!keyframeArr || !(keyframeArr instanceof Array)) throw new Error(`No such type: ${type}`); - if (keyframeArr.length === 1) return; - - const keyframeIndex = keyframeArr.findIndex((e) => e.id === id); - if (keyframeIndex === -1) throw new Error(`Cannot find keyframe ID: "${id}" for props ${type}`); - - const prevKeyframe = keyframeArr.find((e) => e.nextKeyframe && e.nextKeyframe.id === id); - if (prevKeyframe) prevKeyframe.nextKeyframe = null; - - // const keyframe = keyframeArr[keyframeIndex]; - keyframeArr.splice(keyframeIndex, 1); - - this.updateProp(type); - if (type === 'speed') { - this.calcFloorPositions(); - this.updateNotesFloorPosition(); - } - - this.events.emit('props.updated', { type, keyframes: [ ...keyframeArr ] }); - } - - findKeyframeByBeat(type: keyof TChartJudgelineProps, beat: BeatArray) { - const keyframeArr = this.props[type]; - if (!keyframeArr || !(keyframeArr instanceof Array)) throw new Error(`No such type: ${type}`); - - const beatNum = BeatArrayToNumber(beat); - return keyframeArr.find((e) => e.beatNum === beatNum); - } - - findKeyframeById(type: keyof TChartJudgelineProps, id: string) { - const keyframeArr = this.props[type]; - if (!keyframeArr || !(keyframeArr instanceof Array)) throw new Error(`No such type: ${type}`); - - return keyframeArr.find((e) => e.id === id); - } - - addNote(props: Omit, id = uuid()) { - const note = this.calcNoteTime(new Note({ - ...props, - line: this, - }, id)); - this.notes.push(note); - this.sortNotes(); - - note.resize(this.chart.rendererSize); - this.sprite.parent.addChild(note.sprite!); - - this.events.emit('note.added', note); - this.events.emit('notes.updated', [ ...this.notes ]); - - return note; - } - - editNote(id: string, newProps: Partial>) { - const note = this.findNoteById(id); - if (!note) throw new Error(`Cannot find note ID: "${id}" for line "${this.id}"`); - - for (const name in newProps) { - // XXX: This sucks - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - note[name] = newProps[name]; - } - - note.beatNum = BeatArrayToNumber(note.beat); - note.updateHoldProps(); - this.calcNoteTime(note); - this.sortNotes(); - - if (newProps['type'] !== (void 0)) note.createSprite(this.sprite.parent); - note.resize(this.chart.rendererSize); - - this.events.emit('notes.updated', [ ...this.notes ]); - } - - deleteNote(id: string) { - const noteIndex = this.notes.findIndex((e) => e.id === id); - if (noteIndex === -1) throw new Error(`Cannot find note ID: "${id}" for line "${this.id}"`); - - const note = this.notes[noteIndex]; - this.notes.splice(noteIndex, 1); - note.sprite!.removeFromParent(); - note.sprite!.destroy(); - - this.events.emit('note.removed', note); - this.events.emit('notes.updated', [ ...this.notes ]); - } - - findNoteById(id: string) { - return this.notes.find((e) => e.id === id); - } - - getFloorPosition(time: number) { - const getFloorPosition = (time: number) => { - for (const event of this.floorPositions) { - if (event.endTime <= time) continue; - if (event.time > time) break; - - return event; - } - - return { - time, - endTime: Infinity, - value: time, - }; - }; - - const speed = getLinePropValue(time, this.props.speed, 1); - const floorPosition = getFloorPosition(time); - - return parseDoublePrecist(floorPosition.value + (speed * (time - floorPosition.time)), 3, 1); - } - - createSprite(container?: Container) { - this.sprite = new Sprite(Texture.WHITE); - - this.sprite.width = 1920; - this.sprite.height = 3; - this.sprite.anchor.set(0.5); - - if (container) container.addChild(this.sprite); - return this.sprite; - } - - resize(size: RendererSize) { - const scaleX = Math.round((4000 / 1920) * (size.width / 1350) * 1920); - const scaleY = Math.round(size.lineScale * 18.75 * 0.008); - - this.sprite.scale.set(scaleX, scaleY); - - for (const note of this.notes) { - note.resize(size); - } - } - - updateProp(type: keyof TChartJudgelineProps, forceUpdateTime = false) { - this.props[type].sort(PropsSortFn); - this.props[type] = this.calcPropTime(this.props[type], forceUpdateTime); - return this.props[type]; - } - - destroy() { - this.sprite.removeFromParent(); - this.sprite.destroy(); - - for (const note of this.notes) { - if (!note.sprite) continue; - note.sprite.removeFromParent(); - note.sprite.destroy(); - } - } - - get json(): ChartJudgelineExported { - return { - props: this.props.json, - notes: this.notes.map((e) => e.json), - }; - } - - private calcPropTime(keyframes: ChartKeyframe[], forceUpdateTime = false) { - for (let i = 0; i < keyframes.length; i++) { - const keyframe = keyframes[i]; - const keyframeNext = keyframes[i + 1]; - - if (isNaN(keyframe.time) || forceUpdateTime) keyframe.time = this.chart.bpm.getRealTime(keyframe.beat); - - if (!keyframeNext) continue; - if (keyframeNext.continuous) { - keyframe.nextKeyframe = keyframeNext - } else { - keyframe.nextKeyframe = null; - } - } - - return keyframes; - } - - private sortNotes() { - this.notes.sort((a, b) => BeatArrayToNumber(a.beat) - BeatArrayToNumber(b.beat)); - } - - calcNoteTime(note: Note) { - note.time = this.chart.bpm.getRealTime(note.beat); - note.holdEndTime = this.chart.bpm.getRealTime(note.holdEndBeat); - this.updateNoteFloorPosition(note); - - return note; - } - - calcFloorPositions() { - this.floorPositions.length = 0; - - for (const keyframe of this.props.speed) { - const { nextKeyframe } = keyframe; - if (!nextKeyframe || nextKeyframe.value === keyframe.value) { - this.floorPositions.push({ - time: keyframe.time, - endTime: NaN, - value: NaN, - }); - continue; - } - - const beatBetween = nextKeyframe.beatNum - keyframe.beatNum; - for (let i = 0, count = Math.ceil(beatBetween / 0.125); i < count; i++) { - const beatPercent = i / count; - const beatPercentNext = i < count - 1 ? (i + 1) / count : 1; - const currentTime = keyframe.time * (1 - beatPercent) + nextKeyframe.time * beatPercent; - const nextTime = keyframe.time * (1 - beatPercentNext) + nextKeyframe.time * beatPercentNext; - - this.floorPositions.push({ - time: currentTime, - endTime: nextTime, - value: NaN, - }); - } - - this.floorPositions.push({ - time: nextKeyframe.time, - endTime: NaN, - value: NaN, - }); - } - - this.floorPositions.sort((a, b) => a.time - b.time); - if (this.floorPositions[0].time !== 0) { - this.floorPositions.unshift({ - time: 0, - endTime: this.floorPositions[0].time, - value: 0, - }); - } - - let currentFloorPosition = 0; - for (let i = 0; i < this.floorPositions.length; i++) { - const event = this.floorPositions[i]; - const eventNext = this.floorPositions[i + 1]; - - event.value = currentFloorPosition; - event.endTime = eventNext ? eventNext.time : Infinity; - - if (eventNext) currentFloorPosition = parseDoublePrecist(currentFloorPosition + - (eventNext.time - event.time) * getLinePropValue(event.time, this.props.speed, 1) - , 3, -1); - } - } - - private updateNoteFloorPosition(note: Note) { - note.floorPosition = this.getFloorPosition(note.time); - if (note.type === NoteType.HOLD) note.holdEndPosition = this.getFloorPosition(note.holdEndTime); - else note.holdEndPosition = note.floorPosition; - - note.updateHoldProps(); - } - - updateNotesFloorPosition() { - for (const note of this.notes) { - this.updateNoteFloorPosition(note); - note.resize(this.chart.rendererSize); - } - } -} diff --git a/src/Chart/JudgelineProps.ts b/src/Chart/JudgelineProps.ts deleted file mode 100644 index c040fe0..0000000 --- a/src/Chart/JudgelineProps.ts +++ /dev/null @@ -1,61 +0,0 @@ -import ChartKeyframe, { ChartKeyframeExported } from './Keyframe'; - -export type TChartJudgelineProps = { - speed: ChartKeyframe[], - positionX: ChartKeyframe[], - positionY: ChartKeyframe[], - alpha: ChartKeyframe[], - rotate: ChartKeyframe[], -}; - -export type ChartJudgelinePropsExported = { - speed: ChartKeyframeExported[], - positionX: ChartKeyframeExported[], - positionY: ChartKeyframeExported[], - rotate: ChartKeyframeExported[], - alpha: ChartKeyframeExported[], -}; - -export default class ChartJudgelineProps implements TChartJudgelineProps { - speed: ChartKeyframe[] = []; - /** - * Center: half of the screen width - * Unit: Percent - * Value: half of the screen width - */ - positionX: ChartKeyframe[] = []; - /** - * Center: half of the screen height - * Unit: Percent - * Value: half of the screen height - */ - positionY: ChartKeyframe[] = []; - /** - * Range: 0-255 - */ - alpha: ChartKeyframe[] = []; - /** - * Unit: Angle - */ - rotate: ChartKeyframe[] = []; - - constructor(addDefaultKeyframes = true) { - if (addDefaultKeyframes) { - this.speed.push(new ChartKeyframe('speed', [ 0, 0, 1 ], 1, false, 0)); - this.positionX.push(new ChartKeyframe('positionX', [ 0, 0, 1 ], 0, false, 0)); - this.positionY.push(new ChartKeyframe('positionY', [ 0, 0, 1 ], 0, false, 0)); - this.alpha.push(new ChartKeyframe('alpha', [ 0, 0, 1 ], 255, false, 0)); - this.rotate.push(new ChartKeyframe('rotate', [ 0, 0, 1 ], 0, false, 0)); - } - } - - get json(): ChartJudgelinePropsExported { - return { - speed: this.speed.map((e) => e.json), - positionX: this.positionX.map((e) => e.json), - positionY: this.positionY.map((e) => e.json), - rotate: this.rotate.map((e) => e.json), - alpha: this.alpha.map((e) => e.json), - }; - } -} diff --git a/src/Chart/Keyframe.ts b/src/Chart/Keyframe.ts deleted file mode 100644 index e7a75eb..0000000 --- a/src/Chart/Keyframe.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { v4 as uuid } from 'uuid'; -import { BeatArrayToNumber } from '@/utils/math'; -import { BeatArray, Nullable } from '@/utils/types'; -import ChartJudgelineProps from './JudgelineProps'; - -export type TChartKeyframe = { - beat: BeatArray; - beatNum: number; - value: number; - continuous: boolean; - easing: number; -}; - -export type ChartKeyframeExported = Omit; - -export default class ChartKeyframe implements TChartKeyframe { - /** Internal property */ - readonly id: string; - readonly type: keyof ChartJudgelineProps; - - beat: BeatArray; - beatNum: number; - value: number; - continuous: boolean; - easing: number; - - time: number; - nextKeyframe: Nullable = null; - - constructor( - type: keyof ChartJudgelineProps, - beat: BeatArray, - value: number, - continuous: boolean, - easing: number, - id = uuid() - ) { - if (BeatArrayToNumber(beat) < 0) throw new Error('Cannot set a negative beat to keyframe!'); - this.type = type; - this.id = id; - - this.beat = beat; - this.beatNum = BeatArrayToNumber(this.beat); - this.value = value; - this.continuous = continuous; - this.easing = easing; - - // TODO: Auto-generating these - this.time = NaN; - } - - get json(): ChartKeyframeExported { - return { - beat: this.beat, - value: this.value, - continuous: this.continuous, - easing: this.easing, - }; - } -} diff --git a/src/Chart/Note.ts b/src/Chart/Note.ts deleted file mode 100644 index a01c902..0000000 --- a/src/Chart/Note.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { v4 as uuid } from 'uuid'; -import ChartJudgeline from './Judgeline'; -import { BeatArrayToNumber } from '@/utils/math'; -import { NoteType } from './types'; -import { BeatArray, RendererSize } from '@/utils/types'; -import { Sprite, Container, Texture } from 'pixi.js'; - -const getNoteTexture = (type: NoteType) => { - if (type === NoteType.DRAG) return 'note-drag'; - else if (type === NoteType.FLICK) return 'note-flick'; - else return 'note-tap'; -}; - -export type ChartNoteProps = { - line: ChartJudgeline, - type: NoteType, - beat: BeatArray, - positionX: number, - speed: number, - isAbove: boolean, - - holdEndBeat?: BeatArray -}; - -export type ChartNotePropsNoLine = Omit; - -export type ChartNoteExported = ChartNotePropsNoLine & { holdEndBeat: BeatArray }; - -export default class ChartNote { - /** Internal property */ - readonly id: string; - - line: ChartJudgeline; - type: NoteType; - beat: BeatArray; - positionX: number; - speed: number; - isAbove: boolean; - - holdEndBeat: BeatArray; - - beatNum: number; - time: number; - holdEndBeatNum!: number; - holdEndTime: number; - holdLengthBeatNum!: number; - holdLengthTime!: number; - - floorPosition: number; - holdLength!: number; - holdEndPosition!: number; - - sprite?: Sprite | Container; - - _realLinePosX: number = 0; - _realLinePosY: number = 0; - _realPosX: number = 0; - _realPosY: number = 0; - - constructor({ - line, - type, - beat, - positionX, - speed, - isAbove, - - holdEndBeat - }: ChartNoteProps, id = uuid()) { - this.id = id; - - this.line = line; - this.type = type; - this.beat = beat; - this.positionX = positionX; - this.speed = speed; - this.isAbove = isAbove; - - this.beatNum = BeatArrayToNumber(this.beat); - this.holdEndBeat = this.type === NoteType.HOLD && holdEndBeat ? holdEndBeat : this.beat; - - // TODO: Auto-generating these - this.time = 0; - this.holdEndTime = 0; - this.floorPosition = 0; - this.holdEndPosition = 0; - - this.updateHoldProps(); - this.createSprite(); - } - - updateHoldProps() { - this.holdEndBeatNum = this.type === NoteType.HOLD ? BeatArrayToNumber(this.holdEndBeat) : this.beatNum; - if (this.holdEndBeatNum < this.beatNum) { - this.holdEndBeat = this.beat; - this.holdEndBeatNum = this.beatNum; - } - - this.holdLengthBeatNum = this.type === NoteType.HOLD ? this.holdEndBeatNum - this.beatNum : 0; - this.holdLengthTime = this.type === NoteType.HOLD ? this.holdEndTime - this.time : 0; - this.holdLength = this.type === NoteType.HOLD ? this.holdEndPosition - this.floorPosition : 0; - } - - createSprite(container?: Container) { - if (this.sprite) { - if (this.sprite.parent) this.sprite.parent.removeChild(this.sprite); - this.sprite.destroy(); - this.sprite = (void 0); - } - - if (this.type !== NoteType.HOLD) this.sprite = this.createSpriteNonHold(); - else this.sprite = this.createSpriteHold(); - - if (container) container.addChild(this.sprite); - return this.sprite; - } - - resize(size: RendererSize) { - if (!this.sprite) return; - - if (this.type === NoteType.HOLD) { - const holdLength = this.holdLength * this.speed * size.noteSpeed / size.noteScale; - this.sprite.children[1].height = holdLength; - this.sprite.children[2].position.y = -holdLength; - } - - this.sprite.scale.set(size.noteScale); - } - - get json(): ChartNoteExported { - return { - type: this.type, - beat: this.beat, - positionX: this.positionX, - speed: this.speed, - isAbove: this.isAbove, - holdEndBeat: this.holdEndBeat || this.beat, - }; - } - - private createSpriteNonHold() { - const sprite = new Sprite(Texture.from(getNoteTexture(this.type))); - sprite.anchor.set(0.5); - return sprite; - } - - private createSpriteHold() { - const container = new Container(); - const holdHead = new Sprite(Texture.from('note-hold-head')); - const holdBody = new Sprite(Texture.from('note-hold-body')); - const holdEnd = new Sprite(Texture.from('note-hold-end')); - - holdHead.anchor.set(0.5, 0); - holdBody.anchor.set(0.5, 1); - holdEnd.anchor.set(0.5, 1); - - container.addChild( - holdHead, - holdBody, - holdEnd - ); - return container; - } -} diff --git a/src/Chart/Tick.ts b/src/Chart/Tick.ts deleted file mode 100644 index ddd0628..0000000 --- a/src/Chart/Tick.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { Chart } from './Chart'; -import { getLinePropValue } from '@/utils/chart'; -import { NoteType } from './types'; - -function ChartTick(this: Chart) { - const { - rendererSize, - lines, - time, - container, - } = this; - - const { - widthHalf, - heightHalf, - noteSpeed, - noteScale, - } = rendererSize; - for (const line of lines) { - const { props, floorPositions, sprite, notes } = line; - - line._speed = getLinePropValue(time, props.speed, line._speed); - line._posX = getLinePropValue(time, props.positionX, line._posX); - line._posY = getLinePropValue(time, props.positionY, line._posY); - line._rotate = getLinePropValue(time, props.rotate, line._rotate); - line._alpha = getLinePropValue(time, props.alpha, line._alpha); - - for (let i = 0, l = floorPositions.length; i < l; i++) { - const event = floorPositions[i]; - - if (event.endTime < time) continue; - if (event.time > time) break; - - line._fPos = event.value + (time - event.time) * line._speed; - } - - line._realPosX = line._posX / 100 * widthHalf; - line._realPosY = line._posY / -100 * heightHalf; - - line._radian = line._rotate * (Math.PI / 180); - line._cosr = Math.cos(line._radian); - line._sinr = Math.sin(line._radian); - - sprite.position.set(line._realPosX, line._realPosY); - sprite.angle = line._rotate; - sprite.alpha = line._alpha / 255; - - for (const note of notes) { - const { - type, - time: noteTime, - holdEndTime, - positionX, - speed, - isAbove, - floorPosition, - holdLength, - holdEndPosition, - sprite, - } = note; - if (!sprite) continue; - - if ( - (noteTime <= time) && - (type !== NoteType.HOLD || holdEndTime <= time) - ) { - if (sprite.parent) sprite.removeFromParent(); - continue; - } - - const floorPositionDiff = (floorPosition - line._fPos) * speed; - if ( - floorPositionDiff > 2 || - (floorPositionDiff < 0 && noteTime > time) - ) { - if (sprite.parent) sprite.removeFromParent(); - continue; - } - - const posX = widthHalf * positionX / 100; - const posY = floorPositionDiff * noteSpeed * (isAbove ? -1 : 1); - const realXSin = posY * line._sinr * -1; - const realYCos = posY * line._cosr; - - note._realLinePosX = posX * line._cosr + line._realPosX; - note._realLinePosY = posX * line._sinr + line._realPosY; - - note._realPosX = note._realLinePosX + realXSin; - note._realPosY = note._realLinePosY + realYCos; - - if (type === NoteType.HOLD) { - const [ spriteHead, spriteBody, spriteEnd ] = sprite.children; - let realHoldLength = holdLength * speed * noteSpeed / noteScale; - - spriteHead.visible = true; - if (noteTime <= time) { - realHoldLength = (holdEndPosition - line._fPos) * speed * noteSpeed / noteScale; - - note._realPosX -= realXSin; - note._realPosY -= realYCos; - - spriteHead.visible = false; - } - - spriteBody.height = realHoldLength; - spriteEnd.position.y = -realHoldLength; - } - - sprite.position.set(note._realPosX, note._realPosY); - sprite.angle = line._rotate + (isAbove ? 0 : 180); - if (!sprite.parent) container.addChild(sprite); - } - } -} - -export default ChartTick; diff --git a/src/Chart/types.ts b/src/Chart/types.ts deleted file mode 100644 index 62f13bd..0000000 --- a/src/Chart/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Nullable } from '@/utils/types'; - -export type ChartInfo = { - name: string, - artist: string, - illustration: string, - level: string, - designer: string, -}; - -export type ChartInfoWithFile = ChartInfo & { - music: Blob, - background: Blob, -}; - -export type ChartBookmark = { - id: string; - beatNum: number; - label: string; - color: Nullable; -}; - -export enum NoteType { - TAP = 1, - DRAG = 2, - HOLD = 3, - FLICK = 4, -}; - -export type FloorPosition = { - time: number, - endTime: number, - value: number, -}; diff --git a/src/Database/Database.ts b/src/Database/Database.ts deleted file mode 100644 index 6c45395..0000000 --- a/src/Database/Database.ts +++ /dev/null @@ -1,16 +0,0 @@ -import DatabaseEngine from './Engine'; -import { TProject } from './types'; - -class Database { - readonly project = new DatabaseEngine('editor_db_project', 1, { - structures: [ - { name: 'id', options: { key: true, unique: true } }, - { name: 'filesID', options: { unique: true } }, - { name: 'chartID', options: { unique: true } }, - ], - }); -}; - -const database = new Database(); -export default database; -export { Database }; diff --git a/src/Database/Engine.ts b/src/Database/Engine.ts deleted file mode 100644 index 50ffc89..0000000 --- a/src/Database/Engine.ts +++ /dev/null @@ -1,182 +0,0 @@ - -export type TDatabaseDataType = string | boolean | number | Blob; - -export type TDatabaseStructure = { - name: string, - options?: Partial<{ - key: boolean, - index: boolean, - unique: boolean, - multiEntry: boolean, - }>, -}; - -export type TDatabase = { - structures: TDatabaseStructure[], - autoIncrement?: boolean, -}; - -export type TDatabaseData = { - [x: string]: TDatabaseDataType | TDatabaseDataType[], -}; - -export default class DatabaseEngine { - readonly name: string; - readonly version: number; - - private db!: IDBDatabase; - private isReady = false; - - constructor(name: string, version: number, options: TDatabase) { - this.name = name; - this.version = version; - - const request = window.indexedDB.open(this.name, this.version); - - request.onsuccess = () => { - const { result } = request; - if (!result) return; - - this.db = result; - if (this.db.version === version) this.isReady = true; - }; - - request.onerror = (e) => { - throw (e as unknown as Error); - }; - - request.onupgradeneeded = () => { - this.db = request.result; - - const indexes: TDatabaseStructure[] = []; - let keyPath = null; - - for (const structure of options.structures) { - const { options } = structure; - if (!options) continue; - - if (options.key) keyPath = structure.name; - else if (options.index) indexes.push(structure); - } - - const objectOptions = { keyPath: keyPath, autoIncrement: options.autoIncrement }; - const store = this.db.createObjectStore(this.name, objectOptions); - - for (const index of indexes) { - store.createIndex(index.name, index.name, { - unique: index.options!.unique, - multiEntry: index.options!.multiEntry, - }); - } - - this.isReady = true; - }; - } - - add(data: TData) {return new Promise(async (res, rej) => { - await this.waitReady(); - const { db } = this; - - const transaction = db.transaction([ this.name ], 'readwrite'); - const store = transaction.objectStore(this.name); - - transaction.oncomplete = () => { - res(transaction); - }; - transaction.onerror = (e) => { - rej(e); - }; - - store.add(data); - })} - - delete(index: string | number): Promise {return new Promise(async (res, rej) => { - await this.waitReady(); - const { db } = this; - - const transaction = db.transaction([ this.name ], 'readwrite'); - const store = transaction.objectStore(this.name); - const request = store.delete(index); - - request.onsuccess = () => { - res(request.result); - }; - request.onerror = (e) => { - rej(e); - }; - })} - - get(index: string | number, key?: string): Promise {return new Promise(async (res, rej) => { - await this.waitReady(); - const { db } = this; - - const transaction = db.transaction([ this.name ], 'readonly'); - const store = transaction.objectStore(this.name); - const request = key ? store.index(key).get(index) : store.get(index); - - request.onsuccess = () => { - res((request.result as TData) || null); - }; - request.onerror = (e) => { - rej(e); - }; - })} - - getAll(): Promise {return new Promise(async (res, rej) => { - await this.waitReady(); - const { db } = this; - const result: TData[] = []; - - const transaction = db.transaction([ this.name ], 'readonly'); - const store = transaction.objectStore(this.name); - const cursor = store.openCursor(); - - cursor.onsuccess = (e) => { - const _cur = (e.target as IDBRequest).result as (IDBCursorWithValue | null); - if (_cur) { - result.push((_cur.value as TData)); - _cur.continue(); - } else { - res(result); - } - }; - - cursor.onerror = (e) => { - rej(e); - }; - })} - - update(index: string | number, data: TData): Promise {return new Promise(async (res, rej) => { - await this.waitReady(); - const { db } = this; - - const transaction = db.transaction([ this.name ], 'readwrite'); - const store = transaction.objectStore(this.name); - const request = store.get(index); - - request.onsuccess = () => { - const oldData = request.result as TData; - const newData = { ...oldData, ...data }; - - const reqUpdate = store.put(newData); - reqUpdate.onsuccess = () => { - res(newData); - }; - reqUpdate.onerror = (e) => { - rej(e); - }; - }; - request.onerror = (e) => { - rej(e); - }; - })} - - private waitReady() {return new Promise((res) => { - if (this.isReady) return res(this.isReady); - const clockId = setInterval(() => { - if (!this.isReady) return; - res(this.isReady); - clearInterval(clockId); - }, 200); - })} -} diff --git a/src/Database/types.ts b/src/Database/types.ts deleted file mode 100644 index 59efc73..0000000 --- a/src/Database/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ChartInfo } from '@/Chart/types'; - -export type TProject = ChartInfo & { - id: string, - filesID: string, - chartID: string, - musicID: string, - backgroundID: string, -}; diff --git a/src/Settings/Settings.ts b/src/Settings/Settings.ts deleted file mode 100644 index bf06482..0000000 --- a/src/Settings/Settings.ts +++ /dev/null @@ -1,47 +0,0 @@ -import EventEmitter from 'eventemitter3'; -import { TSettings } from './types'; - -const STORAGE_KEY_NAME = 'editor-settings'; - -class Settings { - readonly storage = window.localStorage; - readonly event = new EventEmitter(); - private _current: TSettings = { - // Default settings goes here - noteScale: 8000, - }; - - constructor() { - const storagedSettings = JSON.parse(this.storage.getItem(STORAGE_KEY_NAME) ?? '{}') as TSettings; - - this._current = { - ...this._current, - ...storagedSettings, - }; - this.storage.setItem(STORAGE_KEY_NAME, JSON.stringify(this._current)); - this.event.emit('settings.updated', { ...this._current }); - } - - /** - * Get single setting's value - */ - get(name: keyof TSettings): TSettings[keyof TSettings] { - return this._current[name]; - } - - set(name: keyof TSettings, value: TSettings[keyof TSettings]) { - this._current[name] = value; - this.storage.setItem(STORAGE_KEY_NAME, JSON.stringify(this._current)); - - this.event.emit('settings.updated', { ...this._current }); - return this._current; - } - - get current() { - return this._current; - } -} - -const settings = new Settings(); -export default settings; -export { Settings }; diff --git a/src/Settings/types.tsx b/src/Settings/types.tsx deleted file mode 100644 index ec58d58..0000000 --- a/src/Settings/types.tsx +++ /dev/null @@ -1,4 +0,0 @@ - -export type TSettings = { - noteScale: number, -}; diff --git a/src/Storage/File.ts b/src/Storage/File.ts deleted file mode 100644 index c84e028..0000000 --- a/src/Storage/File.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { v4 as uuid } from 'uuid'; -import DatabaseEngine from '@/Database/Engine'; -import { GetFileMD5 } from '@/utils/file'; -import { TStorageFile } from './types'; -import { Nullable } from '@/utils/types'; - -class StorageFile { - readonly db = new DatabaseEngine('editor_storage_files', 1, { - structures: [ - { name: 'id', options: { key: true, unique: true } }, - { name: 'md5', options: { unique: true, index: true } }, - ] - }); - - add(blob: Blob): Promise<{ md5: string, id: string }> {return new Promise(async (res, rej) => { - const id = uuid(); - const md5 = await GetFileMD5(blob); - const fileData = await this.db.get(md5); - if (fileData) return res(fileData); - - this.db.add({ - id, md5, blob - }).then(() => res({ md5, id })) - .catch(e => rej(e)); - })} - - remove(md5: string) { - return this.db.delete(md5); - } - - get(id: string | string[]): Promise> { - if (typeof id === 'string') return this.db.get(id); - return new Promise(async (res) => { - const allFiles = await this.db.getAll(); - res(allFiles.filter((e) => id.includes(e.id))); - }); - } - - getByMD5(md5: string | string[]): Promise> { - if (typeof md5 === 'string') return this.db.get(md5, 'md5'); - return new Promise(async (res) => { - const allFiles = await this.db.getAll(); - res(allFiles.filter((e) => md5.includes(e.md5))); - }); - } - - update(id: string, file: Blob): Promise<{ md5: string }> {return new Promise(async (res, rej) => { - const md5 = await GetFileMD5(file); - - this.db.update(id, { - id, md5, blob: file, - }).then(() => res({ md5 })) - .catch((e) => rej(e)); - })} -} - -const file = new StorageFile; -export default file; -export { StorageFile }; diff --git a/src/Storage/Storage.ts b/src/Storage/Storage.ts deleted file mode 100644 index a21837b..0000000 --- a/src/Storage/Storage.ts +++ /dev/null @@ -1,41 +0,0 @@ -import DatabaseEngine from '@/Database/Engine'; -import StorageFile from './File'; -import { TStorage, TStorageStructure } from './types'; - -class Storage { - readonly file = StorageFile; - readonly db = new DatabaseEngine('editor_storage_structure', 1, { - structures: [ - { name: 'id', options: { key: true, unique: true } }, - { name: 'structure' } - ], - }); - - add(id: string, structure: TStorageStructure) { - return this.db.add({ - id, structure - }); - } - - remove(id: string) { - return this.db.delete(id); - } - - get(id: string) { - return this.db.get(id); - } - - getAll() { - return this.db.getAll(); - } - - update(id: string, structure: TStorageStructure) { - return this.db.update(id, { - id, structure - }); - } -} - -const storage = new Storage(); -export default storage; -export { Storage }; diff --git a/src/Storage/types.ts b/src/Storage/types.ts deleted file mode 100644 index 3b23eb2..0000000 --- a/src/Storage/types.ts +++ /dev/null @@ -1,32 +0,0 @@ - -export type TStorageItemBase = { - // UUID? - id: string, - name: string, - isPath: boolean, -}; - -export type TStorageItemFile = TStorageItemBase & { - isPath: false, - md5: string, -}; - -export type TStorageItemPath = TStorageItemBase & { - isPath: true, - files: TStorageItem[], -}; - -export type TStorageItem = TStorageItemFile | TStorageItemPath; - -export type TStorageStructure = Record; - -export type TStorage = { - id: string, - structure: TStorageStructure, -}; - -export type TStorageFile = { - id: string, - md5: string, - blob: Blob, -}; diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 494a501..b549718 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,14 +1,11 @@ import TempoContext from './contexts/Tempo'; -import Chart from '@/Chart/Chart'; import PanelDock from './Panel/PanelDock'; import { PopupReadFiles, ReadFileAsText } from '@/utils/file'; import { Clip } from '@phifans/audio'; import { Nullable } from '@/utils/types'; import { useCallback, useState } from 'react'; -import SettingsProvider from './contexts/Settings/Provider'; import { importFromZip } from '@/runtime/skin/importer'; import { DockviewApi } from 'dockview'; -import { ChartExported } from '@/Chart/Chart'; import { showCreateProjectDialog } from './dialogs/createProject'; import { loadFiles } from '@/runtime/resources/loader'; import { store as ChartStore } from '@/core/state/chartStore'; @@ -62,52 +59,6 @@ function App() { .catch((e) => console.error(e)); }; - const onCreateChart = () => { - if (!importedMusic) return; - if (Chart.info) return; - - Chart.create({ - name: 'test', - artist: 'test', - illustration: 'test', - level: 'test', - designer: 'test', - music: importedMusic, - background: importedMusic - }); - }; - - const onLoadChart = () => { - if (!importedMusic) return; - if (Chart.info) return; - - PopupReadFiles(false) - .then(async (files) => { - if (!files || files.length === 0) return; - const chartRaw = JSON.parse(await ReadFileAsText(files[0])) as ChartExported; - Chart.load({ - ...chartRaw.info, - music: importedMusic!, - background: importedMusic!, - }, chartRaw); - }) - .catch((e) => console.error(e)); - }; - - const onExportChart = () => { - if (!Chart.info) return; - - const chartJson = Chart.json!; - const chartText = JSON.stringify(chartJson, null, 4); - const chartBlob = new Blob([chartText], { type: 'text/json' }); - const chartUrl = URL.createObjectURL(chartBlob); - - const downloadDom = document.createElement('a'); - downloadDom.href = chartUrl; - downloadDom.download = 'exported.json'; - downloadDom.click(); - }; - const handleTempoUpdate = useCallback((tempo: number) => { setTempo(tempo); }, []); @@ -125,7 +76,7 @@ function App() { }; return ( - + <> - + ); } diff --git a/src/ui/Panel/NotePanel/NoteContainer/useWheel.ts b/src/ui/Panel/NotePanel/NoteContainer/useWheel.ts index 7b034b2..67c22e8 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/useWheel.ts +++ b/src/ui/Panel/NotePanel/NoteContainer/useWheel.ts @@ -1,5 +1,4 @@ import { useCallback, useMemo } from 'react'; -import Chart from '@/Chart/Chart'; import { useTempo } from '@/ui/contexts/Tempo'; import { GridValue } from '@/utils/math'; @@ -8,13 +7,10 @@ const useWheel = () => { const tempoGrid = useMemo(() => 1 / tempo, [tempo]); const handleWheel = useCallback((e: React.WheelEvent) => { - if (!Chart.info) return; - const { deltaY, shiftKey } = e; const seekFactor = deltaY > 0 ? 1 : -1; - const newTime = GridValue(Chart.beatNum + ((shiftKey ? 1 : tempoGrid) * seekFactor), tempoGrid); - - Chart.beatNum = newTime; + + // TODO }, [tempoGrid]); return { diff --git a/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts b/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts index 040c53f..8cb3fc4 100644 --- a/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts +++ b/src/ui/Panel/NotePanel/NoteContainer/useWrite.ts @@ -1,8 +1,8 @@ import { useCallback, useMemo, useRef } from 'react'; import { nanoid } from 'nanoid'; -import Chart from '@/Chart/Chart'; import { useProps } from '../PropsContext'; import { useTempo } from '@/ui/contexts/Tempo'; +import { runtimeAudioTimeStore } from '@/runtime/audio/state'; import { BeatArrayToNumber, BeatNumberToArray, GridValue, parseDoublePrecist } from '@/utils/math'; import { Point as PixiPoint } from 'pixi.js'; import { Point } from '@/utils/types'; @@ -52,7 +52,7 @@ const useWrite = ({ const posToTime = useCallback((pos: number) => { const hitTime = GridValue(height - pos, beatGrid) / beatGrid / tempo - timeOffset; - const gridResult = GridValue(Chart.beatNum + hitTime, tempoGrid); + const gridResult = GridValue(runtimeAudioTimeStore.getState().currentBeat + hitTime, tempoGrid); return parseDoublePrecist(gridResult, 6, -1); }, [height, timeOffset, tempoGrid, beatGrid, tempo]); diff --git a/src/ui/Panel/PreviewPanel/Controller.tsx b/src/ui/Panel/PreviewPanel/Controller.tsx index 079c418..1c1d520 100644 --- a/src/ui/Panel/PreviewPanel/Controller.tsx +++ b/src/ui/Panel/PreviewPanel/Controller.tsx @@ -1,7 +1,6 @@ import { useMemo } from 'react'; import { Slider, Button, Stack, Center, HStack } from '@chakra-ui/react'; import { useRuntimeAudioStore } from '@/runtime/audio/state'; -import Chart from '@/Chart/Chart'; import { useTempo } from '../../contexts/Tempo'; import { GridValue } from '@/utils/math'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -28,16 +27,14 @@ const PreviewController = () => {