UNPKG

3.24 kBPlain TextView Raw
1import type { ColorScheme } from "./client";
2import { data_fr_scheme, data_fr_theme, rootColorSchemeStyleTagId } from "./constants";
3import { fr } from "../fr";
4
5type GetScriptToRunAsap = (props: {
6 defaultColorScheme: ColorScheme | "system";
7 nonce: string | undefined;
8 trustedTypesPolicyName: string;
9}) => string;
10
11declare global {
12 interface Window {
13 ssrWasPerformedWithIsDark?: boolean;
14 ssrNonce?: string;
15 }
16}
17
18// TODO enhance to use DOMPurify with trustedTypes
19export const getScriptToRunAsap: GetScriptToRunAsap = ({
20 defaultColorScheme,
21 nonce = "",
22 trustedTypesPolicyName
23}) => `
24{
25
26 window.ssrWasPerformedWithIsDark = "${defaultColorScheme}" === "dark";
27 const sanitizer = typeof trustedTypes !== "undefined" ? trustedTypes.createPolicy("${trustedTypesPolicyName}-asap", { createHTML: s => s }) : {
28 createHTML: s => s,
29 };
30
31 const isDark = (() => {
32
33 const isDarkExplicitlyProvidedAsParameter = (() => {
34 if ("${defaultColorScheme}" === "system") {
35 return undefined;
36 }
37
38 switch ("${defaultColorScheme}") {
39 case "dark": return true;
40 case "light": return false;
41 }
42 })();
43
44 const isDarkFromLocalStorage = (() => {
45 const colorSchemeReadFromLocalStorage = localStorage.getItem("scheme");
46
47 if (colorSchemeReadFromLocalStorage === null) {
48 return undefined;
49 }
50
51 if (colorSchemeReadFromLocalStorage === "system") {
52 return undefined;
53 }
54
55 switch (colorSchemeReadFromLocalStorage) {
56 case "dark":
57 return true;
58 case "light":
59 return false;
60 }
61 })();
62
63 const isDarkFromOsPreference = (() => {
64 if (!window.matchMedia) {
65 return undefined;
66 }
67
68 return window.matchMedia("(prefers-color-scheme: dark)").matches;
69 })();
70
71 const isDarkFallback = false;
72
73 return (
74 isDarkFromLocalStorage ??
75 isDarkExplicitlyProvidedAsParameter ??
76 isDarkFromOsPreference ??
77 isDarkFallback
78 );
79
80 })();
81
82 ["${data_fr_scheme}", "${data_fr_theme}"].forEach(attr => document.documentElement.setAttribute(attr, isDark ? "dark" : "light"));
83
84 {
85
86 let element= document.getElementById("${rootColorSchemeStyleTagId}");
87
88 if( element !== null ){
89 element.remove()
90 }
91
92 element = document.createElement("style");
93
94 if ("${nonce}" !== "") {
95 element.setAttribute("nonce", "${nonce}");
96 }
97
98 element.id = "${rootColorSchemeStyleTagId}";
99
100 element.innerHTML = sanitizer.createHTML(\`:root { color-scheme: \${isDark ? "dark" : "light"}; }\`);
101
102 document.head.appendChild(element);
103
104 }
105
106 {
107
108 const name = "theme-color";
109
110 let element = document.querySelector(\`meta[name=\${name}]\`);
111
112 if( element !== null ){
113 element.remove();
114 }
115
116 element = document.createElement("meta");
117
118 element.name = name;
119
120 element.content = isDark ? "${
121 fr.colors.getHex({ "isDark": true }).decisions.background.default.grey.default
122 }" : "${fr.colors.getHex({ "isDark": false }).decisions.background.default.grey.default}";
123
124 document.head.appendChild(element);
125
126 }
127
128}
129`;