Mercurial
annotate mrjunejune/src/jrpg/jrpg.js @ 272:41a49c29a28f
polish JRPG conversation experience
Integrate desktop conversations into the utility panel, simplify the mobile frame, add modal destinations and a reusable Zenbu composer lab, and preserve explicit conversation resume behavior.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 07 Aug 2026 16:05:29 -0700 |
| parents | 056790c4fb0d |
| children | e02e2036ef84 |
| rev | line source |
|---|---|
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1 const CHARACTER_STATES = Object.freeze({ |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 default: { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 alt: "Epi the Shiba Inu standing happily", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 src: "/public/jrpg/shiba-default.webp", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 sad: { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 alt: "Epi the Shiba Inu sitting sadly", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 src: "/public/jrpg/shiba-sad.webp", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 thinking: { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 alt: "Epi the Shiba Inu tilting her head in thought", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
12 src: "/public/jrpg/shiba-thinking.webp", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
13 }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
14 }); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
15 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
16 const PREVIEWS = Object.freeze({ |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
17 resume: { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
18 copy: "Member of Technical Staff and engineering leader with 10+ years building AI agent platforms and production systems across Microsoft, Meta, Google, and growth-stage companies.", |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
19 title: "Resume", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
20 url: "/resume", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
21 works: [ |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
22 { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
23 detail: "Career dossier", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
24 label: "Full resume", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
25 modal: "resume", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
26 url: "/resume", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
27 }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
28 { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
29 detail: "Led engineering", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
30 label: "Copilot Tasks", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
31 url: "https://www.microsoft.com/en-us/microsoft-copilot/blog/2026/02/26/copilot-tasks-from-answers-to-actions/", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
32 }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
33 { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
34 detail: "Foundational platform", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
35 label: "AIX Harness / Copilot", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
36 url: "https://www.cio.com/article/3977098/microsoft-doubles-down-on-multi-model-ai-as-it-builds-a-copilot-super-app.html", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
37 }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
38 { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
39 detail: "Build 2026 products", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
40 label: "Code & Autopilot", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
41 url: "https://news.microsoft.com/build-2026/", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
42 }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
43 { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
44 detail: "Full-stack ads systems", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
45 label: "Meta", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
46 url: "https://www.meta.com/", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
47 }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
48 { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
49 detail: "Workspace platform", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
50 label: "Google", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
51 url: "https://www.google.com/", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
52 }, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
53 { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
54 detail: "Technical lead", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
55 label: "Warner Music Group", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
56 url: "https://www.wmg.com/", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
57 }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
58 { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
59 detail: "Personal agent launch", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
60 label: "Microsoft Scout", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
61 url: "https://www.microsoft.com/en-us/microsoft-365/blog/2026/06/02/introducing-microsoft-scout-your-always-on-personal-agent/", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
62 }, |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
63 ], |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 tools: { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
66 copy: "Useful browser tools backed by first-party C, WASM, media, and document-processing systems.", |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 title: "Tools", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 url: "/tools", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
69 works: [ |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
70 { detail: "Writing", label: "Markdown", url: "/tools/markdown_to_html" }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
71 { detail: "Media", label: "Converter", url: "/tools/file_converter" }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
72 { detail: "Streaming", label: "HLS Player", url: "/tools/hls_player" }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
73 ], |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
74 }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 blog: { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
76 copy: "Technical writing about networking, rendering, performance, developer tooling, and experiments.", |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
77 title: "Blogs", |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
78 url: "/blog", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
79 works: [ |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
80 { detail: "Archive", label: "All posts", url: "/blog" }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
81 ], |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 }); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
85 const CONVERSATION_STORAGE_KEY = "mjj-jrpg-conversation-id"; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
86 const CONVERSATION_LEGACY_KEY = "mjj-jrpg-legacy-claim"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
87 const ARCHIVE_PAGE_SIZE = 20; |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
88 const TYPING_INTERVAL_MS = 18; |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
89 const SCRIPT_LOADS = new Map(); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
90 const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
91 const VALID_PANELS = Object.freeze(["resume", "tools", "blog", "conversations"]); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
92 const ROLE_GREETINGS = Object.freeze({ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
93 guest: "Hi, my name is Epi. June usually calls me Epi-chan. I’m here to help you navigate his personal website and learn about his work, projects, and writing.", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
94 invited: "Hi! I’m Epi, but June usually calls me Epi-chan. Since June invited you, I can be a little more casual. I can help you explore his site, talk about his projects, or brainstorm simple ideas with you.", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
95 admin: "Hi June! I’m Epi-chan. I’m here to help you review your personal website, think through your projects, and draft or refine public-facing ideas.", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
96 }); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
97 const TOOL_ICON_NAMES = Object.freeze({ |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
98 "/notes": "repository", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
99 "/tools/file_converter": "retry", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
100 "/tools/hls_player": "play", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
101 "/tools/latex_editor": "file", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
102 "/tools/markdown_to_html": "code", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
103 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
104 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
105 function loadScript(source) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
106 if (SCRIPT_LOADS.has(source)) return SCRIPT_LOADS.get(source); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
107 const loading = new Promise((resolve, reject) => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
108 const script = document.createElement("script"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
109 script.src = source; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
110 script.addEventListener("load", resolve, { once: true }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
111 script.addEventListener("error", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
112 SCRIPT_LOADS.delete(source); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
113 script.remove(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
114 reject(new Error(`Unable to load ${source}`)); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
115 }, { once: true }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
116 document.head.append(script); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
117 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
118 SCRIPT_LOADS.set(source, loading); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
119 return loading; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
120 } |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
121 |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
122 function greetingForSession(sessionData, hasConversations = false) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
123 const greeting = sessionData?.kind !== "user" |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
124 ? ROLE_GREETINGS.guest |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
125 : sessionData.role === "admin" |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
126 ? ROLE_GREETINGS.admin |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
127 : ROLE_GREETINGS.invited; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
128 return hasConversations |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
129 ? `${greeting} We’ve talked before. Open Conversations if you’d like to continue one.` |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
130 : greeting; |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
131 } |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
132 |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
133 class StreamingTextAnimator { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
134 constructor(render) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
135 this._render = render; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
136 this._displayed = ""; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
137 this._target = ""; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
138 this._timer = 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
139 this._waiters = []; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
140 this._reduceMotion = window.matchMedia( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
141 "(prefers-reduced-motion: reduce)", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
142 ).matches; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
143 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
144 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
145 append(text) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
146 if (typeof text !== "string" || !text) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
147 this._target += text; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
148 this._schedule(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
149 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
150 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
151 complete(text) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
152 if (typeof text === "string") { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
153 this._target = text; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
154 if (!this._target.startsWith(this._displayed)) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
155 let shared = 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
156 while ( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
157 shared < this._target.length && |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
158 shared < this._displayed.length && |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
159 this._target[shared] === this._displayed[shared] |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
160 ) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
161 shared++; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
162 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
163 this._displayed = this._displayed.slice(0, shared); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
164 this._render(this._displayed); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
165 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
166 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
167 this._schedule(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
168 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
169 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
170 waitForIdle() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
171 if (!this._timer && this._displayed === this._target) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
172 return Promise.resolve(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
173 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
174 return new Promise(resolve => { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
175 this._waiters.push(resolve); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
176 }); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
177 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
178 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
179 cancel() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
180 window.clearTimeout(this._timer); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
181 this._timer = 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
182 this._target = this._displayed; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
183 this._settle(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
184 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
185 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
186 _schedule() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
187 if (this._reduceMotion) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
188 this._displayed = this._target; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
189 this._render(this._displayed); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
190 this._settle(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
191 return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
192 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
193 if (this._timer || this._displayed === this._target) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
194 this._timer = window.setTimeout(() => this._tick(), TYPING_INTERVAL_MS); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
195 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
196 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
197 _tick() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
198 this._timer = 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
199 const remaining = this._target.length - this._displayed.length; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
200 if (remaining <= 0) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
201 this._settle(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
202 return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
203 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
204 const amount = Math.max(1, Math.ceil(remaining / 80)); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
205 this._displayed = this._target.slice( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
206 0, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
207 this._displayed.length + amount, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
208 ); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
209 this._render(this._displayed); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
210 if (this._displayed === this._target) this._settle(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
211 else this._schedule(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
212 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
213 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
214 _settle() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
215 if (this._timer || this._displayed !== this._target) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
216 const waiters = this._waiters.splice(0); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
217 for (const resolve of waiters) resolve(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
218 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
219 } |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
220 |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
221 class MjjJrpgCharacter extends HTMLElement { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
222 static get observedAttributes() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
223 return ["state"]; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
224 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
225 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
226 connectedCallback() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
227 this.render(); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
228 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
229 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
230 attributeChangedCallback() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
231 if (this.isConnected) this.render(); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
232 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
233 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
234 render() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
235 const image = this.querySelector("[data-character]"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
236 if (!image) return; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
237 const state = CHARACTER_STATES[this.getAttribute("state")] || |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
238 CHARACTER_STATES.default; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
239 image.src = state.src; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
240 image.alt = state.alt; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
241 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
242 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
243 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
244 class MjjJrpgChat extends HTMLElement { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
245 connectedCallback() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
246 this._messages = this.querySelector("[data-messages]"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
247 this._viewport = this.querySelector("[data-zen-viewport]"); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
248 this._previousButton = this.querySelector("[data-turn-previous]"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
249 this._nextButton = this.querySelector("[data-turn-next]"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
250 this._position = this.querySelector("[data-turn-position]"); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
251 this._greetingText = ROLE_GREETINGS.guest; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
252 this._greetingAnimator = null; |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
253 this._turnSequence = 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
254 this._activeGroup = null; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
255 this._onNavigationClick = event => { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
256 const button = event.target.closest("button"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
257 if (!button || !this.contains(button) || button.disabled) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
258 if (button === this._previousButton) this._moveTurn(-1); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
259 else if (button === this._nextButton) this._moveTurn(1); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
260 }; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
261 this.addEventListener("click", this._onNavigationClick); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
262 this._refreshTurnGroups("start"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
263 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
264 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
265 disconnectedCallback() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
266 this.removeEventListener("click", this._onNavigationClick); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
267 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
268 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
269 appendMessage(speaker, text) { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
270 let group = this._activeGroup || "start"; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
271 if (speaker === "June") { |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
272 this._greetingAnimator?.cancel(); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
273 this._greetingAnimator = null; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
274 const greeting = this._messages?.querySelector("[data-greeting]"); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
275 if (greeting) this.setMessageStreaming(greeting, false); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
276 this._turnSequence++; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
277 group = `turn-${this._turnSequence}`; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
278 this._activeGroup = group; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
279 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
280 return this._createMessage(speaker, text, group, true); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
281 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
282 |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
283 setGreeting(text, animate = true) { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
284 this._greetingText = typeof text === "string" && text |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
285 ? text |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
286 : ROLE_GREETINGS.guest; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
287 this._showGreeting(animate); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
288 } |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
289 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
290 _showGreeting(animate) { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
291 if (!this._messages) return; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
292 this._greetingAnimator?.cancel(); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
293 this._greetingAnimator = null; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
294 this._messages.replaceChildren(); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
295 this._turnSequence = 0; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
296 this._activeGroup = null; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
297 const item = this._createMessage("Epi", "", "start", false); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
298 if (!item) return; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
299 item.dataset.greeting = "true"; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
300 this._refreshTurnGroups("start"); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
301 if (!animate) { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
302 this.setMessageText(item, this._greetingText); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
303 this.setMessageStreaming(item, false); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
304 return; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
305 } |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
306 this.setMessageStreaming(item, true); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
307 const animator = new StreamingTextAnimator(value => { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
308 this.setMessageText(item, value); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
309 }); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
310 this._greetingAnimator = animator; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
311 animator.complete(this._greetingText); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
312 void animator.waitForIdle().then(() => { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
313 if (this._greetingAnimator !== animator) return; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
314 this.setMessageStreaming(item, false); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
315 this._greetingAnimator = null; |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
316 }); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
317 } |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
318 |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
319 _createMessage(speaker, text, group, select) { |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
320 if (!this._messages) return; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
321 const item = document.createElement("li"); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
322 const speakerCell = document.createElement("span"); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
323 const name = document.createElement("strong"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
324 const copy = document.createElement("p"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
325 item.className = "jrpg-message"; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
326 item.dataset.speaker = speaker; |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
327 item.dataset.turnGroup = group; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
328 speakerCell.className = "jrpg-message-speaker"; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
329 if (speaker === "Epi") { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
330 const avatar = document.createElement("img"); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
331 avatar.className = "jrpg-message-avatar"; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
332 avatar.src = "/public/jrpg/shiba-default.webp"; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
333 avatar.alt = ""; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
334 avatar.setAttribute("aria-hidden", "true"); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
335 speakerCell.append(avatar); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
336 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
337 name.textContent = speaker; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
338 copy.textContent = text; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
339 speakerCell.append(name); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
340 item.append(speakerCell, copy); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
341 this._messages.append(item); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
342 this._refreshTurnGroups(select ? group : this._currentGroup); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
343 return item; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
344 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
345 |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
346 replaceMessages(turns) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
347 if (!this._messages) return; |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
348 this._greetingAnimator?.cancel(); |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
349 this._greetingAnimator = null; |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
350 this._messages.replaceChildren(); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
351 this._turnSequence = 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
352 this._activeGroup = null; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
353 const visibleTurns = turns.filter(turn => |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
354 ["user", "assistant"].includes(turn.role) |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
355 ); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
356 if (!visibleTurns.length) { |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
357 this._showGreeting(true); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
358 return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
359 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
360 let group = null; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
361 for (const turn of visibleTurns) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
362 if (turn.role === "user" || !group) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
363 this._turnSequence++; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
364 group = `turn-${this._turnSequence}`; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
365 this._activeGroup = group; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
366 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
367 this._createMessage( |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
368 turn.role === "user" ? "June" : "Epi", |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
369 turn.content || |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
370 (turn.status === "aborted" |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
371 ? "Quest cancelled." |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
372 : turn.status === "failed" |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
373 ? "The quest failed." |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
374 : ""), |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
375 group, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
376 false, |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
377 ); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
378 } |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
379 this._refreshTurnGroups(group); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
380 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
381 |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
382 startAssistantMessage() { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
383 return this.appendMessage("Epi", ""); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
384 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
385 |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
386 setMessageText(item, text) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
387 const copy = item?.querySelector("p"); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
388 if (copy) copy.textContent = text; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
389 this.scrollEnd(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
390 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
391 |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
392 setMessageStreaming(item, streaming) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
393 if (!item) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
394 if (streaming) item.dataset.streaming = "true"; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
395 else delete item.dataset.streaming; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
396 this._viewport?.setAttribute("aria-busy", String(streaming)); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
397 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
398 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
399 _refreshTurnGroups(preferredGroup) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
400 const groups = []; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
401 for (const item of this._messages?.children || []) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
402 const group = item.dataset.turnGroup || "start"; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
403 item.dataset.turnGroup = group; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
404 if (!groups.includes(group)) groups.push(group); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
405 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
406 this._turnGroups = groups; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
407 const preferredIndex = groups.indexOf(preferredGroup); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
408 const currentIndex = groups.indexOf(this._currentGroup); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
409 this._turnIndex = preferredIndex >= 0 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
410 ? preferredIndex |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
411 : currentIndex >= 0 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
412 ? currentIndex |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
413 : Math.max(0, groups.length - 1); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
414 this._showTurn(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
415 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
416 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
417 _moveTurn(offset) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
418 const nextIndex = Math.max( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
419 0, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
420 Math.min(this._turnGroups.length - 1, this._turnIndex + offset), |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
421 ); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
422 if (nextIndex === this._turnIndex) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
423 this._turnIndex = nextIndex; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
424 this._showTurn(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
425 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
426 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
427 _showTurn() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
428 const group = this._turnGroups?.[this._turnIndex]; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
429 this._currentGroup = group; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
430 for (const item of this._messages?.children || []) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
431 item.hidden = item.dataset.turnGroup !== group; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
432 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
433 if (this._previousButton) this._previousButton.disabled = this._turnIndex <= 0; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
434 if (this._nextButton) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
435 this._nextButton.disabled = |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
436 this._turnIndex >= (this._turnGroups?.length || 0) - 1; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
437 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
438 if (this._position) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
439 if (group === "start") { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
440 this._position.textContent = "START"; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
441 } else { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
442 const turns = this._turnGroups.filter(item => item !== "start"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
443 this._position.textContent = |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
444 `TURN ${turns.indexOf(group) + 1} / ${turns.length}`; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
445 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
446 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
447 this.scrollEnd(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
448 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
449 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
450 scrollEnd() { |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
451 requestAnimationFrame(() => { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
452 if (this._viewport) { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
453 this._viewport.scrollTop = this._viewport.scrollHeight; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
454 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
455 }); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
456 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
457 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
458 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
459 class MjjJrpgMenu extends HTMLElement { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
460 connectedCallback() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
461 this._onClick = event => { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
462 const button = event.target.closest("button[data-preview]"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
463 if (!button || !this.contains(button)) return; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
464 for (const item of this.querySelectorAll("button[data-preview]")) { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
465 item.setAttribute("aria-pressed", String(item === button)); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
466 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
467 this.dispatchEvent(new CustomEvent("mjj-jrpg-preview-change", { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
468 bubbles: true, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
469 detail: { selection: button.dataset.preview }, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
470 })); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
471 }; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
472 this.addEventListener("click", this._onClick); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
473 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
474 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
475 disconnectedCallback() { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
476 this.removeEventListener("click", this._onClick); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
477 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
478 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
479 |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
480 function sanitizeFetchedMain(main) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
481 for (const unsafe of main.querySelectorAll( |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
482 "embed, form, iframe, object, script, style, svg", |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
483 )) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
484 unsafe.remove(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
485 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
486 for (const element of main.querySelectorAll("*")) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
487 for (const attribute of [...element.attributes]) { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
488 const name = attribute.name.toLowerCase(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
489 if (name.startsWith("on") || name === "id" || name === "style") { |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
490 element.removeAttribute(attribute.name); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
491 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
492 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
493 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
494 for (const anchor of main.querySelectorAll("a")) { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
495 const href = anchor.getAttribute("href"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
496 if (!href || anchor.getAttribute("aria-disabled") === "true") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
497 anchor.remove(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
498 continue; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
499 } |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
500 const target = new URL( |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
501 href, |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
502 window.location.href, |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
503 ); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
504 anchor.href = target.href; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
505 if (target.origin !== window.location.origin) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
506 anchor.target = "_blank"; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
507 anchor.rel = "noreferrer"; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
508 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
509 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
510 for (const image of main.querySelectorAll("img")) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
511 const source = image.getAttribute("src") || ""; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
512 if (source.startsWith("/public/") && source.endsWith(".png")) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
513 image.src = source.replace(/\.png$/i, ".webp"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
514 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
515 image.loading = "lazy"; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
516 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
517 return main; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
518 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
519 |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
520 function sanitizeToolDetail(main) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
521 sanitizeFetchedMain(main); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
522 for (const textarea of main.querySelectorAll("textarea")) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
523 const sample = document.createElement("pre"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
524 sample.className = "jrpg-tool-source-sample"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
525 sample.textContent = textarea.value || textarea.textContent; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
526 textarea.replaceWith(sample); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
527 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
528 for (const inactive of main.querySelectorAll( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
529 "button, canvas, dialog, input, select, video, [hidden]", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
530 )) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
531 inactive.remove(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
532 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
533 for (const owner of main.querySelectorAll( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
534 "zen-button, zen-checkbox, zen-field, zen-input, zen-textarea", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
535 )) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
536 owner.replaceWith(...owner.childNodes); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
537 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
538 for (const label of main.querySelectorAll("label[for]")) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
539 label.removeAttribute("for"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
540 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
541 return main; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
542 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
543 |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
544 class MjjJrpgPreview extends HTMLElement { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
545 connectedCallback() { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
546 this._dialog = this.querySelector("dialog"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
547 this._onDialogClose = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
548 this._toolRequest = (this._toolRequest || 0) + 1; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
549 this.cleanupTool(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
550 }; |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
551 this._onClick = event => { |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
552 const trigger = event.target.closest("[data-zen-trigger]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
553 if (trigger) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
554 if (this.dataset.selection === "resume") void this.loadResume(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
555 if (this.dataset.selection === "blog") { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
556 this.show("blog"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
557 void this.loadBlogs(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
558 } |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
559 if (this.dataset.selection === "tools") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
560 this.show("tools"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
561 void this.openToolWorkspace(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
562 } |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
563 return; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
564 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
565 const blogEntry = event.target.closest("[data-blog-entry]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
566 if (blogEntry) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
567 void this.loadBlogDetail(blogEntry.dataset.blogUrl); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
568 return; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
569 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
570 const latestBlog = event.target.closest("[data-latest-blog]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
571 if (latestBlog && !event.metaKey && !event.ctrlKey && !event.shiftKey) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
572 event.preventDefault(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
573 this.querySelector("zen-dialog").open(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
574 void this.loadBlogDetail(latestBlog.dataset.blogUrl); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
575 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
576 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
577 const blogArchive = event.target.closest("[data-blog-archive]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
578 if (blogArchive) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
579 event.preventDefault(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
580 this.querySelector("zen-dialog").open(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
581 this.show("blog"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
582 void this.loadBlogs(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
583 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
584 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
585 const resumeModal = event.target.closest("[data-resume-modal]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
586 if (resumeModal) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
587 event.preventDefault(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
588 this.querySelector("zen-dialog").open(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
589 this.show("resume"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
590 void this.loadResume(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
591 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
592 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
593 const latestTool = event.target.closest("[data-latest-tool]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
594 if (latestTool && !event.metaKey && !event.ctrlKey && !event.shiftKey) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
595 event.preventDefault(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
596 this.querySelector("zen-dialog").open(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
597 void this.loadToolDetail(latestTool.dataset.toolUrl); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
598 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
599 }; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
600 this.addEventListener("click", this._onClick); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
601 this._dialog.addEventListener("close", this._onDialogClose); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
602 this.show(this.dataset.selection || "resume"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
603 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
604 |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
605 disconnectedCallback() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
606 this.removeEventListener("click", this._onClick); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
607 this._dialog?.removeEventListener("close", this._onDialogClose); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
608 this.cleanupTool(); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
609 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
610 |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
611 show(selection) { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
612 this.cleanupTool(); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
613 const preview = PREVIEWS[selection] || PREVIEWS.resume; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
614 this.dataset.selection = selection; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
615 this.querySelector("[data-preview-title]").textContent = preview.title; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
616 this.querySelector("[data-preview-copy]").textContent = preview.copy; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
617 this.querySelector("[data-dialog-title]").textContent = preview.title; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
618 this.querySelector("[data-dialog-copy]").textContent = preview.copy; |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
619 this.renderShowcase(preview.works); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
620 const link = this.querySelector("[data-preview-link]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
621 link.href = preview.url; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
622 link.setAttribute("aria-label", `Open ${preview.title}`); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
623 const resumeDossier = this.querySelector("[data-resume-dossier]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
624 const resumeDownload = this.querySelector("[data-resume-download]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
625 const blogBrowser = this.querySelector("[data-blog-browser]"); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
626 const toolBrowser = this.querySelector("[data-tool-browser]"); |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
627 const isResume = selection === "resume"; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
628 const isBlog = selection === "blog"; |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
629 const isTools = selection === "tools"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
630 this._dialog.dataset.detailMode = isTools ? "tools" : "content"; |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
631 resumeDossier.hidden = !isResume; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
632 resumeDownload.hidden = !isResume; |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
633 this.querySelector("[data-dialog-actions]").hidden = !isResume; |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
634 blogBrowser.hidden = !isBlog; |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
635 toolBrowser.hidden = !isTools; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
636 this.querySelector("[data-dialog-copy]").hidden = |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
637 isResume || isBlog || isTools; |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
638 if (!isBlog) this._blogRequest = (this._blogRequest || 0) + 1; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
639 if (isBlog) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
640 const status = this.querySelector("[data-blog-status]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
641 status.hidden = false; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
642 status.textContent = "Select a blog to inspect."; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
643 this.querySelector("[data-blog-content]").replaceChildren(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
644 for (const button of this.querySelectorAll("[data-blog-entry]")) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
645 button.setAttribute("aria-pressed", "false"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
646 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
647 void this.loadBlogs(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
648 } |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
649 if (!isTools) this._toolRequest = (this._toolRequest || 0) + 1; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
650 if (isTools) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
651 const status = this.querySelector("[data-tool-status]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
652 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
653 status.textContent = "Select a tool to inspect."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
654 this.querySelector("[data-tool-content]").replaceChildren(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
655 void this.loadTools(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
656 } |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
657 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
658 |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
659 renderShowcase(works, latestBlogs = false, latestKind = null) { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
660 const showcase = this.querySelector("[data-work-showcase]"); |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
661 showcase.replaceChildren(...works.map(work => { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
662 const item = document.createElement("li"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
663 const link = document.createElement("a"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
664 const label = document.createElement("span"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
665 const detail = document.createElement("small"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
666 link.href = work.url; |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
667 if (latestBlogs) { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
668 if (work.modal === "blog") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
669 link.dataset.blogArchive = ""; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
670 } else { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
671 link.dataset.latestBlog = ""; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
672 link.dataset.blogUrl = work.url; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
673 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
674 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
675 if (work.modal === "resume") link.dataset.resumeModal = ""; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
676 if (latestKind === "tool") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
677 link.dataset.latestTool = ""; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
678 link.dataset.toolUrl = work.url; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
679 const icon = document.createElement("zen-icon"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
680 icon.setAttribute("name", TOOL_ICON_NAMES[work.url] || "settings"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
681 link.prepend(icon); |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
682 } |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
683 if (new URL(work.url, window.location.href).origin !== window.location.origin) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
684 link.target = "_blank"; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
685 link.rel = "noreferrer"; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
686 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
687 label.textContent = work.label; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
688 detail.textContent = work.detail; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
689 link.append(label, detail); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
690 item.append(link); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
691 return item; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
692 })); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
693 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
694 |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
695 async loadResume() { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
696 if (this._resumeLoaded || this._resumeLoading) return; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
697 this._resumeLoading = true; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
698 const status = this.querySelector("[data-resume-status]"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
699 const content = this.querySelector("[data-resume-content]"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
700 try { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
701 const response = await fetch("/resume", { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
702 headers: { Accept: "text/html" }, |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
703 }); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
704 if (!response.ok) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
705 throw new Error(`Resume request failed (${response.status})`); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
706 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
707 const documentCopy = new DOMParser().parseFromString( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
708 await response.text(), |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
709 "text/html", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
710 ); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
711 const resume = documentCopy.querySelector("main"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
712 if (!resume) throw new Error("Resume content is unavailable"); |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
713 sanitizeFetchedMain(resume); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
714 content.replaceChildren(...resume.childNodes); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
715 status.hidden = true; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
716 this._resumeLoaded = true; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
717 } catch (error) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
718 status.textContent = `Unable to load resume: ${error.message}`; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
719 } finally { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
720 this._resumeLoading = false; |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
721 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
722 } |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
723 |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
724 async loadBlogs() { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
725 if (this._blogs) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
726 if (this.dataset.selection === "blog") { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
727 this.renderShowcase([ |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
728 ...this._blogs.slice(0, 4), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
729 { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
730 detail: "Full archive", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
731 label: "All blogs", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
732 modal: "blog", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
733 url: "/blog", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
734 }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
735 ], true); |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
736 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
737 return true; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
738 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
739 if (this._blogsLoading) return this._blogsLoading; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
740 const list = this.querySelector("[data-blog-list]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
741 this._blogsLoading = (async () => { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
742 const response = await fetch("/blog", { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
743 headers: { Accept: "text/html" }, |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
744 }); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
745 if (!response.ok) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
746 throw new Error(`Blog archive request failed (${response.status})`); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
747 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
748 const documentCopy = new DOMParser().parseFromString( |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
749 await response.text(), |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
750 "text/html", |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
751 ); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
752 this._blogs = [...documentCopy.querySelectorAll( |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
753 'main li a[href^="/blog/"]', |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
754 )].map(anchor => ({ |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
755 date: anchor.closest("li")?.querySelector("span")?.textContent.trim() || |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
756 "Archive", |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
757 detail: anchor.closest("li")?.querySelector("span")?.textContent.trim() || |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
758 "Archive", |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
759 label: anchor.textContent.trim(), |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
760 url: anchor.getAttribute("href"), |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
761 })); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
762 if (!this._blogs.length) throw new Error("No blog entries were found"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
763 this.renderBlogList(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
764 if (this.dataset.selection === "blog") { |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
765 this.renderShowcase([ |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
766 ...this._blogs.slice(0, 4), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
767 { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
768 detail: "Full archive", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
769 label: "All blogs", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
770 modal: "blog", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
771 url: "/blog", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
772 }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
773 ], true); |
|
262
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
774 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
775 return true; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
776 })().catch(error => { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
777 list.replaceChildren(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
778 const item = document.createElement("li"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
779 item.textContent = `Unable to load blogs: ${error.message}`; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
780 list.append(item); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
781 return false; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
782 }).finally(() => { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
783 this._blogsLoading = null; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
784 }); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
785 return this._blogsLoading; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
786 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
787 |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
788 renderBlogList() { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
789 const list = this.querySelector("[data-blog-list]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
790 list.replaceChildren(...this._blogs.map(blog => { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
791 const item = document.createElement("li"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
792 const owner = document.createElement("zen-button"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
793 const button = document.createElement("button"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
794 const title = document.createElement("span"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
795 const date = document.createElement("small"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
796 owner.setAttribute("appearance", "plain"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
797 owner.setAttribute("size", "sm"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
798 button.type = "button"; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
799 button.dataset.blogEntry = ""; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
800 button.dataset.blogUrl = blog.url; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
801 title.textContent = blog.label; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
802 date.textContent = blog.date; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
803 button.append(title, date); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
804 owner.append(button); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
805 item.append(owner); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
806 return item; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
807 })); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
808 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
809 |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
810 async loadBlogDetail(url) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
811 if (!await this.loadBlogs()) return; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
812 const blog = this._blogs.find(item => item.url === url); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
813 const status = this.querySelector("[data-blog-status]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
814 const content = this.querySelector("[data-blog-content]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
815 if (!blog) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
816 status.hidden = false; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
817 status.textContent = "Unable to load blog: unknown entry."; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
818 return; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
819 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
820 const request = (this._blogRequest || 0) + 1; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
821 this._blogRequest = request; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
822 status.hidden = false; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
823 status.textContent = `Loading ${blog.label}...`; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
824 content.replaceChildren(); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
825 this.querySelector("[data-dialog-title]").textContent = blog.label; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
826 const fullPage = this.querySelector("[data-preview-link]"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
827 fullPage.href = blog.url; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
828 fullPage.setAttribute("aria-label", `Open ${blog.label}`); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
829 for (const button of this.querySelectorAll("[data-blog-entry]")) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
830 button.setAttribute( |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
831 "aria-pressed", |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
832 String(button.dataset.blogUrl === blog.url), |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
833 ); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
834 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
835 try { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
836 const response = await fetch(blog.url, { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
837 headers: { Accept: "text/html" }, |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
838 }); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
839 if (!response.ok) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
840 throw new Error(`Blog request failed (${response.status})`); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
841 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
842 const documentCopy = new DOMParser().parseFromString( |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
843 await response.text(), |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
844 "text/html", |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
845 ); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
846 const article = documentCopy.querySelector("main"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
847 if (!article) throw new Error("Blog content is unavailable"); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
848 sanitizeFetchedMain(article); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
849 if (request !== this._blogRequest || this.dataset.selection !== "blog") { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
850 return; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
851 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
852 content.replaceChildren(...article.childNodes); |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
853 status.hidden = true; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
854 } catch (error) { |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
855 if (request !== this._blogRequest) return; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
856 status.hidden = false; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
857 status.textContent = `Unable to load blog: ${error.message}`; |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
858 } |
|
0f45474c1b1a
Add cyberpunk JRPG blog browser
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
261
diff
changeset
|
859 } |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
860 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
861 async loadTools() { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
862 if (this._tools) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
863 if (this.dataset.selection === "tools") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
864 this.renderShowcase(this._tools, false, "tool"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
865 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
866 return true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
867 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
868 if (this._toolsLoading) return this._toolsLoading; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
869 this._toolsLoading = (async () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
870 const response = await fetch("/tools", { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
871 headers: { Accept: "text/html" }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
872 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
873 if (!response.ok) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
874 throw new Error(`Tools request failed (${response.status})`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
875 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
876 const documentCopy = new DOMParser().parseFromString( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
877 await response.text(), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
878 "text/html", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
879 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
880 this._tools = [...documentCopy.querySelectorAll("main li a[href]")].map( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
881 anchor => ({ |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
882 detail: anchor.getAttribute("href").startsWith("/notes") |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
883 ? "Writing" |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
884 : "Utility", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
885 label: anchor.textContent.trim(), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
886 url: anchor.getAttribute("href"), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
887 }), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
888 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
889 if (!this._tools.length) throw new Error("No tools were found"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
890 if (this.dataset.selection === "tools") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
891 this.renderShowcase(this._tools, false, "tool"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
892 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
893 return true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
894 })().catch(error => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
895 const status = this.querySelector("[data-tool-status]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
896 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
897 status.textContent = `Unable to load tools: ${error.message}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
898 return false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
899 }).finally(() => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
900 this._toolsLoading = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
901 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
902 return this._toolsLoading; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
903 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
904 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
905 async openToolWorkspace() { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
906 if (!await this.loadTools() || this.dataset.selection !== "tools") return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
907 await this.loadToolDetail(this._activeToolUrl || this._tools[0].url); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
908 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
909 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
910 async loadToolDetail(url) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
911 const request = (this._toolRequest || 0) + 1; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
912 this._toolRequest = request; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
913 if (!await this.loadTools()) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
914 if (request !== this._toolRequest || this.dataset.selection !== "tools") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
915 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
916 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
917 const tool = this._tools.find(item => item.url === url); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
918 const status = this.querySelector("[data-tool-status]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
919 const content = this.querySelector("[data-tool-content]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
920 if (!tool) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
921 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
922 status.textContent = "Unable to load tool: unknown entry."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
923 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
924 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
925 this._activeToolUrl = tool.url; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
926 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
927 status.textContent = `Loading ${tool.label}...`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
928 this.cleanupTool(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
929 content.replaceChildren(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
930 this.querySelector("[data-dialog-title]").textContent = tool.label; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
931 const fullPage = this.querySelector("[data-preview-link]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
932 fullPage.href = tool.url; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
933 fullPage.setAttribute("aria-label", `Open ${tool.label}`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
934 if (tool.url === "/tools/markdown_to_html") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
935 await this.renderMarkdownTool(content, status, request); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
936 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
937 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
938 if (tool.url === "/tools/file_converter") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
939 this.renderFileConverterTool(content, status); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
940 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
941 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
942 if (tool.url === "/tools/hls_player") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
943 await this.renderHlsTool(content, status, request); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
944 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
945 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
946 if (tool.url === "/tools/latex_editor") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
947 this.renderLatexTool(content, status); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
948 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
949 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
950 if (tool.url === "/notes") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
951 const heading = document.createElement("h1"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
952 const description = document.createElement("p"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
953 const privacy = document.createElement("p"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
954 heading.textContent = "Personal Notes"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
955 description.textContent = |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
956 "A private browser-based writing workspace with rich-text editing and server-backed persistence."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
957 privacy.textContent = |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
958 "The interactive editor and authentication flow are available on the full Notes page."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
959 content.replaceChildren( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
960 this.createReadonlyToolNote(), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
961 heading, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
962 description, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
963 privacy, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
964 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
965 status.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
966 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
967 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
968 try { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
969 const response = await fetch(tool.url, { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
970 headers: { Accept: "text/html" }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
971 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
972 if (!response.ok) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
973 throw new Error(`Tool request failed (${response.status})`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
974 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
975 const documentCopy = new DOMParser().parseFromString( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
976 await response.text(), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
977 "text/html", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
978 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
979 const detail = documentCopy.querySelector("main, .container") || |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
980 documentCopy.body; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
981 if (!detail) throw new Error("Tool content is unavailable"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
982 sanitizeToolDetail(detail); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
983 if (request !== this._toolRequest || this.dataset.selection !== "tools") { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
984 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
985 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
986 content.replaceChildren( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
987 this.createReadonlyToolNote(), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
988 ...detail.childNodes, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
989 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
990 status.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
991 } catch (error) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
992 if (request !== this._toolRequest) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
993 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
994 status.textContent = `Unable to load tool: ${error.message}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
995 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
996 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
997 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
998 async renderMarkdownTool(content, status, request) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
999 content.innerHTML = ` |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1000 <section class="jrpg-functional-tool" data-functional-tool="markdown"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1001 <div class="jrpg-tool-panes"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1002 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1003 <h2><zen-icon name="code"></zen-icon> Markdown source</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1004 <zen-field appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1005 <label for="jrpgMarkdownSource">Markdown</label> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1006 <textarea id="jrpgMarkdownSource" data-markdown-source></textarea> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1007 </zen-field> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1008 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1009 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1010 <h2><zen-icon name="check"></zen-icon> Converted HTML</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1011 <div class="jrpg-markdown-output" data-markdown-output></div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1012 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1013 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1014 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1015 `; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1016 const source = content.querySelector("[data-markdown-source]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1017 const output = content.querySelector("[data-markdown-output]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1018 source.value = [ |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1019 "# JRPG Markdown", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1020 "", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1021 "Edit this **Markdown** to update the converted panel.", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1022 "", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1023 "- Bazel-built WASM", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1024 "- Sanitized HTML output", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1025 ].join("\n"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1026 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1027 status.textContent = "Loading the Markdown converter..."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1028 try { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1029 this._markdownModule ||= import("/markdown_to_html_bin.js") |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1030 .then(module => module.default()); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1031 const module = await this._markdownModule; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1032 if (request !== this._toolRequest || !source.isConnected) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1033 const convertMarkdown = module.cwrap( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1034 "markdown_to_html", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1035 "number", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1036 ["string"], |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1037 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1038 const freeMarkdown = module.cwrap("markdown_free", null, ["number"]); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1039 const convert = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1040 const pointer = convertMarkdown(source.value); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1041 const html = module.UTF8ToString(pointer); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1042 freeMarkdown(pointer); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1043 const documentCopy = new DOMParser().parseFromString(html, "text/html"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1044 sanitizeFetchedMain(documentCopy.body); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1045 output.replaceChildren(...documentCopy.body.childNodes); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1046 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1047 source.addEventListener("input", convert); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1048 convert(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1049 status.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1050 } catch (error) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1051 this._markdownModule = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1052 if (request !== this._toolRequest) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1053 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1054 status.textContent = `Unable to start Markdown: ${error.message}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1055 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1056 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1057 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1058 renderFileConverterTool(content, status) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1059 content.innerHTML = ` |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1060 <section class="jrpg-functional-tool" data-functional-tool="converter"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1061 <p class="jrpg-tool-status" data-converter-status> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1062 Choose a file in either panel. |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1063 </p> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1064 <div class="jrpg-tool-panes"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1065 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1066 <h2><zen-icon name="file"></zen-icon> Image to WebP</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1067 <zen-field appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1068 <label for="jrpgImageInput">Image file</label> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1069 <input id="jrpgImageInput" data-converter-input="image" type="file" accept="image/*"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1070 </zen-field> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1071 <zen-button appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1072 <button type="button" data-convert-kind="image"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1073 Convert image <zen-icon name="arrow-right"></zen-icon> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1074 </button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1075 </zen-button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1076 <a data-converter-download="image" hidden>Download WebP</a> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1077 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1078 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1079 <h2><zen-icon name="play"></zen-icon> Video to MP4</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1080 <zen-field appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1081 <label for="jrpgVideoInput">Video file</label> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1082 <input id="jrpgVideoInput" data-converter-input="video" type="file" accept="video/*"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1083 </zen-field> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1084 <zen-button appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1085 <button type="button" data-convert-kind="video"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1086 Convert video <zen-icon name="arrow-right"></zen-icon> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1087 </button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1088 </zen-button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1089 <a data-converter-download="video" hidden>Download MP4</a> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1090 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1091 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1092 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1093 `; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1094 const toolStatus = content.querySelector("[data-converter-status]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1095 let disposed = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1096 const downloads = new Set(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1097 const discardDownload = url => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1098 if (!url) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1099 downloads.delete(url); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1100 void fetch(url, { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1101 method: "DELETE", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1102 keepalive: true, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1103 }).then(response => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1104 if (!response.ok && response.status !== 404) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1105 console.warn(`Unable to discard converted file (${response.status})`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1106 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1107 }).catch(error => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1108 console.warn(`Unable to discard converted file: ${error.message}`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1109 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1110 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1111 const convert = async kind => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1112 const input = content.querySelector(`[data-converter-input="${kind}"]`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1113 const button = content.querySelector(`[data-convert-kind="${kind}"]`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1114 const download = content.querySelector( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1115 `[data-converter-download="${kind}"]`, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1116 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1117 const file = input.files?.[0]; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1118 if (!file) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1119 toolStatus.textContent = `Choose a ${kind} file first.`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1120 toolStatus.dataset.state = "error"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1121 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1122 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1123 button.disabled = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1124 discardDownload(download.dataset.cleanupUrl); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1125 delete download.dataset.cleanupUrl; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1126 download.removeAttribute("href"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1127 download.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1128 toolStatus.textContent = `Converting ${file.name}...`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1129 toolStatus.dataset.state = "working"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1130 try { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1131 const endpoint = kind === "image" |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1132 ? "/api/convert/image-to-webp" |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1133 : "/api/convert/video-to-mp4"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1134 const response = await fetch(endpoint, { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1135 method: "POST", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1136 body: file, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1137 headers: { "Content-Type": file.type || "application/octet-stream" }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1138 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1139 if (!response.ok) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1140 throw new Error(await response.text() || `Conversion failed (${response.status})`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1141 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1142 const result = await response.json(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1143 if (disposed || !download.isConnected) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1144 discardDownload(result.download_url); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1145 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1146 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1147 download.href = result.download_url; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1148 download.dataset.cleanupUrl = result.download_url; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1149 downloads.add(result.download_url); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1150 download.download = file.name.replace(/\.[^/.]+$/, "") + |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1151 (kind === "image" ? ".webp" : ".mp4"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1152 download.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1153 toolStatus.textContent = "Conversion complete."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1154 toolStatus.dataset.state = "ready"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1155 } catch (error) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1156 if (!disposed) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1157 toolStatus.textContent = `Conversion failed: ${error.message}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1158 toolStatus.dataset.state = "error"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1159 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1160 } finally { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1161 if (button.isConnected) button.disabled = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1162 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1163 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1164 for (const button of content.querySelectorAll("[data-convert-kind]")) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1165 button.addEventListener("click", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1166 void convert(button.dataset.convertKind); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1167 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1168 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1169 for (const download of content.querySelectorAll("[data-converter-download]")) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1170 download.addEventListener("click", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1171 downloads.delete(download.dataset.cleanupUrl); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1172 delete download.dataset.cleanupUrl; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1173 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1174 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1175 this._toolCleanup = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1176 disposed = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1177 for (const download of [...downloads]) discardDownload(download); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1178 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1179 status.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1180 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1181 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1182 async renderHlsTool(content, status, request) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1183 content.innerHTML = ` |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1184 <section class="jrpg-functional-tool" data-functional-tool="hls"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1185 <div class="jrpg-tool-panes"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1186 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1187 <h2><zen-icon name="file"></zen-icon> HLS source</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1188 <zen-field appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1189 <label for="jrpgHlsUrl">Playlist URL</label> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1190 <input |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1191 id="jrpgHlsUrl" |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1192 data-hls-url |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1193 type="url" |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1194 value="/public/hls-sample/h264-ts-stream.m3u8" |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1195 > |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1196 </zen-field> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1197 <div class="jrpg-tool-actions"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1198 <zen-button appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1199 <button type="button" data-hls-load> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1200 Load URL <zen-icon name="arrow-right"></zen-icon> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1201 </button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1202 </zen-button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1203 <zen-button appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1204 <button type="button" data-hls-sample> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1205 Load sample <zen-icon name="play"></zen-icon> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1206 </button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1207 </zen-button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1208 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1209 <p class="jrpg-tool-status" data-hls-status>Loading player engine...</p> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1210 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1211 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1212 <h2><zen-icon name="play"></zen-icon> Playback</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1213 <video data-hls-video controls playsinline preload="metadata"></video> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1214 <dl class="jrpg-tool-details" data-hls-details hidden> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1215 <div><dt>Playback</dt><dd data-detail="mode">-</dd></div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1216 <div><dt>Segments</dt><dd data-detail="segments">-</dd></div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1217 <div><dt>Duration</dt><dd data-detail="duration">-</dd></div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1218 <div><dt>Codec</dt><dd data-detail="codecs">-</dd></div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1219 </dl> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1220 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1221 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1222 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1223 `; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1224 try { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1225 await loadScript("/public/hls.min.js"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1226 await loadScript("/tools/hls_player/hls-player.js"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1227 if (request !== this._toolRequest || !content.isConnected) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1228 const video = content.querySelector("[data-hls-video]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1229 const playerStatus = content.querySelector("[data-hls-status]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1230 const details = content.querySelector("[data-hls-details]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1231 const url = content.querySelector("[data-hls-url]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1232 const player = new window.HlsPlayerModule.HlsPlayer(video, { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1233 statusElement: playerStatus, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1234 detailsElement: details, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1235 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1236 const load = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1237 void player.load(url.value.trim()).catch(() => {}); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1238 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1239 content.querySelector("[data-hls-load]").addEventListener("click", load); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1240 content.querySelector("[data-hls-sample]").addEventListener("click", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1241 url.value = "/public/hls-sample/h264-ts-stream.m3u8"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1242 load(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1243 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1244 playerStatus.textContent = "Ready to load a playlist."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1245 playerStatus.dataset.state = "ready"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1246 this._toolCleanup = () => player.destroy(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1247 status.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1248 } catch (error) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1249 if (request !== this._toolRequest) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1250 status.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1251 status.textContent = `Unable to start HLS: ${error.message}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1252 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1253 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1254 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1255 renderLatexTool(content, status) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1256 content.innerHTML = ` |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1257 <section class="jrpg-functional-tool" data-functional-tool="latex"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1258 <p class="jrpg-tool-status" data-latex-status> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1259 Edit the source, then compile the PDF. |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1260 </p> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1261 <div class="jrpg-tool-panes"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1262 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1263 <div class="jrpg-tool-pane-heading"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1264 <h2><zen-icon name="code"></zen-icon> LaTeX source</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1265 <span data-latex-size></span> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1266 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1267 <zen-field appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1268 <label for="jrpgLatexSource">document.tex</label> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1269 <textarea id="jrpgLatexSource" data-latex-source></textarea> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1270 </zen-field> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1271 <div class="jrpg-tool-actions"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1272 <zen-button appearance="plain" size="md"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1273 <button type="button" data-latex-compile> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1274 Compile PDF <zen-icon name="file"></zen-icon> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1275 </button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1276 </zen-button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1277 <zen-button appearance="plain" size="md" data-latex-download hidden> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1278 <a download="document.pdf"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1279 Download PDF <zen-icon name="download"></zen-icon> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1280 </a> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1281 </zen-button> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1282 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1283 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1284 <section class="jrpg-tool-pane jrpg-tool-window"> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1285 <h2><zen-icon name="file"></zen-icon> PDF preview</h2> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1286 <iframe data-latex-preview title="Compiled LaTeX PDF preview"></iframe> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1287 <pre data-latex-diagnostics hidden></pre> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1288 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1289 </div> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1290 </section> |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1291 `; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1292 const source = content.querySelector("[data-latex-source]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1293 const compileButton = content.querySelector("[data-latex-compile]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1294 const toolStatus = content.querySelector("[data-latex-status]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1295 const size = content.querySelector("[data-latex-size]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1296 const preview = content.querySelector("[data-latex-preview]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1297 const diagnostics = content.querySelector("[data-latex-diagnostics]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1298 const downloadOwner = content.querySelector("[data-latex-download]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1299 const download = downloadOwner.querySelector("a"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1300 source.value = String.raw`\documentclass[11pt]{article} |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1301 \usepackage[margin=1in]{geometry} |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1302 \title{JRPG LaTeX} |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1303 \author{MrJuneJune} |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1304 \begin{document} |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1305 \maketitle |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1306 This PDF was compiled from the cyberpunk tool modal. |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1307 \end{document}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1308 let controller = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1309 let pdfUrl = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1310 let compileGeneration = 0; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1311 const clearPdf = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1312 if (pdfUrl) URL.revokeObjectURL(pdfUrl); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1313 pdfUrl = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1314 preview.src = "about:blank"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1315 preview.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1316 diagnostics.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1317 download.removeAttribute("href"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1318 downloadOwner.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1319 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1320 const updateSize = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1321 const bytes = new TextEncoder().encode(source.value).byteLength; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1322 size.textContent = `${bytes.toLocaleString()} / 65,536 bytes`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1323 return bytes; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1324 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1325 const compile = async () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1326 const generation = ++compileGeneration; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1327 clearPdf(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1328 const bytes = updateSize(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1329 if (!source.value.trim() || bytes > 64 * 1024) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1330 toolStatus.textContent = bytes > 64 * 1024 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1331 ? "Source exceeds 64 KiB." |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1332 : "Write LaTeX before compiling."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1333 toolStatus.dataset.state = "error"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1334 return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1335 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1336 controller?.abort(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1337 const requestController = new AbortController(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1338 controller = requestController; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1339 compileButton.disabled = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1340 toolStatus.textContent = "Compiling on the server..."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1341 toolStatus.dataset.state = "working"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1342 try { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1343 const response = await fetch("/api/latex/render", { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1344 method: "POST", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1345 headers: { "Content-Type": "text/plain; charset=utf-8" }, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1346 body: source.value, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1347 cache: "no-store", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1348 signal: requestController.signal, |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1349 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1350 if (generation !== compileGeneration) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1351 if (!response.ok) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1352 throw new Error(await response.text() || `Compilation failed (${response.status})`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1353 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1354 const blob = await response.blob(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1355 if (generation !== compileGeneration) return; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1356 if (blob.type !== "application/pdf" || blob.size < 5) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1357 throw new Error("The server returned an invalid PDF."); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1358 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1359 if (pdfUrl) URL.revokeObjectURL(pdfUrl); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1360 pdfUrl = URL.createObjectURL(blob); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1361 preview.src = pdfUrl; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1362 preview.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1363 diagnostics.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1364 download.href = pdfUrl; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1365 downloadOwner.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1366 toolStatus.textContent = `PDF ready (${Math.ceil(blob.size / 1024)} KiB).`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1367 toolStatus.dataset.state = "ready"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1368 } catch (error) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1369 if (error.name !== "AbortError" && generation === compileGeneration) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1370 diagnostics.textContent = error.message; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1371 diagnostics.hidden = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1372 preview.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1373 toolStatus.textContent = "Compilation failed."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1374 toolStatus.dataset.state = "error"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1375 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1376 } finally { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1377 if (controller === requestController) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1378 controller = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1379 compileButton.disabled = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1380 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1381 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1382 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1383 source.addEventListener("input", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1384 compileGeneration++; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1385 controller?.abort(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1386 controller = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1387 compileButton.disabled = false; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1388 clearPdf(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1389 updateSize(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1390 toolStatus.textContent = "Changes ready to compile."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1391 toolStatus.dataset.state = "working"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1392 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1393 compileButton.addEventListener("click", () => void compile()); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1394 updateSize(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1395 this._toolCleanup = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1396 compileGeneration++; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1397 controller?.abort(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1398 clearPdf(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1399 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1400 status.hidden = true; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1401 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1402 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1403 cleanupTool() { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1404 this._toolCleanup?.(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1405 this._toolCleanup = null; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1406 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1407 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1408 createReadonlyToolNote() { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1409 const introduction = document.createElement("p"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1410 introduction.className = "jrpg-tool-readonly-note"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1411 introduction.textContent = |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1412 "Read-only preview. Open the full page to use this tool."; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1413 return introduction; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
1414 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1415 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1416 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1417 /* ===================================================================== |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1418 MjjConversationArchive — archive panel within the scene |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1419 ===================================================================== */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1420 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1421 class MjjConversationArchive extends HTMLElement { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1422 connectedCallback() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1423 this._list = this.querySelector("[data-archive-list]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1424 this._status = this.querySelector("[data-archive-status]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1425 this._loadMoreOwner = this.querySelector("[data-archive-load-more-owner]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1426 this._loadMoreButton = this.querySelector("[data-archive-load-more]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1427 this._newButton = this.querySelector("[data-archive-new]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1428 this._closeButton = this.querySelector("[data-archive-close]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1429 this._deleteDialog = this.querySelector("[data-archive-delete-dialog]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1430 this._deleteNameEl = this.querySelector("[data-archive-delete-name]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1431 this._deleteCancelButton = this.querySelector("[data-archive-delete-cancel]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1432 this._deleteConfirmButton = this.querySelector("[data-archive-delete-confirm]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1433 this._renameDialog = this.querySelector("[data-archive-rename-dialog]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1434 this._renameInput = this.querySelector("[data-archive-rename-input]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1435 this._renameForm = this.querySelector("[data-archive-rename-form]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1436 this._renameCancelButton = this.querySelector("[data-archive-rename-cancel]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1437 this._pendingDeleteId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1438 this._pendingDeleteTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1439 this._pendingRenameId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1440 this._pendingRenameTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1441 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1442 this._closeButton?.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1443 this.dispatchEvent(new CustomEvent("mjj-archive-toggle", { bubbles: true })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1444 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1445 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1446 this._newButton?.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1447 this.dispatchEvent(new CustomEvent("mjj-archive-new", { bubbles: true })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1448 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1449 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1450 this._loadMoreButton?.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1451 this.dispatchEvent(new CustomEvent("mjj-archive-load-more", { bubbles: true })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1452 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1453 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1454 this._deleteCancelButton?.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1455 this._deleteDialog?.close(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1456 const t = this._pendingDeleteTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1457 this._pendingDeleteId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1458 this._pendingDeleteTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1459 t?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1460 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1461 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1462 this._deleteConfirmButton?.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1463 const id = this._pendingDeleteId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1464 const trigger = this._pendingDeleteTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1465 this._deleteDialog?.close(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1466 this._pendingDeleteId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1467 this._pendingDeleteTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1468 if (id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1469 this.dispatchEvent(new CustomEvent("mjj-archive-delete", { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1470 bubbles: true, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1471 detail: { id, trigger }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1472 })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1473 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1474 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1475 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1476 this._deleteDialog?.addEventListener("close", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1477 const t = this._pendingDeleteTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1478 this._pendingDeleteId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1479 this._pendingDeleteTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1480 t?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1481 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1482 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1483 this._renameCancelButton?.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1484 this._renameDialog?.close(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1485 const t = this._pendingRenameTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1486 this._pendingRenameId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1487 this._pendingRenameTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1488 t?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1489 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1490 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1491 this._renameForm?.addEventListener("submit", event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1492 event.preventDefault(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1493 const id = this._pendingRenameId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1494 const trigger = this._pendingRenameTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1495 const newTitle = this._renameInput?.value.trim(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1496 if (!id || !newTitle) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1497 this._renameDialog?.close(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1498 this._pendingRenameId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1499 this._pendingRenameTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1500 this.dispatchEvent(new CustomEvent("mjj-archive-rename", { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1501 bubbles: true, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1502 detail: { id, newTitle, trigger }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1503 })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1504 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1505 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1506 this._renameDialog?.addEventListener("close", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1507 const t = this._pendingRenameTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1508 this._pendingRenameId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1509 this._pendingRenameTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1510 t?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1511 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1512 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1513 this._onListClick = event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1514 const openButton = event.target.closest("[data-conv-open]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1515 if (openButton) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1516 const id = openButton.closest("[data-conv-item]")?._convId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1517 if (id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1518 this.dispatchEvent(new CustomEvent("mjj-archive-open", { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1519 bubbles: true, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1520 detail: { id }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1521 })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1522 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1523 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1524 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1525 const renameButton = event.target.closest("[data-conv-rename]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1526 if (renameButton) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1527 const item = renameButton.closest("[data-conv-item]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1528 if (item?._convId) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1529 this._pendingRenameId = item._convId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1530 this._pendingRenameTrigger = renameButton; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1531 if (this._renameInput) this._renameInput.value = item._convTitle || ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1532 this._renameDialog?.showModal(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1533 requestAnimationFrame(() => { this._renameInput?.select(); }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1534 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1535 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1536 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1537 const deleteButton = event.target.closest("[data-conv-delete]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1538 if (deleteButton) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1539 const item = deleteButton.closest("[data-conv-item]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1540 if (item?._convId) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1541 this._pendingDeleteId = item._convId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1542 this._pendingDeleteTrigger = deleteButton; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1543 if (this._deleteNameEl) this._deleteNameEl.textContent = item._convTitle || ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1544 this._deleteDialog?.showModal(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1545 requestAnimationFrame(() => { this._deleteConfirmButton?.focus(); }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1546 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1547 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1548 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1549 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1550 this._list?.addEventListener("click", this._onListClick); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1551 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1552 this._onListKeydown = event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1553 if (!["ArrowUp", "ArrowDown"].includes(event.key)) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1554 const items = [...(this._list?.querySelectorAll("[data-conv-open]") || [])]; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1555 const index = items.indexOf(document.activeElement); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1556 if (index < 0) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1557 event.preventDefault(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1558 const next = event.key === "ArrowDown" |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1559 ? items[Math.min(index + 1, items.length - 1)] |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1560 : items[Math.max(index - 1, 0)]; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1561 next?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1562 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1563 this._list?.addEventListener("keydown", this._onListKeydown); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1564 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1565 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1566 disconnectedCallback() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1567 this._list?.removeEventListener("click", this._onListClick); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1568 this._list?.removeEventListener("keydown", this._onListKeydown); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1569 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1570 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1571 setConversations(conversations, cursor, append = false) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1572 if (!this._list) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1573 if (!append) this._list.replaceChildren(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1574 for (const conv of conversations) this._list.append(this._createItem(conv)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1575 if (this._loadMoreOwner) this._loadMoreOwner.hidden = !cursor; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1576 if (!conversations.length && !append) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1577 this._showStatus("No conversations yet. Start a new one!"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1578 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1579 this._hideStatus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1580 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1581 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1582 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1583 setCurrentId(id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1584 for (const button of (this._list?.querySelectorAll("[data-conv-open]") || [])) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1585 const isCurrent = id && button.closest("[data-conv-item]")?._convId === id; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1586 button.setAttribute("aria-current", String(Boolean(isCurrent))); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1587 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1588 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1589 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1590 addConversation(conv) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1591 if (!this._list) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1592 this._list.prepend(this._createItem(conv)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1593 this._hideStatus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1594 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1595 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1596 updateConversation(conv) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1597 if (!this._list) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1598 for (const item of this._list.querySelectorAll("[data-conv-item]")) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1599 if (item._convId === conv.id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1600 const titleEl = item.querySelector("[data-conv-title]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1601 const metaEl = item.querySelector("[data-conv-meta]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1602 if (titleEl) titleEl.textContent = conv.title; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1603 if (metaEl) metaEl.textContent = this._formatMeta(conv); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1604 item._convTitle = conv.title; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1605 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1606 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1607 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1608 this.addConversation(conv); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1609 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1610 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1611 removeConversation(id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1612 for (const item of (this._list?.querySelectorAll("[data-conv-item]") || [])) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1613 if (item._convId === id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1614 item.remove(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1615 break; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1616 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1617 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1618 if (!this._list?.querySelector("[data-conv-item]")) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1619 this._showStatus("No conversations yet. Start a new one!"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1620 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1621 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1622 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1623 setLoading(loading) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1624 if (loading) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1625 this._showStatus("Loading conversations..."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1626 } else if (!this._list?.querySelector("[data-conv-item]")) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1627 this._showStatus("No conversations yet. Start a new one!"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1628 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1629 this._hideStatus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1630 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1631 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1632 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1633 setError(message) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1634 this._showStatus(message); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1635 if (this._status) this._status.dataset.state = "error"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1636 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1637 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1638 setLoadMoreDisabled(disabled) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1639 if (this._loadMoreButton) this._loadMoreButton.disabled = disabled; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1640 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1641 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1642 /* Disable/enable destructive archive controls while a stream is active. */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1643 setStreamActive(active) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1644 const controls = this._list?.querySelectorAll( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1645 "[data-conv-delete], [data-conv-rename]", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1646 ) || []; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1647 for (const el of controls) el.disabled = active; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1648 if (this._newButton) this._newButton.disabled = active; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1649 if (this._deleteConfirmButton) this._deleteConfirmButton.disabled = active; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1650 this.dataset.streamActive = active ? "true" : ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1651 if (!active) delete this.dataset.streamActive; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1652 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1653 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1654 /* Return the open-button of the adjacent surviving item, or New button. */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1655 adjacentItemOrNewButton(id) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1656 const items = [...(this._list?.querySelectorAll("[data-conv-item]") || [])]; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1657 const idx = items.findIndex(el => el._convId === id); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1658 if (idx < 0) return this._newButton; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1659 const sibling = items[idx + 1] || items[idx - 1]; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1660 return sibling?.querySelector("[data-conv-open]") || this._newButton; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1661 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1662 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1663 showLegacyClaim(statusMessage = null, showButton = true) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1664 if (!this._status) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1665 this._status.hidden = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1666 delete this._status.dataset.state; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1667 this._status.textContent = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1668 const msg = document.createElement("span"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1669 msg.textContent = statusMessage ?? "You have a prior conversation. "; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1670 this._status.append(msg); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1671 if (showButton) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1672 const btn = document.createElement("button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1673 btn.type = "button"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1674 btn.textContent = "Claim it"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1675 btn.dataset.archiveClaim = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1676 btn.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1677 this.dispatchEvent(new CustomEvent("mjj-archive-claim", { bubbles: true })); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1678 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1679 this._status.append(btn); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1680 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1681 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1682 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1683 _showStatus(text) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1684 if (this._status) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1685 this._status.textContent = text; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1686 this._status.hidden = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1687 delete this._status.dataset.state; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1688 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1689 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1690 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1691 _hideStatus() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1692 if (this._status) this._status.hidden = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1693 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1694 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1695 _createItem(conv) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1696 const item = document.createElement("li"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1697 item.dataset.convItem = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1698 item._convId = conv.id; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1699 item._convTitle = conv.title; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1700 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1701 const openButton = document.createElement("button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1702 openButton.type = "button"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1703 openButton.dataset.convOpen = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1704 openButton.setAttribute("aria-current", "false"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1705 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1706 const titleEl = document.createElement("span"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1707 titleEl.dataset.convTitle = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1708 titleEl.textContent = conv.title; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1709 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1710 const metaEl = document.createElement("small"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1711 metaEl.dataset.convMeta = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1712 metaEl.textContent = this._formatMeta(conv); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1713 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1714 openButton.append(titleEl, metaEl); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1715 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1716 const actions = document.createElement("div"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1717 actions.className = "jrpg-archive-item-actions"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1718 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1719 const renameButton = document.createElement("button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1720 renameButton.type = "button"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1721 renameButton.dataset.convRename = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1722 renameButton.setAttribute("aria-label", `Rename "${conv.title}"`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1723 renameButton.textContent = "Rename"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1724 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1725 const deleteButton = document.createElement("button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1726 deleteButton.type = "button"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1727 deleteButton.dataset.convDelete = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1728 deleteButton.setAttribute("aria-label", `Delete "${conv.title}"`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1729 deleteButton.textContent = "Delete"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1730 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1731 actions.append(renameButton, deleteButton); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1732 item.append(openButton, actions); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1733 return item; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1734 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1735 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1736 _formatMeta(conv) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1737 const count = conv.turn_count ?? 0; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1738 const turns = count === 1 ? "1 turn" : `${count} turns`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1739 if (conv.last_message_preview) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1740 return `${turns} · ${conv.last_message_preview.slice(0, 28)}`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1741 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1742 return turns; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1743 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1744 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1745 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1746 class MjjJrpgShell extends HTMLElement { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1747 connectedCallback() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1748 this._mobileMenuQuery = window.matchMedia( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1749 "(max-width: 52rem) and (orientation: portrait)", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1750 ); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1751 this._mobileDestinationOwner = this.querySelector( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1752 "[data-mobile-destination-owner]", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1753 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1754 this._mobileDestinationDialog = this.querySelector( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1755 "[data-mobile-destination-dialog]", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1756 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1757 this._mobileDestinationContent = this.querySelector( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1758 "[data-mobile-destination-content]", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1759 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1760 this._mobileDestinationTitle = this.querySelector( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1761 "[data-mobile-destination-title]", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1762 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1763 this._mobileDestinationBackOwner = this.querySelector( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1764 "[data-mobile-destination-back-owner]", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1765 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1766 this._mobileDestinationBack = this.querySelector( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1767 "[data-mobile-destination-back]", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1768 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1769 this._utility = this.querySelector(".jrpg-utility"); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1770 this._menu = this.querySelector("mjj-jrpg-menu"); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1771 this._utilityPlaceholder = document.createComment("jrpg-utility"); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1772 this._menuPlaceholder = document.createComment("jrpg-menu"); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1773 this._utility?.before(this._utilityPlaceholder); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1774 this._menu?.before(this._menuPlaceholder); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1775 |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1776 this._syncMobileLayout = () => { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1777 if (!this._utility || !this._menu || !this._mobileDestinationContent) { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1778 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1779 } |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1780 if (this._mobileMenuQuery.matches) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1781 this._mobileDestinationContent.append(this._menu, this._utility); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1782 this.showMobileMenu(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1783 return; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1784 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1785 this._mobileDestinationOwner?.close(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1786 this._utilityPlaceholder.after(this._utility); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1787 this._menuPlaceholder.after(this._menu); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1788 this._utility.hidden = false; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1789 this._menu.hidden = false; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1790 }; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1791 this._onMobileMenuMediaChange = () => this._syncMobileLayout(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1792 this._onMobileDestinationBack = () => this.showMobileMenu(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1793 this._onMobileDestinationClose = () => this.showMobileMenu(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1794 this._mobileDestinationBack?.addEventListener( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1795 "click", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1796 this._onMobileDestinationBack, |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1797 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1798 this._mobileDestinationDialog?.addEventListener( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1799 "close", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1800 this._onMobileDestinationClose, |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1801 ); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1802 this._mobileMenuQuery.addEventListener( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1803 "change", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1804 this._onMobileMenuMediaChange, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1805 ); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1806 this._syncMobileLayout(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1807 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1808 |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1809 isMobileDestinationModal() { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1810 return Boolean(this._mobileMenuQuery?.matches); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1811 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1812 |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1813 isMobileDestinationOpen() { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1814 return this.isMobileDestinationModal() && |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1815 Boolean(this._mobileDestinationDialog?.open); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1816 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1817 |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1818 showMobileMenu() { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1819 if (!this.isMobileDestinationModal() || !this._menu || !this._utility) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1820 return; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1821 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1822 this._menu.hidden = false; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1823 this._utility.hidden = true; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1824 if (this._mobileDestinationTitle) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1825 this._mobileDestinationTitle.textContent = "Menu"; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1826 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1827 if (this._mobileDestinationBackOwner) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1828 this._mobileDestinationBackOwner.hidden = true; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1829 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1830 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1831 |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1832 showMobileDestination(selection) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1833 if (!this.isMobileDestinationModal() || !this._menu || !this._utility) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1834 return; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1835 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1836 const labels = { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1837 blog: "Blogs", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1838 conversations: "Conversations", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1839 resume: "Resume", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1840 tools: "Tools", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1841 }; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1842 this._menu.hidden = true; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1843 this._utility.hidden = false; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1844 if (this._mobileDestinationTitle) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1845 this._mobileDestinationTitle.textContent = labels[selection] || "Destination"; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1846 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1847 if (this._mobileDestinationBackOwner) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1848 this._mobileDestinationBackOwner.hidden = false; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1849 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1850 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1851 |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1852 closeMobileDestinations() { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1853 if (this.isMobileDestinationModal()) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1854 this._mobileDestinationOwner?.close(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1855 } |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1856 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1857 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1858 disconnectedCallback() { |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1859 this._mobileDestinationBack?.removeEventListener( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1860 "click", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1861 this._onMobileDestinationBack, |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1862 ); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1863 this._mobileDestinationDialog?.removeEventListener( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1864 "close", |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1865 this._onMobileDestinationClose, |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
1866 ); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1867 this._mobileMenuQuery?.removeEventListener( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1868 "change", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1869 this._onMobileMenuMediaChange, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1870 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1871 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1872 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1873 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1874 for (const [name, constructor] of Object.entries({ |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1875 "mjj-conversation-archive": MjjConversationArchive, |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1876 "mjj-jrpg-character": MjjJrpgCharacter, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1877 "mjj-jrpg-chat": MjjJrpgChat, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1878 "mjj-jrpg-menu": MjjJrpgMenu, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1879 "mjj-jrpg-preview": MjjJrpgPreview, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1880 "mjj-jrpg-shell": MjjJrpgShell, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1881 })) { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1882 if (!customElements.get(name)) customElements.define(name, constructor); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1883 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1884 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1885 async function requestJson(url, options = {}) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1886 const response = await fetch(url, { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1887 ...options, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1888 credentials: "same-origin", |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1889 headers: { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1890 "Content-Type": "application/json", |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1891 ...options.headers, |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1892 }, |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1893 }); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1894 if (!response.ok) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1895 let message = `Request failed (${response.status})`; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1896 try { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1897 const body = await response.json(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1898 message = body.error?.message || message; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1899 } catch { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1900 // Preserve the status-derived message. |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1901 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1902 throw new Error(message); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1903 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1904 return response.status === 204 ? null : response.json(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1905 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
1906 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1907 /* Session state for CSRF: bootstrapped once, refreshed at most once on 401/403 */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1908 let _csrfToken = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1909 let _sessionData = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1910 let _sessionRefreshInFlight = null; /* single-flight guard */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1911 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1912 function _principalFingerprint(data) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1913 if (!data) return null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1914 if (data.kind === "user") return `user:${data.username || ""}:${data.role || ""}`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1915 if (data.kind === "guest") return `guest:${data.csrfToken || ""}`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1916 return null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1917 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1918 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1919 async function _fetchSession() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1920 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1921 const response = await fetch("/api/auth/session", { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1922 credentials: "same-origin", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1923 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1924 if (!response.ok) return null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1925 const data = await response.json().catch(() => null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1926 if (!data) return null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1927 _sessionData = data; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1928 return data.csrfToken || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1929 } catch { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1930 return null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1931 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1932 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1933 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1934 /* Single-flight session refresh: dedupe concurrent callers. */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1935 async function _refreshSessionOnce() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1936 if (_sessionRefreshInFlight) return _sessionRefreshInFlight; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1937 _sessionRefreshInFlight = (async () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1938 const prev = _principalFingerprint(_sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1939 const token = await _fetchSession(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1940 const next = _principalFingerprint(_sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1941 return { token, prev, next }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1942 })(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1943 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1944 return await _sessionRefreshInFlight; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1945 } finally { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1946 _sessionRefreshInFlight = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1947 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1948 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1949 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1950 /* |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1951 * Perform a state-changing (mutating) fetch with CSRF token and same-origin |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1952 * credentials. On 401 or CSRF-specific 403 (csrf_invalid), refreshes the |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1953 * session once and retries — but only if the refreshed principal matches the |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1954 * original. If the user becomes a guest or a different account, rejects and |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1955 * triggers the session-changed callback. |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1956 */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1957 let _sessionRefreshCallback = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1958 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1959 async function mutatingFetch(url, options = {}) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1960 const buildHeaders = () => ({ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1961 ...(options.headers || {}), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1962 Origin: window.location.origin, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1963 ...(_csrfToken ? { "X-CSRF-Token": _csrfToken } : {}), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1964 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1965 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1966 const response = await fetch(url, { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1967 ...options, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1968 credentials: "same-origin", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1969 headers: buildHeaders(), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1970 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1971 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1972 const shouldRefresh = response.status === 401 || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1973 (response.status === 403 && await (async () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1974 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1975 const clone = response.clone(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1976 const body = await clone.json(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1977 return body?.error?.code === "csrf_invalid"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1978 } catch { return false; } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1979 })()); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1980 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1981 if (shouldRefresh) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1982 const prevFingerprint = _principalFingerprint(_sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1983 const { token, next } = await _refreshSessionOnce(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1984 _csrfToken = token; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1985 if (next !== prevFingerprint) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1986 if (_sessionRefreshCallback) _sessionRefreshCallback(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1987 const err = Object.assign(new Error("Session changed"), { status: 401 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1988 throw err; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1989 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1990 const retried = await fetch(url, { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1991 ...options, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1992 credentials: "same-origin", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1993 headers: buildHeaders(), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1994 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1995 if (retried.status === 401 && _sessionRefreshCallback) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1996 _sessionRefreshCallback(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1997 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1998 return retried; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
1999 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2000 return response; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2001 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2002 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2003 async function consumeSse(response, onEvent) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2004 if (!response.body) throw new Error("Streaming response body is unavailable"); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2005 const reader = response.body.getReader(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2006 const decoder = new TextDecoder(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2007 let buffer = ""; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2008 |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2009 const dispatch = block => { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2010 let eventName = "message"; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2011 const data = []; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2012 for (const line of block.split("\n")) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2013 if (line.startsWith("event:")) eventName = line.slice(6).trim(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2014 else if (line.startsWith("data:")) data.push(line.slice(5).trimStart()); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2015 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2016 if (!data.length) return; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2017 onEvent(eventName, JSON.parse(data.join("\n"))); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2018 }; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2019 |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2020 while (true) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2021 const { done, value } = await reader.read(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2022 buffer += decoder.decode(value || new Uint8Array(), { stream: !done }); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2023 buffer = buffer.replaceAll("\r\n", "\n"); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2024 let boundary; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2025 while ((boundary = buffer.indexOf("\n\n")) >= 0) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2026 const block = buffer.slice(0, boundary); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2027 buffer = buffer.slice(boundary + 2); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2028 if (block.trim()) dispatch(block); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2029 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2030 if (done) break; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2031 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2032 if (buffer.trim()) dispatch(buffer); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2033 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2034 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2035 /* ===================================================================== |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2036 Account slot rendering |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2037 ===================================================================== */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2038 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2039 function renderAccountSlot(slotEl, sessionData) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2040 if (!slotEl) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2041 slotEl.textContent = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2042 if (!sessionData || sessionData.kind === "guest") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2043 const owner = document.createElement("zen-button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2044 const btn = document.createElement("button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2045 owner.setAttribute("appearance", "plain"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2046 owner.setAttribute("size", "xs"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2047 btn.type = "button"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2048 btn.dataset.loginOpen = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2049 btn.textContent = "LOGIN"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2050 owner.append(btn); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2051 slotEl.setAttribute("aria-label", "Not signed in"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2052 slotEl.append(owner); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2053 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2054 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2055 const username = (sessionData.username || "").slice(0, 8).toUpperCase(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2056 if (sessionData.mustChangePassword) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2057 const link = document.createElement("a"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2058 link.href = "/account/password"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2059 link.textContent = username ? `${username}\u26A0` : "PASSWD"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2060 link.title = "Password change required"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2061 slotEl.setAttribute("aria-label", `${sessionData.username}: password change required`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2062 slotEl.append(link); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2063 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2064 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2065 const nameSpan = document.createElement("span"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2066 nameSpan.dataset.accountUser = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2067 nameSpan.textContent = username; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2068 slotEl.append(nameSpan); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2069 if (sessionData.role === "admin") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2070 const adminLink = document.createElement("a"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2071 adminLink.href = "/admin/users"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2072 adminLink.textContent = "\u00A0ADM"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2073 slotEl.append(adminLink); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2074 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2075 const logoutBtn = document.createElement("button"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2076 logoutBtn.type = "button"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2077 logoutBtn.textContent = "\u00A0LGOUT"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2078 logoutBtn.addEventListener("click", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2079 logoutBtn.disabled = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2080 mutatingFetch("/api/auth/logout", { method: "POST" }).then(response => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2081 if (!response.ok) throw new Error(`Logout failed (${response.status})`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2082 window.dispatchEvent(new CustomEvent("mjj-logout")); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2083 }).catch(() => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2084 logoutBtn.disabled = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2085 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2086 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2087 slotEl.append(logoutBtn); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2088 slotEl.setAttribute("aria-label", `Signed in as ${sessionData.username}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2089 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2090 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2091 /* ===================================================================== |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2092 Quota display helpers |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2093 ===================================================================== */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2094 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2095 function formatQuotaText(quota) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2096 if (!quota) return null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2097 const turns = quota.turnsRemaining ?? 0; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2098 const tokens = quota.outputTokensRemaining ?? 0; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2099 if (turns <= 0) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2100 const resetAt = quota.resetsAt ? new Date(quota.resetsAt * 1000) : null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2101 const resetStr = resetAt |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2102 ? ` Resets ${resetAt.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}` |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2103 : ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2104 return { text: `Quota exhausted.${resetStr}`, state: "exhausted" }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2105 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2106 if (turns <= 2) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2107 return { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2108 text: `${turns} turn${turns === 1 ? "" : "s"} remaining (${tokens.toLocaleString()} tokens)`, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2109 state: "warning", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2110 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2111 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2112 return { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2113 text: `${turns} turns remaining (${tokens.toLocaleString()} tokens)`, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2114 state: "ok", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2115 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2116 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2117 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2118 function updateQuotaDisplay(quotaEl, quota) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2119 if (!quotaEl) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2120 if (!quota) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2121 quotaEl.hidden = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2122 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2123 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2124 const result = formatQuotaText(quota); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2125 /* Only show the bar for low or exhausted quota; hide when turns are plentiful */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2126 if (!result || result.state === "ok") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2127 quotaEl.hidden = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2128 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2129 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2130 quotaEl.textContent = result.text; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2131 if (result.state === "exhausted") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2132 quotaEl.dataset.state = "exhausted"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2133 } else if (result.state === "warning") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2134 quotaEl.dataset.state = "warning"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2135 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2136 delete quotaEl.dataset.state; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2137 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2138 quotaEl.hidden = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2139 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2140 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2141 /* ===================================================================== |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2142 Conversation archive helpers |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2143 ===================================================================== */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2144 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2145 async function fetchConversationList(cursor) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2146 const url = cursor |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2147 ? `/api/conversations?limit=${ARCHIVE_PAGE_SIZE}&cursor=${encodeURIComponent(cursor)}` |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2148 : `/api/conversations?limit=${ARCHIVE_PAGE_SIZE}`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2149 const response = await fetch(url, { credentials: "same-origin" }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2150 if (!response.ok) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2151 let message = `Failed to load conversations (${response.status})`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2152 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2153 const body = await response.json(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2154 message = body.error?.message || message; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2155 } catch { /* keep status message */ } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2156 throw new Error(message); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2157 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2158 return response.json(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2159 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2160 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2161 async function initializeJrpgPage() { |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2162 const colorProbe = document.createElement("span"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2163 colorProbe.style.background = "var(--zenbu-sys-color-surface-page)"; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2164 document.body.append(colorProbe); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2165 const themeColor = getComputedStyle(colorProbe).backgroundColor; |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2166 colorProbe.remove(); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2167 for (const meta of document.querySelectorAll('meta[name="theme-color"]')) { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2168 meta.setAttribute("content", themeColor); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2169 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2170 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2171 /* Bootstrap session to obtain CSRF token and session data */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2172 _csrfToken = await _fetchSession(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2173 |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2174 const shell = document.querySelector("mjj-jrpg-shell"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2175 const character = shell?.querySelector("mjj-jrpg-character"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2176 const chat = shell?.querySelector("mjj-jrpg-chat"); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2177 const composer = shell?.querySelector("mjj-composer"); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2178 const preview = shell?.querySelector("mjj-jrpg-preview"); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2179 const archive = shell?.querySelector("mjj-conversation-archive"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2180 const accountSlot = shell?.querySelector("[data-frame-account]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2181 const quotaEl = shell?.querySelector("[data-quota]"); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2182 const frameNetwork = shell?.querySelector("[data-frame-network]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2183 const frameUptime = shell?.querySelector("[data-frame-uptime]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2184 const minimizeButton = shell?.querySelector("[data-frame-minimize]"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2185 const fullscreenButton = shell?.querySelector("[data-frame-fullscreen]"); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2186 |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2187 let characterTimer = 0; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2188 let currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2189 let currentPanel = "resume"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2190 let archiveCursor = null; |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2191 let activeController = null; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2192 let archiveLoadInFlight = false; /* serialize pagination requests */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2193 let openSeq = 0; /* sequence guard for conversation open */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2194 let popSeq = 0; /* sequence guard for popstate */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2195 let _pendingPopState = null; /* queued popstate received during active stream */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2196 let _claimInFlight = false; /* guard against duplicate concurrent claims */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2197 let legacyClaimId = sessionStorage.getItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2198 let principalEpoch = 0; /* rejects responses from a prior owner */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2199 /* Dedupe conversation IDs: set of IDs currently rendered in archive */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2200 const _renderedIds = new Set(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2201 const invalidatePrincipalRequests = () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2202 principalEpoch += 1; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2203 openSeq += 1; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2204 popSeq += 1; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2205 archiveCursor = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2206 }; |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2207 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2208 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2209 /* Disable composer until fully initialized */ |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2210 composer?.setDisabled(true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2211 |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2212 const setFrameStatus = (label, state, title = "") => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2213 if (frameNetwork) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2214 frameNetwork.textContent = label; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2215 frameNetwork.setAttribute("aria-label", `Status ${label.toLowerCase()}`); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2216 frameNetwork.dataset.state = state; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2217 frameNetwork.title = title; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2218 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2219 }; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2220 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2221 /* Bootstrap failure: keep controls disabled and expose retry */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2222 if (!_csrfToken) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2223 setFrameStatus("OFFLINE", "offline", "Bootstrap failed"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2224 archive?.setError("Connection failed. Reload to retry."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2225 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2226 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2227 |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2228 setFrameStatus("ONLINE", "online"); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2229 |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2230 const startedAt = Date.now(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2231 const updateUptime = () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2232 const elapsed = Math.floor((Date.now() - startedAt) / 1000); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2233 const hours = String(Math.floor(elapsed / 3600)).padStart(2, "0"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2234 const minutes = String(Math.floor((elapsed % 3600) / 60)).padStart(2, "0"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2235 const seconds = String(elapsed % 60).padStart(2, "0"); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2236 if (frameUptime) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2237 frameUptime.textContent = `${hours}:${minutes}:${seconds}`; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2238 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2239 }; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2240 updateUptime(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2241 window.setInterval(updateUptime, 1000); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2242 |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2243 minimizeButton?.addEventListener("click", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2244 const minimized = shell.dataset.minimized !== "true"; |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2245 shell.dataset.minimized = String(minimized); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2246 minimizeButton.setAttribute("aria-pressed", String(minimized)); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2247 minimizeButton.setAttribute( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2248 "aria-label", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2249 minimized ? "Restore interface" : "Minimize interface", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2250 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2251 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2252 fullscreenButton?.addEventListener("click", async () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2253 try { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2254 if (document.fullscreenElement) await document.exitFullscreen(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2255 else await shell.requestFullscreen(); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2256 } catch (error) { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2257 setFrameStatus("DENIED", "offline", error.message); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2258 } |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2259 }); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2260 document.addEventListener("fullscreenchange", () => { |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2261 fullscreenButton?.setAttribute( |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2262 "aria-pressed", |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2263 String(Boolean(document.fullscreenElement)), |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2264 ); |
|
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
2265 }); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2266 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2267 /* Render account slot */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2268 renderAccountSlot(accountSlot, _sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2269 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2270 /* ---- Login modal ---- */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2271 const loginDialogOwner = shell?.querySelector("[data-login-dialog-owner]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2272 const loginDialog = loginDialogOwner?.querySelector("[data-login-dialog]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2273 const loginForm = loginDialog?.querySelector("[data-login-form]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2274 const loginSubmitBtn = loginDialog?.querySelector("[data-login-submit]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2275 const loginCancelBtn = loginDialog?.querySelector("[data-login-cancel]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2276 const loginErrorEl = loginDialog?.querySelector("[data-login-error]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2277 const loginUsernameInput = loginDialog?.querySelector("#jrpg-login-username"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2278 const loginPasswordInput = loginDialog?.querySelector("#jrpg-login-password"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2279 let _loginTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2280 const setAccountActionsDisabled = disabled => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2281 for (const control of accountSlot?.querySelectorAll("button") || []) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2282 control.disabled = disabled; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2283 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2284 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2285 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2286 const _clearLoginError = () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2287 if (loginErrorEl) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2288 loginErrorEl.textContent = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2289 loginErrorEl.hidden = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2290 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2291 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2292 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2293 const _showLoginError = (message) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2294 if (!loginErrorEl) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2295 loginErrorEl.textContent = message; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2296 loginErrorEl.hidden = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2297 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2298 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2299 const openLoginModal = (triggerEl) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2300 if (!loginDialogOwner || !loginDialog) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2301 _loginTrigger = triggerEl || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2302 _clearLoginError(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2303 loginForm?.reset(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2304 loginDialogOwner.open(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2305 requestAnimationFrame(() => { loginUsernameInput?.focus(); }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2306 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2307 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2308 /* Delegate clicks on data-login-open in the account slot */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2309 accountSlot?.addEventListener("click", event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2310 const btn = event.target.closest("[data-login-open]"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2311 if (!btn || activeController) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2312 openLoginModal(btn); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2313 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2314 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2315 /* Cancel button */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2316 loginCancelBtn?.addEventListener("click", () => { loginDialog?.close(); }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2317 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2318 /* Cleanup on any close (Escape, X button, cancel) */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2319 loginDialog?.addEventListener("close", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2320 if (loginPasswordInput) loginPasswordInput.value = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2321 _clearLoginError(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2322 const trigger = _loginTrigger; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2323 _loginTrigger = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2324 requestAnimationFrame(() => { trigger?.focus(); }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2325 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2326 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2327 /* Login form submission */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2328 loginForm?.addEventListener("submit", async event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2329 event.preventDefault(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2330 if (loginSubmitBtn?.disabled) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2331 const username = loginUsernameInput?.value.trim() || ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2332 const password = loginPasswordInput?.value || ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2333 if (!username || !password) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2334 _showLoginError("Please enter your username and password."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2335 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2336 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2337 if (loginSubmitBtn) loginSubmitBtn.disabled = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2338 _clearLoginError(); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2339 try { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2340 const response = await fetch("/api/auth/login", { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2341 method: "POST", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2342 headers: { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2343 "Content-Type": "application/json", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2344 "Origin": window.location.origin, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2345 }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2346 credentials: "same-origin", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2347 body: JSON.stringify({ username, password, csrfToken: _csrfToken }), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2348 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2349 if (loginPasswordInput) loginPasswordInput.value = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2350 if (response.status === 429) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2351 _showLoginError("Too many attempts. Please try again later."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2352 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2353 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2354 if (!response.ok) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2355 _showLoginError("Invalid username or password."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2356 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2357 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2358 let data = await response.json().catch(() => null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2359 if (!data) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2360 _csrfToken = await _fetchSession(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2361 if (_sessionData?.kind !== "user") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2362 loginDialog?.close(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2363 window.location.reload(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2364 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2365 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2366 data = _sessionData; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2367 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2368 invalidatePrincipalRequests(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2369 loginDialog?.close(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2370 _sessionData = { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2371 kind: "user", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2372 username: data.username || username, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2373 role: data.role || "member", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2374 mustChangePassword: Boolean(data.mustChangePassword), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2375 csrfToken: data.csrfToken, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2376 quota: null, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2377 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2378 _csrfToken = data.csrfToken || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2379 if (data.mustChangePassword) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2380 window.location.href = "/account/password"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2381 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2382 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2383 /* Commit the returned principal before optional UI refresh work. */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2384 renderAccountSlot(accountSlot, _sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2385 updateQuotaDisplay(quotaEl, _sessionData?.quota || null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2386 composer?.setDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2387 /* Clear conversation state — guest convs may transfer to user */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2388 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2389 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2390 sessionStorage.removeItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2391 legacyClaimId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2392 _replaceUrlState(currentPanel, null); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2393 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2394 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2395 await refreshArchiveFromScratch(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2396 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2397 archive?.setError(`Signed in, but archive refresh failed: ${error.message}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2398 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2399 requestAnimationFrame(() => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2400 accountSlot?.querySelector("button, a")?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2401 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2402 } catch { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2403 if (loginPasswordInput) loginPasswordInput.value = ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2404 _showLoginError("Sign-in failed. Please try again."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2405 } finally { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2406 if (loginSubmitBtn) loginSubmitBtn.disabled = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2407 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2408 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2409 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2410 /* Handle logout */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2411 _sessionRefreshCallback = () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2412 /* Account changed or session lost — clear active state */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2413 invalidatePrincipalRequests(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2414 if (activeController) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2415 activeController.abort(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2416 activeController = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2417 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2418 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2419 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2420 sessionStorage.removeItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2421 legacyClaimId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2422 _replaceUrlState(currentPanel, null); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2423 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2424 _renderedIds.clear(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2425 archiveCursor = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2426 archive?.setConversations([], null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2427 renderAccountSlot(accountSlot, _sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2428 archive?.setError("Session changed. Loading conversations..."); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2429 void refreshArchiveFromScratch(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2430 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2431 window.addEventListener("mjj-logout", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2432 invalidatePrincipalRequests(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2433 if (activeController) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2434 activeController.abort(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2435 activeController = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2436 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2437 archive?.setStreamActive(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2438 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2439 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2440 sessionStorage.removeItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2441 legacyClaimId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2442 _replaceUrlState(currentPanel, null); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2443 chat?.setGreeting(ROLE_GREETINGS.guest, true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2444 _renderedIds.clear(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2445 archiveCursor = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2446 archive?.setConversations([], null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2447 void refreshArchiveFromScratch(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2448 void (async () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2449 _csrfToken = await _fetchSession(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2450 renderAccountSlot(accountSlot, _sessionData); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2451 updateQuotaDisplay(quotaEl, _sessionData?.quota || null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2452 if (_sessionData?.kind === "user" && _sessionData?.mustChangePassword) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2453 composer?.setDisabled(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2454 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2455 composer?.setDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2456 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2457 })(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2458 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2459 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2460 /* Session quota display */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2461 if (_sessionData?.kind === "guest") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2462 updateQuotaDisplay(quotaEl, _sessionData.quota || null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2463 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2464 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2465 /* Disable composer for forced-password-change */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2466 const isForced = _sessionData?.kind === "user" && _sessionData?.mustChangePassword; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2467 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2468 /* ---- URL state helpers ---- */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2469 const _buildStateUrl = (panel, convId) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2470 const url = new URL(window.location.href); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2471 if (panel && VALID_PANELS.includes(panel)) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2472 url.searchParams.set("panel", panel); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2473 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2474 url.searchParams.delete("panel"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2475 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2476 if (convId && UUID_REGEX.test(convId)) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2477 url.searchParams.set("conversation", convId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2478 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2479 url.searchParams.delete("conversation"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2480 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2481 return url; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2482 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2483 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2484 const _pushUrlState = (panel, convId) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2485 history.pushState({ panel, conversation: convId || null }, "", _buildStateUrl(panel, convId)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2486 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2487 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2488 const _replaceUrlState = (panel, convId) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2489 history.replaceState({ panel, conversation: convId || null }, "", _buildStateUrl(panel, convId)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2490 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2491 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2492 /* ---- Panel selection: shows archive or preview in utility ---- */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2493 const utilityEl = shell?.querySelector(".jrpg-utility"); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2494 const previewContent = preview?.querySelector("[data-preview-content]"); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2495 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2496 const selectPanel = (panel, pushHistory = true) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2497 const validPanel = VALID_PANELS.includes(panel) ? panel : "resume"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2498 currentPanel = validPanel; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2499 for (const btn of (shell?.querySelectorAll("button[data-preview]") || [])) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2500 btn.setAttribute("aria-pressed", String(btn.dataset.preview === validPanel)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2501 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2502 if (validPanel === "conversations") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2503 if (archive) archive.hidden = false; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2504 if (previewContent) previewContent.hidden = true; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2505 if (utilityEl) utilityEl.setAttribute("aria-label", "Conversations"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2506 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2507 if (archive) archive.hidden = true; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2508 if (previewContent) previewContent.hidden = false; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2509 preview?.show(validPanel); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2510 if (utilityEl) utilityEl.setAttribute("aria-label", "Selected destination"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2511 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2512 if (pushHistory) _pushUrlState(validPanel, currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2513 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2514 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2515 /* ---- Archive close button: navigate back to resume panel ---- */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2516 shell?.addEventListener("mjj-archive-toggle", () => { |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2517 if (shell?.isMobileDestinationModal()) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2518 shell.showMobileMenu(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2519 return; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2520 } |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2521 selectPanel("resume"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2522 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2523 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2524 shell?.addEventListener("mjj-archive-new", () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2525 if (activeController) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2526 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2527 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2528 _pushUrlState(currentPanel, null); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2529 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2530 archive?.setCurrentId(null); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2531 shell?.closeMobileDestinations(); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2532 composer?.querySelector("textarea")?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2533 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2534 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2535 /* ---- Popstate: re-apply panel and conversation on back/forward ---- */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2536 /* _applyPopState always increments openSeq so any pending archive-open |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2537 fetch (including a transition to no conversation) cannot overwrite the |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2538 state the user navigated to (Fix 2). */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2539 const _applyPopState = async (seq, popPanel, popConvId) => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2540 const localSeq = ++openSeq; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2541 const epoch = principalEpoch; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2542 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2543 selectPanel(popPanel, false); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2544 if (shell?.isMobileDestinationOpen()) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2545 shell.showMobileDestination(popPanel); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2546 } |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2547 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2548 if (popConvId && popConvId !== currentConversationId) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2549 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2550 const conversation = await requestJson(`/api/conversations/${encodeURIComponent(popConvId)}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2551 if (seq !== popSeq || localSeq !== openSeq || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2552 epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2553 currentConversationId = popConvId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2554 sessionStorage.setItem(CONVERSATION_STORAGE_KEY, popConvId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2555 chat?.replaceMessages(conversation.turns); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2556 archive?.setCurrentId(popConvId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2557 } catch { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2558 if (seq !== popSeq || localSeq !== openSeq || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2559 epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2560 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2561 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2562 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2563 archive?.setCurrentId(null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2564 history.replaceState( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2565 { panel: popPanel, conversation: null }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2566 "", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2567 _buildStateUrl(popPanel, null), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2568 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2569 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2570 } else if (!popConvId && currentConversationId) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2571 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2572 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2573 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2574 archive?.setCurrentId(null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2575 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2576 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2577 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2578 /* When popstate fires while a stream is active the URL has already changed. |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2579 Queue the parsed destination, abort the stream, and apply exactly once in |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2580 the stream's finally block so URL and UI always converge (Fix 1). */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2581 window.addEventListener("popstate", async event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2582 const seq = ++popSeq; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2583 ++openSeq; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2584 const state = event.state || {}; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2585 const popPanel = VALID_PANELS.includes(state.panel) ? state.panel : "resume"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2586 const popConvId = (state.conversation && UUID_REGEX.test(state.conversation)) |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2587 ? state.conversation : null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2588 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2589 if (activeController) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2590 _pendingPopState = { seq, popPanel, popConvId }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2591 activeController.abort(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2592 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2593 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2594 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2595 await _applyPopState(seq, popPanel, popConvId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2596 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2597 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2598 shell?.addEventListener("mjj-archive-rename", async event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2599 const { id, newTitle, trigger } = event.detail; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2600 if (activeController) { trigger?.focus(); return; } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2601 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2602 const response = await mutatingFetch( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2603 `/api/conversations/${encodeURIComponent(id)}`, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2604 { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2605 method: "PATCH", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2606 headers: { "Content-Type": "application/json" }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2607 body: JSON.stringify({ title: newTitle }), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2608 }, |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2609 ); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2610 if (!response.ok) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2611 const body = await response.json().catch(() => ({})); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2612 throw new Error(body.error?.message || `Rename failed (${response.status})`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2613 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2614 archive?.updateConversation({ id, title: newTitle, turn_count: null }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2615 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2616 archive?.setError(`Rename failed: ${error.message}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2617 } finally { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2618 trigger?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2619 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2620 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2621 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2622 shell?.addEventListener("mjj-archive-open", async event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2623 const { id } = event.detail; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2624 if (id === currentConversationId) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2625 if (activeController) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2626 const seq = ++openSeq; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2627 const epoch = principalEpoch; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2628 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2629 const conversation = await requestJson(`/api/conversations/${encodeURIComponent(id)}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2630 if (seq !== openSeq || epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2631 currentConversationId = id; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2632 sessionStorage.setItem(CONVERSATION_STORAGE_KEY, id); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2633 _pushUrlState(currentPanel, id); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2634 chat?.replaceMessages(conversation.turns); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2635 archive?.setCurrentId(id); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2636 shell?.closeMobileDestinations(); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2637 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2638 if (seq !== openSeq || epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2639 archive?.setError(`Unable to open: ${error.message}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2640 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2641 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2642 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2643 shell?.addEventListener("mjj-archive-delete", async event => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2644 const { id, trigger } = event.detail; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2645 if (activeController) { trigger?.focus(); return; } /* block while streaming */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2646 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2647 const response = await mutatingFetch( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2648 `/api/conversations/${encodeURIComponent(id)}`, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2649 { method: "DELETE" }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2650 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2651 if (response.ok || response.status === 404) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2652 /* Focus adjacent archive item or New button before removing the node */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2653 const focusTarget = archive?.adjacentItemOrNewButton(id); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2654 _renderedIds.delete(id); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2655 archive?.removeConversation(id); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2656 if (id === currentConversationId) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2657 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2658 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2659 _replaceUrlState(currentPanel, null); |
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
264
diff
changeset
|
2660 chat?.setGreeting(greetingForSession(_sessionData), true); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2661 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2662 /* Focus surviving element — never the detached trigger */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2663 requestAnimationFrame(() => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2664 (focusTarget || archive?.querySelector("[data-archive-new]"))?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2665 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2666 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2667 const body = await response.json().catch(() => ({})); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2668 archive?.setError(`Delete failed: ${body.error?.message || response.status}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2669 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2670 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2671 archive?.setError(`Delete failed: ${error.message}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2672 /* On error, the trigger is still attached — focus it */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2673 trigger?.focus(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2674 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2675 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2676 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2677 shell?.addEventListener("mjj-archive-load-more", async () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2678 if (!archiveCursor || archiveLoadInFlight) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2679 archiveLoadInFlight = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2680 const epoch = principalEpoch; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2681 archive?.setLoadMoreDisabled(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2682 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2683 const data = await fetchConversationList(archiveCursor); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2684 if (epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2685 archiveCursor = data.cursor || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2686 const newConvs = (data.conversations || []).filter(c => !_renderedIds.has(c.id)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2687 newConvs.forEach(c => _renderedIds.add(c.id)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2688 archive?.setConversations(newConvs, archiveCursor, true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2689 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2690 archive?.setError(`Load failed: ${error.message}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2691 } finally { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2692 archiveLoadInFlight = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2693 archive?.setLoadMoreDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2694 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2695 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2696 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2697 shell?.addEventListener("mjj-archive-claim", async () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2698 const legacyId = |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2699 legacyClaimId || sessionStorage.getItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2700 if (!legacyId || _sessionData?.kind !== "user" || _claimInFlight) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2701 _claimInFlight = true; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2702 archive?.showLegacyClaim("Claiming prior conversation...", false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2703 let _claimOutcome = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2704 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2705 const response = await mutatingFetch( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2706 "/api/conversations/claim", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2707 { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2708 method: "POST", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2709 headers: { "Content-Type": "application/json" }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2710 body: JSON.stringify({ conversationId: legacyId }), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2711 }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2712 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2713 if (response.ok) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2714 sessionStorage.removeItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2715 legacyClaimId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2716 _claimOutcome = "success"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2717 } else if (response.status === 409) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2718 /* Definitive non-legacy conflict: clear key, no retry needed */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2719 sessionStorage.removeItem(CONVERSATION_LEGACY_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2720 legacyClaimId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2721 _claimOutcome = "conflict"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2722 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2723 /* Retryable (401, 403, 429, 5xx): retain key */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2724 sessionStorage.setItem(CONVERSATION_LEGACY_KEY, legacyId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2725 legacyClaimId = legacyId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2726 _claimOutcome = "retry"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2727 } |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2728 } catch { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2729 /* Network error: retain key */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2730 sessionStorage.setItem(CONVERSATION_LEGACY_KEY, legacyId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2731 legacyClaimId = legacyId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2732 _claimOutcome = "network-error"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2733 } finally { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2734 /* Reset guard BEFORE re-rendering so the retry button is immediately usable */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2735 _claimInFlight = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2736 if (_claimOutcome === "success") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2737 void refreshArchiveFromScratch(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2738 } else if (_claimOutcome === "conflict") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2739 archive?.showLegacyClaim("Prior conversation already claimed.", false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2740 } else if (_claimOutcome === "retry") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2741 selectPanel("conversations", false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2742 archive?.showLegacyClaim("Claim failed. Try again. "); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2743 } else if (_claimOutcome === "network-error") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2744 selectPanel("conversations", false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2745 archive?.showLegacyClaim("Claim failed. Check connection. "); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2746 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2747 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2748 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2749 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2750 async function refreshArchiveFromScratch() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2751 if (!archive) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2752 const epoch = principalEpoch; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2753 archive.setLoading(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2754 _renderedIds.clear(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2755 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2756 const data = await fetchConversationList(null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2757 if (epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2758 archiveCursor = data.cursor || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2759 const convs = data.conversations || []; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2760 convs.forEach(c => _renderedIds.add(c.id)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2761 archive.setConversations(convs, archiveCursor); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2762 archive.setCurrentId(currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2763 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2764 archive.setError(`Archive error: ${error.message}`); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2765 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2766 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2767 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2768 async function refreshArchiveHead() { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2769 if (!archive) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2770 const epoch = principalEpoch; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2771 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2772 const data = await fetchConversationList(null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2773 if (epoch !== principalEpoch) return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2774 const fresh = data.conversations || []; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2775 for (const conv of fresh) archive.updateConversation(conv); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2776 if (fresh.length > 0) archive.setCurrentId(currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2777 } catch { /* silent refresh failure */ } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2778 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2779 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2780 /* ---- Parse and validate URL params at startup ---- */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2781 /* Track whether ?conversation was explicitly present (even if malformed) |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2782 so we never migrate sessionStorage when the param was given but invalid. */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2783 let _convParamWasExplicit = false; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2784 { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2785 const initParams = new URLSearchParams(window.location.search); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2786 const rawPanel = initParams.get("panel"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2787 const rawConvId = initParams.get("conversation"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2788 _convParamWasExplicit = rawConvId !== null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2789 const validPanel = VALID_PANELS.includes(rawPanel) ? rawPanel : null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2790 const validConvId = (rawConvId && UUID_REGEX.test(rawConvId)) ? rawConvId : null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2791 /* Remove invalid params with replaceState */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2792 if ((rawPanel && !validPanel) || (rawConvId && !validConvId)) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2793 const normalUrl = new URL(window.location.href); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2794 if (!validPanel) normalUrl.searchParams.delete("panel"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2795 if (!validConvId) normalUrl.searchParams.delete("conversation"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2796 history.replaceState( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2797 { panel: validPanel, conversation: validConvId }, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2798 "", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2799 normalUrl, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2800 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2801 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2802 currentPanel = validPanel || "resume"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2803 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2804 |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2805 /* ---- Load archive; only an explicit URL restores a conversation ---- */ |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2806 const startupEpoch = principalEpoch; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2807 const ensureStartupPrincipal = () => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2808 if (startupEpoch !== principalEpoch) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2809 const error = new Error("Principal changed during startup"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2810 error.name = "StalePrincipalError"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2811 throw error; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2812 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2813 }; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2814 archive?.setLoading(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2815 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2816 const data = await fetchConversationList(null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2817 ensureStartupPrincipal(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2818 archiveCursor = data.cursor || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2819 const conversations = data.conversations || []; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2820 conversations.forEach(c => _renderedIds.add(c.id)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2821 archive?.setConversations(conversations, archiveCursor); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2822 |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2823 /* A conversation opens only through an explicit URL or a user archive action. */ |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2824 const initParams2 = new URLSearchParams(window.location.search); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2825 const urlConvId = initParams2.get("conversation"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2826 const urlConvValid = urlConvId && UUID_REGEX.test(urlConvId) ? urlConvId : null; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2827 const storedConvId = !_convParamWasExplicit |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2828 ? sessionStorage.getItem(CONVERSATION_STORAGE_KEY) |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2829 : null; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2830 |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2831 if (urlConvValid) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2832 const inArchive = conversations.find(c => c.id === urlConvValid); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2833 if (inArchive) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2834 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2835 const conversation = await requestJson( |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2836 `/api/conversations/${encodeURIComponent(urlConvValid)}`, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2837 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2838 ensureStartupPrincipal(); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2839 currentConversationId = urlConvValid; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2840 sessionStorage.setItem(CONVERSATION_STORAGE_KEY, urlConvValid); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2841 chat?.replaceMessages(conversation.turns); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2842 archive?.setCurrentId(urlConvValid); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2843 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2844 if (error.name === "StalePrincipalError" || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2845 startupEpoch !== principalEpoch) throw error; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2846 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2847 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2848 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2849 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2850 /* Not on first page — fetch directly to verify ownership */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2851 let ownedConversation = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2852 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2853 ownedConversation = await requestJson( |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2854 `/api/conversations/${encodeURIComponent(urlConvValid)}`, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2855 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2856 ensureStartupPrincipal(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2857 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2858 if (error.name === "StalePrincipalError" || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2859 startupEpoch !== principalEpoch) throw error; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2860 ownedConversation = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2861 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2862 if (ownedConversation) { |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2863 currentConversationId = urlConvValid; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2864 sessionStorage.setItem(CONVERSATION_STORAGE_KEY, urlConvValid); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2865 chat?.replaceMessages(ownedConversation.turns); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2866 if (!_renderedIds.has(urlConvValid)) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2867 _renderedIds.add(urlConvValid); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2868 archive?.addConversation({ |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2869 id: urlConvValid, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2870 title: ownedConversation.title || "Conversation", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2871 turn_count: ownedConversation.turns?.length || 0, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2872 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2873 } |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2874 archive?.setCurrentId(urlConvValid); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2875 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2876 currentConversationId = null; |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2877 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2878 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2879 } |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2880 } else { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2881 currentConversationId = null; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2882 archive?.setCurrentId(null); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2883 if (conversations.length > 0) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2884 chat?.setGreeting(greetingForSession(_sessionData, true), true); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2885 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2886 if (storedConvId && UUID_REGEX.test(storedConvId)) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2887 const storedConversationIsOwned = conversations.some( |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2888 conversation => conversation.id === storedConvId, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2889 ); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2890 if (_sessionData?.kind === "user" && !storedConversationIsOwned) { |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2891 sessionStorage.setItem(CONVERSATION_LEGACY_KEY, storedConvId); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2892 legacyClaimId = storedConvId; |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2893 archive?.showLegacyClaim(); |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2894 } |
|
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2895 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2896 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2897 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2898 } catch (error) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2899 if (error.name !== "StalePrincipalError" && |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2900 startupEpoch === principalEpoch) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2901 archive?.setError(`Archive error: ${error.message}`); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2902 } |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2903 /* Fall back only for an explicit deep-linked conversation. */ |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2904 const initParams3 = new URLSearchParams(window.location.search); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2905 const fallbackId = initParams3.get("conversation"); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2906 if (startupEpoch === principalEpoch && |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2907 fallbackId && UUID_REGEX.test(fallbackId)) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2908 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2909 const conversation = await requestJson( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2910 `/api/conversations/${encodeURIComponent(fallbackId)}`, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2911 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2912 ensureStartupPrincipal(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2913 currentConversationId = fallbackId; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2914 chat?.replaceMessages(conversation.turns); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2915 } catch (fallbackError) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2916 if (fallbackError.name === "StalePrincipalError" || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2917 startupEpoch !== principalEpoch) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2918 // The new principal owns subsequent rendering. |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2919 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2920 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2921 currentConversationId = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2922 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2923 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2924 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2925 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2926 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2927 /* Apply startup panel and normalize URL (replaceState — not a user navigation) */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2928 if (startupEpoch === principalEpoch) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2929 selectPanel(currentPanel, false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2930 _replaceUrlState(currentPanel, currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2931 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2932 |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2933 shell?.addEventListener("mjj-jrpg-preview-change", event => { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2934 selectPanel(event.detail.selection); |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2935 shell?.showMobileDestination(event.detail.selection); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2936 character?.setAttribute("state", "thinking"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2937 window.clearTimeout(characterTimer); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2938 characterTimer = window.setTimeout(() => { |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2939 character?.setAttribute("state", "default"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2940 }, 650); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2941 }); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2942 |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2943 shell?.addEventListener("mjj-composer-cancel", () => { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2944 activeController?.abort(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2945 }); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2946 |
|
272
41a49c29a28f
polish JRPG conversation experience
MrJuneJune <me@mrjunejune.com>
parents:
265
diff
changeset
|
2947 shell?.addEventListener("mjj-composer-submit", async event => { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2948 if (activeController) return; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2949 /* Block sends when password change is required */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2950 if (_sessionData?.kind === "user" && _sessionData?.mustChangePassword) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2951 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2952 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2953 chat?.appendMessage("June", event.detail.message); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2954 composer?.setBusy(true); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2955 character?.setAttribute("state", "thinking"); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2956 window.clearTimeout(characterTimer); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2957 const assistantItem = chat?.startAssistantMessage(); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2958 chat?.setMessageStreaming(assistantItem, true); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2959 const assistantText = new StreamingTextAnimator(text => { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2960 chat?.setMessageText(assistantItem, text); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2961 }); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2962 let turnFinished = false; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2963 activeController = new AbortController(); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2964 activeController.signal.addEventListener("abort", () => { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2965 assistantText.cancel(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
2966 }, { once: true }); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2967 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2968 /* Disable archive/account mutations while stream is active (finding #7) */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2969 archive?.setStreamActive(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2970 setAccountActionsDisabled(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2971 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2972 try { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2973 const createConversation = async () => { |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2974 const resp = await mutatingFetch("/api/conversations", { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2975 method: "POST", |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2976 headers: { "Content-Type": "application/json" }, |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2977 body: JSON.stringify({ title: "Shiba Quest" }), |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
2978 }); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2979 if (!resp.ok) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2980 let message = `Create failed (${resp.status})`; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2981 try { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2982 const body = await resp.json(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2983 message = body.error?.message || message; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2984 } catch { /* keep */ } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2985 throw new Error(message); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2986 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2987 const conversation = await resp.json(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2988 currentConversationId = conversation.id; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2989 sessionStorage.setItem(CONVERSATION_STORAGE_KEY, currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2990 _pushUrlState(currentPanel, currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2991 if (!_renderedIds.has(currentConversationId)) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2992 _renderedIds.add(currentConversationId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2993 archive?.addConversation({ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2994 id: currentConversationId, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2995 title: "Shiba Quest", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2996 turn_count: 0, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2997 last_message_preview: event.detail.message.slice(0, 32), |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2998 }); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
2999 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3000 archive?.setCurrentId(currentConversationId); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3001 }; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3002 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3003 if (!currentConversationId) { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3004 await createConversation(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3005 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3006 |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3007 const postTurn = () => mutatingFetch( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3008 `/api/conversations/${encodeURIComponent(currentConversationId)}/turns`, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3009 { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3010 method: "POST", |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3011 headers: { "Content-Type": "application/json" }, |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3012 body: JSON.stringify({ prompt: event.detail.message }), |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3013 signal: activeController.signal, |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3014 }, |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3015 ); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3016 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3017 let response = await postTurn(); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3018 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3019 /* Handle 404: conversation may have expired — recreate it */ |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3020 if (response.status === 404) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3021 sessionStorage.removeItem(CONVERSATION_STORAGE_KEY); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3022 currentConversationId = null; |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3023 await createConversation(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3024 response = await postTurn(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3025 } |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3026 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3027 /* Handle 429: distinguish permanent quota from temporary capacity */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3028 if (response.status === 429) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3029 let errorBody = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3030 try { errorBody = await response.json(); } catch { /* keep */ } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3031 const code = errorBody?.error?.code || ""; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3032 const isQuotaExhausted = |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3033 code === "guest_quota_turns_exhausted" || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3034 code === "guest_quota_tokens_exhausted" || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3035 code === "guest_turn_quota_exhausted" || |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3036 code === "guest_token_quota_exhausted"; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3037 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3038 if (isQuotaExhausted) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3039 const quotaState = errorBody?.error?.quota || null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3040 updateQuotaDisplay(quotaEl, quotaState); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3041 composer?.setDisabled(true); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3042 chat?.setMessageStreaming(assistantItem, false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3043 chat?.setMessageText( |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3044 assistantItem, |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3045 quotaState |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3046 ? `Quota exhausted. ${formatQuotaText(quotaState)?.text || ""}` |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3047 : "Quota exhausted. Try again later.", |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3048 ); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3049 character?.setAttribute("state", "sad"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3050 setFrameStatus("QUOTA", "offline"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3051 /* Re-enable when quota resets */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3052 const resetsAt = quotaState?.resetsAt; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3053 if (resetsAt) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3054 const delay = Math.max(0, resetsAt * 1000 - Date.now()); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3055 window.setTimeout(() => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3056 if (_sessionData?.kind !== "user" || !_sessionData?.mustChangePassword) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3057 composer?.setDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3058 setFrameStatus("ONLINE", "online"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3059 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3060 }, Math.min(delay + 1000, 24 * 3600 * 1000)); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3061 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3062 } else { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3063 /* Temporary capacity 429 — use Retry-After or default 5 s */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3064 const retryAfter = parseInt(response.headers.get("Retry-After") || "5", 10); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3065 chat?.setMessageStreaming(assistantItem, false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3066 chat?.setMessageText(assistantItem, "Server busy. Retrying shortly…"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3067 character?.setAttribute("state", "sad"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3068 setFrameStatus("BUSY", "offline"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3069 window.setTimeout(() => { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3070 if (!activeController?.signal.aborted) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3071 setFrameStatus("ONLINE", "online"); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3072 composer?.setDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3073 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3074 }, retryAfter * 1000); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3075 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3076 return; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3077 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3078 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3079 if (!response.ok) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3080 let message = `Turn failed (${response.status})`; |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3081 try { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3082 const body = await response.json(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3083 message = body.error?.message || message; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3084 } catch { /* keep */ } |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3085 throw new Error(message); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3086 } |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3087 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3088 await consumeSse(response, (eventName, data) => { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3089 shell?.dispatchEvent(new CustomEvent("mjj-jrpg-stream-event", { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3090 bubbles: true, |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3091 detail: { data, type: eventName }, |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3092 })); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3093 if (eventName === "assistant.delta") { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3094 assistantText.append(data.delta || ""); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3095 } else if (eventName === "assistant.completed") { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3096 assistantText.complete(data.content); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3097 } else if (eventName === "turn.error") { |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3098 throw new Error( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3099 data.error?.message || data.message || "Inference turn failed", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3100 ); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3101 } else if (eventName === "turn.done") { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3102 turnFinished = true; |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3103 composer?.setCancellable(false); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3104 if (data.failed || data.aborted) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3105 throw new Error( |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3106 data.aborted ? "Inference turn aborted" : "Inference turn failed", |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3107 ); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3108 } |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3109 } |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3110 }); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3111 |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3112 if (!turnFinished) throw new Error("Inference stream ended unexpectedly"); |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3113 await assistantText.waitForIdle(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3114 if (activeController.signal.aborted) { |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3115 throw new DOMException("Quest cancelled", "AbortError"); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3116 } |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3117 chat?.setMessageStreaming(assistantItem, false); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3118 character?.setAttribute("state", "default"); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
3119 setFrameStatus("ONLINE", "online"); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3120 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3121 /* Refresh archive and quota after successful turn */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3122 void refreshArchiveHead(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3123 if (_sessionData?.kind === "guest") { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3124 _csrfToken = await _fetchSession(); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3125 updateQuotaDisplay(quotaEl, _sessionData?.quota || null); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3126 } |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3127 } catch (error) { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3128 const aborted = error instanceof DOMException && error.name === "AbortError"; |
|
261
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3129 assistantText.cancel(); |
|
b401627fc49e
Add JRPG mock flows and interactive previews
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
260
diff
changeset
|
3130 chat?.setMessageStreaming(assistantItem, false); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3131 chat?.setMessageText( |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3132 assistantItem, |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3133 aborted ? "Quest cancelled." : `System error: ${error.message}`, |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3134 ); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3135 character?.setAttribute("state", "sad"); |
|
263
ee04e4e69fed
Add functional JRPG frame and tools
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
262
diff
changeset
|
3136 if (!aborted) setFrameStatus("OFFLINE", "offline"); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3137 } finally { |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3138 composer?.setBusy(false); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3139 composer?.querySelector("textarea")?.focus(); |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3140 activeController = null; |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3141 /* Re-enable archive/account mutations exactly once */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3142 archive?.setStreamActive(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3143 setAccountActionsDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3144 /* Apply popstate that was queued during the stream (Fix 1) */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3145 if (_pendingPopState) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3146 const pending = _pendingPopState; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3147 _pendingPopState = null; |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3148 if (pending.seq === popSeq) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3149 await _applyPopState(pending.seq, pending.popPanel, pending.popConvId); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3150 } |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3151 } |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3152 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3153 }); |
|
264
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3154 |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3155 /* Enable composer unless forced password change */ |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3156 if (!isForced) { |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3157 composer?.setDisabled(false); |
|
04fee26ecce0
add authenticated JRPG conversation platform
MrJuneJune <me@mrjunejune.com>
parents:
263
diff
changeset
|
3158 } |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3159 } |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3160 |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3161 if (document.readyState === "loading") { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3162 document.addEventListener("DOMContentLoaded", () => { |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3163 void initializeJrpgPage(); |
|
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3164 }, { |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3165 once: true, |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3166 }); |
|
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3167 } else { |
|
260
1f9877b637e9
Add Copilot-powered cyberpunk JRPG chat
MrJuneJune <mrjunejune@users.noreply.github.com>
parents:
259
diff
changeset
|
3168 void initializeJrpgPage(); |
|
259
667156fcd3e3
Add dev-only cyberpunk JRPG page
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3169 } |