synthos 0.10.1 → 0.11.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 +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 +288 -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 +1385 -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 +1879 -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 +282 -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 +1411 -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,538 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Synthos — Starters Browser</title>
|
|
7
|
+
<link rel="stylesheet" href="/static-files/fluentlm.min.css">
|
|
8
|
+
<link rel="stylesheet" href="/api/theme.css" id="harness-theme-css">
|
|
9
|
+
<script src="/api/theme-info.js"></script>
|
|
10
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
11
|
+
<style>
|
|
12
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
13
|
+
html, body { margin: 0; padding: 0; height: 100%; width: 100%; }
|
|
14
|
+
body {
|
|
15
|
+
font-family: var(--fontFamily, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
|
|
16
|
+
background: var(--bodyBackground, #ffffff);
|
|
17
|
+
color: var(--bodyText, #1f1f1f);
|
|
18
|
+
display: grid;
|
|
19
|
+
grid-template-columns: 240px 1fr;
|
|
20
|
+
grid-template-rows: 56px 1fr;
|
|
21
|
+
grid-template-areas:
|
|
22
|
+
"sidebar topbar"
|
|
23
|
+
"sidebar main";
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
.sidebar {
|
|
27
|
+
grid-area: sidebar;
|
|
28
|
+
background: var(--defaultStateBackground, #faf9f8);
|
|
29
|
+
border-right: 1px solid var(--bodyDivider, #edebe9);
|
|
30
|
+
overflow-y: auto;
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
}
|
|
34
|
+
.sidebar-header {
|
|
35
|
+
padding: 16px;
|
|
36
|
+
border-bottom: 1px solid var(--bodyDivider, #edebe9);
|
|
37
|
+
font-size: 14px;
|
|
38
|
+
font-weight: 600;
|
|
39
|
+
color: var(--bodyText, #1f1f1f);
|
|
40
|
+
background: var(--bodyStandoutBackground, #ffffff);
|
|
41
|
+
}
|
|
42
|
+
.sidebar-list { list-style: none; padding: 8px 0; margin: 0; }
|
|
43
|
+
.sidebar-item {
|
|
44
|
+
padding: 10px 16px;
|
|
45
|
+
font-size: 13px;
|
|
46
|
+
color: var(--bodyText, #1f1f1f);
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
border-left: 3px solid transparent;
|
|
49
|
+
user-select: none;
|
|
50
|
+
}
|
|
51
|
+
.sidebar-item:hover { background: var(--bodyBackgroundHovered, #f3f2f1); }
|
|
52
|
+
.sidebar-item.active {
|
|
53
|
+
background: var(--bodyBackgroundHovered, #f3f2f1);
|
|
54
|
+
border-left-color: var(--themePrimary, #0078d4);
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
}
|
|
57
|
+
.sidebar-item .status-pair {
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
gap: 3px;
|
|
60
|
+
margin-right: 8px;
|
|
61
|
+
vertical-align: middle;
|
|
62
|
+
}
|
|
63
|
+
.sidebar-item .status {
|
|
64
|
+
display: inline-block;
|
|
65
|
+
width: 8px;
|
|
66
|
+
height: 8px;
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
background: var(--bodyDivider, #edebe9);
|
|
69
|
+
border: 1px solid var(--inputBorder, #8a8886);
|
|
70
|
+
}
|
|
71
|
+
.sidebar-item .status.captured {
|
|
72
|
+
background: #107c10;
|
|
73
|
+
border-color: #107c10;
|
|
74
|
+
}
|
|
75
|
+
.topbar {
|
|
76
|
+
grid-area: topbar;
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
gap: 12px;
|
|
80
|
+
padding: 0 16px;
|
|
81
|
+
border-bottom: 1px solid var(--bodyDivider, #edebe9);
|
|
82
|
+
background: var(--bodyStandoutBackground, #ffffff);
|
|
83
|
+
}
|
|
84
|
+
.topbar .title {
|
|
85
|
+
font-weight: 600;
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
color: var(--bodyText, #1f1f1f);
|
|
88
|
+
margin-right: auto;
|
|
89
|
+
}
|
|
90
|
+
.topbar select, .topbar button {
|
|
91
|
+
font-family: inherit;
|
|
92
|
+
font-size: 12px;
|
|
93
|
+
padding: 6px 12px;
|
|
94
|
+
border: 1px solid var(--inputBorder, #8a8886);
|
|
95
|
+
border-radius: 4px;
|
|
96
|
+
background: var(--bodyBackground, #ffffff);
|
|
97
|
+
color: var(--bodyText, #1f1f1f);
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
}
|
|
100
|
+
.topbar button:hover {
|
|
101
|
+
background: var(--bodyBackgroundHovered, #f3f2f1);
|
|
102
|
+
}
|
|
103
|
+
.topbar button.primary {
|
|
104
|
+
background: var(--themePrimary, #0078d4);
|
|
105
|
+
color: #ffffff;
|
|
106
|
+
border-color: transparent;
|
|
107
|
+
}
|
|
108
|
+
.topbar button.primary:hover {
|
|
109
|
+
background: var(--themeDark, #005a9e);
|
|
110
|
+
}
|
|
111
|
+
.topbar button:disabled {
|
|
112
|
+
opacity: 0.5;
|
|
113
|
+
cursor: not-allowed;
|
|
114
|
+
}
|
|
115
|
+
.main {
|
|
116
|
+
grid-area: main;
|
|
117
|
+
background: var(--bodyBackground, #ffffff);
|
|
118
|
+
overflow: auto;
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: flex-start;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
padding: 24px;
|
|
123
|
+
}
|
|
124
|
+
.frame-wrap {
|
|
125
|
+
position: relative;
|
|
126
|
+
width: 1310px;
|
|
127
|
+
height: 880px;
|
|
128
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
|
|
129
|
+
background: #ffffff;
|
|
130
|
+
flex-shrink: 0;
|
|
131
|
+
}
|
|
132
|
+
.frame-wrap iframe {
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
border: 0;
|
|
136
|
+
background: #ffffff;
|
|
137
|
+
}
|
|
138
|
+
.empty-state {
|
|
139
|
+
font-size: 14px;
|
|
140
|
+
color: var(--bodySubtext, #605e5c);
|
|
141
|
+
}
|
|
142
|
+
.toast {
|
|
143
|
+
position: fixed;
|
|
144
|
+
bottom: 24px;
|
|
145
|
+
left: 50%;
|
|
146
|
+
transform: translateX(-50%);
|
|
147
|
+
background: var(--bodyText, #1f1f1f);
|
|
148
|
+
color: var(--bodyBackground, #ffffff);
|
|
149
|
+
padding: 10px 18px;
|
|
150
|
+
border-radius: 4px;
|
|
151
|
+
font-size: 13px;
|
|
152
|
+
opacity: 0;
|
|
153
|
+
transition: opacity 0.2s;
|
|
154
|
+
pointer-events: none;
|
|
155
|
+
z-index: 1000;
|
|
156
|
+
max-width: 80%;
|
|
157
|
+
}
|
|
158
|
+
.toast.show { opacity: 1; }
|
|
159
|
+
.toast.error { background: #a4262c; }
|
|
160
|
+
.frame-size-label {
|
|
161
|
+
font-size: 11px;
|
|
162
|
+
color: var(--bodySubtext, #605e5c);
|
|
163
|
+
margin-right: 8px;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
166
|
+
</head>
|
|
167
|
+
<body>
|
|
168
|
+
<aside class="sidebar">
|
|
169
|
+
<div class="sidebar-header">Starters</div>
|
|
170
|
+
<ul class="sidebar-list" id="sidebarList"></ul>
|
|
171
|
+
</aside>
|
|
172
|
+
|
|
173
|
+
<header class="topbar">
|
|
174
|
+
<div class="title" id="currentTitle">Pick a starter from the sidebar</div>
|
|
175
|
+
<span class="frame-size-label">Frame:</span>
|
|
176
|
+
<select id="frameSize" title="Frame dimensions approximate the shell viewer panel with the page editor open (toolbar 48px + chat panel 30% of remaining width)">
|
|
177
|
+
<option value="1310x880">1310 × 880 (shell @ 1920, editor open)</option>
|
|
178
|
+
<option value="1760x1180">1760 × 1180 (shell @ 2560, editor open)</option>
|
|
179
|
+
<option value="980x680">980 × 680 (shell @ 1440, editor open)</option>
|
|
180
|
+
<option value="1280x800">1280 × 800</option>
|
|
181
|
+
<option value="1440x900">1440 × 900</option>
|
|
182
|
+
<option value="375x667">375 × 667 (mobile)</option>
|
|
183
|
+
</select>
|
|
184
|
+
<select id="themeSelect">
|
|
185
|
+
<option value="nebula-dawn">Nebula Dawn</option>
|
|
186
|
+
<option value="nebula-dusk">Nebula Dusk</option>
|
|
187
|
+
<option value="aurora-dawn">Aurora Dawn</option>
|
|
188
|
+
<option value="aurora-dusk">Aurora Dusk</option>
|
|
189
|
+
<option value="cosmos-dawn">Cosmos Dawn</option>
|
|
190
|
+
<option value="cosmos-dusk">Cosmos Dusk</option>
|
|
191
|
+
<option value="solar-flare-dawn">Solar Flare Dawn</option>
|
|
192
|
+
<option value="solar-flare-dusk">Solar Flare Dusk</option>
|
|
193
|
+
<option value="high-contrast-light">High Contrast Light</option>
|
|
194
|
+
<option value="high-contrast-dark">High Contrast Dark</option>
|
|
195
|
+
</select>
|
|
196
|
+
<button id="setFolderBtn" title="Pick the starters folder so screenshots save directly into each starter's subfolder">Set save folder…</button>
|
|
197
|
+
<button id="captureBtn" class="primary" disabled title="Save as page.light.png or page.dark.png based on the current theme">Capture page.light.png</button>
|
|
198
|
+
<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>
|
|
199
|
+
</header>
|
|
200
|
+
|
|
201
|
+
<main class="main">
|
|
202
|
+
<div class="frame-wrap" id="frameWrap" style="display: none;">
|
|
203
|
+
<iframe id="previewFrame" sandbox="allow-same-origin allow-scripts allow-forms"></iframe>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="empty-state" id="emptyState">Select a starter to preview.</div>
|
|
206
|
+
</main>
|
|
207
|
+
|
|
208
|
+
<div class="toast" id="toast"></div>
|
|
209
|
+
|
|
210
|
+
<script>
|
|
211
|
+
const STARTERS = [
|
|
212
|
+
'dashboard_starter',
|
|
213
|
+
'generator_starter',
|
|
214
|
+
'reference_starter',
|
|
215
|
+
'roster_starter',
|
|
216
|
+
'form_starter',
|
|
217
|
+
'calendar_starter',
|
|
218
|
+
'kanban_starter',
|
|
219
|
+
'calculator_starter',
|
|
220
|
+
'quiz_starter',
|
|
221
|
+
'tutorial_starter',
|
|
222
|
+
'presentation_builder',
|
|
223
|
+
'retro_game_starter'
|
|
224
|
+
];
|
|
225
|
+
|
|
226
|
+
const sidebarList = document.getElementById('sidebarList');
|
|
227
|
+
const previewFrame = document.getElementById('previewFrame');
|
|
228
|
+
const frameWrap = document.getElementById('frameWrap');
|
|
229
|
+
const emptyState = document.getElementById('emptyState');
|
|
230
|
+
const currentTitle = document.getElementById('currentTitle');
|
|
231
|
+
const captureBtn = document.getElementById('captureBtn');
|
|
232
|
+
const captureAllBtn = document.getElementById('captureAllBtn');
|
|
233
|
+
const setFolderBtn = document.getElementById('setFolderBtn');
|
|
234
|
+
const frameSize = document.getElementById('frameSize');
|
|
235
|
+
const themeSelect = document.getElementById('themeSelect');
|
|
236
|
+
const harnessThemeCss = document.getElementById('harness-theme-css');
|
|
237
|
+
const toastEl = document.getElementById('toast');
|
|
238
|
+
|
|
239
|
+
let activeStarter = null;
|
|
240
|
+
let savedDirHandle = null;
|
|
241
|
+
const captureStatus = {};
|
|
242
|
+
|
|
243
|
+
// Sync the dropdown to whatever the server returned via /api/theme-info.js.
|
|
244
|
+
// window.themeInfo.name is set by the script tag in <head>.
|
|
245
|
+
if (window.themeInfo && window.themeInfo.name) {
|
|
246
|
+
const opt = Array.from(themeSelect.options).find(o => o.value === window.themeInfo.name);
|
|
247
|
+
if (opt) themeSelect.value = window.themeInfo.name;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function themeVariant(name) {
|
|
251
|
+
if (name.includes('dawn') || name === 'high-contrast-light') return 'light';
|
|
252
|
+
if (name.includes('dusk') || name === 'high-contrast-dark') return 'dark';
|
|
253
|
+
return 'light';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function toast(msg, isError) {
|
|
257
|
+
toastEl.textContent = msg;
|
|
258
|
+
toastEl.classList.toggle('error', !!isError);
|
|
259
|
+
toastEl.classList.add('show');
|
|
260
|
+
clearTimeout(toast._t);
|
|
261
|
+
toast._t = setTimeout(() => toastEl.classList.remove('show'), 2400);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function renderSidebar() {
|
|
265
|
+
sidebarList.innerHTML = '';
|
|
266
|
+
STARTERS.forEach(name => {
|
|
267
|
+
const li = document.createElement('li');
|
|
268
|
+
li.className = 'sidebar-item';
|
|
269
|
+
li.dataset.starter = name;
|
|
270
|
+
const status = captureStatus[name] || {};
|
|
271
|
+
const lightCls = status.light ? ' captured' : '';
|
|
272
|
+
const darkCls = status.dark ? ' captured' : '';
|
|
273
|
+
li.innerHTML = `<span class="status-pair" title="left = page.light.png, right = page.dark.png"><span class="status${lightCls}"></span><span class="status${darkCls}"></span></span>${name}`;
|
|
274
|
+
if (name === activeStarter) li.classList.add('active');
|
|
275
|
+
li.addEventListener('click', () => loadStarter(name));
|
|
276
|
+
sidebarList.appendChild(li);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function applyFrameSize() {
|
|
281
|
+
const [w, h] = frameSize.value.split('x').map(Number);
|
|
282
|
+
frameWrap.style.width = w + 'px';
|
|
283
|
+
frameWrap.style.height = h + 'px';
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// POST the picked theme to the server so it sets the cookie that
|
|
287
|
+
// /api/theme.css and /api/theme-info.js read on every subsequent
|
|
288
|
+
// request. Returns once the cookie is set so callers can safely
|
|
289
|
+
// refresh dependent resources.
|
|
290
|
+
async function setServerTheme(theme) {
|
|
291
|
+
const r = await fetch('/api/set-theme', {
|
|
292
|
+
method: 'POST',
|
|
293
|
+
headers: { 'Content-Type': 'application/json' },
|
|
294
|
+
body: JSON.stringify({ theme })
|
|
295
|
+
});
|
|
296
|
+
if (!r.ok) throw new Error('set-theme failed: ' + r.status);
|
|
297
|
+
return r.json();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Re-fetch the harness's own theme CSS and re-run the theme-info script
|
|
301
|
+
// so its <html> classes update. The server emits the matching mode-class
|
|
302
|
+
// and (for v3) the theme-name class via /api/theme-info.js.
|
|
303
|
+
function refreshHarnessTheme() {
|
|
304
|
+
const cb = '?t=' + Date.now();
|
|
305
|
+
harnessThemeCss.href = '/api/theme.css' + cb;
|
|
306
|
+
// Strip stale theme classes the previous run added to <html> before
|
|
307
|
+
// letting the new theme-info.js script class us up again.
|
|
308
|
+
const html = document.documentElement;
|
|
309
|
+
html.classList.remove('light-mode', 'dark-mode');
|
|
310
|
+
// Drop any prior theme-name class we know about.
|
|
311
|
+
Array.from(themeSelect.options).forEach(o => html.classList.remove(o.value));
|
|
312
|
+
// Run a fresh theme-info script. The server-emitted JS adds the
|
|
313
|
+
// correct classes for the cookie's current theme.
|
|
314
|
+
const old = document.getElementById('harness-theme-info-runtime');
|
|
315
|
+
if (old) old.remove();
|
|
316
|
+
const s = document.createElement('script');
|
|
317
|
+
s.id = 'harness-theme-info-runtime';
|
|
318
|
+
s.src = '/api/theme-info.js' + cb;
|
|
319
|
+
document.head.appendChild(s);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function loadStarter(name) {
|
|
323
|
+
activeStarter = name;
|
|
324
|
+
currentTitle.textContent = name;
|
|
325
|
+
emptyState.style.display = 'none';
|
|
326
|
+
frameWrap.style.display = 'block';
|
|
327
|
+
applyFrameSize();
|
|
328
|
+
previewFrame.src = `/starters/${name}/page.html?t=${Date.now()}`;
|
|
329
|
+
captureBtn.disabled = false;
|
|
330
|
+
renderSidebar();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Iframe pages reference /api/theme.css and /api/theme-info.js directly,
|
|
334
|
+
// so the server hands them the right CSS + classes on each load — no
|
|
335
|
+
// theme injection needed here. We DO still need to:
|
|
336
|
+
// 1. Inject FluentLM CSS + JS (pages don't include these themselves
|
|
337
|
+
// — the shell normally provides them; absent them, flm-* web
|
|
338
|
+
// components never upgrade and render unstyled).
|
|
339
|
+
// 2. Stub `window.synthos.*` so pages calling synthos.shared.data.*
|
|
340
|
+
// / synthos.generate.* don't throw and instead render empty-state.
|
|
341
|
+
previewFrame.addEventListener('load', () => {
|
|
342
|
+
const doc = previewFrame.contentDocument;
|
|
343
|
+
const win = previewFrame.contentWindow;
|
|
344
|
+
if (!doc || !win) return;
|
|
345
|
+
|
|
346
|
+
if (!doc.getElementById('harness-fluentlm-css')) {
|
|
347
|
+
const fcss = doc.createElement('link');
|
|
348
|
+
fcss.id = 'harness-fluentlm-css';
|
|
349
|
+
fcss.rel = 'stylesheet';
|
|
350
|
+
fcss.href = '/static-files/fluentlm.min.css';
|
|
351
|
+
doc.head.appendChild(fcss);
|
|
352
|
+
}
|
|
353
|
+
if (!doc.getElementById('harness-fluentlm-js')) {
|
|
354
|
+
const fjs = doc.createElement('script');
|
|
355
|
+
fjs.id = 'harness-fluentlm-js';
|
|
356
|
+
fjs.src = '/static-files/fluentlm.min.js';
|
|
357
|
+
doc.head.appendChild(fjs);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (!win.synthos) {
|
|
361
|
+
win.synthos = {
|
|
362
|
+
data: {
|
|
363
|
+
save: () => Promise.resolve(),
|
|
364
|
+
load: () => Promise.resolve(null),
|
|
365
|
+
remove: () => Promise.resolve()
|
|
366
|
+
},
|
|
367
|
+
shared: {
|
|
368
|
+
data: {
|
|
369
|
+
save: (table, row) => Promise.resolve(row),
|
|
370
|
+
list: () => Promise.resolve([]),
|
|
371
|
+
remove: () => Promise.resolve(),
|
|
372
|
+
get: () => Promise.resolve(null)
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
generate: {
|
|
376
|
+
completion: () => Promise.reject(new Error('synthos.generate.completion is stubbed in the harness')),
|
|
377
|
+
stream: () => Promise.reject(new Error('synthos.generate.stream is stubbed in the harness'))
|
|
378
|
+
},
|
|
379
|
+
shell: {
|
|
380
|
+
navigate: () => {},
|
|
381
|
+
reload: () => {}
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
console.log('[harness] iframe loaded:', activeStarter, '— <html> classes:', doc.documentElement.className);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
async function captureCurrent() {
|
|
390
|
+
if (!activeStarter) return;
|
|
391
|
+
const doc = previewFrame.contentDocument;
|
|
392
|
+
if (!doc || !doc.body) {
|
|
393
|
+
toast('Iframe not ready', true);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const variant = themeVariant(themeSelect.value);
|
|
397
|
+
const filename = `page.${variant}.png`;
|
|
398
|
+
captureBtn.disabled = true;
|
|
399
|
+
try {
|
|
400
|
+
await new Promise(r => setTimeout(r, 250));
|
|
401
|
+
const canvas = await html2canvas(doc.body, {
|
|
402
|
+
width: doc.body.scrollWidth,
|
|
403
|
+
height: doc.body.scrollHeight,
|
|
404
|
+
windowWidth: doc.body.scrollWidth,
|
|
405
|
+
windowHeight: doc.body.scrollHeight,
|
|
406
|
+
backgroundColor: '#ffffff',
|
|
407
|
+
useCORS: true,
|
|
408
|
+
allowTaint: false,
|
|
409
|
+
logging: false,
|
|
410
|
+
scale: 1
|
|
411
|
+
});
|
|
412
|
+
const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
|
|
413
|
+
if (!blob) throw new Error('Could not encode PNG');
|
|
414
|
+
await savePng(activeStarter, filename, blob);
|
|
415
|
+
captureStatus[activeStarter] = captureStatus[activeStarter] || {};
|
|
416
|
+
captureStatus[activeStarter][variant] = true;
|
|
417
|
+
renderSidebar();
|
|
418
|
+
} catch (err) {
|
|
419
|
+
console.error(err);
|
|
420
|
+
toast('Capture failed: ' + err.message, true);
|
|
421
|
+
} finally {
|
|
422
|
+
captureBtn.disabled = false;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async function savePng(starter, filename, blob) {
|
|
427
|
+
if (savedDirHandle) {
|
|
428
|
+
try {
|
|
429
|
+
const sub = await savedDirHandle.getDirectoryHandle(starter, { create: false });
|
|
430
|
+
const file = await sub.getFileHandle(filename, { create: true });
|
|
431
|
+
const w = await file.createWritable();
|
|
432
|
+
await w.write(blob);
|
|
433
|
+
await w.close();
|
|
434
|
+
toast(`Saved ${starter}/${filename}`);
|
|
435
|
+
return;
|
|
436
|
+
} catch (err) {
|
|
437
|
+
console.error('Direct save failed:', err);
|
|
438
|
+
toast(`Direct save failed (${err.message}) — downloading instead`, true);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const url = URL.createObjectURL(blob);
|
|
442
|
+
const a = document.createElement('a');
|
|
443
|
+
a.href = url;
|
|
444
|
+
a.download = `${starter}-${filename}`;
|
|
445
|
+
document.body.appendChild(a);
|
|
446
|
+
a.click();
|
|
447
|
+
a.remove();
|
|
448
|
+
URL.revokeObjectURL(url);
|
|
449
|
+
toast(`Downloaded ${starter}-${filename} — move into starters/${starter}/${filename}`);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async function pickFolder() {
|
|
453
|
+
if (!window.showDirectoryPicker) {
|
|
454
|
+
toast('File System Access API not supported in this browser. Captures will download instead.', true);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
savedDirHandle = await window.showDirectoryPicker({
|
|
459
|
+
id: 'synthos-starters',
|
|
460
|
+
mode: 'readwrite',
|
|
461
|
+
startIn: 'documents'
|
|
462
|
+
});
|
|
463
|
+
toast(`Save folder set: ${savedDirHandle.name}`);
|
|
464
|
+
setFolderBtn.textContent = `Folder: ${savedDirHandle.name}`;
|
|
465
|
+
updateCaptureAllState();
|
|
466
|
+
} catch (err) {
|
|
467
|
+
if (err.name !== 'AbortError') {
|
|
468
|
+
toast('Folder pick failed: ' + err.message, true);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async function captureAll() {
|
|
474
|
+
captureAllBtn.disabled = true;
|
|
475
|
+
captureBtn.disabled = true;
|
|
476
|
+
try {
|
|
477
|
+
for (const name of STARTERS) {
|
|
478
|
+
loadStarter(name);
|
|
479
|
+
await new Promise(resolve => {
|
|
480
|
+
const onLoad = () => {
|
|
481
|
+
previewFrame.removeEventListener('load', onLoad);
|
|
482
|
+
setTimeout(resolve, 800);
|
|
483
|
+
};
|
|
484
|
+
previewFrame.addEventListener('load', onLoad);
|
|
485
|
+
});
|
|
486
|
+
await captureCurrent();
|
|
487
|
+
}
|
|
488
|
+
toast('All starters captured');
|
|
489
|
+
} finally {
|
|
490
|
+
captureAllBtn.disabled = false;
|
|
491
|
+
captureBtn.disabled = !activeStarter;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function updateCaptureButtonLabels() {
|
|
496
|
+
const variant = themeVariant(themeSelect.value);
|
|
497
|
+
captureBtn.textContent = `Capture page.${variant}.png`;
|
|
498
|
+
captureAllBtn.textContent = `Capture all (${variant})`;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function updateCaptureAllState() {
|
|
502
|
+
captureAllBtn.disabled = !savedDirHandle;
|
|
503
|
+
captureAllBtn.title = savedDirHandle
|
|
504
|
+
? 'Capture and save page.png for every starter'
|
|
505
|
+
: 'Set a save folder first to use Capture all';
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
captureBtn.addEventListener('click', captureCurrent);
|
|
509
|
+
captureAllBtn.addEventListener('click', captureAll);
|
|
510
|
+
setFolderBtn.addEventListener('click', pickFolder);
|
|
511
|
+
frameSize.addEventListener('change', () => {
|
|
512
|
+
applyFrameSize();
|
|
513
|
+
if (activeStarter) loadStarter(activeStarter);
|
|
514
|
+
});
|
|
515
|
+
themeSelect.addEventListener('change', async () => {
|
|
516
|
+
const theme = themeSelect.value;
|
|
517
|
+
try {
|
|
518
|
+
await setServerTheme(theme);
|
|
519
|
+
} catch (err) {
|
|
520
|
+
toast('Theme switch failed: ' + err.message, true);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
refreshHarnessTheme();
|
|
524
|
+
updateCaptureButtonLabels();
|
|
525
|
+
// Reload the iframe so its /api/theme.css + /api/theme-info.js
|
|
526
|
+
// re-fetch under the new cookie. In-place swap is possible but a
|
|
527
|
+
// full reload guarantees the page's theme-info script re-runs and
|
|
528
|
+
// applies the right <html> classes deterministically.
|
|
529
|
+
if (activeStarter) loadStarter(activeStarter);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
applyFrameSize();
|
|
533
|
+
updateCaptureButtonLabels();
|
|
534
|
+
updateCaptureAllState();
|
|
535
|
+
renderSidebar();
|
|
536
|
+
</script>
|
|
537
|
+
</body>
|
|
538
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"role":"assistant","content":"Welcome to the Kanban starter — a column-card workflow scaffold. Tell me what stages you want to track (e.g. tasks, content pipeline, sales funnel, bug triage) and I'll wire the columns, cards, drag-and-drop, and edit drawer."}]
|
|
Binary file
|