create-pixi-vn 1.6.2 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import"node:util";import N,{stdin as wu,stdout as $u}from"node:process";import*a
6
6
  `).map(r=>fD(r,e,t)).join(`
7
7
  `)}const dD=["up","down","left","right","space","enter","cancel"],ru={actions:new Set(dD),aliases:new Map([["k","up"],["j","down"],["h","left"],["l","right"],["","cancel"],["escape","cancel"]])};function pu(D,e){if(typeof D=="string")return ru.aliases.get(D)===e;for(const t of D)if(t!==void 0&&pu(t,e))return!0;return!1}function BD(D,e){if(D===e)return;const t=D.split(`
8
8
  `),r=e.split(`
9
- `),i=[];for(let s=0;s<Math.max(t.length,r.length);s++)t[s]!==r[s]&&i.push(s);return i}const gD=globalThis.process.platform.startsWith("win"),hu=Symbol("clack:cancel");function _(D){return D===hu}function iu(D,e){const t=D;t.isTTY&&t.setRawMode(e)}function bD({input:D=wu,output:e=$u,overwrite:t=!0,hideCursor:r=!0}={}){const i=Du.createInterface({input:D,output:e,prompt:"",tabSize:1});Du.emitKeypressEvents(D,i),D.isTTY&&D.setRawMode(!0);const s=(u,{name:n,sequence:a})=>{const c=String(u);if(pu([c,n,a],"cancel")){r&&e.write(S.cursor.show),process.exit(0);return}if(!t)return;const h=n==="return"?0:-1,F=n==="return"?-1:0;Du.moveCursor(e,h,F,()=>{Du.clearLine(e,1,()=>{D.once("keypress",s)})})};return r&&e.write(S.cursor.hide),D.once("keypress",s),()=>{D.off("keypress",s),r&&e.write(S.cursor.show),D.isTTY&&!gD&&D.setRawMode(!1),i.terminal=!1,i.close()}}var vD=Object.defineProperty,AD=(D,e,t)=>e in D?vD(D,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):D[e]=t,R=(D,e,t)=>(AD(D,typeof e!="symbol"?e+"":e,t),t);let mu=class{constructor(e,t=!0){R(this,"input"),R(this,"output"),R(this,"_abortSignal"),R(this,"rl"),R(this,"opts"),R(this,"_render"),R(this,"_track",!1),R(this,"_prevFrame",""),R(this,"_subscribers",new Map),R(this,"_cursor",0),R(this,"state","initial"),R(this,"error",""),R(this,"value");const{input:r=wu,output:i=$u,render:s,signal:u,...n}=e;this.opts=n,this.onKeypress=this.onKeypress.bind(this),this.close=this.close.bind(this),this.render=this.render.bind(this),this._render=s.bind(this),this._track=t,this._abortSignal=u,this.input=r,this.output=i}unsubscribe(){this._subscribers.clear()}setSubscriber(e,t){const r=this._subscribers.get(e)??[];r.push(t),this._subscribers.set(e,r)}on(e,t){this.setSubscriber(e,{cb:t})}once(e,t){this.setSubscriber(e,{cb:t,once:!0})}emit(e,...t){const r=this._subscribers.get(e)??[],i=[];for(const s of r)s.cb(...t),s.once&&i.push(()=>r.splice(r.indexOf(s),1));for(const s of i)s()}prompt(){return new Promise((e,t)=>{if(this._abortSignal){if(this._abortSignal.aborted)return this.state="cancel",this.close(),e(hu);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}const r=new Xu;r._write=(i,s,u)=>{this._track&&(this.value=this.rl?.line.replace(/\t/g,""),this._cursor=this.rl?.cursor??0,this.emit("value",this.value)),u()},this.input.pipe(r),this.rl=yu.createInterface({input:this.input,output:r,tabSize:2,prompt:"",escapeCodeTimeout:50,terminal:!0}),yu.emitKeypressEvents(this.input,this.rl),this.rl.prompt(),this.opts.initialValue!==void 0&&this._track&&this.rl.write(this.opts.initialValue),this.input.on("keypress",this.onKeypress),iu(this.input,!0),this.output.on("resize",this.render),this.render(),this.once("submit",()=>{this.output.write(S.cursor.show),this.output.off("resize",this.render),iu(this.input,!1),e(this.value)}),this.once("cancel",()=>{this.output.write(S.cursor.show),this.output.off("resize",this.render),iu(this.input,!1),e(hu)})})}onKeypress(e,t){if(this.state==="error"&&(this.state="active"),t?.name&&(!this._track&&ru.aliases.has(t.name)&&this.emit("cursor",ru.aliases.get(t.name)),ru.actions.has(t.name)&&this.emit("cursor",t.name)),e&&(e.toLowerCase()==="y"||e.toLowerCase()==="n")&&this.emit("confirm",e.toLowerCase()==="y"),e===" "&&this.opts.placeholder&&(this.value||(this.rl?.write(this.opts.placeholder),this.emit("value",this.opts.placeholder))),e&&this.emit("key",e.toLowerCase()),t?.name==="return"){if(!this.value&&this.opts.placeholder&&(this.rl?.write(this.opts.placeholder),this.emit("value",this.opts.placeholder)),this.opts.validate){const r=this.opts.validate(this.value);r&&(this.error=r instanceof Error?r.message:r,this.state="error",this.rl?.write(this.value))}this.state!=="error"&&(this.state="submit")}pu([e,t?.name,t?.sequence],"cancel")&&(this.state="cancel"),(this.state==="submit"||this.state==="cancel")&&this.emit("finalize"),this.render(),(this.state==="submit"||this.state==="cancel")&&this.close()}close(){this.input.unpipe(),this.input.removeListener("keypress",this.onKeypress),this.output.write(`
9
+ `),i=[];for(let s=0;s<Math.max(t.length,r.length);s++)t[s]!==r[s]&&i.push(s);return i}const gD=globalThis.process.platform.startsWith("win"),hu=Symbol("clack:cancel");function _(D){return D===hu}function iu(D,e){const t=D;t.isTTY&&t.setRawMode(e)}function bD({input:D=wu,output:e=$u,overwrite:t=!0,hideCursor:r=!0}={}){const i=Du.createInterface({input:D,output:e,prompt:"",tabSize:1});Du.emitKeypressEvents(D,i),D.isTTY&&D.setRawMode(!0);const s=(u,{name:n,sequence:a})=>{const c=String(u);if(pu([c,n,a],"cancel")){r&&e.write(S.cursor.show),process.exit(0);return}if(!t)return;const h=n==="return"?0:-1,F=n==="return"?-1:0;Du.moveCursor(e,h,F,()=>{Du.clearLine(e,1,()=>{D.once("keypress",s)})})};return r&&e.write(S.cursor.hide),D.once("keypress",s),()=>{D.off("keypress",s),r&&e.write(S.cursor.show),D.isTTY&&!gD&&D.setRawMode(!1),i.terminal=!1,i.close()}}var vD=Object.defineProperty,AD=(D,e,t)=>e in D?vD(D,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):D[e]=t,R=(D,e,t)=>(AD(D,typeof e!="symbol"?e+"":e,t),t);let mu=class{constructor(e,t=!0){R(this,"input"),R(this,"output"),R(this,"_abortSignal"),R(this,"rl"),R(this,"opts"),R(this,"_render"),R(this,"_track",!1),R(this,"_prevFrame",""),R(this,"_subscribers",new Map),R(this,"_cursor",0),R(this,"state","initial"),R(this,"error",""),R(this,"value");const{input:r=wu,output:i=$u,render:s,signal:u,...n}=e;this.opts=n,this.onKeypress=this.onKeypress.bind(this),this.close=this.close.bind(this),this.render=this.render.bind(this),this._render=s.bind(this),this._track=t,this._abortSignal=u,this.input=r,this.output=i}unsubscribe(){this._subscribers.clear()}setSubscriber(e,t){const r=this._subscribers.get(e)??[];r.push(t),this._subscribers.set(e,r)}on(e,t){this.setSubscriber(e,{cb:t})}once(e,t){this.setSubscriber(e,{cb:t,once:!0})}emit(e,...t){const r=this._subscribers.get(e)??[],i=[];for(const s of r)s.cb(...t),s.once&&i.push(()=>r.splice(r.indexOf(s),1));for(const s of i)s()}prompt(){return new Promise((e,t)=>{if(this._abortSignal){if(this._abortSignal.aborted)return this.state="cancel",this.close(),e(hu);this._abortSignal.addEventListener("abort",()=>{this.state="cancel",this.close()},{once:!0})}const r=new Xu;r._write=(i,s,u)=>{this._track&&(this.value=this.rl?.line.replace(/\t/g,""),this._cursor=this.rl?.cursor??0,this.emit("value",this.value)),u()},this.input.pipe(r),this.rl=yu.createInterface({input:this.input,output:r,tabSize:2,prompt:"",escapeCodeTimeout:50,terminal:!0}),yu.emitKeypressEvents(this.input,this.rl),this.rl.prompt(),this.opts.initialValue!==void 0&&this._track&&this.rl.write(this.opts.initialValue),this.input.on("keypress",this.onKeypress),iu(this.input,!0),this.output.on("resize",this.render),this.render(),this.once("submit",()=>{this.output.write(S.cursor.show),this.output.off("resize",this.render),iu(this.input,!1),e(this.value)}),this.once("cancel",()=>{this.output.write(S.cursor.show),this.output.off("resize",this.render),iu(this.input,!1),e(hu)})})}onKeypress(e,t){if(this.state==="error"&&(this.state="active"),t?.name&&(!this._track&&ru.aliases.has(t.name)&&this.emit("cursor",ru.aliases.get(t.name)),ru.actions.has(t.name)&&this.emit("cursor",t.name)),e&&(e.toLowerCase()==="y"||e.toLowerCase()==="n")&&this.emit("confirm",e.toLowerCase()==="y"),e===" "&&this.opts.placeholder&&(this.value||(this.rl?.write(this.opts.placeholder),this.emit("value",this.opts.placeholder))),e&&this.emit("key",e.toLowerCase()),t?.name==="return"){if(this.opts.validate){const r=this.opts.validate(this.value);r&&(this.error=r instanceof Error?r.message:r,this.state="error",this.rl?.write(this.value))}this.state!=="error"&&(this.state="submit")}pu([e,t?.name,t?.sequence],"cancel")&&(this.state="cancel"),(this.state==="submit"||this.state==="cancel")&&this.emit("finalize"),this.render(),(this.state==="submit"||this.state==="cancel")&&this.close()}close(){this.input.unpipe(),this.input.removeListener("keypress",this.onKeypress),this.output.write(`
10
10
  `),iu(this.input,!1),this.rl?.close(),this.rl=void 0,this.emit(`${this.state}`,this.value),this.unsubscribe()}restoreCursor(){const e=Uu(this._prevFrame,process.stdout.columns,{hard:!0}).split(`
