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
|
@@ -1,326 +1,302 @@
|
|
|
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</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>.idle-container{position:absolute;width:100%;height:100%;pointer-events:none;opacity:1;transition:opacity 1s ease-out}.idle-container.hidden{opacity:0}.breathing-orb{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:80px;height:80px;border-radius:50%;background:radial-gradient(circle,rgba(102,126,234,.15) 0,transparent 70%);animation:4s ease-in-out infinite breathe}.breathing-orb::before{content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:8px;height:8px;border-radius:50%;background:rgba(183,148,246,.6);box-shadow:0 0 20px rgba(183,148,246,.4);animation:4s ease-in-out infinite core-pulse}@keyframes breathe{0%,100%{width:80px;height:80px;opacity:.3}50%{width:120px;height:120px;opacity:.6}}@keyframes core-pulse{0%,100%{opacity:.4;box-shadow:0 0 20px rgba(183,148,246,.3)}50%{opacity:.8;box-shadow:0 0 30px rgba(183,148,246,.5)}}.orbit-ring{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:200px;height:200px;border:1px solid rgba(102,126,234,.1);border-radius:50%;animation:20s linear infinite orbit-rotate}.orbit-ring::after{content:'';position:absolute;top:-3px;left:50%;transform:translateX(-50%);width:6px;height:6px;background:rgba(240,147,251,.5);border-radius:50%;box-shadow:0 0 10px rgba(240,147,251,.3)}@keyframes orbit-rotate{from{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}}</style>
|
|
8
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
|
|
9
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
|
|
10
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
|
|
11
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
12
|
-
<script id="page-info" src="/api/page-info.js?page=builder"></script>
|
|
13
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js" id="topojson-lib"></script><style id="us-map-styles">#us-map-container{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:hidden}#us-map-header{min-height:var(--header-min-height);padding:var(--header-padding-vertical) var(--header-padding-horizontal);line-height:var(--header-line-height);display:flex;align-items:center;justify-content:center;box-sizing:border-box;font-size:1.25rem;font-weight:600;color:var(--bodyText);width:100%;border-bottom:1px solid var(--variantBorder);background-color:var(--bodyStandoutBackground);flex-shrink:0;position:relative}#us-map-svg-wrap{flex:1;width:100%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;position:relative}#us-map-svg-wrap svg{width:100%;height:100%;position:absolute;top:0;left:0;cursor:grab}#us-map-svg-wrap svg:active{cursor:grabbing}.region-path{cursor:pointer;transition:filter .2s ease;stroke-linejoin:round}.region-path:hover{filter:brightness(1.25)}.region-state{fill:rgba(46,125,50,0.5);stroke:#1b5e20;stroke-width:1.2}.region-oregon{fill:rgba(230,81,0,0.45);stroke:#bf360c;stroke-width:1.5}.region-minnesota{fill:rgba(255,152,0,0.45);stroke:#e65100;stroke-width:1.5}.region-utah{fill:rgba(255,111,0,0.4);stroke:#bf360c;stroke-width:1.5}.region-newmexico{fill:rgba(239,108,0,0.45);stroke:#bf360c;stroke-width:1.5}.region-unorganized{fill:rgba(141,110,99,0.4);stroke:#4e342e;stroke-width:1.5}.region-indian{fill:rgba(121,85,72,0.45);stroke:#3e2723;stroke-width:1.5}.light-mode .region-state{fill:rgba(46,125,50,0.5);stroke:#1b5e20}.light-mode .region-oregon{fill:rgba(230,81,0,0.45);stroke:#bf360c}.light-mode .region-minnesota{fill:rgba(255,152,0,0.45);stroke:#e65100}.light-mode .region-utah{fill:rgba(255,111,0,0.4);stroke:#bf360c}.light-mode .region-newmexico{fill:rgba(239,108,0,0.45);stroke:#bf360c}.light-mode .region-unorganized{fill:rgba(141,110,99,0.4);stroke:#4e342e}.light-mode .region-indian{fill:rgba(121,85,72,0.45);stroke:#3e2723}#map-tooltip{position:absolute;pointer-events:none;background-color:var(--bodyBackground);color:var(--bodyText);border:1px solid var(--variantBorder);border-radius:var(--roundedCorner4);padding:6px 12px;font-size:0.85rem;font-weight:500;box-shadow:var(--elevation8);opacity:0;transition:opacity .15s ease;z-index:10;white-space:nowrap}#hist-legend{position:absolute;bottom:16px;left:16px;background-color:var(--bodyBackground);border:1px solid var(--variantBorder);border-radius:8px;padding:10px 14px;font-size:0.75rem;color:var(--bodyText);z-index:5;box-shadow:0 2px 8px rgba(0,0,0,0.1)}#hist-legend .legend-item{display:flex;align-items:center;gap:8px;margin-bottom:4px}#hist-legend .legend-item:last-child{margin-bottom:0}#hist-legend .legend-swatch{width:14px;height:14px;border-radius:3px;flex-shrink:0}#zoom-controls{position:absolute;top:16px;right:16px;display:flex;flex-direction:column;gap:4px;z-index:5}#zoom-controls button{width:36px;height:36px;border:1px solid var(--variantBorder);border-radius:var(--roundedCorner4);background-color:var(--bodyBackground);color:var(--bodyText);font-size:1.2rem;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--elevation8);transition:background .15s ease}#zoom-controls button:hover{background-color:var(--bodyStandoutBackground)}</style><style id="detail-card-styles">.city-marker{cursor:pointer}.city-marker .marker-glow{fill:var(--themePrimary);opacity:0.15;transition:opacity .2s ease}.city-marker .marker-dot{fill:var(--themePrimary);transition:r .2s ease}.city-marker .marker-hit{fill:transparent;cursor:pointer}.city-marker:hover .marker-glow{opacity:0.35}.city-marker:hover .marker-dot{r:3.5}.city-marker .marker-label{font-size:8px;font-weight:600;fill:var(--bodyText);text-anchor:middle;pointer-events:none;paint-order:stroke;stroke:var(--bodyBackground);stroke-width:2.5px;stroke-linecap:round;stroke-linejoin:round}#detail-card{position:absolute;top:16px;right:16px;width:340px;max-height:calc(100% - 40px);background-color:var(--bodyBackground);border:1px solid var(--variantBorder);border-radius:var(--roundedCorner4);box-shadow:var(--elevation64);z-index:20;opacity:0;transform:translateY(-10px) scale(0.97);pointer-events:none;transition:opacity .25s ease,transform .25s ease;overflow:hidden;display:flex;flex-direction:column}#detail-card.visible{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}#detail-card .card-header{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 8px;border-bottom:1px solid var(--variantBorder);background-color:var(--bodyStandoutBackground);flex-shrink:0}#detail-card .card-header h3{margin:0;font-size:0.95rem;font-weight:700;color:var(--bodyText);line-height:1.3}#detail-card .card-header .card-close{background:none;border:none;font-size:1.3rem;cursor:pointer;color:var(--bodySubtext);padding:0 2px;line-height:1;border-radius:4px;transition:background .15s ease}#detail-card .card-header .card-close:hover{background-color:var(--buttonBackgroundHovered)}#detail-card .card-subtitle{font-size:0.72rem;color:var(--bodySubtext);margin:2px 0 0;font-weight:500}#detail-card .card-tabs{display:flex;border-bottom:1px solid var(--variantBorder);flex-shrink:0}#detail-card .card-tab{flex:1;padding:8px 10px;font-size:0.78rem;font-weight:600;text-align:center;cursor:pointer;border:none;background:none;color:var(--bodySubtext);transition:all .15s ease;border-bottom:2px solid transparent;position:relative}#detail-card .card-tab:hover{color:var(--bodyText);background-color:var(--buttonBackgroundHovered)}#detail-card .card-tab.active{color:var(--themePrimary);border-bottom-color:var(--themePrimary)}#detail-card .card-tab-icon{margin-right:4px}#detail-card .tab-content{flex:1;overflow:hidden;display:flex;flex-direction:column;min-height:0}#detail-card .tab-pane{display:none;flex:1;overflow-y:auto;flex-direction:column;min-height:0}#detail-card .tab-pane.active{display:flex}#detail-card .facts-pane{padding:12px 14px;overflow-y:auto}#detail-card .fact-row{display:flex;gap:8px;margin-bottom:8px;align-items:flex-start}#detail-card .fact-icon{font-size:1rem;flex-shrink:0;width:22px;text-align:center;margin-top:1px}#detail-card .fact-content{flex:1}#detail-card .fact-label{font-size:0.65rem;text-transform:uppercase;letter-spacing:0.5px;color:var(--bodySubtext);font-weight:600;margin-bottom:1px}#detail-card .fact-value{font-size:0.8rem;color:var(--bodyText);line-height:1.4}#detail-card .card-divider{height:1px;background-color:var(--variantBorder);margin:4px 0 8px}#detail-card .card-description{font-size:0.78rem;color:var(--bodyText);line-height:1.5;margin-top:2px}#detail-card .chat-pane{flex-direction:column;min-height:0;flex:1}#detail-card .chat-messages-area{flex:1;overflow-y:auto;padding:10px 12px;display:flex;flex-direction:column;gap:8px;min-height:120px}#detail-card .chat-welcome{text-align:center;padding:16px 8px;color:var(--bodySubtext);font-size:0.78rem;line-height:1.5}#detail-card .chat-welcome strong{color:var(--bodyText)}#detail-card .chat-bubble{max-width:92%;padding:8px 11px;border-radius:var(--roundedCorner4);font-size:0.78rem;line-height:1.45;word-wrap:break-word;animation:bubbleIn .2s ease}#detail-card .chat-bubble.user-bubble{align-self:flex-end;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border-bottom-right-radius:4px}#detail-card .chat-bubble.ai-bubble{align-self:flex-start;background-color:var(--bodyStandoutBackground);color:var(--bodyText);border:1px solid var(--variantBorder);border-bottom-left-radius:4px}#detail-card .chat-bubble.ai-bubble.loading{opacity:0.7}#detail-card .typing-dots{display:inline-flex;gap:3px;padding:2px 0}#detail-card .typing-dots span{width:5px;height:5px;border-radius:50%;background-color:var(--bodySubtext);animation:dotBounce .6s ease-in-out infinite}#detail-card .typing-dots span:nth-child(2){animation-delay:.15s}#detail-card .typing-dots span:nth-child(3){animation-delay:.3s}@keyframes dotBounce{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}@keyframes bubbleIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}#detail-card .chat-input-area{display:flex;gap:6px;padding:8px 10px;border-top:1px solid var(--variantBorder);background-color:var(--bodyBackground);flex-shrink:0;border-radius:0 0 var(--roundedCorner4) var(--roundedCorner4)}#detail-card .chat-input-field{flex:1;border:1px solid var(--variantBorder);border-radius:18px;padding:7px 12px;font-size:0.78rem;background-color:var(--inputBackground);color:var(--bodyText);outline:none;transition:border-color .15s ease;font-family:inherit}#detail-card .chat-input-field:focus{border-color:var(--themePrimary)}#detail-card .chat-input-field::placeholder{color:var(--bodySubtext);opacity:0.7}#detail-card .chat-send-btn{width:32px;height:32px;border-radius:50%;border:none;background:linear-gradient(135deg,var(--themePrimary),var(--themeDarker));color:#fff;font-size:0.9rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform .1s ease,opacity .15s ease;flex-shrink:0}#detail-card .chat-send-btn:hover{transform:scale(1.08)}#detail-card .chat-send-btn:disabled{opacity:0.4;cursor:not-allowed;transform:none}#detail-card .suggested-questions{display:flex;flex-wrap:wrap;gap:4px;padding:0 12px 8px}#detail-card .suggested-q{font-size:0.68rem;padding:4px 8px;border-radius:var(--roundedCorner4);border:1px solid var(--variantBorder);background-color:var(--inputBackground);color:var(--bodySubtext);cursor:pointer;transition:all .15s ease;white-space:nowrap}#detail-card .suggested-q:hover{color:var(--themePrimary);border-color:var(--themePrimary)}#card-backdrop{display:none;position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--overlayBackground);z-index:15}#card-backdrop.visible{display:block}</style></head>
|
|
14
|
-
<body>
|
|
15
|
-
<div class="
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
var
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
var
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
var
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
document.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
function
|
|
230
|
-
var
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
parts.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
addChatBubble('Something went wrong. Please try again in a moment.',false);
|
|
304
|
-
console.error('Detail card chat error:',err);
|
|
305
|
-
}
|
|
306
|
-
sendBtn.disabled=false;
|
|
307
|
-
input.focus();
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/* ─── EVENT LISTENERS ─────────────────────────────────────────────── */
|
|
311
|
-
document.getElementById('card-close-btn').addEventListener('click',function(e){e.stopPropagation();closeCard();});
|
|
312
|
-
document.getElementById('card-backdrop').addEventListener('click',function(e){e.stopPropagation();closeCard();});
|
|
313
|
-
document.querySelectorAll('#detail-card .card-tab').forEach(function(tab){
|
|
314
|
-
tab.addEventListener('click',function(e){e.stopPropagation();setActiveTab(tab.getAttribute('data-tab'));});
|
|
315
|
-
});
|
|
316
|
-
document.getElementById('detail-chat-send').addEventListener('click',function(e){
|
|
317
|
-
e.stopPropagation();sendChat(document.getElementById('detail-chat-input').value);
|
|
318
|
-
});
|
|
319
|
-
document.getElementById('detail-chat-input').addEventListener('keydown',function(e){
|
|
320
|
-
if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();e.stopPropagation();sendChat(this.value);}
|
|
321
|
-
});
|
|
322
|
-
document.getElementById('detail-chat-input').addEventListener('click',function(e){e.stopPropagation();});
|
|
323
|
-
|
|
324
|
-
/* ─── INIT ────────────────────────────────────────────────────────── */
|
|
325
|
-
waitForMap();
|
|
326
|
-
})();</script><script id="page-helpers" src="/api/page-helpers.js?v=3" data-locked="true"></script><script id="page-script" src="/api/page-script.js?v=3" data-locked="true"></script></body></html>
|
|
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</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>.idle-container{position:absolute;width:100%;height:100%;pointer-events:none;opacity:1;transition:opacity 1s ease-out}.idle-container.hidden{opacity:0}.breathing-orb{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:80px;height:80px;border-radius:50%;background:radial-gradient(circle,rgba(102,126,234,.15) 0,transparent 70%);animation:4s ease-in-out infinite breathe}.breathing-orb::before{content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:8px;height:8px;border-radius:50%;background:rgba(183,148,246,.6);box-shadow:0 0 20px rgba(183,148,246,.4);animation:4s ease-in-out infinite core-pulse}@keyframes breathe{0%,100%{width:80px;height:80px;opacity:.3}50%{width:120px;height:120px;opacity:.6}}@keyframes core-pulse{0%,100%{opacity:.4;box-shadow:0 0 20px rgba(183,148,246,.3)}50%{opacity:.8;box-shadow:0 0 30px rgba(183,148,246,.5)}}.orbit-ring{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:200px;height:200px;border:1px solid rgba(102,126,234,.1);border-radius:50%;animation:20s linear infinite orbit-rotate}.orbit-ring::after{content:'';position:absolute;top:-3px;left:50%;transform:translateX(-50%);width:6px;height:6px;background:rgba(240,147,251,.5);border-radius:50%;box-shadow:0 0 10px rgba(240,147,251,.3)}@keyframes orbit-rotate{from{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}}</style>
|
|
8
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
|
|
9
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
|
|
10
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
|
|
11
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
12
|
+
<script id="page-info" src="/api/page-info.js?page=builder"></script>
|
|
13
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js" id="topojson-lib"></script><style id="us-map-styles">#us-map-container{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;overflow:hidden}#us-map-header{min-height:var(--header-min-height);padding:var(--header-padding-vertical) var(--header-padding-horizontal);line-height:var(--header-line-height);display:flex;align-items:center;justify-content:center;box-sizing:border-box;font-size:1.25rem;font-weight:600;color:var(--bodyText);width:100%;border-bottom:1px solid var(--variantBorder);background-color:var(--bodyStandoutBackground);flex-shrink:0;position:relative}#us-map-svg-wrap{flex:1;width:100%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;position:relative}#us-map-svg-wrap svg{width:100%;height:100%;position:absolute;top:0;left:0;cursor:grab}#us-map-svg-wrap svg:active{cursor:grabbing}.region-path{cursor:pointer;transition:filter .2s ease;stroke-linejoin:round}.region-path:hover{filter:brightness(1.25)}.region-state{fill:rgba(46,125,50,0.5);stroke:#1b5e20;stroke-width:1.2}.region-oregon{fill:rgba(230,81,0,0.45);stroke:#bf360c;stroke-width:1.5}.region-minnesota{fill:rgba(255,152,0,0.45);stroke:#e65100;stroke-width:1.5}.region-utah{fill:rgba(255,111,0,0.4);stroke:#bf360c;stroke-width:1.5}.region-newmexico{fill:rgba(239,108,0,0.45);stroke:#bf360c;stroke-width:1.5}.region-unorganized{fill:rgba(141,110,99,0.4);stroke:#4e342e;stroke-width:1.5}.region-indian{fill:rgba(121,85,72,0.45);stroke:#3e2723;stroke-width:1.5}.light-mode .region-state{fill:rgba(46,125,50,0.5);stroke:#1b5e20}.light-mode .region-oregon{fill:rgba(230,81,0,0.45);stroke:#bf360c}.light-mode .region-minnesota{fill:rgba(255,152,0,0.45);stroke:#e65100}.light-mode .region-utah{fill:rgba(255,111,0,0.4);stroke:#bf360c}.light-mode .region-newmexico{fill:rgba(239,108,0,0.45);stroke:#bf360c}.light-mode .region-unorganized{fill:rgba(141,110,99,0.4);stroke:#4e342e}.light-mode .region-indian{fill:rgba(121,85,72,0.45);stroke:#3e2723}#map-tooltip{position:absolute;pointer-events:none;background-color:var(--bodyBackground);color:var(--bodyText);border:1px solid var(--variantBorder);border-radius:var(--roundedCorner4);padding:6px 12px;font-size:0.85rem;font-weight:500;box-shadow:var(--elevation8);opacity:0;transition:opacity .15s ease;z-index:10;white-space:nowrap}#hist-legend{position:absolute;bottom:16px;left:16px;background-color:var(--bodyBackground);border:1px solid var(--variantBorder);border-radius:8px;padding:10px 14px;font-size:0.75rem;color:var(--bodyText);z-index:5;box-shadow:0 2px 8px rgba(0,0,0,0.1)}#hist-legend .legend-item{display:flex;align-items:center;gap:8px;margin-bottom:4px}#hist-legend .legend-item:last-child{margin-bottom:0}#hist-legend .legend-swatch{width:14px;height:14px;border-radius:3px;flex-shrink:0}#zoom-controls{position:absolute;top:16px;right:16px;display:flex;flex-direction:column;gap:4px;z-index:5}#zoom-controls button{width:36px;height:36px;border:1px solid var(--variantBorder);border-radius:var(--roundedCorner4);background-color:var(--bodyBackground);color:var(--bodyText);font-size:1.2rem;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--elevation8);transition:background .15s ease}#zoom-controls button:hover{background-color:var(--bodyStandoutBackground)}</style><style id="detail-card-styles">.city-marker{cursor:pointer}.city-marker .marker-glow{fill:var(--themePrimary);opacity:0.15;transition:opacity .2s ease}.city-marker .marker-dot{fill:var(--themePrimary);transition:r .2s ease}.city-marker .marker-hit{fill:transparent;cursor:pointer}.city-marker:hover .marker-glow{opacity:0.35}.city-marker:hover .marker-dot{r:3.5}.city-marker .marker-label{font-size:8px;font-weight:600;fill:var(--bodyText);text-anchor:middle;pointer-events:none;paint-order:stroke;stroke:var(--bodyBackground);stroke-width:2.5px;stroke-linecap:round;stroke-linejoin:round}#detail-card{position:absolute;top:16px;right:16px;width:340px;max-height:calc(100% - 40px);background-color:var(--bodyBackground);border:1px solid var(--variantBorder);border-radius:var(--roundedCorner4);box-shadow:var(--elevation64);z-index:20;opacity:0;transform:translateY(-10px) scale(0.97);pointer-events:none;transition:opacity .25s ease,transform .25s ease;overflow:hidden;display:flex;flex-direction:column}#detail-card.visible{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}#detail-card .card-header{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 8px;border-bottom:1px solid var(--variantBorder);background-color:var(--bodyStandoutBackground);flex-shrink:0}#detail-card .card-header h3{margin:0;font-size:0.95rem;font-weight:700;color:var(--bodyText);line-height:1.3}#detail-card .card-header .card-close{background:none;border:none;font-size:1.3rem;cursor:pointer;color:var(--bodySubtext);padding:0 2px;line-height:1;border-radius:4px;transition:background .15s ease}#detail-card .card-header .card-close:hover{background-color:var(--buttonBackgroundHovered)}#detail-card .card-subtitle{font-size:0.72rem;color:var(--bodySubtext);margin:2px 0 0;font-weight:500}#detail-card .card-tabs{display:flex;border-bottom:1px solid var(--variantBorder);flex-shrink:0}#detail-card .card-tab{flex:1;padding:8px 10px;font-size:0.78rem;font-weight:600;text-align:center;cursor:pointer;border:none;background:none;color:var(--bodySubtext);transition:all .15s ease;border-bottom:2px solid transparent;position:relative}#detail-card .card-tab:hover{color:var(--bodyText);background-color:var(--buttonBackgroundHovered)}#detail-card .card-tab.active{color:var(--themePrimary);border-bottom-color:var(--themePrimary)}#detail-card .card-tab-icon{margin-right:4px}#detail-card .tab-content{flex:1;overflow:hidden;display:flex;flex-direction:column;min-height:0}#detail-card .tab-pane{display:none;flex:1;overflow-y:auto;flex-direction:column;min-height:0}#detail-card .tab-pane.active{display:flex}#detail-card .facts-pane{padding:12px 14px;overflow-y:auto}#detail-card .fact-row{display:flex;gap:8px;margin-bottom:8px;align-items:flex-start}#detail-card .fact-icon{font-size:1rem;flex-shrink:0;width:22px;text-align:center;margin-top:1px}#detail-card .fact-content{flex:1}#detail-card .fact-label{font-size:0.65rem;text-transform:uppercase;letter-spacing:0.5px;color:var(--bodySubtext);font-weight:600;margin-bottom:1px}#detail-card .fact-value{font-size:0.8rem;color:var(--bodyText);line-height:1.4}#detail-card .card-divider{height:1px;background-color:var(--variantBorder);margin:4px 0 8px}#detail-card .card-description{font-size:0.78rem;color:var(--bodyText);line-height:1.5;margin-top:2px}#detail-card .chat-pane{flex-direction:column;min-height:0;flex:1}#detail-card .chat-messages-area{flex:1;overflow-y:auto;padding:10px 12px;display:flex;flex-direction:column;gap:8px;min-height:120px}#detail-card .chat-welcome{text-align:center;padding:16px 8px;color:var(--bodySubtext);font-size:0.78rem;line-height:1.5}#detail-card .chat-welcome strong{color:var(--bodyText)}#detail-card .chat-bubble{max-width:92%;padding:8px 11px;border-radius:var(--roundedCorner4);font-size:0.78rem;line-height:1.45;word-wrap:break-word;animation:bubbleIn .2s ease}#detail-card .chat-bubble.user-bubble{align-self:flex-end;background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border-bottom-right-radius:4px}#detail-card .chat-bubble.ai-bubble{align-self:flex-start;background-color:var(--bodyStandoutBackground);color:var(--bodyText);border:1px solid var(--variantBorder);border-bottom-left-radius:4px}#detail-card .chat-bubble.ai-bubble.loading{opacity:0.7}#detail-card .typing-dots{display:inline-flex;gap:3px;padding:2px 0}#detail-card .typing-dots span{width:5px;height:5px;border-radius:50%;background-color:var(--bodySubtext);animation:dotBounce .6s ease-in-out infinite}#detail-card .typing-dots span:nth-child(2){animation-delay:.15s}#detail-card .typing-dots span:nth-child(3){animation-delay:.3s}@keyframes dotBounce{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}@keyframes bubbleIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}#detail-card .chat-input-area{display:flex;gap:6px;padding:8px 10px;border-top:1px solid var(--variantBorder);background-color:var(--bodyBackground);flex-shrink:0;border-radius:0 0 var(--roundedCorner4) var(--roundedCorner4)}#detail-card .chat-input-field{flex:1;border:1px solid var(--variantBorder);border-radius:18px;padding:7px 12px;font-size:0.78rem;background-color:var(--inputBackground);color:var(--bodyText);outline:none;transition:border-color .15s ease;font-family:inherit}#detail-card .chat-input-field:focus{border-color:var(--themePrimary)}#detail-card .chat-input-field::placeholder{color:var(--bodySubtext);opacity:0.7}#detail-card .chat-send-btn{width:32px;height:32px;border-radius:50%;border:none;background:linear-gradient(135deg,var(--themePrimary),var(--themeDarker));color:#fff;font-size:0.9rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform .1s ease,opacity .15s ease;flex-shrink:0}#detail-card .chat-send-btn:hover{transform:scale(1.08)}#detail-card .chat-send-btn:disabled{opacity:0.4;cursor:not-allowed;transform:none}#detail-card .suggested-questions{display:flex;flex-wrap:wrap;gap:4px;padding:0 12px 8px}#detail-card .suggested-q{font-size:0.68rem;padding:4px 8px;border-radius:var(--roundedCorner4);border:1px solid var(--variantBorder);background-color:var(--inputBackground);color:var(--bodySubtext);cursor:pointer;transition:all .15s ease;white-space:nowrap}#detail-card .suggested-q:hover{color:var(--themePrimary);border-color:var(--themePrimary)}#card-backdrop{display:none;position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--overlayBackground);z-index:15}#card-backdrop.visible{display:block}</style></head>
|
|
14
|
+
<body>
|
|
15
|
+
<div class="viewer-panel full-viewer" id="viewerPanel"><div id="us-map-container"><div id="us-map-header">United States — Circa 1850</div><div id="us-map-svg-wrap"><div id="hist-legend"><div style="font-weight:600;margin-bottom:6px;">Circa 1850</div><div class="legend-item"><div class="legend-swatch" style="background:rgba(46,125,50,0.6);border:1px solid #1b5e20;"></div><span>States (31)</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(230,81,0,0.55);border:1px solid #bf360c;"></div><span>Oregon Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(255,152,0,0.55);border:1px solid #e65100;"></div><span>Minnesota Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(255,111,0,0.5);border:1px solid #bf360c;"></div><span>Utah Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(239,108,0,0.55);border:1px solid #bf360c;"></div><span>New Mexico Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(141,110,99,0.5);border:1px solid #4e342e;"></div><span>Unorganized Territory</span></div><div class="legend-item"><div class="legend-swatch" style="background:rgba(121,85,72,0.55);border:1px solid #3e2723;"></div><span>Indian Territory</span></div></div><div id="zoom-controls"><button id="zoom-in-btn" title="Zoom in">+</button><button id="zoom-out-btn" title="Zoom out">−</button><button id="zoom-reset-btn" title="Reset view" style="font-size:0.75rem;">⟲</button></div></div><div id="map-tooltip"></div><div id="detail-card"><div class="card-header"><div><h3 id="card-title"></h3><div class="card-subtitle" id="card-subtitle"></div></div><button class="card-close" id="card-close-btn" aria-label="Close">×</button></div><div class="card-tabs"><button class="card-tab active" data-tab="facts"><span class="card-tab-icon">📋</span>Facts</button><button class="card-tab" data-tab="chat"><span class="card-tab-icon">💬</span>Ask Me</button></div><div class="tab-content"><div class="tab-pane facts-pane active" id="facts-pane"><div id="card-body"></div></div><div class="tab-pane chat-pane" id="chat-pane"><div class="chat-messages-area" id="detail-chat-messages"></div><div class="suggested-questions" id="detail-suggested-q"></div><div class="chat-input-area"><input type="text" class="chat-input-field" id="detail-chat-input" placeholder="Ask me anything..." autocomplete="off"><button class="chat-send-btn" id="detail-chat-send" aria-label="Send">➤</button></div></div></div></div><div id="card-backdrop"></div></div></div>
|
|
16
|
+
<div id="instructions" style="display: none;" data-locked="true"></div>
|
|
17
|
+
<div id="thoughts" style="display: none;" data-locked="true"></div>
|
|
18
|
+
<script id="idle-animation">function hideIdleAnimation(){const idleContainer=document.getElementById("idleAnimation");idleContainer&&(idleContainer.classList.add("hidden"),setTimeout(()=>{idleContainer.style.display="none"},1e3))}function showIdleAnimation(){const idleContainer=document.getElementById("idleAnimation");idleContainer&&(idleContainer.style.display="block",setTimeout(()=>{idleContainer.classList.remove("hidden")},10))}</script>
|
|
19
|
+
<button class="chat-toggle" aria-label="Toggle chat panel">
|
|
20
|
+
<span class="chat-toggle-dots">
|
|
21
|
+
<span class="chat-toggle-dot"></span>
|
|
22
|
+
<span class="chat-toggle-dot"></span>
|
|
23
|
+
<span class="chat-toggle-dot"></span>
|
|
24
|
+
</span>
|
|
25
|
+
</button>
|
|
26
|
+
|
|
27
|
+
<script id="us-map-script">(function(){var FIPS_TO_NAME={1:'Alabama',2:'Alaska',4:'Arizona',5:'Arkansas',6:'California',8:'Colorado',9:'Connecticut',10:'Delaware',11:'District of Columbia',12:'Florida',13:'Georgia',15:'Hawaii',16:'Idaho',17:'Illinois',18:'Indiana',19:'Iowa',20:'Kansas',21:'Kentucky',22:'Louisiana',23:'Maine',24:'Maryland',25:'Massachusetts',26:'Michigan',27:'Minnesota',28:'Mississippi',29:'Missouri',30:'Montana',31:'Nebraska',32:'Nevada',33:'New Hampshire',34:'New Jersey',35:'New Mexico',36:'New York',37:'North Carolina',38:'North Dakota',39:'Ohio',40:'Oklahoma',41:'Oregon',42:'Pennsylvania',44:'Rhode Island',45:'South Carolina',46:'South Dakota',47:'Tennessee',48:'Texas',49:'Utah',50:'Vermont',51:'Virginia',53:'Washington',54:'West Virginia',55:'Wisconsin',56:'Wyoming'};
|
|
28
|
+
var STATES_1850=[9,10,13,24,25,33,34,36,37,42,44,45,51,50,21,47,39,22,18,28,17,1,23,29,5,26,12,48,19,55,6,54,11];
|
|
29
|
+
var OREGON_TERR=[41,53,16];
|
|
30
|
+
var MINNESOTA_TERR=[27];
|
|
31
|
+
var UTAH_TERR=[49,32];
|
|
32
|
+
var NEWMEXICO_TERR=[35,4];
|
|
33
|
+
var UNORGANIZED=[31,20,38,46,56,30,8];
|
|
34
|
+
var INDIAN_TERR=[40];
|
|
35
|
+
var TERRITORY_GROUPS=[{fips:OREGON_TERR,name:'Oregon Territory',cls:'region-oregon'},{fips:MINNESOTA_TERR,name:'Minnesota Territory',cls:'region-minnesota'},{fips:UTAH_TERR,name:'Utah Territory',cls:'region-utah'},{fips:NEWMEXICO_TERR,name:'New Mexico Territory',cls:'region-newmexico'},{fips:UNORGANIZED,name:'Unorganized Territory',cls:'region-unorganized'},{fips:INDIAN_TERR,name:'Indian Territory',cls:'region-indian'}];
|
|
36
|
+
function init(){var wrap=document.getElementById('us-map-svg-wrap');if(!wrap)return;var tooltip=document.getElementById('map-tooltip');wrap.querySelectorAll('svg').forEach(function(s){s.remove();});
|
|
37
|
+
var svg=d3.select(wrap).append('svg').attr('id','hist-map-svg').attr('viewBox','0 0 960 600').attr('preserveAspectRatio','xMidYMid meet').style('padding','0').style('box-sizing','border-box');
|
|
38
|
+
var g=svg.append('g').attr('id','map-zoom-group');
|
|
39
|
+
var zoom=d3.zoom().scaleExtent([1,12]).on('zoom',function(event){g.attr('transform',event.transform);});
|
|
40
|
+
svg.call(zoom);
|
|
41
|
+
svg.on('dblclick.zoom',null);
|
|
42
|
+
var projection=d3.geoAlbersUsa().scale(1280).translate([480,300]);var path=d3.geoPath().projection(projection);
|
|
43
|
+
d3.json('https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json').then(function(us){var statesGeo=us.objects.states;var allGeometries=statesGeo.geometries;
|
|
44
|
+
function geomsForFips(fipsList){return allGeometries.filter(function(g){return fipsList.indexOf(+g.id)!==-1;});}
|
|
45
|
+
var stateGeoms=geomsForFips(STATES_1850);stateGeoms.forEach(function(geom){var feature=topojson.feature(us,geom);g.append('path').datum(feature).attr('class','region-path region-state').attr('d',path).on('mousemove',function(event){var name=FIPS_TO_NAME[+geom.id]||'Unknown';tooltip.textContent=name+' (State)';tooltip.style.opacity='1';var rect=wrap.getBoundingClientRect();var x=event.clientX-rect.left+12;var y=event.clientY-rect.top-30;if(x+180>rect.width)x=x-200;if(y<0)y=event.clientY-rect.top+18;tooltip.style.left=x+'px';tooltip.style.top=y+'px';}).on('mouseleave',function(){tooltip.style.opacity='0';});});
|
|
46
|
+
TERRITORY_GROUPS.forEach(function(group){var geoms=geomsForFips(group.fips);if(geoms.length===0)return;var merged=topojson.merge(us,geoms);g.append('path').datum(merged).attr('class','region-path '+group.cls).attr('d',path).on('mousemove',function(event){tooltip.textContent=group.name;tooltip.style.opacity='1';var rect=wrap.getBoundingClientRect();var x=event.clientX-rect.left+12;var y=event.clientY-rect.top-30;if(x+180>rect.width)x=x-200;if(y<0)y=event.clientY-rect.top+18;tooltip.style.left=x+'px';tooltip.style.top=y+'px';}).on('mouseleave',function(){tooltip.style.opacity='0';});});
|
|
47
|
+
var stateGeoms2=geomsForFips(STATES_1850);g.append('path').datum(topojson.mesh(us,{type:'GeometryCollection',geometries:stateGeoms2},function(a,b){return a!==b&&STATES_1850.indexOf(+a.id)!==-1&&STATES_1850.indexOf(+b.id)!==-1;})).attr('fill','none').attr('stroke','rgba(27,94,32,0.4)').attr('stroke-width','0.5').attr('d',path).style('pointer-events','none');
|
|
48
|
+
}).catch(function(err){console.error('Failed to load US map data:',err);wrap.innerHTML='<p style="color:var(--bodySubtext);text-align:center;">Failed to load map data. Please try again.</p>';});}
|
|
49
|
+
if(typeof topojson!=='undefined'){init();}else{var check=setInterval(function(){if(typeof topojson!=='undefined'){clearInterval(check);init();}},100);setTimeout(function(){clearInterval(check);},10000);}
|
|
50
|
+
})();</script><script id="zoom-controls-script">(function(){function waitForSvg(){var svg=d3.select('#hist-map-svg');if(svg.empty()){setTimeout(waitForSvg,200);return;}var zoomBehavior=null;svg.each(function(){var z=d3.zoomTransform(this);if(z)zoomBehavior=true;});var zoomHandler=d3.zoom().scaleExtent([1,12]).on('zoom',function(event){d3.select('#map-zoom-group').attr('transform',event.transform);});document.getElementById('zoom-in-btn').addEventListener('click',function(){svg.transition().duration(300).call(zoomHandler.scaleBy,1.5);});document.getElementById('zoom-out-btn').addEventListener('click',function(){svg.transition().duration(300).call(zoomHandler.scaleBy,1/1.5);});document.getElementById('zoom-reset-btn').addEventListener('click',function(){svg.transition().duration(400).call(zoomHandler.transform,d3.zoomIdentity);});svg.call(zoomHandler);}waitForSvg();})();</script><script id="detail-card-script">(function(){
|
|
51
|
+
/* ─── DETAIL CARD SCRIPT ───────────────────────────────────────────────
|
|
52
|
+
* RENDERING ORDER CONTRACT:
|
|
53
|
+
* This script executes AFTER us-map-script (which starts async TopoJSON
|
|
54
|
+
* loading) and zoom-controls-script. waitForMap() polls until at least
|
|
55
|
+
* one .region-path exists in the SVG before appending markers. This
|
|
56
|
+
* guarantees markers are the LAST children in the zoom group so they
|
|
57
|
+
* paint on top of map paths and receive click events.
|
|
58
|
+
* ──────────────────────────────────────────────────────────────────── */
|
|
59
|
+
|
|
60
|
+
/* ─── MARKER DATA ──────────────────────────────────────────────────────
|
|
61
|
+
* Each entry describes a point of interest to plot on the map.
|
|
62
|
+
* Expected shape:
|
|
63
|
+
* {
|
|
64
|
+
* name: 'City Name', // display name (used as card title)
|
|
65
|
+
* lat: 40.7128, // latitude (decimal degrees)
|
|
66
|
+
* lon: -74.0060, // longitude (negative = west)
|
|
67
|
+
* subtitle: 'A short tagline', // shown below the title in the header
|
|
68
|
+
* description: 'Longer text.', // shown at bottom of the facts pane
|
|
69
|
+
* facts: [ // array of fact rows for the card
|
|
70
|
+
* { icon: '📏', label: 'Elevation', value: '5,280 ft' }
|
|
71
|
+
* ],
|
|
72
|
+
* suggestedQuestions: [ // (optional) starter questions for chat
|
|
73
|
+
* 'What was life like here?'
|
|
74
|
+
* ]
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* The LLM should populate this array with location-specific data.
|
|
78
|
+
* ──────────────────────────────────────────────────────────────────── */
|
|
79
|
+
var MARKER_DATA = [
|
|
80
|
+
// Example (replace with real data):
|
|
81
|
+
// { name: 'St. Louis', lat: 38.627, lon: -90.199, subtitle: 'Gateway to the West',
|
|
82
|
+
// description: 'A major hub for westward expansion.',
|
|
83
|
+
// facts: [{ icon: '👥', label: 'Population', value: '~78,000 by 1850' }],
|
|
84
|
+
// suggestedQuestions: ['What was St. Louis like in the 1850s?'] }
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/* ─── STATE ─────────────────────────────────────────────────────────── */
|
|
88
|
+
var currentItem = null;
|
|
89
|
+
var chatHistory = [];
|
|
90
|
+
|
|
91
|
+
/* ─── RENDERING ORDER GUARD ───────────────────────────────────────────
|
|
92
|
+
* ⚠️ Do NOT remove this guard. Markers MUST be appended AFTER the async
|
|
93
|
+
* TopoJSON fetch finishes and paths are drawn. Without this check the
|
|
94
|
+
* SVG paint order would put paths on top of markers, blocking clicks.
|
|
95
|
+
* ──────────────────────────────────────────────────────────────────── */
|
|
96
|
+
function waitForMap(){
|
|
97
|
+
var g=document.getElementById('map-zoom-group');
|
|
98
|
+
if(!g||!g.querySelector('.region-path')){setTimeout(waitForMap,300);return;}
|
|
99
|
+
plotMarkers(g);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* ─── PLOT MARKERS ────────────────────────────────────────────────────
|
|
103
|
+
* Markers are appended as the LAST children of the zoom group so they
|
|
104
|
+
* sit on top of all map paths in SVG paint order. Do not move this
|
|
105
|
+
* call earlier in the execution chain.
|
|
106
|
+
* ──────────────────────────────────────────────────────────────────── */
|
|
107
|
+
function plotMarkers(zoomGroup){
|
|
108
|
+
if(MARKER_DATA.length===0)return;
|
|
109
|
+
var projection=d3.geoAlbersUsa().scale(1280).translate([480,300]);
|
|
110
|
+
var g=d3.select(zoomGroup);
|
|
111
|
+
MARKER_DATA.forEach(function(item){
|
|
112
|
+
var pt=projection([item.lon,item.lat]);
|
|
113
|
+
if(!pt)return;
|
|
114
|
+
var marker=g.append('g').attr('class','city-marker').attr('transform','translate('+pt[0]+','+pt[1]+')');
|
|
115
|
+
marker.append('circle').attr('class','marker-glow').attr('r',8);
|
|
116
|
+
marker.append('circle').attr('class','marker-dot').attr('r',3);
|
|
117
|
+
marker.append('text').attr('class','marker-label').attr('y',-12).text(item.name);
|
|
118
|
+
marker.append('circle').attr('class','marker-hit').attr('r',14);
|
|
119
|
+
marker.on('click',function(event){event.stopPropagation();openCard(item);});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ─── CARD FUNCTIONS ──────────────────────────────────────────────── */
|
|
124
|
+
function openCard(item){
|
|
125
|
+
var card=document.getElementById('detail-card');
|
|
126
|
+
var backdrop=document.getElementById('card-backdrop');
|
|
127
|
+
if(!card)return;
|
|
128
|
+
document.getElementById('card-title').textContent=item.name;
|
|
129
|
+
document.getElementById('card-subtitle').textContent=item.subtitle||'';
|
|
130
|
+
var body=document.getElementById('card-body');
|
|
131
|
+
var html='';
|
|
132
|
+
if(item.facts&&item.facts.length){
|
|
133
|
+
item.facts.forEach(function(f){
|
|
134
|
+
html+='<div class="fact-row"><div class="fact-icon">'+f.icon+'</div><div class="fact-content"><div class="fact-label">'+f.label+'</div><div class="fact-value">'+f.value+'</div></div></div>';
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if(item.description){
|
|
138
|
+
if(html)html+='<div class="card-divider"></div>';
|
|
139
|
+
html+='<div class="card-description">'+item.description+'</div>';
|
|
140
|
+
}
|
|
141
|
+
body.innerHTML=html||'<div class="card-description" style="color:var(--bodySubtext);">No facts available.</div>';
|
|
142
|
+
if(!currentItem||currentItem.name!==item.name){
|
|
143
|
+
chatHistory=[];
|
|
144
|
+
var msgArea=document.getElementById('detail-chat-messages');
|
|
145
|
+
msgArea.innerHTML='<div class="chat-welcome">Select the <strong>Ask Me</strong> tab to ask questions about <strong>'+item.name+'</strong>.</div>';
|
|
146
|
+
}
|
|
147
|
+
currentItem=item;
|
|
148
|
+
updateSuggestedQuestions(item);
|
|
149
|
+
card.classList.add('visible');
|
|
150
|
+
if(backdrop)backdrop.classList.add('visible');
|
|
151
|
+
setActiveTab('facts');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function closeCard(){
|
|
155
|
+
var card=document.getElementById('detail-card');
|
|
156
|
+
var backdrop=document.getElementById('card-backdrop');
|
|
157
|
+
if(card)card.classList.remove('visible');
|
|
158
|
+
if(backdrop)backdrop.classList.remove('visible');
|
|
159
|
+
currentItem=null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function setActiveTab(tabName){
|
|
163
|
+
document.querySelectorAll('#detail-card .card-tab').forEach(function(t){
|
|
164
|
+
t.classList.toggle('active',t.getAttribute('data-tab')===tabName);
|
|
165
|
+
});
|
|
166
|
+
document.querySelectorAll('#detail-card .tab-pane').forEach(function(p){
|
|
167
|
+
if(tabName==='facts')p.classList.toggle('active',p.id==='facts-pane');
|
|
168
|
+
else p.classList.toggle('active',p.id==='chat-pane');
|
|
169
|
+
});
|
|
170
|
+
if(tabName==='chat'){
|
|
171
|
+
var input=document.getElementById('detail-chat-input');
|
|
172
|
+
if(input)setTimeout(function(){input.focus();},100);
|
|
173
|
+
scrollChatToBottom();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function addChatBubble(text,isUser){
|
|
178
|
+
var area=document.getElementById('detail-chat-messages');
|
|
179
|
+
var welcome=area.querySelector('.chat-welcome');
|
|
180
|
+
if(welcome)welcome.remove();
|
|
181
|
+
var bubble=document.createElement('div');
|
|
182
|
+
bubble.className='chat-bubble '+(isUser?'user-bubble':'ai-bubble');
|
|
183
|
+
bubble.textContent=text;
|
|
184
|
+
area.appendChild(bubble);
|
|
185
|
+
scrollChatToBottom();
|
|
186
|
+
return bubble;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function addLoadingBubble(){
|
|
190
|
+
var area=document.getElementById('detail-chat-messages');
|
|
191
|
+
var bubble=document.createElement('div');
|
|
192
|
+
bubble.className='chat-bubble ai-bubble loading';
|
|
193
|
+
bubble.id='detail-loading-bubble';
|
|
194
|
+
bubble.innerHTML='<div class="typing-dots"><span></span><span></span><span></span></div>';
|
|
195
|
+
area.appendChild(bubble);
|
|
196
|
+
scrollChatToBottom();
|
|
197
|
+
return bubble;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function removeLoadingBubble(){
|
|
201
|
+
var el=document.getElementById('detail-loading-bubble');
|
|
202
|
+
if(el)el.remove();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function scrollChatToBottom(){
|
|
206
|
+
var area=document.getElementById('detail-chat-messages');
|
|
207
|
+
if(area)area.scrollTop=area.scrollHeight;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function updateSuggestedQuestions(item){
|
|
211
|
+
var container=document.getElementById('detail-suggested-q');
|
|
212
|
+
var questions=(item.suggestedQuestions&&item.suggestedQuestions.length)
|
|
213
|
+
?item.suggestedQuestions
|
|
214
|
+
:['What was it like here?','Tell me more about this place.','Why was this important?'];
|
|
215
|
+
container.innerHTML='';
|
|
216
|
+
questions.forEach(function(q){
|
|
217
|
+
var btn=document.createElement('button');
|
|
218
|
+
btn.className='suggested-q';
|
|
219
|
+
btn.textContent=q;
|
|
220
|
+
btn.addEventListener('click',function(){sendChat(q);});
|
|
221
|
+
container.appendChild(btn);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* ─── LLM INTEGRATION ─────────────────────────────────────────────────
|
|
226
|
+
* The system prompt below is generic and factual. Customize it to match
|
|
227
|
+
* the page's topic, audience, or persona as needed.
|
|
228
|
+
* ──────────────────────────────────────────────────────────────────── */
|
|
229
|
+
function buildPrompt(userQuestion){
|
|
230
|
+
var parts=[];
|
|
231
|
+
parts.push('You are a knowledgeable expert. Answer questions about '+currentItem.name+' based on the provided context.');
|
|
232
|
+
parts.push('');
|
|
233
|
+
parts.push('Location: '+currentItem.name);
|
|
234
|
+
if(currentItem.subtitle)parts.push('Summary: '+currentItem.subtitle);
|
|
235
|
+
if(currentItem.description)parts.push('Description: '+currentItem.description);
|
|
236
|
+
if(currentItem.facts&¤tItem.facts.length){
|
|
237
|
+
parts.push('Key facts:');
|
|
238
|
+
currentItem.facts.forEach(function(f){parts.push('- '+f.label+': '+f.value);});
|
|
239
|
+
}
|
|
240
|
+
parts.push('');
|
|
241
|
+
parts.push('RULES:');
|
|
242
|
+
parts.push('- Keep answers concise (2-4 short paragraphs max)');
|
|
243
|
+
parts.push('- Be accurate and informative');
|
|
244
|
+
parts.push('- If you do not know something, say so honestly');
|
|
245
|
+
parts.push('');
|
|
246
|
+
if(chatHistory.length>0){
|
|
247
|
+
parts.push('Recent conversation:');
|
|
248
|
+
var recent=chatHistory.slice(-10);
|
|
249
|
+
recent.forEach(function(turn){
|
|
250
|
+
parts.push((turn.role==='user'?'User: ':'Assistant: ')+turn.text);
|
|
251
|
+
});
|
|
252
|
+
parts.push('');
|
|
253
|
+
}
|
|
254
|
+
parts.push('User question: '+userQuestion);
|
|
255
|
+
return parts.join('\n');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function sendChat(message){
|
|
259
|
+
if(!message||!message.trim()||!currentItem)return;
|
|
260
|
+
var input=document.getElementById('detail-chat-input');
|
|
261
|
+
var sendBtn=document.getElementById('detail-chat-send');
|
|
262
|
+
message=message.trim();
|
|
263
|
+
input.value='';
|
|
264
|
+
sendBtn.disabled=true;
|
|
265
|
+
setActiveTab('chat');
|
|
266
|
+
addChatBubble(message,true);
|
|
267
|
+
chatHistory.push({role:'user',text:message});
|
|
268
|
+
addLoadingBubble();
|
|
269
|
+
try{
|
|
270
|
+
var prompt=buildPrompt(message);
|
|
271
|
+
var result=await synthos.generate.completion({prompt:prompt,temperature:0.7});
|
|
272
|
+
removeLoadingBubble();
|
|
273
|
+
var answer=result.answer||'I wasn\'t able to generate a response. Please try again.';
|
|
274
|
+
addChatBubble(answer,false);
|
|
275
|
+
chatHistory.push({role:'assistant',text:answer});
|
|
276
|
+
if(chatHistory.length>20)chatHistory=chatHistory.slice(-20);
|
|
277
|
+
}catch(err){
|
|
278
|
+
removeLoadingBubble();
|
|
279
|
+
addChatBubble('Something went wrong. Please try again in a moment.',false);
|
|
280
|
+
console.error('Detail card chat error:',err);
|
|
281
|
+
}
|
|
282
|
+
sendBtn.disabled=false;
|
|
283
|
+
input.focus();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* ─── EVENT LISTENERS ─────────────────────────────────────────────── */
|
|
287
|
+
document.getElementById('card-close-btn').addEventListener('click',function(e){e.stopPropagation();closeCard();});
|
|
288
|
+
document.getElementById('card-backdrop').addEventListener('click',function(e){e.stopPropagation();closeCard();});
|
|
289
|
+
document.querySelectorAll('#detail-card .card-tab').forEach(function(tab){
|
|
290
|
+
tab.addEventListener('click',function(e){e.stopPropagation();setActiveTab(tab.getAttribute('data-tab'));});
|
|
291
|
+
});
|
|
292
|
+
document.getElementById('detail-chat-send').addEventListener('click',function(e){
|
|
293
|
+
e.stopPropagation();sendChat(document.getElementById('detail-chat-input').value);
|
|
294
|
+
});
|
|
295
|
+
document.getElementById('detail-chat-input').addEventListener('keydown',function(e){
|
|
296
|
+
if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();e.stopPropagation();sendChat(this.value);}
|
|
297
|
+
});
|
|
298
|
+
document.getElementById('detail-chat-input').addEventListener('click',function(e){e.stopPropagation();});
|
|
299
|
+
|
|
300
|
+
/* ─── INIT ────────────────────────────────────────────────────────── */
|
|
301
|
+
waitForMap();
|
|
302
|
+
})();</script></body></html>
|