@react-text-game/ui 0.2.3 → 0.3.0
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/README.md +67 -0
- package/dist/components/GameProvider/GameProvider.d.ts.map +1 -1
- package/dist/components/GameProvider/GameProvider.js +2 -1
- package/dist/components/GameProvider/GameProvider.js.map +1 -1
- package/dist/components/LanguageToggle.d.ts +47 -0
- package/dist/components/LanguageToggle.d.ts.map +1 -0
- package/dist/components/LanguageToggle.js +56 -0
- package/dist/components/LanguageToggle.js.map +1 -0
- package/dist/components/MainMenu.d.ts.map +1 -1
- package/dist/components/MainMenu.js +6 -5
- package/dist/components/MainMenu.js.map +1 -1
- package/dist/components/ReloadButton.d.ts.map +1 -1
- package/dist/components/ReloadButton.js +1 -0
- package/dist/components/ReloadButton.js.map +1 -1
- package/dist/components/SaveButton.d.ts.map +1 -1
- package/dist/components/SaveButton.js +1 -0
- package/dist/components/SaveButton.js.map +1 -1
- package/dist/components/SaveLoadModal/SaveLoadModal.d.ts +1 -1
- package/dist/components/SaveLoadModal/SaveLoadModal.d.ts.map +1 -1
- package/dist/components/SaveLoadModal/SaveLoadModal.js +11 -3
- package/dist/components/SaveLoadModal/SaveLoadModal.js.map +1 -1
- package/dist/components/SaveLoadModal/SaveSlot.d.ts +16 -0
- package/dist/components/SaveLoadModal/SaveSlot.d.ts.map +1 -0
- package/dist/components/SaveLoadModal/SaveSlot.js +21 -0
- package/dist/components/SaveLoadModal/SaveSlot.js.map +1 -0
- package/dist/components/StoryComponent/StoryComponent.d.ts.map +1 -1
- package/dist/components/StoryComponent/StoryComponent.js +25 -4
- package/dist/components/StoryComponent/StoryComponent.js.map +1 -1
- package/dist/components/StoryComponent/components/Conversation.d.ts.map +1 -1
- package/dist/components/StoryComponent/components/Conversation.js +32 -6
- package/dist/components/StoryComponent/components/Conversation.js.map +1 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -1
- package/dist/components/index.js.map +1 -1
- package/dist/context/ComponentsContext/ComponentsContext.d.ts.map +1 -1
- package/dist/context/ComponentsContext/ComponentsContext.js +1 -0
- package/dist/context/ComponentsContext/ComponentsContext.js.map +1 -1
- package/dist/context/ComponentsContext/types.d.ts.map +1 -1
- package/dist/context/ConversationClickContext/ConversationClickContext.d.ts +8 -0
- package/dist/context/ConversationClickContext/ConversationClickContext.d.ts.map +1 -0
- package/dist/context/ConversationClickContext/ConversationClickContext.js +4 -0
- package/dist/context/ConversationClickContext/ConversationClickContext.js.map +1 -0
- package/dist/context/ConversationClickContext/ConversationClickProvider.d.ts +3 -0
- package/dist/context/ConversationClickContext/ConversationClickProvider.d.ts.map +1 -0
- package/dist/context/ConversationClickContext/ConversationClickProvider.js +25 -0
- package/dist/context/ConversationClickContext/ConversationClickProvider.js.map +1 -0
- package/dist/context/ConversationClickContext/index.d.ts +4 -0
- package/dist/context/ConversationClickContext/index.d.ts.map +1 -0
- package/dist/context/ConversationClickContext/index.js +4 -0
- package/dist/context/ConversationClickContext/index.js.map +1 -0
- package/dist/context/ConversationClickContext/useConversationClickContext.d.ts +2 -0
- package/dist/context/ConversationClickContext/useConversationClickContext.d.ts.map +1 -0
- package/dist/context/ConversationClickContext/useConversationClickContext.js +10 -0
- package/dist/context/ConversationClickContext/useConversationClickContext.js.map +1 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/i18n/index.d.ts +37 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +5 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locales/en/ui.json +32 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/styles/index.css +50 -35
- package/dist/tests/GameProvider.test.d.ts +2 -0
- package/dist/tests/GameProvider.test.d.ts.map +1 -0
- package/dist/tests/GameProvider.test.js +178 -0
- package/dist/tests/GameProvider.test.js.map +1 -0
- package/dist/tests/StoryComponent/Conversation.test.d.ts +2 -0
- package/dist/tests/StoryComponent/Conversation.test.d.ts.map +1 -0
- package/dist/tests/StoryComponent/Conversation.test.js +306 -0
- package/dist/tests/StoryComponent/Conversation.test.js.map +1 -0
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -4,6 +4,13 @@ UI components library for react-text-game built with React 19, TypeScript, and T
|
|
|
4
4
|
|
|
5
5
|
> Install this package inside your own React project. It depends on `@react-text-game/core` for game state and Tailwind CSS v4 for styling tokens.
|
|
6
6
|
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Drop-in game shell: main menu, passage renderer, save/load modal, and dev helpers
|
|
10
|
+
- Tailwind CSS v4 theme tokens for full visual customization
|
|
11
|
+
- Language-aware UI copy powered by i18next with persistent language switching
|
|
12
|
+
- React hooks and context utilities that integrate directly with `@react-text-game/core`
|
|
13
|
+
|
|
7
14
|
## Installation
|
|
8
15
|
|
|
9
16
|
### 1. Install and configure Tailwind CSS
|
|
@@ -57,6 +64,66 @@ export function App() {
|
|
|
57
64
|
|
|
58
65
|
With those two components in place, the UI handles menus, passage rendering, and save/load modals. You can immediately start defining entities and passages through `@react-text-game/core`.
|
|
59
66
|
|
|
67
|
+
## Internationalization
|
|
68
|
+
|
|
69
|
+
The UI package ships with an `en` translation bundle for the `ui` namespace and exposes it through `@react-text-game/ui/i18n`. When you call `Game.init`, the core engine automatically merges these strings with your game resources and persists the active language for every player.
|
|
70
|
+
|
|
71
|
+
### Default UI copy
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { uiTranslations } from '@react-text-game/ui/i18n';
|
|
75
|
+
|
|
76
|
+
console.log(uiTranslations.en.ui.mainMenu.title); // "Main Menu"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Components such as `MainMenu`, `SaveLoadModal`, and `ErrorBoundary` already call `useTranslation('ui')`, so English works out of the box. You only need to add resources when you want to localize beyond the default language or override labels.
|
|
80
|
+
|
|
81
|
+
### Adding more languages
|
|
82
|
+
|
|
83
|
+
Create your own `ui` namespace JSON file per language and pass it alongside your story translations:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import uiEs from './locales/es/ui.json';
|
|
87
|
+
import passagesEs from './locales/es/passages.json';
|
|
88
|
+
|
|
89
|
+
await Game.init({
|
|
90
|
+
gameName: 'My Text Adventure',
|
|
91
|
+
translations: {
|
|
92
|
+
defaultLanguage: 'en',
|
|
93
|
+
fallbackLanguage: 'en',
|
|
94
|
+
resources: {
|
|
95
|
+
es: {
|
|
96
|
+
ui: uiEs,
|
|
97
|
+
passages: passagesEs,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- Any namespace you provide (including `ui`) overrides the defaults for that language.
|
|
105
|
+
- If you omit a translation key, i18next falls back to the language defined in `fallbackLanguage`.
|
|
106
|
+
- Because the core engine persists language preference in its settings store, players keep their choice on reload.
|
|
107
|
+
|
|
108
|
+
### Language toggle component
|
|
109
|
+
|
|
110
|
+
Use the built-in `LanguageToggle` to expose language switching in your UI. It relies on `useGameTranslation`, so language changes propagate everywhere.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { LanguageToggle } from '@react-text-game/ui';
|
|
114
|
+
|
|
115
|
+
function Header() {
|
|
116
|
+
return (
|
|
117
|
+
<header className="flex justify-end">
|
|
118
|
+
<LanguageToggle
|
|
119
|
+
languageNames={{ en: 'English', es: 'Español' }}
|
|
120
|
+
showCode
|
|
121
|
+
/>
|
|
122
|
+
</header>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
60
127
|
## Development
|
|
61
128
|
|
|
62
129
|
```bash
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameProvider.d.ts","sourceRoot":"","sources":["../../../src/components/GameProvider/GameProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEH,UAAU,EAGb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAuB,MAAM,OAAO,CAAC;AAK/D,OAAO,EAAE,UAAU,EAAsB,MAAM,4BAA4B,CAAC;AAS5E,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;IAC9C,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B,CAAC,CAAC;AAOH,eAAO,MAAM,YAAY,GAAI,oCAI1B,iBAAiB,
|
|
1
|
+
{"version":3,"file":"GameProvider.d.ts","sourceRoot":"","sources":["../../../src/components/GameProvider/GameProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEH,UAAU,EAGb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAuB,MAAM,OAAO,CAAC;AAK/D,OAAO,EAAE,UAAU,EAAsB,MAAM,4BAA4B,CAAC;AAS5E,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;IAC9C,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B,CAAC,CAAC;AAOH,eAAO,MAAM,YAAY,GAAI,oCAI1B,iBAAiB,mDA6CnB,CAAC"}
|
|
@@ -19,7 +19,8 @@ export const GameProvider = ({ children, options, components = {}, }) => {
|
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
Game.init(options).then(() => {
|
|
21
21
|
newWidget(SYSTEM_PASSAGE_NAMES.START_MENU, components?.MainMenu?.() || _jsx(MainMenu, {}));
|
|
22
|
-
|
|
22
|
+
const initialPassage = options.startPassage || SYSTEM_PASSAGE_NAMES.START_MENU;
|
|
23
|
+
Game.setCurrent(initialPassage);
|
|
23
24
|
setIsInitialized(true);
|
|
24
25
|
});
|
|
25
26
|
}, [options]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameProvider.js","sourceRoot":"","sources":["../../../src/components/GameProvider/GameProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACH,IAAI,EAEJ,SAAS,EACT,oBAAoB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAqB,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAc,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EACH,oBAAoB,EACpB,eAAe,GAClB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAO5C,MAAM,oBAAoB,GAAG,GAAG,EAAE;IAC9B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,eAAe,EAAE,CAAC;IAClD,OAAO,KAAC,aAAa,IAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAI,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EACzB,QAAQ,EACR,OAAO,EACP,UAAU,GAAG,EAAE,GACC,EAAE,EAAE;IACpB,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAa,OAAO,CAAC,CAAC;IAC5E,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE1D,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YACzB,SAAS,CACL,oBAAoB,CAAC,UAAU,EAC/B,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,KAAC,QAAQ,KAAG,CAC3C,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"GameProvider.js","sourceRoot":"","sources":["../../../src/components/GameProvider/GameProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACH,IAAI,EAEJ,SAAS,EACT,oBAAoB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAqB,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAc,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EACH,oBAAoB,EACpB,eAAe,GAClB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAO5C,MAAM,oBAAoB,GAAG,GAAG,EAAE;IAC9B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,eAAe,EAAE,CAAC;IAClD,OAAO,KAAC,aAAa,IAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAI,CAAC;AACzE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EACzB,QAAQ,EACR,OAAO,EACP,UAAU,GAAG,EAAE,GACC,EAAE,EAAE;IACpB,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAa,OAAO,CAAC,CAAC;IAC5E,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE1D,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YACzB,SAAS,CACL,oBAAoB,CAAC,UAAU,EAC/B,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,KAAC,QAAQ,KAAG,CAC3C,CAAC;YACF,MAAM,cAAc,GAAG,OAAO,CAAC,YAAY,IAAI,oBAAoB,CAAC,UAAU,CAAC;YAC/E,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAChC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,eAAe,IAAI,aAAa,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;YAClE,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;QACxC,CAAC;IACL,CAAC,EAAE,CAAC,eAAe,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC;IAE9C,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,CACH,KAAC,aAAa,cACV,KAAC,kBAAkB,IAAC,UAAU,EAAE,UAAU,YACtC,MAAC,oBAAoB,eAChB,QAAQ,EACR,OAAO,CAAC,SAAS,IAAI,CAClB,8BACI,KAAC,WAAW,IACR,OAAO,EAAE,eAAe,EACxB,UAAU,EAAE,kBAAkB,GAChC,EACF,KAAC,aAAa,IAAC,OAAO,EAAE,eAAe,GAAI,IAC5C,CACN,EACD,KAAC,oBAAoB,KAAG,IACL,GACN,GACT,CACnB,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type LanguageToggleProps = Readonly<{
|
|
2
|
+
/**
|
|
3
|
+
* Optional CSS class name for custom styling
|
|
4
|
+
*/
|
|
5
|
+
className?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Optional namespace for translations (defaults to 'ui')
|
|
8
|
+
*/
|
|
9
|
+
namespace?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Optional custom language names mapping
|
|
12
|
+
* Example: { en: 'English', ru: 'Русский', de: 'Deutsch' }
|
|
13
|
+
*/
|
|
14
|
+
languageNames?: Record<string, string>;
|
|
15
|
+
/**
|
|
16
|
+
* Show language code alongside the name (e.g., "English (en)")
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
showCode?: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* A themed language toggle dropdown component that opens on hover.
|
|
23
|
+
* Uses the UI package's semantic theming system for automatic dark mode support.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Basic usage
|
|
28
|
+
* <LanguageToggle />
|
|
29
|
+
*
|
|
30
|
+
* // With custom language names
|
|
31
|
+
* <LanguageToggle
|
|
32
|
+
* languageNames={{
|
|
33
|
+
* en: 'English',
|
|
34
|
+
* ru: 'Русский',
|
|
35
|
+
* de: 'Deutsch'
|
|
36
|
+
* }}
|
|
37
|
+
* />
|
|
38
|
+
*
|
|
39
|
+
* // With custom styling and code display
|
|
40
|
+
* <LanguageToggle
|
|
41
|
+
* className="custom-class"
|
|
42
|
+
* showCode={true}
|
|
43
|
+
* />
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const LanguageToggle: ({ className, namespace, languageNames, showCode, }: LanguageToggleProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
47
|
+
//# sourceMappingURL=LanguageToggle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LanguageToggle.d.ts","sourceRoot":"","sources":["../../src/components/LanguageToggle.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACvC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,cAAc,GAAI,oDAK5B,mBAAmB,mDAgHrB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useGameTranslation } from "@react-text-game/core/i18n";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { twMerge } from "tailwind-merge";
|
|
6
|
+
/**
|
|
7
|
+
* A themed language toggle dropdown component that opens on hover.
|
|
8
|
+
* Uses the UI package's semantic theming system for automatic dark mode support.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* // Basic usage
|
|
13
|
+
* <LanguageToggle />
|
|
14
|
+
*
|
|
15
|
+
* // With custom language names
|
|
16
|
+
* <LanguageToggle
|
|
17
|
+
* languageNames={{
|
|
18
|
+
* en: 'English',
|
|
19
|
+
* ru: 'Русский',
|
|
20
|
+
* de: 'Deutsch'
|
|
21
|
+
* }}
|
|
22
|
+
* />
|
|
23
|
+
*
|
|
24
|
+
* // With custom styling and code display
|
|
25
|
+
* <LanguageToggle
|
|
26
|
+
* className="custom-class"
|
|
27
|
+
* showCode={true}
|
|
28
|
+
* />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export const LanguageToggle = ({ className = "", namespace, languageNames, showCode = false, }) => {
|
|
32
|
+
const { currentLanguage, languages, changeLanguage } = useGameTranslation(namespace);
|
|
33
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
34
|
+
// Default language names - uppercase language codes
|
|
35
|
+
const getLanguageName = (lang) => {
|
|
36
|
+
if (languageNames && languageNames[lang]) {
|
|
37
|
+
return languageNames[lang];
|
|
38
|
+
}
|
|
39
|
+
return lang.toUpperCase();
|
|
40
|
+
};
|
|
41
|
+
const handleLanguageChange = async (lang) => {
|
|
42
|
+
await changeLanguage(lang);
|
|
43
|
+
setIsOpen(false);
|
|
44
|
+
};
|
|
45
|
+
// Don't render if there's only one language or no languages
|
|
46
|
+
if (languages.length <= 1) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return (_jsxs("div", { className: twMerge("relative inline-block", className), onMouseEnter: () => setIsOpen(true), onMouseLeave: () => setIsOpen(false), children: [_jsxs("button", { className: "flex items-center gap-2 px-4 py-2 bg-primary-500 hover:bg-primary-600 text-primary-foreground rounded-lg shadow-md transition-colors duration-200 cursor-pointer active:scale-95", "aria-label": "Select language", "aria-expanded": isOpen, "aria-haspopup": "true", children: [_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-5 h-5", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" }), _jsx("path", { d: "M2 12h20" })] }), _jsxs("span", { className: "font-medium", children: [getLanguageName(currentLanguage), showCode && ` (${currentLanguage})`] }), _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: twMerge("w-4 h-4 transition-transform duration-200", isOpen ? "rotate-180" : ""), "aria-hidden": "true", children: _jsx("polyline", { points: "6 9 12 15 18 9" }) })] }), isOpen && (_jsx("div", { className: "absolute top-full left-0 pt-2 min-w-full z-50", role: "menu", "aria-orientation": "vertical", children: _jsx("div", { className: "bg-popover border border-border rounded-lg shadow-lg overflow-hidden animate-[fadeIn_150ms_ease-in]", children: languages.map((lang) => {
|
|
50
|
+
const isActive = lang === currentLanguage;
|
|
51
|
+
return (_jsxs("button", { onClick: () => handleLanguageChange(lang), className: twMerge("w-full text-left px-4 py-2.5 transition-colors duration-150 whitespace-nowrap", isActive
|
|
52
|
+
? "bg-primary-100 text-primary-700 font-medium cursor-default"
|
|
53
|
+
: "text-popover-foreground hover:bg-muted hover:text-accent-foreground cursor-pointer"), role: "menuitem", "aria-current": isActive ? "true" : undefined, children: [getLanguageName(lang), showCode && ` (${lang})`, isActive && (_jsx("span", { className: "ml-2", "aria-label": "Current language", children: "\u2713" }))] }, lang));
|
|
54
|
+
}) }) }))] }));
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=LanguageToggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LanguageToggle.js","sourceRoot":"","sources":["../../src/components/LanguageToggle.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MainMenu.d.ts","sourceRoot":"","sources":["../../src/components/MainMenu.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MainMenu.d.ts","sourceRoot":"","sources":["../../src/components/MainMenu.tsx"],"names":[],"mappings":"AAWA,eAAO,MAAM,QAAQ,+CA+CpB,CAAC"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { Game, SYSTEM_PASSAGE_NAMES } from "@react-text-game/core";
|
|
3
4
|
import { useLastLoadGame } from "@react-text-game/core/saves";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
4
6
|
import { useSaveLoadMenu } from "../context/SaveLoadMenuContext";
|
|
5
7
|
import { Button } from "./common";
|
|
8
|
+
import { LanguageToggle } from "./LanguageToggle";
|
|
6
9
|
export const MainMenu = () => {
|
|
10
|
+
const { t } = useTranslation("ui");
|
|
7
11
|
const { hasLastSave, loadLastGame } = useLastLoadGame();
|
|
8
12
|
const { openLoadMenu } = useSaveLoadMenu();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
console.log(result);
|
|
12
|
-
};
|
|
13
|
-
return (_jsxs("div", { className: "mt-10 flex flex-col items-center justify-center h-full gap-8", children: [_jsxs("div", { className: "fixed top-10 left-10 flex flex-col items-start", children: [_jsxs("h2", { className: "text-2xl flex gap-2", children: [_jsx("span", { className: "text-primary-500 font-semibold", children: Game.options.gameName.toUpperCase() }), _jsxs("span", { className: "font-mono font-light text-secondary-500", children: ["v", Game.options.gameVersion] })] }), Game.options.author && (_jsxs("h3", { className: "text-md font-light text-secondary-400", children: ["by ", Game.options.author] }))] }), _jsx("h1", { className: "text-4xl font-bold text-primary-900", children: "Main Menu" }), _jsxs("div", { className: "flex flex-col w-40 gap-4", children: [_jsx(Button, { onClick: () => Game.jumpTo(Game.options.startPassage || SYSTEM_PASSAGE_NAMES.START), children: "New Game" }), _jsx(Button, { disabled: !hasLastSave, onClick: continueCallback, children: "Continue" }), _jsx(Button, { onClick: openLoadMenu, children: "Load Game" })] })] }));
|
|
13
|
+
return (_jsxs("div", { className: "mt-10 flex flex-col items-center justify-center h-full gap-8", children: [_jsxs("div", { className: "fixed top-10 left-10 flex flex-col items-start", children: [_jsxs("h2", { className: "text-2xl flex gap-2", children: [_jsx("span", { className: "text-primary-500 font-semibold", children: Game.options.gameName.toUpperCase() }), _jsxs("span", { className: "font-mono font-light text-secondary-500", children: ["v", Game.options.gameVersion] })] }), Game.options.author && (_jsxs("h3", { className: "text-md font-light text-secondary-400", children: ["by ", Game.options.author] }))] }), _jsx("div", { className: "fixed top-10 right-20", children: _jsx(LanguageToggle, {}) }), _jsx("h1", { className: "text-4xl font-bold text-primary-900", children: t("mainMenu.title") }), _jsxs("div", { className: "flex flex-col w-40 gap-4", children: [_jsx(Button, { onClick: () => Game.jumpTo(Game.options.startPassage ||
|
|
14
|
+
SYSTEM_PASSAGE_NAMES.START), children: t("mainMenu.newGame") }), _jsx(Button, { disabled: !hasLastSave, onClick: loadLastGame, children: t("mainMenu.continue") }), _jsx(Button, { onClick: openLoadMenu, children: t("mainMenu.loadGame") })] })] }));
|
|
14
15
|
};
|
|
15
16
|
//# sourceMappingURL=MainMenu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MainMenu.js","sourceRoot":"","sources":["../../src/components/MainMenu.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MainMenu.js","sourceRoot":"","sources":["../../src/components/MainMenu.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE;IACzB,MAAM,EAAE,CAAC,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAEnC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,eAAe,EAAE,CAAC;IACxD,MAAM,EAAE,YAAY,EAAE,GAAG,eAAe,EAAE,CAAC;IAE3C,OAAO,CACH,eAAK,SAAS,EAAC,8DAA8D,aACzE,eAAK,SAAS,EAAC,gDAAgD,aAC3D,cAAI,SAAS,EAAC,qBAAqB,aAC/B,eAAM,SAAS,EAAC,gCAAgC,YAC3C,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,GACjC,EACP,gBAAM,SAAS,EAAC,yCAAyC,kBACnD,IAAI,CAAC,OAAO,CAAC,WAAW,IACvB,IACN,EACJ,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CACpB,cAAI,SAAS,EAAC,uCAAuC,oBAC7C,IAAI,CAAC,OAAO,CAAC,MAAM,IACtB,CACR,IACC,EACN,cAAK,SAAS,EAAC,uBAAuB,YAClC,KAAC,cAAc,KAAG,GAChB,EACN,aAAI,SAAS,EAAC,qCAAqC,YAC9C,CAAC,CAAC,gBAAgB,CAAC,GACnB,EACL,eAAK,SAAS,EAAC,0BAA0B,aACrC,KAAC,MAAM,IACH,OAAO,EAAE,GAAG,EAAE,CACV,IAAI,CAAC,MAAM,CACP,IAAI,CAAC,OAAO,CAAC,YAAY;4BACrB,oBAAoB,CAAC,KAAK,CACjC,YAGJ,CAAC,CAAC,kBAAkB,CAAC,GACjB,EACT,KAAC,MAAM,IAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,YAAY,YAChD,CAAC,CAAC,mBAAmB,CAAC,GAClB,EACT,KAAC,MAAM,IAAC,OAAO,EAAE,YAAY,YAAG,CAAC,CAAC,mBAAmB,CAAC,GAAU,IAC9D,IACJ,CACT,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReloadButton.d.ts","sourceRoot":"","sources":["../../src/components/ReloadButton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ReloadButton.d.ts","sourceRoot":"","sources":["../../src/components/ReloadButton.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAU,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,SAAS,CAAC,GACrE,QAAQ,CAAC;IACL;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC,CAAC;AAEP,eAAO,MAAM,IAAI,GAAI,eAAe;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,4CAezD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,qCAI1B,iBAAiB,4CAanB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReloadButton.js","sourceRoot":"","sources":["../../src/components/ReloadButton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ReloadButton.js","sourceRoot":"","sources":["../../src/components/ReloadButton.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAe,MAAM,oBAAoB,CAAC;AAYzD,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE,SAAS,EAA0B,EAAE,EAAE,CAAC,CAC3D,cACI,KAAK,EAAC,4BAA4B,EAClC,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,EACnB,SAAS,EAAE,SAAS,YAEpB,aAAG,MAAM,EAAC,cAAc,EAAC,aAAa,EAAC,OAAO,EAAC,WAAW,EAAC,KAAK,aAC5D,eACI,cAAc,EAAC,OAAO,EACtB,CAAC,EAAC,wIAAwI,GAC5I,EACF,eAAM,CAAC,EAAC,8LAA8L,GAAG,IACzM,GACF,CACT,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EACzB,UAAU,EACV,SAAS,EACT,GAAG,KAAK,EACQ,EAAE,EAAE;IACpB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAEhC,OAAO,CACH,MAAC,MAAM,IACH,SAAS,EAAE,OAAO,CAAC,yBAAyB,EAAE,SAAS,CAAC,EACxD,OAAO,EAAE,MAAM,KACX,KAAK,aAET,KAAC,IAAI,IAAC,SAAS,EAAC,SAAS,GAAG,EAC3B,CAAC,UAAU,IAAI,0CAAyB,IACpC,CACZ,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveButton.d.ts","sourceRoot":"","sources":["../../src/components/SaveButton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SaveButton.d.ts","sourceRoot":"","sources":["../../src/components/SaveButton.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAU,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAG5D,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,SAAS,CAAC,GACnE,QAAQ,CAAC;IACL;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;CACrC,CAAC,CAAC;AAkBP,eAAO,MAAM,UAAU,GAAI,2CAKxB,eAAe,4CAajB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveButton.js","sourceRoot":"","sources":["../../src/components/SaveButton.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SaveButton.js","sourceRoot":"","sources":["../../src/components/SaveButton.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAe,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAoB/D,MAAM,IAAI,GAAG,CAAC,EAAE,SAAS,EAA0B,EAAE,EAAE,CAAC,CACpD,cACI,KAAK,EAAC,4BAA4B,EAClC,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,EACnB,SAAS,EAAE,SAAS,YAEpB,eACI,IAAI,EAAC,cAAc,EACnB,QAAQ,EAAC,SAAS,EAClB,CAAC,EAAC,mbAAmb,EACrb,QAAQ,EAAC,SAAS,GACpB,GACA,CACT,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACvB,UAAU,EACV,SAAS,EACT,IAAI,EACJ,GAAG,KAAK,EACM,EAAE,EAAE;IAClB,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,eAAe,EAAE,CAAC;IAE7D,OAAO,CACH,MAAC,MAAM,IACH,SAAS,EAAE,OAAO,CAAC,yBAAyB,EAAE,SAAS,CAAC,EACxD,OAAO,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,KACtD,KAAK,aAET,KAAC,IAAI,IAAC,SAAS,EAAC,SAAS,GAAG,EAC3B,CAAC,UAAU,IAAI,uCAAsB,IACjC,CACZ,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -4,6 +4,6 @@ interface SaveLoadModalProps {
|
|
|
4
4
|
onClose: () => void;
|
|
5
5
|
mode?: SaveLoadMode;
|
|
6
6
|
}
|
|
7
|
-
export declare const SaveLoadModal: ({ isOpen, onClose, mode }: SaveLoadModalProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export declare const SaveLoadModal: ({ isOpen, onClose, mode, }: SaveLoadModalProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
8
8
|
export {};
|
|
9
9
|
//# sourceMappingURL=SaveLoadModal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveLoadModal.d.ts","sourceRoot":"","sources":["../../../src/components/SaveLoadModal/SaveLoadModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SaveLoadModal.d.ts","sourceRoot":"","sources":["../../../src/components/SaveLoadModal/SaveLoadModal.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAI5D,UAAU,kBAAkB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,IAAI,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,GAAI,4BAI3B,kBAAkB,mDAwHpB,CAAC"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useSaveSlots } from "@react-text-game/core/saves";
|
|
3
4
|
import { useEffect, useState } from "react";
|
|
4
|
-
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import { SaveSlot } from "./SaveSlot";
|
|
7
|
+
export const SaveLoadModal = ({ isOpen, onClose, mode = "saveLoad", }) => {
|
|
8
|
+
const { t } = useTranslation("ui");
|
|
5
9
|
const saveSlots = useSaveSlots({ count: 9 });
|
|
6
10
|
const [loading, setLoading] = useState(null);
|
|
7
11
|
useEffect(() => {
|
|
@@ -41,12 +45,16 @@ export const SaveLoadModal = ({ isOpen, onClose, mode = "saveLoad" }) => {
|
|
|
41
45
|
}
|
|
42
46
|
catch (error) {
|
|
43
47
|
console.error("Action failed:", error);
|
|
44
|
-
alert("
|
|
48
|
+
alert(t("saves.errors.actionFailed"));
|
|
45
49
|
}
|
|
46
50
|
finally {
|
|
47
51
|
setLoading(null);
|
|
48
52
|
}
|
|
49
53
|
};
|
|
50
|
-
return (_jsxs("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [_jsx("div", { className: "absolute inset-0 bg-overlay/40 backdrop-blur-sm", onClick: onClose }), _jsxs("div", { className: "relative w-full h-full md:h-auto md:max-h-[90vh] md:w-full md:max-w-4xl mx-0 md:mx-4 bg-background md:rounded-lg shadow-2xl flex flex-col overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between p-4 md:p-6 border-b border-border", children: [_jsx("h2", { className: "text-xl md:text-2xl font-bold text-foreground", children: mode === "save"
|
|
54
|
+
return (_jsxs("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center", children: [_jsx("div", { className: "absolute inset-0 bg-overlay/40 backdrop-blur-sm", onClick: onClose }), _jsxs("div", { className: "relative w-full h-full md:h-auto md:max-h-[90vh] md:w-full md:max-w-4xl mx-0 md:mx-4 bg-background md:rounded-lg shadow-2xl flex flex-col overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between p-4 md:p-6 border-b border-border", children: [_jsx("h2", { className: "text-xl md:text-2xl font-bold text-foreground", children: mode === "save"
|
|
55
|
+
? t("saves.title.save")
|
|
56
|
+
: mode === "load"
|
|
57
|
+
? t("saves.title.load")
|
|
58
|
+
: t("saves.title.saveLoad") }), _jsx("button", { onClick: onClose, className: "text-muted-foreground hover:text-foreground transition-colors p-2 hover:bg-muted rounded-lg", "aria-label": "Close", children: _jsx("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-4 md:p-6 bg-muted", children: _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: saveSlots.map((slot, index) => (_jsx(SaveSlot, { slot: slot, index: index, mode: mode, loading: loading, onAction: handleAction }, index))) }) }), _jsx("div", { className: "p-4 md:p-6 border-t border-border bg-background", children: _jsx("button", { onClick: onClose, className: "w-full md:w-auto px-6 py-2 bg-muted hover:bg-muted-300 text-foreground rounded-lg transition-colors font-medium", children: t("saves.actions.close") }) })] })] }));
|
|
51
59
|
};
|
|
52
60
|
//# sourceMappingURL=SaveLoadModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SaveLoadModal.js","sourceRoot":"","sources":["../../../src/components/SaveLoadModal/SaveLoadModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SaveLoadModal.js","sourceRoot":"","sources":["../../../src/components/SaveLoadModal/SaveLoadModal.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useSaveSlots } from "@react-text-game/core/saves";
|
|
2
|
+
import { SaveLoadMode } from "../../context/SaveLoadMenuContext";
|
|
3
|
+
type SaveSlotType = ReturnType<typeof useSaveSlots>[number];
|
|
4
|
+
interface SaveSlotProps {
|
|
5
|
+
slot: SaveSlotType;
|
|
6
|
+
index: number;
|
|
7
|
+
mode: SaveLoadMode;
|
|
8
|
+
loading: number | null;
|
|
9
|
+
onAction: (slotIndex: number, action: () => Promise<void | {
|
|
10
|
+
success: boolean;
|
|
11
|
+
message: string;
|
|
12
|
+
} | undefined>) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const SaveSlot: ({ slot, index, mode, loading, onAction, }: SaveSlotProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=SaveSlot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SaveSlot.d.ts","sourceRoot":"","sources":["../../../src/components/SaveLoadModal/SaveSlot.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAK3D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,UAAU,aAAa;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,CACN,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,OAAO,CACjB,IAAI,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAC3D,KACA,IAAI,CAAC;CACb;AAED,eAAO,MAAM,QAAQ,GAAI,2CAMtB,aAAa,4CAgHf,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { twMerge } from "tailwind-merge";
|
|
5
|
+
import { Button } from "../../components/common/Button";
|
|
6
|
+
export const SaveSlot = ({ slot, index, mode, loading, onAction, }) => {
|
|
7
|
+
const { t } = useTranslation("ui");
|
|
8
|
+
const hasActions = mode === "save" || (mode === "load" && slot.data) || mode === "saveLoad";
|
|
9
|
+
return (_jsxs("div", { className: twMerge("bg-card rounded-lg border border-border transition-all overflow-hidden", hasActions ? "hover:border-muted-400 hover:shadow-lg" : "cursor-default"), children: [_jsxs("div", { className: "p-3 border-b border-border", children: [_jsx("h3", { className: "text-lg font-semibold text-card-foreground", children: t("saves.slot.label", {
|
|
10
|
+
number: index + 1,
|
|
11
|
+
}) }), _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: slot.data ? new Date(slot.data.timestamp).toLocaleString() : 'no data' })] }), _jsx("div", { className: "p-3", children: slot.data ? (_jsxs("div", { className: "space-y-2", children: [slot.data.description &&
|
|
12
|
+
slot.data.description !== "undefined" && (_jsx("p", { className: "text-sm text-card-foreground line-clamp-2", children: slot.data.description })), slot.data.screenshot &&
|
|
13
|
+
slot.data.screenshot !== "undefined" && (_jsx("img", { src: slot.data.screenshot, alt: "Save screenshot", className: "w-full h-32 object-cover rounded" })), _jsxs("div", { className: "flex gap-2", children: [(mode === "load" || mode === "saveLoad") && (_jsx(Button, { onClick: () => onAction(index, slot.load), disabled: loading !== null, color: "primary", className: "flex-1 rounded-lg font-medium", children: loading === index
|
|
14
|
+
? t("saves.actions.loading")
|
|
15
|
+
: t("saves.actions.load") })), (mode === "save" || mode === "saveLoad") && (_jsx(Button, { onClick: () => onAction(index, slot.save), disabled: loading !== null, color: "success", className: "flex-1 rounded-lg font-medium", children: loading === index
|
|
16
|
+
? t("saves.actions.saving")
|
|
17
|
+
: t("saves.slot.overwrite") })), _jsx(Button, { onClick: () => onAction(index, slot.delete), disabled: loading !== null, color: "danger", className: "rounded-lg", "aria-label": "Delete save", children: _jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }) })] })] })) : (_jsxs("div", { className: "flex flex-col items-center justify-center py-6", children: [_jsx("p", { className: "text-muted-foreground mb-4", children: t("saves.slot.empty") }), (mode === "save" || mode === "saveLoad") && (_jsx(Button, { onClick: () => onAction(index, slot.save), disabled: loading !== null, color: "success", className: "rounded-lg font-medium", children: loading === index
|
|
18
|
+
? t("saves.actions.saving")
|
|
19
|
+
: t("saves.slot.saveHere") }))] })) })] }));
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=SaveSlot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SaveSlot.js","sourceRoot":"","sources":["../../../src/components/SaveLoadModal/SaveSlot.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StoryComponent.d.ts","sourceRoot":"","sources":["../../../src/components/StoryComponent/StoryComponent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"StoryComponent.d.ts","sourceRoot":"","sources":["../../../src/components/StoryComponent/StoryComponent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAUpD,KAAK,mBAAmB,GAAG;IACvB,KAAK,EAAE,KAAK,CAAC;CAChB,CAAC;AAsGF,eAAO,MAAM,cAAc,GAAI,WAAW,mBAAmB,4CAM5D,CAAC"}
|
|
@@ -4,15 +4,33 @@ import { Game } from "@react-text-game/core";
|
|
|
4
4
|
import { useMemo } from "react";
|
|
5
5
|
import { twMerge } from "tailwind-merge";
|
|
6
6
|
import { useComponents } from "../../context/ComponentsContext/useComponents";
|
|
7
|
-
|
|
7
|
+
import { ConversationClickProvider, useConversationClickContext, } from "../../context/ConversationClickContext";
|
|
8
|
+
const StoryContent = ({ story }) => {
|
|
8
9
|
const displayable = useMemo(() => story.display(), [story]);
|
|
9
|
-
const { story: { Heading, Conversation, Actions, Video, Image, Text } } = useComponents();
|
|
10
|
-
|
|
10
|
+
const { story: { Heading, Conversation, Actions, Video, Image, Text }, } = useComponents();
|
|
11
|
+
const context = useConversationClickContext();
|
|
12
|
+
const handleClick = (event) => {
|
|
13
|
+
const target = event.target;
|
|
14
|
+
// Check if the clicked element is non-clickable (not a button, link, or interactive element)
|
|
15
|
+
const isClickable = target.tagName === "BUTTON" ||
|
|
16
|
+
target.tagName === "A" ||
|
|
17
|
+
target.closest("button") ||
|
|
18
|
+
target.closest("a") ||
|
|
19
|
+
target.closest('[role="button"]') ||
|
|
20
|
+
target.closest("input") ||
|
|
21
|
+
target.closest("select") ||
|
|
22
|
+
target.closest("textarea");
|
|
23
|
+
if (!isClickable) {
|
|
24
|
+
// Notify all byClick conversations to show next bubble
|
|
25
|
+
context.notifyClick();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
return (_jsx("div", { className: twMerge("w-full h-full flex flex-col content-center items-center", displayable.options?.classNames?.base), onClick: handleClick, children: _jsx("div", { className: "px-4 w-full flex flex-col content-center items-center", children: _jsx("div", { className: twMerge("w-full overflow-x-hidden max-w-[1200px] flex flex-col gap-4 my-4", displayable.options?.classNames?.container), children: displayable.components.map((component, index) => {
|
|
11
29
|
switch (component.type) {
|
|
12
30
|
case "header":
|
|
13
31
|
return (_jsx(Heading, { component: component }, index));
|
|
14
32
|
case "text":
|
|
15
|
-
return
|
|
33
|
+
return _jsx(Text, { component: component }, index);
|
|
16
34
|
case "image":
|
|
17
35
|
return (_jsx(Image, { component: component }, index));
|
|
18
36
|
case "video":
|
|
@@ -28,4 +46,7 @@ export const StoryComponent = ({ story }) => {
|
|
|
28
46
|
}
|
|
29
47
|
}) }) }) }));
|
|
30
48
|
};
|
|
49
|
+
export const StoryComponent = ({ story }) => {
|
|
50
|
+
return (_jsx(ConversationClickProvider, { children: _jsx(StoryContent, { story: story }) }));
|
|
51
|
+
};
|
|
31
52
|
//# sourceMappingURL=StoryComponent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StoryComponent.js","sourceRoot":"","sources":["../../../src/components/StoryComponent/StoryComponent.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,IAAI,EAAS,MAAM,uBAAuB,CAAC;AACpD,OAAO,
|
|
1
|
+
{"version":3,"file":"StoryComponent.js","sourceRoot":"","sources":["../../../src/components/StoryComponent/StoryComponent.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Conversation.d.ts","sourceRoot":"","sources":["../../../../src/components/StoryComponent/components/Conversation.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,qBAAqB,EAExB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"Conversation.d.ts","sourceRoot":"","sources":["../../../../src/components/StoryComponent/components/Conversation.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,qBAAqB,EAExB,MAAM,gCAAgC,CAAC;AA4ExC,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACrC,SAAS,EAAE,qBAAqB,CAAC;CACpC,CAAC,CAAC;AAEH,eAAO,MAAM,YAAY,GAAI,eAAe,iBAAiB,4CAmE5D,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
3
|
+
import { useEffect, useId, useState } from "react";
|
|
4
4
|
import { twMerge } from "tailwind-merge";
|
|
5
|
+
import { useConversationClickContext } from "../../../context/ConversationClickContext";
|
|
5
6
|
const bubbleStyles = {
|
|
6
7
|
chat: (side) => ({
|
|
7
8
|
base: `flex items-start gap-2 mb-3 ${side === "left" ? "justify-start" : "justify-end"}`,
|
|
@@ -25,17 +26,28 @@ const ConversationLine = ({ line, onClick, variant = "chat", }) => {
|
|
|
25
26
|
export const Conversation = ({ component }) => {
|
|
26
27
|
const [lines, setLines] = useState([]);
|
|
27
28
|
const { appearance, content, props } = component;
|
|
29
|
+
const conversationId = useId();
|
|
30
|
+
// Try to get context, but don't fail if not available (for standalone usage in tests)
|
|
31
|
+
let context;
|
|
32
|
+
try {
|
|
33
|
+
context = useConversationClickContext();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Context not available, component will work standalone
|
|
37
|
+
context = undefined;
|
|
38
|
+
}
|
|
28
39
|
useEffect(() => {
|
|
29
40
|
if (appearance === "byClick") {
|
|
30
|
-
//
|
|
31
|
-
|
|
41
|
+
// Show first bubble immediately when using byClick
|
|
42
|
+
const firstBubble = content[0];
|
|
43
|
+
setLines(firstBubble ? [firstBubble] : []);
|
|
32
44
|
}
|
|
33
45
|
else {
|
|
34
|
-
// If it appears at once,
|
|
46
|
+
// If it appears at once, set all lines immediately
|
|
35
47
|
setLines(content);
|
|
36
48
|
}
|
|
37
49
|
}, [appearance, content]);
|
|
38
|
-
const
|
|
50
|
+
const showNext = () => {
|
|
39
51
|
if (appearance === "byClick") {
|
|
40
52
|
// If the conversation is set to appear by click, append the next line
|
|
41
53
|
setLines((prevLines) => {
|
|
@@ -46,7 +58,21 @@ export const Conversation = ({ component }) => {
|
|
|
46
58
|
return prevLines; // No more lines to add
|
|
47
59
|
});
|
|
48
60
|
}
|
|
49
|
-
|
|
61
|
+
};
|
|
62
|
+
// Register with context for byClick conversations
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (appearance === "byClick" && context) {
|
|
65
|
+
context.registerConversation(conversationId, showNext);
|
|
66
|
+
return () => {
|
|
67
|
+
context.unregisterConversation(conversationId);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}, [appearance, context, conversationId]);
|
|
71
|
+
const onClick = () => {
|
|
72
|
+
// For standalone usage (like tests), support direct clicks
|
|
73
|
+
if (appearance === "byClick" && !context) {
|
|
74
|
+
showNext();
|
|
75
|
+
}
|
|
50
76
|
};
|
|
51
77
|
return (_jsx("div", { className: props?.className, children: lines.map((line, index) => (_jsx(ConversationLine, { onClick: onClick, line: line, variant: props?.variant }, index))) }));
|
|
52
78
|
};
|