11
11
  `).length-1;this.output.write(S.cursor.move(-999,e*-1))}render(){const e=Uu(this._render(this)??"",process.stdout.columns,{hard:!0});if(e!==this._prevFrame){if(this.state==="initial")this.output.write(S.cursor.hide);else{const t=BD(this._prevFrame,e);if(this.restoreCursor(),t&&t?.length===1){const r=t[0];this.output.write(S.cursor.move(0,r)),this.output.write(S.erase.lines(1));const i=e.split(`
12
12
  `);this.output.write(i[r]),this._prevFrame=e,this.output.write(S.cursor.move(0,i.length-r-1));return}if(t&&t?.length>1){const r=t[0];this.output.write(S.cursor.move(0,r)),this.output.write(S.erase.down());const i=e.split(`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-pixi-vn",
3
3
  "description": "Create a new Pixi’VN project",
4
- "version": "1.6.2",
4
+ "version": "1.6.3",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0",
7
7
  "author": "DRincs-Productions",
@@ -47,16 +47,16 @@
47
47
  "homepage": "https://pixi-vn.web.app/",
48
48
  "funding": "https://github.com/DRincs-Productions/pixi-vn?sponsor=1",
49
49
  "devDependencies": {
50
- "@clack/prompts": "^0.10.1",
50
+ "@clack/prompts": "^0.11.0",
51
51
  "@types/minimist": "^1.2.5",
52
52
  "@types/which": "^3.0.4",
53
- "inquirer": "^12.6.0",
53
+ "inquirer": "^12.8.0",
54
54
  "kolorist": "^1.8.0",
55
55
  "minimist": "^1.2.8",
56
56
  "unbuild": "^3.5.0"
57
57
  },
