@filipgutica/ui 0.2.2 → 0.3.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/README.md +22 -0
- package/dist/open-vsx.js +129 -112
- package/package.json +8 -2
- package/src/components.css +64 -14
- package/src/theme.css +60 -59
package/README.md
CHANGED
|
@@ -79,6 +79,28 @@ redistribute theme assets remain responsible for their licenses.
|
|
|
79
79
|
this package so applications keep a consistent design language.
|
|
80
80
|
- `@filipgutica/ui/open-vsx` is Node-only. Do not import it into browser bundles.
|
|
81
81
|
|
|
82
|
+
## Docs and sandbox
|
|
83
|
+
|
|
84
|
+
Start the component docs and sandbox:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
pnpm docs:dev
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Build the provider-neutral static assets:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
pnpm docs:build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The docs use hash routes, so the static assets do not require rewrite rules.
|
|
97
|
+
The local Vite server also provides the same-origin `/api/open-vsx` endpoint.
|
|
98
|
+
The theme picker uses this endpoint to search and import Open VSX themes.
|
|
99
|
+
|
|
100
|
+
A production host must provide the same API endpoint for live Open VSX imports.
|
|
101
|
+
Netlify and Amplify can use a serverless adapter. GitHub Pages needs an external
|
|
102
|
+
API or a catalog of normalized themes built in advance.
|
|
103
|
+
|
|
82
104
|
## Development
|
|
83
105
|
|
|
84
106
|
```sh
|
package/dist/open-vsx.js
CHANGED
|
@@ -3,36 +3,36 @@ import { parse as n } from "jsonc-parser";
|
|
|
3
3
|
import { createHash as r } from "node:crypto";
|
|
4
4
|
import i from "jszip";
|
|
5
5
|
//#region src/open-vsx/index.ts
|
|
6
|
-
var a = "https://open-vsx.org", o = `${a}/api/-/search`,
|
|
6
|
+
var a = "https://open-vsx.org", o = "https://openvsx.eclipsecontent.org", s = `${a}/api/-/search`, c = 524288, l = 262144, u = 262144, d = 1048576, f = 20971520, p = 5e3, m = 104857600, h = 200, g = 40, _ = 8, v = 15e3, y = class extends Error {
|
|
7
7
|
code;
|
|
8
8
|
constructor(e, t) {
|
|
9
9
|
super(t), this.name = "OpenVsxThemeError", this.code = e;
|
|
10
10
|
}
|
|
11
|
-
},
|
|
11
|
+
}, b = (e) => typeof e == "object" && !!e && !Array.isArray(e), x = (e, t) => {
|
|
12
12
|
let r = [], i = n(e, r, { allowTrailingComma: !0 });
|
|
13
|
-
if (r.length > 0 || !
|
|
13
|
+
if (r.length > 0 || !b(i)) throw new y("unsupported-extension", `${t} is not valid JSON.`);
|
|
14
14
|
return i;
|
|
15
|
-
},
|
|
15
|
+
}, S = (e, { allowResourceOrigin: t = !1 } = {}) => {
|
|
16
16
|
if (typeof e != "string") return null;
|
|
17
17
|
try {
|
|
18
|
-
let
|
|
19
|
-
return
|
|
18
|
+
let n = new URL(e), r = n.origin.toLowerCase();
|
|
19
|
+
return r === a || t && r === o ? n.toString() : null;
|
|
20
20
|
} catch {
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
|
-
},
|
|
23
|
+
}, C = (e) => {
|
|
24
24
|
let t = /^([a-z0-9][a-z0-9_-]{0,99})\.([a-z0-9][a-z0-9_-]{0,99})$/i.exec(e);
|
|
25
|
-
if (!t?.[1] || !t[2]) throw new
|
|
25
|
+
if (!t?.[1] || !t[2]) throw new y("unsupported-extension", "The selected Open VSX extension identifier is invalid.");
|
|
26
26
|
return [t[1], t[2]];
|
|
27
|
-
},
|
|
28
|
-
let t =
|
|
29
|
-
return Array.isArray(t?.themes) ? t.themes.filter(
|
|
30
|
-
},
|
|
27
|
+
}, w = (e) => {
|
|
28
|
+
let t = b(e.contributes) ? e.contributes : null;
|
|
29
|
+
return Array.isArray(t?.themes) ? t.themes.filter(b) : [];
|
|
30
|
+
}, T = async (e, t, n) => {
|
|
31
31
|
let r = Number(e.headers.get("content-length"));
|
|
32
|
-
if (Number.isFinite(r) && r > t) throw new
|
|
32
|
+
if (Number.isFinite(r) && r > t) throw new y("file-too-large", n);
|
|
33
33
|
if (!e.body) {
|
|
34
34
|
let r = new Uint8Array(await e.arrayBuffer());
|
|
35
|
-
if (r.byteLength > t) throw new
|
|
35
|
+
if (r.byteLength > t) throw new y("file-too-large", n);
|
|
36
36
|
return r;
|
|
37
37
|
}
|
|
38
38
|
let i = e.body.getReader(), a = [], o = 0;
|
|
@@ -40,7 +40,7 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
40
40
|
for (;;) {
|
|
41
41
|
let { done: e, value: r } = await i.read();
|
|
42
42
|
if (e) break;
|
|
43
|
-
if (o += r.byteLength, o > t) throw await i.cancel(), new
|
|
43
|
+
if (o += r.byteLength, o > t) throw await i.cancel(), new y("file-too-large", n);
|
|
44
44
|
a.push(r);
|
|
45
45
|
}
|
|
46
46
|
} finally {
|
|
@@ -49,24 +49,24 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
49
49
|
let s = new Uint8Array(o), c = 0;
|
|
50
50
|
for (let e of a) s.set(e, c), c += e.byteLength;
|
|
51
51
|
return s;
|
|
52
|
-
},
|
|
53
|
-
let
|
|
52
|
+
}, E = (e) => async ({ url: t, limit: n, failureMessage: r, tooLargeMessage: i, allowResourceOrigin: a = !1 }) => {
|
|
53
|
+
let o = new AbortController(), s = setTimeout(() => o.abort(), v);
|
|
54
54
|
try {
|
|
55
|
-
let
|
|
56
|
-
if (!
|
|
57
|
-
let
|
|
55
|
+
let s = S(String(t), { allowResourceOrigin: a });
|
|
56
|
+
if (!s) throw new y("open-vsx-unavailable", r);
|
|
57
|
+
let c = await e(s, {
|
|
58
58
|
redirect: "follow",
|
|
59
|
-
signal:
|
|
59
|
+
signal: o.signal
|
|
60
60
|
});
|
|
61
|
-
if (!
|
|
62
|
-
return await
|
|
61
|
+
if (!S(c.url || s, { allowResourceOrigin: a }) || !c.ok) throw new y("open-vsx-unavailable", r);
|
|
62
|
+
return await T(c, n, i);
|
|
63
63
|
} catch (e) {
|
|
64
|
-
throw e instanceof
|
|
64
|
+
throw e instanceof y ? e : new y("open-vsx-unavailable", o.signal.aborted ? "Open VSX took too long to respond." : r);
|
|
65
65
|
} finally {
|
|
66
|
-
clearTimeout(
|
|
66
|
+
clearTimeout(s);
|
|
67
67
|
}
|
|
68
|
-
},
|
|
69
|
-
if (!
|
|
68
|
+
}, D = (e) => {
|
|
69
|
+
if (!b(e)) return null;
|
|
70
70
|
let t = typeof e.namespace == "string" ? e.namespace.trim() : "", n = typeof e.name == "string" ? e.name.trim() : "";
|
|
71
71
|
if (!t || !n) return null;
|
|
72
72
|
let r = typeof e.displayName == "string" && e.displayName.trim() ? e.displayName.trim() : n;
|
|
@@ -77,49 +77,49 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
77
77
|
description: typeof e.description == "string" ? e.description.slice(0, 300) : "",
|
|
78
78
|
downloadCount: typeof e.downloadCount == "number" && Number.isFinite(e.downloadCount) ? Math.max(0, e.downloadCount) : 0
|
|
79
79
|
};
|
|
80
|
-
},
|
|
81
|
-
if (e.length > 1024 || e.includes("\0") || e.startsWith("/") || /^[a-z]:/i.test(e)) throw new
|
|
82
|
-
},
|
|
83
|
-
|
|
80
|
+
}, O = (e) => {
|
|
81
|
+
if (e.length > 1024 || e.includes("\0") || e.startsWith("/") || /^[a-z]:/i.test(e)) throw new y("unsupported-extension", "A theme path is not safe.");
|
|
82
|
+
}, k = ({ path: e, initialSegments: t, minimumDepth: n }) => {
|
|
83
|
+
O(e);
|
|
84
84
|
let r = [...t];
|
|
85
85
|
for (let t of e.replaceAll("\\", "/").split("/")) if (!(!t || t === ".")) {
|
|
86
86
|
if (t === "..") {
|
|
87
|
-
if (r.length <= n) throw new
|
|
87
|
+
if (r.length <= n) throw new y("unsupported-extension", "A theme path escapes its package.");
|
|
88
88
|
r.pop();
|
|
89
89
|
} else r.push(t);
|
|
90
90
|
}
|
|
91
91
|
return r.join("/");
|
|
92
|
-
},
|
|
92
|
+
}, A = (e, t = "extension/") => {
|
|
93
93
|
let n = t.split("/").slice(0, -1);
|
|
94
|
-
return n[0] !== "extension" && n.unshift("extension"),
|
|
94
|
+
return n[0] !== "extension" && n.unshift("extension"), k({
|
|
95
95
|
path: e,
|
|
96
96
|
initialSegments: n,
|
|
97
97
|
minimumDepth: 1
|
|
98
98
|
});
|
|
99
|
-
},
|
|
100
|
-
let t =
|
|
99
|
+
}, j = (e) => {
|
|
100
|
+
let t = k({
|
|
101
101
|
path: e,
|
|
102
102
|
initialSegments: [],
|
|
103
103
|
minimumDepth: 0
|
|
104
104
|
});
|
|
105
|
-
if (!t) throw new
|
|
105
|
+
if (!t) throw new y("unsupported-extension", "The extension package has an invalid file name.");
|
|
106
106
|
return t;
|
|
107
|
-
},
|
|
107
|
+
}, M = (e) => {
|
|
108
108
|
let t = e.byteLength, n = Math.max(0, t - 65557), r = t - 22;
|
|
109
109
|
for (; r >= n && (e.getUint32(r, !0) !== 101010256 || r + 22 + e.getUint16(r + 20, !0) !== t);) --r;
|
|
110
|
-
if (r < n) throw new
|
|
110
|
+
if (r < n) throw new y("unsupported-extension", "The extension package is not a valid ZIP file.");
|
|
111
111
|
return r;
|
|
112
|
-
},
|
|
113
|
-
let t =
|
|
114
|
-
if (i !== t || i > e.byteLength) throw new
|
|
112
|
+
}, N = (e) => {
|
|
113
|
+
let t = M(e), n = e.getUint32(t + 12, !0), r = e.getUint32(t + 16, !0), i = r + n;
|
|
114
|
+
if (i !== t || i > e.byteLength) throw new y("unsupported-extension", "The extension package has an invalid ZIP directory.");
|
|
115
115
|
return {
|
|
116
116
|
start: r,
|
|
117
117
|
end: i
|
|
118
118
|
};
|
|
119
|
-
},
|
|
120
|
-
if (n + 46 > r || t.getUint32(n, !0) !== 33639248) throw new
|
|
119
|
+
}, P = ({ bytes: e, view: t, offset: n, directoryEnd: r }) => {
|
|
120
|
+
if (n + 46 > r || t.getUint32(n, !0) !== 33639248) throw new y("unsupported-extension", "The extension package has an invalid ZIP directory.");
|
|
121
121
|
let i = t.getUint32(n + 20, !0), a = t.getUint32(n + 24, !0), o = t.getUint16(n + 28, !0), s = t.getUint16(n + 30, !0), c = t.getUint16(n + 32, !0), l = n + 46 + o + s + c;
|
|
122
|
-
if (l > r || i === 4294967295 || a === 4294967295 || a > 0 && (i === 0 || a / i >
|
|
122
|
+
if (l > r || i === 4294967295 || a === 4294967295 || a > 0 && (i === 0 || a / i > h)) throw new y("unsupported-extension", "The extension package has unsafe ZIP metadata.");
|
|
123
123
|
try {
|
|
124
124
|
return {
|
|
125
125
|
name: new TextDecoder("utf-8", { fatal: !0 }).decode(e.subarray(n + 46, n + 46 + o)),
|
|
@@ -127,32 +127,32 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
127
127
|
nextOffset: l
|
|
128
128
|
};
|
|
129
129
|
} catch {
|
|
130
|
-
throw new
|
|
130
|
+
throw new y("unsupported-extension", "The extension package has an invalid file name.");
|
|
131
131
|
}
|
|
132
|
-
},
|
|
133
|
-
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n =
|
|
132
|
+
}, F = (e) => {
|
|
133
|
+
let t = new DataView(e.buffer, e.byteOffset, e.byteLength), n = N(t), r = /* @__PURE__ */ new Map(), i = 0, a = 0, o = n.start;
|
|
134
134
|
for (; o < n.end;) {
|
|
135
|
-
if (a += 1, a >
|
|
136
|
-
let s =
|
|
135
|
+
if (a += 1, a > p) throw new y("unsupported-extension", "The extension package has an invalid ZIP directory.");
|
|
136
|
+
let s = P({
|
|
137
137
|
bytes: e,
|
|
138
138
|
view: t,
|
|
139
139
|
offset: o,
|
|
140
140
|
directoryEnd: n.end
|
|
141
141
|
});
|
|
142
|
-
if (i += s.uncompressed, i >
|
|
143
|
-
r.set(
|
|
142
|
+
if (i += s.uncompressed, i > m) throw new y("file-too-large", "The extension package expands beyond the safe limit.");
|
|
143
|
+
r.set(j(s.name), s.uncompressed), o = s.nextOffset;
|
|
144
144
|
}
|
|
145
145
|
return r;
|
|
146
|
-
},
|
|
146
|
+
}, I = async ({ zip: e, sizes: t, path: n, description: r }) => {
|
|
147
147
|
let i = t.get(n);
|
|
148
|
-
if (i === void 0) throw new
|
|
149
|
-
if (i >
|
|
148
|
+
if (i === void 0) throw new y("unsupported-extension", `${r} is missing.`);
|
|
149
|
+
if (i > d) throw new y("file-too-large", `${r} is too large.`);
|
|
150
150
|
let a = e.file(n);
|
|
151
|
-
if (!a) throw new
|
|
151
|
+
if (!a) throw new y("unsupported-extension", `${r} is missing.`);
|
|
152
152
|
return a.async("string");
|
|
153
|
-
},
|
|
154
|
-
if (r.size >=
|
|
155
|
-
let i =
|
|
153
|
+
}, L = async ({ zip: e, sizes: t, path: n, ancestors: r = /* @__PURE__ */ new Set() }) => {
|
|
154
|
+
if (r.size >= _ || r.has(n)) throw new y("unsupported-extension", "Theme includes are cyclic or too deeply nested.");
|
|
155
|
+
let i = x(await I({
|
|
156
156
|
zip: e,
|
|
157
157
|
sizes: t,
|
|
158
158
|
path: n,
|
|
@@ -161,90 +161,93 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
161
161
|
if (typeof i.include != "string") return i;
|
|
162
162
|
let a = new Set(r);
|
|
163
163
|
a.add(n);
|
|
164
|
-
let o = await
|
|
164
|
+
let o = await L({
|
|
165
165
|
zip: e,
|
|
166
166
|
sizes: t,
|
|
167
|
-
path:
|
|
167
|
+
path: A(i.include, n),
|
|
168
168
|
ancestors: a
|
|
169
169
|
});
|
|
170
170
|
return {
|
|
171
171
|
...o,
|
|
172
172
|
...i,
|
|
173
173
|
colors: {
|
|
174
|
-
...
|
|
175
|
-
...
|
|
174
|
+
...b(o.colors) ? o.colors : {},
|
|
175
|
+
...b(i.colors) ? i.colors : {}
|
|
176
176
|
}
|
|
177
177
|
};
|
|
178
|
-
},
|
|
179
|
-
let [n, r] =
|
|
178
|
+
}, R = (e) => e === "vs" ? "light" : e === "vs-dark" ? "dark" : e === "hc-black" ? "hc" : e === "hc-light" ? "hcLight" : null, z = (e, t) => e.find((e) => t === "dark" ? e.appearance === "dark" || e.appearance === "high-contrast-dark" : e.appearance === "light" || e.appearance === "high-contrast-light") ?? e[0], B = async ({ request: e, extensionId: t }) => {
|
|
179
|
+
let [n, r] = C(t), i = await e({
|
|
180
180
|
url: `${a}/api/${encodeURIComponent(n)}/${encodeURIComponent(r)}`,
|
|
181
|
-
limit:
|
|
181
|
+
limit: l,
|
|
182
182
|
failureMessage: "Open VSX theme details are unavailable right now.",
|
|
183
183
|
tooLargeMessage: "Open VSX returned unexpectedly large theme details."
|
|
184
184
|
}), o = JSON.parse(new TextDecoder().decode(i));
|
|
185
|
-
if (!
|
|
186
|
-
let s =
|
|
187
|
-
if (!
|
|
185
|
+
if (!b(o) || !b(o.files)) throw new y("unsupported-extension", "Open VSX returned malformed theme details.");
|
|
186
|
+
let s = { allowResourceOrigin: !0 }, c = S(o.files.manifest, s), u = S(o.files.download, s), d = S(o.files.sha256, s), f = typeof o.version == "string" ? o.version : "";
|
|
187
|
+
if (!c || !u || !d || !f) throw new y("unsupported-extension", "Open VSX returned malformed theme details.");
|
|
188
188
|
return {
|
|
189
189
|
extensionName: r,
|
|
190
|
-
manifestUrl:
|
|
191
|
-
packageUrl:
|
|
192
|
-
checksumUrl:
|
|
193
|
-
version:
|
|
190
|
+
manifestUrl: c,
|
|
191
|
+
packageUrl: u,
|
|
192
|
+
checksumUrl: d,
|
|
193
|
+
version: f
|
|
194
194
|
};
|
|
195
|
-
},
|
|
195
|
+
}, V = async ({ request: e, manifestUrl: t }) => {
|
|
196
196
|
let n = await e({
|
|
197
197
|
url: t,
|
|
198
|
-
limit:
|
|
198
|
+
limit: u,
|
|
199
199
|
failureMessage: "That extension has no readable manifest.",
|
|
200
|
-
tooLargeMessage: "That extension manifest is too large."
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
tooLargeMessage: "That extension manifest is too large.",
|
|
201
|
+
allowResourceOrigin: !0
|
|
202
|
+
}), r = w(x(new TextDecoder().decode(n), "The extension manifest"));
|
|
203
|
+
if (r.length === 0 || r.length > g) throw new y("unsupported-extension", "That extension does not contain a supported number of color themes.");
|
|
204
|
+
}, H = async ({ request: e, packageUrl: t, checksumUrl: n }) => {
|
|
204
205
|
let [i, a] = await Promise.all([e({
|
|
205
206
|
url: t,
|
|
206
|
-
limit:
|
|
207
|
+
limit: f,
|
|
207
208
|
failureMessage: "That Open VSX theme could not be downloaded.",
|
|
208
|
-
tooLargeMessage: "That theme extension is too large to import safely."
|
|
209
|
+
tooLargeMessage: "That theme extension is too large to import safely.",
|
|
210
|
+
allowResourceOrigin: !0
|
|
209
211
|
}), e({
|
|
210
212
|
url: n,
|
|
211
213
|
limit: 256,
|
|
212
214
|
failureMessage: "That Open VSX theme has no readable checksum.",
|
|
213
|
-
tooLargeMessage: "That Open VSX checksum response is invalid."
|
|
215
|
+
tooLargeMessage: "That Open VSX checksum response is invalid.",
|
|
216
|
+
allowResourceOrigin: !0
|
|
214
217
|
})]), o = new TextDecoder().decode(a).trim().split(/\s+/)[0], s = r("sha256").update(i).digest("hex");
|
|
215
|
-
if (!o || !/^[a-f\d]{64}$/i.test(o)) throw new
|
|
216
|
-
if (o.toLowerCase() !== s) throw new
|
|
218
|
+
if (!o || !/^[a-f\d]{64}$/i.test(o)) throw new y("integrity-failed", "That Open VSX theme has an invalid checksum.");
|
|
219
|
+
if (o.toLowerCase() !== s) throw new y("integrity-failed", "That Open VSX theme failed its integrity check.");
|
|
217
220
|
return i;
|
|
218
|
-
},
|
|
219
|
-
let t =
|
|
221
|
+
}, U = async (e) => {
|
|
222
|
+
let t = F(e);
|
|
220
223
|
try {
|
|
221
224
|
return {
|
|
222
225
|
zip: await i.loadAsync(e),
|
|
223
226
|
sizes: t
|
|
224
227
|
};
|
|
225
228
|
} catch {
|
|
226
|
-
throw new
|
|
229
|
+
throw new y("unsupported-extension", "That extension package could not be opened.");
|
|
227
230
|
}
|
|
228
|
-
},
|
|
229
|
-
let i =
|
|
231
|
+
}, W = async ({ zip: e, sizes: t, extensionId: n, version: r }) => {
|
|
232
|
+
let i = x(await I({
|
|
230
233
|
zip: e,
|
|
231
234
|
sizes: t,
|
|
232
235
|
path: "extension/package.json",
|
|
233
236
|
description: "The packaged extension manifest"
|
|
234
237
|
}), "The packaged extension manifest");
|
|
235
|
-
if ((typeof i.publisher == "string" && typeof i.name == "string" ? `${i.publisher}.${i.name}` : "").toLowerCase() !== n.toLowerCase() || i.version !== r) throw new
|
|
238
|
+
if ((typeof i.publisher == "string" && typeof i.name == "string" ? `${i.publisher}.${i.name}` : "").toLowerCase() !== n.toLowerCase() || i.version !== r) throw new y("integrity-failed", "The downloaded package does not match the selected Open VSX theme.");
|
|
236
239
|
return i;
|
|
237
|
-
},
|
|
238
|
-
let a =
|
|
239
|
-
if (a.length === 0 || a.length >
|
|
240
|
+
}, G = async ({ zip: e, sizes: n, manifest: r, fallbackName: i }) => {
|
|
241
|
+
let a = w(r);
|
|
242
|
+
if (a.length === 0 || a.length > g) throw new y("unsupported-extension", "That extension has no compatible color themes.");
|
|
240
243
|
let o = [];
|
|
241
244
|
for (let r of a) {
|
|
242
|
-
if (typeof r.path != "string") throw new
|
|
243
|
-
let a =
|
|
245
|
+
if (typeof r.path != "string") throw new y("unsupported-extension", "A contributed theme has no valid path.");
|
|
246
|
+
let a = A(r.path), s = await L({
|
|
244
247
|
zip: e,
|
|
245
248
|
sizes: n,
|
|
246
249
|
path: a
|
|
247
|
-
}), c =
|
|
250
|
+
}), c = R(r.uiTheme), l = typeof r.label == "string" && r.label.trim() ? r.label.trim() : i;
|
|
248
251
|
o.push(t({
|
|
249
252
|
source: JSON.stringify({
|
|
250
253
|
...s,
|
|
@@ -255,8 +258,8 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
255
258
|
}));
|
|
256
259
|
}
|
|
257
260
|
return o;
|
|
258
|
-
},
|
|
259
|
-
let n =
|
|
261
|
+
}, K = ({ fetchImpl: t = fetch } = {}) => {
|
|
262
|
+
let n = E(t);
|
|
260
263
|
return {
|
|
261
264
|
search: async (e) => {
|
|
262
265
|
let t = e.trim();
|
|
@@ -269,21 +272,35 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
269
272
|
message: "Search terms must be 100 characters or fewer."
|
|
270
273
|
};
|
|
271
274
|
try {
|
|
272
|
-
let e = new URL(
|
|
275
|
+
let e = new URL(s);
|
|
273
276
|
e.searchParams.set("query", t), e.searchParams.set("category", "Themes"), e.searchParams.set("sortBy", "downloadCount"), e.searchParams.set("sortOrder", "desc"), e.searchParams.set("size", "12");
|
|
274
277
|
let r = await n({
|
|
275
278
|
url: e,
|
|
276
|
-
limit:
|
|
279
|
+
limit: c,
|
|
277
280
|
failureMessage: "Open VSX search is unavailable right now.",
|
|
278
281
|
tooLargeMessage: "Open VSX returned an unexpectedly large search response."
|
|
279
282
|
}), i = JSON.parse(new TextDecoder().decode(r));
|
|
280
|
-
if (!
|
|
283
|
+
if (!b(i) || !Array.isArray(i.extensions)) throw Error("invalid response");
|
|
284
|
+
let a = i.extensions.flatMap((e) => {
|
|
285
|
+
let t = D(e);
|
|
286
|
+
return t ? [t] : [];
|
|
287
|
+
}).slice(0, 12);
|
|
281
288
|
return {
|
|
282
289
|
status: "success",
|
|
283
|
-
themes:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
themes: (await Promise.all(a.map(async (e) => {
|
|
291
|
+
try {
|
|
292
|
+
let t = await B({
|
|
293
|
+
request: n,
|
|
294
|
+
extensionId: e.id
|
|
295
|
+
});
|
|
296
|
+
return await V({
|
|
297
|
+
request: n,
|
|
298
|
+
manifestUrl: t.manifestUrl
|
|
299
|
+
}), e;
|
|
300
|
+
} catch {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
}))).filter((e) => e !== null)
|
|
287
304
|
};
|
|
288
305
|
} catch {
|
|
289
306
|
return {
|
|
@@ -294,24 +311,24 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
294
311
|
},
|
|
295
312
|
importTheme: async (t, r) => {
|
|
296
313
|
try {
|
|
297
|
-
let e = await
|
|
314
|
+
let e = await B({
|
|
298
315
|
request: n,
|
|
299
316
|
extensionId: t
|
|
300
317
|
});
|
|
301
|
-
await
|
|
318
|
+
await V({
|
|
302
319
|
request: n,
|
|
303
320
|
manifestUrl: e.manifestUrl
|
|
304
321
|
});
|
|
305
|
-
let { zip: i, sizes: a } = await
|
|
322
|
+
let { zip: i, sizes: a } = await U(await H({
|
|
306
323
|
request: n,
|
|
307
324
|
...e
|
|
308
325
|
}));
|
|
309
326
|
return {
|
|
310
327
|
status: "success",
|
|
311
|
-
theme:
|
|
328
|
+
theme: z(await G({
|
|
312
329
|
zip: i,
|
|
313
330
|
sizes: a,
|
|
314
|
-
manifest: await
|
|
331
|
+
manifest: await W({
|
|
315
332
|
zip: i,
|
|
316
333
|
sizes: a,
|
|
317
334
|
extensionId: t,
|
|
@@ -321,7 +338,7 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
321
338
|
}), r)
|
|
322
339
|
};
|
|
323
340
|
} catch (t) {
|
|
324
|
-
return t instanceof e || t instanceof
|
|
341
|
+
return t instanceof e || t instanceof y ? {
|
|
325
342
|
status: "error",
|
|
326
343
|
error: {
|
|
327
344
|
code: t.code,
|
|
@@ -339,4 +356,4 @@ var a = "https://open-vsx.org", o = `${a}/api/-/search`, s = 524288, c = 262144,
|
|
|
339
356
|
};
|
|
340
357
|
};
|
|
341
358
|
//#endregion
|
|
342
|
-
export {
|
|
359
|
+
export { K as createOpenVsxThemeService };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@filipgutica/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A compact Vue design system with Tailwind CSS and VS Code theme support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -31,12 +31,17 @@
|
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
34
|
+
"docs:build": "vite build --config docs/vite.config.ts",
|
|
35
|
+
"docs:dev": "vite --config docs/vite.config.ts",
|
|
36
|
+
"docs:preview": "vite preview --config docs/vite.config.ts",
|
|
37
|
+
"docs:smoke": "node scripts/docs-smoke.mjs",
|
|
38
|
+
"docs:typecheck": "vue-tsc -p docs/tsconfig.json --noEmit",
|
|
34
39
|
"prepublishOnly": "pnpm verify",
|
|
35
40
|
"release": "semantic-release",
|
|
36
41
|
"release:dry-run": "semantic-release --dry-run --no-ci",
|
|
37
42
|
"test": "vitest run",
|
|
38
43
|
"typecheck": "vue-tsc -p tsconfig.json --noEmit",
|
|
39
|
-
"verify": "pnpm typecheck && pnpm test && pnpm build && pnpm pack --dry-run && publint"
|
|
44
|
+
"verify": "pnpm typecheck && pnpm docs:typecheck && pnpm test && pnpm build && pnpm docs:build && pnpm pack --dry-run && publint"
|
|
40
45
|
},
|
|
41
46
|
"engines": {
|
|
42
47
|
"node": ">=22.12"
|
|
@@ -67,6 +72,7 @@
|
|
|
67
72
|
"@commitlint/cli": "^21.2.2",
|
|
68
73
|
"@commitlint/config-conventional": "^21.2.2",
|
|
69
74
|
"@semantic-release/commit-analyzer": "13.0.1",
|
|
75
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
70
76
|
"@types/node": "^26.0.0",
|
|
71
77
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
72
78
|
"@vue/test-utils": "^2.4.6",
|
package/src/components.css
CHANGED
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
.fg-input,
|
|
4
4
|
.fg-select,
|
|
5
5
|
.fg-dialog__close {
|
|
6
|
-
min-height: 2.
|
|
6
|
+
min-height: 2.75rem;
|
|
7
7
|
border: 1px solid transparent;
|
|
8
8
|
border-radius: var(--radius-control);
|
|
9
9
|
font: inherit;
|
|
10
|
+
transition:
|
|
11
|
+
background-color var(--duration-fast) ease,
|
|
12
|
+
border-color var(--duration-fast) ease,
|
|
13
|
+
color var(--duration-fast) ease,
|
|
14
|
+
box-shadow var(--duration-fast) ease,
|
|
15
|
+
transform var(--duration-fast) ease;
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
.fg-button {
|
|
@@ -14,10 +20,12 @@
|
|
|
14
20
|
align-items: center;
|
|
15
21
|
justify-content: center;
|
|
16
22
|
gap: 0.5rem;
|
|
17
|
-
padding: 0.
|
|
23
|
+
padding: 0.65rem 1rem;
|
|
18
24
|
color: var(--color-button-text);
|
|
19
25
|
background: var(--color-button-bg);
|
|
20
|
-
|
|
26
|
+
box-shadow: var(--shadow-control);
|
|
27
|
+
font-weight: 700;
|
|
28
|
+
letter-spacing: -0.01em;
|
|
21
29
|
line-height: 1.25;
|
|
22
30
|
cursor: pointer;
|
|
23
31
|
}
|
|
@@ -26,6 +34,11 @@
|
|
|
26
34
|
background: var(--color-button-hover);
|
|
27
35
|
}
|
|
28
36
|
|
|
37
|
+
.fg-button:active:not(:disabled) {
|
|
38
|
+
transform: translateY(1px);
|
|
39
|
+
box-shadow: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
.fg-button:disabled,
|
|
30
43
|
.fg-input:disabled,
|
|
31
44
|
.fg-select:disabled,
|
|
@@ -38,9 +51,20 @@
|
|
|
38
51
|
cursor: wait;
|
|
39
52
|
}
|
|
40
53
|
|
|
54
|
+
.fg-button[aria-busy="true"]::before {
|
|
55
|
+
width: 0.85rem;
|
|
56
|
+
height: 0.85rem;
|
|
57
|
+
flex: none;
|
|
58
|
+
border: 2px solid currentColor;
|
|
59
|
+
border-right-color: transparent;
|
|
60
|
+
border-radius: 50%;
|
|
61
|
+
content: "";
|
|
62
|
+
animation: fg-button-spin 700ms linear infinite;
|
|
63
|
+
}
|
|
64
|
+
|
|
41
65
|
.fg-button[data-size="compact"] {
|
|
42
|
-
min-height:
|
|
43
|
-
padding: 0.
|
|
66
|
+
min-height: 2.25rem;
|
|
67
|
+
padding: 0.4rem 0.7rem;
|
|
44
68
|
font-size: 0.8125rem;
|
|
45
69
|
}
|
|
46
70
|
|
|
@@ -59,11 +83,20 @@
|
|
|
59
83
|
.fg-button[data-variant="ghost"] {
|
|
60
84
|
color: var(--color-muted);
|
|
61
85
|
background: transparent;
|
|
86
|
+
box-shadow: none;
|
|
62
87
|
}
|
|
63
88
|
|
|
64
89
|
.fg-button[data-variant="danger"] {
|
|
65
90
|
color: var(--color-error);
|
|
66
91
|
background: var(--color-error-surface);
|
|
92
|
+
box-shadow: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.fg-button[data-variant="danger"]:hover:not(:disabled) {
|
|
96
|
+
border-color: var(--color-error);
|
|
97
|
+
color: var(--color-error);
|
|
98
|
+
background: var(--color-error-surface);
|
|
99
|
+
box-shadow: inset 0 0 0 1px var(--color-error);
|
|
67
100
|
}
|
|
68
101
|
|
|
69
102
|
.fg-button[data-variant="text"] {
|
|
@@ -73,6 +106,7 @@
|
|
|
73
106
|
background: transparent;
|
|
74
107
|
text-decoration: underline;
|
|
75
108
|
text-underline-offset: 0.2em;
|
|
109
|
+
box-shadow: none;
|
|
76
110
|
}
|
|
77
111
|
|
|
78
112
|
.fg-button[data-variant="text"]:hover:not(:disabled) {
|
|
@@ -87,6 +121,7 @@
|
|
|
87
121
|
border-color: var(--color-input-border);
|
|
88
122
|
color: var(--color-input-text);
|
|
89
123
|
background: var(--color-input-bg);
|
|
124
|
+
box-shadow: var(--shadow-control);
|
|
90
125
|
line-height: 1.35;
|
|
91
126
|
}
|
|
92
127
|
|
|
@@ -107,9 +142,9 @@
|
|
|
107
142
|
}
|
|
108
143
|
|
|
109
144
|
.fg-field__label {
|
|
110
|
-
color: var(--color-
|
|
145
|
+
color: var(--color-text);
|
|
111
146
|
font-size: 0.8125rem;
|
|
112
|
-
font-weight:
|
|
147
|
+
font-weight: 700;
|
|
113
148
|
}
|
|
114
149
|
|
|
115
150
|
.fg-field__description,
|
|
@@ -132,14 +167,15 @@
|
|
|
132
167
|
.fg-checkbox__control {
|
|
133
168
|
display: inline-grid;
|
|
134
169
|
flex: none;
|
|
135
|
-
width: 1.
|
|
136
|
-
height: 1.
|
|
170
|
+
width: 1.25rem;
|
|
171
|
+
height: 1.25rem;
|
|
137
172
|
margin-top: 0.1rem;
|
|
138
173
|
place-items: center;
|
|
139
174
|
border: 1px solid var(--color-input-border);
|
|
140
175
|
border-radius: 0.3rem;
|
|
141
176
|
color: var(--color-button-text);
|
|
142
177
|
background: var(--color-input-bg);
|
|
178
|
+
box-shadow: var(--shadow-control);
|
|
143
179
|
}
|
|
144
180
|
|
|
145
181
|
.fg-checkbox__control[data-state="checked"] {
|
|
@@ -180,14 +216,15 @@
|
|
|
180
216
|
gap: 0.75rem;
|
|
181
217
|
padding: 0.85rem 1rem;
|
|
182
218
|
border: 1px solid var(--color-border-subtle);
|
|
219
|
+
border-left: 3px solid var(--color-border);
|
|
183
220
|
border-radius: var(--radius-control);
|
|
184
221
|
color: var(--color-text);
|
|
185
222
|
background: var(--color-surface);
|
|
186
223
|
}
|
|
187
224
|
|
|
188
|
-
.fg-alert[data-tone="info"] { background: var(--color-info-surface); }
|
|
189
|
-
.fg-alert[data-tone="success"] { background: var(--color-success-surface); }
|
|
190
|
-
.fg-alert[data-tone="warning"] { background: var(--color-warning-surface); }
|
|
225
|
+
.fg-alert[data-tone="info"] { border-left-color: var(--color-info); background: var(--color-info-surface); }
|
|
226
|
+
.fg-alert[data-tone="success"] { border-left-color: var(--color-success); background: var(--color-success-surface); }
|
|
227
|
+
.fg-alert[data-tone="warning"] { border-left-color: var(--color-warning); background: var(--color-warning-surface); }
|
|
191
228
|
.fg-alert[data-tone="danger"],
|
|
192
229
|
.fg-alert[data-tone="error"] {
|
|
193
230
|
border-color: var(--color-error);
|
|
@@ -199,6 +236,7 @@
|
|
|
199
236
|
border: 1px solid var(--color-border-subtle);
|
|
200
237
|
border-radius: var(--radius-panel);
|
|
201
238
|
background: var(--color-surface-raised);
|
|
239
|
+
box-shadow: 0 1px 2px var(--color-shadow);
|
|
202
240
|
}
|
|
203
241
|
|
|
204
242
|
.fg-surface[data-padding="compact"] { padding: 0.85rem; }
|
|
@@ -225,6 +263,7 @@
|
|
|
225
263
|
inset: 0;
|
|
226
264
|
z-index: 50;
|
|
227
265
|
background: var(--color-overlay);
|
|
266
|
+
backdrop-filter: blur(2px);
|
|
228
267
|
}
|
|
229
268
|
|
|
230
269
|
.fg-dialog__content {
|
|
@@ -259,7 +298,8 @@
|
|
|
259
298
|
.fg-dialog__title {
|
|
260
299
|
margin: 0;
|
|
261
300
|
font-size: 1.1rem;
|
|
262
|
-
font-weight:
|
|
301
|
+
font-weight: 760;
|
|
302
|
+
letter-spacing: -0.02em;
|
|
263
303
|
}
|
|
264
304
|
|
|
265
305
|
.fg-dialog__description {
|
|
@@ -277,7 +317,7 @@
|
|
|
277
317
|
.fg-dialog__close {
|
|
278
318
|
display: inline-grid;
|
|
279
319
|
flex: none;
|
|
280
|
-
width: 2.
|
|
320
|
+
width: 2.75rem;
|
|
281
321
|
padding: 0;
|
|
282
322
|
place-items: center;
|
|
283
323
|
color: var(--color-muted);
|
|
@@ -288,6 +328,10 @@
|
|
|
288
328
|
|
|
289
329
|
.fg-dialog__close:hover { color: var(--color-text); background: var(--color-row-hover); }
|
|
290
330
|
|
|
331
|
+
@keyframes fg-button-spin {
|
|
332
|
+
to { transform: rotate(360deg); }
|
|
333
|
+
}
|
|
334
|
+
|
|
291
335
|
.fg-button:focus-visible,
|
|
292
336
|
.fg-input:focus-visible,
|
|
293
337
|
.fg-select:focus-visible,
|
|
@@ -322,6 +366,12 @@
|
|
|
322
366
|
}
|
|
323
367
|
|
|
324
368
|
@media (prefers-reduced-motion: reduce) {
|
|
369
|
+
.fg-button,
|
|
370
|
+
.fg-input,
|
|
371
|
+
.fg-select,
|
|
372
|
+
.fg-dialog__close,
|
|
325
373
|
.fg-progress__indicator { transition: none; }
|
|
374
|
+
|
|
375
|
+
.fg-button[aria-busy="true"]::before { animation-duration: 1.4s; }
|
|
326
376
|
}
|
|
327
377
|
}
|
package/src/theme.css
CHANGED
|
@@ -2,78 +2,79 @@
|
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
4
|
color-scheme: light;
|
|
5
|
-
--color-bg: #
|
|
6
|
-
--color-surface: #
|
|
5
|
+
--color-bg: #ffffff;
|
|
6
|
+
--color-surface: #f7f8fa;
|
|
7
7
|
--color-surface-raised: #fff;
|
|
8
|
-
--color-surface-muted: #
|
|
9
|
-
--color-text: #
|
|
10
|
-
--color-muted: #
|
|
11
|
-
--color-link: #
|
|
12
|
-
--color-accent: #
|
|
13
|
-
--color-focus: #
|
|
14
|
-
--color-border: #
|
|
15
|
-
--color-border-subtle: #
|
|
16
|
-
--color-button-bg: #
|
|
8
|
+
--color-surface-muted: #eef1f5;
|
|
9
|
+
--color-text: #101828;
|
|
10
|
+
--color-muted: #5d6979;
|
|
11
|
+
--color-link: #155eef;
|
|
12
|
+
--color-accent: #4d7c0f;
|
|
13
|
+
--color-focus: #155eef;
|
|
14
|
+
--color-border: #667085;
|
|
15
|
+
--color-border-subtle: #d8dee8;
|
|
16
|
+
--color-button-bg: #155eef;
|
|
17
17
|
--color-button-text: #fff;
|
|
18
|
-
--color-button-hover: #
|
|
18
|
+
--color-button-hover: #004eeb;
|
|
19
19
|
--color-input-bg: #fff;
|
|
20
|
-
--color-input-text: #
|
|
21
|
-
--color-input-border: #
|
|
22
|
-
--color-input-placeholder: #
|
|
23
|
-
--color-row-hover: #
|
|
24
|
-
--color-row-selected: #
|
|
25
|
-
--color-row-selected-text: #
|
|
26
|
-
--color-code: #
|
|
27
|
-
--color-code-text: #
|
|
28
|
-
--color-error: #
|
|
29
|
-
--color-warning: #
|
|
30
|
-
--color-success: #
|
|
31
|
-
--color-info: #
|
|
32
|
-
--color-progress: #
|
|
33
|
-
--color-shadow: rgb(
|
|
20
|
+
--color-input-text: #101828;
|
|
21
|
+
--color-input-border: #667085;
|
|
22
|
+
--color-input-placeholder: #667085;
|
|
23
|
+
--color-row-hover: #f2f4f7;
|
|
24
|
+
--color-row-selected: #eaf1ff;
|
|
25
|
+
--color-row-selected-text: #143d8f;
|
|
26
|
+
--color-code: #0c1426;
|
|
27
|
+
--color-code-text: #edf2ff;
|
|
28
|
+
--color-error: #c01048;
|
|
29
|
+
--color-warning: #854a0e;
|
|
30
|
+
--color-success: #067647;
|
|
31
|
+
--color-info: #175cd3;
|
|
32
|
+
--color-progress: #155eef;
|
|
33
|
+
--color-shadow: rgb(16 24 40 / 10%);
|
|
34
34
|
--color-overlay: rgb(0 0 0 / 42%);
|
|
35
35
|
--color-error-surface: color-mix(in srgb, var(--color-error) 12%, var(--color-surface));
|
|
36
36
|
--color-warning-surface: color-mix(in srgb, var(--color-warning) 13%, var(--color-surface));
|
|
37
37
|
--color-success-surface: color-mix(in srgb, var(--color-success) 12%, var(--color-surface));
|
|
38
38
|
--color-info-surface: color-mix(in srgb, var(--color-info) 12%, var(--color-surface));
|
|
39
|
-
--radius-control: 0.
|
|
40
|
-
--radius-panel: 0.
|
|
39
|
+
--radius-control: 0.375rem;
|
|
40
|
+
--radius-panel: 0.5rem;
|
|
41
41
|
--radius-pill: 999px;
|
|
42
|
-
--duration-fast:
|
|
43
|
-
--shadow-
|
|
42
|
+
--duration-fast: 140ms;
|
|
43
|
+
--shadow-control: 0 1px 2px rgb(16 24 40 / 8%);
|
|
44
|
+
--shadow-dialog: 0 24px 80px rgb(5 12 24 / 28%);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
:root.dark {
|
|
47
48
|
color-scheme: dark;
|
|
48
|
-
--color-bg: #
|
|
49
|
-
--color-surface: #
|
|
50
|
-
--color-surface-raised: #
|
|
51
|
-
--color-surface-muted: #
|
|
52
|
-
--color-text: #
|
|
53
|
-
--color-muted: #
|
|
54
|
-
--color-link: #
|
|
55
|
-
--color-accent: #
|
|
56
|
-
--color-focus: #
|
|
57
|
-
--color-border: #
|
|
58
|
-
--color-border-subtle: #
|
|
59
|
-
--color-button-bg: #
|
|
60
|
-
--color-button-text: #
|
|
61
|
-
--color-button-hover: #
|
|
62
|
-
--color-input-bg: #
|
|
63
|
-
--color-input-text: #
|
|
64
|
-
--color-input-border: #
|
|
65
|
-
--color-input-placeholder: #
|
|
66
|
-
--color-row-hover: #
|
|
67
|
-
--color-row-selected: #
|
|
68
|
-
--color-row-selected-text: #
|
|
69
|
-
--color-code: #
|
|
70
|
-
--color-code-text: #
|
|
71
|
-
--color-error: #
|
|
72
|
-
--color-warning: #
|
|
73
|
-
--color-success: #
|
|
74
|
-
--color-info: #
|
|
75
|
-
--color-progress: #
|
|
76
|
-
--color-shadow: rgb(0 0 0 /
|
|
49
|
+
--color-bg: #0b1020;
|
|
50
|
+
--color-surface: #111827;
|
|
51
|
+
--color-surface-raised: #151d2f;
|
|
52
|
+
--color-surface-muted: #202a3d;
|
|
53
|
+
--color-text: #f4f7ff;
|
|
54
|
+
--color-muted: #a8b3c7;
|
|
55
|
+
--color-link: #8fb4ff;
|
|
56
|
+
--color-accent: #b7ef53;
|
|
57
|
+
--color-focus: #8fb4ff;
|
|
58
|
+
--color-border: #647189;
|
|
59
|
+
--color-border-subtle: #2d384d;
|
|
60
|
+
--color-button-bg: #6e9cff;
|
|
61
|
+
--color-button-text: #071126;
|
|
62
|
+
--color-button-hover: #8fb4ff;
|
|
63
|
+
--color-input-bg: #0d1526;
|
|
64
|
+
--color-input-text: #f4f7ff;
|
|
65
|
+
--color-input-border: #647189;
|
|
66
|
+
--color-input-placeholder: #8995aa;
|
|
67
|
+
--color-row-hover: #1b2538;
|
|
68
|
+
--color-row-selected: #1b315b;
|
|
69
|
+
--color-row-selected-text: #dbe7ff;
|
|
70
|
+
--color-code: #070d19;
|
|
71
|
+
--color-code-text: #edf2ff;
|
|
72
|
+
--color-error: #ff8aad;
|
|
73
|
+
--color-warning: #f8c477;
|
|
74
|
+
--color-success: #75e0a7;
|
|
75
|
+
--color-info: #84adff;
|
|
76
|
+
--color-progress: #8fb4ff;
|
|
77
|
+
--color-shadow: rgb(0 0 0 / 32%);
|
|
77
78
|
--color-overlay: rgb(0 0 0 / 62%);
|
|
78
79
|
}
|
|
79
80
|
|