@sanity/themer 0.5.0 → 0.7.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 +3 -1
- package/dist/bundle-css.d.ts +2 -0
- package/dist/bundle-css.js +4 -0
- package/dist/bundle.css +1 -0
- package/dist/tool.js +2110 -1375
- package/dist/tool.js.map +1 -1
- package/package.json +19 -11
package/dist/tool.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import "@sanity/themer/bundle.css";
|
|
1
2
|
import { a as DEFAULT_BACKGROUND, c as resolveThemeOptions, d as hslToHex, f as relativeLuminance, i as DEFAULT_ACCENT, l as isColor, n as buildTheme, o as SCHEMES, r as buildPalette, s as deriveTextColor, t as presets, u as hexToHsl } from "./presets-CqBgS3A-.js";
|
|
2
|
-
import { c } from "react
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
3
4
|
import { definePlugin, useColorSchemeValue } from "sanity";
|
|
4
|
-
import { Badge, Box, Button, Card, Dialog, Flex, Layer, Stack, Text, TextInput, ThemeProvider, useRootTheme, useTheme_v2 } from "@sanity/ui";
|
|
5
|
+
import { Badge, Box, Button, Card, Dialog, Flex, Layer, Stack, Text, TextInput, ThemeProvider, useMediaIndex, useRootTheme, useTheme_v2 } from "@sanity/ui";
|
|
5
6
|
import { useActor, useSelector } from "@xstate/react";
|
|
6
|
-
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
7
|
-
import { assign, not, setup } from "xstate";
|
|
8
|
-
import { styled } from "styled-components";
|
|
7
|
+
import { Activity, ViewTransition, createContext, useContext, useDeferredValue, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
8
|
+
import { assign, not, or, setup, stateIn } from "xstate";
|
|
9
9
|
import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
|
|
10
10
|
import { CloseIcon } from "@sanity/icons/Close";
|
|
11
11
|
import { CodeBlockIcon } from "@sanity/icons/CodeBlock";
|
|
12
12
|
import { SplitVerticalIcon } from "@sanity/icons/SplitVertical";
|
|
13
13
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { assignInlineVars } from "@vanilla-extract/dynamic";
|
|
14
15
|
import { ResetIcon } from "@sanity/icons/Reset";
|
|
15
16
|
import { TrashIcon } from "@sanity/icons/Trash";
|
|
16
17
|
import { SparklesIcon } from "@sanity/icons/Sparkles";
|
|
@@ -18,12 +19,17 @@ import { Tooltip } from "@sanity/ui/tooltip";
|
|
|
18
19
|
import { ImageIcon } from "@sanity/icons/Image";
|
|
19
20
|
import { useToast } from "@sanity/ui/toast";
|
|
20
21
|
import { AddIcon } from "@sanity/icons/Add";
|
|
22
|
+
import { ClipboardIcon } from "@sanity/icons/Clipboard";
|
|
21
23
|
import { RestoreIcon } from "@sanity/icons/Restore";
|
|
24
|
+
import { MotionConfig, Reorder, useDragControls } from "motion/react";
|
|
25
|
+
import { ArrowDownIcon } from "@sanity/icons/ArrowDown";
|
|
26
|
+
import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
|
|
22
27
|
import { CopyIcon } from "@sanity/icons/Copy";
|
|
23
28
|
import { EditIcon } from "@sanity/icons/Edit";
|
|
24
29
|
import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
|
|
30
|
+
import { ShareIcon } from "@sanity/icons/Share";
|
|
25
31
|
import { Menu, MenuButton, MenuDivider, MenuItem } from "@sanity/ui/menu";
|
|
26
|
-
import
|
|
32
|
+
import scrollIntoView from "scroll-into-view-if-needed";
|
|
27
33
|
import { Code } from "@sanity/ui/code";
|
|
28
34
|
import { registerLanguage } from "react-refractor";
|
|
29
35
|
import typescript from "refractor/typescript";
|
|
@@ -36,992 +42,1300 @@ function useThemer() {
|
|
|
36
42
|
if (!context) throw Error("useThemer must be used within the `themerTool` plugin");
|
|
37
43
|
return context;
|
|
38
44
|
}
|
|
45
|
+
/** @internal */
|
|
46
|
+
const IMAGE_PALETTE_KEYS = [
|
|
47
|
+
"vibrant",
|
|
48
|
+
"lightVibrant",
|
|
49
|
+
"darkVibrant",
|
|
50
|
+
"muted",
|
|
51
|
+
"lightMuted",
|
|
52
|
+
"darkMuted",
|
|
53
|
+
"dominant"
|
|
54
|
+
], IMAGE_PALETTE_VARIANTS = [
|
|
55
|
+
"muted",
|
|
56
|
+
"vibrant",
|
|
57
|
+
"lightMuted",
|
|
58
|
+
"lightVibrant",
|
|
59
|
+
"darkMuted",
|
|
60
|
+
"darkVibrant"
|
|
61
|
+
], IMAGE_PALETTE_TITLES = {
|
|
62
|
+
dominant: "Dominant",
|
|
63
|
+
vibrant: "Vibrant",
|
|
64
|
+
lightVibrant: "Light vibrant",
|
|
65
|
+
darkVibrant: "Dark vibrant",
|
|
66
|
+
muted: "Muted",
|
|
67
|
+
lightMuted: "Light muted",
|
|
68
|
+
darkMuted: "Dark muted"
|
|
69
|
+
}, TARGETS = [
|
|
70
|
+
["vibrant", {
|
|
71
|
+
lightness: [
|
|
72
|
+
.5,
|
|
73
|
+
.3,
|
|
74
|
+
.7
|
|
75
|
+
],
|
|
76
|
+
saturation: [
|
|
77
|
+
1,
|
|
78
|
+
.35,
|
|
79
|
+
1
|
|
80
|
+
]
|
|
81
|
+
}],
|
|
82
|
+
["lightVibrant", {
|
|
83
|
+
lightness: [
|
|
84
|
+
.74,
|
|
85
|
+
.55,
|
|
86
|
+
1
|
|
87
|
+
],
|
|
88
|
+
saturation: [
|
|
89
|
+
1,
|
|
90
|
+
.35,
|
|
91
|
+
1
|
|
92
|
+
]
|
|
93
|
+
}],
|
|
94
|
+
["darkVibrant", {
|
|
95
|
+
lightness: [
|
|
96
|
+
.26,
|
|
97
|
+
0,
|
|
98
|
+
.45
|
|
99
|
+
],
|
|
100
|
+
saturation: [
|
|
101
|
+
1,
|
|
102
|
+
.35,
|
|
103
|
+
1
|
|
104
|
+
]
|
|
105
|
+
}],
|
|
106
|
+
["muted", {
|
|
107
|
+
lightness: [
|
|
108
|
+
.5,
|
|
109
|
+
.3,
|
|
110
|
+
.7
|
|
111
|
+
],
|
|
112
|
+
saturation: [
|
|
113
|
+
.3,
|
|
114
|
+
0,
|
|
115
|
+
.4
|
|
116
|
+
]
|
|
117
|
+
}],
|
|
118
|
+
["lightMuted", {
|
|
119
|
+
lightness: [
|
|
120
|
+
.74,
|
|
121
|
+
.55,
|
|
122
|
+
1
|
|
123
|
+
],
|
|
124
|
+
saturation: [
|
|
125
|
+
.3,
|
|
126
|
+
0,
|
|
127
|
+
.4
|
|
128
|
+
]
|
|
129
|
+
}],
|
|
130
|
+
["darkMuted", {
|
|
131
|
+
lightness: [
|
|
132
|
+
.26,
|
|
133
|
+
0,
|
|
134
|
+
.45
|
|
135
|
+
],
|
|
136
|
+
saturation: [
|
|
137
|
+
.3,
|
|
138
|
+
0,
|
|
139
|
+
.4
|
|
140
|
+
]
|
|
141
|
+
}]
|
|
142
|
+
];
|
|
39
143
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
144
|
+
* Extracts the color palette of an image from its pixels, the way the Vibrant
|
|
145
|
+
* algorithm does: the colors are quantized into a coarse histogram, and each
|
|
146
|
+
* swatch claims the color that comes closest to its target lightness and
|
|
147
|
+
* saturation — weighted by how much of the image it covers — that no other
|
|
148
|
+
* swatch has claimed yet. The dominant swatch is simply the most common
|
|
149
|
+
* color. Runs anywhere pixels come from, so it can run on device.
|
|
46
150
|
*
|
|
47
151
|
* @internal
|
|
48
152
|
*/
|
|
49
|
-
function
|
|
50
|
-
let
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
153
|
+
function extractImagePalette(pixels) {
|
|
154
|
+
let candidates = quantize(pixels), palette = {
|
|
155
|
+
dominant: null,
|
|
156
|
+
vibrant: null,
|
|
157
|
+
lightVibrant: null,
|
|
158
|
+
darkVibrant: null,
|
|
159
|
+
muted: null,
|
|
160
|
+
lightMuted: null,
|
|
161
|
+
darkMuted: null
|
|
162
|
+
};
|
|
163
|
+
if (candidates.length === 0) return palette;
|
|
164
|
+
let maximumPopulation = Math.max(...candidates.map((candidate) => candidate.population)), claimed = /* @__PURE__ */ new Set();
|
|
165
|
+
for (let [key, target] of TARGETS) {
|
|
166
|
+
let best = null, bestScore = -Infinity;
|
|
167
|
+
for (let candidate of candidates) {
|
|
168
|
+
if (claimed.has(candidate.hex) || !matchesTarget(candidate, target)) continue;
|
|
169
|
+
let score = scoreCandidate(candidate, target, maximumPopulation);
|
|
170
|
+
score > bestScore && (best = candidate, bestScore = score);
|
|
171
|
+
}
|
|
172
|
+
best && (palette[key] = best.hex, claimed.add(best.hex));
|
|
54
173
|
}
|
|
55
|
-
return
|
|
174
|
+
return palette.dominant = candidates.reduce((most, candidate) => candidate.population > most.population ? candidate : most).hex, palette;
|
|
56
175
|
}
|
|
57
176
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* @internal
|
|
177
|
+
* Turns the pixels into a histogram of quantized colors, each averaged over
|
|
178
|
+
* the pixels it stands for, leaving out transparent pixels and the near-black
|
|
179
|
+
* and near-white ones that are backdrop rather than color.
|
|
63
180
|
*/
|
|
64
|
-
function
|
|
65
|
-
let
|
|
66
|
-
|
|
181
|
+
function quantize(pixels) {
|
|
182
|
+
let { data } = pixels, buckets = /* @__PURE__ */ new Map(), length = Math.min(data.length, pixels.width * pixels.height * 4);
|
|
183
|
+
for (let offset = 0; offset + 3 < length; offset += 4) {
|
|
184
|
+
let r = data[offset], g = data[offset + 1], b = data[offset + 2];
|
|
185
|
+
if (data[offset + 3] < 125) continue;
|
|
186
|
+
let lightness = (Math.max(r, g, b) + Math.min(r, g, b)) / 510;
|
|
187
|
+
if (lightness < .05 || lightness > .95) continue;
|
|
188
|
+
let key = r >> 3 << 10 | g >> 3 << 5 | b >> 3, bucket = buckets.get(key);
|
|
189
|
+
bucket ? (bucket.count++, bucket.r += r, bucket.g += g, bucket.b += b) : buckets.set(key, {
|
|
190
|
+
count: 1,
|
|
191
|
+
r,
|
|
192
|
+
g,
|
|
193
|
+
b
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
let candidates = [];
|
|
197
|
+
for (let bucket of buckets.values()) {
|
|
198
|
+
let r = Math.round(bucket.r / bucket.count), g = Math.round(bucket.g / bucket.count), b = Math.round(bucket.b / bucket.count), { saturation, lightness } = saturationAndLightness(r, g, b);
|
|
199
|
+
candidates.push({
|
|
200
|
+
hex: rgbToHex(r, g, b),
|
|
201
|
+
population: bucket.count,
|
|
202
|
+
saturation,
|
|
203
|
+
lightness
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return candidates;
|
|
67
207
|
}
|
|
68
|
-
function
|
|
69
|
-
return
|
|
208
|
+
function matchesTarget(candidate, target) {
|
|
209
|
+
return candidate.lightness >= target.lightness[1] && candidate.lightness <= target.lightness[2] && candidate.saturation >= target.saturation[1] && candidate.saturation <= target.saturation[2];
|
|
70
210
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
active: null,
|
|
74
|
-
custom: [],
|
|
75
|
-
removed: []
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Resolves the list of themes: the configured theme first, then the presets
|
|
79
|
-
* (minus the ones that would only repeat the configured theme), then the
|
|
80
|
-
* user's own themes. Removed themes are set aside so they can be restored,
|
|
81
|
-
* and the active theme falls back to the configured one when its slug no
|
|
82
|
-
* longer resolves.
|
|
83
|
-
*
|
|
84
|
-
* @internal
|
|
85
|
-
*/
|
|
86
|
-
function resolveThemes(state, baseOptions) {
|
|
87
|
-
let config = {
|
|
88
|
-
slug: "config",
|
|
89
|
-
title: "Studio config",
|
|
90
|
-
options: baseOptions,
|
|
91
|
-
source: "config"
|
|
92
|
-
}, all = [config];
|
|
93
|
-
for (let preset of presets) sameOptions(preset.options, baseOptions) || all.push({
|
|
94
|
-
slug: preset.slug,
|
|
95
|
-
title: preset.title,
|
|
96
|
-
options: preset.options,
|
|
97
|
-
source: "preset"
|
|
98
|
-
});
|
|
99
|
-
for (let theme of state.custom) all.push({
|
|
100
|
-
slug: theme.slug,
|
|
101
|
-
title: theme.title,
|
|
102
|
-
options: theme.options,
|
|
103
|
-
source: "custom",
|
|
104
|
-
...theme.palette ? { palette: theme.palette } : {}
|
|
105
|
-
});
|
|
106
|
-
let removedSlugs = new Set(state.removed), themes = all.filter((theme) => !removedSlugs.has(theme.slug));
|
|
107
|
-
return {
|
|
108
|
-
themes,
|
|
109
|
-
removed: all.filter((theme) => removedSlugs.has(theme.slug)),
|
|
110
|
-
active: themes.find((theme) => theme.slug === state.active) ?? config
|
|
111
|
-
};
|
|
211
|
+
function scoreCandidate(candidate, target, maximumPopulation) {
|
|
212
|
+
return 3 * (1 - Math.abs(candidate.saturation - target.saturation[0])) + 6.5 * (1 - Math.abs(candidate.lightness - target.lightness[0])) + .5 * (candidate.population / maximumPopulation);
|
|
112
213
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
* the configured theme.
|
|
116
|
-
*
|
|
117
|
-
* @internal
|
|
118
|
-
*/
|
|
119
|
-
function createCustomTheme(title, options, palette) {
|
|
214
|
+
function saturationAndLightness(r, g, b) {
|
|
215
|
+
let max = Math.max(r, g, b) / 255, min = Math.min(r, g, b) / 255, lightness = (max + min) / 2, delta = max - min;
|
|
120
216
|
return {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
options,
|
|
124
|
-
...palette ? { palette } : {}
|
|
217
|
+
saturation: delta === 0 ? 0 : lightness > .5 ? delta / (2 - max - min) : delta / (max + min),
|
|
218
|
+
lightness
|
|
125
219
|
};
|
|
126
220
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
221
|
+
function rgbToHex(r, g, b) {
|
|
222
|
+
return `#${[
|
|
223
|
+
r,
|
|
224
|
+
g,
|
|
225
|
+
b
|
|
226
|
+
].map((channel) => channel.toString(16).padStart(2, "0")).join("")}`;
|
|
130
227
|
}
|
|
131
|
-
/**
|
|
132
|
-
function
|
|
133
|
-
|
|
228
|
+
/** Reads `#rgb` and `#rrggbb` alike — stored palettes may hold either */
|
|
229
|
+
function hexToRgb(hex) {
|
|
230
|
+
let expanded = hex.length === 4 ? `${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex.slice(1);
|
|
231
|
+
return [
|
|
232
|
+
parseInt(expanded.slice(0, 2), 16),
|
|
233
|
+
parseInt(expanded.slice(2, 4), 16),
|
|
234
|
+
parseInt(expanded.slice(4, 6), 16)
|
|
235
|
+
];
|
|
134
236
|
}
|
|
135
|
-
|
|
136
|
-
|
|
237
|
+
/** Mixes `amount` of `color` into `base` */
|
|
238
|
+
function tint(base, color, amount) {
|
|
239
|
+
let [r1, g1, b1] = hexToRgb(base), [r2, g2, b2] = hexToRgb(color);
|
|
240
|
+
return rgbToHex(Math.round(r1 + (r2 - r1) * amount), Math.round(g1 + (g2 - g1) * amount), Math.round(b1 + (b2 - b1) * amount));
|
|
137
241
|
}
|
|
138
|
-
|
|
139
|
-
|
|
242
|
+
/** How much of the palette tints each scheme's stock background */
|
|
243
|
+
const BACKGROUND_TINT = {
|
|
244
|
+
light: .08,
|
|
245
|
+
dark: .3
|
|
246
|
+
}, BUTTON_LABEL = {
|
|
247
|
+
light: "#ffffff",
|
|
248
|
+
dark: "#000000"
|
|
249
|
+
}, ACCENT_LIGHTNESS_STEP = .01;
|
|
250
|
+
function contrastRatio(a, b) {
|
|
251
|
+
let [lighter, darker] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
|
|
252
|
+
return (lighter + .05) / (darker + .05);
|
|
140
253
|
}
|
|
141
254
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* side by side (`split`). The context carries the persisted state (the
|
|
147
|
-
* applied theme, the user's themes and what was removed) alongside what the
|
|
148
|
-
* flows need.
|
|
149
|
-
*
|
|
150
|
-
* Theme operations are handled in every flow, and the flows leave on their
|
|
151
|
-
* own when they lose their subject: the editor when its theme is removed or
|
|
152
|
-
* deleted, and the removed view when its last theme is restored or deleted.
|
|
255
|
+
* Makes an accent readable as a button in the given scheme: a light scheme
|
|
256
|
+
* accent is darkened until white text on it reaches AA contrast, a dark
|
|
257
|
+
* scheme accent lightened until black text does — as far as the accent's
|
|
258
|
+
* hue and saturation allow. Accents that already pass come back untouched.
|
|
153
259
|
*
|
|
154
260
|
* @internal
|
|
155
261
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
},
|
|
167
|
-
actions: {
|
|
168
|
-
pick: assign((_, params) => ({ active: params.slug === "config" ? null : params.slug })),
|
|
169
|
-
add: assign(({ context }, params) => {
|
|
170
|
-
let theme = createCustomTheme(params.title ?? "Untitled theme", params.options ?? themesOf(context).active.options, params.palette);
|
|
171
|
-
return {
|
|
172
|
-
active: theme.slug,
|
|
173
|
-
custom: [...context.custom, theme],
|
|
174
|
-
editing: {
|
|
175
|
-
slug: theme.slug,
|
|
176
|
-
focusTitle: params.title === void 0
|
|
177
|
-
},
|
|
178
|
-
images: params.imageUrl ? {
|
|
179
|
-
...context.images,
|
|
180
|
-
[theme.slug]: params.imageUrl
|
|
181
|
-
} : context.images
|
|
182
|
-
};
|
|
183
|
-
}),
|
|
184
|
-
duplicate: assign(({ context }, params) => {
|
|
185
|
-
let { themes, removed } = themesOf(context), source = [...themes, ...removed].find((theme) => theme.slug === params.slug);
|
|
186
|
-
if (!source) return {};
|
|
187
|
-
let theme = createCustomTheme(duplicateTitle(source.title), source.options, source.palette);
|
|
188
|
-
return {
|
|
189
|
-
active: theme.slug,
|
|
190
|
-
custom: [...context.custom, theme],
|
|
191
|
-
editing: {
|
|
192
|
-
slug: theme.slug,
|
|
193
|
-
focusTitle: !0
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
}),
|
|
197
|
-
startEditing: assign((_, params) => ({
|
|
198
|
-
active: params.slug,
|
|
199
|
-
editing: {
|
|
200
|
-
slug: params.slug,
|
|
201
|
-
focusTitle: !1
|
|
202
|
-
}
|
|
203
|
-
})),
|
|
204
|
-
stopEditing: assign({ editing: null }),
|
|
205
|
-
update: assign(({ context }, params) => ({
|
|
206
|
-
custom: context.custom.map((theme) => theme.slug === params.slug ? {
|
|
207
|
-
...theme,
|
|
208
|
-
title: params.title ?? theme.title,
|
|
209
|
-
options: params.options ?? theme.options,
|
|
210
|
-
...params.palette ? { palette: params.palette } : {}
|
|
211
|
-
} : theme),
|
|
212
|
-
images: params.imageUrl && context.custom.some((theme) => theme.slug === params.slug) ? {
|
|
213
|
-
...context.images,
|
|
214
|
-
[params.slug]: params.imageUrl
|
|
215
|
-
} : context.images
|
|
216
|
-
})),
|
|
217
|
-
remove: assign(({ context }, params) => params.slug === "config" || context.removed.includes(params.slug) ? {} : {
|
|
218
|
-
active: context.active === params.slug ? null : context.active,
|
|
219
|
-
removed: [...context.removed, params.slug]
|
|
220
|
-
}),
|
|
221
|
-
restore: assign(({ context }, params) => ({ removed: context.removed.filter((slug) => slug !== params.slug) })),
|
|
222
|
-
delete: assign(({ context }, params) => {
|
|
223
|
-
if (!context.custom.some((theme) => theme.slug === params.slug)) return {};
|
|
224
|
-
let { [params.slug]: _deleted, ...images } = context.images;
|
|
225
|
-
return {
|
|
226
|
-
active: context.active === params.slug ? null : context.active,
|
|
227
|
-
custom: context.custom.filter((theme) => theme.slug !== params.slug),
|
|
228
|
-
removed: context.removed.filter((slug) => slug !== params.slug),
|
|
229
|
-
images
|
|
230
|
-
};
|
|
231
|
-
})
|
|
232
|
-
}
|
|
233
|
-
}).createMachine({
|
|
234
|
-
id: "themer",
|
|
235
|
-
context: ({ input }) => ({
|
|
236
|
-
...input.stored,
|
|
237
|
-
baseOptions: input.baseOptions,
|
|
238
|
-
editing: null,
|
|
239
|
-
images: {}
|
|
240
|
-
}),
|
|
241
|
-
type: "parallel",
|
|
242
|
-
states: {
|
|
243
|
-
sidebar: {
|
|
244
|
-
initial: "closed",
|
|
245
|
-
states: {
|
|
246
|
-
closed: { on: { "sidebar.toggle": "open" } },
|
|
247
|
-
open: { on: {
|
|
248
|
-
"sidebar.toggle": "closed",
|
|
249
|
-
"sidebar.close": "closed"
|
|
250
|
-
} }
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
preview: {
|
|
254
|
-
initial: "single",
|
|
255
|
-
states: {
|
|
256
|
-
single: { on: { "preview.toggle": "split" } },
|
|
257
|
-
split: { on: { "preview.toggle": "single" } }
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
flow: {
|
|
261
|
-
initial: "list",
|
|
262
|
-
on: {
|
|
263
|
-
"theme.pick": { actions: {
|
|
264
|
-
type: "pick",
|
|
265
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
266
|
-
} },
|
|
267
|
-
"theme.add": {
|
|
268
|
-
target: ".edit",
|
|
269
|
-
actions: {
|
|
270
|
-
type: "add",
|
|
271
|
-
params: ({ event }) => ({
|
|
272
|
-
title: event.title,
|
|
273
|
-
options: event.options,
|
|
274
|
-
palette: event.palette,
|
|
275
|
-
imageUrl: event.imageUrl
|
|
276
|
-
})
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
"theme.duplicate": {
|
|
280
|
-
target: ".edit",
|
|
281
|
-
actions: {
|
|
282
|
-
type: "duplicate",
|
|
283
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
"theme.edit": {
|
|
287
|
-
target: ".edit",
|
|
288
|
-
guard: {
|
|
289
|
-
type: "isCustomTheme",
|
|
290
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
291
|
-
},
|
|
292
|
-
actions: {
|
|
293
|
-
type: "startEditing",
|
|
294
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
295
|
-
}
|
|
296
|
-
},
|
|
297
|
-
"theme.update": { actions: {
|
|
298
|
-
type: "update",
|
|
299
|
-
params: ({ event }) => ({
|
|
300
|
-
slug: event.slug,
|
|
301
|
-
title: event.title,
|
|
302
|
-
options: event.options,
|
|
303
|
-
palette: event.palette,
|
|
304
|
-
imageUrl: event.imageUrl
|
|
305
|
-
})
|
|
306
|
-
} },
|
|
307
|
-
"theme.remove": { actions: {
|
|
308
|
-
type: "remove",
|
|
309
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
310
|
-
} },
|
|
311
|
-
"theme.restore": { actions: {
|
|
312
|
-
type: "restore",
|
|
313
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
314
|
-
} },
|
|
315
|
-
"theme.delete": { actions: {
|
|
316
|
-
type: "delete",
|
|
317
|
-
params: ({ event }) => ({ slug: event.slug })
|
|
318
|
-
} },
|
|
319
|
-
"flow.list": ".list",
|
|
320
|
-
"flow.removed": {
|
|
321
|
-
target: ".removed",
|
|
322
|
-
guard: "hasRemovedThemes"
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
states: {
|
|
326
|
-
list: {},
|
|
327
|
-
edit: {
|
|
328
|
-
exit: "stopEditing",
|
|
329
|
-
always: {
|
|
330
|
-
guard: not("isEditingListedTheme"),
|
|
331
|
-
target: "list"
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
removed: { always: {
|
|
335
|
-
guard: not("hasRemovedThemes"),
|
|
336
|
-
target: "list"
|
|
337
|
-
} }
|
|
338
|
-
}
|
|
339
|
-
}
|
|
262
|
+
function readableAccent(hex, scheme) {
|
|
263
|
+
let label = BUTTON_LABEL[scheme], { h, s } = hexToHsl(hex), { l } = hexToHsl(hex), current = hex;
|
|
264
|
+
for (; contrastRatio(current, label) < 4.5;) {
|
|
265
|
+
let next = scheme === "light" ? l - ACCENT_LIGHTNESS_STEP : l + ACCENT_LIGHTNESS_STEP;
|
|
266
|
+
if (next < 0 || next > 1) break;
|
|
267
|
+
l = next, current = hslToHex({
|
|
268
|
+
h,
|
|
269
|
+
s,
|
|
270
|
+
l
|
|
271
|
+
});
|
|
340
272
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
custom,
|
|
348
|
-
removed
|
|
349
|
-
};
|
|
273
|
+
return current;
|
|
274
|
+
}
|
|
275
|
+
/** The accent a variant gives a scheme, made readable on a button */
|
|
276
|
+
function variantAccent(palette, variant, scheme) {
|
|
277
|
+
let swatch = (variant ? palette[variant] : null) ?? palette.vibrant ?? (scheme === "light" ? palette.darkVibrant : palette.lightVibrant) ?? palette.dominant;
|
|
278
|
+
return swatch === null ? null : readableAccent(swatch, scheme);
|
|
350
279
|
}
|
|
351
|
-
const Root$2 = styled(Box).withConfig({
|
|
352
|
-
displayName: "Root",
|
|
353
|
-
componentId: "sc-6lslk9-0"
|
|
354
|
-
})`scrollbar-gutter:stable;`, ScrollAreaInsetContext = createContext({
|
|
355
|
-
left: 0,
|
|
356
|
-
right: 0,
|
|
357
|
-
bottom: 0
|
|
358
|
-
});
|
|
359
280
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
281
|
+
* Derives theme options from an image palette: the accent of both schemes is
|
|
282
|
+
* the swatch of the chosen variant — or, without one, the vibrant swatch,
|
|
283
|
+
* each scheme falling back to the vibrant swatch of its own end of the scale —
|
|
284
|
+
* adjusted until it is readable as a button. The muted swatch becomes the text color, and the light and dark muted
|
|
285
|
+
* swatches tint the stock backgrounds of their scheme — enough to carry the
|
|
286
|
+
* image's tone without giving up a usable canvas. Whatever the palette lacks
|
|
287
|
+
* stays at the theme defaults.
|
|
365
288
|
*
|
|
366
289
|
* @internal
|
|
367
290
|
*/
|
|
368
|
-
function
|
|
369
|
-
let
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
let observer = new ResizeObserver(measure);
|
|
376
|
-
return observer.observe(element), () => observer.disconnect();
|
|
377
|
-
}, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
|
|
378
|
-
let t2 = space[padding], t3 = Math.max(0, space[padding] - gutter), t4 = space[padding], t5;
|
|
379
|
-
$[2] !== t2 || $[3] !== t3 || $[4] !== t4 ? (t5 = {
|
|
380
|
-
left: t2,
|
|
381
|
-
right: t3,
|
|
382
|
-
bottom: t4
|
|
383
|
-
}, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5) : t5 = $[5];
|
|
384
|
-
let inset = t5, t6;
|
|
385
|
-
$[6] === inset.right ? t6 = $[7] : (t6 = { paddingRight: inset.right }, $[6] = inset.right, $[7] = t6);
|
|
386
|
-
let t7;
|
|
387
|
-
$[8] !== children || $[9] !== inset ? (t7 = /* @__PURE__ */ jsx(ScrollAreaInsetContext.Provider, {
|
|
388
|
-
value: inset,
|
|
389
|
-
children
|
|
390
|
-
}), $[8] = children, $[9] = inset, $[10] = t7) : t7 = $[10];
|
|
391
|
-
let t8;
|
|
392
|
-
return $[11] !== padding || $[12] !== t6 || $[13] !== t7 ? (t8 = /* @__PURE__ */ jsx(Root$2, {
|
|
393
|
-
flex: 1,
|
|
394
|
-
overflow: "auto",
|
|
395
|
-
padding,
|
|
396
|
-
ref,
|
|
397
|
-
style: t6,
|
|
398
|
-
children: t7
|
|
399
|
-
}), $[11] = padding, $[12] = t6, $[13] = t7, $[14] = t8) : t8 = $[14], t8;
|
|
291
|
+
function optionsFromImagePalette(palette, variant) {
|
|
292
|
+
let options = {}, light = schemeFromPalette(variantAccent(palette, variant ?? null, "light"), palette.muted ?? palette.darkMuted, palette.lightMuted ?? palette.muted ?? palette.lightVibrant, "light"), dark = schemeFromPalette(variantAccent(palette, variant ?? null, "dark"), palette.muted ?? palette.lightMuted, palette.darkMuted ?? palette.muted ?? palette.darkVibrant, "dark");
|
|
293
|
+
return light && (options.light = light), dark && (options.dark = dark), options;
|
|
294
|
+
}
|
|
295
|
+
function schemeFromPalette(accent, text, backgroundTint, scheme) {
|
|
296
|
+
let options = {};
|
|
297
|
+
return accent && (options.accent = accent), text && (options.text = text), backgroundTint && (options.background = tint(DEFAULT_BACKGROUND[scheme], backgroundTint, BACKGROUND_TINT[scheme])), Object.keys(options).length > 0 ? options : null;
|
|
400
298
|
}
|
|
401
299
|
/**
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
300
|
+
* Applies an image palette to existing theme options: the colors the palette
|
|
301
|
+
* provides replace the current ones scheme by scheme, and whatever it does
|
|
302
|
+
* not touch — like the contrast — stays as it is.
|
|
405
303
|
*
|
|
406
304
|
* @internal
|
|
407
305
|
*/
|
|
408
|
-
function
|
|
409
|
-
let
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
let t4;
|
|
416
|
-
return $[4] !== props.children || $[5] !== t3 ? (t4 = /* @__PURE__ */ jsx("div", {
|
|
417
|
-
style: t3,
|
|
418
|
-
children: props.children
|
|
419
|
-
}), $[4] = props.children, $[5] = t3, $[6] = t4) : t4 = $[6], t4;
|
|
306
|
+
function applyImagePalette(options, palette, variant) {
|
|
307
|
+
let derived = optionsFromImagePalette(palette, variant), next = { ...options };
|
|
308
|
+
for (let scheme of SCHEMES) derived[scheme] && (next[scheme] = {
|
|
309
|
+
...options[scheme],
|
|
310
|
+
...derived[scheme]
|
|
311
|
+
});
|
|
312
|
+
return next;
|
|
420
313
|
}
|
|
421
314
|
/**
|
|
422
|
-
* The
|
|
423
|
-
*
|
|
424
|
-
*
|
|
315
|
+
* The variant a theme is built around: the one whose swatch is the theme's
|
|
316
|
+
* accent, or `null` when the accent comes from somewhere else.
|
|
317
|
+
*
|
|
318
|
+
* @internal
|
|
425
319
|
*/
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
"62%",
|
|
431
|
-
"46%",
|
|
432
|
-
"70%",
|
|
433
|
-
"52%"
|
|
434
|
-
], FIELDS = ["32%", "24%"];
|
|
320
|
+
function currentImageVariant(options, palette) {
|
|
321
|
+
let accent = options.light?.accent;
|
|
322
|
+
return accent ? IMAGE_PALETTE_VARIANTS.find((variant) => palette[variant] !== null && variantAccent(palette, variant, "light") === accent) ?? null : null;
|
|
323
|
+
}
|
|
435
324
|
/**
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
325
|
+
* How much a swatch has going for it as an accent: saturation first, then
|
|
326
|
+
* closeness to mid lightness — the range where an accent reads best.
|
|
327
|
+
*/
|
|
328
|
+
function interest(hex) {
|
|
329
|
+
let { s, l } = hexToHsl(hex);
|
|
330
|
+
return .1 + .55 * s + .35 * (1 - Math.abs(l - .5) * 2);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Picks a variant for the "I'm feeling lucky" button: a random one, weighted
|
|
334
|
+
* by how interesting its swatch is as an accent, and never the one the theme
|
|
335
|
+
* already uses while there are others to pick from.
|
|
443
336
|
*
|
|
444
337
|
* @internal
|
|
445
338
|
*/
|
|
446
|
-
function
|
|
447
|
-
let
|
|
448
|
-
|
|
449
|
-
let
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
$[3] === theme ? t2 = $[4] : (t2 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
453
|
-
scheme: "light",
|
|
454
|
-
theme,
|
|
455
|
-
tone: "default",
|
|
456
|
-
children: t1
|
|
457
|
-
}), $[3] = theme, $[4] = t2);
|
|
458
|
-
let t3;
|
|
459
|
-
$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(MockStudio, { style: { clipPath: "polygon(58% 0, 100% 0, 100% 100%, 42% 100%)" } }), $[5] = t3) : t3 = $[5];
|
|
460
|
-
let t4;
|
|
461
|
-
$[6] === theme ? t4 = $[7] : (t4 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
462
|
-
scheme: "dark",
|
|
463
|
-
theme,
|
|
464
|
-
tone: "default",
|
|
465
|
-
children: t3
|
|
466
|
-
}), $[6] = theme, $[7] = t4);
|
|
467
|
-
let t5;
|
|
468
|
-
return $[8] !== t2 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Root$1, {
|
|
469
|
-
"aria-hidden": !0,
|
|
470
|
-
children: [t2, t4]
|
|
471
|
-
}), $[8] = t2, $[9] = t4, $[10] = t5) : t5 = $[10], t5;
|
|
472
|
-
}
|
|
473
|
-
function MockStudio(props) {
|
|
474
|
-
let $ = c(53), { color } = useTheme_v2(), primary = color.button.default.primary.enabled, selected = color.selectable.default.selected, input = color.input.default.enabled, border = `1px solid ${color.border}`, line = _temp$4, t0;
|
|
475
|
-
$[0] !== color.bg || $[1] !== props.style ? (t0 = {
|
|
476
|
-
position: "absolute",
|
|
477
|
-
inset: 0,
|
|
478
|
-
display: "flex",
|
|
479
|
-
flexDirection: "column",
|
|
480
|
-
background: color.bg,
|
|
481
|
-
...props.style
|
|
482
|
-
}, $[0] = color.bg, $[1] = props.style, $[2] = t0) : t0 = $[2];
|
|
483
|
-
let t1;
|
|
484
|
-
$[3] === border ? t1 = $[4] : (t1 = {
|
|
485
|
-
flex: "none",
|
|
486
|
-
display: "flex",
|
|
487
|
-
alignItems: "center",
|
|
488
|
-
gap: 5,
|
|
489
|
-
height: "18%",
|
|
490
|
-
padding: "0 5%",
|
|
491
|
-
borderBottom: border
|
|
492
|
-
}, $[3] = border, $[4] = t1);
|
|
493
|
-
let t2;
|
|
494
|
-
$[5] === primary.bg ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx("div", { style: {
|
|
495
|
-
flex: "none",
|
|
496
|
-
width: 8,
|
|
497
|
-
height: 8,
|
|
498
|
-
borderRadius: 2,
|
|
499
|
-
background: primary.bg
|
|
500
|
-
} }), $[5] = primary.bg, $[6] = t2);
|
|
501
|
-
let t3;
|
|
502
|
-
$[7] === color.fg ? t3 = $[8] : (t3 = /* @__PURE__ */ jsx("div", { style: line("22%", color.fg) }), $[7] = color.fg, $[8] = t3);
|
|
503
|
-
let t4;
|
|
504
|
-
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("div", { style: { flex: 1 } }), $[9] = t4) : t4 = $[9];
|
|
505
|
-
let t5;
|
|
506
|
-
$[10] === color.avatar.blue.bg ? t5 = $[11] : (t5 = /* @__PURE__ */ jsx("div", { style: {
|
|
507
|
-
flex: "none",
|
|
508
|
-
width: 8,
|
|
509
|
-
height: 8,
|
|
510
|
-
borderRadius: "50%",
|
|
511
|
-
background: color.avatar.blue.bg
|
|
512
|
-
} }), $[10] = color.avatar.blue.bg, $[11] = t5);
|
|
513
|
-
let t6;
|
|
514
|
-
$[12] !== t1 || $[13] !== t2 || $[14] !== t3 || $[15] !== t5 ? (t6 = /* @__PURE__ */ jsxs("div", {
|
|
515
|
-
style: t1,
|
|
516
|
-
children: [
|
|
517
|
-
t2,
|
|
518
|
-
t3,
|
|
519
|
-
t4,
|
|
520
|
-
t5
|
|
521
|
-
]
|
|
522
|
-
}), $[12] = t1, $[13] = t2, $[14] = t3, $[15] = t5, $[16] = t6) : t6 = $[16];
|
|
523
|
-
let t7;
|
|
524
|
-
$[17] === Symbol.for("react.memo_cache_sentinel") ? (t7 = {
|
|
525
|
-
flex: 1,
|
|
526
|
-
display: "flex",
|
|
527
|
-
minHeight: 0
|
|
528
|
-
}, $[17] = t7) : t7 = $[17];
|
|
529
|
-
let t8;
|
|
530
|
-
$[18] === border ? t8 = $[19] : (t8 = {
|
|
531
|
-
flex: "none",
|
|
532
|
-
display: "flex",
|
|
533
|
-
flexDirection: "column",
|
|
534
|
-
width: "36%",
|
|
535
|
-
borderRight: border
|
|
536
|
-
}, $[18] = border, $[19] = t8);
|
|
537
|
-
let t9;
|
|
538
|
-
$[20] !== color.muted || $[21] !== selected ? (t9 = LIST_ROWS.map((width_0, index) => {
|
|
539
|
-
let isSelected = index === 1;
|
|
540
|
-
return /* @__PURE__ */ jsx("div", {
|
|
541
|
-
style: {
|
|
542
|
-
flex: "none",
|
|
543
|
-
display: "flex",
|
|
544
|
-
alignItems: "center",
|
|
545
|
-
height: "18%",
|
|
546
|
-
padding: "0 9%",
|
|
547
|
-
background: isSelected ? selected.bg : void 0
|
|
548
|
-
},
|
|
549
|
-
children: /* @__PURE__ */ jsx("div", { style: line(width_0, isSelected ? selected.fg : color.muted.fg) })
|
|
550
|
-
}, width_0);
|
|
551
|
-
}), $[20] = color.muted, $[21] = selected, $[22] = t9) : t9 = $[22];
|
|
552
|
-
let t10;
|
|
553
|
-
$[23] !== t8 || $[24] !== t9 ? (t10 = /* @__PURE__ */ jsx("div", {
|
|
554
|
-
style: t8,
|
|
555
|
-
children: t9
|
|
556
|
-
}), $[23] = t8, $[24] = t9, $[25] = t10) : t10 = $[25];
|
|
557
|
-
let t11, t12;
|
|
558
|
-
$[26] === Symbol.for("react.memo_cache_sentinel") ? (t11 = {
|
|
559
|
-
flex: 1,
|
|
560
|
-
display: "flex",
|
|
561
|
-
flexDirection: "column",
|
|
562
|
-
minWidth: 0
|
|
563
|
-
}, t12 = {
|
|
564
|
-
flex: 1,
|
|
565
|
-
display: "flex",
|
|
566
|
-
flexDirection: "column",
|
|
567
|
-
gap: 7,
|
|
568
|
-
padding: "9% 8% 0",
|
|
569
|
-
minHeight: 0,
|
|
570
|
-
overflow: "hidden"
|
|
571
|
-
}, $[26] = t11, $[27] = t12) : (t11 = $[26], t12 = $[27]);
|
|
572
|
-
let t13;
|
|
573
|
-
$[28] === color.fg ? t13 = $[29] : (t13 = /* @__PURE__ */ jsx("div", { style: line("45%", color.fg) }), $[28] = color.fg, $[29] = t13);
|
|
574
|
-
let t14;
|
|
575
|
-
$[30] !== color.muted || $[31] !== input ? (t14 = FIELDS.map((width_1) => /* @__PURE__ */ jsxs("div", {
|
|
576
|
-
style: {
|
|
577
|
-
flex: "none",
|
|
578
|
-
display: "flex",
|
|
579
|
-
flexDirection: "column",
|
|
580
|
-
gap: 3
|
|
581
|
-
},
|
|
582
|
-
children: [/* @__PURE__ */ jsx("div", { style: line(width_1, color.muted.fg) }), /* @__PURE__ */ jsx("div", { style: {
|
|
583
|
-
height: 12,
|
|
584
|
-
borderRadius: 3,
|
|
585
|
-
background: input.bg,
|
|
586
|
-
boxShadow: `inset 0 0 0 1px ${input.border}`
|
|
587
|
-
} })]
|
|
588
|
-
}, width_1)), $[30] = color.muted, $[31] = input, $[32] = t14) : t14 = $[32];
|
|
589
|
-
let t15;
|
|
590
|
-
$[33] !== t13 || $[34] !== t14 ? (t15 = /* @__PURE__ */ jsxs("div", {
|
|
591
|
-
style: t12,
|
|
592
|
-
children: [t13, t14]
|
|
593
|
-
}), $[33] = t13, $[34] = t14, $[35] = t15) : t15 = $[35];
|
|
594
|
-
let t16;
|
|
595
|
-
$[36] === border ? t16 = $[37] : (t16 = {
|
|
596
|
-
flex: "none",
|
|
597
|
-
display: "flex",
|
|
598
|
-
alignItems: "center",
|
|
599
|
-
justifyContent: "flex-end",
|
|
600
|
-
height: "20%",
|
|
601
|
-
padding: "0 8%",
|
|
602
|
-
borderTop: border
|
|
603
|
-
}, $[36] = border, $[37] = t16);
|
|
604
|
-
let t17;
|
|
605
|
-
$[38] === primary.bg ? t17 = $[39] : (t17 = /* @__PURE__ */ jsx("div", { style: {
|
|
606
|
-
width: "32%",
|
|
607
|
-
height: "50%",
|
|
608
|
-
borderRadius: 3,
|
|
609
|
-
background: primary.bg
|
|
610
|
-
} }), $[38] = primary.bg, $[39] = t17);
|
|
611
|
-
let t18;
|
|
612
|
-
$[40] !== t16 || $[41] !== t17 ? (t18 = /* @__PURE__ */ jsx("div", {
|
|
613
|
-
style: t16,
|
|
614
|
-
children: t17
|
|
615
|
-
}), $[40] = t16, $[41] = t17, $[42] = t18) : t18 = $[42];
|
|
616
|
-
let t19;
|
|
617
|
-
$[43] !== t15 || $[44] !== t18 ? (t19 = /* @__PURE__ */ jsxs("div", {
|
|
618
|
-
style: t11,
|
|
619
|
-
children: [t15, t18]
|
|
620
|
-
}), $[43] = t15, $[44] = t18, $[45] = t19) : t19 = $[45];
|
|
621
|
-
let t20;
|
|
622
|
-
$[46] !== t10 || $[47] !== t19 ? (t20 = /* @__PURE__ */ jsxs("div", {
|
|
623
|
-
style: t7,
|
|
624
|
-
children: [t10, t19]
|
|
625
|
-
}), $[46] = t10, $[47] = t19, $[48] = t20) : t20 = $[48];
|
|
626
|
-
let t21;
|
|
627
|
-
return $[49] !== t0 || $[50] !== t20 || $[51] !== t6 ? (t21 = /* @__PURE__ */ jsxs("div", {
|
|
628
|
-
style: t0,
|
|
629
|
-
children: [t6, t20]
|
|
630
|
-
}), $[49] = t0, $[50] = t20, $[51] = t6, $[52] = t21) : t21 = $[52], t21;
|
|
339
|
+
function pickLuckyVariant(palette, options = {}) {
|
|
340
|
+
let { exclude = null, random = Math.random } = options, candidates = IMAGE_PALETTE_VARIANTS.filter((variant) => palette[variant] !== null);
|
|
341
|
+
if (candidates.length > 1 && (candidates = candidates.filter((variant) => variant !== exclude)), candidates.length === 0) return null;
|
|
342
|
+
let weights = candidates.map((variant) => interest(palette[variant])), total = weights.reduce((sum, weight) => sum + weight, 0), pick = random() * total;
|
|
343
|
+
for (let [index, variant] of candidates.entries()) if (pick -= weights[index], pick < 0) return variant;
|
|
344
|
+
return candidates.at(-1) ?? null;
|
|
631
345
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
width,
|
|
636
|
-
height: 4,
|
|
637
|
-
borderRadius: 2,
|
|
638
|
-
background
|
|
639
|
-
};
|
|
346
|
+
/** A theme title for the image a palette came from, e.g. `sunset-beach.jpg` → `sunset beach` @internal */
|
|
347
|
+
function titleFromFileName(name) {
|
|
348
|
+
return name.replace(/\.[^.]+$/, "").replace(/[-_]+/g, " ").trim() || "Image theme";
|
|
640
349
|
}
|
|
641
350
|
/**
|
|
642
|
-
*
|
|
643
|
-
*
|
|
351
|
+
* Reduces theme options to the minimal object that recreates them through
|
|
352
|
+
* `buildTheme`: in each scheme the accent is dropped when it is the stock
|
|
353
|
+
* one, the text color when it matches the one derived from the accent, and
|
|
354
|
+
* the background and contrast when they match the defaults — and a scheme
|
|
355
|
+
* with nothing left is dropped altogether. Options that boil down to the
|
|
356
|
+
* stock Studio theme reduce to `null` — they need nothing from this package.
|
|
644
357
|
*
|
|
645
358
|
* @internal
|
|
646
359
|
*/
|
|
647
|
-
function
|
|
648
|
-
let
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
}), $[0] = props.options, $[1] = t0), t0;
|
|
360
|
+
function minimizeOptions(options) {
|
|
361
|
+
let resolved = resolveThemeOptions(options), minimized = {};
|
|
362
|
+
for (let scheme of SCHEMES) {
|
|
363
|
+
let values = resolved[scheme], kept = {};
|
|
364
|
+
values.accent !== DEFAULT_ACCENT && (kept.accent = values.accent), values.text !== deriveTextColor(values.accent) && (kept.text = values.text), values.background !== DEFAULT_BACKGROUND[scheme] && (kept.background = values.background), values.contrast !== 85 && (kept.contrast = values.contrast), Object.keys(kept).length > 0 && (minimized[scheme] = kept);
|
|
365
|
+
}
|
|
366
|
+
return Object.keys(minimized).length === 0 ? null : minimized;
|
|
655
367
|
}
|
|
656
368
|
/**
|
|
657
|
-
*
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
* the last one is gone.
|
|
369
|
+
* Whether two sets of theme options generate the same theme, comparing their
|
|
370
|
+
* resolved forms so that derived and explicit values (and hex casing) don't
|
|
371
|
+
* matter.
|
|
661
372
|
*
|
|
662
373
|
* @internal
|
|
663
374
|
*/
|
|
664
|
-
function
|
|
665
|
-
let
|
|
666
|
-
|
|
667
|
-
let t1;
|
|
668
|
-
$[3] === send ? t1 = $[4] : (t1 = (theme) => /* @__PURE__ */ jsxs(Stack, {
|
|
669
|
-
gap: 3,
|
|
670
|
-
children: [
|
|
671
|
-
/* @__PURE__ */ jsx(Box, {
|
|
672
|
-
style: { opacity: .6 },
|
|
673
|
-
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
|
|
674
|
-
}),
|
|
675
|
-
/* @__PURE__ */ jsx(Text, {
|
|
676
|
-
align: "center",
|
|
677
|
-
size: 1,
|
|
678
|
-
textOverflow: "ellipsis",
|
|
679
|
-
children: displayTitle(theme.title)
|
|
680
|
-
}),
|
|
681
|
-
/* @__PURE__ */ jsxs(Flex, {
|
|
682
|
-
gap: 2,
|
|
683
|
-
justify: "center",
|
|
684
|
-
children: [/* @__PURE__ */ jsx(Button, {
|
|
685
|
-
fontSize: 1,
|
|
686
|
-
mode: "ghost",
|
|
687
|
-
onClick: () => send({
|
|
688
|
-
type: "theme.restore",
|
|
689
|
-
slug: theme.slug
|
|
690
|
-
}),
|
|
691
|
-
padding: 2,
|
|
692
|
-
text: "Restore"
|
|
693
|
-
}), theme.source === "custom" && /* @__PURE__ */ jsx(Button, {
|
|
694
|
-
fontSize: 1,
|
|
695
|
-
mode: "ghost",
|
|
696
|
-
onClick: () => send({
|
|
697
|
-
type: "theme.delete",
|
|
698
|
-
slug: theme.slug
|
|
699
|
-
}),
|
|
700
|
-
padding: 2,
|
|
701
|
-
text: "Delete",
|
|
702
|
-
tone: "critical"
|
|
703
|
-
})]
|
|
704
|
-
})
|
|
705
|
-
]
|
|
706
|
-
}, theme.slug), $[3] = send, $[4] = t1), t0 = removed.map(t1), $[0] = removed, $[1] = send, $[2] = t0;
|
|
707
|
-
} else t0 = $[2];
|
|
708
|
-
let t1;
|
|
709
|
-
return $[5] === t0 ? t1 = $[6] : (t1 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
710
|
-
padding: 3,
|
|
711
|
-
children: /* @__PURE__ */ jsx(Stack, {
|
|
712
|
-
gap: 5,
|
|
713
|
-
children: t0
|
|
714
|
-
})
|
|
715
|
-
}), $[5] = t0, $[6] = t1), t1;
|
|
375
|
+
function sameOptions(a, b) {
|
|
376
|
+
let left = resolveThemeOptions(a), right = resolveThemeOptions(b);
|
|
377
|
+
return SCHEMES.every((scheme) => sameScheme(left[scheme], right[scheme]));
|
|
716
378
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
"muted",
|
|
728
|
-
"vibrant",
|
|
729
|
-
"lightMuted",
|
|
730
|
-
"lightVibrant",
|
|
731
|
-
"darkMuted",
|
|
732
|
-
"darkVibrant"
|
|
733
|
-
], IMAGE_PALETTE_TITLES = {
|
|
734
|
-
dominant: "Dominant",
|
|
735
|
-
vibrant: "Vibrant",
|
|
736
|
-
lightVibrant: "Light vibrant",
|
|
737
|
-
darkVibrant: "Dark vibrant",
|
|
738
|
-
muted: "Muted",
|
|
739
|
-
lightMuted: "Light muted",
|
|
740
|
-
darkMuted: "Dark muted"
|
|
741
|
-
}, TARGETS = [
|
|
742
|
-
["vibrant", {
|
|
743
|
-
lightness: [
|
|
744
|
-
.5,
|
|
745
|
-
.3,
|
|
746
|
-
.7
|
|
747
|
-
],
|
|
748
|
-
saturation: [
|
|
749
|
-
1,
|
|
750
|
-
.35,
|
|
751
|
-
1
|
|
752
|
-
]
|
|
753
|
-
}],
|
|
754
|
-
["lightVibrant", {
|
|
755
|
-
lightness: [
|
|
756
|
-
.74,
|
|
757
|
-
.55,
|
|
758
|
-
1
|
|
759
|
-
],
|
|
760
|
-
saturation: [
|
|
761
|
-
1,
|
|
762
|
-
.35,
|
|
763
|
-
1
|
|
764
|
-
]
|
|
765
|
-
}],
|
|
766
|
-
["darkVibrant", {
|
|
767
|
-
lightness: [
|
|
768
|
-
.26,
|
|
769
|
-
0,
|
|
770
|
-
.45
|
|
771
|
-
],
|
|
772
|
-
saturation: [
|
|
773
|
-
1,
|
|
774
|
-
.35,
|
|
775
|
-
1
|
|
776
|
-
]
|
|
777
|
-
}],
|
|
778
|
-
["muted", {
|
|
779
|
-
lightness: [
|
|
780
|
-
.5,
|
|
781
|
-
.3,
|
|
782
|
-
.7
|
|
783
|
-
],
|
|
784
|
-
saturation: [
|
|
785
|
-
.3,
|
|
786
|
-
0,
|
|
787
|
-
.4
|
|
788
|
-
]
|
|
789
|
-
}],
|
|
790
|
-
["lightMuted", {
|
|
791
|
-
lightness: [
|
|
792
|
-
.74,
|
|
793
|
-
.55,
|
|
794
|
-
1
|
|
795
|
-
],
|
|
796
|
-
saturation: [
|
|
797
|
-
.3,
|
|
798
|
-
0,
|
|
799
|
-
.4
|
|
800
|
-
]
|
|
801
|
-
}],
|
|
802
|
-
["darkMuted", {
|
|
803
|
-
lightness: [
|
|
804
|
-
.26,
|
|
805
|
-
0,
|
|
806
|
-
.45
|
|
807
|
-
],
|
|
808
|
-
saturation: [
|
|
809
|
-
.3,
|
|
810
|
-
0,
|
|
811
|
-
.4
|
|
812
|
-
]
|
|
813
|
-
}]
|
|
814
|
-
];
|
|
379
|
+
function sameScheme(a, b) {
|
|
380
|
+
return a.accent === b.accent && a.text === b.text && a.background === b.background && a.contrast === b.contrast;
|
|
381
|
+
}
|
|
382
|
+
/** The slug of the theme the Studio config was generated from @internal */
|
|
383
|
+
const initialThemerState = {
|
|
384
|
+
active: null,
|
|
385
|
+
custom: [],
|
|
386
|
+
removed: [],
|
|
387
|
+
order: []
|
|
388
|
+
};
|
|
815
389
|
/**
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
390
|
+
* Resolves the list of themes: the configured theme first, then the presets
|
|
391
|
+
* (minus the ones that would only repeat the configured theme), then the
|
|
392
|
+
* user's own themes — rearranged into the order the user dragged them into,
|
|
393
|
+
* with themes that order does not know about kept in that default order after
|
|
394
|
+
* the ones it does. Removed themes are set aside so they can be restored, and
|
|
395
|
+
* the active theme falls back to the configured one when its slug no longer
|
|
396
|
+
* resolves.
|
|
822
397
|
*
|
|
823
398
|
* @internal
|
|
824
399
|
*/
|
|
825
|
-
function
|
|
826
|
-
let
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
400
|
+
function resolveThemes(state, baseOptions) {
|
|
401
|
+
let config = {
|
|
402
|
+
slug: "config",
|
|
403
|
+
title: "Studio config",
|
|
404
|
+
options: baseOptions,
|
|
405
|
+
source: "config"
|
|
406
|
+
}, all = [config];
|
|
407
|
+
for (let preset of presets) sameOptions(preset.options, baseOptions) || all.push({
|
|
408
|
+
slug: preset.slug,
|
|
409
|
+
title: preset.title,
|
|
410
|
+
options: preset.options,
|
|
411
|
+
source: "preset"
|
|
412
|
+
});
|
|
413
|
+
for (let theme of state.custom) all.push({
|
|
414
|
+
slug: theme.slug,
|
|
415
|
+
title: theme.title,
|
|
416
|
+
options: theme.options,
|
|
417
|
+
source: "custom",
|
|
418
|
+
...theme.palette ? { palette: theme.palette } : {}
|
|
419
|
+
});
|
|
420
|
+
let position = new Map(state.order.map((slug, index) => [slug, index])), rank = (theme) => position.get(theme.slug) ?? state.order.length;
|
|
421
|
+
all.sort((a, b) => rank(a) - rank(b));
|
|
422
|
+
let removedSlugs = new Set(state.removed), themes = all.filter((theme) => !removedSlugs.has(theme.slug));
|
|
423
|
+
return {
|
|
424
|
+
themes,
|
|
425
|
+
removed: all.filter((theme) => removedSlugs.has(theme.slug)),
|
|
426
|
+
active: themes.find((theme) => theme.slug === state.active) ?? config
|
|
834
427
|
};
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Creates a custom theme with a slug that cannot collide with the presets or
|
|
431
|
+
* the configured theme.
|
|
432
|
+
*
|
|
433
|
+
* @internal
|
|
434
|
+
*/
|
|
435
|
+
function createCustomTheme(title, options, palette) {
|
|
436
|
+
return {
|
|
437
|
+
slug: `custom-${randomId()}`,
|
|
438
|
+
title,
|
|
439
|
+
options,
|
|
440
|
+
...palette ? { palette } : {}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
/** The title of a duplicated theme @internal */
|
|
444
|
+
function duplicateTitle(title) {
|
|
445
|
+
return `${displayTitle(title)} copy`;
|
|
446
|
+
}
|
|
447
|
+
/** The title to show for a theme, falling back when the user cleared it @internal */
|
|
448
|
+
function displayTitle(title) {
|
|
449
|
+
return title.trim() || "Untitled theme";
|
|
450
|
+
}
|
|
451
|
+
function randomId() {
|
|
452
|
+
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
453
|
+
}
|
|
454
|
+
const STORAGE_KEY = "sanityStudio:themer:state", LEGACY_STORAGE_KEY = "sanityStudio:themer:options";
|
|
455
|
+
function sanitizeColor(value) {
|
|
456
|
+
return typeof value == "string" && isColor(value) ? value.toLowerCase() : null;
|
|
457
|
+
}
|
|
458
|
+
function sanitizeContrast(value) {
|
|
459
|
+
return typeof value == "number" && Number.isFinite(value) ? Math.min(100, Math.max(15, value)) : null;
|
|
460
|
+
}
|
|
461
|
+
function sanitizeSchemeOptions(value) {
|
|
462
|
+
let options = {};
|
|
463
|
+
if (!value || typeof value != "object") return options;
|
|
464
|
+
let accent = sanitizeColor(Reflect.get(value, "accent")), text = sanitizeColor(Reflect.get(value, "text")), background = sanitizeColor(Reflect.get(value, "background")), contrast = sanitizeContrast(Reflect.get(value, "contrast"));
|
|
465
|
+
return accent && (options.accent = accent), text && (options.text = text), background && (options.background = background), contrast !== null && (options.contrast = contrast), options;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Options from before they were grouped by scheme: one accent, text color and
|
|
469
|
+
* contrast for both schemes, and a background per scheme. Both schemes get
|
|
470
|
+
* the shared colors, so the theme keeps looking the same.
|
|
471
|
+
*/
|
|
472
|
+
function sanitizeFlatOptions(value) {
|
|
473
|
+
let accent = sanitizeColor(Reflect.get(value, "accent"));
|
|
474
|
+
if (!accent) return null;
|
|
475
|
+
let shared = { accent }, text = sanitizeColor(Reflect.get(value, "text")), contrast = sanitizeContrast(Reflect.get(value, "contrast"));
|
|
476
|
+
text && (shared.text = text), contrast !== null && (shared.contrast = contrast);
|
|
477
|
+
let backgrounds = Reflect.get(value, "background"), options = {};
|
|
478
|
+
for (let scheme of SCHEMES) {
|
|
479
|
+
let background = backgrounds && typeof backgrounds == "object" ? sanitizeColor(Reflect.get(backgrounds, scheme)) : null;
|
|
480
|
+
options[scheme] = background ? {
|
|
481
|
+
...shared,
|
|
482
|
+
background
|
|
483
|
+
} : { ...shared };
|
|
484
|
+
}
|
|
485
|
+
return options;
|
|
486
|
+
}
|
|
487
|
+
function sanitizeOptions(value) {
|
|
488
|
+
if (!value || typeof value != "object") return null;
|
|
489
|
+
if ("accent" in value) return sanitizeFlatOptions(value);
|
|
490
|
+
let options = {};
|
|
491
|
+
for (let scheme of SCHEMES) {
|
|
492
|
+
let schemeOptions = sanitizeSchemeOptions(Reflect.get(value, scheme));
|
|
493
|
+
Object.keys(schemeOptions).length > 0 && (options[scheme] = schemeOptions);
|
|
494
|
+
}
|
|
495
|
+
return options;
|
|
496
|
+
}
|
|
497
|
+
function isReservedSlug(slug) {
|
|
498
|
+
return slug === "config" || presets.some((preset) => preset.slug === slug);
|
|
499
|
+
}
|
|
500
|
+
function sanitizeCustomTheme(value) {
|
|
501
|
+
if (!value || typeof value != "object") return null;
|
|
502
|
+
let slug = Reflect.get(value, "slug");
|
|
503
|
+
if (typeof slug != "string" || !slug || isReservedSlug(slug)) return null;
|
|
504
|
+
let options = sanitizeOptions(Reflect.get(value, "options"));
|
|
505
|
+
if (!options) return null;
|
|
506
|
+
let title = Reflect.get(value, "title"), palette = sanitizePalette(Reflect.get(value, "palette"));
|
|
507
|
+
return {
|
|
508
|
+
slug,
|
|
509
|
+
title: displayTitle(typeof title == "string" ? title : ""),
|
|
510
|
+
options,
|
|
511
|
+
...palette ? { palette } : {}
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function sanitizePalette(value) {
|
|
515
|
+
if (!value || typeof value != "object") return null;
|
|
516
|
+
let palette = {}, swatches = 0;
|
|
517
|
+
for (let key of IMAGE_PALETTE_KEYS) {
|
|
518
|
+
let swatch = sanitizeColor(Reflect.get(value, key));
|
|
519
|
+
palette[key] = swatch, swatch && swatches++;
|
|
520
|
+
}
|
|
521
|
+
return swatches > 0 ? palette : null;
|
|
522
|
+
}
|
|
523
|
+
function sanitizeState(value) {
|
|
524
|
+
if (!value || typeof value != "object") return initialThemerState;
|
|
525
|
+
let custom = [], rawCustom = Reflect.get(value, "custom");
|
|
526
|
+
if (Array.isArray(rawCustom)) for (let item of rawCustom) {
|
|
527
|
+
let theme = sanitizeCustomTheme(item);
|
|
528
|
+
theme && !custom.some((existing) => existing.slug === theme.slug) && custom.push(theme);
|
|
529
|
+
}
|
|
530
|
+
let removed = [], rawRemoved = Reflect.get(value, "removed");
|
|
531
|
+
if (Array.isArray(rawRemoved)) for (let slug of rawRemoved) typeof slug == "string" && slug !== "config" && (presets.some((preset) => preset.slug === slug) || custom.some((theme) => theme.slug === slug)) && !removed.includes(slug) && removed.push(slug);
|
|
532
|
+
let order = [], rawOrder = Reflect.get(value, "order");
|
|
533
|
+
if (Array.isArray(rawOrder)) for (let slug of rawOrder) typeof slug == "string" && (slug === "config" || presets.some((preset) => preset.slug === slug) || custom.some((theme) => theme.slug === slug)) && !order.includes(slug) && order.push(slug);
|
|
534
|
+
let rawActive = Reflect.get(value, "active");
|
|
535
|
+
return {
|
|
536
|
+
active: typeof rawActive == "string" ? rawActive : null,
|
|
537
|
+
custom,
|
|
538
|
+
removed,
|
|
539
|
+
order
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function readLegacyState() {
|
|
543
|
+
let raw = localStorage.getItem(LEGACY_STORAGE_KEY);
|
|
544
|
+
if (!raw) return null;
|
|
545
|
+
let options = sanitizeOptions(JSON.parse(raw));
|
|
546
|
+
if (!options) return null;
|
|
547
|
+
let theme = createCustomTheme("Draft theme", options);
|
|
548
|
+
return {
|
|
549
|
+
active: theme.slug,
|
|
550
|
+
custom: [theme],
|
|
551
|
+
removed: [],
|
|
552
|
+
order: []
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Restores the themer state from localStorage, so the user's themes survive
|
|
557
|
+
* studio reloads. Falls back to the initial state when nothing usable is
|
|
558
|
+
* stored.
|
|
559
|
+
*
|
|
560
|
+
* @internal
|
|
561
|
+
*/
|
|
562
|
+
function readStoredState() {
|
|
563
|
+
try {
|
|
564
|
+
if (typeof localStorage > "u") return initialThemerState;
|
|
565
|
+
let raw = localStorage.getItem(STORAGE_KEY);
|
|
566
|
+
return raw ? sanitizeState(JSON.parse(raw)) : readLegacyState() ?? initialThemerState;
|
|
567
|
+
} catch {
|
|
568
|
+
return initialThemerState;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/** @internal */
|
|
572
|
+
function writeStoredState(state) {
|
|
573
|
+
try {
|
|
574
|
+
if (typeof localStorage > "u") return;
|
|
575
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(state)), localStorage.removeItem(LEGACY_STORAGE_KEY);
|
|
576
|
+
} catch {}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* How long the layout's motions — the panel's and the split preview's, and
|
|
580
|
+
* the cross-fade to another theme — are taken to last when the layout never
|
|
581
|
+
* says: it reports every view transition it starts, so this only ends a
|
|
582
|
+
* motion that has none (reduced motion, a browser without view transitions),
|
|
583
|
+
* where the `moving` and `switching` tags have nothing to affect. Generous,
|
|
584
|
+
* so that it never runs out before a slow deferred commit starts the real one.
|
|
585
|
+
*
|
|
586
|
+
* @internal
|
|
587
|
+
*/
|
|
588
|
+
const MOTION_DURATION = 2e3;
|
|
589
|
+
function themesOf(context) {
|
|
590
|
+
return resolveThemes(context, context.baseOptions);
|
|
591
|
+
}
|
|
592
|
+
function revokeObjectUrl(url) {
|
|
593
|
+
typeof URL < "u" && typeof URL.revokeObjectURL == "function" && URL.revokeObjectURL(url);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* The state of the themer tool: three parallel regions, whether the
|
|
597
|
+
* `sidebar` is open, which `flow` it is in — picking a theme from the `list`,
|
|
598
|
+
* `edit`ing one of the user's own themes, or restoring `removed` ones — and
|
|
599
|
+
* whether the `preview` shows the Studio once (`single`) or in light and dark
|
|
600
|
+
* side by side (`split`). The context carries the persisted state (the
|
|
601
|
+
* applied theme, the user's themes and what was removed) alongside what the
|
|
602
|
+
* flows need.
|
|
603
|
+
*
|
|
604
|
+
* The sidebar and the preview pass through `opening`/`closing` and
|
|
605
|
+
* `splitting`/`unsplitting` on their way, states tagged for the UI: `panel`
|
|
606
|
+
* and `split` say what shows (the panel from `opening` on, the split copy from
|
|
607
|
+
* `splitting` on), `moving` that the Studio is about to give way or take room
|
|
608
|
+
* — which is when, and only when, the layout lets a view transition animate
|
|
609
|
+
* it. A fourth region, `theme`, is `switching` (its tag) right after an event
|
|
610
|
+
* that applies another theme — picking one, adding, duplicating, importing or
|
|
611
|
+
* editing one, removing or deleting the applied one — when the layout
|
|
612
|
+
* cross-fades to it; edits to the applied theme's colors are not switches,
|
|
613
|
+
* they follow the pointer. These states last until the layout reports its
|
|
614
|
+
* transition under way — every boundary reports, the panel's and the copy's
|
|
615
|
+
* entering and leaving as much as the Studio's morphing — or for
|
|
616
|
+
* `MOTION_DURATION` when nothing animates.
|
|
617
|
+
*
|
|
618
|
+
* Theme operations are handled in every flow, and the flows leave on their
|
|
619
|
+
* own when they lose their subject: the editor when its theme is removed or
|
|
620
|
+
* deleted, and the removed view when its last theme is restored or deleted.
|
|
621
|
+
*
|
|
622
|
+
* @internal
|
|
623
|
+
*/
|
|
624
|
+
const themerMachine = setup({
|
|
625
|
+
types: {
|
|
626
|
+
context: {},
|
|
627
|
+
events: {},
|
|
628
|
+
input: {}
|
|
629
|
+
},
|
|
630
|
+
guards: {
|
|
631
|
+
isCustomTheme: ({ context }, params) => themesOf(context).themes.some((theme) => theme.slug === params.slug && theme.source === "custom"),
|
|
632
|
+
isEditingListedTheme: ({ context }) => context.editing !== null && themesOf(context).themes.some((theme) => theme.slug === context.editing?.slug && theme.source === "custom"),
|
|
633
|
+
hasRemovedThemes: ({ context }) => themesOf(context).removed.length > 0,
|
|
634
|
+
sidebarShown: or([stateIn({ sidebar: "opening" }), stateIn({ sidebar: "open" })]),
|
|
635
|
+
isAnotherTheme: ({ context }, params) => params.slug !== (context.active ?? "config"),
|
|
636
|
+
isAppliedTheme: ({ context }, params) => params.slug === context.active,
|
|
637
|
+
hasOptions: (_, params) => params.options !== void 0
|
|
638
|
+
},
|
|
639
|
+
actions: {
|
|
640
|
+
persist: ({ context }) => {
|
|
641
|
+
let { active, custom, removed, order } = context;
|
|
642
|
+
writeStoredState({
|
|
643
|
+
active,
|
|
644
|
+
custom,
|
|
645
|
+
removed,
|
|
646
|
+
order
|
|
647
|
+
});
|
|
648
|
+
},
|
|
649
|
+
revokeImage: (_, params) => {
|
|
650
|
+
params.url && revokeObjectUrl(params.url);
|
|
651
|
+
},
|
|
652
|
+
pick: assign((_, params) => ({ active: params.slug === "config" ? null : params.slug })),
|
|
653
|
+
add: assign(({ context }, params) => {
|
|
654
|
+
let theme = createCustomTheme(params.title ?? "Untitled theme", params.options ?? themesOf(context).active.options, params.palette);
|
|
655
|
+
return {
|
|
656
|
+
active: theme.slug,
|
|
657
|
+
custom: [...context.custom, theme],
|
|
658
|
+
editing: {
|
|
659
|
+
slug: theme.slug,
|
|
660
|
+
focusTitle: params.title === void 0
|
|
661
|
+
},
|
|
662
|
+
images: params.imageUrl ? {
|
|
663
|
+
...context.images,
|
|
664
|
+
[theme.slug]: params.imageUrl
|
|
665
|
+
} : context.images
|
|
666
|
+
};
|
|
667
|
+
}),
|
|
668
|
+
import: assign(({ context }, params) => {
|
|
669
|
+
let theme = createCustomTheme(params.title, params.options);
|
|
670
|
+
return {
|
|
671
|
+
active: theme.slug,
|
|
672
|
+
custom: [...context.custom, theme]
|
|
673
|
+
};
|
|
674
|
+
}),
|
|
675
|
+
duplicate: assign(({ context }, params) => {
|
|
676
|
+
let { themes, removed } = themesOf(context), source = [...themes, ...removed].find((theme) => theme.slug === params.slug);
|
|
677
|
+
if (!source) return {};
|
|
678
|
+
let theme = createCustomTheme(duplicateTitle(source.title), source.options, source.palette);
|
|
679
|
+
return {
|
|
680
|
+
active: theme.slug,
|
|
681
|
+
custom: [...context.custom, theme],
|
|
682
|
+
editing: {
|
|
683
|
+
slug: theme.slug,
|
|
684
|
+
focusTitle: !0
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}),
|
|
688
|
+
startEditing: assign((_, params) => ({
|
|
689
|
+
active: params.slug,
|
|
690
|
+
editing: {
|
|
691
|
+
slug: params.slug,
|
|
692
|
+
focusTitle: !1
|
|
693
|
+
}
|
|
694
|
+
})),
|
|
695
|
+
stopEditing: assign({ editing: null }),
|
|
696
|
+
update: assign(({ context }, params) => ({
|
|
697
|
+
custom: context.custom.map((theme) => theme.slug === params.slug ? {
|
|
698
|
+
...theme,
|
|
699
|
+
title: params.title ?? theme.title,
|
|
700
|
+
options: params.options ?? theme.options,
|
|
701
|
+
...params.palette ? { palette: params.palette } : {}
|
|
702
|
+
} : theme),
|
|
703
|
+
images: params.imageUrl && context.custom.some((theme) => theme.slug === params.slug) ? {
|
|
704
|
+
...context.images,
|
|
705
|
+
[params.slug]: params.imageUrl
|
|
706
|
+
} : context.images
|
|
707
|
+
})),
|
|
708
|
+
remove: assign(({ context }, params) => params.slug === "config" || context.removed.includes(params.slug) ? {} : {
|
|
709
|
+
active: context.active === params.slug ? null : context.active,
|
|
710
|
+
removed: [...context.removed, params.slug]
|
|
711
|
+
}),
|
|
712
|
+
restore: assign(({ context }, params) => ({ removed: context.removed.filter((slug) => slug !== params.slug) })),
|
|
713
|
+
reorder: assign(({ context }, params) => {
|
|
714
|
+
let listed = new Set(themesOf(context).themes.map((theme) => theme.slug)), order = params.order.filter((slug) => listed.has(slug));
|
|
715
|
+
return { order: [...order, ...context.order.filter((slug) => !order.includes(slug))] };
|
|
716
|
+
}),
|
|
717
|
+
delete: assign(({ context }, params) => {
|
|
718
|
+
if (!context.custom.some((theme) => theme.slug === params.slug)) return {};
|
|
719
|
+
let { [params.slug]: _deleted, ...images } = context.images;
|
|
720
|
+
return {
|
|
721
|
+
active: context.active === params.slug ? null : context.active,
|
|
722
|
+
custom: context.custom.filter((theme) => theme.slug !== params.slug),
|
|
723
|
+
removed: context.removed.filter((slug) => slug !== params.slug),
|
|
724
|
+
images
|
|
725
|
+
};
|
|
726
|
+
})
|
|
727
|
+
}
|
|
728
|
+
}).createMachine({
|
|
729
|
+
id: "themer",
|
|
730
|
+
context: ({ input }) => ({
|
|
731
|
+
...input.stored,
|
|
732
|
+
baseOptions: input.baseOptions,
|
|
733
|
+
editing: null,
|
|
734
|
+
images: {}
|
|
735
|
+
}),
|
|
736
|
+
entry: "persist",
|
|
737
|
+
type: "parallel",
|
|
738
|
+
states: {
|
|
739
|
+
sidebar: {
|
|
740
|
+
initial: "closed",
|
|
741
|
+
states: {
|
|
742
|
+
closed: { on: { "sidebar.toggle": "opening" } },
|
|
743
|
+
opening: {
|
|
744
|
+
tags: ["panel", "moving"],
|
|
745
|
+
after: { [MOTION_DURATION]: "open" },
|
|
746
|
+
on: {
|
|
747
|
+
"layout.transitioned": "open",
|
|
748
|
+
"sidebar.toggle": "closing",
|
|
749
|
+
"sidebar.close": "closing"
|
|
750
|
+
}
|
|
751
|
+
},
|
|
752
|
+
open: {
|
|
753
|
+
tags: ["panel"],
|
|
754
|
+
on: {
|
|
755
|
+
"sidebar.toggle": "closing",
|
|
756
|
+
"sidebar.close": "closing"
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
closing: {
|
|
760
|
+
tags: ["moving"],
|
|
761
|
+
after: { [MOTION_DURATION]: "closed" },
|
|
762
|
+
on: {
|
|
763
|
+
"layout.transitioned": "closed",
|
|
764
|
+
"sidebar.toggle": "opening"
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
preview: {
|
|
770
|
+
initial: "single",
|
|
771
|
+
states: {
|
|
772
|
+
single: { on: { "preview.toggle": "splitting" } },
|
|
773
|
+
splitting: {
|
|
774
|
+
tags: ["split", "moving"],
|
|
775
|
+
after: { [MOTION_DURATION]: "split" },
|
|
776
|
+
on: {
|
|
777
|
+
"layout.transitioned": "split",
|
|
778
|
+
"preview.toggle": "unsplitting",
|
|
779
|
+
"sidebar.close": "unsplitting",
|
|
780
|
+
"sidebar.toggle": {
|
|
781
|
+
guard: "sidebarShown",
|
|
782
|
+
target: "unsplitting"
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
split: {
|
|
787
|
+
tags: ["split"],
|
|
788
|
+
on: {
|
|
789
|
+
"preview.toggle": "unsplitting",
|
|
790
|
+
"sidebar.close": "unsplitting",
|
|
791
|
+
"sidebar.toggle": {
|
|
792
|
+
guard: "sidebarShown",
|
|
793
|
+
target: "unsplitting"
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
unsplitting: {
|
|
798
|
+
tags: ["moving"],
|
|
799
|
+
after: { [MOTION_DURATION]: "single" },
|
|
800
|
+
on: {
|
|
801
|
+
"layout.transitioned": "single",
|
|
802
|
+
"preview.toggle": "splitting"
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
theme: {
|
|
808
|
+
initial: "applied",
|
|
809
|
+
states: {
|
|
810
|
+
applied: { on: {
|
|
811
|
+
"theme.pick": {
|
|
812
|
+
guard: {
|
|
813
|
+
type: "isAnotherTheme",
|
|
814
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
815
|
+
},
|
|
816
|
+
target: "switching"
|
|
817
|
+
},
|
|
818
|
+
"theme.edit": {
|
|
819
|
+
guard: {
|
|
820
|
+
type: "isAnotherTheme",
|
|
821
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
822
|
+
},
|
|
823
|
+
target: "switching"
|
|
824
|
+
},
|
|
825
|
+
"theme.duplicate": {
|
|
826
|
+
guard: {
|
|
827
|
+
type: "isAnotherTheme",
|
|
828
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
829
|
+
},
|
|
830
|
+
target: "switching"
|
|
831
|
+
},
|
|
832
|
+
"theme.remove": {
|
|
833
|
+
guard: {
|
|
834
|
+
type: "isAppliedTheme",
|
|
835
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
836
|
+
},
|
|
837
|
+
target: "switching"
|
|
838
|
+
},
|
|
839
|
+
"theme.delete": {
|
|
840
|
+
guard: {
|
|
841
|
+
type: "isAppliedTheme",
|
|
842
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
843
|
+
},
|
|
844
|
+
target: "switching"
|
|
845
|
+
},
|
|
846
|
+
"theme.add": {
|
|
847
|
+
guard: {
|
|
848
|
+
type: "hasOptions",
|
|
849
|
+
params: ({ event }) => ({ options: event.options })
|
|
850
|
+
},
|
|
851
|
+
target: "switching"
|
|
852
|
+
},
|
|
853
|
+
"theme.import": "switching"
|
|
854
|
+
} },
|
|
855
|
+
switching: {
|
|
856
|
+
tags: ["switching"],
|
|
857
|
+
after: { [MOTION_DURATION]: "applied" },
|
|
858
|
+
on: {
|
|
859
|
+
"layout.transitioned": "applied",
|
|
860
|
+
"theme.pick": {
|
|
861
|
+
guard: {
|
|
862
|
+
type: "isAnotherTheme",
|
|
863
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
864
|
+
},
|
|
865
|
+
target: "switching",
|
|
866
|
+
reenter: !0
|
|
867
|
+
},
|
|
868
|
+
"theme.edit": {
|
|
869
|
+
guard: {
|
|
870
|
+
type: "isAnotherTheme",
|
|
871
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
872
|
+
},
|
|
873
|
+
target: "switching",
|
|
874
|
+
reenter: !0
|
|
875
|
+
},
|
|
876
|
+
"theme.duplicate": {
|
|
877
|
+
guard: {
|
|
878
|
+
type: "isAnotherTheme",
|
|
879
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
880
|
+
},
|
|
881
|
+
target: "switching",
|
|
882
|
+
reenter: !0
|
|
883
|
+
},
|
|
884
|
+
"theme.remove": {
|
|
885
|
+
guard: {
|
|
886
|
+
type: "isAppliedTheme",
|
|
887
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
888
|
+
},
|
|
889
|
+
target: "switching",
|
|
890
|
+
reenter: !0
|
|
891
|
+
},
|
|
892
|
+
"theme.delete": {
|
|
893
|
+
guard: {
|
|
894
|
+
type: "isAppliedTheme",
|
|
895
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
896
|
+
},
|
|
897
|
+
target: "switching",
|
|
898
|
+
reenter: !0
|
|
899
|
+
},
|
|
900
|
+
"theme.add": {
|
|
901
|
+
guard: {
|
|
902
|
+
type: "hasOptions",
|
|
903
|
+
params: ({ event }) => ({ options: event.options })
|
|
904
|
+
},
|
|
905
|
+
target: "switching",
|
|
906
|
+
reenter: !0
|
|
907
|
+
},
|
|
908
|
+
"theme.import": {
|
|
909
|
+
target: "switching",
|
|
910
|
+
reenter: !0
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
flow: {
|
|
917
|
+
initial: "list",
|
|
918
|
+
on: {
|
|
919
|
+
"theme.pick": { actions: [{
|
|
920
|
+
type: "pick",
|
|
921
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
922
|
+
}, "persist"] },
|
|
923
|
+
"theme.add": {
|
|
924
|
+
target: ".edit",
|
|
925
|
+
actions: [{
|
|
926
|
+
type: "add",
|
|
927
|
+
params: ({ event }) => ({
|
|
928
|
+
title: event.title,
|
|
929
|
+
options: event.options,
|
|
930
|
+
palette: event.palette,
|
|
931
|
+
imageUrl: event.imageUrl
|
|
932
|
+
})
|
|
933
|
+
}, "persist"]
|
|
934
|
+
},
|
|
935
|
+
"theme.duplicate": {
|
|
936
|
+
target: ".edit",
|
|
937
|
+
actions: [{
|
|
938
|
+
type: "duplicate",
|
|
939
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
940
|
+
}, "persist"]
|
|
941
|
+
},
|
|
942
|
+
"theme.edit": {
|
|
943
|
+
target: ".edit",
|
|
944
|
+
guard: {
|
|
945
|
+
type: "isCustomTheme",
|
|
946
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
947
|
+
},
|
|
948
|
+
actions: [{
|
|
949
|
+
type: "startEditing",
|
|
950
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
951
|
+
}, "persist"]
|
|
952
|
+
},
|
|
953
|
+
"theme.update": { actions: [
|
|
954
|
+
{
|
|
955
|
+
type: "revokeImage",
|
|
956
|
+
params: ({ context, event }) => ({ url: event.imageUrl ? context.images[event.slug] : void 0 })
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
type: "update",
|
|
960
|
+
params: ({ event }) => ({
|
|
961
|
+
slug: event.slug,
|
|
962
|
+
title: event.title,
|
|
963
|
+
options: event.options,
|
|
964
|
+
palette: event.palette,
|
|
965
|
+
imageUrl: event.imageUrl
|
|
966
|
+
})
|
|
967
|
+
},
|
|
968
|
+
"persist"
|
|
969
|
+
] },
|
|
970
|
+
"theme.remove": { actions: [{
|
|
971
|
+
type: "remove",
|
|
972
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
973
|
+
}, "persist"] },
|
|
974
|
+
"theme.restore": { actions: [{
|
|
975
|
+
type: "restore",
|
|
976
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
977
|
+
}, "persist"] },
|
|
978
|
+
"theme.delete": { actions: [
|
|
979
|
+
{
|
|
980
|
+
type: "revokeImage",
|
|
981
|
+
params: ({ context, event }) => ({ url: context.images[event.slug] })
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
type: "delete",
|
|
985
|
+
params: ({ event }) => ({ slug: event.slug })
|
|
986
|
+
},
|
|
987
|
+
"persist"
|
|
988
|
+
] },
|
|
989
|
+
"theme.reorder": { actions: [{
|
|
990
|
+
type: "reorder",
|
|
991
|
+
params: ({ event }) => ({ order: event.order })
|
|
992
|
+
}, "persist"] },
|
|
993
|
+
"theme.import": { actions: [{
|
|
994
|
+
type: "import",
|
|
995
|
+
params: ({ event }) => ({
|
|
996
|
+
title: event.title,
|
|
997
|
+
options: event.options
|
|
998
|
+
})
|
|
999
|
+
}, "persist"] },
|
|
1000
|
+
"flow.list": ".list",
|
|
1001
|
+
"flow.removed": {
|
|
1002
|
+
target: ".removed",
|
|
1003
|
+
guard: "hasRemovedThemes"
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
states: {
|
|
1007
|
+
list: {},
|
|
1008
|
+
edit: {
|
|
1009
|
+
exit: "stopEditing",
|
|
1010
|
+
always: {
|
|
1011
|
+
guard: not("isEditingListedTheme"),
|
|
1012
|
+
target: "list"
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
removed: { always: {
|
|
1016
|
+
guard: not("hasRemovedThemes"),
|
|
1017
|
+
target: "list"
|
|
1018
|
+
} }
|
|
1019
|
+
}
|
|
843
1020
|
}
|
|
844
|
-
best && (palette[key] = best.hex, claimed.add(best.hex));
|
|
845
|
-
}
|
|
846
|
-
return palette.dominant = candidates.reduce((most, candidate) => candidate.population > most.population ? candidate : most).hex, palette;
|
|
847
|
-
}
|
|
848
|
-
/**
|
|
849
|
-
* Turns the pixels into a histogram of quantized colors, each averaged over
|
|
850
|
-
* the pixels it stands for, leaving out transparent pixels and the near-black
|
|
851
|
-
* and near-white ones that are backdrop rather than color.
|
|
852
|
-
*/
|
|
853
|
-
function quantize(pixels) {
|
|
854
|
-
let { data } = pixels, buckets = /* @__PURE__ */ new Map(), length = Math.min(data.length, pixels.width * pixels.height * 4);
|
|
855
|
-
for (let offset = 0; offset + 3 < length; offset += 4) {
|
|
856
|
-
let r = data[offset], g = data[offset + 1], b = data[offset + 2];
|
|
857
|
-
if (data[offset + 3] < 125) continue;
|
|
858
|
-
let lightness = (Math.max(r, g, b) + Math.min(r, g, b)) / 510;
|
|
859
|
-
if (lightness < .05 || lightness > .95) continue;
|
|
860
|
-
let key = r >> 3 << 10 | g >> 3 << 5 | b >> 3, bucket = buckets.get(key);
|
|
861
|
-
bucket ? (bucket.count++, bucket.r += r, bucket.g += g, bucket.b += b) : buckets.set(key, {
|
|
862
|
-
count: 1,
|
|
863
|
-
r,
|
|
864
|
-
g,
|
|
865
|
-
b
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
let candidates = [];
|
|
869
|
-
for (let bucket of buckets.values()) {
|
|
870
|
-
let r = Math.round(bucket.r / bucket.count), g = Math.round(bucket.g / bucket.count), b = Math.round(bucket.b / bucket.count), { saturation, lightness } = saturationAndLightness(r, g, b);
|
|
871
|
-
candidates.push({
|
|
872
|
-
hex: rgbToHex(r, g, b),
|
|
873
|
-
population: bucket.count,
|
|
874
|
-
saturation,
|
|
875
|
-
lightness
|
|
876
|
-
});
|
|
877
1021
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
function
|
|
881
|
-
|
|
882
|
-
}
|
|
883
|
-
function scoreCandidate(candidate, target, maximumPopulation) {
|
|
884
|
-
return 3 * (1 - Math.abs(candidate.saturation - target.saturation[0])) + 6.5 * (1 - Math.abs(candidate.lightness - target.lightness[0])) + .5 * (candidate.population / maximumPopulation);
|
|
885
|
-
}
|
|
886
|
-
function saturationAndLightness(r, g, b) {
|
|
887
|
-
let max = Math.max(r, g, b) / 255, min = Math.min(r, g, b) / 255, lightness = (max + min) / 2, delta = max - min;
|
|
1022
|
+
});
|
|
1023
|
+
/** The part of the machine context that is persisted between sessions @internal */
|
|
1024
|
+
function selectStoredState(snapshot) {
|
|
1025
|
+
let { active, custom, removed, order } = snapshot.context;
|
|
888
1026
|
return {
|
|
889
|
-
|
|
890
|
-
|
|
1027
|
+
active,
|
|
1028
|
+
custom,
|
|
1029
|
+
removed,
|
|
1030
|
+
order
|
|
891
1031
|
};
|
|
892
1032
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
}
|
|
900
|
-
/** Reads `#rgb` and `#rrggbb` alike — stored palettes may hold either */
|
|
901
|
-
function hexToRgb(hex) {
|
|
902
|
-
let expanded = hex.length === 4 ? `${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex.slice(1);
|
|
903
|
-
return [
|
|
904
|
-
parseInt(expanded.slice(0, 2), 16),
|
|
905
|
-
parseInt(expanded.slice(2, 4), 16),
|
|
906
|
-
parseInt(expanded.slice(4, 6), 16)
|
|
907
|
-
];
|
|
908
|
-
}
|
|
909
|
-
/** Mixes `amount` of `color` into `base` */
|
|
910
|
-
function tint(base, color, amount) {
|
|
911
|
-
let [r1, g1, b1] = hexToRgb(base), [r2, g2, b2] = hexToRgb(color);
|
|
912
|
-
return rgbToHex(Math.round(r1 + (r2 - r1) * amount), Math.round(g1 + (g2 - g1) * amount), Math.round(b1 + (b2 - b1) * amount));
|
|
913
|
-
}
|
|
914
|
-
/** How much of the palette tints each scheme's stock background */
|
|
915
|
-
const BACKGROUND_TINT = {
|
|
916
|
-
light: .08,
|
|
917
|
-
dark: .3
|
|
918
|
-
}, BUTTON_LABEL = {
|
|
919
|
-
light: "#ffffff",
|
|
920
|
-
dark: "#000000"
|
|
921
|
-
}, ACCENT_LIGHTNESS_STEP = .01;
|
|
922
|
-
function contrastRatio(a, b) {
|
|
923
|
-
let [lighter, darker] = [relativeLuminance(a), relativeLuminance(b)].sort((x, y) => y - x);
|
|
924
|
-
return (lighter + .05) / (darker + .05);
|
|
925
|
-
}
|
|
1033
|
+
var root$2 = "_1o50s7t0";
|
|
1034
|
+
const ScrollAreaInsetContext = createContext({
|
|
1035
|
+
left: 0,
|
|
1036
|
+
right: 0,
|
|
1037
|
+
bottom: 0
|
|
1038
|
+
});
|
|
926
1039
|
/**
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
*
|
|
1040
|
+
* The gutter the last scroll area measured. It is the same for every scroll
|
|
1041
|
+
* area (the reserved gutter does not depend on the content), so the next one
|
|
1042
|
+
* starts out with the right padding instead of shifting after its first
|
|
1043
|
+
* measurement — which would also throw off anything scrolling into view as
|
|
1044
|
+
* the content mounts.
|
|
1045
|
+
*/
|
|
1046
|
+
let lastGutter = 0;
|
|
1047
|
+
/**
|
|
1048
|
+
* The scrolling body of a sidebar flow. It always reserves the scrollbar's
|
|
1049
|
+
* space, so the content does not shift when the list grows or shrinks past
|
|
1050
|
+
* the point where it needs to scroll — and it takes that space out of its
|
|
1051
|
+
* right padding, so the content stays centered rather than hugging the left.
|
|
1052
|
+
* With overlay scrollbars there is no gutter and the padding stays even.
|
|
931
1053
|
*
|
|
932
1054
|
* @internal
|
|
933
1055
|
*/
|
|
934
|
-
function
|
|
935
|
-
let
|
|
936
|
-
for (
|
|
937
|
-
let
|
|
938
|
-
if (
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1056
|
+
function ScrollArea(props) {
|
|
1057
|
+
let $ = c(15), { children, padding } = props, { space } = useTheme_v2(), ref = useRef(null), [gutter, setGutter] = useState(_temp$7), t0, t1;
|
|
1058
|
+
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => {
|
|
1059
|
+
let element = ref.current;
|
|
1060
|
+
if (!element) return;
|
|
1061
|
+
let measure = () => {
|
|
1062
|
+
lastGutter = element.offsetWidth - element.clientWidth, setGutter(lastGutter);
|
|
1063
|
+
};
|
|
1064
|
+
measure();
|
|
1065
|
+
let observer = new ResizeObserver(measure);
|
|
1066
|
+
return observer.observe(element), () => observer.disconnect();
|
|
1067
|
+
}, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
|
|
1068
|
+
let t2 = space[padding], t3 = Math.max(0, space[padding] - gutter), t4 = space[padding], t5;
|
|
1069
|
+
$[2] !== t2 || $[3] !== t3 || $[4] !== t4 ? (t5 = {
|
|
1070
|
+
left: t2,
|
|
1071
|
+
right: t3,
|
|
1072
|
+
bottom: t4
|
|
1073
|
+
}, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5) : t5 = $[5];
|
|
1074
|
+
let inset = t5, t6;
|
|
1075
|
+
$[6] === inset.right ? t6 = $[7] : (t6 = { paddingRight: inset.right }, $[6] = inset.right, $[7] = t6);
|
|
1076
|
+
let t7;
|
|
1077
|
+
$[8] !== children || $[9] !== inset ? (t7 = /* @__PURE__ */ jsx(ScrollAreaInsetContext.Provider, {
|
|
1078
|
+
value: inset,
|
|
1079
|
+
children
|
|
1080
|
+
}), $[8] = children, $[9] = inset, $[10] = t7) : t7 = $[10];
|
|
1081
|
+
let t8;
|
|
1082
|
+
return $[11] !== padding || $[12] !== t6 || $[13] !== t7 ? (t8 = /* @__PURE__ */ jsx(Box, {
|
|
1083
|
+
className: root$2,
|
|
1084
|
+
flex: 1,
|
|
1085
|
+
overflow: "auto",
|
|
1086
|
+
padding,
|
|
1087
|
+
ref,
|
|
1088
|
+
style: t6,
|
|
1089
|
+
children: t7
|
|
1090
|
+
}), $[11] = padding, $[12] = t6, $[13] = t7, $[14] = t8) : t8 = $[14], t8;
|
|
946
1091
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
let swatch = (variant ? palette[variant] : null) ?? palette.vibrant ?? (scheme === "light" ? palette.darkVibrant : palette.lightVibrant) ?? palette.dominant;
|
|
950
|
-
return swatch === null ? null : readableAccent(swatch, scheme);
|
|
1092
|
+
function _temp$7() {
|
|
1093
|
+
return lastGutter;
|
|
951
1094
|
}
|
|
952
1095
|
/**
|
|
953
|
-
*
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
* adjusted until it is readable as a button. The muted swatch becomes the text color, and the light and dark muted
|
|
957
|
-
* swatches tint the stock backgrounds of their scheme — enough to carry the
|
|
958
|
-
* image's tone without giving up a usable canvas. Whatever the palette lacks
|
|
959
|
-
* stays at the theme defaults.
|
|
1096
|
+
* Content that runs edge to edge in a scroll area — up to the scrollbar —
|
|
1097
|
+
* instead of sitting inside its padding. It goes last: it runs down to the
|
|
1098
|
+
* bottom edge too.
|
|
960
1099
|
*
|
|
961
1100
|
* @internal
|
|
962
1101
|
*/
|
|
963
|
-
function
|
|
964
|
-
let
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1102
|
+
function ScrollAreaBleed(props) {
|
|
1103
|
+
let $ = c(7), { left, right, bottom } = useContext(ScrollAreaInsetContext), t0 = -left, t1 = -right, t2 = -bottom, t3;
|
|
1104
|
+
$[0] !== t0 || $[1] !== t1 || $[2] !== t2 ? (t3 = {
|
|
1105
|
+
marginLeft: t0,
|
|
1106
|
+
marginRight: t1,
|
|
1107
|
+
marginBottom: t2
|
|
1108
|
+
}, $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3) : t3 = $[3];
|
|
1109
|
+
let t4;
|
|
1110
|
+
return $[4] !== props.children || $[5] !== t3 ? (t4 = /* @__PURE__ */ jsx("div", {
|
|
1111
|
+
style: t3,
|
|
1112
|
+
children: props.children
|
|
1113
|
+
}), $[4] = props.children, $[5] = t3, $[6] = t4) : t4 = $[6], t4;
|
|
970
1114
|
}
|
|
1115
|
+
var avatar = "_1aa9huuh", body = "_1aa9huui", button = "_1aa9huuq", colors = {
|
|
1116
|
+
bg: "var(--_1aa9huu0)",
|
|
1117
|
+
fg: "var(--_1aa9huu1)",
|
|
1118
|
+
mutedFg: "var(--_1aa9huu2)",
|
|
1119
|
+
border: "var(--_1aa9huu3)",
|
|
1120
|
+
accent: "var(--_1aa9huu4)",
|
|
1121
|
+
avatar: "var(--_1aa9huu5)",
|
|
1122
|
+
selectedBg: "var(--_1aa9huu6)",
|
|
1123
|
+
selectedFg: "var(--_1aa9huu7)",
|
|
1124
|
+
inputBg: "var(--_1aa9huu8)",
|
|
1125
|
+
inputBorder: "var(--_1aa9huu9)"
|
|
1126
|
+
}, field = "_1aa9huun", footer = "_1aa9huup", form = "_1aa9huum", input = "_1aa9huuo", line = {
|
|
1127
|
+
fg: "_1aa9huus _1aa9huur",
|
|
1128
|
+
muted: "_1aa9huut _1aa9huur",
|
|
1129
|
+
selected: "_1aa9huuu _1aa9huur"
|
|
1130
|
+
}, list = "_1aa9huuj", listRow = "_1aa9huuk", logo = "_1aa9huuf", navbar = "_1aa9huue", pane = "_1aa9huul", root$1 = "_1aa9huua", spacer = "_1aa9huug", studio = {
|
|
1131
|
+
light: "_1aa9huub",
|
|
1132
|
+
dark: "_1aa9huud _1aa9huub"
|
|
1133
|
+
};
|
|
1134
|
+
/** The document rows in the list pane — the widths of their title lines */
|
|
1135
|
+
const LIST_ROWS = [
|
|
1136
|
+
"62%",
|
|
1137
|
+
"46%",
|
|
1138
|
+
"70%",
|
|
1139
|
+
"52%"
|
|
1140
|
+
], FIELDS$1 = ["32%", "24%"];
|
|
971
1141
|
/**
|
|
972
|
-
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
1142
|
+
* A tiny, lo-fi mockup of a Studio in the given theme — the navbar over the
|
|
1143
|
+
* structure tool with a list of documents on the left and a document form on
|
|
1144
|
+
* the right — in both color schemes at once: the light scheme on the left and
|
|
1145
|
+
* the dark scheme on the right, split diagonally. It only paints colors the
|
|
1146
|
+
* theme options change (backgrounds, text, borders, the accent) so that a
|
|
1147
|
+
* glance shows what the theme does to the Studio — with few and bold enough
|
|
1148
|
+
* elements to still read when scaled down to a thumbnail.
|
|
975
1149
|
*
|
|
976
1150
|
* @internal
|
|
977
1151
|
*/
|
|
978
|
-
function
|
|
979
|
-
let
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1152
|
+
function ThemePreview(props) {
|
|
1153
|
+
let $ = c(11), { options } = props, t0;
|
|
1154
|
+
$[0] === options ? t0 = $[1] : (t0 = buildTheme(options), $[0] = options, $[1] = t0);
|
|
1155
|
+
let theme = t0, t1;
|
|
1156
|
+
$[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(MockStudio, { scheme: "light" }), $[2] = t1) : t1 = $[2];
|
|
1157
|
+
let t2;
|
|
1158
|
+
$[3] === theme ? t2 = $[4] : (t2 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
1159
|
+
scheme: "light",
|
|
1160
|
+
theme,
|
|
1161
|
+
tone: "default",
|
|
1162
|
+
children: t1
|
|
1163
|
+
}), $[3] = theme, $[4] = t2);
|
|
1164
|
+
let t3;
|
|
1165
|
+
$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(MockStudio, { scheme: "dark" }), $[5] = t3) : t3 = $[5];
|
|
1166
|
+
let t4;
|
|
1167
|
+
$[6] === theme ? t4 = $[7] : (t4 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
1168
|
+
scheme: "dark",
|
|
1169
|
+
theme,
|
|
1170
|
+
tone: "default",
|
|
1171
|
+
children: t3
|
|
1172
|
+
}), $[6] = theme, $[7] = t4);
|
|
1173
|
+
let t5;
|
|
1174
|
+
return $[8] !== t2 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsxs("div", {
|
|
1175
|
+
"aria-hidden": !0,
|
|
1176
|
+
className: root$1,
|
|
1177
|
+
children: [t2, t4]
|
|
1178
|
+
}), $[8] = t2, $[9] = t4, $[10] = t5) : t5 = $[10], t5;
|
|
1179
|
+
}
|
|
1180
|
+
function MockStudio(props) {
|
|
1181
|
+
let $ = c(19), { scheme } = props, { color } = useTheme_v2(), selected = color.selectable.default.selected, inputColor = color.input.default.enabled, t0 = studio[scheme], t1;
|
|
1182
|
+
$[0] !== color.avatar.blue.bg || $[1] !== color.bg || $[2] !== color.border || $[3] !== color.button.default.primary.enabled.bg || $[4] !== color.fg || $[5] !== color.muted.fg || $[6] !== inputColor.bg || $[7] !== inputColor.border || $[8] !== selected.bg || $[9] !== selected.fg ? (t1 = assignInlineVars({
|
|
1183
|
+
[colors.bg]: color.bg,
|
|
1184
|
+
[colors.fg]: color.fg,
|
|
1185
|
+
[colors.mutedFg]: color.muted.fg,
|
|
1186
|
+
[colors.border]: color.border,
|
|
1187
|
+
[colors.accent]: color.button.default.primary.enabled.bg,
|
|
1188
|
+
[colors.avatar]: color.avatar.blue.bg,
|
|
1189
|
+
[colors.selectedBg]: selected.bg,
|
|
1190
|
+
[colors.selectedFg]: selected.fg,
|
|
1191
|
+
[colors.inputBg]: inputColor.bg,
|
|
1192
|
+
[colors.inputBorder]: inputColor.border
|
|
1193
|
+
}), $[0] = color.avatar.blue.bg, $[1] = color.bg, $[2] = color.border, $[3] = color.button.default.primary.enabled.bg, $[4] = color.fg, $[5] = color.muted.fg, $[6] = inputColor.bg, $[7] = inputColor.border, $[8] = selected.bg, $[9] = selected.fg, $[10] = t1) : t1 = $[10];
|
|
1194
|
+
let t2;
|
|
1195
|
+
$[11] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx("div", { className: logo }), $[11] = t2) : t2 = $[11];
|
|
1196
|
+
let t3;
|
|
1197
|
+
$[12] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsxs("div", {
|
|
1198
|
+
className: navbar,
|
|
1199
|
+
children: [
|
|
1200
|
+
t2,
|
|
1201
|
+
/* @__PURE__ */ jsx("div", {
|
|
1202
|
+
className: line.fg,
|
|
1203
|
+
style: { width: "22%" }
|
|
1204
|
+
}),
|
|
1205
|
+
/* @__PURE__ */ jsx("div", { className: spacer }),
|
|
1206
|
+
/* @__PURE__ */ jsx("div", { className: avatar })
|
|
1207
|
+
]
|
|
1208
|
+
}), $[12] = t3) : t3 = $[12];
|
|
1209
|
+
let t4;
|
|
1210
|
+
$[13] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("div", {
|
|
1211
|
+
className: list,
|
|
1212
|
+
children: LIST_ROWS.map(_temp$6)
|
|
1213
|
+
}), $[13] = t4) : t4 = $[13];
|
|
1214
|
+
let t5;
|
|
1215
|
+
$[14] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsxs("div", {
|
|
1216
|
+
className: form,
|
|
1217
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1218
|
+
className: line.fg,
|
|
1219
|
+
style: { width: "45%" }
|
|
1220
|
+
}), FIELDS$1.map(_temp2)]
|
|
1221
|
+
}), $[14] = t5) : t5 = $[14];
|
|
1222
|
+
let t6;
|
|
1223
|
+
$[15] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsxs("div", {
|
|
1224
|
+
className: body,
|
|
1225
|
+
children: [t4, /* @__PURE__ */ jsxs("div", {
|
|
1226
|
+
className: pane,
|
|
1227
|
+
children: [t5, /* @__PURE__ */ jsx("div", {
|
|
1228
|
+
className: footer,
|
|
1229
|
+
children: /* @__PURE__ */ jsx("div", { className: button })
|
|
1230
|
+
})]
|
|
1231
|
+
})]
|
|
1232
|
+
}), $[15] = t6) : t6 = $[15];
|
|
1233
|
+
let t7;
|
|
1234
|
+
return $[16] !== t0 || $[17] !== t1 ? (t7 = /* @__PURE__ */ jsxs("div", {
|
|
1235
|
+
className: t0,
|
|
1236
|
+
style: t1,
|
|
1237
|
+
children: [t3, t6]
|
|
1238
|
+
}), $[16] = t0, $[17] = t1, $[18] = t7) : t7 = $[18], t7;
|
|
1239
|
+
}
|
|
1240
|
+
function _temp2(width_0) {
|
|
1241
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1242
|
+
className: field,
|
|
1243
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1244
|
+
className: line.muted,
|
|
1245
|
+
style: { width: width_0 }
|
|
1246
|
+
}), /* @__PURE__ */ jsx("div", { className: input })]
|
|
1247
|
+
}, width_0);
|
|
1248
|
+
}
|
|
1249
|
+
function _temp$6(width, index) {
|
|
1250
|
+
let isSelected = index === 1;
|
|
1251
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1252
|
+
className: listRow,
|
|
1253
|
+
"data-selected": isSelected,
|
|
1254
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1255
|
+
className: isSelected ? line.selected : line.muted,
|
|
1256
|
+
style: { width }
|
|
1257
|
+
})
|
|
1258
|
+
}, width);
|
|
985
1259
|
}
|
|
986
1260
|
/**
|
|
987
|
-
* The
|
|
988
|
-
*
|
|
1261
|
+
* The floating preview card of a theme: the lo-fi studio mockup on a raised,
|
|
1262
|
+
* rounded card, like the appearance previews in macOS System Settings.
|
|
989
1263
|
*
|
|
990
1264
|
* @internal
|
|
991
1265
|
*/
|
|
992
|
-
function
|
|
993
|
-
let
|
|
994
|
-
return
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
function interest(hex) {
|
|
1001
|
-
let { s, l } = hexToHsl(hex);
|
|
1002
|
-
return .1 + .55 * s + .35 * (1 - Math.abs(l - .5) * 2);
|
|
1266
|
+
function ThemeThumbnail(props) {
|
|
1267
|
+
let $ = c(2), t0;
|
|
1268
|
+
return $[0] === props.options ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Card, {
|
|
1269
|
+
overflow: "hidden",
|
|
1270
|
+
radius: 3,
|
|
1271
|
+
shadow: 1,
|
|
1272
|
+
children: /* @__PURE__ */ jsx(ThemePreview, { options: props.options })
|
|
1273
|
+
}), $[0] = props.options, $[1] = t0), t0;
|
|
1003
1274
|
}
|
|
1275
|
+
var removedThumbnail = "_1vdkp0v0";
|
|
1004
1276
|
/**
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1277
|
+
* The flow for restoring removed themes: the presets and custom themes the
|
|
1278
|
+
* user took out of the list, each with a button to put it back — and, for
|
|
1279
|
+
* custom themes, one to delete it for good. The machine leaves the flow once
|
|
1280
|
+
* the last one is gone.
|
|
1008
1281
|
*
|
|
1009
1282
|
* @internal
|
|
1010
1283
|
*/
|
|
1011
|
-
function
|
|
1012
|
-
let
|
|
1013
|
-
if (
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1284
|
+
function RemovedThemes() {
|
|
1285
|
+
let $ = c(7), { removed, send } = useThemer(), t0;
|
|
1286
|
+
if ($[0] !== removed || $[1] !== send) {
|
|
1287
|
+
let t1;
|
|
1288
|
+
$[3] === send ? t1 = $[4] : (t1 = (theme) => /* @__PURE__ */ jsxs(Stack, {
|
|
1289
|
+
gap: 3,
|
|
1290
|
+
children: [
|
|
1291
|
+
/* @__PURE__ */ jsx(Box, {
|
|
1292
|
+
className: removedThumbnail,
|
|
1293
|
+
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
|
|
1294
|
+
}),
|
|
1295
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1296
|
+
align: "center",
|
|
1297
|
+
size: 1,
|
|
1298
|
+
textOverflow: "ellipsis",
|
|
1299
|
+
children: displayTitle(theme.title)
|
|
1300
|
+
}),
|
|
1301
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
1302
|
+
gap: 2,
|
|
1303
|
+
justify: "center",
|
|
1304
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
1305
|
+
mode: "ghost",
|
|
1306
|
+
onClick: () => send({
|
|
1307
|
+
type: "theme.restore",
|
|
1308
|
+
slug: theme.slug
|
|
1309
|
+
}),
|
|
1310
|
+
padding: 2,
|
|
1311
|
+
text: "Restore"
|
|
1312
|
+
}), theme.source === "custom" && /* @__PURE__ */ jsx(Button, {
|
|
1313
|
+
mode: "ghost",
|
|
1314
|
+
onClick: () => send({
|
|
1315
|
+
type: "theme.delete",
|
|
1316
|
+
slug: theme.slug
|
|
1317
|
+
}),
|
|
1318
|
+
padding: 2,
|
|
1319
|
+
text: "Delete",
|
|
1320
|
+
tone: "critical"
|
|
1321
|
+
})]
|
|
1322
|
+
})
|
|
1323
|
+
]
|
|
1324
|
+
}, theme.slug), $[3] = send, $[4] = t1), t0 = removed.map(t1), $[0] = removed, $[1] = send, $[2] = t0;
|
|
1325
|
+
} else t0 = $[2];
|
|
1326
|
+
let t1;
|
|
1327
|
+
return $[5] === t0 ? t1 = $[6] : (t1 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
1328
|
+
padding: 3,
|
|
1329
|
+
children: /* @__PURE__ */ jsx(Stack, {
|
|
1330
|
+
gap: 5,
|
|
1331
|
+
children: t0
|
|
1332
|
+
})
|
|
1333
|
+
}), $[5] = t0, $[6] = t1), t1;
|
|
1021
1334
|
}
|
|
1022
1335
|
/**
|
|
1023
|
-
* A button with an animated tooltip instead of a `title` attribute
|
|
1024
|
-
* buttons
|
|
1336
|
+
* A button with an animated tooltip instead of a `title` attribute, sized like
|
|
1337
|
+
* the Studio's own buttons (`padding` and `gap` of 2). Icon-only buttons take
|
|
1338
|
+
* the tooltip as their accessible name.
|
|
1025
1339
|
*
|
|
1026
1340
|
* @internal
|
|
1027
1341
|
*/
|
|
@@ -1036,6 +1350,8 @@ function TooltipButton(props) {
|
|
|
1036
1350
|
let t1 = buttonProps.text === void 0 ? tooltip : void 0, t2;
|
|
1037
1351
|
$[5] !== buttonProps || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(Button, {
|
|
1038
1352
|
"aria-label": t1,
|
|
1353
|
+
gap: 2,
|
|
1354
|
+
padding: 2,
|
|
1039
1355
|
...buttonProps
|
|
1040
1356
|
}), $[5] = buttonProps, $[6] = t1, $[7] = t2) : t2 = $[7];
|
|
1041
1357
|
let t3;
|
|
@@ -1135,7 +1451,7 @@ function useImagePalette(onPalette) {
|
|
|
1135
1451
|
setBusy(!0);
|
|
1136
1452
|
let isCurrent = () => mountedRef.current && latestPickRef.current === pick, extract = async () => {
|
|
1137
1453
|
let palette = extractImagePalette(await readImagePixels(file));
|
|
1138
|
-
isCurrent() && (Object.values(palette).every(_temp$
|
|
1454
|
+
isCurrent() && (Object.values(palette).every(_temp$5) ? toast.push({
|
|
1139
1455
|
status: "warning",
|
|
1140
1456
|
title: "Found no colors in that image"
|
|
1141
1457
|
}) : onPaletteRef.current(palette, file));
|
|
@@ -1155,9 +1471,10 @@ function useImagePalette(onPalette) {
|
|
|
1155
1471
|
pickImage
|
|
1156
1472
|
}, $[7] = busy, $[8] = pickImage, $[9] = t5) : t5 = $[9], t5;
|
|
1157
1473
|
}
|
|
1158
|
-
function _temp$
|
|
1474
|
+
function _temp$5(swatch) {
|
|
1159
1475
|
return swatch === null;
|
|
1160
1476
|
}
|
|
1477
|
+
var paletteGrid = "_17s80v42", tile = "_17s80v44", variantButton = "_17s80v46", variantFrame = "_17s80v47", variantRow = "_17s80v45", variantScale = "var(--_17s80v41)", variantScaleBox = "_17s80v48", variantWidth = "var(--_17s80v40)";
|
|
1161
1478
|
/** The swatches on display: the vibrant family over the muted one */
|
|
1162
1479
|
const TILES = [
|
|
1163
1480
|
"vibrant",
|
|
@@ -1166,28 +1483,7 @@ const TILES = [
|
|
|
1166
1483
|
"muted",
|
|
1167
1484
|
"lightMuted",
|
|
1168
1485
|
"darkMuted"
|
|
1169
|
-
]
|
|
1170
|
-
displayName: "PaletteGrid",
|
|
1171
|
-
componentId: "sc-j2tqre-0"
|
|
1172
|
-
})`display:grid;grid-template-columns:repeat(3,${24}px);grid-auto-rows:${24}px;gap:${4}px;&[data-with-image='true']{grid-template-columns:${52}px repeat(3,${24}px);}`, ImageTile = styled.img.withConfig({
|
|
1173
|
-
displayName: "ImageTile",
|
|
1174
|
-
componentId: "sc-j2tqre-1"
|
|
1175
|
-
})`display:block;grid-row:span 2;width:${52}px;height:${52}px;border-radius:3px;object-fit:cover;box-shadow:inset 0 0 0 1px var(--card-border-color);`, Tile = styled.span.withConfig({
|
|
1176
|
-
displayName: "Tile",
|
|
1177
|
-
componentId: "sc-j2tqre-2"
|
|
1178
|
-
})`display:block;border-radius:3px;box-shadow:inset 0 0 0 1px var(--card-border-color);&[data-empty='true']{background:repeating-linear-gradient( -45deg,transparent 0 3px,var(--card-border-color) 3px 4px );}`, VariantRow = styled.div.withConfig({
|
|
1179
|
-
displayName: "VariantRow",
|
|
1180
|
-
componentId: "sc-j2tqre-3"
|
|
1181
|
-
})`display:flex;gap:${8}px;margin:0 -${12}px;padding:0 ${12}px;overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-left:${12}px;scrollbar-width:thin;`, VariantButton = styled.button.withConfig({
|
|
1182
|
-
displayName: "VariantButton",
|
|
1183
|
-
componentId: "sc-j2tqre-4"
|
|
1184
|
-
})`appearance:none;flex:none;display:block;box-sizing:border-box;width:calc(var(--variant-width) + 8px);margin:0;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:center;cursor:pointer;scroll-snap-align:start;&:focus{outline:none;}`, VariantFrame = styled.span.withConfig({
|
|
1185
|
-
displayName: "VariantFrame",
|
|
1186
|
-
componentId: "sc-j2tqre-5"
|
|
1187
|
-
})`display:block;box-sizing:border-box;width:calc(var(--variant-width) + 8px);height:calc(var(--variant-width) * 9 / 16 + 8px);padding:4px;border-radius:7px;overflow:hidden;transition:box-shadow 100ms;${VariantButton}:hover &{box-shadow:inset 0 0 0 2px var(--card-border-color);}${VariantButton}[aria-pressed='true'] &{box-shadow:inset 0 0 0 2px var(--card-focus-ring-color);}${VariantButton}:focus-visible &{outline:2px solid var(--card-focus-ring-color);outline-offset:-2px;}`, VariantScale = styled.span.withConfig({
|
|
1188
|
-
displayName: "VariantScale",
|
|
1189
|
-
componentId: "sc-j2tqre-6"
|
|
1190
|
-
})`display:block;width:${144}px;transform:scale(var(--variant-scale));transform-origin:top left;`;
|
|
1486
|
+
];
|
|
1191
1487
|
/**
|
|
1192
1488
|
* Takes the colors of a theme from an image, on device: the image is read
|
|
1193
1489
|
* into a canvas and its palette extracted right there — nothing is uploaded.
|
|
@@ -1200,13 +1496,13 @@ const TILES = [
|
|
|
1200
1496
|
function ImagePaletteSection(props) {
|
|
1201
1497
|
let $ = c(38), { imageUrl, onPalette, onVariant, onLucky, options, palette } = props, { busy, pickImage } = useImagePalette(onPalette), [dragging, setDragging] = useState(!1), dragDepth = useRef(0), t0;
|
|
1202
1498
|
$[0] !== options || $[1] !== palette ? (t0 = palette ? currentImageVariant(options, palette) : null, $[0] = options, $[1] = palette, $[2] = t0) : t0 = $[2];
|
|
1203
|
-
let current = t0, rowRef = useRef(null), [
|
|
1499
|
+
let current = t0, rowRef = useRef(null), [thumbnailWidth, setThumbnailWidth] = useState(58), t1;
|
|
1204
1500
|
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
|
|
1205
1501
|
let row = rowRef.current;
|
|
1206
1502
|
if (!row) return;
|
|
1207
1503
|
let measure = () => {
|
|
1208
1504
|
let visible = row.clientWidth - 12 - 16;
|
|
1209
|
-
|
|
1505
|
+
setThumbnailWidth(Math.max(24, Math.floor(visible / 2.5) - 8));
|
|
1210
1506
|
};
|
|
1211
1507
|
measure();
|
|
1212
1508
|
let observer = new ResizeObserver(measure);
|
|
@@ -1224,6 +1520,7 @@ function ImagePaletteSection(props) {
|
|
|
1224
1520
|
let t4;
|
|
1225
1521
|
$[7] !== options || $[8] !== palette ? (t4 = IMAGE_PALETTE_VARIANTS.flatMap((variant) => palette[variant] === null ? [] : [{
|
|
1226
1522
|
variant,
|
|
1523
|
+
title: IMAGE_PALETTE_TITLES[variant],
|
|
1227
1524
|
options: applyImagePalette(options, palette, variant)
|
|
1228
1525
|
}]), $[7] = options, $[8] = palette, $[9] = t4) : t4 = $[9], t3 = t4;
|
|
1229
1526
|
}
|
|
@@ -1263,11 +1560,13 @@ function ImagePaletteSection(props) {
|
|
|
1263
1560
|
children: [t8, t9]
|
|
1264
1561
|
}), $[19] = t9, $[20] = t10);
|
|
1265
1562
|
let t11;
|
|
1266
|
-
$[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !==
|
|
1267
|
-
/* @__PURE__ */ jsxs(
|
|
1563
|
+
$[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !== thumbnailWidth || $[29] !== variants ? (t11 = palette ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1564
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1565
|
+
className: paletteGrid,
|
|
1268
1566
|
"data-with-image": imageUrl !== void 0,
|
|
1269
|
-
children: [imageUrl && /* @__PURE__ */ jsx(
|
|
1567
|
+
children: [imageUrl && /* @__PURE__ */ jsx("img", {
|
|
1270
1568
|
alt: "",
|
|
1569
|
+
className: "_17s80v43",
|
|
1271
1570
|
src: imageUrl
|
|
1272
1571
|
}), TILES.map((key) => {
|
|
1273
1572
|
let hex = palette[key], title = IMAGE_PALETTE_TITLES[key];
|
|
@@ -1279,7 +1578,8 @@ function ImagePaletteSection(props) {
|
|
|
1279
1578
|
}),
|
|
1280
1579
|
placement: "bottom",
|
|
1281
1580
|
portal: !0,
|
|
1282
|
-
children: /* @__PURE__ */ jsx(
|
|
1581
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1582
|
+
className: tile,
|
|
1283
1583
|
"data-empty": hex === null,
|
|
1284
1584
|
style: { background: hex ?? void 0 }
|
|
1285
1585
|
})
|
|
@@ -1292,26 +1592,37 @@ function ImagePaletteSection(props) {
|
|
|
1292
1592
|
muted: !0,
|
|
1293
1593
|
size: 0,
|
|
1294
1594
|
children: "Pick the swatch to build the theme around"
|
|
1295
|
-
}), /* @__PURE__ */ jsx(
|
|
1595
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1596
|
+
className: variantRow,
|
|
1296
1597
|
ref: rowRef,
|
|
1297
|
-
style: {
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
},
|
|
1598
|
+
style: assignInlineVars({
|
|
1599
|
+
[variantWidth]: `${thumbnailWidth}px`,
|
|
1600
|
+
[variantScale]: String(thumbnailWidth / 144)
|
|
1601
|
+
}),
|
|
1301
1602
|
children: variants.map((t12) => {
|
|
1302
|
-
let { variant: variant_0, options: variantOptions } = t12;
|
|
1303
|
-
return /* @__PURE__ */ jsxs(
|
|
1603
|
+
let { variant: variant_0, title: title_0, options: variantOptions } = t12;
|
|
1604
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
1304
1605
|
"aria-pressed": variant_0 === current,
|
|
1606
|
+
className: variantButton,
|
|
1305
1607
|
onClick: () => onVariant(variant_0),
|
|
1306
1608
|
type: "button",
|
|
1307
|
-
children: [/* @__PURE__ */ jsx(
|
|
1609
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1610
|
+
className: variantFrame,
|
|
1611
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1612
|
+
className: variantScaleBox,
|
|
1613
|
+
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: variantOptions })
|
|
1614
|
+
})
|
|
1615
|
+
}), /* @__PURE__ */ jsx(Box, {
|
|
1616
|
+
as: "span",
|
|
1617
|
+
display: "block",
|
|
1308
1618
|
paddingTop: 1,
|
|
1309
1619
|
children: /* @__PURE__ */ jsx(Text, {
|
|
1310
1620
|
align: "center",
|
|
1621
|
+
as: "span",
|
|
1311
1622
|
size: 0,
|
|
1312
1623
|
textOverflow: "ellipsis",
|
|
1313
1624
|
weight: variant_0 === current ? "medium" : "regular",
|
|
1314
|
-
children:
|
|
1625
|
+
children: title_0
|
|
1315
1626
|
})
|
|
1316
1627
|
})]
|
|
1317
1628
|
}, variant_0);
|
|
@@ -1340,7 +1651,7 @@ function ImagePaletteSection(props) {
|
|
|
1340
1651
|
tooltip: "Take the colors from an image on your device",
|
|
1341
1652
|
width: "fill"
|
|
1342
1653
|
})]
|
|
1343
|
-
}), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] =
|
|
1654
|
+
}), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] = thumbnailWidth, $[29] = variants, $[30] = t11) : t11 = $[30];
|
|
1344
1655
|
let t12;
|
|
1345
1656
|
$[31] !== t10 || $[32] !== t11 ? (t12 = /* @__PURE__ */ jsxs(Stack, {
|
|
1346
1657
|
gap: 3,
|
|
@@ -1351,7 +1662,7 @@ function ImagePaletteSection(props) {
|
|
|
1351
1662
|
border: !0,
|
|
1352
1663
|
onDragEnter: t4,
|
|
1353
1664
|
onDragLeave: t5,
|
|
1354
|
-
onDragOver: _temp$
|
|
1665
|
+
onDragOver: _temp$4,
|
|
1355
1666
|
onDrop: t6,
|
|
1356
1667
|
padding: 3,
|
|
1357
1668
|
radius: 3,
|
|
@@ -1359,27 +1670,33 @@ function ImagePaletteSection(props) {
|
|
|
1359
1670
|
children: t12
|
|
1360
1671
|
}), $[34] = t12, $[35] = t6, $[36] = t7, $[37] = t13) : t13 = $[37], t13;
|
|
1361
1672
|
}
|
|
1362
|
-
function _temp$
|
|
1673
|
+
function _temp$4(event_0) {
|
|
1363
1674
|
event_0.preventDefault();
|
|
1364
1675
|
}
|
|
1676
|
+
var colorRowText = "os3rj2", range = "os3rj1", swatch = "os3rj0";
|
|
1365
1677
|
const SCHEME_TITLES = {
|
|
1366
1678
|
dark: "Dark mode",
|
|
1367
1679
|
light: "Light mode"
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1680
|
+
};
|
|
1681
|
+
/**
|
|
1682
|
+
* Where the split preview shows a scheme: the Studio's own scheme stays next
|
|
1683
|
+
* to the sidebar (or at the bottom, stacked on small screens), the other one
|
|
1684
|
+
* takes the far side
|
|
1685
|
+
*/
|
|
1686
|
+
function splitHint(own, mobile) {
|
|
1687
|
+
return mobile ? own ? "Shown at the bottom" : "Shown at the top" : own ? "Shown on the right, next to the themer" : "Shown on the left";
|
|
1688
|
+
}
|
|
1689
|
+
const SCHEME_OPTION_KEYS = [
|
|
1372
1690
|
"accent",
|
|
1373
1691
|
"text",
|
|
1374
1692
|
"background",
|
|
1375
1693
|
"contrast"
|
|
1376
|
-
]
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
})`display:block;width:100%;margin:0;accent-color:var(--card-focus-ring-color);`;
|
|
1694
|
+
];
|
|
1695
|
+
/**
|
|
1696
|
+
* `<input type="color">` paints the color into a shadow-DOM swatch that brings
|
|
1697
|
+
* its own border and padding, which then sits inside ours as a second border.
|
|
1698
|
+
* Stripping that chrome leaves the themed border as the only one.
|
|
1699
|
+
*/
|
|
1383
1700
|
/**
|
|
1384
1701
|
* The flow for editing one of the user's own themes: its title, a live
|
|
1385
1702
|
* preview, and a card per color scheme with the accent/text/background
|
|
@@ -1390,7 +1707,7 @@ const SCHEME_TITLES = {
|
|
|
1390
1707
|
* @internal
|
|
1391
1708
|
*/
|
|
1392
1709
|
function ThemeEditor(props) {
|
|
1393
|
-
let $ = c(
|
|
1710
|
+
let $ = c(42), { focusTitle, slug } = props, { themes, images, split, mobile, send } = useThemer(), t0;
|
|
1394
1711
|
if ($[0] !== slug || $[1] !== themes) {
|
|
1395
1712
|
let t1;
|
|
1396
1713
|
$[3] === slug ? t1 = $[4] : (t1 = (candidate) => candidate.slug === slug && candidate.source === "custom", $[3] = slug, $[4] = t1), t0 = themes.find(t1), $[0] = slug, $[1] = themes, $[2] = t0;
|
|
@@ -1435,7 +1752,7 @@ function ThemeEditor(props) {
|
|
|
1435
1752
|
title
|
|
1436
1753
|
}), $[23] = send, $[24] = slug, $[25] = t7, $[26] = t8) : (t7 = $[25], t8 = $[26]);
|
|
1437
1754
|
let t9;
|
|
1438
|
-
return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !==
|
|
1755
|
+
return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !== mobile || $[30] !== split || $[31] !== t2 || $[32] !== t3 || $[33] !== t4 || $[34] !== t5 || $[35] !== t6 || $[36] !== t7 || $[37] !== t8 || $[38] !== theme.options || $[39] !== theme.palette || $[40] !== theme.title ? (t9 = /* @__PURE__ */ jsx(ThemeEditorForm, {
|
|
1439
1756
|
focusTitle,
|
|
1440
1757
|
imageUrl: t2,
|
|
1441
1758
|
onDone: t3,
|
|
@@ -1448,11 +1765,12 @@ function ThemeEditor(props) {
|
|
|
1448
1765
|
options: theme.options,
|
|
1449
1766
|
palette: theme.palette,
|
|
1450
1767
|
split,
|
|
1768
|
+
mobile,
|
|
1451
1769
|
title: theme.title
|
|
1452
|
-
}), $[27] = applyVariant, $[28] = focusTitle, $[29] =
|
|
1770
|
+
}), $[27] = applyVariant, $[28] = focusTitle, $[29] = mobile, $[30] = split, $[31] = t2, $[32] = t3, $[33] = t4, $[34] = t5, $[35] = t6, $[36] = t7, $[37] = t8, $[38] = theme.options, $[39] = theme.palette, $[40] = theme.title, $[41] = t9) : t9 = $[41], t9;
|
|
1453
1771
|
}
|
|
1454
1772
|
function ThemeEditorForm(props) {
|
|
1455
|
-
let $ = c(
|
|
1773
|
+
let $ = c(50), { focusTitle, imageUrl, onDone, onLucky, onOptionsChange, onPalette, onRemove, onTitleChange, onVariant, options, palette, split, mobile, title } = props, studioScheme = useColorSchemeValue(), t0;
|
|
1456
1774
|
$[0] === options ? t0 = $[1] : (t0 = resolveThemeOptions(options), $[0] = options, $[1] = t0);
|
|
1457
1775
|
let resolved = t0, t1;
|
|
1458
1776
|
$[2] === options ? t1 = $[3] : (t1 = buildPalette(options), $[2] = options, $[3] = t1);
|
|
@@ -1476,7 +1794,7 @@ function ThemeEditorForm(props) {
|
|
|
1476
1794
|
}), $[9] = t4) : t4 = $[9];
|
|
1477
1795
|
let t5;
|
|
1478
1796
|
$[10] === onTitleChange ? t5 = $[11] : (t5 = (event) => onTitleChange(event.currentTarget.value), $[10] = onTitleChange, $[11] = t5);
|
|
1479
|
-
let t6 = focusTitle ? _temp$
|
|
1797
|
+
let t6 = focusTitle ? _temp$3 : void 0, t7;
|
|
1480
1798
|
$[12] !== focusTitle || $[13] !== t5 || $[14] !== t6 || $[15] !== title ? (t7 = /* @__PURE__ */ jsxs(Stack, {
|
|
1481
1799
|
gap: 2,
|
|
1482
1800
|
children: [t4, /* @__PURE__ */ jsx(TextInput, {
|
|
@@ -1499,19 +1817,20 @@ function ThemeEditorForm(props) {
|
|
|
1499
1817
|
palette
|
|
1500
1818
|
}), $[17] = imageUrl, $[18] = onLucky, $[19] = onPalette, $[20] = onVariant, $[21] = options, $[22] = palette, $[23] = t8) : t8 = $[23];
|
|
1501
1819
|
let t9;
|
|
1502
|
-
$[24] !==
|
|
1820
|
+
$[24] !== mobile || $[25] !== options || $[26] !== palettes || $[27] !== patchScheme || $[28] !== resolved || $[29] !== split || $[30] !== studioScheme ? (t9 = SCHEMES.map((scheme_0) => /* @__PURE__ */ jsx(SchemeCard, {
|
|
1503
1821
|
active: split || scheme_0 === studioScheme,
|
|
1504
1822
|
onChange: (changes_0) => patchScheme(scheme_0, changes_0),
|
|
1505
1823
|
options: options[scheme_0] ?? {},
|
|
1506
1824
|
palette: palettes[scheme_0],
|
|
1507
1825
|
resolved: resolved[scheme_0],
|
|
1508
1826
|
scheme: scheme_0,
|
|
1509
|
-
split
|
|
1510
|
-
|
|
1827
|
+
split,
|
|
1828
|
+
splitHint: splitHint(scheme_0 === studioScheme, mobile)
|
|
1829
|
+
}, scheme_0)), $[24] = mobile, $[25] = options, $[26] = palettes, $[27] = patchScheme, $[28] = resolved, $[29] = split, $[30] = studioScheme, $[31] = t9) : t9 = $[31];
|
|
1511
1830
|
let t10;
|
|
1512
|
-
$[
|
|
1831
|
+
$[32] === t9 ? t10 = $[33] : (t10 = /* @__PURE__ */ jsx(ScrollAreaBleed, { children: t9 }), $[32] = t9, $[33] = t10);
|
|
1513
1832
|
let t11;
|
|
1514
|
-
$[
|
|
1833
|
+
$[34] !== t10 || $[35] !== t3 || $[36] !== t7 || $[37] !== t8 ? (t11 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
1515
1834
|
padding: 3,
|
|
1516
1835
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1517
1836
|
gap: 4,
|
|
@@ -1522,26 +1841,27 @@ function ThemeEditorForm(props) {
|
|
|
1522
1841
|
t10
|
|
1523
1842
|
]
|
|
1524
1843
|
})
|
|
1525
|
-
}), $[
|
|
1844
|
+
}), $[34] = t10, $[35] = t3, $[36] = t7, $[37] = t8, $[38] = t11) : t11 = $[38];
|
|
1526
1845
|
let t12;
|
|
1527
|
-
$[
|
|
1846
|
+
$[39] === onRemove ? t12 = $[40] : (t12 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
1528
1847
|
icon: TrashIcon,
|
|
1529
1848
|
mode: "ghost",
|
|
1530
1849
|
onClick: onRemove,
|
|
1531
1850
|
text: "Remove",
|
|
1532
1851
|
tone: "critical",
|
|
1533
1852
|
tooltip: "Remove the theme — it can be restored until it is deleted"
|
|
1534
|
-
}), $[
|
|
1853
|
+
}), $[39] = onRemove, $[40] = t12);
|
|
1535
1854
|
let t13;
|
|
1536
|
-
$[
|
|
1855
|
+
$[41] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Box, { flex: 1 }), $[41] = t13) : t13 = $[41];
|
|
1537
1856
|
let t14;
|
|
1538
|
-
$[
|
|
1857
|
+
$[42] === onDone ? t14 = $[43] : (t14 = /* @__PURE__ */ jsx(Button, {
|
|
1539
1858
|
mode: "ghost",
|
|
1540
1859
|
onClick: onDone,
|
|
1860
|
+
padding: 2,
|
|
1541
1861
|
text: "Done"
|
|
1542
|
-
}), $[
|
|
1862
|
+
}), $[42] = onDone, $[43] = t14);
|
|
1543
1863
|
let t15;
|
|
1544
|
-
$[
|
|
1864
|
+
$[44] !== t12 || $[45] !== t14 ? (t15 = /* @__PURE__ */ jsx(Card, {
|
|
1545
1865
|
borderTop: !0,
|
|
1546
1866
|
padding: 3,
|
|
1547
1867
|
children: /* @__PURE__ */ jsxs(Flex, {
|
|
@@ -1552,11 +1872,11 @@ function ThemeEditorForm(props) {
|
|
|
1552
1872
|
t14
|
|
1553
1873
|
]
|
|
1554
1874
|
})
|
|
1555
|
-
}), $[
|
|
1875
|
+
}), $[44] = t12, $[45] = t14, $[46] = t15) : t15 = $[46];
|
|
1556
1876
|
let t16;
|
|
1557
|
-
return $[
|
|
1877
|
+
return $[47] !== t11 || $[48] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Fragment, { children: [t11, t15] }), $[47] = t11, $[48] = t15, $[49] = t16) : t16 = $[49], t16;
|
|
1558
1878
|
}
|
|
1559
|
-
function _temp$
|
|
1879
|
+
function _temp$3(event_0) {
|
|
1560
1880
|
return event_0.currentTarget.select();
|
|
1561
1881
|
}
|
|
1562
1882
|
/**
|
|
@@ -1568,7 +1888,7 @@ function _temp$1(event_0) {
|
|
|
1568
1888
|
* active, in the split preview.
|
|
1569
1889
|
*/
|
|
1570
1890
|
function SchemeCard(props) {
|
|
1571
|
-
let $ = c(66), { active, onChange, options, palette, resolved, scheme, split } = props, name = SCHEME_TITLES[scheme], t0;
|
|
1891
|
+
let $ = c(66), { active, onChange, options, palette, resolved, scheme, split, splitHint } = props, name = SCHEME_TITLES[scheme], t0;
|
|
1572
1892
|
$[0] === name ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Box, {
|
|
1573
1893
|
flex: 1,
|
|
1574
1894
|
children: /* @__PURE__ */ jsx(Text, {
|
|
@@ -1589,7 +1909,7 @@ function SchemeCard(props) {
|
|
|
1589
1909
|
gap: 2,
|
|
1590
1910
|
children: [t0, t1]
|
|
1591
1911
|
}), $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
|
|
1592
|
-
let t3 = split ?
|
|
1912
|
+
let t3 = split ? splitHint : active ? "Shown in the Studio right now" : `Shown once the Studio appearance is ${scheme}`, t4;
|
|
1593
1913
|
$[7] === t3 ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
1594
1914
|
muted: !0,
|
|
1595
1915
|
size: 0,
|
|
@@ -1667,8 +1987,9 @@ function SchemeCard(props) {
|
|
|
1667
1987
|
let t27 = `${name} contrast`, t28;
|
|
1668
1988
|
$[50] === onChange ? t28 = $[51] : (t28 = (event) => onChange({ contrast: Number(event.currentTarget.value) }), $[50] = onChange, $[51] = t28);
|
|
1669
1989
|
let t29;
|
|
1670
|
-
$[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx(
|
|
1990
|
+
$[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx("input", {
|
|
1671
1991
|
"aria-label": t27,
|
|
1992
|
+
className: range,
|
|
1672
1993
|
max: 100,
|
|
1673
1994
|
min: 15,
|
|
1674
1995
|
onChange: t28,
|
|
@@ -1709,92 +2030,411 @@ function SchemeCard(props) {
|
|
|
1709
2030
|
}
|
|
1710
2031
|
/** One color of a scheme: a swatch with its value and an optional reset button */
|
|
1711
2032
|
function ColorRow(props) {
|
|
1712
|
-
let $ = c(
|
|
2033
|
+
let $ = c(23), { adjusted, auto, autoLabel: t0, label, onChange, onClear, title, value } = props, autoLabel = t0 === void 0 ? "auto" : t0, t1;
|
|
1713
2034
|
$[0] === onChange ? t1 = $[1] : (t1 = (event) => onChange(event.currentTarget.value), $[0] = onChange, $[1] = t1);
|
|
1714
2035
|
let t2;
|
|
1715
|
-
$[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx(
|
|
2036
|
+
$[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx("input", {
|
|
1716
2037
|
"aria-label": label,
|
|
2038
|
+
className: swatch,
|
|
1717
2039
|
onChange: t1,
|
|
1718
2040
|
type: "color",
|
|
1719
2041
|
value
|
|
1720
2042
|
}), $[2] = label, $[3] = t1, $[4] = value, $[5] = t2) : t2 = $[5];
|
|
1721
2043
|
let t3;
|
|
1722
|
-
$[6] ===
|
|
1723
|
-
let t4;
|
|
1724
|
-
$[7] === title ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
2044
|
+
$[6] === title ? t3 = $[7] : (t3 = /* @__PURE__ */ jsx(Text, {
|
|
1725
2045
|
size: 1,
|
|
1726
2046
|
children: title
|
|
1727
|
-
}), $[
|
|
1728
|
-
let
|
|
1729
|
-
$[
|
|
2047
|
+
}), $[6] = title, $[7] = t3);
|
|
2048
|
+
let t4 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t5 = auto ? ` · ${autoLabel}` : "", t6;
|
|
2049
|
+
$[8] !== t4 || $[9] !== t5 || $[10] !== value ? (t6 = /* @__PURE__ */ jsxs(Text, {
|
|
1730
2050
|
muted: !0,
|
|
1731
2051
|
size: 0,
|
|
1732
2052
|
textOverflow: "ellipsis",
|
|
1733
2053
|
children: [
|
|
1734
2054
|
value,
|
|
1735
|
-
|
|
1736
|
-
|
|
2055
|
+
t4,
|
|
2056
|
+
t5
|
|
1737
2057
|
]
|
|
1738
|
-
}), $[
|
|
1739
|
-
let
|
|
1740
|
-
$[
|
|
2058
|
+
}), $[8] = t4, $[9] = t5, $[10] = value, $[11] = t6) : t6 = $[11];
|
|
2059
|
+
let t7;
|
|
2060
|
+
$[12] !== t3 || $[13] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Stack, {
|
|
2061
|
+
className: colorRowText,
|
|
1741
2062
|
flex: 1,
|
|
1742
2063
|
gap: 2,
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
$[16] !== auto || $[17] !== autoLabel || $[18] !== onClear ? (t9 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
|
|
2064
|
+
children: [t3, t6]
|
|
2065
|
+
}), $[12] = t3, $[13] = t6, $[14] = t7) : t7 = $[14];
|
|
2066
|
+
let t8;
|
|
2067
|
+
$[15] !== auto || $[16] !== autoLabel || $[17] !== onClear ? (t8 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
|
|
1748
2068
|
icon: ResetIcon,
|
|
1749
2069
|
mode: "bleed",
|
|
1750
2070
|
onClick: onClear,
|
|
1751
2071
|
padding: 2,
|
|
1752
2072
|
tooltip: `Reset to ${autoLabel}`
|
|
1753
|
-
}), $[
|
|
1754
|
-
let
|
|
1755
|
-
return $[
|
|
2073
|
+
}), $[15] = auto, $[16] = autoLabel, $[17] = onClear, $[18] = t8) : t8 = $[18];
|
|
2074
|
+
let t9;
|
|
2075
|
+
return $[19] !== t2 || $[20] !== t7 || $[21] !== t8 ? (t9 = /* @__PURE__ */ jsxs(Flex, {
|
|
1756
2076
|
align: "center",
|
|
1757
2077
|
gap: 2,
|
|
1758
2078
|
children: [
|
|
1759
|
-
t2,
|
|
1760
|
-
|
|
1761
|
-
|
|
2079
|
+
t2,
|
|
2080
|
+
t7,
|
|
2081
|
+
t8
|
|
2082
|
+
]
|
|
2083
|
+
}), $[19] = t2, $[20] = t7, $[21] = t8, $[22] = t9) : t9 = $[22], t9;
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* The version of the code format, the first byte of every code — bumped if
|
|
2087
|
+
* the layout below ever changes, so older codes can still be told apart
|
|
2088
|
+
*/
|
|
2089
|
+
const FIELDS = [
|
|
2090
|
+
"accent",
|
|
2091
|
+
"text",
|
|
2092
|
+
"background",
|
|
2093
|
+
"contrast"
|
|
2094
|
+
];
|
|
2095
|
+
/**
|
|
2096
|
+
* Turns a theme into a short code to share in a message: `title`, and the
|
|
2097
|
+
* colors and contrasts of both schemes, packed into bytes — one flag byte says
|
|
2098
|
+
* which of the eight fields are set, each color is its three RGB bytes and a
|
|
2099
|
+
* contrast one byte, and the title takes up the rest — then base64url'd, so
|
|
2100
|
+
* it is one word without padding, safe in URLs and chat. A theme setting
|
|
2101
|
+
* everything comes to about 30 bytes plus its title.
|
|
2102
|
+
*
|
|
2103
|
+
* @internal
|
|
2104
|
+
*/
|
|
2105
|
+
function encodeTheme(theme) {
|
|
2106
|
+
let bytes = [1, 0], flags = 0;
|
|
2107
|
+
return SCHEMES.forEach((scheme, schemeIndex) => {
|
|
2108
|
+
let options = theme.options[scheme] ?? {};
|
|
2109
|
+
FIELDS.forEach((field, fieldIndex) => {
|
|
2110
|
+
let value = options[field];
|
|
2111
|
+
if (value !== void 0) {
|
|
2112
|
+
if (field === "contrast") {
|
|
2113
|
+
if (typeof value != "number" || !Number.isFinite(value)) return;
|
|
2114
|
+
bytes.push(Math.round(Math.min(100, Math.max(15, value))));
|
|
2115
|
+
} else {
|
|
2116
|
+
if (typeof value != "string" || !isColor(value)) return;
|
|
2117
|
+
bytes.push(...rgbBytes(value));
|
|
2118
|
+
}
|
|
2119
|
+
flags |= 1 << schemeIndex * FIELDS.length + fieldIndex;
|
|
2120
|
+
}
|
|
2121
|
+
});
|
|
2122
|
+
}), bytes[1] = flags, bytes.push(...new TextEncoder().encode(theme.title.trim())), toBase64Url(Uint8Array.from(bytes));
|
|
2123
|
+
}
|
|
2124
|
+
/**
|
|
2125
|
+
* Reads a theme back out of a code — as pasted, so surrounding whitespace and
|
|
2126
|
+
* words around the code are fine: the first word that is a code counts. `null`
|
|
2127
|
+
* when nothing in the text is one.
|
|
2128
|
+
*
|
|
2129
|
+
* @internal
|
|
2130
|
+
*/
|
|
2131
|
+
function decodeTheme(text) {
|
|
2132
|
+
for (let word of text.trim().split(/\s+/)) {
|
|
2133
|
+
let theme = decodeCode(word);
|
|
2134
|
+
if (theme) return theme;
|
|
2135
|
+
}
|
|
2136
|
+
return null;
|
|
2137
|
+
}
|
|
2138
|
+
function decodeCode(code) {
|
|
2139
|
+
let bytes = fromBase64Url(code);
|
|
2140
|
+
if (!bytes || bytes.length < 2 || bytes[0] !== 1) return null;
|
|
2141
|
+
let flags = bytes[1], options = {}, offset = 2;
|
|
2142
|
+
for (let [schemeIndex, scheme] of SCHEMES.entries()) {
|
|
2143
|
+
let schemeOptions = {};
|
|
2144
|
+
for (let [fieldIndex, field] of FIELDS.entries()) if (flags & 1 << schemeIndex * FIELDS.length + fieldIndex) {
|
|
2145
|
+
if (field === "contrast") {
|
|
2146
|
+
if (offset + 1 > bytes.length) return null;
|
|
2147
|
+
schemeOptions.contrast = Math.min(100, Math.max(15, bytes[offset])), offset += 1;
|
|
2148
|
+
} else {
|
|
2149
|
+
if (offset + 3 > bytes.length) return null;
|
|
2150
|
+
schemeOptions[field] = hexColor(bytes.subarray(offset, offset + 3)), offset += 3;
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
Object.keys(schemeOptions).length > 0 && (options[scheme] = schemeOptions);
|
|
2154
|
+
}
|
|
2155
|
+
let title;
|
|
2156
|
+
try {
|
|
2157
|
+
title = new TextDecoder("utf-8", { fatal: !0 }).decode(bytes.subarray(offset));
|
|
2158
|
+
} catch {
|
|
2159
|
+
return null;
|
|
2160
|
+
}
|
|
2161
|
+
return {
|
|
2162
|
+
title: displayTitle(title),
|
|
2163
|
+
options
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
/** The three RGB bytes of a `#rgb` or `#rrggbb` color */
|
|
2167
|
+
function rgbBytes(color) {
|
|
2168
|
+
let hex = color.length === 4 ? color.slice(1).replaceAll(/./g, "$&$&") : color.slice(1);
|
|
2169
|
+
return [
|
|
2170
|
+
0,
|
|
2171
|
+
2,
|
|
2172
|
+
4
|
|
2173
|
+
].map((start) => parseInt(hex.slice(start, start + 2), 16));
|
|
2174
|
+
}
|
|
2175
|
+
function hexColor(rgb) {
|
|
2176
|
+
return `#${[...rgb].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
2177
|
+
}
|
|
2178
|
+
function toBase64Url(bytes) {
|
|
2179
|
+
let binary = "";
|
|
2180
|
+
for (let byte of bytes) binary += String.fromCharCode(byte);
|
|
2181
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
2182
|
+
}
|
|
2183
|
+
function fromBase64Url(code) {
|
|
2184
|
+
if (!/^[A-Za-z0-9_-]+$/.test(code)) return null;
|
|
2185
|
+
let base64 = code.replaceAll("-", "+").replaceAll("_", "/");
|
|
2186
|
+
try {
|
|
2187
|
+
return Uint8Array.from(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")), (char) => char.charCodeAt(0));
|
|
2188
|
+
} catch {
|
|
2189
|
+
return null;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Copying a theme as a code to share, and adding a theme from a code someone
|
|
2194
|
+
* shared — with toasts telling how it went.
|
|
2195
|
+
*
|
|
2196
|
+
* @internal
|
|
2197
|
+
*/
|
|
2198
|
+
function useThemeCodes() {
|
|
2199
|
+
let $ = c(11), { send } = useThemer(), toast = useToast(), t0;
|
|
2200
|
+
$[0] === toast ? t0 = $[1] : (t0 = async (theme) => {
|
|
2201
|
+
let title = displayTitle(theme.title);
|
|
2202
|
+
try {
|
|
2203
|
+
await navigator.clipboard.writeText(encodeTheme(theme)), toast.push({
|
|
2204
|
+
status: "success",
|
|
2205
|
+
title: `Copied ${title} as a code`,
|
|
2206
|
+
description: "Paste it in the themer of another Studio to add the theme there"
|
|
2207
|
+
});
|
|
2208
|
+
} catch {
|
|
2209
|
+
toast.push({
|
|
2210
|
+
status: "error",
|
|
2211
|
+
title: `Could not copy ${title}`
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
}, $[0] = toast, $[1] = t0);
|
|
2215
|
+
let copyTheme = t0, t1;
|
|
2216
|
+
$[2] !== send || $[3] !== toast ? (t1 = (text) => {
|
|
2217
|
+
let theme_0 = decodeTheme(text);
|
|
2218
|
+
return theme_0 ? (send({
|
|
2219
|
+
type: "theme.import",
|
|
2220
|
+
title: theme_0.title,
|
|
2221
|
+
options: theme_0.options
|
|
2222
|
+
}), toast.push({
|
|
2223
|
+
status: "success",
|
|
2224
|
+
title: `Added ${theme_0.title}`
|
|
2225
|
+
}), !0) : !1;
|
|
2226
|
+
}, $[2] = send, $[3] = toast, $[4] = t1) : t1 = $[4];
|
|
2227
|
+
let addThemeFromText = t1, t2;
|
|
2228
|
+
$[5] === addThemeFromText ? t2 = $[6] : (t2 = async () => {
|
|
2229
|
+
let text_0;
|
|
2230
|
+
try {
|
|
2231
|
+
text_0 = await navigator.clipboard.readText();
|
|
2232
|
+
} catch {
|
|
2233
|
+
return "no-clipboard";
|
|
2234
|
+
}
|
|
2235
|
+
return addThemeFromText(text_0) ? "added" : "no-theme";
|
|
2236
|
+
}, $[5] = addThemeFromText, $[6] = t2);
|
|
2237
|
+
let addThemeFromClipboard = t2, t3;
|
|
2238
|
+
return $[7] !== addThemeFromClipboard || $[8] !== addThemeFromText || $[9] !== copyTheme ? (t3 = {
|
|
2239
|
+
copyTheme,
|
|
2240
|
+
addThemeFromText,
|
|
2241
|
+
addThemeFromClipboard
|
|
2242
|
+
}, $[7] = addThemeFromClipboard, $[8] = addThemeFromText, $[9] = copyTheme, $[10] = t3) : t3 = $[10], t3;
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* Adds a theme pasted anywhere in the Studio while the themer's list is
|
|
2246
|
+
* showing — pastes into inputs and other editable things are theirs.
|
|
2247
|
+
*
|
|
2248
|
+
* @internal
|
|
2249
|
+
*/
|
|
2250
|
+
function usePasteThemeCodes() {
|
|
2251
|
+
let $ = c(5), { open, send } = useThemer(), toast = useToast(), t0, t1;
|
|
2252
|
+
$[0] !== open || $[1] !== send || $[2] !== toast ? (t0 = () => {
|
|
2253
|
+
if (!open) return;
|
|
2254
|
+
let handlePaste = (event) => {
|
|
2255
|
+
if (isEditable(event.target)) return;
|
|
2256
|
+
let theme = decodeTheme(event.clipboardData?.getData("text/plain") ?? "");
|
|
2257
|
+
theme && (event.preventDefault(), send({
|
|
2258
|
+
type: "theme.import",
|
|
2259
|
+
title: theme.title,
|
|
2260
|
+
options: theme.options
|
|
2261
|
+
}), toast.push({
|
|
2262
|
+
status: "success",
|
|
2263
|
+
title: `Added ${theme.title}`
|
|
2264
|
+
}));
|
|
2265
|
+
};
|
|
2266
|
+
return document.addEventListener("paste", handlePaste), () => document.removeEventListener("paste", handlePaste);
|
|
2267
|
+
}, t1 = [
|
|
2268
|
+
open,
|
|
2269
|
+
send,
|
|
2270
|
+
toast
|
|
2271
|
+
], $[0] = open, $[1] = send, $[2] = toast, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1);
|
|
2272
|
+
}
|
|
2273
|
+
function isEditable(target) {
|
|
2274
|
+
return target instanceof HTMLElement && (target.isContentEditable || target.matches("input, textarea, select"));
|
|
2275
|
+
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Where a theme code someone shared gets pasted by hand — for browsers that
|
|
2278
|
+
* do not hand the clipboard over, and for codes that are not on it.
|
|
2279
|
+
*
|
|
2280
|
+
* @internal
|
|
2281
|
+
*/
|
|
2282
|
+
function PasteThemeDialog(props) {
|
|
2283
|
+
let $ = c(35), { onClose } = props, { addThemeFromText } = useThemeCodes(), [text, setText] = useState(""), [invalid, setInvalid] = useState(!1), t0;
|
|
2284
|
+
$[0] !== addThemeFromText || $[1] !== onClose || $[2] !== text ? (t0 = () => {
|
|
2285
|
+
addThemeFromText(text) ? onClose() : setInvalid(!0);
|
|
2286
|
+
}, $[0] = addThemeFromText, $[1] = onClose, $[2] = text, $[3] = t0) : t0 = $[3];
|
|
2287
|
+
let add = t0, t1;
|
|
2288
|
+
$[4] === onClose ? t1 = $[5] : (t1 = /* @__PURE__ */ jsx(Button, {
|
|
2289
|
+
mode: "ghost",
|
|
2290
|
+
onClick: onClose,
|
|
2291
|
+
padding: 2,
|
|
2292
|
+
text: "Cancel"
|
|
2293
|
+
}), $[4] = onClose, $[5] = t1);
|
|
2294
|
+
let t2;
|
|
2295
|
+
$[6] === text ? t2 = $[7] : (t2 = text.trim(), $[6] = text, $[7] = t2);
|
|
2296
|
+
let t3 = t2 === "", t4;
|
|
2297
|
+
$[8] !== add || $[9] !== t3 ? (t4 = /* @__PURE__ */ jsx(Button, {
|
|
2298
|
+
disabled: t3,
|
|
2299
|
+
onClick: add,
|
|
2300
|
+
padding: 2,
|
|
2301
|
+
text: "Add theme",
|
|
2302
|
+
tone: "primary"
|
|
2303
|
+
}), $[8] = add, $[9] = t3, $[10] = t4) : t4 = $[10];
|
|
2304
|
+
let t5;
|
|
2305
|
+
$[11] !== t1 || $[12] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Flex, {
|
|
2306
|
+
gap: 2,
|
|
2307
|
+
justify: "flex-end",
|
|
2308
|
+
padding: 3,
|
|
2309
|
+
children: [t1, t4]
|
|
2310
|
+
}), $[11] = t1, $[12] = t4, $[13] = t5) : t5 = $[13];
|
|
2311
|
+
let t6;
|
|
2312
|
+
$[14] === add ? t6 = $[15] : (t6 = (event) => {
|
|
2313
|
+
event.preventDefault(), add();
|
|
2314
|
+
}, $[14] = add, $[15] = t6);
|
|
2315
|
+
let t7;
|
|
2316
|
+
$[16] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsx(Text, {
|
|
2317
|
+
muted: !0,
|
|
2318
|
+
size: 1,
|
|
2319
|
+
children: "Paste the code someone copied from their themer — the theme is added to your list and applied."
|
|
2320
|
+
}), $[16] = t7) : t7 = $[16];
|
|
2321
|
+
let t8 = invalid ? "themer-paste-error" : void 0, t9 = invalid ? "That is not a theme code" : void 0, t10;
|
|
2322
|
+
$[17] === Symbol.for("react.memo_cache_sentinel") ? (t10 = (event_0) => {
|
|
2323
|
+
setText(event_0.currentTarget.value), setInvalid(!1);
|
|
2324
|
+
}, $[17] = t10) : t10 = $[17];
|
|
2325
|
+
let t11;
|
|
2326
|
+
$[18] !== invalid || $[19] !== t8 || $[20] !== t9 || $[21] !== text ? (t11 = /* @__PURE__ */ jsx(TextInput, {
|
|
2327
|
+
"aria-describedby": t8,
|
|
2328
|
+
"aria-invalid": invalid,
|
|
2329
|
+
"aria-label": "Theme code",
|
|
2330
|
+
autoFocus: !0,
|
|
2331
|
+
customValidity: t9,
|
|
2332
|
+
fontSize: 1,
|
|
2333
|
+
onChange: t10,
|
|
2334
|
+
placeholder: "AQ…",
|
|
2335
|
+
value: text
|
|
2336
|
+
}), $[18] = invalid, $[19] = t8, $[20] = t9, $[21] = text, $[22] = t11) : t11 = $[22];
|
|
2337
|
+
let t12;
|
|
2338
|
+
$[23] === invalid ? t12 = $[24] : (t12 = invalid && /* @__PURE__ */ jsx(Card, {
|
|
2339
|
+
id: "themer-paste-error",
|
|
2340
|
+
padding: 3,
|
|
2341
|
+
radius: 2,
|
|
2342
|
+
role: "alert",
|
|
2343
|
+
tone: "critical",
|
|
2344
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
2345
|
+
size: 1,
|
|
2346
|
+
children: "That is not a theme code — codes are one word, copied from a theme's menu."
|
|
2347
|
+
})
|
|
2348
|
+
}), $[23] = invalid, $[24] = t12);
|
|
2349
|
+
let t13;
|
|
2350
|
+
$[25] !== t11 || $[26] !== t12 ? (t13 = /* @__PURE__ */ jsxs(Stack, {
|
|
2351
|
+
gap: 3,
|
|
2352
|
+
padding: 4,
|
|
2353
|
+
children: [
|
|
2354
|
+
t7,
|
|
2355
|
+
t11,
|
|
2356
|
+
t12
|
|
1762
2357
|
]
|
|
1763
|
-
}), $[
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
})
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
2358
|
+
}), $[25] = t11, $[26] = t12, $[27] = t13) : t13 = $[27];
|
|
2359
|
+
let t14;
|
|
2360
|
+
$[28] !== t13 || $[29] !== t6 ? (t14 = /* @__PURE__ */ jsx("form", {
|
|
2361
|
+
onSubmit: t6,
|
|
2362
|
+
children: t13
|
|
2363
|
+
}), $[28] = t13, $[29] = t6, $[30] = t14) : t14 = $[30];
|
|
2364
|
+
let t15;
|
|
2365
|
+
return $[31] !== onClose || $[32] !== t14 || $[33] !== t5 ? (t15 = /* @__PURE__ */ jsx(Dialog, {
|
|
2366
|
+
animate: !0,
|
|
2367
|
+
footer: t5,
|
|
2368
|
+
header: "Add a shared theme",
|
|
2369
|
+
id: "themer-paste",
|
|
2370
|
+
onClickOutside: onClose,
|
|
2371
|
+
onClose,
|
|
2372
|
+
width: 0,
|
|
2373
|
+
children: t14
|
|
2374
|
+
}), $[31] = onClose, $[32] = t14, $[33] = t5, $[34] = t15) : t15 = $[34], t15;
|
|
2375
|
+
}
|
|
2376
|
+
var frame$1 = "_1wsn7882", menuCard = "_1wsn7884", menuSlot = "_1wsn7883", pickButton = "_1wsn7881", root = "_1wsn7880";
|
|
2377
|
+
/**
|
|
2378
|
+
* Scrolls the applied theme's card into view when it is not already, as a
|
|
2379
|
+
* ref: the list scrolls to it as it mounts — coming back from the editor or
|
|
2380
|
+
* the removed themes — and when another theme gets applied
|
|
2381
|
+
*/
|
|
2382
|
+
function scrollRefIntoViewIfNeeded(node) {
|
|
2383
|
+
node && scrollIntoView(node, {
|
|
2384
|
+
block: "nearest",
|
|
2385
|
+
scrollMode: "if-needed"
|
|
2386
|
+
});
|
|
2387
|
+
}
|
|
1778
2388
|
/**
|
|
1779
2389
|
* One theme in the list: the floating preview with the title below it, like
|
|
1780
2390
|
* an appearance option in macOS System Settings. Clicking it applies the
|
|
1781
|
-
* theme to the whole Studio
|
|
1782
|
-
*
|
|
2391
|
+
* theme to the whole Studio, dragging it moves the theme to another place in
|
|
2392
|
+
* the list; its menu holds the move, edit, duplicate and remove flows that
|
|
2393
|
+
* apply to the theme.
|
|
1783
2394
|
*
|
|
1784
2395
|
* @internal
|
|
1785
2396
|
*/
|
|
1786
2397
|
function ThemeCard(props) {
|
|
1787
|
-
let $ = c(
|
|
2398
|
+
let $ = c(85), { active, theme } = props, { themes, send } = useThemer(), { copyTheme } = useThemeCodes(), { scheme } = useRootTheme(), [menuOpen, setMenuOpen] = useState(!1), dragControls = useDragControls(), dragged = useRef(!1), t0;
|
|
1788
2399
|
$[0] === theme.title ? t0 = $[1] : (t0 = displayTitle(theme.title), $[0] = theme.title, $[1] = t0);
|
|
1789
2400
|
let title = t0, t1;
|
|
1790
|
-
$[2]
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
2401
|
+
$[2] === theme.slug ? t1 = $[3] : (t1 = (candidate) => candidate.slug === theme.slug, $[2] = theme.slug, $[3] = t1);
|
|
2402
|
+
let index = themes.findIndex(t1), t2;
|
|
2403
|
+
$[4] !== index || $[5] !== send || $[6] !== themes ? (t2 = (to) => {
|
|
2404
|
+
let order = themes.map(_temp$2);
|
|
2405
|
+
order.splice(to, 0, ...order.splice(index, 1)), send({
|
|
2406
|
+
type: "theme.reorder",
|
|
2407
|
+
order
|
|
2408
|
+
});
|
|
2409
|
+
}, $[4] = index, $[5] = send, $[6] = themes, $[7] = t2) : t2 = $[7];
|
|
2410
|
+
let moveTo = t2, t3, t4;
|
|
2411
|
+
$[8] === Symbol.for("react.memo_cache_sentinel") ? (t3 = () => {
|
|
2412
|
+
requestAnimationFrame(() => {
|
|
2413
|
+
dragged.current = !1;
|
|
2414
|
+
});
|
|
2415
|
+
}, t4 = () => {
|
|
2416
|
+
dragged.current = !0;
|
|
2417
|
+
}, $[8] = t3, $[9] = t4) : (t3 = $[8], t4 = $[9]);
|
|
2418
|
+
let t5 = active ? scrollRefIntoViewIfNeeded : void 0, t6;
|
|
2419
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t6 = { scale: 1.04 }, $[10] = t6) : t6 = $[10];
|
|
2420
|
+
let t7;
|
|
2421
|
+
$[11] !== send || $[12] !== theme.slug ? (t7 = () => {
|
|
2422
|
+
dragged.current || send({
|
|
2423
|
+
type: "theme.pick",
|
|
2424
|
+
slug: theme.slug
|
|
2425
|
+
});
|
|
2426
|
+
}, $[11] = send, $[12] = theme.slug, $[13] = t7) : t7 = $[13];
|
|
2427
|
+
let t8;
|
|
2428
|
+
$[14] === dragControls ? t8 = $[15] : (t8 = (event) => {
|
|
2429
|
+
event.pointerType !== "touch" && dragControls.start(event);
|
|
2430
|
+
}, $[14] = dragControls, $[15] = t8);
|
|
2431
|
+
let t9;
|
|
2432
|
+
$[16] === theme.options ? t9 = $[17] : (t9 = /* @__PURE__ */ jsx("span", {
|
|
2433
|
+
className: frame$1,
|
|
2434
|
+
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
|
|
2435
|
+
}), $[16] = theme.options, $[17] = t9);
|
|
2436
|
+
let t10 = active ? "medium" : "regular", t11;
|
|
2437
|
+
$[18] !== t10 || $[19] !== title ? (t11 = /* @__PURE__ */ jsx(Box, {
|
|
1798
2438
|
as: "span",
|
|
1799
2439
|
display: "block",
|
|
1800
2440
|
paddingTop: 2,
|
|
@@ -1804,55 +2444,81 @@ function ThemeCard(props) {
|
|
|
1804
2444
|
as: "span",
|
|
1805
2445
|
size: 1,
|
|
1806
2446
|
textOverflow: "ellipsis",
|
|
1807
|
-
weight:
|
|
2447
|
+
weight: t10,
|
|
1808
2448
|
children: title
|
|
1809
2449
|
})
|
|
1810
|
-
}), $[
|
|
1811
|
-
let
|
|
1812
|
-
$[
|
|
2450
|
+
}), $[18] = t10, $[19] = title, $[20] = t11) : t11 = $[20];
|
|
2451
|
+
let t12;
|
|
2452
|
+
$[21] !== active || $[22] !== t11 || $[23] !== t7 || $[24] !== t8 || $[25] !== t9 ? (t12 = /* @__PURE__ */ jsxs("button", {
|
|
1813
2453
|
"aria-pressed": active,
|
|
1814
|
-
|
|
2454
|
+
className: pickButton,
|
|
2455
|
+
onClick: t7,
|
|
2456
|
+
onPointerDown: t8,
|
|
1815
2457
|
type: "button",
|
|
1816
|
-
children: [
|
|
1817
|
-
}), $[
|
|
1818
|
-
let
|
|
1819
|
-
$[
|
|
2458
|
+
children: [t9, t11]
|
|
2459
|
+
}), $[21] = active, $[22] = t11, $[23] = t7, $[24] = t8, $[25] = t9, $[26] = t12) : t12 = $[26];
|
|
2460
|
+
let t13;
|
|
2461
|
+
$[27] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Text, {
|
|
1820
2462
|
size: 1,
|
|
1821
2463
|
children: "Show more"
|
|
1822
|
-
}), $[
|
|
1823
|
-
let
|
|
1824
|
-
$[
|
|
1825
|
-
|
|
1826
|
-
$[17] === t8 ? t9 = $[18] : (t9 = /* @__PURE__ */ jsx(Button, {
|
|
1827
|
-
"aria-label": t8,
|
|
2464
|
+
}), $[27] = t13) : t13 = $[27];
|
|
2465
|
+
let t14 = `Show more for ${title}`, t15;
|
|
2466
|
+
$[28] === t14 ? t15 = $[29] : (t15 = /* @__PURE__ */ jsx(Button, {
|
|
2467
|
+
"aria-label": t14,
|
|
1828
2468
|
fontSize: 1,
|
|
1829
2469
|
icon: EllipsisHorizontalIcon,
|
|
1830
2470
|
mode: "ghost",
|
|
1831
2471
|
padding: 1,
|
|
1832
2472
|
radius: 2
|
|
1833
|
-
}), $[
|
|
1834
|
-
let
|
|
1835
|
-
$[
|
|
2473
|
+
}), $[28] = t14, $[29] = t15);
|
|
2474
|
+
let t16 = `themer-theme-${theme.slug}`, t17 = index <= 0, t18;
|
|
2475
|
+
$[30] !== index || $[31] !== moveTo ? (t18 = () => moveTo(index - 1), $[30] = index, $[31] = moveTo, $[32] = t18) : t18 = $[32];
|
|
2476
|
+
let t19;
|
|
2477
|
+
$[33] !== t17 || $[34] !== t18 ? (t19 = /* @__PURE__ */ jsx(MenuItem, {
|
|
2478
|
+
disabled: t17,
|
|
2479
|
+
icon: ArrowUpIcon,
|
|
2480
|
+
onClick: t18,
|
|
2481
|
+
text: "Move up"
|
|
2482
|
+
}), $[33] = t17, $[34] = t18, $[35] = t19) : t19 = $[35];
|
|
2483
|
+
let t20 = index >= themes.length - 1, t21;
|
|
2484
|
+
$[36] !== index || $[37] !== moveTo ? (t21 = () => moveTo(index + 1), $[36] = index, $[37] = moveTo, $[38] = t21) : t21 = $[38];
|
|
2485
|
+
let t22;
|
|
2486
|
+
$[39] !== t20 || $[40] !== t21 ? (t22 = /* @__PURE__ */ jsx(MenuItem, {
|
|
2487
|
+
disabled: t20,
|
|
2488
|
+
icon: ArrowDownIcon,
|
|
2489
|
+
onClick: t21,
|
|
2490
|
+
text: "Move down"
|
|
2491
|
+
}), $[39] = t20, $[40] = t21, $[41] = t22) : t22 = $[41];
|
|
2492
|
+
let t23;
|
|
2493
|
+
$[42] === Symbol.for("react.memo_cache_sentinel") ? (t23 = /* @__PURE__ */ jsx(MenuDivider, {}), $[42] = t23) : t23 = $[42];
|
|
2494
|
+
let t24;
|
|
2495
|
+
$[43] !== send || $[44] !== theme.slug || $[45] !== theme.source ? (t24 = theme.source === "custom" && /* @__PURE__ */ jsx(MenuItem, {
|
|
1836
2496
|
icon: EditIcon,
|
|
1837
2497
|
onClick: () => send({
|
|
1838
2498
|
type: "theme.edit",
|
|
1839
2499
|
slug: theme.slug
|
|
1840
2500
|
}),
|
|
1841
2501
|
text: "Edit"
|
|
1842
|
-
}), $[
|
|
1843
|
-
let
|
|
1844
|
-
$[
|
|
2502
|
+
}), $[43] = send, $[44] = theme.slug, $[45] = theme.source, $[46] = t24) : t24 = $[46];
|
|
2503
|
+
let t25;
|
|
2504
|
+
$[47] !== send || $[48] !== theme.slug ? (t25 = () => send({
|
|
1845
2505
|
type: "theme.duplicate",
|
|
1846
2506
|
slug: theme.slug
|
|
1847
|
-
}), $[
|
|
1848
|
-
let
|
|
1849
|
-
$[
|
|
2507
|
+
}), $[47] = send, $[48] = theme.slug, $[49] = t25) : t25 = $[49];
|
|
2508
|
+
let t26 = theme.source === "custom" ? "Duplicate" : "Duplicate to edit", t27;
|
|
2509
|
+
$[50] !== t25 || $[51] !== t26 ? (t27 = /* @__PURE__ */ jsx(MenuItem, {
|
|
1850
2510
|
icon: CopyIcon,
|
|
1851
|
-
onClick:
|
|
1852
|
-
text:
|
|
1853
|
-
}), $[
|
|
1854
|
-
let
|
|
1855
|
-
$[
|
|
2511
|
+
onClick: t25,
|
|
2512
|
+
text: t26
|
|
2513
|
+
}), $[50] = t25, $[51] = t26, $[52] = t27) : t27 = $[52];
|
|
2514
|
+
let t28;
|
|
2515
|
+
$[53] !== copyTheme || $[54] !== theme ? (t28 = /* @__PURE__ */ jsx(MenuItem, {
|
|
2516
|
+
icon: ShareIcon,
|
|
2517
|
+
onClick: () => void copyTheme(theme),
|
|
2518
|
+
text: "Copy to share"
|
|
2519
|
+
}), $[53] = copyTheme, $[54] = theme, $[55] = t28) : t28 = $[55];
|
|
2520
|
+
let t29;
|
|
2521
|
+
$[56] !== send || $[57] !== theme.slug || $[58] !== theme.source ? (t29 = theme.source !== "config" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx(MenuItem, {
|
|
1856
2522
|
icon: TrashIcon,
|
|
1857
2523
|
onClick: () => send({
|
|
1858
2524
|
type: "theme.remove",
|
|
@@ -1860,59 +2526,86 @@ function ThemeCard(props) {
|
|
|
1860
2526
|
}),
|
|
1861
2527
|
text: "Remove",
|
|
1862
2528
|
tone: "critical"
|
|
1863
|
-
})] }), $[
|
|
1864
|
-
let
|
|
1865
|
-
$[
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
$[
|
|
2529
|
+
})] }), $[56] = send, $[57] = theme.slug, $[58] = theme.source, $[59] = t29) : t29 = $[59];
|
|
2530
|
+
let t30;
|
|
2531
|
+
$[60] !== t19 || $[61] !== t22 || $[62] !== t24 || $[63] !== t27 || $[64] !== t28 || $[65] !== t29 ? (t30 = /* @__PURE__ */ jsxs(Menu, { children: [
|
|
2532
|
+
t19,
|
|
2533
|
+
t22,
|
|
2534
|
+
t23,
|
|
2535
|
+
t24,
|
|
2536
|
+
t27,
|
|
2537
|
+
t28,
|
|
2538
|
+
t29
|
|
2539
|
+
] }), $[60] = t19, $[61] = t22, $[62] = t24, $[63] = t27, $[64] = t28, $[65] = t29, $[66] = t30) : t30 = $[66];
|
|
2540
|
+
let t31, t32;
|
|
2541
|
+
$[67] === Symbol.for("react.memo_cache_sentinel") ? (t31 = () => setMenuOpen(!1), t32 = () => setMenuOpen(!0), $[67] = t31, $[68] = t32) : (t31 = $[67], t32 = $[68]);
|
|
2542
|
+
let t33;
|
|
2543
|
+
$[69] === scheme ? t33 = $[70] : (t33 = {
|
|
1874
2544
|
animate: !0,
|
|
1875
2545
|
placement: "bottom-end",
|
|
1876
2546
|
portal: !0,
|
|
1877
2547
|
scheme
|
|
1878
|
-
}, $[
|
|
1879
|
-
let
|
|
1880
|
-
$[
|
|
2548
|
+
}, $[69] = scheme, $[70] = t33);
|
|
2549
|
+
let t34;
|
|
2550
|
+
$[71] !== t15 || $[72] !== t16 || $[73] !== t30 || $[74] !== t33 ? (t34 = /* @__PURE__ */ jsx(Tooltip, {
|
|
1881
2551
|
animate: !0,
|
|
1882
|
-
content:
|
|
2552
|
+
content: t13,
|
|
1883
2553
|
placement: "bottom",
|
|
1884
2554
|
portal: !0,
|
|
1885
2555
|
children: /* @__PURE__ */ jsx(Card, {
|
|
2556
|
+
className: menuCard,
|
|
1886
2557
|
radius: 2,
|
|
1887
2558
|
scheme: "dark",
|
|
1888
|
-
style: t7,
|
|
1889
2559
|
children: /* @__PURE__ */ jsx(MenuButton, {
|
|
1890
|
-
button:
|
|
1891
|
-
id:
|
|
1892
|
-
menu:
|
|
1893
|
-
onClose:
|
|
1894
|
-
onOpen:
|
|
1895
|
-
popover:
|
|
2560
|
+
button: t15,
|
|
2561
|
+
id: t16,
|
|
2562
|
+
menu: t30,
|
|
2563
|
+
onClose: t31,
|
|
2564
|
+
onOpen: t32,
|
|
2565
|
+
popover: t33
|
|
1896
2566
|
})
|
|
1897
2567
|
})
|
|
1898
|
-
}), $[
|
|
1899
|
-
let
|
|
1900
|
-
$[
|
|
2568
|
+
}), $[71] = t15, $[72] = t16, $[73] = t30, $[74] = t33, $[75] = t34) : t34 = $[75];
|
|
2569
|
+
let t35;
|
|
2570
|
+
$[76] !== menuOpen || $[77] !== t34 ? (t35 = /* @__PURE__ */ jsx("div", {
|
|
2571
|
+
className: menuSlot,
|
|
1901
2572
|
"data-visible": menuOpen,
|
|
1902
|
-
children:
|
|
1903
|
-
}), $[
|
|
1904
|
-
let
|
|
1905
|
-
return $[
|
|
1906
|
-
|
|
2573
|
+
children: t34
|
|
2574
|
+
}), $[76] = menuOpen, $[77] = t34, $[78] = t35) : t35 = $[78];
|
|
2575
|
+
let t36;
|
|
2576
|
+
return $[79] !== dragControls || $[80] !== t12 || $[81] !== t35 || $[82] !== t5 || $[83] !== theme.slug ? (t36 = /* @__PURE__ */ jsxs(Reorder.Item, {
|
|
2577
|
+
as: "div",
|
|
2578
|
+
className: root,
|
|
2579
|
+
dragControls,
|
|
2580
|
+
dragListener: !1,
|
|
2581
|
+
onDragEnd: t3,
|
|
2582
|
+
onDragStart: t4,
|
|
2583
|
+
ref: t5,
|
|
2584
|
+
value: theme.slug,
|
|
2585
|
+
whileDrag: t6,
|
|
2586
|
+
children: [t12, t35]
|
|
2587
|
+
}), $[79] = dragControls, $[80] = t12, $[81] = t35, $[82] = t5, $[83] = theme.slug, $[84] = t36) : t36 = $[84], t36;
|
|
2588
|
+
}
|
|
2589
|
+
function _temp$2(candidate_0) {
|
|
2590
|
+
return candidate_0.slug;
|
|
2591
|
+
}
|
|
2592
|
+
var cardGrid = "twjqgh0";
|
|
2593
|
+
/**
|
|
2594
|
+
* One column at the sidebar's default width; wider sidebars — and the
|
|
2595
|
+
* overlay on small screens — fit more cards per row
|
|
2596
|
+
*/
|
|
1907
2597
|
/**
|
|
1908
|
-
* The flow for picking a theme:
|
|
1909
|
-
*
|
|
1910
|
-
* the add and restore flows below.
|
|
2598
|
+
* The flow for picking a theme: a grid of theme cards — the configured theme,
|
|
2599
|
+
* the presets and the user's own themes — that drag into the order the user
|
|
2600
|
+
* wants, with the entry points to the add and restore flows below. A theme
|
|
2601
|
+
* code someone shared pastes right into the list, or through the paste button.
|
|
1911
2602
|
*
|
|
1912
2603
|
* @internal
|
|
1913
2604
|
*/
|
|
1914
2605
|
function ThemeList() {
|
|
1915
|
-
let $ = c(
|
|
2606
|
+
let $ = c(38), { themes, removed, active, send } = useThemer(), { addThemeFromClipboard } = useThemeCodes(), [pasting, setPasting] = useState(!1);
|
|
2607
|
+
usePasteThemeCodes();
|
|
2608
|
+
let t0;
|
|
1916
2609
|
$[0] === send ? t0 = $[1] : (t0 = (palette, file) => send({
|
|
1917
2610
|
type: "theme.add",
|
|
1918
2611
|
title: titleFromFileName(file.name),
|
|
@@ -1921,31 +2614,51 @@ function ThemeList() {
|
|
|
1921
2614
|
imageUrl: URL.createObjectURL(file)
|
|
1922
2615
|
}), $[0] = send, $[1] = t0);
|
|
1923
2616
|
let { busy, pickImage } = useImagePalette(t0), t1;
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
theme
|
|
1929
|
-
}, theme.slug), $[5] = active, $[6] = t2), t1 = themes.map(t2), $[2] = active, $[3] = themes, $[4] = t1;
|
|
1930
|
-
} else t1 = $[4];
|
|
2617
|
+
$[2] === send ? t1 = $[3] : (t1 = (order) => send({
|
|
2618
|
+
type: "theme.reorder",
|
|
2619
|
+
order
|
|
2620
|
+
}), $[2] = send, $[3] = t1);
|
|
1931
2621
|
let t2;
|
|
1932
|
-
$[
|
|
2622
|
+
$[4] === themes ? t2 = $[5] : (t2 = themes.map(_temp$1), $[4] = themes, $[5] = t2);
|
|
2623
|
+
let t3;
|
|
2624
|
+
if ($[6] !== active || $[7] !== themes) {
|
|
2625
|
+
let t4;
|
|
2626
|
+
$[9] === active ? t4 = $[10] : (t4 = (theme_0) => /* @__PURE__ */ jsx(ThemeCard, {
|
|
2627
|
+
active: theme_0.slug === active.slug,
|
|
2628
|
+
theme: theme_0
|
|
2629
|
+
}, theme_0.slug), $[9] = active, $[10] = t4), t3 = themes.map(t4), $[6] = active, $[7] = themes, $[8] = t3;
|
|
2630
|
+
} else t3 = $[8];
|
|
2631
|
+
let t4;
|
|
2632
|
+
$[11] !== t1 || $[12] !== t2 || $[13] !== t3 ? (t4 = /* @__PURE__ */ jsx(MotionConfig, {
|
|
2633
|
+
reducedMotion: "user",
|
|
2634
|
+
children: /* @__PURE__ */ jsx(Reorder.Group, {
|
|
2635
|
+
as: "div",
|
|
2636
|
+
className: cardGrid,
|
|
2637
|
+
onReorder: t1,
|
|
2638
|
+
values: t2,
|
|
2639
|
+
children: t3
|
|
2640
|
+
})
|
|
2641
|
+
}), $[11] = t1, $[12] = t2, $[13] = t3, $[14] = t4) : t4 = $[14];
|
|
2642
|
+
let t5;
|
|
2643
|
+
$[15] !== removed.length || $[16] !== send ? (t5 = removed.length > 0 && /* @__PURE__ */ jsx(Button, {
|
|
2644
|
+
gap: 2,
|
|
1933
2645
|
icon: RestoreIcon,
|
|
1934
2646
|
mode: "bleed",
|
|
1935
2647
|
onClick: () => send({ type: "flow.removed" }),
|
|
2648
|
+
padding: 2,
|
|
1936
2649
|
text: `Show removed (${removed.length})`,
|
|
1937
2650
|
width: "fill"
|
|
1938
|
-
}), $[
|
|
1939
|
-
let
|
|
1940
|
-
$[
|
|
2651
|
+
}), $[15] = removed.length, $[16] = send, $[17] = t5) : t5 = $[17];
|
|
2652
|
+
let t6;
|
|
2653
|
+
$[18] !== t4 || $[19] !== t5 ? (t6 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
1941
2654
|
padding: 3,
|
|
1942
2655
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1943
2656
|
gap: 4,
|
|
1944
|
-
children: [
|
|
2657
|
+
children: [t4, t5]
|
|
1945
2658
|
})
|
|
1946
|
-
}), $[
|
|
1947
|
-
let
|
|
1948
|
-
$[
|
|
2659
|
+
}), $[18] = t4, $[19] = t5, $[20] = t6) : t6 = $[20];
|
|
2660
|
+
let t7;
|
|
2661
|
+
$[21] === send ? t7 = $[22] : (t7 = /* @__PURE__ */ jsx(Box, {
|
|
1949
2662
|
flex: 1,
|
|
1950
2663
|
children: /* @__PURE__ */ jsx(TooltipButton, {
|
|
1951
2664
|
icon: AddIcon,
|
|
@@ -1955,25 +2668,47 @@ function ThemeList() {
|
|
|
1955
2668
|
tooltip: "Add a theme based on the applied one",
|
|
1956
2669
|
width: "fill"
|
|
1957
2670
|
})
|
|
1958
|
-
}), $[
|
|
1959
|
-
let
|
|
1960
|
-
$[
|
|
2671
|
+
}), $[21] = send, $[22] = t7);
|
|
2672
|
+
let t8;
|
|
2673
|
+
$[23] !== busy || $[24] !== pickImage ? (t8 = /* @__PURE__ */ jsx(ImageFileButton, {
|
|
1961
2674
|
loading: busy,
|
|
1962
2675
|
mode: "ghost",
|
|
1963
2676
|
onFile: pickImage,
|
|
1964
2677
|
tooltip: "Add a theme from the colors of an image"
|
|
1965
|
-
}), $[
|
|
1966
|
-
let
|
|
1967
|
-
$[
|
|
2678
|
+
}), $[23] = busy, $[24] = pickImage, $[25] = t8) : t8 = $[25];
|
|
2679
|
+
let t9;
|
|
2680
|
+
$[26] === addThemeFromClipboard ? t9 = $[27] : (t9 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
2681
|
+
icon: ClipboardIcon,
|
|
2682
|
+
mode: "ghost",
|
|
2683
|
+
onClick: async () => {
|
|
2684
|
+
await addThemeFromClipboard() !== "added" && setPasting(!0);
|
|
2685
|
+
},
|
|
2686
|
+
tooltip: "Add a theme from a code someone shared"
|
|
2687
|
+
}), $[26] = addThemeFromClipboard, $[27] = t9);
|
|
2688
|
+
let t10;
|
|
2689
|
+
$[28] !== t7 || $[29] !== t8 || $[30] !== t9 ? (t10 = /* @__PURE__ */ jsx(Card, {
|
|
1968
2690
|
borderTop: !0,
|
|
1969
2691
|
padding: 3,
|
|
1970
2692
|
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1971
2693
|
gap: 2,
|
|
1972
|
-
children: [
|
|
2694
|
+
children: [
|
|
2695
|
+
t7,
|
|
2696
|
+
t8,
|
|
2697
|
+
t9
|
|
2698
|
+
]
|
|
1973
2699
|
})
|
|
1974
|
-
}), $[
|
|
1975
|
-
let
|
|
1976
|
-
|
|
2700
|
+
}), $[28] = t7, $[29] = t8, $[30] = t9, $[31] = t10) : t10 = $[31];
|
|
2701
|
+
let t11;
|
|
2702
|
+
$[32] === pasting ? t11 = $[33] : (t11 = pasting && /* @__PURE__ */ jsx(PasteThemeDialog, { onClose: () => setPasting(!1) }), $[32] = pasting, $[33] = t11);
|
|
2703
|
+
let t12;
|
|
2704
|
+
return $[34] !== t10 || $[35] !== t11 || $[36] !== t6 ? (t12 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2705
|
+
t6,
|
|
2706
|
+
t10,
|
|
2707
|
+
t11
|
|
2708
|
+
] }), $[34] = t10, $[35] = t11, $[36] = t6, $[37] = t12) : t12 = $[37], t12;
|
|
2709
|
+
}
|
|
2710
|
+
function _temp$1(theme) {
|
|
2711
|
+
return theme.slug;
|
|
1977
2712
|
}
|
|
1978
2713
|
/**
|
|
1979
2714
|
* Serializes theme options into the `buildTheme` call to paste into
|
|
@@ -2032,9 +2767,11 @@ function ThemeSnippetDialog(props) {
|
|
|
2032
2767
|
justify: "flex-end",
|
|
2033
2768
|
padding: 3,
|
|
2034
2769
|
children: /* @__PURE__ */ jsx(Button, {
|
|
2770
|
+
gap: 2,
|
|
2035
2771
|
icon: ClipboardIcon,
|
|
2036
2772
|
mode: "ghost",
|
|
2037
2773
|
onClick: () => void handleCopy(),
|
|
2774
|
+
padding: 2,
|
|
2038
2775
|
text: "Copy"
|
|
2039
2776
|
})
|
|
2040
2777
|
}), $[5] = handleCopy, $[6] = t2);
|
|
@@ -2096,6 +2833,7 @@ function ThemeSnippetDialog(props) {
|
|
|
2096
2833
|
children: t9
|
|
2097
2834
|
}), $[19] = onClose, $[20] = t2, $[21] = t9, $[22] = t10) : t10 = $[22], t10;
|
|
2098
2835
|
}
|
|
2836
|
+
var title = "c2pqej0";
|
|
2099
2837
|
const VIEW_TITLES = {
|
|
2100
2838
|
list: "Themer",
|
|
2101
2839
|
edit: "Edit theme",
|
|
@@ -2110,32 +2848,29 @@ const VIEW_TITLES = {
|
|
|
2110
2848
|
* @internal
|
|
2111
2849
|
*/
|
|
2112
2850
|
function ThemerSidebar() {
|
|
2113
|
-
let $ = c(
|
|
2114
|
-
$[0]
|
|
2851
|
+
let $ = c(42), { active, split, view, navbarHeight, send } = useThemer(), [snippetOpen, setSnippetOpen] = useState(!1), inList = view.name === "list", t0;
|
|
2852
|
+
$[0] === navbarHeight ? t0 = $[1] : (t0 = navbarHeight === null ? void 0 : { height: navbarHeight }, $[0] = navbarHeight, $[1] = t0);
|
|
2853
|
+
let t1;
|
|
2854
|
+
$[2] !== inList || $[3] !== send ? (t1 = !inList && /* @__PURE__ */ jsx(TooltipButton, {
|
|
2115
2855
|
icon: ArrowLeftIcon,
|
|
2116
2856
|
mode: "bleed",
|
|
2117
2857
|
onClick: () => send({ type: "flow.list" }),
|
|
2118
2858
|
padding: 2,
|
|
2119
2859
|
tooltip: "Back to the themes"
|
|
2120
|
-
}), $[
|
|
2121
|
-
let
|
|
2122
|
-
$[
|
|
2123
|
-
|
|
2124
|
-
$[4] === t3 ? t4 = $[5] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
2125
|
-
size: 1,
|
|
2126
|
-
textOverflow: "ellipsis",
|
|
2127
|
-
weight: "semibold",
|
|
2128
|
-
children: t3
|
|
2129
|
-
}), $[4] = t3, $[5] = t4);
|
|
2130
|
-
let t5;
|
|
2131
|
-
$[6] !== t1 || $[7] !== t4 ? (t5 = /* @__PURE__ */ jsx(Box, {
|
|
2860
|
+
}), $[2] = inList, $[3] = send, $[4] = t1) : t1 = $[4];
|
|
2861
|
+
let t2 = VIEW_TITLES[view.name], t3;
|
|
2862
|
+
$[5] === t2 ? t3 = $[6] : (t3 = /* @__PURE__ */ jsx(Box, {
|
|
2863
|
+
className: title,
|
|
2132
2864
|
flex: 1,
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2865
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
2866
|
+
size: 1,
|
|
2867
|
+
textOverflow: "ellipsis",
|
|
2868
|
+
weight: "semibold",
|
|
2869
|
+
children: t2
|
|
2870
|
+
})
|
|
2871
|
+
}), $[5] = t2, $[6] = t3);
|
|
2872
|
+
let t4;
|
|
2873
|
+
$[7] !== send || $[8] !== split || $[9] !== view.name ? (t4 = view.name !== "removed" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TooltipButton, {
|
|
2139
2874
|
"aria-pressed": split,
|
|
2140
2875
|
icon: SplitVerticalIcon,
|
|
2141
2876
|
mode: "bleed",
|
|
@@ -2149,66 +2884,69 @@ function ThemerSidebar() {
|
|
|
2149
2884
|
onClick: () => setSnippetOpen(!0),
|
|
2150
2885
|
padding: 2,
|
|
2151
2886
|
tooltip: "Show the code for the applied theme"
|
|
2152
|
-
})] }), $[
|
|
2153
|
-
let
|
|
2154
|
-
$[
|
|
2887
|
+
})] }), $[7] = send, $[8] = split, $[9] = view.name, $[10] = t4) : t4 = $[10];
|
|
2888
|
+
let t5;
|
|
2889
|
+
$[11] === send ? t5 = $[12] : (t5 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
2155
2890
|
icon: CloseIcon,
|
|
2156
2891
|
mode: "bleed",
|
|
2157
2892
|
onClick: () => send({ type: "sidebar.close" }),
|
|
2158
2893
|
padding: 2,
|
|
2159
2894
|
tooltip: "Close themer"
|
|
2160
|
-
}), $[
|
|
2895
|
+
}), $[11] = send, $[12] = t5);
|
|
2896
|
+
let t6;
|
|
2897
|
+
$[13] !== t4 || $[14] !== t5 ? (t6 = /* @__PURE__ */ jsxs(Flex, { children: [t4, t5] }), $[13] = t4, $[14] = t5, $[15] = t6) : t6 = $[15];
|
|
2898
|
+
let t7;
|
|
2899
|
+
$[16] !== t1 || $[17] !== t3 || $[18] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Flex, {
|
|
2900
|
+
align: "center",
|
|
2901
|
+
gap: 1,
|
|
2902
|
+
height: "fill",
|
|
2903
|
+
children: [
|
|
2904
|
+
t1,
|
|
2905
|
+
t3,
|
|
2906
|
+
t6
|
|
2907
|
+
]
|
|
2908
|
+
}), $[16] = t1, $[17] = t3, $[18] = t6, $[19] = t7) : t7 = $[19];
|
|
2161
2909
|
let t8;
|
|
2162
|
-
$[
|
|
2910
|
+
$[20] !== t0 || $[21] !== t7 ? (t8 = /* @__PURE__ */ jsx(Card, {
|
|
2911
|
+
borderBottom: !0,
|
|
2912
|
+
padding: 3,
|
|
2913
|
+
sizing: "border",
|
|
2914
|
+
style: t0,
|
|
2915
|
+
children: t7
|
|
2916
|
+
}), $[20] = t0, $[21] = t7, $[22] = t8) : t8 = $[22];
|
|
2163
2917
|
let t9;
|
|
2164
|
-
$[
|
|
2165
|
-
padding: 2,
|
|
2166
|
-
children: /* @__PURE__ */ jsxs(Flex, {
|
|
2167
|
-
align: "center",
|
|
2168
|
-
gap: 1,
|
|
2169
|
-
children: [
|
|
2170
|
-
t0,
|
|
2171
|
-
t5,
|
|
2172
|
-
t8
|
|
2173
|
-
]
|
|
2174
|
-
})
|
|
2175
|
-
}), $[18] = t0, $[19] = t5, $[20] = t8, $[21] = t9) : t9 = $[21];
|
|
2918
|
+
$[23] === view.name ? t9 = $[24] : (t9 = view.name === "list" && /* @__PURE__ */ jsx(ThemeList, {}), $[23] = view.name, $[24] = t9);
|
|
2176
2919
|
let t10;
|
|
2177
|
-
$[
|
|
2178
|
-
let t11;
|
|
2179
|
-
$[24] !== view.focusTitle || $[25] !== view.name || $[26] !== view.slug ? (t11 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
|
|
2920
|
+
$[25] !== view.focusTitle || $[26] !== view.name || $[27] !== view.slug ? (t10 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
|
|
2180
2921
|
focusTitle: view.focusTitle,
|
|
2181
2922
|
slug: view.slug
|
|
2182
|
-
}), $[
|
|
2923
|
+
}), $[25] = view.focusTitle, $[26] = view.name, $[27] = view.slug, $[28] = t10) : t10 = $[28];
|
|
2924
|
+
let t11;
|
|
2925
|
+
$[29] === view.name ? t11 = $[30] : (t11 = view.name === "removed" && /* @__PURE__ */ jsx(RemovedThemes, {}), $[29] = view.name, $[30] = t11);
|
|
2183
2926
|
let t12;
|
|
2184
|
-
$[
|
|
2185
|
-
let t13;
|
|
2186
|
-
$[30] !== t10 || $[31] !== t11 || $[32] !== t12 || $[33] !== t9 ? (t13 = /* @__PURE__ */ jsxs(Flex, {
|
|
2927
|
+
$[31] !== t10 || $[32] !== t11 || $[33] !== t8 || $[34] !== t9 ? (t12 = /* @__PURE__ */ jsxs(Flex, {
|
|
2187
2928
|
direction: "column",
|
|
2188
2929
|
height: "fill",
|
|
2189
2930
|
children: [
|
|
2931
|
+
t8,
|
|
2190
2932
|
t9,
|
|
2191
2933
|
t10,
|
|
2192
|
-
t11
|
|
2193
|
-
t12
|
|
2934
|
+
t11
|
|
2194
2935
|
]
|
|
2195
|
-
}), $[
|
|
2196
|
-
let
|
|
2197
|
-
$[
|
|
2936
|
+
}), $[31] = t10, $[32] = t11, $[33] = t8, $[34] = t9, $[35] = t12) : t12 = $[35];
|
|
2937
|
+
let t13;
|
|
2938
|
+
$[36] !== active || $[37] !== snippetOpen ? (t13 = snippetOpen && /* @__PURE__ */ jsx(ThemeSnippetDialog, {
|
|
2198
2939
|
onClose: () => setSnippetOpen(!1),
|
|
2199
2940
|
theme: active
|
|
2200
|
-
}), $[
|
|
2201
|
-
let
|
|
2202
|
-
return $[
|
|
2941
|
+
}), $[36] = active, $[37] = snippetOpen, $[38] = t13) : t13 = $[38];
|
|
2942
|
+
let t14;
|
|
2943
|
+
return $[39] !== t12 || $[40] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Card, {
|
|
2203
2944
|
height: "fill",
|
|
2204
|
-
children: [
|
|
2205
|
-
}), $[
|
|
2945
|
+
children: [t12, t13]
|
|
2946
|
+
}), $[39] = t12, $[40] = t13, $[41] = t14) : t14 = $[41], t14;
|
|
2206
2947
|
}
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
* studio preview as much room as possible, while the themes stack in a single
|
|
2210
|
-
* column of preview cards and the editor fits a swatch next to its label.
|
|
2211
|
-
*/
|
|
2948
|
+
var content = "bgn4np4", frame = "bgn4np3", sidebar = "bgn4np2";
|
|
2949
|
+
/** How far one arrow key press resizes the sidebar */
|
|
2212
2950
|
const WIDTH_STORAGE_KEY = "sanityStudio:themer:width";
|
|
2213
2951
|
function clampWidth(width) {
|
|
2214
2952
|
return Math.min(400, Math.max(200, Math.round(width)));
|
|
@@ -2226,25 +2964,16 @@ function writeStoredWidth(width) {
|
|
|
2226
2964
|
width === 200 ? localStorage.removeItem(WIDTH_STORAGE_KEY) : localStorage.setItem(WIDTH_STORAGE_KEY, String(width));
|
|
2227
2965
|
} catch {}
|
|
2228
2966
|
}
|
|
2229
|
-
const Sidebar = styled(Layer).withConfig({
|
|
2230
|
-
displayName: "Sidebar",
|
|
2231
|
-
componentId: "sc-ryrt6y-0"
|
|
2232
|
-
})`flex:none;`, Frame = styled(Card).withConfig({
|
|
2233
|
-
displayName: "Frame",
|
|
2234
|
-
componentId: "sc-ryrt6y-1"
|
|
2235
|
-
})`position:relative;`, ResizeHandle = styled.div.withConfig({
|
|
2236
|
-
displayName: "ResizeHandle",
|
|
2237
|
-
componentId: "sc-ryrt6y-2"
|
|
2238
|
-
})`position:absolute;top:0;bottom:0;left:-3px;z-index:1;width:7px;cursor:col-resize;touch-action:none;&::after{content:'';position:absolute;top:0;bottom:0;left:2px;width:3px;background:var(--card-focus-ring-color);opacity:0;transition:opacity 100ms;}&:hover::after,&:focus-visible::after,&[data-dragging='true']::after{opacity:1;}&:focus{outline:none;}`;
|
|
2239
2967
|
/**
|
|
2240
2968
|
* The themer sidebar, in a layer along the right edge of the Studio. Its left
|
|
2241
2969
|
* edge drags (or arrow-keys) it wider, up to twice its default width — the
|
|
2242
|
-
* width sticks between sessions.
|
|
2970
|
+
* width sticks between sessions. As an overlay (small screens) it covers the
|
|
2971
|
+
* Studio edge to edge instead, with nothing to resize.
|
|
2243
2972
|
*
|
|
2244
2973
|
* @internal
|
|
2245
2974
|
*/
|
|
2246
|
-
function ResizableSidebar() {
|
|
2247
|
-
let $ = c(
|
|
2975
|
+
function ResizableSidebar(props) {
|
|
2976
|
+
let $ = c(24), { overlay } = props, [width, setWidth] = useState(readStoredWidth), [dragging, setDragging] = useState(!1), drag = useRef(null), t0, t1;
|
|
2248
2977
|
$[0] === width ? (t0 = $[1], t1 = $[2]) : (t0 = () => writeStoredWidth(width), t1 = [width], $[0] = width, $[1] = t0, $[2] = t1), useEffect(t0, t1);
|
|
2249
2978
|
let t2;
|
|
2250
2979
|
$[3] === width ? t2 = $[4] : (t2 = (event) => {
|
|
@@ -2273,18 +3002,17 @@ function ResizableSidebar() {
|
|
|
2273
3002
|
step !== void 0 && (event_2.preventDefault(), setWidth((current) => clampWidth(current + step)));
|
|
2274
3003
|
}, $[7] = t5) : t5 = $[7];
|
|
2275
3004
|
let handleKeyDown = t5, t6;
|
|
2276
|
-
$[8]
|
|
2277
|
-
let t7;
|
|
2278
|
-
$[
|
|
2279
|
-
let t8;
|
|
2280
|
-
$[11] !== dragging || $[12] !== handlePointerDown || $[13] !== width ? (t8 = /* @__PURE__ */ jsx(ResizeHandle, {
|
|
3005
|
+
$[8] !== overlay || $[9] !== width ? (t6 = overlay ? void 0 : { width }, $[8] = overlay, $[9] = width, $[10] = t6) : t6 = $[10];
|
|
3006
|
+
let t7 = !overlay, t8;
|
|
3007
|
+
$[11] !== dragging || $[12] !== handlePointerDown || $[13] !== overlay || $[14] !== width ? (t8 = !overlay && /* @__PURE__ */ jsx("div", {
|
|
2281
3008
|
"aria-label": "Resize the themer",
|
|
3009
|
+
className: "bgn4np5",
|
|
2282
3010
|
"aria-orientation": "vertical",
|
|
2283
3011
|
"aria-valuemax": 400,
|
|
2284
3012
|
"aria-valuemin": 200,
|
|
2285
3013
|
"aria-valuenow": width,
|
|
2286
3014
|
"data-dragging": dragging,
|
|
2287
|
-
onDoubleClick:
|
|
3015
|
+
onDoubleClick: () => setWidth(200),
|
|
2288
3016
|
onKeyDown: handleKeyDown,
|
|
2289
3017
|
onPointerCancel: handlePointerUp,
|
|
2290
3018
|
onPointerDown: handlePointerDown,
|
|
@@ -2292,148 +3020,94 @@ function ResizableSidebar() {
|
|
|
2292
3020
|
onPointerUp: handlePointerUp,
|
|
2293
3021
|
role: "separator",
|
|
2294
3022
|
tabIndex: 0
|
|
2295
|
-
}), $[11] = dragging, $[12] = handlePointerDown, $[13] =
|
|
3023
|
+
}), $[11] = dragging, $[12] = handlePointerDown, $[13] = overlay, $[14] = width, $[15] = t8) : t8 = $[15];
|
|
2296
3024
|
let t9;
|
|
2297
|
-
$[
|
|
3025
|
+
$[16] === Symbol.for("react.memo_cache_sentinel") ? (t9 = /* @__PURE__ */ jsx(Box, {
|
|
3026
|
+
className: content,
|
|
2298
3027
|
height: "fill",
|
|
2299
3028
|
overflow: "hidden",
|
|
2300
3029
|
children: /* @__PURE__ */ jsx(ThemerSidebar, {})
|
|
2301
|
-
}), $[
|
|
3030
|
+
}), $[16] = t9) : t9 = $[16];
|
|
2302
3031
|
let t10;
|
|
2303
|
-
$[
|
|
2304
|
-
borderLeft:
|
|
3032
|
+
$[17] !== t7 || $[18] !== t8 ? (t10 = /* @__PURE__ */ jsxs(Card, {
|
|
3033
|
+
borderLeft: t7,
|
|
3034
|
+
className: frame,
|
|
2305
3035
|
height: "fill",
|
|
2306
3036
|
children: [t8, t9]
|
|
2307
|
-
}), $[
|
|
3037
|
+
}), $[17] = t7, $[18] = t8, $[19] = t10) : t10 = $[19];
|
|
2308
3038
|
let t11;
|
|
2309
|
-
return $[
|
|
3039
|
+
return $[20] !== overlay || $[21] !== t10 || $[22] !== t6 ? (t11 = /* @__PURE__ */ jsx(Layer, {
|
|
3040
|
+
className: sidebar,
|
|
3041
|
+
"data-overlay": overlay,
|
|
2310
3042
|
style: t6,
|
|
2311
3043
|
zOffset: 100,
|
|
2312
3044
|
children: t10
|
|
2313
|
-
}), $[
|
|
3045
|
+
}), $[20] = overlay, $[21] = t10, $[22] = t6, $[23] = t11) : t11 = $[23], t11;
|
|
2314
3046
|
}
|
|
2315
|
-
const
|
|
2316
|
-
function
|
|
2317
|
-
|
|
3047
|
+
const QUERY = "(prefers-reduced-motion: reduce)";
|
|
3048
|
+
function subscribe(onChange) {
|
|
3049
|
+
let media = matchMedia(QUERY);
|
|
3050
|
+
return media.addEventListener("change", onChange), () => media.removeEventListener("change", onChange);
|
|
2318
3051
|
}
|
|
2319
|
-
function
|
|
2320
|
-
return
|
|
3052
|
+
function getSnapshot() {
|
|
3053
|
+
return matchMedia(QUERY).matches;
|
|
2321
3054
|
}
|
|
2322
|
-
function
|
|
2323
|
-
|
|
2324
|
-
if (!value || typeof value != "object") return options;
|
|
2325
|
-
let accent = sanitizeColor(Reflect.get(value, "accent")), text = sanitizeColor(Reflect.get(value, "text")), background = sanitizeColor(Reflect.get(value, "background")), contrast = sanitizeContrast(Reflect.get(value, "contrast"));
|
|
2326
|
-
return accent && (options.accent = accent), text && (options.text = text), background && (options.background = background), contrast !== null && (options.contrast = contrast), options;
|
|
3055
|
+
function getServerSnapshot() {
|
|
3056
|
+
return !1;
|
|
2327
3057
|
}
|
|
2328
3058
|
/**
|
|
2329
|
-
*
|
|
2330
|
-
*
|
|
2331
|
-
*
|
|
3059
|
+
* Whether the user prefers reduced motion — live, so that turning the
|
|
3060
|
+
* setting on while the Studio is open takes effect right away.
|
|
3061
|
+
*
|
|
3062
|
+
* @internal
|
|
2332
3063
|
*/
|
|
2333
|
-
function
|
|
2334
|
-
|
|
2335
|
-
if (!accent) return null;
|
|
2336
|
-
let shared = { accent }, text = sanitizeColor(Reflect.get(value, "text")), contrast = sanitizeContrast(Reflect.get(value, "contrast"));
|
|
2337
|
-
text && (shared.text = text), contrast !== null && (shared.contrast = contrast);
|
|
2338
|
-
let backgrounds = Reflect.get(value, "background"), options = {};
|
|
2339
|
-
for (let scheme of SCHEMES) {
|
|
2340
|
-
let background = backgrounds && typeof backgrounds == "object" ? sanitizeColor(Reflect.get(backgrounds, scheme)) : null;
|
|
2341
|
-
options[scheme] = background ? {
|
|
2342
|
-
...shared,
|
|
2343
|
-
background
|
|
2344
|
-
} : { ...shared };
|
|
2345
|
-
}
|
|
2346
|
-
return options;
|
|
2347
|
-
}
|
|
2348
|
-
function sanitizeOptions(value) {
|
|
2349
|
-
if (!value || typeof value != "object") return null;
|
|
2350
|
-
if ("accent" in value) return sanitizeFlatOptions(value);
|
|
2351
|
-
let options = {};
|
|
2352
|
-
for (let scheme of SCHEMES) {
|
|
2353
|
-
let schemeOptions = sanitizeSchemeOptions(Reflect.get(value, scheme));
|
|
2354
|
-
Object.keys(schemeOptions).length > 0 && (options[scheme] = schemeOptions);
|
|
2355
|
-
}
|
|
2356
|
-
return options;
|
|
2357
|
-
}
|
|
2358
|
-
function isReservedSlug(slug) {
|
|
2359
|
-
return slug === "config" || presets.some((preset) => preset.slug === slug);
|
|
2360
|
-
}
|
|
2361
|
-
function sanitizeCustomTheme(value) {
|
|
2362
|
-
if (!value || typeof value != "object") return null;
|
|
2363
|
-
let slug = Reflect.get(value, "slug");
|
|
2364
|
-
if (typeof slug != "string" || !slug || isReservedSlug(slug)) return null;
|
|
2365
|
-
let options = sanitizeOptions(Reflect.get(value, "options"));
|
|
2366
|
-
if (!options) return null;
|
|
2367
|
-
let title = Reflect.get(value, "title"), palette = sanitizePalette(Reflect.get(value, "palette"));
|
|
2368
|
-
return {
|
|
2369
|
-
slug,
|
|
2370
|
-
title: displayTitle(typeof title == "string" ? title : ""),
|
|
2371
|
-
options,
|
|
2372
|
-
...palette ? { palette } : {}
|
|
2373
|
-
};
|
|
2374
|
-
}
|
|
2375
|
-
function sanitizePalette(value) {
|
|
2376
|
-
if (!value || typeof value != "object") return null;
|
|
2377
|
-
let palette = {}, swatches = 0;
|
|
2378
|
-
for (let key of IMAGE_PALETTE_KEYS) {
|
|
2379
|
-
let swatch = sanitizeColor(Reflect.get(value, key));
|
|
2380
|
-
palette[key] = swatch, swatch && swatches++;
|
|
2381
|
-
}
|
|
2382
|
-
return swatches > 0 ? palette : null;
|
|
2383
|
-
}
|
|
2384
|
-
function sanitizeState(value) {
|
|
2385
|
-
if (!value || typeof value != "object") return initialThemerState;
|
|
2386
|
-
let custom = [], rawCustom = Reflect.get(value, "custom");
|
|
2387
|
-
if (Array.isArray(rawCustom)) for (let item of rawCustom) {
|
|
2388
|
-
let theme = sanitizeCustomTheme(item);
|
|
2389
|
-
theme && !custom.some((existing) => existing.slug === theme.slug) && custom.push(theme);
|
|
2390
|
-
}
|
|
2391
|
-
let removed = [], rawRemoved = Reflect.get(value, "removed");
|
|
2392
|
-
if (Array.isArray(rawRemoved)) for (let slug of rawRemoved) typeof slug == "string" && slug !== "config" && (presets.some((preset) => preset.slug === slug) || custom.some((theme) => theme.slug === slug)) && !removed.includes(slug) && removed.push(slug);
|
|
2393
|
-
let rawActive = Reflect.get(value, "active");
|
|
2394
|
-
return {
|
|
2395
|
-
active: typeof rawActive == "string" ? rawActive : null,
|
|
2396
|
-
custom,
|
|
2397
|
-
removed
|
|
2398
|
-
};
|
|
2399
|
-
}
|
|
2400
|
-
function readLegacyState() {
|
|
2401
|
-
let raw = localStorage.getItem(LEGACY_STORAGE_KEY);
|
|
2402
|
-
if (!raw) return null;
|
|
2403
|
-
let options = sanitizeOptions(JSON.parse(raw));
|
|
2404
|
-
if (!options) return null;
|
|
2405
|
-
let theme = createCustomTheme("Draft theme", options);
|
|
2406
|
-
return {
|
|
2407
|
-
active: theme.slug,
|
|
2408
|
-
custom: [theme],
|
|
2409
|
-
removed: []
|
|
2410
|
-
};
|
|
3064
|
+
function usePrefersReducedMotion() {
|
|
3065
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
2411
3066
|
}
|
|
2412
3067
|
/**
|
|
2413
|
-
*
|
|
2414
|
-
*
|
|
2415
|
-
*
|
|
3068
|
+
* The height of the Studio navbar inside the given element, in pixels — kept
|
|
3069
|
+
* up to date as the navbar renders, remounts and resizes, and `null` until
|
|
3070
|
+
* there is one. The themer's header takes this height, so that its bottom
|
|
3071
|
+
* border lines up with the navbar's whatever height the Studio version, its
|
|
3072
|
+
* breakpoint or a custom navbar gives it.
|
|
2416
3073
|
*
|
|
2417
3074
|
* @internal
|
|
2418
3075
|
*/
|
|
2419
|
-
function
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
let
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
3076
|
+
function useStudioNavbarHeight(ref) {
|
|
3077
|
+
let $ = c(3), [height, setHeight] = useState(null), t0, t1;
|
|
3078
|
+
return $[0] === ref ? (t0 = $[1], t1 = $[2]) : (t0 = () => {
|
|
3079
|
+
let root = ref.current;
|
|
3080
|
+
if (!root) return;
|
|
3081
|
+
let navbar = null, resizeObserver = new ResizeObserver(() => {
|
|
3082
|
+
navbar && setHeight(navbar.getBoundingClientRect().height);
|
|
3083
|
+
}), observeNavbar = () => {
|
|
3084
|
+
let next = root.querySelector("[data-testid=\"studio-navbar\"]");
|
|
3085
|
+
next !== navbar && (navbar && resizeObserver.unobserve(navbar), navbar = next, navbar ? (resizeObserver.observe(navbar), setHeight(navbar.getBoundingClientRect().height)) : setHeight(null));
|
|
3086
|
+
}, mutationObserver = new MutationObserver(observeNavbar);
|
|
3087
|
+
return mutationObserver.observe(root, {
|
|
3088
|
+
childList: !0,
|
|
3089
|
+
subtree: !0
|
|
3090
|
+
}), observeNavbar(), () => {
|
|
3091
|
+
mutationObserver.disconnect(), resizeObserver.disconnect();
|
|
3092
|
+
};
|
|
3093
|
+
}, t1 = [ref], $[0] = ref, $[1] = t0, $[2] = t1), useEffect(t0, t1), height;
|
|
3094
|
+
}
|
|
3095
|
+
var layout = "_1yq4ar78", panelTransitionClasses = {
|
|
3096
|
+
slideIn: "_1yq4ar76",
|
|
3097
|
+
slideOut: "_1yq4ar77"
|
|
3098
|
+
}, splitTransitionClasses = {
|
|
3099
|
+
resize: "_1yq4ar70",
|
|
3100
|
+
crossfade: "_1yq4ar71",
|
|
3101
|
+
slideIn: "_1yq4ar72",
|
|
3102
|
+
slideOut: "_1yq4ar73",
|
|
3103
|
+
dropIn: "_1yq4ar74",
|
|
3104
|
+
dropOut: "_1yq4ar75"
|
|
3105
|
+
}, studioScheme = {
|
|
3106
|
+
light: "_1yq4ar79",
|
|
3107
|
+
dark: "_1yq4ar7a"
|
|
3108
|
+
};
|
|
2435
3109
|
function sameStoredState(a, b) {
|
|
2436
|
-
return a.active === b.active && a.custom === b.custom && a.removed === b.removed;
|
|
3110
|
+
return a.active === b.active && a.custom === b.custom && a.removed === b.removed && a.order === b.order;
|
|
2437
3111
|
}
|
|
2438
3112
|
function selectView(snapshot) {
|
|
2439
3113
|
let { editing } = snapshot.context;
|
|
@@ -2455,13 +3129,21 @@ function sameView(a, b) {
|
|
|
2455
3129
|
* `layout` level rather than in `activeToolLayout` because the split preview
|
|
2456
3130
|
* renders the Studio twice, and the sidebar must not come along.
|
|
2457
3131
|
*
|
|
2458
|
-
* The
|
|
2459
|
-
*
|
|
3132
|
+
* The Studio next to the sidebar always follows the appearance setting
|
|
3133
|
+
* (light/dark/system) and the picked theme like any other theme would. The
|
|
3134
|
+
* split preview adds a second copy in the opposite scheme on the far side —
|
|
3135
|
+
* or on top, on small screens — through React's view transitions (React
|
|
3136
|
+
* 19.3), styled in `ThemerLayout.css.ts`.
|
|
3137
|
+
*
|
|
3138
|
+
* The machine says what shows and when the layout is in motion (its `panel`,
|
|
3139
|
+
* `split` and `moving` tags); the layout defers what shows, which puts the
|
|
3140
|
+
* panel's and the copy's mounts in a transition — what lets React animate
|
|
3141
|
+
* them — and picks the view transition classes from the tags.
|
|
2460
3142
|
*
|
|
2461
3143
|
* @internal
|
|
2462
3144
|
*/
|
|
2463
3145
|
function ThemerLayout(props) {
|
|
2464
|
-
let $ = c(
|
|
3146
|
+
let $ = c(85), { baseOptions, ...layoutProps } = props, t0;
|
|
2465
3147
|
$[0] === baseOptions ? t0 = $[1] : (t0 = () => ({
|
|
2466
3148
|
baseOptions,
|
|
2467
3149
|
stored: readStoredState()
|
|
@@ -2469,38 +3151,34 @@ function ThemerLayout(props) {
|
|
|
2469
3151
|
let [input] = useState(t0), t1;
|
|
2470
3152
|
$[2] === input ? t1 = $[3] : (t1 = { input }, $[2] = input, $[3] = t1);
|
|
2471
3153
|
let [snapshot, send, actorRef] = useActor(themerMachine, t1), stored = useSelector(actorRef, selectStoredState, sameStoredState), view = useSelector(actorRef, selectView, sameView), t2;
|
|
2472
|
-
$[4] === snapshot ? t2 = $[5] : (t2 = snapshot.
|
|
3154
|
+
$[4] === snapshot ? t2 = $[5] : (t2 = snapshot.hasTag("panel"), $[4] = snapshot, $[5] = t2);
|
|
2473
3155
|
let open = t2, t3;
|
|
2474
|
-
$[6] === snapshot ? t3 = $[7] : (t3 = snapshot.
|
|
2475
|
-
let split = t3,
|
|
2476
|
-
$[8] ===
|
|
2477
|
-
let
|
|
2478
|
-
$[
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
let
|
|
2484
|
-
$[
|
|
2485
|
-
|
|
2486
|
-
}, t9 = [], $[14] = t8, $[15] = t9) : (t8 = $[14], t9 = $[15]), useEffect(t8, t9);
|
|
2487
|
-
let t10;
|
|
2488
|
-
$[16] !== baseOptions || $[17] !== stored ? (t10 = resolveThemes(stored, baseOptions), $[16] = baseOptions, $[17] = stored, $[18] = t10) : t10 = $[18];
|
|
2489
|
-
let { themes, removed, active } = t10, activeOptions = active.source === "config" ? null : active.options, t11;
|
|
2490
|
-
$[19] === activeOptions ? t11 = $[20] : (t11 = activeOptions === null ? null : buildTheme(activeOptions), $[19] = activeOptions, $[20] = t11);
|
|
2491
|
-
let theme = t11, scheme = useColorSchemeValue(), t12;
|
|
2492
|
-
$[21] !== scheme || $[22] !== theme?.v2?.color ? (t12 = () => {
|
|
2493
|
-
let background = theme?.v2?.color[scheme].default.bg;
|
|
3156
|
+
$[6] === snapshot ? t3 = $[7] : (t3 = snapshot.hasTag("split"), $[6] = snapshot, $[7] = t3);
|
|
3157
|
+
let split = t3, t4;
|
|
3158
|
+
$[8] === snapshot ? t4 = $[9] : (t4 = snapshot.hasTag("moving"), $[8] = snapshot, $[9] = t4);
|
|
3159
|
+
let moving = t4, t5;
|
|
3160
|
+
$[10] === snapshot ? t5 = $[11] : (t5 = snapshot.hasTag("switching"), $[10] = snapshot, $[11] = t5);
|
|
3161
|
+
let switching = t5, { images } = snapshot.context, mobile = useMediaIndex() <= 1, studioRef = useRef(null), navbarHeight = useStudioNavbarHeight(studioRef), reduceMotion = usePrefersReducedMotion(), deferredOpen = useDeferredValue(reduceMotion ? null : open), deferredSplit = useDeferredValue(reduceMotion ? null : split), shownOpen = deferredOpen ?? open, shownSplit = deferredSplit ?? split, t6;
|
|
3162
|
+
$[12] !== baseOptions || $[13] !== stored ? (t6 = resolveThemes(stored, baseOptions), $[12] = baseOptions, $[13] = stored, $[14] = t6) : t6 = $[14];
|
|
3163
|
+
let { themes, removed, active } = t6, activeOptions = active.source === "config" ? null : active.options, t7;
|
|
3164
|
+
$[15] === activeOptions ? t7 = $[16] : (t7 = activeOptions === null ? null : buildTheme(activeOptions), $[15] = activeOptions, $[16] = t7);
|
|
3165
|
+
let theme = t7, deferredTheme = useDeferredValue(reduceMotion ? void 0 : theme), shownTheme = deferredTheme === void 0 ? theme : deferredTheme, scheme = useColorSchemeValue(), oppositeScheme = scheme === "dark" ? "light" : "dark", t8;
|
|
3166
|
+
$[17] !== scheme || $[18] !== shownTheme?.v2?.color ? (t8 = () => {
|
|
3167
|
+
let background = shownTheme?.v2?.color[scheme].default.bg;
|
|
2494
3168
|
if (background === void 0) return;
|
|
2495
3169
|
let { style } = document.body, previous = style.backgroundColor;
|
|
2496
3170
|
return style.backgroundColor = background, () => {
|
|
2497
3171
|
style.backgroundColor = previous;
|
|
2498
3172
|
};
|
|
2499
|
-
}, $[
|
|
2500
|
-
let
|
|
2501
|
-
$[
|
|
2502
|
-
let
|
|
2503
|
-
$[
|
|
3173
|
+
}, $[17] = scheme, $[18] = shownTheme?.v2?.color, $[19] = t8) : t8 = $[19];
|
|
3174
|
+
let t9;
|
|
3175
|
+
$[20] !== scheme || $[21] !== shownTheme ? (t9 = [scheme, shownTheme], $[20] = scheme, $[21] = shownTheme, $[22] = t9) : t9 = $[22], useEffect(t8, t9);
|
|
3176
|
+
let t10, t11;
|
|
3177
|
+
$[23] === actorRef ? (t10 = $[24], t11 = $[25]) : (t10 = () => () => {
|
|
3178
|
+
for (let url of Object.values(actorRef.getSnapshot().context.images)) URL.revokeObjectURL(url);
|
|
3179
|
+
}, t11 = [actorRef], $[23] = actorRef, $[24] = t10, $[25] = t11), useEffect(t10, t11);
|
|
3180
|
+
let t12;
|
|
3181
|
+
$[26] !== active || $[27] !== baseOptions || $[28] !== images || $[29] !== mobile || $[30] !== navbarHeight || $[31] !== open || $[32] !== removed || $[33] !== send || $[34] !== split || $[35] !== themes || $[36] !== view ? (t12 = {
|
|
2504
3182
|
baseOptions,
|
|
2505
3183
|
themes,
|
|
2506
3184
|
removed,
|
|
@@ -2509,41 +3187,98 @@ function ThemerLayout(props) {
|
|
|
2509
3187
|
view,
|
|
2510
3188
|
open,
|
|
2511
3189
|
split,
|
|
3190
|
+
mobile,
|
|
3191
|
+
navbarHeight,
|
|
2512
3192
|
send
|
|
2513
|
-
}, $[
|
|
2514
|
-
let context =
|
|
2515
|
-
$[
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
3193
|
+
}, $[26] = active, $[27] = baseOptions, $[28] = images, $[29] = mobile, $[30] = navbarHeight, $[31] = open, $[32] = removed, $[33] = send, $[34] = split, $[35] = themes, $[36] = view, $[37] = t12) : t12 = $[37];
|
|
3194
|
+
let context = t12, studio = layoutProps.renderDefault(layoutProps), t13;
|
|
3195
|
+
$[38] === send ? t13 = $[39] : (t13 = () => send({ type: "layout.transitioned" }), $[38] = send, $[39] = t13);
|
|
3196
|
+
let transitioned = t13, t14;
|
|
3197
|
+
$[40] !== mobile || $[41] !== moving || $[42] !== reduceMotion || $[43] !== switching ? (t14 = reduceMotion ? {
|
|
3198
|
+
copyEnter: "none",
|
|
3199
|
+
copyExit: "none",
|
|
3200
|
+
panelEnter: "none",
|
|
3201
|
+
panelExit: "none",
|
|
3202
|
+
update: "none",
|
|
3203
|
+
studioUpdate: "none"
|
|
3204
|
+
} : {
|
|
3205
|
+
copyEnter: mobile ? splitTransitionClasses.dropIn : splitTransitionClasses.slideIn,
|
|
3206
|
+
copyExit: mobile ? splitTransitionClasses.dropOut : splitTransitionClasses.slideOut,
|
|
3207
|
+
panelEnter: panelTransitionClasses.slideIn,
|
|
3208
|
+
panelExit: panelTransitionClasses.slideOut,
|
|
3209
|
+
update: switching ? splitTransitionClasses.crossfade : "none",
|
|
3210
|
+
studioUpdate: moving ? splitTransitionClasses.resize : switching ? splitTransitionClasses.crossfade : "none"
|
|
3211
|
+
}, $[40] = mobile, $[41] = moving, $[42] = reduceMotion, $[43] = switching, $[44] = t14) : t14 = $[44];
|
|
3212
|
+
let classes = t14, t15 = mobile ? "column" : "row", t16;
|
|
3213
|
+
$[45] !== classes.copyEnter || $[46] !== classes.copyExit || $[47] !== classes.update || $[48] !== mobile || $[49] !== oppositeScheme || $[50] !== shownOpen || $[51] !== shownSplit || $[52] !== shownTheme || $[53] !== studio || $[54] !== transitioned ? (t16 = shownOpen && /* @__PURE__ */ jsx(Activity, {
|
|
3214
|
+
mode: shownSplit ? "visible" : "hidden",
|
|
3215
|
+
children: /* @__PURE__ */ jsx(ViewTransition, {
|
|
3216
|
+
enter: classes.copyEnter,
|
|
3217
|
+
exit: classes.copyExit,
|
|
3218
|
+
onEnter: transitioned,
|
|
3219
|
+
onExit: transitioned,
|
|
3220
|
+
onUpdate: transitioned,
|
|
3221
|
+
update: classes.update,
|
|
3222
|
+
children: /* @__PURE__ */ jsx(StudioPreview, {
|
|
3223
|
+
borderBottom: mobile,
|
|
3224
|
+
borderRight: !mobile,
|
|
3225
|
+
scheme: oppositeScheme,
|
|
3226
|
+
theme: shownTheme,
|
|
3227
|
+
children: studio
|
|
3228
|
+
})
|
|
3229
|
+
}, "opposite")
|
|
3230
|
+
}), $[45] = classes.copyEnter, $[46] = classes.copyExit, $[47] = classes.update, $[48] = mobile, $[49] = oppositeScheme, $[50] = shownOpen, $[51] = shownSplit, $[52] = shownTheme, $[53] = studio, $[54] = transitioned, $[55] = t16) : t16 = $[55];
|
|
2520
3231
|
let t17;
|
|
2521
|
-
$[
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
theme,
|
|
3232
|
+
$[56] !== shownTheme || $[57] !== studio ? (t17 = /* @__PURE__ */ jsx(StudioPreview, {
|
|
3233
|
+
ref: studioRef,
|
|
3234
|
+
theme: shownTheme,
|
|
2525
3235
|
children: studio
|
|
2526
|
-
}), $[
|
|
3236
|
+
}), $[56] = shownTheme, $[57] = studio, $[58] = t17) : t17 = $[58];
|
|
2527
3237
|
let t18;
|
|
2528
|
-
$[
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
3238
|
+
$[59] !== classes.studioUpdate || $[60] !== t17 || $[61] !== transitioned ? (t18 = /* @__PURE__ */ jsx(ViewTransition, {
|
|
3239
|
+
onUpdate: transitioned,
|
|
3240
|
+
update: classes.studioUpdate,
|
|
3241
|
+
children: t17
|
|
3242
|
+
}, "primary"), $[59] = classes.studioUpdate, $[60] = t17, $[61] = transitioned, $[62] = t18) : t18 = $[62];
|
|
3243
|
+
let t19 = shownOpen ? "visible" : "hidden", t20 = shownTheme ?? void 0, t21;
|
|
3244
|
+
$[63] === mobile ? t21 = $[64] : (t21 = /* @__PURE__ */ jsx(ResizableSidebar, { overlay: mobile }), $[63] = mobile, $[64] = t21);
|
|
3245
|
+
let t22;
|
|
3246
|
+
$[65] !== t20 || $[66] !== t21 ? (t22 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
3247
|
+
theme: t20,
|
|
3248
|
+
children: t21
|
|
3249
|
+
}), $[65] = t20, $[66] = t21, $[67] = t22) : t22 = $[67];
|
|
3250
|
+
let t23;
|
|
3251
|
+
$[68] !== classes.panelEnter || $[69] !== classes.panelExit || $[70] !== classes.update || $[71] !== t22 || $[72] !== transitioned ? (t23 = /* @__PURE__ */ jsx(ViewTransition, {
|
|
3252
|
+
enter: classes.panelEnter,
|
|
3253
|
+
exit: classes.panelExit,
|
|
3254
|
+
onEnter: transitioned,
|
|
3255
|
+
onExit: transitioned,
|
|
3256
|
+
onUpdate: transitioned,
|
|
3257
|
+
update: classes.update,
|
|
3258
|
+
children: t22
|
|
3259
|
+
}, "panel"), $[68] = classes.panelEnter, $[69] = classes.panelExit, $[70] = classes.update, $[71] = t22, $[72] = transitioned, $[73] = t23) : t23 = $[73];
|
|
3260
|
+
let t24;
|
|
3261
|
+
$[74] !== t19 || $[75] !== t23 ? (t24 = /* @__PURE__ */ jsx(Activity, {
|
|
3262
|
+
mode: t19,
|
|
3263
|
+
children: t23
|
|
3264
|
+
}), $[74] = t19, $[75] = t23, $[76] = t24) : t24 = $[76];
|
|
3265
|
+
let t25;
|
|
3266
|
+
$[77] !== t15 || $[78] !== t16 || $[79] !== t18 || $[80] !== t24 ? (t25 = /* @__PURE__ */ jsxs(Flex, {
|
|
3267
|
+
className: layout,
|
|
3268
|
+
direction: t15,
|
|
2534
3269
|
height: "fill",
|
|
2535
3270
|
sizing: "border",
|
|
2536
3271
|
children: [
|
|
2537
3272
|
t16,
|
|
2538
|
-
|
|
2539
|
-
|
|
3273
|
+
t18,
|
|
3274
|
+
t24
|
|
2540
3275
|
]
|
|
2541
|
-
}), $[
|
|
2542
|
-
let
|
|
2543
|
-
return $[
|
|
3276
|
+
}), $[77] = t15, $[78] = t16, $[79] = t18, $[80] = t24, $[81] = t25) : t25 = $[81];
|
|
3277
|
+
let t26;
|
|
3278
|
+
return $[82] !== context || $[83] !== t25 ? (t26 = /* @__PURE__ */ jsx(ThemerContext.Provider, {
|
|
2544
3279
|
value: context,
|
|
2545
|
-
children:
|
|
2546
|
-
}), $[
|
|
3280
|
+
children: t25
|
|
3281
|
+
}), $[82] = context, $[83] = t25, $[84] = t26) : t26 = $[84], t26;
|
|
2547
3282
|
}
|
|
2548
3283
|
/**
|
|
2549
3284
|
* One copy of the Studio, in the given color scheme — or, without one, in the
|
|
@@ -2557,17 +3292,17 @@ function ThemerLayout(props) {
|
|
|
2557
3292
|
* keeps native form controls and scrollbars in step with it.
|
|
2558
3293
|
*/
|
|
2559
3294
|
function StudioPreview(props) {
|
|
2560
|
-
let $ = c(10), {
|
|
2561
|
-
$[0]
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
3295
|
+
let $ = c(10), { borderBottom, borderRight, children, ref, scheme, theme } = props, t0 = theme ?? void 0, t1 = scheme ? studioScheme[scheme] : void 0, t2;
|
|
3296
|
+
$[0] !== borderBottom || $[1] !== borderRight || $[2] !== children || $[3] !== ref || $[4] !== t1 ? (t2 = /* @__PURE__ */ jsx(Card, {
|
|
3297
|
+
borderBottom,
|
|
3298
|
+
borderRight,
|
|
3299
|
+
className: t1,
|
|
2565
3300
|
flex: 1,
|
|
2566
3301
|
height: "fill",
|
|
2567
3302
|
overflow: "hidden",
|
|
2568
|
-
|
|
3303
|
+
ref,
|
|
2569
3304
|
children
|
|
2570
|
-
}), $[2] =
|
|
3305
|
+
}), $[0] = borderBottom, $[1] = borderRight, $[2] = children, $[3] = ref, $[4] = t1, $[5] = t2) : t2 = $[5];
|
|
2571
3306
|
let t3;
|
|
2572
3307
|
return $[6] !== scheme || $[7] !== t0 || $[8] !== t2 ? (t3 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
2573
3308
|
scheme,
|