@magicborn/dialogue-forge 0.1.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.
Files changed (241) hide show
  1. package/README.md +233 -0
  2. package/bin/dialogue-forge.js +78 -0
  3. package/demo/app/layout.tsx +36 -0
  4. package/demo/app/page.tsx +440 -0
  5. package/demo/components/ThemeSwitcher.tsx +611 -0
  6. package/demo/next.config.mjs +7 -0
  7. package/demo/package.json +29 -0
  8. package/demo/postcss.config.mjs +7 -0
  9. package/demo/public/logo.svg +1 -0
  10. package/demo/styles/globals.css +19 -0
  11. package/demo/tailwind.config.ts +90 -0
  12. package/demo/tsconfig.json +42 -0
  13. package/dist/components/ChoiceEdgeV2.d.ts +3 -0
  14. package/dist/components/ChoiceEdgeV2.js +103 -0
  15. package/dist/components/CodeBlock.d.ts +8 -0
  16. package/dist/components/CodeBlock.js +24 -0
  17. package/dist/components/ConditionAutocomplete.d.ts +14 -0
  18. package/dist/components/ConditionAutocomplete.js +284 -0
  19. package/dist/components/ConditionalNodeV2.d.ts +16 -0
  20. package/dist/components/ConditionalNodeV2.js +147 -0
  21. package/dist/components/DialogueEditorV2.d.ts +22 -0
  22. package/dist/components/DialogueEditorV2.js +1170 -0
  23. package/dist/components/EdgeIcon.d.ts +8 -0
  24. package/dist/components/EdgeIcon.js +13 -0
  25. package/dist/components/ExampleLoader.d.ts +11 -0
  26. package/dist/components/ExampleLoader.js +52 -0
  27. package/dist/components/ExampleLoaderButton.d.ts +15 -0
  28. package/dist/components/ExampleLoaderButton.js +102 -0
  29. package/dist/components/FlagManager.d.ts +11 -0
  30. package/dist/components/FlagManager.js +282 -0
  31. package/dist/components/FlagSelector.d.ts +11 -0
  32. package/dist/components/FlagSelector.js +235 -0
  33. package/dist/components/GuidePanel.d.ts +7 -0
  34. package/dist/components/GuidePanel.js +1176 -0
  35. package/dist/components/Minimap.d.ts +16 -0
  36. package/dist/components/Minimap.js +93 -0
  37. package/dist/components/NPCEdgeV2.d.ts +3 -0
  38. package/dist/components/NPCEdgeV2.js +104 -0
  39. package/dist/components/NPCNodeV2.d.ts +26 -0
  40. package/dist/components/NPCNodeV2.js +86 -0
  41. package/dist/components/NodeEditor.d.ts +18 -0
  42. package/dist/components/NodeEditor.js +1025 -0
  43. package/dist/components/PlayView.d.ts +12 -0
  44. package/dist/components/PlayView.js +307 -0
  45. package/dist/components/PlayerNodeV2.d.ts +16 -0
  46. package/dist/components/PlayerNodeV2.js +139 -0
  47. package/dist/components/ReactFlowPOC.d.ts +61 -0
  48. package/dist/components/ReactFlowPOC.js +312 -0
  49. package/dist/components/ScenePlayer.d.ts +18 -0
  50. package/dist/components/ScenePlayer.js +196 -0
  51. package/dist/components/YarnView.d.ts +9 -0
  52. package/dist/components/YarnView.js +45 -0
  53. package/dist/components/ZoomControls.d.ts +11 -0
  54. package/dist/components/ZoomControls.js +34 -0
  55. package/dist/esm/components/ChoiceEdgeV2.d.ts +3 -0
  56. package/dist/esm/components/ChoiceEdgeV2.js +67 -0
  57. package/dist/esm/components/CodeBlock.d.ts +8 -0
  58. package/dist/esm/components/CodeBlock.js +18 -0
  59. package/dist/esm/components/ConditionAutocomplete.d.ts +14 -0
  60. package/dist/esm/components/ConditionAutocomplete.js +248 -0
  61. package/dist/esm/components/ConditionalNodeV2.d.ts +16 -0
  62. package/dist/esm/components/ConditionalNodeV2.js +111 -0
  63. package/dist/esm/components/DialogueEditorV2.d.ts +22 -0
  64. package/dist/esm/components/DialogueEditorV2.js +1134 -0
  65. package/dist/esm/components/EdgeIcon.d.ts +8 -0
  66. package/dist/esm/components/EdgeIcon.js +7 -0
  67. package/dist/esm/components/ExampleLoader.d.ts +11 -0
  68. package/dist/esm/components/ExampleLoader.js +46 -0
  69. package/dist/esm/components/ExampleLoaderButton.d.ts +15 -0
  70. package/dist/esm/components/ExampleLoaderButton.js +66 -0
  71. package/dist/esm/components/FlagManager.d.ts +11 -0
  72. package/dist/esm/components/FlagManager.js +246 -0
  73. package/dist/esm/components/FlagSelector.d.ts +11 -0
  74. package/dist/esm/components/FlagSelector.js +199 -0
  75. package/dist/esm/components/GuidePanel.d.ts +7 -0
  76. package/dist/esm/components/GuidePanel.js +1140 -0
  77. package/dist/esm/components/Minimap.d.ts +16 -0
  78. package/dist/esm/components/Minimap.js +57 -0
  79. package/dist/esm/components/NPCEdgeV2.d.ts +3 -0
  80. package/dist/esm/components/NPCEdgeV2.js +68 -0
  81. package/dist/esm/components/NPCNodeV2.d.ts +26 -0
  82. package/dist/esm/components/NPCNodeV2.js +80 -0
  83. package/dist/esm/components/NodeEditor.d.ts +18 -0
  84. package/dist/esm/components/NodeEditor.js +989 -0
  85. package/dist/esm/components/PlayView.d.ts +12 -0
  86. package/dist/esm/components/PlayView.js +271 -0
  87. package/dist/esm/components/PlayerNodeV2.d.ts +16 -0
  88. package/dist/esm/components/PlayerNodeV2.js +103 -0
  89. package/dist/esm/components/ReactFlowPOC.d.ts +61 -0
  90. package/dist/esm/components/ReactFlowPOC.js +275 -0
  91. package/dist/esm/components/ScenePlayer.d.ts +18 -0
  92. package/dist/esm/components/ScenePlayer.js +160 -0
  93. package/dist/esm/components/YarnView.d.ts +9 -0
  94. package/dist/esm/components/YarnView.js +39 -0
  95. package/dist/esm/components/ZoomControls.d.ts +11 -0
  96. package/dist/esm/components/ZoomControls.js +28 -0
  97. package/dist/esm/examples/example-loader.d.ts +29 -0
  98. package/dist/esm/examples/example-loader.js +103 -0
  99. package/dist/esm/examples/examples-registry.d.ts +38 -0
  100. package/dist/esm/examples/examples-registry.js +153 -0
  101. package/dist/esm/examples/index.d.ts +26 -0
  102. package/dist/esm/examples/index.js +50 -0
  103. package/dist/esm/examples/legacy-examples.d.ts +9 -0
  104. package/dist/esm/examples/legacy-examples.js +814 -0
  105. package/dist/esm/examples/yarn-examples.d.ts +35 -0
  106. package/dist/esm/examples/yarn-examples.js +181 -0
  107. package/dist/esm/index.d.ts +21 -0
  108. package/dist/esm/index.js +26 -0
  109. package/dist/esm/lib/flag-manager.d.ts +21 -0
  110. package/dist/esm/lib/flag-manager.js +93 -0
  111. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  112. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.js +169 -0
  113. package/dist/esm/lib/yarn-converter.d.ts +17 -0
  114. package/dist/esm/lib/yarn-converter.js +521 -0
  115. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  116. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.js +171 -0
  117. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  118. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.js +237 -0
  119. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  120. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.js +106 -0
  121. package/dist/esm/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  122. package/dist/esm/lib/yarn-runner/condition-evaluator.js +56 -0
  123. package/dist/esm/lib/yarn-runner/index.d.ts +12 -0
  124. package/dist/esm/lib/yarn-runner/index.js +11 -0
  125. package/dist/esm/lib/yarn-runner/node-processor.d.ts +18 -0
  126. package/dist/esm/lib/yarn-runner/node-processor.js +129 -0
  127. package/dist/esm/lib/yarn-runner/variable-manager.d.ts +51 -0
  128. package/dist/esm/lib/yarn-runner/variable-manager.js +120 -0
  129. package/dist/esm/lib/yarn-runner/variable-operations.d.ts +16 -0
  130. package/dist/esm/lib/yarn-runner/variable-operations.js +88 -0
  131. package/dist/esm/types/conditionals.d.ts +29 -0
  132. package/dist/esm/types/conditionals.js +1 -0
  133. package/dist/esm/types/constants.d.ts +59 -0
  134. package/dist/esm/types/constants.js +55 -0
  135. package/dist/esm/types/flags.d.ts +49 -0
  136. package/dist/esm/types/flags.js +49 -0
  137. package/dist/esm/types/game-state.d.ts +62 -0
  138. package/dist/esm/types/game-state.js +6 -0
  139. package/dist/esm/types/index.d.ts +77 -0
  140. package/dist/esm/types/index.js +1 -0
  141. package/dist/esm/utils/constants.d.ts +5 -0
  142. package/dist/esm/utils/constants.js +5 -0
  143. package/dist/esm/utils/feature-flags.d.ts +11 -0
  144. package/dist/esm/utils/feature-flags.js +11 -0
  145. package/dist/esm/utils/game-state-flattener.d.ts +41 -0
  146. package/dist/esm/utils/game-state-flattener.js +135 -0
  147. package/dist/esm/utils/layout/collision.d.ts +27 -0
  148. package/dist/esm/utils/layout/collision.js +74 -0
  149. package/dist/esm/utils/layout/index.d.ts +82 -0
  150. package/dist/esm/utils/layout/index.js +98 -0
  151. package/dist/esm/utils/layout/registry.d.ts +91 -0
  152. package/dist/esm/utils/layout/registry.js +148 -0
  153. package/dist/esm/utils/layout/strategies/dagre.d.ts +19 -0
  154. package/dist/esm/utils/layout/strategies/dagre.js +182 -0
  155. package/dist/esm/utils/layout/strategies/force.d.ts +21 -0
  156. package/dist/esm/utils/layout/strategies/force.js +178 -0
  157. package/dist/esm/utils/layout/strategies/grid.d.ts +17 -0
  158. package/dist/esm/utils/layout/strategies/grid.js +91 -0
  159. package/dist/esm/utils/layout/strategies/index.d.ts +8 -0
  160. package/dist/esm/utils/layout/strategies/index.js +8 -0
  161. package/dist/esm/utils/layout/types.d.ts +100 -0
  162. package/dist/esm/utils/layout/types.js +7 -0
  163. package/dist/esm/utils/layout.d.ts +9 -0
  164. package/dist/esm/utils/layout.js +17 -0
  165. package/dist/esm/utils/node-helpers.d.ts +7 -0
  166. package/dist/esm/utils/node-helpers.js +94 -0
  167. package/dist/esm/utils/reactflow-converter.d.ts +42 -0
  168. package/dist/esm/utils/reactflow-converter.js +217 -0
  169. package/dist/examples/example-loader.d.ts +29 -0
  170. package/dist/examples/example-loader.js +109 -0
  171. package/dist/examples/examples-registry.d.ts +38 -0
  172. package/dist/examples/examples-registry.js +160 -0
  173. package/dist/examples/index.d.ts +26 -0
  174. package/dist/examples/index.js +63 -0
  175. package/dist/examples/legacy-examples.d.ts +9 -0
  176. package/dist/examples/legacy-examples.js +817 -0
  177. package/dist/examples/yarn-examples.d.ts +35 -0
  178. package/dist/examples/yarn-examples.js +189 -0
  179. package/dist/index.d.ts +21 -0
  180. package/dist/index.js +66 -0
  181. package/dist/lib/flag-manager.d.ts +21 -0
  182. package/dist/lib/flag-manager.js +99 -0
  183. package/dist/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  184. package/dist/lib/yarn-converter/__tests__/round-trip.test.js +171 -0
  185. package/dist/lib/yarn-converter.d.ts +17 -0
  186. package/dist/lib/yarn-converter.js +525 -0
  187. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  188. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.js +173 -0
  189. package/dist/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  190. package/dist/lib/yarn-runner/__tests__/node-processor.test.js +239 -0
  191. package/dist/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  192. package/dist/lib/yarn-runner/__tests__/variable-manager.test.js +108 -0
  193. package/dist/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  194. package/dist/lib/yarn-runner/condition-evaluator.js +60 -0
  195. package/dist/lib/yarn-runner/index.d.ts +12 -0
  196. package/dist/lib/yarn-runner/index.js +21 -0
  197. package/dist/lib/yarn-runner/node-processor.d.ts +18 -0
  198. package/dist/lib/yarn-runner/node-processor.js +133 -0
  199. package/dist/lib/yarn-runner/variable-manager.d.ts +51 -0
  200. package/dist/lib/yarn-runner/variable-manager.js +124 -0
  201. package/dist/lib/yarn-runner/variable-operations.d.ts +16 -0
  202. package/dist/lib/yarn-runner/variable-operations.js +92 -0
  203. package/dist/types/conditionals.d.ts +29 -0
  204. package/dist/types/conditionals.js +2 -0
  205. package/dist/types/constants.d.ts +59 -0
  206. package/dist/types/constants.js +58 -0
  207. package/dist/types/flags.d.ts +49 -0
  208. package/dist/types/flags.js +52 -0
  209. package/dist/types/game-state.d.ts +62 -0
  210. package/dist/types/game-state.js +7 -0
  211. package/dist/types/index.d.ts +77 -0
  212. package/dist/types/index.js +2 -0
  213. package/dist/utils/constants.d.ts +5 -0
  214. package/dist/utils/constants.js +8 -0
  215. package/dist/utils/feature-flags.d.ts +11 -0
  216. package/dist/utils/feature-flags.js +14 -0
  217. package/dist/utils/game-state-flattener.d.ts +41 -0
  218. package/dist/utils/game-state-flattener.js +140 -0
  219. package/dist/utils/layout/collision.d.ts +27 -0
  220. package/dist/utils/layout/collision.js +77 -0
  221. package/dist/utils/layout/index.d.ts +82 -0
  222. package/dist/utils/layout/index.js +109 -0
  223. package/dist/utils/layout/registry.d.ts +91 -0
  224. package/dist/utils/layout/registry.js +151 -0
  225. package/dist/utils/layout/strategies/dagre.d.ts +19 -0
  226. package/dist/utils/layout/strategies/dagre.js +189 -0
  227. package/dist/utils/layout/strategies/force.d.ts +21 -0
  228. package/dist/utils/layout/strategies/force.js +182 -0
  229. package/dist/utils/layout/strategies/grid.d.ts +17 -0
  230. package/dist/utils/layout/strategies/grid.js +95 -0
  231. package/dist/utils/layout/strategies/index.d.ts +8 -0
  232. package/dist/utils/layout/strategies/index.js +14 -0
  233. package/dist/utils/layout/types.d.ts +100 -0
  234. package/dist/utils/layout/types.js +8 -0
  235. package/dist/utils/layout.d.ts +9 -0
  236. package/dist/utils/layout.js +25 -0
  237. package/dist/utils/node-helpers.d.ts +7 -0
  238. package/dist/utils/node-helpers.js +101 -0
  239. package/dist/utils/reactflow-converter.d.ts +42 -0
  240. package/dist/utils/reactflow-converter.js +223 -0
  241. package/package.json +70 -0
