synthos 0.10.1 → 0.11.1
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 +5 -5
- package/default-pages/elevenlabs_effects_studio/chat-history.json +1 -0
- package/default-pages/elevenlabs_effects_studio/page.html +1345 -1363
- package/default-pages/elevenlabs_effects_studio/page.json +13 -11
- package/default-pages/elevenlabs_voice_studio/chat-history.json +1 -0
- package/default-pages/elevenlabs_voice_studio/page.html +782 -801
- package/default-pages/elevenlabs_voice_studio/page.json +13 -11
- package/default-pages/json_tools/chat-history.json +1 -0
- package/default-pages/json_tools/page.html +70 -90
- package/default-pages/json_tools/page.json +12 -10
- package/default-pages/my_notes/chat-history.json +1 -0
- package/default-pages/my_notes/page.html +115 -131
- package/default-pages/my_notes/page.json +14 -12
- package/default-pages/neon_asteroids/chat-history.json +1 -0
- package/default-pages/neon_asteroids/page.html +1777 -1803
- package/default-pages/neon_asteroids/page.json +14 -12
- package/default-pages/oregon_trail/chat-history.json +1 -0
- package/default-pages/oregon_trail/page.html +290 -307
- package/default-pages/oregon_trail/page.json +14 -12
- package/default-pages/solar_explorer/chat-history.json +1 -0
- package/default-pages/solar_explorer/page.html +1929 -1951
- package/default-pages/solar_explorer/page.json +14 -12
- package/default-pages/solar_tutorial/chat-history.json +1 -0
- package/default-pages/solar_tutorial/page.html +464 -478
- package/default-pages/solar_tutorial/page.json +12 -10
- package/default-pages/us_map/chat-history.json +1 -0
- package/default-pages/us_map/page.html +170 -193
- package/default-pages/us_map/page.json +14 -12
- package/default-pages/us_map/page.light.png +0 -0
- package/default-pages/us_map_1850/chat-history.json +1 -0
- package/default-pages/us_map_1850/page.html +302 -326
- package/default-pages/us_map_1850/page.json +14 -12
- package/default-pages/western_cities_1850/chat-history.json +1 -0
- package/default-pages/western_cities_1850/page.html +503 -527
- package/default-pages/western_cities_1850/page.json +14 -12
- package/default-themes/aurora-dawn.v3.css +15 -14
- package/default-themes/aurora-dusk.v3.css +26 -26
- package/default-themes/cosmos-dawn.v3.css +15 -14
- package/default-themes/cosmos-dusk.v3.css +26 -26
- package/default-themes/elemental-dawn.v3.css +200 -0
- package/default-themes/nebula-dawn.v3.css +15 -14
- package/default-themes/nebula-dusk.v3.css +24 -24
- package/default-themes/solar-flare-dawn.v3.css +15 -14
- package/default-themes/solar-flare-dusk.v3.css +26 -26
- package/dist/builders/anthropic.d.ts +26 -2
- package/dist/builders/anthropic.d.ts.map +1 -1
- package/dist/builders/anthropic.js +132 -31
- package/dist/builders/anthropic.js.map +1 -1
- package/dist/builders/claudecode.d.ts +13 -0
- package/dist/builders/claudecode.d.ts.map +1 -0
- package/dist/builders/claudecode.js +253 -0
- package/dist/builders/claudecode.js.map +1 -0
- package/dist/builders/index.d.ts +2 -1
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +8 -1
- package/dist/builders/index.js.map +1 -1
- package/dist/builders/openai.js +2 -1
- package/dist/builders/openai.js.map +1 -1
- package/dist/builders/types.d.ts +31 -7
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +60 -28
- package/dist/builders/types.js.map +1 -1
- package/dist/connectors/types.d.ts +8 -0
- package/dist/connectors/types.d.ts.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +13 -6
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +161 -14
- package/dist/migrations.js.map +1 -1
- package/dist/models/anthropic.d.ts +1 -0
- package/dist/models/anthropic.d.ts.map +1 -1
- package/dist/models/anthropic.js +129 -29
- package/dist/models/anthropic.js.map +1 -1
- package/dist/models/chainOfThought.d.ts.map +1 -1
- package/dist/models/chainOfThought.js +32 -19
- package/dist/models/chainOfThought.js.map +1 -1
- package/dist/models/index.d.ts +2 -2
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/providers.d.ts +1 -0
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +12 -4
- package/dist/models/providers.js.map +1 -1
- package/dist/models/types.d.ts +15 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js.map +1 -1
- package/dist/pages.d.ts +57 -8
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +258 -45
- package/dist/pages.js.map +1 -1
- package/dist/service/createCompletePrompt.d.ts.map +1 -1
- package/dist/service/createCompletePrompt.js +5 -0
- package/dist/service/createCompletePrompt.js.map +1 -1
- package/dist/service/mediaCache.d.ts +36 -0
- package/dist/service/mediaCache.d.ts.map +1 -0
- package/dist/service/mediaCache.js +182 -0
- package/dist/service/mediaCache.js.map +1 -0
- package/dist/service/pageValidator.d.ts +25 -0
- package/dist/service/pageValidator.d.ts.map +1 -0
- package/dist/service/pageValidator.js +315 -0
- package/dist/service/pageValidator.js.map +1 -0
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +4 -0
- package/dist/service/server.js.map +1 -1
- package/dist/service/sharedTableSchema.d.ts +73 -0
- package/dist/service/sharedTableSchema.d.ts.map +1 -0
- package/dist/service/sharedTableSchema.js +206 -0
- package/dist/service/sharedTableSchema.js.map +1 -0
- package/dist/service/transformPage.d.ts +49 -11
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +354 -241
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +285 -34
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.d.ts.map +1 -1
- package/dist/service/useConnectorRoutes.js +170 -32
- package/dist/service/useConnectorRoutes.js.map +1 -1
- package/dist/service/useDataRoutes.d.ts.map +1 -1
- package/dist/service/useDataRoutes.js +59 -2
- package/dist/service/useDataRoutes.js.map +1 -1
- package/dist/service/useExtractRoutes.d.ts +4 -0
- package/dist/service/useExtractRoutes.d.ts.map +1 -0
- package/dist/service/useExtractRoutes.js +304 -0
- package/dist/service/useExtractRoutes.js.map +1 -0
- package/dist/service/usePageRoutes.d.ts +17 -0
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +1388 -483
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/service/useSharedDataRoutes.d.ts.map +1 -1
- package/dist/service/useSharedDataRoutes.js +54 -2
- package/dist/service/useSharedDataRoutes.js.map +1 -1
- package/dist/settings.d.ts +27 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +40 -1
- package/dist/settings.js.map +1 -1
- package/dist/themes.d.ts +0 -5
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +3 -95
- package/dist/themes.js.map +1 -1
- package/migration-rules/v2-to-v3.md +277 -119
- package/package.json +5 -1
- package/{default-pages/application → required-pages/_shell}/page.html +56 -42
- package/required-pages/_shell/page.json +14 -0
- package/required-pages/_starters/page.html +534 -0
- package/required-pages/_starters/page.json +12 -0
- package/required-pages/builder/page.html +353 -43
- package/required-pages/builder/page.json +12 -10
- package/required-pages/pages/page.html +697 -924
- package/required-pages/pages/page.json +12 -10
- package/required-pages/settings/page.html +1888 -1753
- package/required-pages/settings/page.json +12 -10
- package/required-pages/synthos_apis/page.html +834 -845
- package/required-pages/synthos_apis/page.json +12 -10
- package/required-pages/synthos_scripts/page.html +74 -88
- package/required-pages/synthos_scripts/page.json +12 -10
- package/scripts/append-instructions.py +90 -0
- package/scripts/audit-instructions.py +76 -0
- package/scripts/cleanup-shell-markup.mjs +112 -0
- package/service-connectors/buffer/connector.json +46 -0
- package/service-connectors/canva/connector.json +67 -0
- package/service-connectors/elevenlabs/connector.json +1 -1
- package/src/builders/anthropic.ts +150 -25
- package/src/builders/claudecode.ts +310 -0
- package/src/builders/index.ts +7 -1
- package/src/builders/openai.ts +2 -1
- package/src/builders/types.ts +93 -32
- package/src/connectors/types.ts +8 -0
- package/src/init.ts +13 -7
- package/src/migrations.ts +187 -16
- package/src/models/anthropic.ts +140 -30
- package/src/models/chainOfThought.ts +33 -18
- package/src/models/index.ts +2 -2
- package/src/models/providers.ts +10 -1
- package/src/models/types.ts +21 -1
- package/src/pages.ts +271 -35
- package/src/service/createCompletePrompt.ts +6 -0
- package/src/service/mediaCache.ts +206 -0
- package/src/service/pageValidator.ts +337 -0
- package/src/service/server.ts +4 -0
- package/src/service/sharedTableSchema.ts +236 -0
- package/src/service/transformPage.ts +370 -260
- package/src/service/useApiRoutes.ts +283 -32
- package/src/service/useConnectorRoutes.ts +189 -34
- package/src/service/useDataRoutes.ts +198 -116
- package/src/service/useExtractRoutes.ts +331 -0
- package/src/service/usePageRoutes.ts +1414 -394
- package/src/service/useSharedDataRoutes.ts +184 -109
- package/src/settings.ts +65 -0
- package/src/themes.ts +78 -180
- package/starters/blank_starter/chat-history.json +1 -0
- package/starters/blank_starter/page.dark.png +0 -0
- package/starters/blank_starter/page.html +47 -0
- package/starters/blank_starter/page.json +13 -0
- package/starters/blank_starter/page.light.png +0 -0
- package/starters/calculator_starter/chat-history.json +1 -0
- package/starters/calculator_starter/page.dark.png +0 -0
- package/starters/calculator_starter/page.html +232 -0
- package/starters/calculator_starter/page.json +13 -0
- package/starters/calculator_starter/page.light.png +0 -0
- package/starters/calendar_starter/chat-history.json +1 -0
- package/starters/calendar_starter/page.dark.png +0 -0
- package/starters/calendar_starter/page.html +495 -0
- package/starters/calendar_starter/page.json +13 -0
- package/starters/calendar_starter/page.light.png +0 -0
- package/starters/chat_starter/chat-history.json +1 -0
- package/starters/chat_starter/page.dark.png +0 -0
- package/starters/chat_starter/page.html +351 -0
- package/starters/chat_starter/page.json +13 -0
- package/starters/chat_starter/page.light.png +0 -0
- package/starters/checklist_starter/chat-history.json +1 -0
- package/starters/checklist_starter/page.dark.png +0 -0
- package/starters/checklist_starter/page.html +437 -0
- package/starters/checklist_starter/page.json +13 -0
- package/starters/checklist_starter/page.light.png +0 -0
- package/starters/dashboard_starter/chat-history.json +1 -0
- package/starters/dashboard_starter/page.dark.png +0 -0
- package/starters/dashboard_starter/page.html +195 -0
- package/starters/dashboard_starter/page.json +13 -0
- package/starters/dashboard_starter/page.light.png +0 -0
- package/starters/form_starter/chat-history.json +1 -0
- package/starters/form_starter/page.dark.png +0 -0
- package/starters/form_starter/page.html +313 -0
- package/starters/form_starter/page.json +13 -0
- package/starters/form_starter/page.light.png +0 -0
- package/starters/gallery_starter/chat-history.json +1 -0
- package/starters/gallery_starter/page.dark.png +0 -0
- package/starters/gallery_starter/page.html +418 -0
- package/starters/gallery_starter/page.json +13 -0
- package/starters/gallery_starter/page.light.png +0 -0
- package/starters/generator_starter/chat-history.json +1 -0
- package/starters/generator_starter/page.dark.png +0 -0
- package/starters/generator_starter/page.html +261 -0
- package/starters/generator_starter/page.json +13 -0
- package/starters/generator_starter/page.light.png +0 -0
- package/starters/index.html +538 -0
- package/starters/kanban_starter/chat-history.json +1 -0
- package/starters/kanban_starter/page.dark.png +0 -0
- package/starters/kanban_starter/page.html +432 -0
- package/starters/kanban_starter/page.json +13 -0
- package/starters/kanban_starter/page.light.png +0 -0
- package/starters/presentation_builder/chat-history.json +1 -0
- package/starters/presentation_builder/page.dark.png +0 -0
- package/starters/presentation_builder/page.html +970 -0
- package/starters/presentation_builder/page.json +15 -0
- package/starters/presentation_builder/page.light.png +0 -0
- package/starters/presentation_builder/presentation_voice/voice_config.json +9 -0
- package/starters/pulse_starter/chat-history.json +1 -0
- package/starters/pulse_starter/page.dark.png +0 -0
- package/starters/pulse_starter/page.html +698 -0
- package/starters/pulse_starter/page.json +13 -0
- package/starters/pulse_starter/page.light.png +0 -0
- package/starters/quiz_starter/chat-history.json +1 -0
- package/starters/quiz_starter/page.dark.png +0 -0
- package/starters/quiz_starter/page.html +292 -0
- package/starters/quiz_starter/page.json +13 -0
- package/starters/quiz_starter/page.light.png +0 -0
- package/starters/reference_starter/chat-history.json +1 -0
- package/starters/reference_starter/page.dark.png +0 -0
- package/starters/reference_starter/page.html +250 -0
- package/starters/reference_starter/page.json +13 -0
- package/starters/reference_starter/page.light.png +0 -0
- package/starters/retro_game_starter/chat-history.json +1 -0
- package/starters/retro_game_starter/page.dark.png +0 -0
- package/{default-pages → starters}/retro_game_starter/page.html +1281 -1308
- package/starters/retro_game_starter/page.json +15 -0
- package/starters/retro_game_starter/page.light.png +0 -0
- package/starters/roster_starter/chat-history.json +1 -0
- package/starters/roster_starter/page.dark.png +0 -0
- package/starters/roster_starter/page.html +600 -0
- package/starters/roster_starter/page.json +13 -0
- package/starters/roster_starter/page.light.png +0 -0
- package/starters/server.js +182 -0
- package/starters/start.cmd +1 -0
- package/starters/timeline_starter/chat-history.json +1 -0
- package/starters/timeline_starter/page.dark.png +0 -0
- package/starters/timeline_starter/page.html +446 -0
- package/starters/timeline_starter/page.json +13 -0
- package/starters/timeline_starter/page.light.png +0 -0
- package/starters/tutorial_starter/chat-history.json +1 -0
- package/starters/tutorial_starter/page.dark.png +0 -0
- package/starters/tutorial_starter/page.html +283 -0
- package/starters/tutorial_starter/page.json +13 -0
- package/starters/tutorial_starter/page.light.png +0 -0
- package/static-files/agent.v3.js +122 -0
- package/static-files/connector.v3.js +48 -0
- package/static-files/extract.v3.js +188 -0
- package/static-files/helpers.v3.js +50 -6
- package/static-files/page-bridge.js +114 -0
- package/static-files/page.v3.js +1292 -1290
- package/static-files/script.v3.js +32 -0
- package/static-files/server.v3.js +89 -0
- package/static-files/shell-bridge.v3.js +174 -0
- package/static-files/shell-modals.v3.js +521 -0
- package/static-files/{shell.css → shell.v3.css} +271 -22
- package/static-files/shell.v3.js +1865 -0
- package/static-files/storage.v3.js +176 -0
- package/tests/anthropic.spec.ts +42 -7
- package/tests/builders.spec.ts +70 -2
- package/tests/pageValidator.spec.ts +548 -0
- package/tests/profiles.spec.ts +122 -0
- package/tests/sharedTableSchema.spec.ts +242 -0
- package/tests/transformPage.spec.ts +62 -81
- package/default-pages/application/page.json +0 -10
- package/default-pages/retro_game_starter/page.json +0 -12
- package/default-pages/sidebar_page/page.html +0 -51
- package/default-pages/sidebar_page/page.json +0 -10
- package/default-pages/two-panel_page/page.html +0 -68
- package/default-pages/two-panel_page/page.json +0 -10
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"><head>
|
|
2
|
+
<meta charset="UTF-8">
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4
|
+
<title>SynthOS - Starters Browser</title>
|
|
5
|
+
<script id="theme-info" src="/api/theme-info.js" data-locked="true"></script>
|
|
6
|
+
<link id="theme-css" rel="stylesheet" href="/api/theme.css" data-locked="true">
|
|
7
|
+
<style>
|
|
8
|
+
html, body, .viewer-panel { height: 100%; margin: 0; }
|
|
9
|
+
.starters-app {
|
|
10
|
+
height: 100%;
|
|
11
|
+
display: grid;
|
|
12
|
+
grid-template-columns: 260px 1fr;
|
|
13
|
+
grid-template-rows: 56px 1fr;
|
|
14
|
+
grid-template-areas:
|
|
15
|
+
"sidebar topbar"
|
|
16
|
+
"sidebar main";
|
|
17
|
+
background: var(--bodyBackground, #ffffff);
|
|
18
|
+
color: var(--bodyText, #1f1f1f);
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
}
|
|
21
|
+
.sidebar {
|
|
22
|
+
grid-area: sidebar;
|
|
23
|
+
background: var(--defaultStateBackground, #faf9f8);
|
|
24
|
+
border-right: 1px solid var(--bodyDivider, #edebe9);
|
|
25
|
+
overflow-y: auto;
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
}
|
|
29
|
+
.sidebar-header {
|
|
30
|
+
padding: 14px 16px;
|
|
31
|
+
border-bottom: 1px solid var(--bodyDivider, #edebe9);
|
|
32
|
+
font-size: 14px;
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
color: var(--bodyText, #1f1f1f);
|
|
35
|
+
}
|
|
36
|
+
.sidebar-list { list-style: none; padding: 8px 0; margin: 0; }
|
|
37
|
+
.sidebar-item {
|
|
38
|
+
list-style: none;
|
|
39
|
+
padding: 10px 16px;
|
|
40
|
+
font-size: 13px;
|
|
41
|
+
color: var(--bodyText, #1f1f1f);
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
border-left: 3px solid transparent;
|
|
44
|
+
user-select: none;
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-wrap: nowrap;
|
|
47
|
+
align-items: center;
|
|
48
|
+
}
|
|
49
|
+
.sidebar-item::marker { content: none; }
|
|
50
|
+
.sidebar-item:hover { background: var(--bodyBackgroundHovered, #f3f2f1); }
|
|
51
|
+
.sidebar-item.active {
|
|
52
|
+
background: var(--bodyBackgroundHovered, #f3f2f1);
|
|
53
|
+
border-left-color: var(--themePrimary, #0078d4);
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
}
|
|
56
|
+
.status-pair {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex: 0 0 auto;
|
|
59
|
+
flex-direction: row;
|
|
60
|
+
flex-wrap: nowrap;
|
|
61
|
+
gap: 3px;
|
|
62
|
+
margin-right: 10px;
|
|
63
|
+
}
|
|
64
|
+
.status {
|
|
65
|
+
flex: 0 0 auto;
|
|
66
|
+
display: inline-block;
|
|
67
|
+
width: 8px;
|
|
68
|
+
height: 8px;
|
|
69
|
+
border-radius: 50%;
|
|
70
|
+
background: var(--bodyDivider, #edebe9);
|
|
71
|
+
border: 1px solid var(--inputBorder, #8a8886);
|
|
72
|
+
}
|
|
73
|
+
.status.captured { background: #107c10; border-color: #107c10; }
|
|
74
|
+
.topbar {
|
|
75
|
+
grid-area: topbar;
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 10px;
|
|
79
|
+
padding: 0 16px;
|
|
80
|
+
border-bottom: 1px solid var(--bodyDivider, #edebe9);
|
|
81
|
+
background: var(--bodyStandoutBackground, #ffffff);
|
|
82
|
+
}
|
|
83
|
+
.topbar .title {
|
|
84
|
+
font-weight: 600;
|
|
85
|
+
font-size: 14px;
|
|
86
|
+
color: var(--bodyText, #1f1f1f);
|
|
87
|
+
margin-right: auto;
|
|
88
|
+
white-space: nowrap;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
text-overflow: ellipsis;
|
|
91
|
+
}
|
|
92
|
+
.topbar select, .topbar button {
|
|
93
|
+
font-family: inherit;
|
|
94
|
+
font-size: 12px;
|
|
95
|
+
padding: 6px 12px;
|
|
96
|
+
border: 1px solid var(--inputBorder, #8a8886);
|
|
97
|
+
border-radius: 4px;
|
|
98
|
+
background: var(--bodyBackground, #ffffff);
|
|
99
|
+
color: var(--bodyText, #1f1f1f);
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
}
|
|
102
|
+
.topbar button:hover {
|
|
103
|
+
background: var(--bodyBackgroundHovered, #f3f2f1);
|
|
104
|
+
}
|
|
105
|
+
.topbar button.primary {
|
|
106
|
+
background: var(--themePrimary, #0078d4);
|
|
107
|
+
color: #ffffff;
|
|
108
|
+
border-color: transparent;
|
|
109
|
+
}
|
|
110
|
+
.topbar button.primary:hover { filter: brightness(1.05); }
|
|
111
|
+
.topbar button:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
112
|
+
.frame-size-label {
|
|
113
|
+
font-size: 11px;
|
|
114
|
+
color: var(--bodySubtext, #605e5c);
|
|
115
|
+
}
|
|
116
|
+
.main {
|
|
117
|
+
grid-area: main;
|
|
118
|
+
background: var(--bodyBackground, #ffffff);
|
|
119
|
+
overflow: auto;
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: flex-start;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
padding: 24px;
|
|
124
|
+
}
|
|
125
|
+
.frame-wrap {
|
|
126
|
+
position: relative;
|
|
127
|
+
width: 1310px;
|
|
128
|
+
height: 880px;
|
|
129
|
+
min-width: 1310px;
|
|
130
|
+
min-height: 880px;
|
|
131
|
+
background: #ffffff;
|
|
132
|
+
flex: 0 0 auto;
|
|
133
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
|
|
134
|
+
}
|
|
135
|
+
.frame-wrap iframe {
|
|
136
|
+
width: 100%;
|
|
137
|
+
height: 100%;
|
|
138
|
+
border: 0;
|
|
139
|
+
background: #ffffff;
|
|
140
|
+
}
|
|
141
|
+
.empty-state {
|
|
142
|
+
font-size: 14px;
|
|
143
|
+
color: var(--bodySubtext, #605e5c);
|
|
144
|
+
}
|
|
145
|
+
.toast {
|
|
146
|
+
position: fixed;
|
|
147
|
+
bottom: 24px;
|
|
148
|
+
left: 50%;
|
|
149
|
+
transform: translateX(-50%);
|
|
150
|
+
background: var(--bodyText, #1f1f1f);
|
|
151
|
+
color: var(--bodyBackground, #ffffff);
|
|
152
|
+
padding: 10px 18px;
|
|
153
|
+
border-radius: 4px;
|
|
154
|
+
font-size: 13px;
|
|
155
|
+
opacity: 0;
|
|
156
|
+
transition: opacity 0.2s;
|
|
157
|
+
pointer-events: none;
|
|
158
|
+
z-index: 1000;
|
|
159
|
+
max-width: 80%;
|
|
160
|
+
}
|
|
161
|
+
.toast.show { opacity: 1; }
|
|
162
|
+
.toast.error { background: #a4262c; }
|
|
163
|
+
</style>
|
|
164
|
+
<script id="page-info" src="/api/page-info.js?page=_starters"></script>
|
|
165
|
+
</head>
|
|
166
|
+
<body>
|
|
167
|
+
<div class="viewer-panel" id="viewerPanel" style="padding: 0;">
|
|
168
|
+
<div class="starters-app">
|
|
169
|
+
<aside class="sidebar">
|
|
170
|
+
<div class="sidebar-header">Starters</div>
|
|
171
|
+
<ul class="sidebar-list" id="sidebarList">
|
|
172
|
+
<li class="sidebar-item" style="cursor: default; color: var(--bodySubtext, #605e5c);">Loading…</li>
|
|
173
|
+
</ul>
|
|
174
|
+
</aside>
|
|
175
|
+
|
|
176
|
+
<header class="topbar">
|
|
177
|
+
<div class="title" id="currentTitle">Pick a starter from the sidebar</div>
|
|
178
|
+
<span class="frame-size-label">Frame:</span>
|
|
179
|
+
<select id="frameSize" title="Frame dimensions approximate the shell viewer panel with the page editor open (toolbar 48px + chat panel 30% of remaining width)">
|
|
180
|
+
<option value="1310x880">1310 × 880 (shell @ 1920, editor open)</option>
|
|
181
|
+
<option value="1760x1180">1760 × 1180 (shell @ 2560, editor open)</option>
|
|
182
|
+
<option value="980x680">980 × 680 (shell @ 1440, editor open)</option>
|
|
183
|
+
<option value="1280x800">1280 × 800</option>
|
|
184
|
+
<option value="1440x900">1440 × 900</option>
|
|
185
|
+
<option value="375x667">375 × 667 (mobile)</option>
|
|
186
|
+
</select>
|
|
187
|
+
<select id="themeSelect" title="Switching theme here updates the global Synthos setting and reloads the preview"></select>
|
|
188
|
+
<button id="captureBtn" class="primary" disabled title="Save as page.light.png or page.dark.png in the starter's folder, based on the current theme">Capture page.light.png</button>
|
|
189
|
+
<button id="captureAllBtn" disabled title="Capture every starter at the current theme. Run twice (once with a light theme, once with a dark theme) to fill in both page.light.png and page.dark.png.">Capture all (light)</button>
|
|
190
|
+
</header>
|
|
191
|
+
|
|
192
|
+
<main class="main">
|
|
193
|
+
<div class="frame-wrap" id="frameWrap" style="display: none;">
|
|
194
|
+
<iframe id="previewFrame" sandbox="allow-same-origin allow-scripts allow-forms" title="Starter Preview"></iframe>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="empty-state" id="emptyState">Select a starter to preview.</div>
|
|
197
|
+
</main>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div class="toast" id="toast"></div>
|
|
202
|
+
|
|
203
|
+
<div id="instructions" style="display: none;" data-locked="true"></div>
|
|
204
|
+
<div id="thoughts" style="display: none;" data-locked="true"></div>
|
|
205
|
+
|
|
206
|
+
<script>
|
|
207
|
+
(function() {
|
|
208
|
+
'use strict';
|
|
209
|
+
|
|
210
|
+
// ── DOM refs ──
|
|
211
|
+
var sidebarList = document.getElementById('sidebarList');
|
|
212
|
+
var previewFrame = document.getElementById('previewFrame');
|
|
213
|
+
var frameWrap = document.getElementById('frameWrap');
|
|
214
|
+
var emptyState = document.getElementById('emptyState');
|
|
215
|
+
var currentTitle = document.getElementById('currentTitle');
|
|
216
|
+
var captureBtn = document.getElementById('captureBtn');
|
|
217
|
+
var captureAllBtn = document.getElementById('captureAllBtn');
|
|
218
|
+
var frameSize = document.getElementById('frameSize');
|
|
219
|
+
var themeSelect = document.getElementById('themeSelect');
|
|
220
|
+
var toastEl = document.getElementById('toast');
|
|
221
|
+
|
|
222
|
+
// ── State ──
|
|
223
|
+
var starters = []; // [{name, title, ...}]
|
|
224
|
+
var activeStarter = null; // page name
|
|
225
|
+
var captureStatus = {}; // { name: { light: true, dark: true } }
|
|
226
|
+
|
|
227
|
+
// ── Helpers ──
|
|
228
|
+
|
|
229
|
+
function themeVariant(name) {
|
|
230
|
+
if (!name) return 'light';
|
|
231
|
+
if (name.indexOf('dawn') !== -1 || name === 'high-contrast-light' || name.indexOf('-light') !== -1) return 'light';
|
|
232
|
+
if (name.indexOf('dusk') !== -1 || name === 'high-contrast-dark' || name.indexOf('-dark') !== -1) return 'dark';
|
|
233
|
+
return 'light';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function toast(msg, isError) {
|
|
237
|
+
toastEl.textContent = msg;
|
|
238
|
+
toastEl.classList.toggle('error', !!isError);
|
|
239
|
+
toastEl.classList.add('show');
|
|
240
|
+
clearTimeout(toast._t);
|
|
241
|
+
toast._t = setTimeout(function() { toastEl.classList.remove('show'); }, 2400);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function displayName(p) { return p.title || p.name; }
|
|
245
|
+
|
|
246
|
+
// ── Sidebar ──
|
|
247
|
+
|
|
248
|
+
function renderSidebar() {
|
|
249
|
+
sidebarList.innerHTML = '';
|
|
250
|
+
if (starters.length === 0) {
|
|
251
|
+
var empty = document.createElement('li');
|
|
252
|
+
empty.className = 'sidebar-item';
|
|
253
|
+
empty.style.cursor = 'default';
|
|
254
|
+
empty.style.color = 'var(--bodySubtext, #605e5c)';
|
|
255
|
+
empty.textContent = 'No starter pages found';
|
|
256
|
+
sidebarList.appendChild(empty);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
starters.forEach(function(p) {
|
|
260
|
+
var li = document.createElement('li');
|
|
261
|
+
li.className = 'sidebar-item';
|
|
262
|
+
li.dataset.starter = p.name;
|
|
263
|
+
var status = captureStatus[p.name] || {};
|
|
264
|
+
var lightCls = status.light ? ' captured' : '';
|
|
265
|
+
var darkCls = status.dark ? ' captured' : '';
|
|
266
|
+
var pair = document.createElement('span');
|
|
267
|
+
pair.className = 'status-pair';
|
|
268
|
+
pair.title = 'left = page.light.png, right = page.dark.png';
|
|
269
|
+
pair.innerHTML = '<span class="status' + lightCls + '"></span><span class="status' + darkCls + '"></span>';
|
|
270
|
+
var label = document.createElement('span');
|
|
271
|
+
label.textContent = displayName(p);
|
|
272
|
+
li.appendChild(pair);
|
|
273
|
+
li.appendChild(label);
|
|
274
|
+
if (p.name === activeStarter) li.classList.add('active');
|
|
275
|
+
li.addEventListener('click', function() { loadStarter(p.name); });
|
|
276
|
+
sidebarList.appendChild(li);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function applyFrameSize() {
|
|
281
|
+
var parts = frameSize.value.split('x').map(Number);
|
|
282
|
+
frameWrap.style.width = parts[0] + 'px';
|
|
283
|
+
frameWrap.style.height = parts[1] + 'px';
|
|
284
|
+
frameWrap.style.minWidth = parts[0] + 'px';
|
|
285
|
+
frameWrap.style.minHeight = parts[1] + 'px';
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function frameDimensions() {
|
|
289
|
+
var parts = frameSize.value.split('x').map(Number);
|
|
290
|
+
return { w: parts[0], h: parts[1] };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function loadStarter(name) {
|
|
294
|
+
activeStarter = name;
|
|
295
|
+
var meta = starters.find(function(p) { return p.name === name; });
|
|
296
|
+
currentTitle.textContent = meta ? displayName(meta) : name;
|
|
297
|
+
emptyState.style.display = 'none';
|
|
298
|
+
frameWrap.style.display = 'block';
|
|
299
|
+
applyFrameSize();
|
|
300
|
+
// ?frame=1 returns the bare iframe content (theme + helpers injected by the server).
|
|
301
|
+
previewFrame.src = '/' + encodeURIComponent(name) + '?frame=1&t=' + Date.now();
|
|
302
|
+
captureBtn.disabled = false;
|
|
303
|
+
renderSidebar();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Inject html2canvas into the iframe so capture runs in the page's own
|
|
307
|
+
// window context. Capturing from the harness produced subtle horizontal
|
|
308
|
+
// misalignment because html2canvas was reading computed styles through
|
|
309
|
+
// the parent window — this keeps the library's `window` aligned with the
|
|
310
|
+
// page's actual layout viewport.
|
|
311
|
+
function injectCaptureLib() {
|
|
312
|
+
var doc, win;
|
|
313
|
+
try {
|
|
314
|
+
doc = previewFrame.contentDocument;
|
|
315
|
+
win = previewFrame.contentWindow;
|
|
316
|
+
} catch (e) { return; }
|
|
317
|
+
if (!doc || !win || win.html2canvas) return;
|
|
318
|
+
var s = doc.createElement('script');
|
|
319
|
+
s.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js';
|
|
320
|
+
doc.head.appendChild(s);
|
|
321
|
+
}
|
|
322
|
+
previewFrame.addEventListener('load', injectCaptureLib);
|
|
323
|
+
|
|
324
|
+
async function waitForFrameCaptureLib(timeoutMs) {
|
|
325
|
+
var win;
|
|
326
|
+
try { win = previewFrame.contentWindow; } catch (e) { return false; }
|
|
327
|
+
if (!win) return false;
|
|
328
|
+
var waited = 0;
|
|
329
|
+
while (!win.html2canvas && waited < timeoutMs) {
|
|
330
|
+
await new Promise(function(r) { setTimeout(r, 100); });
|
|
331
|
+
waited += 100;
|
|
332
|
+
}
|
|
333
|
+
return !!win.html2canvas;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ── Theme switching ──
|
|
337
|
+
// POST /api/settings updates the global theme. The shell + this page were
|
|
338
|
+
// already rendered with the previous theme, so only the inner preview iframe
|
|
339
|
+
// re-fetches /api/theme.css under the new setting. That is intentional —
|
|
340
|
+
// we want isolated theme switching for capture without rebuilding the harness.
|
|
341
|
+
|
|
342
|
+
async function setServerTheme(theme) {
|
|
343
|
+
var res = await fetch('/api/settings', {
|
|
344
|
+
method: 'POST',
|
|
345
|
+
headers: { 'Content-Type': 'application/json' },
|
|
346
|
+
body: JSON.stringify({ theme: theme }),
|
|
347
|
+
redirect: 'manual'
|
|
348
|
+
});
|
|
349
|
+
// express does res.redirect → opaqueredirect under manual; both 0 and 200 are OK here
|
|
350
|
+
if (res.type !== 'opaqueredirect' && !res.ok) {
|
|
351
|
+
throw new Error('Settings save failed: ' + res.status);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async function loadThemes() {
|
|
356
|
+
var names;
|
|
357
|
+
try {
|
|
358
|
+
var res = await fetch('/api/themes');
|
|
359
|
+
if (!res.ok) throw new Error('themes failed (' + res.status + ')');
|
|
360
|
+
names = await res.json();
|
|
361
|
+
if (!Array.isArray(names)) throw new Error('themes payload not an array');
|
|
362
|
+
} catch (err) {
|
|
363
|
+
console.error('Failed to load themes:', err);
|
|
364
|
+
names = ['nebula-dawn','nebula-dusk','aurora-dawn','aurora-dusk','cosmos-dawn','cosmos-dusk','solar-flare-dawn','solar-flare-dusk','high-contrast-light','high-contrast-dark'];
|
|
365
|
+
}
|
|
366
|
+
themeSelect.innerHTML = '';
|
|
367
|
+
names.forEach(function(name) {
|
|
368
|
+
var opt = document.createElement('option');
|
|
369
|
+
opt.value = name;
|
|
370
|
+
opt.textContent = name;
|
|
371
|
+
themeSelect.appendChild(opt);
|
|
372
|
+
});
|
|
373
|
+
// Preselect the active theme reported by /api/theme-info.js
|
|
374
|
+
if (window.themeInfo && window.themeInfo.name) {
|
|
375
|
+
themeSelect.value = window.themeInfo.name;
|
|
376
|
+
}
|
|
377
|
+
updateCaptureButtonLabels();
|
|
378
|
+
updateCaptureAllState();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ── Capture ──
|
|
382
|
+
|
|
383
|
+
async function captureCurrent() {
|
|
384
|
+
if (!activeStarter) return;
|
|
385
|
+
var doc = previewFrame.contentDocument;
|
|
386
|
+
var win = previewFrame.contentWindow;
|
|
387
|
+
if (!doc || !doc.body || !win) {
|
|
388
|
+
toast('Iframe not ready', true);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
var variant = themeVariant(themeSelect.value);
|
|
392
|
+
var filename = 'page.' + variant + '.png';
|
|
393
|
+
captureBtn.disabled = true;
|
|
394
|
+
try {
|
|
395
|
+
// Wait for html2canvas to load INSIDE the iframe. Running the library
|
|
396
|
+
// in the page's own window means it sees the layout the page sees —
|
|
397
|
+
// no parent-frame measurement skew.
|
|
398
|
+
var ready = await waitForFrameCaptureLib(8000);
|
|
399
|
+
if (!ready) throw new Error('Capture library failed to load in page');
|
|
400
|
+
await new Promise(function(r) { setTimeout(r, 150); });
|
|
401
|
+
var dims = frameDimensions();
|
|
402
|
+
var de = doc.documentElement;
|
|
403
|
+
var contentH = Math.max(dims.h, de.scrollHeight, doc.body.scrollHeight);
|
|
404
|
+
var canvas = await win.html2canvas(de, {
|
|
405
|
+
width: dims.w,
|
|
406
|
+
height: contentH,
|
|
407
|
+
windowWidth: dims.w,
|
|
408
|
+
windowHeight: dims.h,
|
|
409
|
+
backgroundColor: '#ffffff',
|
|
410
|
+
useCORS: true,
|
|
411
|
+
allowTaint: false,
|
|
412
|
+
logging: false,
|
|
413
|
+
scale: 1
|
|
414
|
+
});
|
|
415
|
+
var blob = await new Promise(function(resolve) { canvas.toBlob(resolve, 'image/png'); });
|
|
416
|
+
if (!blob) throw new Error('Could not encode PNG');
|
|
417
|
+
await savePng(activeStarter, filename, blob);
|
|
418
|
+
captureStatus[activeStarter] = captureStatus[activeStarter] || {};
|
|
419
|
+
captureStatus[activeStarter][variant] = true;
|
|
420
|
+
renderSidebar();
|
|
421
|
+
} catch (err) {
|
|
422
|
+
console.error(err);
|
|
423
|
+
toast('Capture failed: ' + err.message, true);
|
|
424
|
+
} finally {
|
|
425
|
+
captureBtn.disabled = false;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async function savePng(starter, filename, blob) {
|
|
430
|
+
// filename is "page.light.png" or "page.dark.png" — derive variant from it
|
|
431
|
+
var variant = filename === 'page.dark.png' ? 'dark' : 'light';
|
|
432
|
+
var url = '/api/starters/' + encodeURIComponent(starter) + '/screenshot/' + variant;
|
|
433
|
+
var res = await fetch(url, {
|
|
434
|
+
method: 'POST',
|
|
435
|
+
headers: { 'Content-Type': 'image/png' },
|
|
436
|
+
body: blob
|
|
437
|
+
});
|
|
438
|
+
if (!res.ok) {
|
|
439
|
+
var msg = 'HTTP ' + res.status;
|
|
440
|
+
try { var body = await res.json(); if (body && body.error) msg = body.error; } catch (e) {}
|
|
441
|
+
throw new Error(msg);
|
|
442
|
+
}
|
|
443
|
+
var data = {};
|
|
444
|
+
try { data = await res.json(); } catch (e) {}
|
|
445
|
+
var n = (data.paths && data.paths.length) || 0;
|
|
446
|
+
toast('Saved ' + starter + '/' + filename + (n > 1 ? ' (×' + n + ')' : ''));
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
async function captureAll() {
|
|
450
|
+
captureAllBtn.disabled = true;
|
|
451
|
+
captureBtn.disabled = true;
|
|
452
|
+
try {
|
|
453
|
+
for (var i = 0; i < starters.length; i++) {
|
|
454
|
+
var name = starters[i].name;
|
|
455
|
+
loadStarter(name);
|
|
456
|
+
await new Promise(function(resolve) {
|
|
457
|
+
var onLoad = function() {
|
|
458
|
+
previewFrame.removeEventListener('load', onLoad);
|
|
459
|
+
setTimeout(resolve, 800);
|
|
460
|
+
};
|
|
461
|
+
previewFrame.addEventListener('load', onLoad);
|
|
462
|
+
});
|
|
463
|
+
await captureCurrent();
|
|
464
|
+
}
|
|
465
|
+
toast('All starters captured');
|
|
466
|
+
} finally {
|
|
467
|
+
captureAllBtn.disabled = false;
|
|
468
|
+
captureBtn.disabled = !activeStarter;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function updateCaptureButtonLabels() {
|
|
473
|
+
var variant = themeVariant(themeSelect.value);
|
|
474
|
+
captureBtn.textContent = 'Capture page.' + variant + '.png';
|
|
475
|
+
captureAllBtn.textContent = 'Capture all (' + variant + ')';
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function updateCaptureAllState() {
|
|
479
|
+
captureAllBtn.disabled = starters.length === 0;
|
|
480
|
+
captureAllBtn.title = 'Capture and save page.' + themeVariant(themeSelect.value) + '.png for every starter';
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// ── Page list ──
|
|
484
|
+
|
|
485
|
+
async function loadStarters() {
|
|
486
|
+
try {
|
|
487
|
+
var res = await fetch('/api/pages');
|
|
488
|
+
if (!res.ok) throw new Error('pages failed');
|
|
489
|
+
var allPages = await res.json();
|
|
490
|
+
starters = allPages
|
|
491
|
+
.filter(function(p) {
|
|
492
|
+
return Array.isArray(p.categories) && p.categories.indexOf('_Starters') !== -1;
|
|
493
|
+
})
|
|
494
|
+
.sort(function(a, b) { return displayName(a).localeCompare(displayName(b)); });
|
|
495
|
+
renderSidebar();
|
|
496
|
+
updateCaptureAllState();
|
|
497
|
+
} catch (err) {
|
|
498
|
+
console.error('Failed to load pages:', err);
|
|
499
|
+
toast('Failed to load starters: ' + err.message, true);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ── Wire up ──
|
|
504
|
+
|
|
505
|
+
captureBtn.addEventListener('click', captureCurrent);
|
|
506
|
+
captureAllBtn.addEventListener('click', captureAll);
|
|
507
|
+
|
|
508
|
+
frameSize.addEventListener('change', function() {
|
|
509
|
+
applyFrameSize();
|
|
510
|
+
if (activeStarter) loadStarter(activeStarter);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
themeSelect.addEventListener('change', async function() {
|
|
514
|
+
var theme = themeSelect.value;
|
|
515
|
+
try {
|
|
516
|
+
await setServerTheme(theme);
|
|
517
|
+
} catch (err) {
|
|
518
|
+
toast('Theme switch failed: ' + err.message, true);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
updateCaptureButtonLabels();
|
|
522
|
+
updateCaptureAllState();
|
|
523
|
+
// Reload only the preview iframe — the new theme takes effect on next /<page>?frame=1 fetch
|
|
524
|
+
if (activeStarter) loadStarter(activeStarter);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
applyFrameSize();
|
|
528
|
+
updateCaptureButtonLabels();
|
|
529
|
+
updateCaptureAllState();
|
|
530
|
+
loadThemes();
|
|
531
|
+
loadStarters();
|
|
532
|
+
})();
|
|
533
|
+
</script>
|
|
534
|
+
</body></html>
|