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.
@@ -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'&&currentState.dismissed);
145
- host.hidden=terminal||dismissed||(!currentState.available&&!pending&&!requestError);
146
- installButton.disabled=pending||!currentState.available;
147
- const message=requestError
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',dismiss,{signal:lifecycleController.signal});
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
- /* layout.css */
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
- @media (prefers-color-scheme: dark) {
341
- /* Base Dark Mode Variables */
342
- :root:not([data-color-scheme]) {
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
- a{
436
- color: var(--secondary-color);
241
+ @media (prefers-color-scheme:dark){
242
+ :root:not([data-color-scheme]) a{
243
+ color:var(--secondary-color);
437
244
  }
438
245
  }