58
58
  "dependencies": {
59
- "execa": "^9.5.3",
59
+ "execa": "^9.6.0",
60
60
  "which": "^5.0.0"
61
61
  }
62
62
  }
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@drincs/nqtr": "^0.5.5",
15
- "@drincs/pixi-vn": "^1.2.22",
15
+ "@drincs/pixi-vn": "^1.2.23",
16
16
  "@emotion/react": "^11.14.0",
17
17
  "@emotion/styled": "^11.14.1",
18
18
  "@mui/icons-material": "^7.2.0",
@@ -19,6 +19,7 @@ export default function useNQTRDetector() {
19
19
 
20
20
  useEffect(() => {
21
21
  const { background } = currentRoom || {};
22
+ canvas.removeAll();
22
23
  if (background) {
23
24
  let image = convertMultiTypeSprite(background, gameProps);
24
25
  let layer = canvas.getLayer(CANVAS_UI_LAYER_NAME);
@@ -7,12 +7,16 @@ import { INTERFACE_DATA_USE_QUEY_KEY } from "./useQueryInterface";
7
7
 
8
8
  function getRoomInfo(room: RoomInterface) {
9
9
  const routine = room.routine;
10
- const background = routine.length > 0 ? routine[0].background : room.background;
10
+ let background = room.background;
11
11
  let icon: string | TimeSlotsImage | undefined;
12
12
  if (typeof background === "string" || background instanceof TimeSlotsImage) {
13
13
  icon = background;
14
14
  }
15
15
 
16
+ if (routine.length > 0 && routine[0].background) {
17
+ background = routine[0].background;
18
+ }
19
+
16
20
  return {
17
21
  id: room.id,
18
22
  background: background,
@@ -52,10 +56,10 @@ export function useQueryCurrentRoomId() {
52
56
 
53
57
  const QUICK_ROOMS_USE_QUEY_KEY = "quick_rooms_use_quey_key";
54
58
  export function useQueryQuickRooms() {
55
- const rooms = navigator.currentLocation?.rooms || [];
56
59
  return useQuery({
57
60
  queryKey: [INTERFACE_DATA_USE_QUEY_KEY, QUICK_ROOMS_USE_QUEY_KEY],
58
61
  queryFn: async () => {
62
+ const rooms = navigator.currentLocation?.rooms || [];
59
63
  const loadRoomsImage = async () => {
60
64
  rooms?.forEach((room) => {
61
65
  Assets.backgroundLoadBundle(room.id);
@@ -9,7 +9,7 @@ export default class Activity extends ActivityStoredClass implements ActivityInt
9
9
  props: {
10
10
  name?: string;
11
11
  sprite?: MultiTypeSpriteProp<Activity>;
12
- icon: ReactElement | ((props: Activity, runProps: OnRunProps) => ReactElement);
12
+ icon?: ReactElement | ((props: Activity, runProps: OnRunProps) => ReactElement);
13
13
  disabled?: boolean | (() => boolean);
14
14
  hidden?: boolean | (() => boolean);
15
15
  } & ActivityStoredClassProps
@@ -24,15 +24,15 @@ export default class Activity extends ActivityStoredClass implements ActivityInt
24
24
  readonly name: string;
25
25
  private readonly _sprite?: MultiTypeSpriteProp<Activity>;
26
26
  get sprite(): MultiTypeSprite | undefined {
27
- let sprite = this._sprite;
27
+ const sprite = this._sprite;
28
28
  if (typeof sprite === "function") {
29
29
  return (runProps: OnRunProps) => sprite(this, runProps);
30
30
  }
31
31
  return sprite;
32
32
  }
33
- private readonly _icon: ReactElement | ((props: Activity, runProps: OnRunProps) => ReactElement);
34
- get icon(): ReactElement | ((props: OnRunProps) => ReactElement) {
35
- let icon = this._icon;
33
+ private readonly _icon?: ReactElement | ((props: Activity, runProps: OnRunProps) => ReactElement);
34
+ get icon(): ReactElement | ((props: OnRunProps) => ReactElement) | undefined {
35
+ const icon = this._icon;
36
36
  if (typeof icon === "function") {
37
37
  return (runProps: OnRunProps) => icon(this, runProps);
38
38
  }
@@ -2,7 +2,7 @@ import { canvas, ImageSprite, narration } from "@drincs/pixi-vn";
2
2
  import Stack from "@mui/joy/Stack";
3
3
  import { useQueryClient } from "@tanstack/react-query";
4
4
  import { motion } from "motion/react";
5
- import { useEffect } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import MenuButton from "../components/MenuButton";
7
7
  import { CANVAS_UI_LAYER_NAME } from "../constans";
8
8
  import useGameProps from "../hooks/useGameProps";
@@ -22,6 +22,7 @@ export default function MainMenu() {
22
22
  const { data: lastSave = null, isLoading } = useQueryLastSave();
23
23
  const gameProps = useGameProps();
24
24
  const { uiTransition: t, navigate, notify } = gameProps;
25
+ const [loading, setLoading] = useState(false);
25
26
 
26
27
  useEffect(() => {
27
28
  editHideInterface(false);
@@ -58,31 +59,36 @@ export default function MainMenu() {
58
59
  if (!lastSave) {
59
60
  return;
60
61
  }
62
+ setLoading(true);
61
63
  loadSave(lastSave, navigate)
62
64
  .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
63
65
  .catch((e) => {
64
66
  notify(t("fail_load"), { variant: "error" });
65
67
  console.error(e);
66
- });
68
+ })
69
+ .finally(() => setLoading(false));
67
70
  }}
68
71
  transitionDelay={0.1}
69
72
  loading={isLoading}
70
- disabled={!isLoading && !lastSave}
73
+ disabled={!isLoading && !lastSave && !loading}
71
74
  >
72
75
  {t("continue")}
73
76
  </MenuButton>
74
77
  <MenuButton
75
- onClick={() => {
78
+ onClick={async () => {
79
+ setLoading(true);
76
80
  canvas.removeAll();
77
- narration.callLabel(startLabel, gameProps).then(() => {
78
- queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] });
79
- });
81
+ narration
82
+ .callLabel(startLabel, gameProps)
83
+ .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
84
+ .finally(() => setLoading(false));
80
85
  }}
81
86
  transitionDelay={0.2}
87
+ disabled={loading}
82
88
  >
83
89
  {t("start")}
84
90
  </MenuButton>
85
- <MenuButton onClick={editSaveScreen} transitionDelay={0.3}>
91
+ <MenuButton onClick={editSaveScreen} transitionDelay={0.3} disabled={loading}>
86
92
  {t("load")}
87
93
  </MenuButton>
88
94
  <MenuButton onClick={() => setOpenSettings(true)} transitionDelay={0.4}>
@@ -24,7 +24,7 @@ export function getSave(image?: string): GameSaveData {
24
24
  }
25
25
 
26
26
  export async function loadSave(saveData: GameSaveData, navigate: NavigateFunction) {
27
- navigate(LOADING_ROUTE);
27
+ await navigate(LOADING_ROUTE);
28
28
  // load the save data from the JSON string
29
29
  await Game.restoreGameState(saveData.saveData, navigate);
30
30
  }
@@ -11,7 +11,7 @@
11
11
  "preview": "vite preview"
12
12
  },
13
13
  "dependencies": {
14
- "@drincs/pixi-vn": "^1.2.22",
14
+ "@drincs/pixi-vn": "^1.2.23",
15
15
  "@emotion/react": "^11.14.0",
16
16
  "@emotion/styled": "^11.14.1",
17
17
  "@mui/icons-material": "^7.2.0",
@@ -2,7 +2,7 @@ import { canvas, ImageSprite, narration } from "@drincs/pixi-vn";
2
2
  import Stack from "@mui/joy/Stack";
3
3
  import { useQueryClient } from "@tanstack/react-query";
4
4
  import { motion } from "motion/react";
5
- import { useEffect } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import MenuButton from "../components/MenuButton";
7
7
  import { CANVAS_UI_LAYER_NAME, NARRATION_ROUTE } from "../constans";
8
8
  import useGameProps from "../hooks/useGameProps";
@@ -22,6 +22,7 @@ export default function MainMenu() {
22
22
  const { data: lastSave = null, isLoading } = useQueryLastSave();
23
23
  const gameProps = useGameProps();
24
24
  const { uiTransition: t, navigate, notify } = gameProps;
25
+ const [loading, setLoading] = useState(false);
25
26
 
26
27
  useEffect(() => {
27
28
  editHideInterface(false);
@@ -58,32 +59,37 @@ export default function MainMenu() {
58
59
  if (!lastSave) {
59
60
  return;
60
61
  }
62
+ setLoading(true);
61
63
  loadSave(lastSave, navigate)
62
64
  .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
63
65
  .catch((e) => {
64
66
  notify(t("fail_load"), { variant: "error" });
65
67
  console.error(e);
66
- });
68
+ })
69
+ .finally(() => setLoading(false));
67
70
  }}
68
71
  transitionDelay={0.1}
69
72
  loading={isLoading}
70
- disabled={!isLoading && !lastSave}
73
+ disabled={!isLoading && !lastSave && !loading}
71
74
  >
72
75
  {t("continue")}
73
76
  </MenuButton>
74
77
  <MenuButton
75
- onClick={() => {
78
+ onClick={async () => {
79
+ setLoading(true);
76
80
  canvas.removeAll();
77
- narration.callLabel(startLabel, gameProps).then(() => {
78
- queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] });
79
- navigate(NARRATION_ROUTE);
80
- });
81
+ await navigate(NARRATION_ROUTE);
82
+ narration
83
+ .callLabel(startLabel, gameProps)
84
+ .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
85
+ .finally(() => setLoading(false));
81
86
  }}
82
87
  transitionDelay={0.2}
88
+ disabled={loading}
83
89
  >
84
90
  {t("start")}
85
91
  </MenuButton>
86
- <MenuButton onClick={editSaveScreen} transitionDelay={0.3}>
92
+ <MenuButton onClick={editSaveScreen} transitionDelay={0.3} disabled={loading}>
87
93
  {t("load")}
88
94
  </MenuButton>
89
95
  <MenuButton onClick={() => setOpenSettings(true)} transitionDelay={0.4}>
@@ -24,7 +24,7 @@ export function getSave(image?: string): GameSaveData {
24
24
  }
25
25
 
26
26
  export async function loadSave(saveData: GameSaveData, navigate: NavigateFunction) {
27
- navigate(LOADING_ROUTE);
27
+ await navigate(LOADING_ROUTE);
28
28
  // load the save data from the JSON string
29
29
  await Game.restoreGameState(saveData.saveData, navigate);
30
30
  }
@@ -11,7 +11,7 @@
11
11
  "preview": "vite preview"
12
12
  },
13
13
  "dependencies": {
14
- "@drincs/pixi-vn": "^1.2.22",
14
+ "@drincs/pixi-vn": "^1.2.23",
15
15
  "@drincs/pixi-vn-ink": "^0.7.5",
16
16
  "@emotion/react": "^11.14.0",
17
17
  "@emotion/styled": "^11.14.1",
@@ -2,7 +2,7 @@ import { canvas, ImageSprite, narration } from "@drincs/pixi-vn";
2
2
  import Stack from "@mui/joy/Stack";
3
3
  import { useQueryClient } from "@tanstack/react-query";
4
4
  import { motion } from "motion/react";
5
- import { useEffect } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import MenuButton from "../components/MenuButton";
7
7
  import { CANVAS_UI_LAYER_NAME, NARRATION_ROUTE } from "../constans";
8
8
  import useGameProps from "../hooks/useGameProps";
@@ -21,6 +21,7 @@ export default function MainMenu() {
21
21
  const { data: lastSave = null, isLoading } = useQueryLastSave();
22
22
  const gameProps = useGameProps();
23
23
  const { uiTransition: t, navigate, notify } = gameProps;
24
+ const [loading, setLoading] = useState(false);
24
25
 
25
26
  useEffect(() => {
26
27
  editHideInterface(false);
@@ -57,32 +58,37 @@ export default function MainMenu() {
57
58
  if (!lastSave) {
58
59
  return;
59
60
  }
61
+ setLoading(true);
60
62
  loadSave(lastSave, navigate)
61
63
  .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
62
64
  .catch((e) => {
63
65
  notify(t("fail_load"), { variant: "error" });
64
66
  console.error(e);
65
- });
67
+ })
68
+ .finally(() => setLoading(false));
66
69
  }}
67
70
  transitionDelay={0.1}
68
71
  loading={isLoading}
69
- disabled={!isLoading && !lastSave}
72
+ disabled={!isLoading && !lastSave && !loading}
70
73
  >
71
74
  {t("continue")}
72
75
  </MenuButton>
73
76
  <MenuButton
74
- onClick={() => {
77
+ onClick={async () => {
78
+ setLoading(true);
75
79
  canvas.removeAll();
76
- narration.callLabel("start", gameProps).then(() => {
77
- queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] });
78
- navigate(NARRATION_ROUTE);
79
- });
80
+ await navigate(NARRATION_ROUTE);
81
+ narration
82
+ .callLabel("start", gameProps)
83
+ .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
84
+ .finally(() => setLoading(false));
80
85
  }}
81
86
  transitionDelay={0.2}
87
+ disabled={loading}
82
88
  >
83
89
  {t("start")}
84
90
  </MenuButton>
85
- <MenuButton onClick={editSaveScreen} transitionDelay={0.3}>
91
+ <MenuButton onClick={editSaveScreen} transitionDelay={0.3} disabled={loading}>
86
92
  {t("load")}
87
93
  </MenuButton>
88
94
  <MenuButton onClick={() => setOpenSettings(true)} transitionDelay={0.4}>
@@ -24,7 +24,7 @@ export function getSave(image?: string): GameSaveData {
24
24
  }
25
25
 
26
26
  export async function loadSave(saveData: GameSaveData, navigate: NavigateFunction) {
27
- navigate(LOADING_ROUTE);
27
+ await navigate(LOADING_ROUTE);
28
28
  // load the save data from the JSON string
29
29
  await Game.restoreGameState(saveData.saveData, navigate);
30
30
  }
@@ -12,7 +12,7 @@
12
12
  "tauri": "tauri"
13
13
  },
14
14
  "dependencies": {
15
- "@drincs/pixi-vn": "^1.2.22",
15
+ "@drincs/pixi-vn": "^1.2.23",
16
16
  "@drincs/pixi-vn-ink": "^0.7.5",
17
17
  "@emotion/react": "^11.14.0",
18
18
  "@emotion/styled": "^11.14.1",
@@ -2,7 +2,7 @@ import { canvas, ImageSprite, narration } from "@drincs/pixi-vn";
2
2
  import Stack from "@mui/joy/Stack";
3
3
  import { useQueryClient } from "@tanstack/react-query";
4
4
  import { motion } from "motion/react";
5
- import { useEffect } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import MenuButton from "../components/MenuButton";
7
7
  import { CANVAS_UI_LAYER_NAME, NARRATION_ROUTE } from "../constans";
8
8
  import useGameProps from "../hooks/useGameProps";
@@ -21,6 +21,7 @@ export default function MainMenu() {
21
21
  const { data: lastSave = null, isLoading } = useQueryLastSave();
22
22
  const gameProps = useGameProps();
23
23
  const { uiTransition: t, navigate, notify } = gameProps;
24
+ const [loading, setLoading] = useState(false);
24
25
 
25
26
  useEffect(() => {
26
27
  editHideInterface(false);
@@ -57,32 +58,37 @@ export default function MainMenu() {
57
58
  if (!lastSave) {
58
59
  return;
59
60
  }
61
+ setLoading(true);
60
62
  loadSave(lastSave, navigate)
61
63
  .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
62
64
  .catch((e) => {
63
65
  notify(t("fail_load"), { variant: "error" });
64
66
  console.error(e);
65
- });
67
+ })
68
+ .finally(() => setLoading(false));
66
69
  }}
67
70
  transitionDelay={0.1}
68
71
  loading={isLoading}
69
- disabled={!isLoading && !lastSave}
72
+ disabled={!isLoading && !lastSave && !loading}
70
73
  >
71
74
  {t("continue")}
72
75
  </MenuButton>
73
76
  <MenuButton
74
- onClick={() => {
77
+ onClick={async () => {
78
+ setLoading(true);
75
79
  canvas.removeAll();
76
- narration.callLabel("start", gameProps).then(() => {
77
- queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] });
78
- navigate(NARRATION_ROUTE);
79
- });
80
+ await navigate(NARRATION_ROUTE);
81
+ narration
82
+ .callLabel("start", gameProps)
83
+ .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
84
+ .finally(() => setLoading(false));
80
85
  }}
81
86
  transitionDelay={0.2}
87
+ disabled={loading}
82
88
  >
83
89
  {t("start")}
84
90
  </MenuButton>
85
- <MenuButton onClick={editSaveScreen} transitionDelay={0.3}>
91
+ <MenuButton onClick={editSaveScreen} transitionDelay={0.3} disabled={loading}>
86
92
  {t("load")}
87
93
  </MenuButton>
88
94
  <MenuButton onClick={() => setOpenSettings(true)} transitionDelay={0.4}>
@@ -24,7 +24,7 @@ export function getSave(image?: string): GameSaveData {
24
24
  }
25
25
 
26
26
  export async function loadSave(saveData: GameSaveData, navigate: NavigateFunction) {
27
- navigate(LOADING_ROUTE);
27
+ await navigate(LOADING_ROUTE);
28
28
  // load the save data from the JSON string
29
29
  await Game.restoreGameState(saveData.saveData, navigate);
30
30
  }
@@ -12,7 +12,7 @@
12
12
  "tauri": "tauri"
13
13
  },
14
14
  "dependencies": {
15
- "@drincs/pixi-vn": "^1.2.22",
15
+ "@drincs/pixi-vn": "^1.2.23",
16
16
  "@emotion/react": "^11.14.0",
17
17
  "@emotion/styled": "^11.14.1",
18
18
  "@mui/icons-material": "^7.2.0",
@@ -2,7 +2,7 @@ import { canvas, ImageSprite, narration } from "@drincs/pixi-vn";
2
2
  import Stack from "@mui/joy/Stack";
3
3
  import { useQueryClient } from "@tanstack/react-query";
4
4
  import { motion } from "motion/react";
5
- import { useEffect } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import MenuButton from "../components/MenuButton";
7
7
  import { CANVAS_UI_LAYER_NAME, NARRATION_ROUTE } from "../constans";
8
8
  import useGameProps from "../hooks/useGameProps";
@@ -22,6 +22,7 @@ export default function MainMenu() {
22
22
  const { data: lastSave = null, isLoading } = useQueryLastSave();
23
23
  const gameProps = useGameProps();
24
24
  const { uiTransition: t, navigate, notify } = gameProps;
25
+ const [loading, setLoading] = useState(false);
25
26
 
26
27
  useEffect(() => {
27
28
  editHideInterface(false);
@@ -58,32 +59,37 @@ export default function MainMenu() {
58
59
  if (!lastSave) {
59
60
  return;
60
61
  }
62
+ setLoading(true);
61
63
  loadSave(lastSave, navigate)
62
64
  .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
63
65
  .catch((e) => {
64
66
  notify(t("fail_load"), { variant: "error" });
65
67
  console.error(e);
66
- });
68
+ })
69
+ .finally(() => setLoading(false));
67
70
  }}
68
71
  transitionDelay={0.1}
69
72
  loading={isLoading}
70
- disabled={!isLoading && !lastSave}
73
+ disabled={!isLoading && !lastSave && !loading}
71
74
  >
72
75
  {t("continue")}
73
76
  </MenuButton>
74
77
  <MenuButton
75
- onClick={() => {
78
+ onClick={async () => {
79
+ setLoading(true);
76
80
  canvas.removeAll();
77
- narration.callLabel(startLabel, gameProps).then(() => {
78
- queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] });
79
- navigate(NARRATION_ROUTE);
80
- });
81
+ await navigate(NARRATION_ROUTE);
82
+ narration
83
+ .callLabel(startLabel, gameProps)
84
+ .then(() => queryClient.invalidateQueries({ queryKey: [INTERFACE_DATA_USE_QUEY_KEY] }))
85
+ .finally(() => setLoading(false));
81
86
  }}
82
87
  transitionDelay={0.2}
88
+ disabled={loading}
83
89
  >
84
90
  {t("start")}
85
91
  </MenuButton>
86
- <MenuButton onClick={editSaveScreen} transitionDelay={0.3}>
92
+ <MenuButton onClick={editSaveScreen} transitionDelay={0.3} disabled={loading}>
87
93
  {t("load")}
88
94
  </MenuButton>
89
95
  <MenuButton onClick={() => setOpenSettings(true)} transitionDelay={0.4}>
@@ -24,7 +24,7 @@ export function getSave(image?: string): GameSaveData {
24
24
  }
25
25
 
26
26
  export async function loadSave(saveData: GameSaveData, navigate: NavigateFunction) {
27
- navigate(LOADING_ROUTE);
27
+ await navigate(LOADING_ROUTE);
28
28
  // load the save data from the JSON string
29
29
  await Game.restoreGameState(saveData.saveData, navigate);
30
30
  }