relmio 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +49 -5
- package/docs/maintenance.md +13 -1
- package/docs/security.md +8 -2
- package/docs/troubleshooting.md +31 -7
- package/docs/video-outline.md +13 -4
- package/package.json +1 -1
- package/src/ui/app.js +1 -1
- package/src/ui/index.html +27 -9
- package/src/ui/styles.css +182 -12
- package/src/ui/theme.js +50 -0
- package/src/web/server.js +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,48 @@ checks the registry separately after publication.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## [0.2.7] - 2026-08-02
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Restore the original Relmio hosted layout and local browser wizard flow, with
|
|
15
|
+
the horizontal five-step Signal Spine and GitHub star/version control kept
|
|
16
|
+
visible.
|
|
17
|
+
- Add Astryx's built theme and accessible segmented appearance control to the
|
|
18
|
+
hosted app, plus lightweight System/Light/Dark preference support to the
|
|
19
|
+
local wizard.
|
|
20
|
+
- Add responsive dark-mode logo treatment, phone-sized controls, and matching
|
|
21
|
+
browser-wizard guidance to the GitHub and npm README variants.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Keep the checksum-verified temporary Node.js 22 runtime on the child process
|
|
26
|
+
path so Git Bash and other Node-free systems can launch the Relmio package
|
|
27
|
+
shim without falling back to a missing or outdated system `node` command.
|
|
28
|
+
|
|
29
|
+
## [0.2.6] - 2026-08-02
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Add a curl-based wizard bootstrap for macOS, Linux, WSL, and Git Bash that
|
|
34
|
+
reuses Node.js 22+ or downloads and checksum-verifies a temporary official
|
|
35
|
+
runtime when Node.js is not installed.
|
|
36
|
+
- Add a native Windows PowerShell bootstrap for PowerShell and Command Prompt
|
|
37
|
+
that works without Git Bash or a preinstalled Node.js runtime and verifies
|
|
38
|
+
the temporary official Windows archive before execution.
|
|
39
|
+
- Expand the hosted installer into an accessible macOS/Linux, PowerShell,
|
|
40
|
+
Command Prompt, and NPX terminal switcher.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Revamp the hosted Vercel experience and local browser wizard around the
|
|
45
|
+
Signal Spine composition and Patchbay Ledger design language.
|
|
46
|
+
- Integrate the Astryx component system, neutral theme, CLI, and AI-readable
|
|
47
|
+
setup guidance in the hosted React application while keeping the published
|
|
48
|
+
wizard dependency-light.
|
|
49
|
+
- Add persistent route context, sanitized preview status, responsive layouts,
|
|
50
|
+
reduced-motion behavior, and synchronized GitHub/npm setup documentation.
|
|
51
|
+
|
|
10
52
|
## [0.2.5] - 2026-07-31
|
|
11
53
|
|
|
12
54
|
### Added
|
package/README.md
CHANGED
|
@@ -72,20 +72,64 @@ installing the private n8n sidecar.
|
|
|
72
72
|
</figure>
|
|
73
73
|
|
|
74
74
|
Use the site's [Install wizard](https://relmio.vercel.app/install) page for a
|
|
75
|
-
|
|
76
|
-
setup path.
|
|
75
|
+
clickable macOS/Linux, PowerShell, Command Prompt, and NPX command switcher
|
|
76
|
+
tailored to the current self-hosted n8n and Hostinger VPS setup path.
|
|
77
|
+
|
|
78
|
+
### Browser interface and theme modes
|
|
79
|
+
|
|
80
|
+
The hosted site and local wizard keep the original Relmio relay layout while
|
|
81
|
+
adding a compact **System / Light / Dark** appearance control. System follows
|
|
82
|
+
the computer's preference; Light and Dark are remembered on that browser only.
|
|
83
|
+
The local wizard keeps its horizontal five-step Signal Spine at the top of the
|
|
84
|
+
flow, and the hosted site keeps the live GitHub star/version control visible.
|
|
85
|
+
Both surfaces collapse their controls for narrow phone screens without
|
|
86
|
+
turning the setup flow into a side rail or requiring a separate mobile app.
|
|
77
87
|
|
|
78
88
|
## Quick start
|
|
79
89
|
|
|
80
|
-
|
|
90
|
+
Choose the terminal already on your own computer. Do not run these commands on
|
|
91
|
+
the VPS.
|
|
92
|
+
|
|
93
|
+
### macOS, Linux, WSL, or Git Bash
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
curl -fsSL https://relmio.vercel.app/install.sh | sh
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Windows PowerShell
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
irm https://relmio.vercel.app/install.ps1 | iex
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Windows Command Prompt
|
|
106
|
+
|
|
107
|
+
```bat
|
|
108
|
+
powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://relmio.vercel.app/install.ps1 | iex"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
No Node.js or Git Bash installation is required first. The
|
|
112
|
+
[POSIX](https://github.com/Demonbane18/relmio/blob/main/web/public/install.sh)
|
|
113
|
+
and [Windows PowerShell](https://github.com/Demonbane18/relmio/blob/main/web/public/install.ps1)
|
|
114
|
+
bootstraps reuse Node.js 22 or newer when available. Otherwise they download
|
|
115
|
+
the matching current official Node.js 22 runtime to a private temporary
|
|
116
|
+
directory, verify its SHA-256 checksum, run Relmio with npm lifecycle scripts
|
|
117
|
+
disabled, and remove the temporary runtime when the wizard closes.
|
|
118
|
+
|
|
119
|
+
Users who already have Node.js 22 or newer can run the npm package directly:
|
|
120
|
+
|
|
121
|
+
### NPX (requires Node.js 22+)
|
|
81
122
|
|
|
82
123
|
```bash
|
|
83
124
|
npx --yes --ignore-scripts relmio@latest
|
|
84
125
|
```
|
|
85
126
|
|
|
86
|
-
Requirements
|
|
127
|
+
### Requirements
|
|
87
128
|
|
|
88
|
-
-
|
|
129
|
+
- On macOS/Linux/WSL/Git Bash: `curl`, `awk`, `tar`, and either `sha256sum` or
|
|
130
|
+
`shasum`; Git Bash also needs `unzip`
|
|
131
|
+
- On native Windows: Windows PowerShell 5.1 or PowerShell 7; Command Prompt can
|
|
132
|
+
launch the included PowerShell bootstrap
|
|
89
133
|
- A browser and an eligible ChatGPT/Codex account
|
|
90
134
|
- A self-hosted n8n Docker deployment on a VPS
|
|
91
135
|
- Docker Compose v2, SSH access, and a Docker network shared with n8n
|
package/docs/maintenance.md
CHANGED
|
@@ -5,7 +5,19 @@ Every command on this page targets the separate
|
|
|
5
5
|
|
|
6
6
|
## Refresh an expired ChatGPT login
|
|
7
7
|
|
|
8
|
-
The easiest method
|
|
8
|
+
The easiest method is to open the
|
|
9
|
+
[hosted install page](https://relmio.vercel.app/install) and choose the local
|
|
10
|
+
terminal you already have. For macOS, Linux, WSL, or Git Bash:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
curl -fsSL https://relmio.vercel.app/install.sh | sh
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
For Windows PowerShell, with no Git Bash or preinstalled Node.js required:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
irm https://relmio.vercel.app/install.ps1 | iex
|
|
20
|
+
```
|
|
9
21
|
|
|
10
22
|
1. Start the local wizard again.
|
|
11
23
|
2. Select **Refresh ChatGPT sign-in**.
|
package/docs/security.md
CHANGED
|
@@ -92,8 +92,14 @@ The current release pins:
|
|
|
92
92
|
- `ssh2` `1.17.0`
|
|
93
93
|
- `openai-oauth` `2.0.0`
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
The POSIX and native Windows PowerShell bootstraps reuse a compatible local
|
|
96
|
+
Node.js runtime or download the matching current official Node.js 22 archive
|
|
97
|
+
to a private temporary directory. Each validates the archive against Node.js's
|
|
98
|
+
SHA-256 manifest before execution and removes it when the wizard closes. The
|
|
99
|
+
PowerShell bootstrap accepts only strict Windows x64 or ARM64 archive names,
|
|
100
|
+
uses HTTPS without redirects, and enables TLS 1.2 for Windows PowerShell 5.1.
|
|
101
|
+
npm lifecycle scripts are disabled when either bootstrap starts Relmio. The
|
|
102
|
+
generated sidecar also installs `openai-oauth` with `--ignore-scripts`.
|
|
97
103
|
|
|
98
104
|
Do not replace pinned versions with `latest` in production. Follow the upgrade
|
|
99
105
|
checklist in [maintenance.md](maintenance.md).
|
package/docs/troubleshooting.md
CHANGED
|
@@ -30,17 +30,39 @@ it after the wizard saves the credential.
|
|
|
30
30
|
|
|
31
31
|
## Confirm the local package first
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Close every old wizard terminal and browser tab, then run the newest published
|
|
34
|
+
build on your own computer, not on the VPS. Choose the command for the terminal
|
|
35
|
+
you already have.
|
|
36
|
+
|
|
37
|
+
macOS, Linux, WSL, or Git Bash:
|
|
34
38
|
|
|
35
39
|
```bash
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
curl -fsSL https://relmio.vercel.app/install.sh | sh
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Windows PowerShell:
|
|
44
|
+
|
|
45
|
+
```powershell
|
|
46
|
+
irm https://relmio.vercel.app/install.ps1 | iex
|
|
38
47
|
```
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
Windows Command Prompt:
|
|
50
|
+
|
|
51
|
+
```bat
|
|
52
|
+
powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://relmio.vercel.app/install.ps1 | iex"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
These commands do not require Node.js to be installed. The Windows options do
|
|
56
|
+
not require Git Bash. Each bootstrap reuses Node.js 22 or newer when available,
|
|
57
|
+
or downloads an official temporary runtime and verifies its SHA-256 checksum
|
|
58
|
+
before execution.
|
|
59
|
+
|
|
60
|
+
If you choose the existing-Node fallback, confirm Node is version 22 or newer
|
|
61
|
+
and check the published package version first:
|
|
42
62
|
|
|
43
63
|
```bash
|
|
64
|
+
node --version
|
|
65
|
+
npm view relmio version
|
|
44
66
|
npx --yes --ignore-scripts relmio@latest
|
|
45
67
|
```
|
|
46
68
|
|
|
@@ -49,7 +71,7 @@ newest printed `http://127.0.0.1:...` URL into the browser. That URL contains a
|
|
|
49
71
|
temporary setup token: do not post it in an issue or screenshot.
|
|
50
72
|
|
|
51
73
|
You do not need to sign in to npm, configure npm 2FA, or own this package to
|
|
52
|
-
run
|
|
74
|
+
run any public command. npm authentication is required only for the
|
|
53
75
|
maintainer who publishes a release.
|
|
54
76
|
|
|
55
77
|
## Quick VPS checks
|
|
@@ -88,7 +110,9 @@ bypassed.
|
|
|
88
110
|
|
|
89
111
|
| Symptom | Meaning | Fix |
|
|
90
112
|
|---|---|---|
|
|
91
|
-
| `node: command not found`, `node is not recognized`, or Node is older than 22 | The
|
|
113
|
+
| `node: command not found`, `node is not recognized`, or Node is older than 22 | The NPX fallback cannot use the local runtime. | Use the macOS/Linux curl command or the native Windows PowerShell/Command Prompt command above. Either can run with a verified temporary runtime. Do not install Node.js on the VPS for the wizard. |
|
|
114
|
+
| `curl` or `sh` is not recognized on Windows | The macOS/Linux command was pasted into a native Windows terminal. | Use the PowerShell command in PowerShell, or the longer `powershell -NoProfile ...` command in Command Prompt. Git Bash is not required. |
|
|
115
|
+
| A bootstrap reports a checksum mismatch | The Node.js download did not match the official SHA-256 manifest, so it was not executed. | Retry on a trusted connection. Do not bypass the check. If it repeats, use an existing Node.js 22+ installation and report the sanitized error. |
|
|
92
116
|
| The browser did not open | The automatic browser launch failed, but the local server may still be running. | Keep the newest terminal open and copy its newest `127.0.0.1` setup URL into the browser. Do not reuse a URL from a closed terminal. |
|
|
93
117
|
| An old wizard page reports an invalid or expired setup session | The local server was closed or a newer wizard run created a different one-time session token. | Close the old page and use only the URL printed by the currently running terminal. |
|
|
94
118
|
| `npx` appears to run an older wizard | An old terminal or tab is still active, or the package was run without an explicit tag. | Close old runs, check `npm view relmio version`, then run `npx --yes --ignore-scripts relmio@latest`. |
|
package/docs/video-outline.md
CHANGED
|
@@ -41,17 +41,26 @@ Use this simple explanation:
|
|
|
41
41
|
|
|
42
42
|
On screen: the Mermaid flowchart in the README.
|
|
43
43
|
|
|
44
|
-
### 2:20 — Start the
|
|
44
|
+
### 2:20 — Start the wizard
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Open the hosted install page and choose the terminal already on the local
|
|
47
|
+
computer. Show both the macOS/Linux and native Windows choices:
|
|
47
48
|
|
|
48
49
|
```bash
|
|
49
|
-
|
|
50
|
+
curl -fsSL https://relmio.vercel.app/install.sh | sh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
irm https://relmio.vercel.app/install.ps1 | iex
|
|
50
55
|
```
|
|
51
56
|
|
|
52
57
|
Explain that:
|
|
53
58
|
|
|
54
|
-
-
|
|
59
|
+
- no preinstalled Node.js runtime is required;
|
|
60
|
+
- native Windows does not require Git Bash and also has a Command Prompt option;
|
|
61
|
+
- the bootstrap reuses Node.js 22+ or downloads and checksum-verifies a
|
|
62
|
+
temporary official Node.js 22 runtime;
|
|
63
|
+
- npm lifecycle scripts stay disabled when it starts the published package;
|
|
55
64
|
- the wizard binds to `127.0.0.1`;
|
|
56
65
|
- the printed setup URL is private and temporary;
|
|
57
66
|
- the terminal must remain open until the wizard finishes.
|
package/package.json
CHANGED
package/src/ui/app.js
CHANGED
|
@@ -294,7 +294,7 @@ async function discover() {
|
|
|
294
294
|
element("container-select"),
|
|
295
295
|
result.containers.map((container) => ({
|
|
296
296
|
value: container.name,
|
|
297
|
-
label: `${container.name}
|
|
297
|
+
label: `${container.name} - ${container.image}`,
|
|
298
298
|
})),
|
|
299
299
|
result.containers[0].name,
|
|
300
300
|
);
|
package/src/ui/index.html
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
name="description"
|
|
8
8
|
content="Relmio connects compatible AI clients to a private ChatGPT/Codex OAuth sidecar, starting with self-hosted n8n."
|
|
9
9
|
/>
|
|
10
|
-
<title>Relmio
|
|
10
|
+
<title>Relmio | n8n Setup</title>
|
|
11
11
|
<link
|
|
12
12
|
rel="icon"
|
|
13
13
|
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath fill='%23137c74' d='M7 8h19l31 24H41L26 20v10L7 17Z'/%3E%3Cpath fill='%2312211f' d='M7 47l19-13v10l15-12h16L26 56H7Z'/%3E%3C/svg%3E"
|
|
14
14
|
/>
|
|
15
15
|
<link rel="stylesheet" href="/styles.css" />
|
|
16
|
+
<script src="/theme.js" type="module"></script>
|
|
16
17
|
<script src="/app.js" type="module"></script>
|
|
17
18
|
</head>
|
|
18
19
|
<body>
|
|
@@ -31,7 +32,24 @@
|
|
|
31
32
|
</svg>
|
|
32
33
|
<span>Relmio</span>
|
|
33
34
|
</div>
|
|
34
|
-
<
|
|
35
|
+
<div class="header-actions">
|
|
36
|
+
<fieldset class="theme-picker">
|
|
37
|
+
<legend class="visually-hidden">Color theme</legend>
|
|
38
|
+
<label>
|
|
39
|
+
<input type="radio" name="color-theme" value="system" checked />
|
|
40
|
+
<span>System</span>
|
|
41
|
+
</label>
|
|
42
|
+
<label>
|
|
43
|
+
<input type="radio" name="color-theme" value="light" />
|
|
44
|
+
<span>Light</span>
|
|
45
|
+
</label>
|
|
46
|
+
<label>
|
|
47
|
+
<input type="radio" name="color-theme" value="dark" />
|
|
48
|
+
<span>Dark</span>
|
|
49
|
+
</label>
|
|
50
|
+
</fieldset>
|
|
51
|
+
<span class="local-badge">Runs only on this computer</span>
|
|
52
|
+
</div>
|
|
35
53
|
</header>
|
|
36
54
|
|
|
37
55
|
<main id="main-content" class="shell">
|
|
@@ -141,7 +159,7 @@
|
|
|
141
159
|
placeholder="your-vps-ip-or-hostname"
|
|
142
160
|
required
|
|
143
161
|
/>
|
|
144
|
-
<small>Use the full IP address
|
|
162
|
+
<small>Use the full IP address. Do not add <code>ssh root@</code>.</small>
|
|
145
163
|
</label>
|
|
146
164
|
|
|
147
165
|
<label class="field compact">
|
|
@@ -226,8 +244,8 @@
|
|
|
226
244
|
</div>
|
|
227
245
|
|
|
228
246
|
<div class="version-strip" aria-label="Detected Docker versions">
|
|
229
|
-
<span>Docker <strong id="docker-version"
|
|
230
|
-
<span>Compose <strong id="compose-version"
|
|
247
|
+
<span>Docker <strong id="docker-version">Not detected</strong></span>
|
|
248
|
+
<span>Compose <strong id="compose-version">Not detected</strong></span>
|
|
231
249
|
</div>
|
|
232
250
|
|
|
233
251
|
<div class="field-grid single">
|
|
@@ -266,7 +284,7 @@
|
|
|
266
284
|
<ul class="check-list">
|
|
267
285
|
<li>Create or update <code>/docker/n8n-openai-oauth</code></li>
|
|
268
286
|
<li>Build and start only the <code>openai-oauth</code> sidecar</li>
|
|
269
|
-
<li>Attach the sidecar to <strong id="review-network"
|
|
287
|
+
<li>Attach the sidecar to <strong id="review-network">Not selected</strong></li>
|
|
270
288
|
<li>
|
|
271
289
|
Use the private hostname
|
|
272
290
|
<code id="review-endpoint">n8n-openai-oauth</code>
|
|
@@ -361,12 +379,12 @@
|
|
|
361
379
|
</button>
|
|
362
380
|
|
|
363
381
|
<div class="model-box">
|
|
364
|
-
<h3>2. OpenAI Chat Model
|
|
382
|
+
<h3>2. OpenAI Chat Model for AI Agent or Basic LLM Chain</h3>
|
|
365
383
|
<dl class="result-list">
|
|
366
384
|
<div>
|
|
367
385
|
<dt>Model ID</dt>
|
|
368
386
|
<dd class="result-value">
|
|
369
|
-
<code id="result-model"
|
|
387
|
+
<code id="result-model">Not detected</code>
|
|
370
388
|
<button
|
|
371
389
|
class="button secondary copy-value"
|
|
372
390
|
type="button"
|
|
@@ -383,7 +401,7 @@
|
|
|
383
401
|
<dd><strong>On</strong> for Chat Model node version 1.3</dd>
|
|
384
402
|
</div>
|
|
385
403
|
</dl>
|
|
386
|
-
<p>All models detected: <span id="result-models"
|
|
404
|
+
<p>All models detected: <span id="result-models">Not detected</span></p>
|
|
387
405
|
<p>
|
|
388
406
|
If the Responses API switch is absent, keep the node's default
|
|
389
407
|
Chat Completions behavior; the bridge supports that route too.
|
package/src/ui/styles.css
CHANGED
|
@@ -11,11 +11,15 @@
|
|
|
11
11
|
--accent-deep: #0c5f59;
|
|
12
12
|
--accent-bright: #1ba397;
|
|
13
13
|
--accent-soft: #e9f4ef;
|
|
14
|
+
--accent-border: #b9d9d2;
|
|
15
|
+
--accent-icon: #d3eae0;
|
|
16
|
+
--accent-copy: #355a54;
|
|
14
17
|
--warning: #8a4b0f;
|
|
15
18
|
--warning-soft: #fff4e2;
|
|
16
19
|
--warning-border: #e3c491;
|
|
17
20
|
--danger: #a22b2b;
|
|
18
21
|
--danger-soft: #fff0f0;
|
|
22
|
+
--danger-border: #e4abab;
|
|
19
23
|
--success: #17653f;
|
|
20
24
|
--ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
21
25
|
--shadow-sm: 0 1px 2px rgb(13 27 24 / 5%);
|
|
@@ -27,6 +31,62 @@
|
|
|
27
31
|
--radius-lg: 1.25rem;
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
:root[data-theme="dark"] {
|
|
35
|
+
color-scheme: dark;
|
|
36
|
+
--background: #101513;
|
|
37
|
+
--surface: #1d2421;
|
|
38
|
+
--surface-muted: #171d1b;
|
|
39
|
+
--text: #edf3f0;
|
|
40
|
+
--text-muted: #a9b8b3;
|
|
41
|
+
--border: #303a36;
|
|
42
|
+
--border-strong: #52615b;
|
|
43
|
+
--accent-bright: #52c7bb;
|
|
44
|
+
--accent-soft: #1c2925;
|
|
45
|
+
--accent-border: #35564f;
|
|
46
|
+
--accent-icon: #20342f;
|
|
47
|
+
--accent-copy: #b8d8d1;
|
|
48
|
+
--warning: #f0b37f;
|
|
49
|
+
--warning-soft: #2a2118;
|
|
50
|
+
--warning-border: #725237;
|
|
51
|
+
--danger: #f09a9a;
|
|
52
|
+
--danger-soft: #2b1b1b;
|
|
53
|
+
--danger-border: #744141;
|
|
54
|
+
--success: #61c897;
|
|
55
|
+
--shadow-sm: 0 1px 2px rgb(0 0 0 / 24%);
|
|
56
|
+
--shadow-md:
|
|
57
|
+
0 1px 2px rgb(0 0 0 / 22%),
|
|
58
|
+
0 12px 36px -14px rgb(0 0 0 / 58%);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@media (prefers-color-scheme: dark) {
|
|
62
|
+
:root:not([data-theme]) {
|
|
63
|
+
color-scheme: dark;
|
|
64
|
+
--background: #101513;
|
|
65
|
+
--surface: #1d2421;
|
|
66
|
+
--surface-muted: #171d1b;
|
|
67
|
+
--text: #edf3f0;
|
|
68
|
+
--text-muted: #a9b8b3;
|
|
69
|
+
--border: #303a36;
|
|
70
|
+
--border-strong: #52615b;
|
|
71
|
+
--accent-bright: #52c7bb;
|
|
72
|
+
--accent-soft: #1c2925;
|
|
73
|
+
--accent-border: #35564f;
|
|
74
|
+
--accent-icon: #20342f;
|
|
75
|
+
--accent-copy: #b8d8d1;
|
|
76
|
+
--warning: #f0b37f;
|
|
77
|
+
--warning-soft: #2a2118;
|
|
78
|
+
--warning-border: #725237;
|
|
79
|
+
--danger: #f09a9a;
|
|
80
|
+
--danger-soft: #2b1b1b;
|
|
81
|
+
--danger-border: #744141;
|
|
82
|
+
--success: #61c897;
|
|
83
|
+
--shadow-sm: 0 1px 2px rgb(0 0 0 / 24%);
|
|
84
|
+
--shadow-md:
|
|
85
|
+
0 1px 2px rgb(0 0 0 / 22%),
|
|
86
|
+
0 12px 36px -14px rgb(0 0 0 / 58%);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
30
90
|
* {
|
|
31
91
|
box-sizing: border-box;
|
|
32
92
|
}
|
|
@@ -103,7 +163,7 @@ a:focus-visible {
|
|
|
103
163
|
min-height: 4.25rem;
|
|
104
164
|
padding: 0.75rem clamp(1rem, 4vw, 3rem);
|
|
105
165
|
border-bottom: 1px solid rgb(221 227 223 / 75%);
|
|
106
|
-
background:
|
|
166
|
+
background: color-mix(in srgb, var(--background) 82%, transparent);
|
|
107
167
|
backdrop-filter: blur(14px) saturate(1.4);
|
|
108
168
|
-webkit-backdrop-filter: blur(14px) saturate(1.4);
|
|
109
169
|
}
|
|
@@ -122,6 +182,78 @@ a:focus-visible {
|
|
|
122
182
|
width: 2rem;
|
|
123
183
|
height: 2rem;
|
|
124
184
|
flex: none;
|
|
185
|
+
border-radius: 0.4375rem;
|
|
186
|
+
transition:
|
|
187
|
+
background 180ms var(--ease),
|
|
188
|
+
box-shadow 180ms var(--ease);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.header-actions {
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
gap: 0.625rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.theme-picker {
|
|
198
|
+
display: inline-flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
gap: 0.125rem;
|
|
201
|
+
min-width: 0;
|
|
202
|
+
margin: 0;
|
|
203
|
+
padding: 0.1875rem;
|
|
204
|
+
border: 1px solid var(--border);
|
|
205
|
+
border-radius: 0.625rem;
|
|
206
|
+
background: var(--surface-muted);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.theme-picker label {
|
|
210
|
+
position: relative;
|
|
211
|
+
cursor: pointer;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.theme-picker input {
|
|
215
|
+
position: absolute;
|
|
216
|
+
opacity: 0;
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.theme-picker span {
|
|
221
|
+
min-height: 2rem;
|
|
222
|
+
display: inline-flex;
|
|
223
|
+
align-items: center;
|
|
224
|
+
justify-content: center;
|
|
225
|
+
padding: 0 0.625rem;
|
|
226
|
+
border-radius: 0.4375rem;
|
|
227
|
+
color: var(--text-muted);
|
|
228
|
+
font-size: 0.6875rem;
|
|
229
|
+
font-weight: 700;
|
|
230
|
+
transition:
|
|
231
|
+
color 160ms var(--ease),
|
|
232
|
+
background 160ms var(--ease),
|
|
233
|
+
box-shadow 160ms var(--ease);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.theme-picker input:checked + span {
|
|
237
|
+
color: var(--text);
|
|
238
|
+
background: var(--surface);
|
|
239
|
+
box-shadow: var(--shadow-sm);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.theme-picker input:focus-visible + span {
|
|
243
|
+
outline: 3px solid #f2a94a;
|
|
244
|
+
outline-offset: 2px;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.visually-hidden {
|
|
248
|
+
position: absolute;
|
|
249
|
+
width: 1px;
|
|
250
|
+
height: 1px;
|
|
251
|
+
padding: 0;
|
|
252
|
+
margin: -1px;
|
|
253
|
+
overflow: hidden;
|
|
254
|
+
clip: rect(0 0 0 0);
|
|
255
|
+
white-space: nowrap;
|
|
256
|
+
border: 0;
|
|
125
257
|
}
|
|
126
258
|
|
|
127
259
|
.local-badge {
|
|
@@ -215,7 +347,7 @@ h3 {
|
|
|
215
347
|
align-items: start;
|
|
216
348
|
margin: 1.25rem 0 0;
|
|
217
349
|
padding: 1rem 1.125rem;
|
|
218
|
-
border: 1px solid
|
|
350
|
+
border: 1px solid var(--accent-border);
|
|
219
351
|
border-radius: var(--radius);
|
|
220
352
|
background: var(--accent-soft);
|
|
221
353
|
box-shadow: var(--shadow-sm);
|
|
@@ -229,7 +361,7 @@ h3 {
|
|
|
229
361
|
place-items: center;
|
|
230
362
|
border-radius: 0.625rem;
|
|
231
363
|
color: var(--accent-deep);
|
|
232
|
-
background:
|
|
364
|
+
background: var(--accent-icon);
|
|
233
365
|
font-size: 1rem;
|
|
234
366
|
font-weight: 800;
|
|
235
367
|
content: "✓";
|
|
@@ -240,7 +372,7 @@ h3 {
|
|
|
240
372
|
}
|
|
241
373
|
|
|
242
374
|
.safety-note span {
|
|
243
|
-
color:
|
|
375
|
+
color: var(--accent-copy);
|
|
244
376
|
}
|
|
245
377
|
|
|
246
378
|
.backup-note {
|
|
@@ -250,7 +382,7 @@ h3 {
|
|
|
250
382
|
|
|
251
383
|
.backup-note::before {
|
|
252
384
|
color: var(--warning);
|
|
253
|
-
background:
|
|
385
|
+
background: color-mix(in srgb, var(--warning) 18%, var(--surface));
|
|
254
386
|
content: "!";
|
|
255
387
|
}
|
|
256
388
|
|
|
@@ -383,7 +515,7 @@ h3 {
|
|
|
383
515
|
}
|
|
384
516
|
|
|
385
517
|
.error {
|
|
386
|
-
border: 1px solid
|
|
518
|
+
border: 1px solid var(--danger-border);
|
|
387
519
|
color: var(--danger);
|
|
388
520
|
background: var(--danger-soft);
|
|
389
521
|
font-weight: 650;
|
|
@@ -478,7 +610,7 @@ h3 {
|
|
|
478
610
|
border: 1px solid var(--border-strong);
|
|
479
611
|
border-radius: var(--radius-sm);
|
|
480
612
|
color: var(--text);
|
|
481
|
-
background:
|
|
613
|
+
background: var(--surface);
|
|
482
614
|
transition:
|
|
483
615
|
border-color 200ms var(--ease),
|
|
484
616
|
box-shadow 200ms var(--ease),
|
|
@@ -527,7 +659,7 @@ h3 {
|
|
|
527
659
|
code {
|
|
528
660
|
padding: 0.1rem 0.3rem;
|
|
529
661
|
border-radius: 0.25rem;
|
|
530
|
-
background:
|
|
662
|
+
background: var(--surface-muted);
|
|
531
663
|
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
532
664
|
font-size: 0.875em;
|
|
533
665
|
overflow-wrap: anywhere;
|
|
@@ -626,7 +758,7 @@ code {
|
|
|
626
758
|
.button.copied {
|
|
627
759
|
border-color: var(--success);
|
|
628
760
|
color: var(--success);
|
|
629
|
-
background:
|
|
761
|
+
background: color-mix(in srgb, var(--success) 12%, var(--surface));
|
|
630
762
|
}
|
|
631
763
|
|
|
632
764
|
/* ---------- Fingerprint & approvals ---------- */
|
|
@@ -655,7 +787,7 @@ code {
|
|
|
655
787
|
padding: 0.625rem 0.75rem;
|
|
656
788
|
border: 1px solid var(--warning-border);
|
|
657
789
|
border-radius: var(--radius-sm);
|
|
658
|
-
background:
|
|
790
|
+
background: var(--surface);
|
|
659
791
|
}
|
|
660
792
|
|
|
661
793
|
.check-row {
|
|
@@ -709,12 +841,12 @@ code {
|
|
|
709
841
|
}
|
|
710
842
|
|
|
711
843
|
.review-grid section:first-child {
|
|
712
|
-
border-color:
|
|
844
|
+
border-color: var(--accent-border);
|
|
713
845
|
background: var(--accent-soft);
|
|
714
846
|
}
|
|
715
847
|
|
|
716
848
|
.review-grid section:last-child {
|
|
717
|
-
border-color:
|
|
849
|
+
border-color: var(--danger-border);
|
|
718
850
|
background: var(--danger-soft);
|
|
719
851
|
}
|
|
720
852
|
|
|
@@ -831,6 +963,32 @@ footer p {
|
|
|
831
963
|
margin: 0;
|
|
832
964
|
}
|
|
833
965
|
|
|
966
|
+
/* ---------- Dark mode refinement ---------- */
|
|
967
|
+
|
|
968
|
+
:root[data-theme="dark"] .brand-mark {
|
|
969
|
+
padding: 0.125rem;
|
|
970
|
+
background: #f7f8f5;
|
|
971
|
+
box-shadow: 0 0 0 1px rgb(255 255 255 / 14%);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
:root[data-theme="dark"] .eyebrow,
|
|
975
|
+
:root[data-theme="dark"] .step-kicker {
|
|
976
|
+
color: var(--accent-bright);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
@media (prefers-color-scheme: dark) {
|
|
980
|
+
:root:not([data-theme]) .brand-mark {
|
|
981
|
+
padding: 0.125rem;
|
|
982
|
+
background: #f7f8f5;
|
|
983
|
+
box-shadow: 0 0 0 1px rgb(255 255 255 / 14%);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
:root:not([data-theme]) .eyebrow,
|
|
987
|
+
:root:not([data-theme]) .step-kicker {
|
|
988
|
+
color: var(--accent-bright);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
834
992
|
/* ---------- Animations ---------- */
|
|
835
993
|
|
|
836
994
|
@keyframes panel-in {
|
|
@@ -884,6 +1042,18 @@ footer p {
|
|
|
884
1042
|
display: none;
|
|
885
1043
|
}
|
|
886
1044
|
|
|
1045
|
+
.site-header {
|
|
1046
|
+
padding-inline: 1rem;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
.header-actions {
|
|
1050
|
+
gap: 0.375rem;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
.theme-picker span {
|
|
1054
|
+
padding-inline: 0.5rem;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
887
1057
|
.shell {
|
|
888
1058
|
width: min(100% - 1rem, 54rem);
|
|
889
1059
|
padding-top: 2rem;
|
package/src/ui/theme.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const colorModes = new Set(["system", "light", "dark"]);
|
|
2
|
+
const storageKey = "relmio-color-mode";
|
|
3
|
+
|
|
4
|
+
function applyMode(mode) {
|
|
5
|
+
if (mode === "light" || mode === "dark") {
|
|
6
|
+
document.documentElement.dataset.theme = mode;
|
|
7
|
+
} else {
|
|
8
|
+
delete document.documentElement.dataset.theme;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
document
|
|
12
|
+
.querySelectorAll('input[name="color-theme"]')
|
|
13
|
+
.forEach((input) => {
|
|
14
|
+
input.checked = input.value === mode;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let initialMode = "system";
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const savedMode = window.localStorage.getItem(storageKey);
|
|
22
|
+
if (colorModes.has(savedMode)) {
|
|
23
|
+
initialMode = savedMode;
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// System mode remains available when browser storage is unavailable.
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
applyMode(initialMode);
|
|
30
|
+
|
|
31
|
+
document
|
|
32
|
+
.querySelectorAll('input[name="color-theme"]')
|
|
33
|
+
.forEach((input) => {
|
|
34
|
+
input.addEventListener("change", () => {
|
|
35
|
+
if (!input.checked || !colorModes.has(input.value)) return;
|
|
36
|
+
|
|
37
|
+
applyMode(input.value);
|
|
38
|
+
try {
|
|
39
|
+
window.localStorage.setItem(storageKey, input.value);
|
|
40
|
+
} catch {
|
|
41
|
+
// The selection still applies for this page view.
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
window.addEventListener("storage", (event) => {
|
|
47
|
+
if (event.key === storageKey) {
|
|
48
|
+
applyMode(colorModes.has(event.newValue) ? event.newValue : "system");
|
|
49
|
+
}
|
|
50
|
+
});
|
package/src/web/server.js
CHANGED
|
@@ -179,6 +179,7 @@ async function loadDefaultUiFiles() {
|
|
|
179
179
|
const files = await Promise.all([
|
|
180
180
|
readFile(new URL("../ui/index.html", import.meta.url), "utf8"),
|
|
181
181
|
readFile(new URL("../ui/app.js", import.meta.url), "utf8"),
|
|
182
|
+
readFile(new URL("../ui/theme.js", import.meta.url), "utf8"),
|
|
182
183
|
readFile(new URL("../ui/time.js", import.meta.url), "utf8"),
|
|
183
184
|
readFile(new URL("../ui/styles.css", import.meta.url), "utf8"),
|
|
184
185
|
]);
|
|
@@ -186,8 +187,9 @@ async function loadDefaultUiFiles() {
|
|
|
186
187
|
return {
|
|
187
188
|
"/": files[0],
|
|
188
189
|
"/app.js": files[1],
|
|
189
|
-
"/
|
|
190
|
-
"/
|
|
190
|
+
"/theme.js": files[2],
|
|
191
|
+
"/time.js": files[3],
|
|
192
|
+
"/styles.css": files[4],
|
|
191
193
|
};
|
|
192
194
|
}
|
|
193
195
|
|