arcane-os 0.37.0 → 0.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/browser-runtime/pwa-install.mjs +42 -3
- package/browser-runtime/pwa.mjs +16 -0
- package/docs/reference/inventory/package-api.json +6 -6
- package/docs/reference/inventory/runtime-components.json +8 -6
- package/docs/reference/inventory/runtime-entities.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +20 -8
- package/docs/reference/pwa.md +68 -6
- package/docs/reference/runtime-components.md +44 -9
- package/docs/reference/runtime-entities.md +35 -2
- package/docs/reference/runtime-modules.md +151 -10
- package/docs/reference/sdk-api.md +31 -8
- package/package.json +1 -1
- package/runtime/arcane/components/chat.html +11 -2
- package/runtime/arcane/components/file-manager.html +24 -3
- package/runtime/arcane/components/header.html +5 -18
- package/runtime/arcane/components/pwa-install.html +43 -10
- package/runtime/arcane/css/layout.css +8 -201
- package/runtime/arcane/css/theme.css +278 -61
- package/runtime/arcane/entities/Chat.js +15 -3
- package/runtime/arcane/entities/User.js +20 -0
- package/runtime/arcane/modules/PersistentAIChatSession.js +28 -25
- package/runtime/arcane/modules/ThemeBootstrap.js +31 -3
- package/runtime/arcane/modules/ThemeManager.js +33 -1
- package/runtime/arcane/modules/ThemePresentation.js +138 -0
- package/src/pwa-worker.mjs +88 -2
|
@@ -90,6 +90,10 @@
|
|
|
90
90
|
closeLabel:'Close installation suggestion',
|
|
91
91
|
promptingLabel:'Choose an option in the browser installation prompt.',
|
|
92
92
|
description:'Open this app directly from your device.',
|
|
93
|
+
updateTitle:'Update available',
|
|
94
|
+
updateLabel:'Update',
|
|
95
|
+
updateDescription:'Reload this page to use the updated app.',
|
|
96
|
+
updateCloseLabel:'Close update suggestion',
|
|
93
97
|
presentation:host.dataset.presentation||'floating'
|
|
94
98
|
};
|
|
95
99
|
let currentState=owner.state;
|
|
@@ -101,6 +105,8 @@
|
|
|
101
105
|
host.configure=configure;
|
|
102
106
|
host.install=install;
|
|
103
107
|
host.dismiss=dismiss;
|
|
108
|
+
host.update=update;
|
|
109
|
+
host.dismissUpdate=dismissUpdate;
|
|
104
110
|
host.destroy=destroy;
|
|
105
111
|
Object.defineProperty(host,'state',{configurable:true,get:getState});
|
|
106
112
|
|
|
@@ -120,7 +126,8 @@
|
|
|
120
126
|
throw new TypeError('PWA install configuration must be an object.');
|
|
121
127
|
}
|
|
122
128
|
const next={...options,...input};
|
|
123
|
-
for(const key of ['appName','installLabel','closeLabel','promptingLabel','description'
|
|
129
|
+
for(const key of ['appName','installLabel','closeLabel','promptingLabel','description',
|
|
130
|
+
'updateTitle','updateLabel','updateDescription','updateCloseLabel']){
|
|
124
131
|
if(!is.string(next[key]))throw new TypeError(`PWA install ${key} must be a string.`);
|
|
125
132
|
}
|
|
126
133
|
if(next.presentation!=='floating'&&next.presentation!=='inline'){
|
|
@@ -128,28 +135,30 @@
|
|
|
128
135
|
}
|
|
129
136
|
options=next;
|
|
130
137
|
host.dataset.presentation=options.presentation;
|
|
131
|
-
title.textContent=`Install ${options.appName}`;
|
|
132
|
-
description.textContent=options.description;
|
|
133
|
-
installButton.textContent=options.installLabel;
|
|
134
|
-
closeButton.setAttribute('aria-label',options.closeLabel);
|
|
135
138
|
render();
|
|
136
139
|
return {...options};
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
function render(){
|
|
140
143
|
if(destroyed)return;
|
|
144
|
+
const updating=currentState.updateAvailable&&!currentState.updateDismissed;
|
|
141
145
|
const terminal=['accepted','installed','running','disposed'].includes(currentState.status);
|
|
142
146
|
if(terminal)requestError=null;
|
|
143
147
|
const dismissed=locallyDismissed
|
|
144
148
|
||(options.presentation==='floating'&¤tState.dismissed);
|
|
145
|
-
host.hidden=
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
host.hidden=currentState.status==='disposed'
|
|
150
|
+
||(!updating&&(terminal||dismissed||(!currentState.available&&!pending&&!requestError)));
|
|
151
|
+
title.textContent=updating?options.updateTitle:`Install ${options.appName}`;
|
|
152
|
+
description.textContent=updating?options.updateDescription:options.description;
|
|
153
|
+
installButton.textContent=updating?options.updateLabel:options.installLabel;
|
|
154
|
+
closeButton.setAttribute('aria-label',updating?options.updateCloseLabel:options.closeLabel);
|
|
155
|
+
installButton.disabled=updating?false:pending||!currentState.available;
|
|
156
|
+
const message=updating?'':requestError
|
|
148
157
|
?is.string(requestError.message)?requestError.message:String(requestError)
|
|
149
158
|
:pending?options.promptingLabel:'';
|
|
150
159
|
status.textContent=message;
|
|
151
160
|
status.hidden=!message;
|
|
152
|
-
status.dataset.error=String(Boolean(requestError));
|
|
161
|
+
status.dataset.error=String(!updating&&Boolean(requestError));
|
|
153
162
|
}
|
|
154
163
|
|
|
155
164
|
function observeInstallState(state){
|
|
@@ -192,6 +201,19 @@
|
|
|
192
201
|
return true;
|
|
193
202
|
}
|
|
194
203
|
|
|
204
|
+
function update(){
|
|
205
|
+
if(destroyed)return false;
|
|
206
|
+
return owner.update();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function dismissUpdate(){
|
|
210
|
+
if(destroyed)return false;
|
|
211
|
+
owner.dismissUpdate();
|
|
212
|
+
render();
|
|
213
|
+
emit('pwa-install-dismissed',{presentation:options.presentation,kind:'update',state:getState()});
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
|
|
195
217
|
function destroy(){
|
|
196
218
|
if(destroyed)return false;
|
|
197
219
|
destroyed=true;
|
|
@@ -203,11 +225,22 @@
|
|
|
203
225
|
}
|
|
204
226
|
|
|
205
227
|
installButton.addEventListener('click',function requestInstallation(){
|
|
228
|
+
if(currentState.updateAvailable&&!currentState.updateDismissed){
|
|
229
|
+
try{
|
|
230
|
+
update();
|
|
231
|
+
}catch(error){
|
|
232
|
+
arcaneLogging.error('Unable to reload the updated app:',error);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
206
236
|
install().catch(function reportInstallationFailure(error){
|
|
207
237
|
arcaneLogging.error('Unable to open the browser installation prompt:',error);
|
|
208
238
|
});
|
|
209
239
|
},{signal:lifecycleController.signal});
|
|
210
|
-
closeButton.addEventListener('click',
|
|
240
|
+
closeButton.addEventListener('click',function dismissSuggestion(){
|
|
241
|
+
if(currentState.updateAvailable&&!currentState.updateDismissed)dismissUpdate();
|
|
242
|
+
else dismiss();
|
|
243
|
+
},{signal:lifecycleController.signal});
|
|
211
244
|
|
|
212
245
|
configure();
|
|
213
246
|
owner.subscribe(observeInstallState,{signal:lifecycleController.signal});
|
|
@@ -1,106 +1,5 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
/* Base styles with default variables */
|
|
4
|
-
:root {
|
|
5
|
-
color-scheme:light;
|
|
6
|
-
--background:#E8EBF0;
|
|
7
|
-
--modal-background:#F8F9FB;
|
|
8
|
-
--text-color:#1F2937;
|
|
9
|
-
--primary-color:#52677F;
|
|
10
|
-
--secondary-color:#D8E1EB;
|
|
11
|
-
--accent-color:#305F8D;
|
|
12
|
-
--border-color:#C6CED8;
|
|
13
|
-
--platinum:#52606F;
|
|
14
|
-
--button-text-color:#FFFFFF;
|
|
15
|
-
--focus-color:#2878B8;
|
|
16
|
-
--success-color:#24804D;
|
|
17
|
-
--danger-color:#B43C3C;
|
|
18
|
-
--shadow-color:rgba(30,41,59,.18);
|
|
19
|
-
--icon-filter:none;
|
|
20
|
-
--file-icon-filter:hue-rotate(-8deg) saturate(.65) brightness(.88);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/* Warm Theme */
|
|
24
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.warm {
|
|
25
|
-
--background:#F8EFE5;
|
|
26
|
-
--modal-background:#FFF9F3;
|
|
27
|
-
--text-color:#352A24;
|
|
28
|
-
--primary-color:#AF5822;
|
|
29
|
-
--secondary-color:#F2D0AF;
|
|
30
|
-
--accent-color:#8D4318;
|
|
31
|
-
--border-color:#D8B99B;
|
|
32
|
-
--platinum:#725848;
|
|
33
|
-
--focus-color:#A64E19;
|
|
34
|
-
--file-icon-filter:hue-rotate(160deg) saturate(.85) brightness(.9);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/* Curious Theme */
|
|
38
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.curious {
|
|
39
|
-
--background:#EAF5EE;
|
|
40
|
-
--modal-background:#F8FCF9;
|
|
41
|
-
--text-color:#1E3327;
|
|
42
|
-
--primary-color:#287A4E;
|
|
43
|
-
--secondary-color:#CDE8D8;
|
|
44
|
-
--accent-color:#1E6A42;
|
|
45
|
-
--border-color:#AACDB8;
|
|
46
|
-
--platinum:#4D6B5A;
|
|
47
|
-
--focus-color:#1F7548;
|
|
48
|
-
--file-icon-filter:hue-rotate(285deg) saturate(.65) brightness(.82);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* Hopeful Theme */
|
|
52
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.hopeful {
|
|
53
|
-
--background:#EAF3F9;
|
|
54
|
-
--modal-background:#F8FCFF;
|
|
55
|
-
--text-color:#203247;
|
|
56
|
-
--primary-color:#2F6F9F;
|
|
57
|
-
--secondary-color:#CFE4F3;
|
|
58
|
-
--accent-color:#245F8B;
|
|
59
|
-
--border-color:#B5CEDF;
|
|
60
|
-
--platinum:#526C7F;
|
|
61
|
-
--focus-color:#246A9D;
|
|
62
|
-
--file-icon-filter:hue-rotate(345deg) saturate(.65) brightness(.95);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/* Harmony Theme */
|
|
66
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.harmony {
|
|
67
|
-
--background:#F2F0E5;
|
|
68
|
-
--modal-background:#FCFAF4;
|
|
69
|
-
--text-color:#303328;
|
|
70
|
-
--primary-color:#90602F;
|
|
71
|
-
--secondary-color:#DCE5C8;
|
|
72
|
-
--accent-color:#386B4F;
|
|
73
|
-
--border-color:#C9C6A9;
|
|
74
|
-
--platinum:#646650;
|
|
75
|
-
--focus-color:#4D7259;
|
|
76
|
-
--file-icon-filter:hue-rotate(150deg) saturate(.55) brightness(.78);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/* Warrior Spirit Theme (light)
|
|
80
|
-
Source cues: steel/gunmetal, ember heart, flame orange
|
|
81
|
-
Design intent: calm, confident neutrals with a hopeful flame CTA
|
|
82
|
-
*/
|
|
83
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.warrior {
|
|
84
|
-
/* Surfaces */
|
|
85
|
-
--background: #F5F7FA; /* cool off‑white “steel light” */
|
|
86
|
-
--modal-background: #EFF2F6; /* panel on the main surface */
|
|
87
|
-
|
|
88
|
-
/* Text */
|
|
89
|
-
--text-color: #1D232A; /* gunmetal charcoal for body text */
|
|
90
|
-
|
|
91
|
-
/* Brand actions */
|
|
92
|
-
--primary-color: #FF7A1A; /* flame orange (buttons, key actions) */
|
|
93
|
-
--secondary-color: #FFD166; /* ember glow for hovers / highlights */
|
|
94
|
-
--accent-color: #8C1D18; /* deep heart red for accents */
|
|
95
|
-
|
|
96
|
-
/* Lines & neutrals */
|
|
97
|
-
--border-color: #C7CDD6; /* cool steel border */
|
|
98
|
-
--platinum: #A7A9AC; /* neutral “platinum” metal */
|
|
99
|
-
|
|
100
|
-
/* Accessibility: keep button text dark on bright orange/gold */
|
|
101
|
-
--button-text-color: #1D232A; /* ensures AA contrast on primary/hover */
|
|
102
|
-
--file-icon-filter:hue-rotate(160deg) saturate(1.2) brightness(1.03);
|
|
103
|
-
}
|
|
1
|
+
/* Layout and controls consume the canonical shared palette definitions. */
|
|
2
|
+
@import url('./theme.css');
|
|
104
3
|
|
|
105
4
|
/* General styles for the page layout */
|
|
106
5
|
html {
|
|
@@ -112,7 +11,6 @@ html {
|
|
|
112
11
|
body {
|
|
113
12
|
display: grid;
|
|
114
13
|
grid-template-columns:11em minmax(0,1fr); /* Sidebar and content split */
|
|
115
|
-
transition:background-color 250ms,color 250ms;
|
|
116
14
|
grid-template-rows: auto 1fr; /* Header and main content */
|
|
117
15
|
height: 100vh;
|
|
118
16
|
margin: 0;
|
|
@@ -134,7 +32,6 @@ main {
|
|
|
134
32
|
border-radius: 0.5em 0 0 0;
|
|
135
33
|
overflow: auto;
|
|
136
34
|
padding: 1em;
|
|
137
|
-
transition:background-color 250ms;
|
|
138
35
|
}
|
|
139
36
|
|
|
140
37
|
main.data-chat{
|
|
@@ -337,102 +234,12 @@ pre code{
|
|
|
337
234
|
}
|
|
338
235
|
}
|
|
339
236
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
color-scheme:dark;
|
|
344
|
-
--background:#0F1220;
|
|
345
|
-
--modal-background:#191D31;
|
|
346
|
-
--text-color:#EBEDF5;
|
|
347
|
-
--primary-color:#D94C94;
|
|
348
|
-
--secondary-color:#43B8AD;
|
|
349
|
-
--accent-color:#A58ADF;
|
|
350
|
-
--border-color:#3A4262;
|
|
351
|
-
--platinum:#AEB5CA;
|
|
352
|
-
--button-text-color:#161724;
|
|
353
|
-
--focus-color:#65D8CE;
|
|
354
|
-
--success-color:#61C98B;
|
|
355
|
-
--danger-color:#F07D7D;
|
|
356
|
-
--shadow-color:rgba(0,0,0,.42);
|
|
357
|
-
--icon-filter:brightness(0) invert(.78);
|
|
358
|
-
--file-icon-filter:hue-rotate(95deg) saturate(.8) brightness(1.12);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/* Dark Mode - Warm Theme */
|
|
362
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.warm {
|
|
363
|
-
--background:#1D1613;
|
|
364
|
-
--modal-background:#2B211C;
|
|
365
|
-
--text-color:#F1E6DD;
|
|
366
|
-
--primary-color:#DF7C3B;
|
|
367
|
-
--secondary-color:#F1AA72;
|
|
368
|
-
--accent-color:#F0B783;
|
|
369
|
-
--border-color:#6A4939;
|
|
370
|
-
--platinum:#C9AB99;
|
|
371
|
-
--button-text-color:#24160E;
|
|
372
|
-
--focus-color:#FFB27A;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/* Dark Mode - Curious Theme */
|
|
376
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.curious {
|
|
377
|
-
--background:#101B16;
|
|
378
|
-
--modal-background:#1B2A22;
|
|
379
|
-
--text-color:#DFF1E6;
|
|
380
|
-
--primary-color:#4FAE78;
|
|
381
|
-
--secondary-color:#79C89B;
|
|
382
|
-
--accent-color:#86D1A7;
|
|
383
|
-
--border-color:#386247;
|
|
384
|
-
--platinum:#A6C4B0;
|
|
385
|
-
--button-text-color:#102117;
|
|
386
|
-
--focus-color:#8ED7AE;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/* Dark Mode - Hopeful Theme */
|
|
390
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.hopeful {
|
|
391
|
-
--background:#111821;
|
|
392
|
-
--modal-background:#1D2935;
|
|
393
|
-
--text-color:#E1EBF4;
|
|
394
|
-
--primary-color:#67A9D6;
|
|
395
|
-
--secondary-color:#96C7E8;
|
|
396
|
-
--accent-color:#A6D4F1;
|
|
397
|
-
--border-color:#3A5A72;
|
|
398
|
-
--platinum:#A8BAC9;
|
|
399
|
-
--button-text-color:#11202B;
|
|
400
|
-
--focus-color:#9CD2F5;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/* Dark Mode - Harmony Theme */
|
|
404
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.harmony {
|
|
405
|
-
--background:#191A14;
|
|
406
|
-
--modal-background:#282A21;
|
|
407
|
-
--text-color:#ECEBDB;
|
|
408
|
-
--primary-color:#D48A4B;
|
|
409
|
-
--secondary-color:#87B58E;
|
|
410
|
-
--accent-color:#E0AA70;
|
|
411
|
-
--border-color:#5C604A;
|
|
412
|
-
--platinum:#B9B9A3;
|
|
413
|
-
--button-text-color:#211A12;
|
|
414
|
-
--focus-color:#A7CEA9;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/* Warrior Spirit — Dark */
|
|
418
|
-
:root:not([data-color-scheme]):not([data-arcane-skin]) body.warrior {
|
|
419
|
-
--background: #0E1216; /* night steel */
|
|
420
|
-
--modal-background: #151A20; /* panel against night steel */
|
|
421
|
-
--text-color: #E9EEF3; /* soft steel-white for text */
|
|
422
|
-
|
|
423
|
-
/* Keep flame as the action color; hover warms slightly */
|
|
424
|
-
--primary-color: #FF7A1A; /* flame orange (unchanged) */
|
|
425
|
-
--secondary-color: #FFB24A; /* warm hover on dark */
|
|
426
|
-
--accent-color: #E04F3D; /* ember red that reads on dark */
|
|
427
|
-
--border-color: #26313B; /* subdued steel line */
|
|
428
|
-
--platinum:#A9B3BD;
|
|
429
|
-
--focus-color:#FFB24A;
|
|
430
|
-
|
|
431
|
-
/* Critical for contrast: dark text on bright buttons */
|
|
432
|
-
--button-text-color: #1D232A;
|
|
433
|
-
}
|
|
237
|
+
:root[data-color-scheme="dark"] a{
|
|
238
|
+
color:var(--secondary-color);
|
|
239
|
+
}
|
|
434
240
|
|
|
435
|
-
|
|
436
|
-
|
|
241
|
+
@media (prefers-color-scheme:dark){
|
|
242
|
+
:root:not([data-color-scheme]) a{
|
|
243
|
+
color:var(--secondary-color);
|
|
437
244
|
}
|
|
438
245
|
}
|