@@ -0,0 +1,440 @@
1
+ 'use client';
2
+
3
+ import { useState, useCallback } from 'react';
4
+ import { DialogueEditorV2 } from '@magicborn/dialogue-forge/src/components/DialogueEditorV2';
5
+ import { FlagManager } from '@magicborn/dialogue-forge/src/components/FlagManager';
6
+ import { GuidePanel } from '@magicborn/dialogue-forge/src/components/GuidePanel';
7
+ import { FlagSchema, exampleFlagSchema } from '@magicborn/dialogue-forge/src/types/flags';
8
+ import { DialogueTree } from '@magicborn/dialogue-forge/src/types';
9
+ import { exportToYarn } from '@magicborn/dialogue-forge/src/lib/yarn-converter';
10
+ import {
11
+ listExamples,
12
+ getExampleDialogue,
13
+ listDemoFlagSchemas,
14
+ getDemoFlagSchema
15
+ } from '@magicborn/dialogue-forge/src/examples';
16
+ import { Play, Layout, FileText } from 'lucide-react';
17
+ import { ThemeSwitcher } from '../components/ThemeSwitcher';
18
+
19
+ type ViewMode = 'graph' | 'yarn' | 'play';
20
+
21
+ // Tell Next.js this page is static (no dynamic params/searchParams)
22
+ export const dynamic = 'force-static';
23
+
24
+ // Demo examples - these are specific to the demo app
25
+ const demoDialogues: Record<string, DialogueTree> = {
26
+ 'mysterious-stranger': {
27
+ id: 'mysterious-stranger',
28
+ title: 'Demo: The Mysterious Stranger',
29
+ startNodeId: 'start',
30
+ nodes: {
31
+ 'start': {
32
+ id: 'start',
33
+ type: 'npc',
34
+ speaker: 'Stranger',
35
+ x: 300,
36
+ y: 100,
37
+ content: "You find yourself at a crossroads. A cloaked figure emerges from the shadows.",
38
+ nextNodeId: 'greeting',
39
+ },
40
+ 'greeting': {
41
+ id: 'greeting',
42
+ type: 'npc',
43
+ speaker: 'Stranger',
44
+ x: 300,
45
+ y: 200,
46
+ content: "\"Traveler... I've been waiting for you. What brings you to these lands?\"",
47
+ nextNodeId: 'first_choice',
48
+ },
49
+ 'first_choice': {
50
+ id: 'first_choice',
51
+ type: 'player',
52
+ content: '',
53
+ x: 300,
54
+ y: 300,
55
+ choices: [
56
+ {
57
+ id: 'choice_treasure',
58
+ text: "I seek the legendary treasure.",
59
+ nextNodeId: 'treasure_response',
60
+ conditions: [
61
+ { flag: 'reputation', operator: 'greater_equal', value: 0 },
62
+ ],
63
+ },
64
+ {
65
+ id: 'choice_knowledge',
66
+ text: "I'm searching for ancient knowledge.",
67
+ nextNodeId: 'knowledge_response',
68
+ conditions: [
69
+ { flag: 'reputation', operator: 'greater_equal', value: 0 },
70
+ ],
71
+ },
72
+ {
73
+ id: 'choice_high_rep',
74
+ text: "I am a hero of this land!",
75
+ nextNodeId: 'high_rep_response',
76
+ conditions: [
77
+ { flag: 'reputation', operator: 'greater_than', value: 50 },
78
+ ],
79
+ },
80
+ ],
81
+ },
82
+ 'treasure_response': {
83
+ id: 'treasure_response',
84
+ type: 'npc',
85
+ speaker: 'Stranger',
86
+ x: 200,
87
+ y: 450,
88
+ content: "\"Many have sought the same. Take this map—it shows the entrance to the catacombs.\"",
89
+ nextNodeId: undefined,
90
+ },
91
+ 'knowledge_response': {
92
+ id: 'knowledge_response',
93
+ type: 'npc',
94
+ speaker: 'Stranger',
95
+ x: 400,
96
+ y: 450,
97
+ content: "\"A seeker of truth... Take this tome. It contains the riddles you must solve.\"",
98
+ nextNodeId: undefined,
99
+ },
100
+ 'high_rep_response': {
101
+ id: 'high_rep_response',
102
+ type: 'npc',
103
+ speaker: 'Stranger',
104
+ x: 500,
105
+ y: 450,
106
+ content: "\"Ah, a hero! Your reputation precedes you. I have something special for you...\"",
107
+ nextNodeId: undefined,
108
+ setFlags: ['reputation'],
109
+ },
110
+ },
111
+ },
112
+ 'tavern-quest': {
113
+ id: 'tavern-quest',
114
+ title: 'Demo: Tavern Quest',
115
+ startNodeId: 'enter_tavern',
116
+ nodes: {
117
+ 'enter_tavern': {
118
+ id: 'enter_tavern',
119
+ type: 'npc',
120
+ speaker: 'Narrator',
121
+ x: 300,
122
+ y: 50,
123
+ content: "You push open the heavy wooden door and enter the Rusty Dragon tavern.",
124
+ nextNodeId: 'bartender_greet',
125
+ },
126
+ 'bartender_greet': {
127
+ id: 'bartender_greet',
128
+ type: 'npc',
129
+ speaker: 'Bartender',
130
+ x: 300,
131
+ y: 150,
132
+ content: "\"Welcome, stranger! What can I get ya? We've got ale, mead, or if you're looking for work, I might have something.\"",
133
+ nextNodeId: 'tavern_choice',
134
+ },
135
+ 'tavern_choice': {
136
+ id: 'tavern_choice',
137
+ type: 'player',
138
+ content: '',
139
+ x: 300,
140
+ y: 280,
141
+ choices: [
142
+ { id: 'order_ale', text: "I'll have an ale.", nextNodeId: 'drink_ale' },
143
+ { id: 'ask_work', text: "What kind of work?", nextNodeId: 'work_info' },
144
+ { id: 'look_around', text: "I'll just look around.", nextNodeId: 'observe_tavern' },
145
+ {
146
+ id: 'vip_entrance',
147
+ text: "I'm a VIP member.",
148
+ nextNodeId: 'vip_response',
149
+ conditions: [
150
+ { flag: 'reputation', operator: 'greater_than', value: 75 },
151
+ ],
152
+ },
153
+ ],
154
+ },
155
+ 'drink_ale': {
156
+ id: 'drink_ale',
157
+ type: 'npc',
158
+ speaker: 'Bartender',
159
+ x: 100,
160
+ y: 420,
161
+ content: "\"Coming right up!\" He slides a frothy mug across the bar.",
162
+ nextNodeId: undefined,
163
+ },
164
+ 'work_info': {
165
+ id: 'work_info',
166
+ type: 'npc',
167
+ speaker: 'Bartender',
168
+ x: 300,
169
+ y: 420,
170
+ content: "\"Rats in the cellar. Big ones. I'll pay 10 gold if you clear 'em out.\"",
171
+ nextNodeId: 'accept_quest',
172
+ },
173
+ 'accept_quest': {
174
+ id: 'accept_quest',
175
+ type: 'player',
176
+ content: '',
177
+ x: 300,
178
+ y: 550,
179
+ choices: [
180
+ { id: 'accept', text: "I'll do it.", nextNodeId: 'quest_accepted' },
181
+ { id: 'decline', text: "Not interested." },
182
+ ],
183
+ },
184
+ 'quest_accepted': {
185
+ id: 'quest_accepted',
186
+ type: 'npc',
187
+ speaker: 'Bartender',
188
+ x: 300,
189
+ y: 680,
190
+ content: "\"Great! The cellar door is in the back. Good luck!\"",
191
+ nextNodeId: undefined,
192
+ },
193
+ 'observe_tavern': {
194
+ id: 'observe_tavern',
195
+ type: 'npc',
196
+ speaker: 'Narrator',
197
+ x: 500,
198
+ y: 420,
199
+ content: "You notice a hooded figure in the corner, watching you intently...",
200
+ nextNodeId: undefined,
201
+ },
202
+ 'vip_response': {
203
+ id: 'vip_response',
204
+ type: 'npc',
205
+ speaker: 'Bartender',
206
+ x: 600,
207
+ y: 420,
208
+ content: "\"Of course! Right this way to the VIP lounge. Your reputation grants you access.\"",
209
+ nextNodeId: undefined,
210
+ },
211
+ },
212
+ },
213
+ };
214
+
215
+ // Enhanced flag schema with reputation for demo examples
216
+ const demoFlagSchema: FlagSchema = {
217
+ ...exampleFlagSchema,
218
+ flags: [
219
+ ...exampleFlagSchema.flags,
220
+ {
221
+ id: 'reputation',
222
+ name: 'Reputation',
223
+ type: 'stat',
224
+ description: 'Player reputation score',
225
+ defaultValue: 0,
226
+ },
227
+ ],
228
+ };
229
+
230
+ export default function DialogueForgeDemo() {
231
+ const [dialogueTree, setDialogueTree] = useState<DialogueTree>(demoDialogues['mysterious-stranger']);
232
+ const [flagSchema, setFlagSchema] = useState<FlagSchema>(demoFlagSchema);
233
+ const [viewMode, setViewMode] = useState<ViewMode>('graph');
234
+
235
+ // Panel states
236
+ const [showFlagManager, setShowFlagManager] = useState(false);
237
+ const [showGuide, setShowGuide] = useState(false);
238
+ const [showExamplePicker, setShowExamplePicker] = useState(false);
239
+
240
+ const handleExportYarn = useCallback(() => {
241
+ const yarn = exportToYarn(dialogueTree);
242
+ const blob = new Blob([yarn], { type: 'text/plain' });
243
+ const url = URL.createObjectURL(blob);
244
+ const a = document.createElement('a');
245
+ a.href = url;
246
+ a.download = `${dialogueTree.title.replace(/\s+/g, '_')}.yarn`;
247
+ a.click();
248
+ URL.revokeObjectURL(url);
249
+ }, [dialogueTree]);
250
+
251
+ const handleLoadExample = useCallback((exampleId: string) => {
252
+ // Try demo examples first
253
+ if (demoDialogues[exampleId]) {
254
+ setDialogueTree(demoDialogues[exampleId]);
255
+ setShowExamplePicker(false);
256
+ return;
257
+ }
258
+ // Try package examples
259
+ const example = getExampleDialogue(exampleId);
260
+ if (example) {
261
+ setDialogueTree(example);
262
+ }
263
+ setShowExamplePicker(false);
264
+ }, []);
265
+
266
+ const handleLoadFlagSchema = useCallback((schemaId: string) => {
267
+ const schema = getDemoFlagSchema(schemaId);
268
+ if (schema) {
269
+ setFlagSchema(schema);
270
+ }
271
+ }, []);
272
+
273
+ // Get all available examples
274
+ const allExamples = [
275
+ ...Object.keys(demoDialogues),
276
+ ...listExamples()
277
+ ].filter((v, i, a) => a.indexOf(v) === i); // unique
278
+
279
+ const allFlagSchemas = listDemoFlagSchemas();
280
+
281
+ return (
282
+ <div className="w-full h-screen flex flex-col">
283
+ {/* Header */}
284
+ <div className="max-w-7xl mx-auto px-4 py-4 flex-shrink-0 w-full">
285
+ <div className="flex items-center justify-between">
286
+ <div>
287
+ <h1 className="text-2xl font-bold text-white mb-1">Dialogue Forge Editor</h1>
288
+ <p className="text-zinc-400 text-sm">
289
+ Create interactive dialogues with a visual node-based editor. Export to Yarn Spinner format.
290
+ </p>
291
+ </div>
292
+ <div className="flex items-center gap-2">
293
+ <ThemeSwitcher />
294
+ <div className="w-px h-6 bg-zinc-700" />
295
+ <button
296
+ onClick={() => setShowExamplePicker(true)}
297
+ className="px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-sm rounded-lg transition-colors"
298
+ >
299
+ Load Example
300
+ </button>
301
+ <div className="w-px h-6 bg-zinc-700" />
302
+ {/* View Mode Toggle */}
303
+ <div className="flex items-center gap-1 bg-[#12121a] border border-[#2a2a3e] rounded-lg p-1">
304
+ <button
305
+ onClick={() => setViewMode('graph')}
306
+ className={`px-3 py-1.5 text-sm rounded transition-colors flex items-center gap-1.5 ${
307
+ viewMode === 'graph'
308
+ ? 'bg-indigo-600 text-white'
309
+ : 'text-gray-400 hover:text-white'
310
+ }`}
311
+ title="Graph Editor"
312
+ >
313
+ <Layout size={14} />
314
+ <span className="hidden sm:inline">Editor</span>
315
+ </button>
316
+ <button
317
+ onClick={() => setViewMode('play')}
318
+ className={`px-3 py-1.5 text-sm rounded transition-colors flex items-center gap-1.5 ${
319
+ viewMode === 'play'
320
+ ? 'bg-green-600 text-white'
321
+ : 'text-gray-400 hover:text-white'
322
+ }`}
323
+ title="Play Dialogue"
324
+ >
325
+ <Play size={14} />
326
+ <span className="hidden sm:inline">Play</span>
327
+ </button>
328
+ </div>
329
+ <button
330
+ onClick={() => setShowExamplePicker(true)}
331
+ className="px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-sm rounded-lg transition-colors"
332
+ >
333
+ Load Example
334
+ </button>
335
+ </div>
336
+ </div>
337
+ </div>
338
+
339
+ {/* Editor/Player */}
340
+ <div className="flex-1 w-full min-h-0">
341
+ <DialogueEditorV2
342
+ dialogue={dialogueTree}
343
+ onChange={setDialogueTree}
344
+ onExportYarn={handleExportYarn}
345
+ flagSchema={flagSchema}
346
+ viewMode={viewMode}
347
+ onViewModeChange={setViewMode}
348
+ className="w-full h-full"
349
+ onOpenFlagManager={() => setShowFlagManager(true)}
350
+ onOpenGuide={() => setShowGuide(true)}
351
+ />
352
+ </div>
353
+
354
+ {/* Flag Manager Modal */}
355
+ {showFlagManager && (
356
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
357
+ <div className="bg-[#0d0d14] border border-[#2a2a3e] rounded-lg shadow-xl max-w-4xl w-full max-h-[80vh] overflow-hidden">
358
+ <FlagManager
359
+ flagSchema={flagSchema}
360
+ dialogue={dialogueTree}
361
+ onUpdate={setFlagSchema}
362
+ onClose={() => setShowFlagManager(false)}
363
+ />
364
+ </div>
365
+ </div>
366
+ )}
367
+
368
+ {/* Guide Panel */}
369
+ <GuidePanel
370
+ isOpen={showGuide}
371
+ onClose={() => setShowGuide(false)}
372
+ />
373
+
374
+ {/* Example Picker Modal */}
375
+ {showExamplePicker && (
376
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
377
+ <div className="bg-[#0d0d14] border border-[#2a2a3e] rounded-lg shadow-xl max-w-lg w-full p-6">
378
+ <div className="flex items-center justify-between mb-4">
379
+ <h2 className="text-lg font-semibold text-white">Load Example Dialogue</h2>
380
+ <button
381
+ onClick={() => setShowExamplePicker(false)}
382
+ className="text-gray-400 hover:text-white"
383
+ >
384
+
385
+ </button>
386
+ </div>
387
+
388
+ <div className="space-y-2 max-h-64 overflow-y-auto">
389
+ <h3 className="text-sm font-medium text-gray-400 mb-2">Demo Examples</h3>
390
+ {Object.entries(demoDialogues).map(([id, dialogue]) => (
391
+ <button
392
+ key={id}
393
+ onClick={() => handleLoadExample(id)}
394
+ className="w-full text-left px-4 py-3 bg-[#12121a] hover:bg-[#1a1a2e] border border-[#2a2a3e] rounded-lg transition-colors"
395
+ >
396
+ <div className="font-medium text-white">{dialogue.title}</div>
397
+ <div className="text-xs text-gray-400">
398
+ {Object.keys(dialogue.nodes).length} nodes
399
+ </div>
400
+ </button>
401
+ ))}
402
+
403
+ {listExamples().length > 0 && (
404
+ <>
405
+ <h3 className="text-sm font-medium text-gray-400 mt-4 mb-2">Package Examples</h3>
406
+ {listExamples().map((id) => (
407
+ <button
408
+ key={id}
409
+ onClick={() => handleLoadExample(id)}
410
+ className="w-full text-left px-4 py-3 bg-[#12121a] hover:bg-[#1a1a2e] border border-[#2a2a3e] rounded-lg transition-colors"
411
+ >
412
+ <div className="font-medium text-white">{id}</div>
413
+ </button>
414
+ ))}
415
+ </>
416
+ )}
417
+ </div>
418
+
419
+ {allFlagSchemas.length > 0 && (
420
+ <div className="mt-4 pt-4 border-t border-[#2a2a3e]">
421
+ <h3 className="text-sm font-medium text-gray-400 mb-2">Flag Schemas</h3>
422
+ <div className="flex flex-wrap gap-2">
423
+ {allFlagSchemas.map((id) => (
424
+ <button
425
+ key={id}
426
+ onClick={() => handleLoadFlagSchema(id)}
427
+ className="px-3 py-1 text-xs bg-purple-500/20 text-purple-400 border border-purple-500/30 rounded hover:bg-purple-500/30 transition-colors"
428
+ >
429
+ {id}
430
+ </button>
431
+ ))}
432
+ </div>
433
+ </div>
434
+ )}
435
+ </div>
436
+ </div>
437
+ )}
438
+ </div>
439
+ );
440
+ }