dsh-dracula-theme 0.1.0 → 0.1.2
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/lib/client.js +80 -22
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -456,13 +456,49 @@ window.__ModuleLoader__.load({
|
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
-
/**
|
|
459
|
+
/**
|
|
460
|
+
* The DSH Desktop client boots its web app on a fresh random port
|
|
461
|
+
* every launch (`--port 0`), and localStorage is scoped per origin —
|
|
462
|
+
* including the port. A choice saved under http://127.0.0.1:55337 is
|
|
463
|
+
* invisible to the next launch at http://127.0.0.1:49562, so the
|
|
464
|
+
* theme silently reverts to default on every desktop start.
|
|
465
|
+
* Cookies, by contrast, are scoped per host and ignore the port, and
|
|
466
|
+
* the desktop client keeps a persistent cookie jar. So the saved
|
|
467
|
+
* skin is mirrored into a host-scoped cookie; reads prefer the
|
|
468
|
+
* cookie and fall back to localStorage (the plain `dsh web` browser
|
|
469
|
+
* session keeps its fixed-port origin, where both stores agree).
|
|
470
|
+
*/
|
|
471
|
+
const COOKIE_KEY = "dsh-dracula-skin";
|
|
472
|
+
const COOKIE_MAX_AGE = 60 * 60 * 24 * 400;
|
|
473
|
+
|
|
474
|
+
/** Read a cookie value (null on absence). */
|
|
475
|
+
function readCookie(name) {
|
|
476
|
+
try {
|
|
477
|
+
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)`));
|
|
478
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
479
|
+
} catch {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Write (or remove with max-age=0) a cookie. */
|
|
485
|
+
function writeCookie(name, value) {
|
|
486
|
+
try {
|
|
487
|
+
if (value === null) document.cookie = `${name}=; path=/; max-age=0`;
|
|
488
|
+
else document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${COOKIE_MAX_AGE}`;
|
|
489
|
+
} catch {
|
|
490
|
+
// storage unavailable — the preference stays process-local
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/** Saved skin id (may be unknown/absent): cookie first, localStorage fallback. */
|
|
460
495
|
function readSavedSkin() {
|
|
461
|
-
return readStorage(STORAGE_KEY);
|
|
496
|
+
return readCookie(COOKIE_KEY) ?? readStorage(STORAGE_KEY);
|
|
462
497
|
}
|
|
463
498
|
|
|
464
499
|
/** Persist a skin choice; DEFAULT_SKIN clears the stored value. */
|
|
465
500
|
function writeSavedSkin(id) {
|
|
501
|
+
writeCookie(COOKIE_KEY, id === DEFAULT_SKIN ? null : id);
|
|
466
502
|
writeStorage(STORAGE_KEY, id === DEFAULT_SKIN ? null : id);
|
|
467
503
|
}
|
|
468
504
|
//#endregion
|
|
@@ -765,29 +801,51 @@ window.__ModuleLoader__.load({
|
|
|
765
801
|
style.remove();
|
|
766
802
|
}, "dsh-dracula-theme: surface tint lifecycle");
|
|
767
803
|
|
|
768
|
-
// Restore the saved skin
|
|
769
|
-
// built-in preference
|
|
770
|
-
//
|
|
771
|
-
//
|
|
772
|
-
//
|
|
773
|
-
//
|
|
804
|
+
// Restore the saved skin against the boot adoption storm. The
|
|
805
|
+
// ThemeService adopts its durable built-in preference
|
|
806
|
+
// ("light"/"dark"/"system") from the Host settings scope
|
|
807
|
+
// asynchronously after boot; every adoption emits theme/change
|
|
808
|
+
// with a built-in preference that overwrites a third-party one.
|
|
809
|
+
// In slower boot paths — the desktop client's RPC bridge emits
|
|
810
|
+
// more, later sync events — a fixed retry budget (a handful of
|
|
811
|
+
// tries within a few seconds) can be exhausted and the theme
|
|
812
|
+
// silently reverts to default. So instead of a time-boxed guard
|
|
813
|
+
// we stay armed while the storm is active: re-assert the saved
|
|
814
|
+
// skin on every built-in revert, and only yield to user actions
|
|
815
|
+
// once the preference has rested on the saved skin for a quiet
|
|
816
|
+
// period with no further adoption events.
|
|
774
817
|
const saved = readSavedSkin();
|
|
775
818
|
const savedValid = typeof saved === "string" && saved !== DEFAULT_SKIN && SKINS.some((skinDefinition) => skinDefinition.id === saved);
|
|
776
|
-
let
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
819
|
+
let armed = savedValid;
|
|
820
|
+
let quietTimer;
|
|
821
|
+
const disarm = () => {
|
|
822
|
+
armed = false;
|
|
823
|
+
};
|
|
824
|
+
const scheduleDisarm = () => {
|
|
825
|
+
clearTimeout(quietTimer);
|
|
826
|
+
quietTimer = setTimeout(disarm, 4000);
|
|
827
|
+
};
|
|
828
|
+
const reassertAgainstAdoption = () => {
|
|
829
|
+
if (!armed) return;
|
|
830
|
+
const pref = ctx.theme.getTheme().preference;
|
|
831
|
+
if (pref === saved) {
|
|
832
|
+
scheduleDisarm();
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
if (pref === "light" || pref === "dark" || pref === DEFAULT_SKIN) {
|
|
836
|
+
// A built-in won — during boot this can only be a scope
|
|
837
|
+
// adoption (nobody reaches the Appearance row that fast).
|
|
838
|
+
// Re-assert, then require another quiet period.
|
|
839
|
+
ctx.theme.setTheme(saved);
|
|
840
|
+
scheduleDisarm();
|
|
841
|
+
}
|
|
842
|
+
// Another third-party theme — the drop-foreign convention
|
|
843
|
+
// below clears our stored choice instead of fighting.
|
|
783
844
|
};
|
|
784
|
-
|
|
785
|
-
const bootWindow = setTimeout(() => {
|
|
786
|
-
bootGuard = 0;
|
|
787
|
-
}, 5000);
|
|
845
|
+
reassertAgainstAdoption();
|
|
788
846
|
ctx.effect(() => () => {
|
|
789
|
-
clearTimeout(
|
|
790
|
-
}, "dsh-dracula: boot restore
|
|
847
|
+
clearTimeout(quietTimer);
|
|
848
|
+
}, "dsh-dracula-theme: boot restore lifecycle");
|
|
791
849
|
|
|
792
850
|
const skinStore = createSkinStore();
|
|
793
851
|
let skinBound;
|
|
@@ -807,7 +865,7 @@ window.__ModuleLoader__.load({
|
|
|
807
865
|
// dispatch is missed by other subscribers (ui-layout's
|
|
808
866
|
// ThemePresenter), so the restored skin would never reach the DOM.
|
|
809
867
|
setTimeout(() => {
|
|
810
|
-
|
|
868
|
+
reassertAgainstAdoption();
|
|
811
869
|
}, 0);
|
|
812
870
|
});
|
|
813
871
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-dracula-theme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "🧛 Dracula theme for DeepSeek Harness: the classic dark palette (plus the Soft variant) registered into the built-in theme runtime",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ossFrankFrank",
|