@sanity/themer 0.3.16 → 0.5.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 +19 -13
- package/dist/index.d.ts +42 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/options-CU-emn_p.d.ts +69 -0
- package/dist/options-CU-emn_p.d.ts.map +1 -0
- package/dist/{presets-By3s-D-S.js → presets-CqBgS3A-.js} +133 -98
- package/dist/presets-CqBgS3A-.js.map +1 -0
- package/dist/tool.d.ts +12 -7
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js +2467 -523
- package/dist/tool.js.map +1 -1
- package/package.json +5 -3
- package/dist/options-BaqJJgRs.d.ts +0 -59
- package/dist/options-BaqJJgRs.d.ts.map +0 -1
- package/dist/presets-By3s-D-S.js.map +0 -1
package/dist/tool.js
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { COLOR_TINTS } from "@sanity/color";
|
|
1
|
+
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";
|
|
3
2
|
import { c } from "react-compiler-runtime";
|
|
4
|
-
import { definePlugin } from "sanity";
|
|
5
|
-
import { Box, Button, Card,
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
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 { 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";
|
|
9
|
+
import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
|
|
8
10
|
import { CloseIcon } from "@sanity/icons/Close";
|
|
11
|
+
import { CodeBlockIcon } from "@sanity/icons/CodeBlock";
|
|
12
|
+
import { SplitVerticalIcon } from "@sanity/icons/SplitVertical";
|
|
13
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
14
|
import { ResetIcon } from "@sanity/icons/Reset";
|
|
10
|
-
import {
|
|
15
|
+
import { TrashIcon } from "@sanity/icons/Trash";
|
|
16
|
+
import { SparklesIcon } from "@sanity/icons/Sparkles";
|
|
17
|
+
import { Tooltip } from "@sanity/ui/tooltip";
|
|
18
|
+
import { ImageIcon } from "@sanity/icons/Image";
|
|
11
19
|
import { useToast } from "@sanity/ui/toast";
|
|
20
|
+
import { AddIcon } from "@sanity/icons/Add";
|
|
21
|
+
import { RestoreIcon } from "@sanity/icons/Restore";
|
|
22
|
+
import { CopyIcon } from "@sanity/icons/Copy";
|
|
23
|
+
import { EditIcon } from "@sanity/icons/Edit";
|
|
24
|
+
import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
|
|
25
|
+
import { Menu, MenuButton, MenuDivider, MenuItem } from "@sanity/ui/menu";
|
|
26
|
+
import { ClipboardIcon } from "@sanity/icons/Clipboard";
|
|
27
|
+
import { Code } from "@sanity/ui/code";
|
|
12
28
|
import { registerLanguage } from "react-refractor";
|
|
13
29
|
import typescript from "refractor/typescript";
|
|
14
|
-
import { styled } from "styled-components";
|
|
15
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
30
|
import { ColorWheelIcon } from "@sanity/icons/ColorWheel";
|
|
17
|
-
import { Tooltip } from "@sanity/ui/tooltip";
|
|
18
31
|
/** @internal */
|
|
19
32
|
const ThemerContext = createContext(null);
|
|
20
33
|
/** @internal */
|
|
@@ -25,18 +38,21 @@ function useThemer() {
|
|
|
25
38
|
}
|
|
26
39
|
/**
|
|
27
40
|
* Reduces theme options to the minimal object that recreates them through
|
|
28
|
-
* `buildTheme`: the
|
|
29
|
-
*
|
|
30
|
-
* the
|
|
31
|
-
*
|
|
41
|
+
* `buildTheme`: in each scheme the accent is dropped when it is the stock
|
|
42
|
+
* one, the text color when it matches the one derived from the accent, and
|
|
43
|
+
* the background and contrast when they match the defaults — and a scheme
|
|
44
|
+
* with nothing left is dropped altogether. Options that boil down to the
|
|
45
|
+
* stock Studio theme reduce to `null` — they need nothing from this package.
|
|
32
46
|
*
|
|
33
47
|
* @internal
|
|
34
48
|
*/
|
|
35
49
|
function minimizeOptions(options) {
|
|
36
|
-
let resolved = resolveThemeOptions(options), minimized = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
let resolved = resolveThemeOptions(options), minimized = {};
|
|
51
|
+
for (let scheme of SCHEMES) {
|
|
52
|
+
let values = resolved[scheme], kept = {};
|
|
53
|
+
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);
|
|
54
|
+
}
|
|
55
|
+
return Object.keys(minimized).length === 0 ? null : minimized;
|
|
40
56
|
}
|
|
41
57
|
/**
|
|
42
58
|
* Whether two sets of theme options generate the same theme, comparing their
|
|
@@ -47,11 +63,1922 @@ function minimizeOptions(options) {
|
|
|
47
63
|
*/
|
|
48
64
|
function sameOptions(a, b) {
|
|
49
65
|
let left = resolveThemeOptions(a), right = resolveThemeOptions(b);
|
|
50
|
-
return
|
|
66
|
+
return SCHEMES.every((scheme) => sameScheme(left[scheme], right[scheme]));
|
|
67
|
+
}
|
|
68
|
+
function sameScheme(a, b) {
|
|
69
|
+
return a.accent === b.accent && a.text === b.text && a.background === b.background && a.contrast === b.contrast;
|
|
70
|
+
}
|
|
71
|
+
/** The slug of the theme the Studio config was generated from @internal */
|
|
72
|
+
const initialThemerState = {
|
|
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
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Creates a custom theme with a slug that cannot collide with the presets or
|
|
115
|
+
* the configured theme.
|
|
116
|
+
*
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
function createCustomTheme(title, options, palette) {
|
|
120
|
+
return {
|
|
121
|
+
slug: `custom-${randomId()}`,
|
|
122
|
+
title,
|
|
123
|
+
options,
|
|
124
|
+
...palette ? { palette } : {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** The title of a duplicated theme @internal */
|
|
128
|
+
function duplicateTitle(title) {
|
|
129
|
+
return `${displayTitle(title)} copy`;
|
|
130
|
+
}
|
|
131
|
+
/** The title to show for a theme, falling back when the user cleared it @internal */
|
|
132
|
+
function displayTitle(title) {
|
|
133
|
+
return title.trim() || "Untitled theme";
|
|
134
|
+
}
|
|
135
|
+
function randomId() {
|
|
136
|
+
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
137
|
+
}
|
|
138
|
+
function themesOf(context) {
|
|
139
|
+
return resolveThemes(context, context.baseOptions);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The state of the themer tool: three parallel regions, whether the
|
|
143
|
+
* `sidebar` is open, which `flow` it is in — picking a theme from the `list`,
|
|
144
|
+
* `edit`ing one of the user's own themes, or restoring `removed` ones — and
|
|
145
|
+
* whether the `preview` shows the Studio once (`single`) or in light and dark
|
|
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.
|
|
153
|
+
*
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
const themerMachine = setup({
|
|
157
|
+
types: {
|
|
158
|
+
context: {},
|
|
159
|
+
events: {},
|
|
160
|
+
input: {}
|
|
161
|
+
},
|
|
162
|
+
guards: {
|
|
163
|
+
isCustomTheme: ({ context }, params) => themesOf(context).themes.some((theme) => theme.slug === params.slug && theme.source === "custom"),
|
|
164
|
+
isEditingListedTheme: ({ context }) => context.editing !== null && themesOf(context).themes.some((theme) => theme.slug === context.editing?.slug && theme.source === "custom"),
|
|
165
|
+
hasRemovedThemes: ({ context }) => themesOf(context).removed.length > 0
|
|
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
|
+
}
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
/** The part of the machine context that is persisted between sessions @internal */
|
|
343
|
+
function selectStoredState(snapshot) {
|
|
344
|
+
let { active, custom, removed } = snapshot.context;
|
|
345
|
+
return {
|
|
346
|
+
active,
|
|
347
|
+
custom,
|
|
348
|
+
removed
|
|
349
|
+
};
|
|
350
|
+
}
|
|
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
|
+
/**
|
|
360
|
+
* The scrolling body of a sidebar flow. It always reserves the scrollbar's
|
|
361
|
+
* space, so the content does not shift when the list grows or shrinks past
|
|
362
|
+
* the point where it needs to scroll — and it takes that space out of its
|
|
363
|
+
* right padding, so the content stays centered rather than hugging the left.
|
|
364
|
+
* With overlay scrollbars there is no gutter and the padding stays even.
|
|
365
|
+
*
|
|
366
|
+
* @internal
|
|
367
|
+
*/
|
|
368
|
+
function ScrollArea(props) {
|
|
369
|
+
let $ = c(15), { children, padding } = props, { space } = useTheme_v2(), ref = useRef(null), [gutter, setGutter] = useState(0), t0, t1;
|
|
370
|
+
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => {
|
|
371
|
+
let element = ref.current;
|
|
372
|
+
if (!element) return;
|
|
373
|
+
let measure = () => setGutter(element.offsetWidth - element.clientWidth);
|
|
374
|
+
measure();
|
|
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;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Content that runs edge to edge in a scroll area — up to the scrollbar —
|
|
403
|
+
* instead of sitting inside its padding. It goes last: it runs down to the
|
|
404
|
+
* bottom edge too.
|
|
405
|
+
*
|
|
406
|
+
* @internal
|
|
407
|
+
*/
|
|
408
|
+
function ScrollAreaBleed(props) {
|
|
409
|
+
let $ = c(7), { left, right, bottom } = useContext(ScrollAreaInsetContext), t0 = -left, t1 = -right, t2 = -bottom, t3;
|
|
410
|
+
$[0] !== t0 || $[1] !== t1 || $[2] !== t2 ? (t3 = {
|
|
411
|
+
marginLeft: t0,
|
|
412
|
+
marginRight: t1,
|
|
413
|
+
marginBottom: t2
|
|
414
|
+
}, $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3) : t3 = $[3];
|
|
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;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The dark scheme covers the right side of the preview behind a diagonal cut,
|
|
423
|
+
* like the "Auto" appearance preview in macOS System Settings shows both
|
|
424
|
+
* schemes at once.
|
|
425
|
+
*/
|
|
426
|
+
const Root$1 = styled.div.withConfig({
|
|
427
|
+
displayName: "Root",
|
|
428
|
+
componentId: "sc-w55yz9-0"
|
|
429
|
+
})`position:relative;aspect-ratio:16 / 9;overflow:hidden;`, LIST_ROWS = [
|
|
430
|
+
"62%",
|
|
431
|
+
"46%",
|
|
432
|
+
"70%",
|
|
433
|
+
"52%"
|
|
434
|
+
], FIELDS = ["32%", "24%"];
|
|
435
|
+
/**
|
|
436
|
+
* A tiny, lo-fi mockup of a Studio in the given theme — the navbar over the
|
|
437
|
+
* structure tool with a list of documents on the left and a document form on
|
|
438
|
+
* the right — in both color schemes at once: the light scheme on the left and
|
|
439
|
+
* the dark scheme on the right, split diagonally. It only paints colors the
|
|
440
|
+
* theme options change (backgrounds, text, borders, the accent) so that a
|
|
441
|
+
* glance shows what the theme does to the Studio — with few and bold enough
|
|
442
|
+
* elements to still read when scaled down to a thumbnail.
|
|
443
|
+
*
|
|
444
|
+
* @internal
|
|
445
|
+
*/
|
|
446
|
+
function ThemePreview(props) {
|
|
447
|
+
let $ = c(11), { options } = props, t0;
|
|
448
|
+
$[0] === options ? t0 = $[1] : (t0 = buildTheme(options), $[0] = options, $[1] = t0);
|
|
449
|
+
let theme = t0, t1;
|
|
450
|
+
$[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(MockStudio, {}), $[2] = t1) : t1 = $[2];
|
|
451
|
+
let t2;
|
|
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;
|
|
631
|
+
}
|
|
632
|
+
function _temp$4(width, background) {
|
|
633
|
+
return {
|
|
634
|
+
flex: "none",
|
|
635
|
+
width,
|
|
636
|
+
height: 4,
|
|
637
|
+
borderRadius: 2,
|
|
638
|
+
background
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* The floating preview card of a theme: the lo-fi studio mockup on a raised,
|
|
643
|
+
* rounded card, like the appearance previews in macOS System Settings.
|
|
644
|
+
*
|
|
645
|
+
* @internal
|
|
646
|
+
*/
|
|
647
|
+
function ThemeThumbnail(props) {
|
|
648
|
+
let $ = c(2), t0;
|
|
649
|
+
return $[0] === props.options ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Card, {
|
|
650
|
+
overflow: "hidden",
|
|
651
|
+
radius: 3,
|
|
652
|
+
shadow: 1,
|
|
653
|
+
children: /* @__PURE__ */ jsx(ThemePreview, { options: props.options })
|
|
654
|
+
}), $[0] = props.options, $[1] = t0), t0;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* The flow for restoring removed themes: the presets and custom themes the
|
|
658
|
+
* user took out of the list, each with a button to put it back — and, for
|
|
659
|
+
* custom themes, one to delete it for good. The machine leaves the flow once
|
|
660
|
+
* the last one is gone.
|
|
661
|
+
*
|
|
662
|
+
* @internal
|
|
663
|
+
*/
|
|
664
|
+
function RemovedThemes() {
|
|
665
|
+
let $ = c(7), { removed, send } = useThemer(), t0;
|
|
666
|
+
if ($[0] !== removed || $[1] !== send) {
|
|
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;
|
|
716
|
+
}
|
|
717
|
+
/** @internal */
|
|
718
|
+
const IMAGE_PALETTE_KEYS = [
|
|
719
|
+
"vibrant",
|
|
720
|
+
"lightVibrant",
|
|
721
|
+
"darkVibrant",
|
|
722
|
+
"muted",
|
|
723
|
+
"lightMuted",
|
|
724
|
+
"darkMuted",
|
|
725
|
+
"dominant"
|
|
726
|
+
], IMAGE_PALETTE_VARIANTS = [
|
|
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
|
+
];
|
|
815
|
+
/**
|
|
816
|
+
* Extracts the color palette of an image from its pixels, the way the Vibrant
|
|
817
|
+
* algorithm does: the colors are quantized into a coarse histogram, and each
|
|
818
|
+
* swatch claims the color that comes closest to its target lightness and
|
|
819
|
+
* saturation — weighted by how much of the image it covers — that no other
|
|
820
|
+
* swatch has claimed yet. The dominant swatch is simply the most common
|
|
821
|
+
* color. Runs anywhere pixels come from, so it can run on device.
|
|
822
|
+
*
|
|
823
|
+
* @internal
|
|
824
|
+
*/
|
|
825
|
+
function extractImagePalette(pixels) {
|
|
826
|
+
let candidates = quantize(pixels), palette = {
|
|
827
|
+
dominant: null,
|
|
828
|
+
vibrant: null,
|
|
829
|
+
lightVibrant: null,
|
|
830
|
+
darkVibrant: null,
|
|
831
|
+
muted: null,
|
|
832
|
+
lightMuted: null,
|
|
833
|
+
darkMuted: null
|
|
834
|
+
};
|
|
835
|
+
if (candidates.length === 0) return palette;
|
|
836
|
+
let maximumPopulation = Math.max(...candidates.map((candidate) => candidate.population)), claimed = /* @__PURE__ */ new Set();
|
|
837
|
+
for (let [key, target] of TARGETS) {
|
|
838
|
+
let best = null, bestScore = -Infinity;
|
|
839
|
+
for (let candidate of candidates) {
|
|
840
|
+
if (claimed.has(candidate.hex) || !matchesTarget(candidate, target)) continue;
|
|
841
|
+
let score = scoreCandidate(candidate, target, maximumPopulation);
|
|
842
|
+
score > bestScore && (best = candidate, bestScore = score);
|
|
843
|
+
}
|
|
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
|
+
}
|
|
878
|
+
return candidates;
|
|
879
|
+
}
|
|
880
|
+
function matchesTarget(candidate, target) {
|
|
881
|
+
return candidate.lightness >= target.lightness[1] && candidate.lightness <= target.lightness[2] && candidate.saturation >= target.saturation[1] && candidate.saturation <= target.saturation[2];
|
|
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;
|
|
888
|
+
return {
|
|
889
|
+
saturation: delta === 0 ? 0 : lightness > .5 ? delta / (2 - max - min) : delta / (max + min),
|
|
890
|
+
lightness
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
function rgbToHex(r, g, b) {
|
|
894
|
+
return `#${[
|
|
895
|
+
r,
|
|
896
|
+
g,
|
|
897
|
+
b
|
|
898
|
+
].map((channel) => channel.toString(16).padStart(2, "0")).join("")}`;
|
|
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
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Makes an accent readable as a button in the given scheme: a light scheme
|
|
928
|
+
* accent is darkened until white text on it reaches AA contrast, a dark
|
|
929
|
+
* scheme accent lightened until black text does — as far as the accent's
|
|
930
|
+
* hue and saturation allow. Accents that already pass come back untouched.
|
|
931
|
+
*
|
|
932
|
+
* @internal
|
|
933
|
+
*/
|
|
934
|
+
function readableAccent(hex, scheme) {
|
|
935
|
+
let label = BUTTON_LABEL[scheme], { h, s } = hexToHsl(hex), { l } = hexToHsl(hex), current = hex;
|
|
936
|
+
for (; contrastRatio(current, label) < 4.5;) {
|
|
937
|
+
let next = scheme === "light" ? l - ACCENT_LIGHTNESS_STEP : l + ACCENT_LIGHTNESS_STEP;
|
|
938
|
+
if (next < 0 || next > 1) break;
|
|
939
|
+
l = next, current = hslToHex({
|
|
940
|
+
h,
|
|
941
|
+
s,
|
|
942
|
+
l
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
return current;
|
|
946
|
+
}
|
|
947
|
+
/** The accent a variant gives a scheme, made readable on a button */
|
|
948
|
+
function variantAccent(palette, variant, scheme) {
|
|
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);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Derives theme options from an image palette: the accent of both schemes is
|
|
954
|
+
* the swatch of the chosen variant — or, without one, the vibrant swatch,
|
|
955
|
+
* each scheme falling back to the vibrant swatch of its own end of the scale —
|
|
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.
|
|
960
|
+
*
|
|
961
|
+
* @internal
|
|
962
|
+
*/
|
|
963
|
+
function optionsFromImagePalette(palette, variant) {
|
|
964
|
+
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");
|
|
965
|
+
return light && (options.light = light), dark && (options.dark = dark), options;
|
|
966
|
+
}
|
|
967
|
+
function schemeFromPalette(accent, text, backgroundTint, scheme) {
|
|
968
|
+
let options = {};
|
|
969
|
+
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;
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Applies an image palette to existing theme options: the colors the palette
|
|
973
|
+
* provides replace the current ones scheme by scheme, and whatever it does
|
|
974
|
+
* not touch — like the contrast — stays as it is.
|
|
975
|
+
*
|
|
976
|
+
* @internal
|
|
977
|
+
*/
|
|
978
|
+
function applyImagePalette(options, palette, variant) {
|
|
979
|
+
let derived = optionsFromImagePalette(palette, variant), next = { ...options };
|
|
980
|
+
for (let scheme of SCHEMES) derived[scheme] && (next[scheme] = {
|
|
981
|
+
...options[scheme],
|
|
982
|
+
...derived[scheme]
|
|
983
|
+
});
|
|
984
|
+
return next;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* The variant a theme is built around: the one whose swatch is the theme's
|
|
988
|
+
* accent, or `null` when the accent comes from somewhere else.
|
|
989
|
+
*
|
|
990
|
+
* @internal
|
|
991
|
+
*/
|
|
992
|
+
function currentImageVariant(options, palette) {
|
|
993
|
+
let accent = options.light?.accent;
|
|
994
|
+
return accent ? IMAGE_PALETTE_VARIANTS.find((variant) => palette[variant] !== null && variantAccent(palette, variant, "light") === accent) ?? null : null;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* How much a swatch has going for it as an accent: saturation first, then
|
|
998
|
+
* closeness to mid lightness — the range where an accent reads best.
|
|
999
|
+
*/
|
|
1000
|
+
function interest(hex) {
|
|
1001
|
+
let { s, l } = hexToHsl(hex);
|
|
1002
|
+
return .1 + .55 * s + .35 * (1 - Math.abs(l - .5) * 2);
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Picks a variant for the "I'm feeling lucky" button: a random one, weighted
|
|
1006
|
+
* by how interesting its swatch is as an accent, and never the one the theme
|
|
1007
|
+
* already uses while there are others to pick from.
|
|
1008
|
+
*
|
|
1009
|
+
* @internal
|
|
1010
|
+
*/
|
|
1011
|
+
function pickLuckyVariant(palette, options = {}) {
|
|
1012
|
+
let { exclude = null, random = Math.random } = options, candidates = IMAGE_PALETTE_VARIANTS.filter((variant) => palette[variant] !== null);
|
|
1013
|
+
if (candidates.length > 1 && (candidates = candidates.filter((variant) => variant !== exclude)), candidates.length === 0) return null;
|
|
1014
|
+
let weights = candidates.map((variant) => interest(palette[variant])), total = weights.reduce((sum, weight) => sum + weight, 0), pick = random() * total;
|
|
1015
|
+
for (let [index, variant] of candidates.entries()) if (pick -= weights[index], pick < 0) return variant;
|
|
1016
|
+
return candidates.at(-1) ?? null;
|
|
1017
|
+
}
|
|
1018
|
+
/** A theme title for the image a palette came from, e.g. `sunset-beach.jpg` → `sunset beach` @internal */
|
|
1019
|
+
function titleFromFileName(name) {
|
|
1020
|
+
return name.replace(/\.[^.]+$/, "").replace(/[-_]+/g, " ").trim() || "Image theme";
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* A button with an animated tooltip instead of a `title` attribute. Icon-only
|
|
1024
|
+
* buttons take the tooltip as their accessible name.
|
|
1025
|
+
*
|
|
1026
|
+
* @internal
|
|
1027
|
+
*/
|
|
1028
|
+
function TooltipButton(props) {
|
|
1029
|
+
let $ = c(11), buttonProps, tooltip;
|
|
1030
|
+
$[0] === props ? (buttonProps = $[1], tooltip = $[2]) : ({tooltip, ...buttonProps} = props, $[0] = props, $[1] = buttonProps, $[2] = tooltip);
|
|
1031
|
+
let t0;
|
|
1032
|
+
$[3] === tooltip ? t0 = $[4] : (t0 = /* @__PURE__ */ jsx(Text, {
|
|
1033
|
+
size: 1,
|
|
1034
|
+
children: tooltip
|
|
1035
|
+
}), $[3] = tooltip, $[4] = t0);
|
|
1036
|
+
let t1 = buttonProps.text === void 0 ? tooltip : void 0, t2;
|
|
1037
|
+
$[5] !== buttonProps || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(Button, {
|
|
1038
|
+
"aria-label": t1,
|
|
1039
|
+
...buttonProps
|
|
1040
|
+
}), $[5] = buttonProps, $[6] = t1, $[7] = t2) : t2 = $[7];
|
|
1041
|
+
let t3;
|
|
1042
|
+
return $[8] !== t0 || $[9] !== t2 ? (t3 = /* @__PURE__ */ jsx(Tooltip, {
|
|
1043
|
+
animate: !0,
|
|
1044
|
+
content: t0,
|
|
1045
|
+
placement: "bottom",
|
|
1046
|
+
portal: !0,
|
|
1047
|
+
children: t2
|
|
1048
|
+
}), $[8] = t0, $[9] = t2, $[10] = t3) : t3 = $[10], t3;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* A button that opens the file picker for an image, and hands the chosen file
|
|
1052
|
+
* over — the picker is a hidden file input, so nothing is uploaded anywhere.
|
|
1053
|
+
*
|
|
1054
|
+
* @internal
|
|
1055
|
+
*/
|
|
1056
|
+
function ImageFileButton(props) {
|
|
1057
|
+
let $ = c(11), buttonProps, onFile;
|
|
1058
|
+
$[0] === props ? (buttonProps = $[1], onFile = $[2]) : ({onFile, ...buttonProps} = props, $[0] = props, $[1] = buttonProps, $[2] = onFile);
|
|
1059
|
+
let inputRef = useRef(null), t0;
|
|
1060
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => inputRef.current?.click(), $[3] = t0) : t0 = $[3];
|
|
1061
|
+
let t1;
|
|
1062
|
+
$[4] === buttonProps ? t1 = $[5] : (t1 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
1063
|
+
...buttonProps,
|
|
1064
|
+
icon: ImageIcon,
|
|
1065
|
+
onClick: t0
|
|
1066
|
+
}), $[4] = buttonProps, $[5] = t1);
|
|
1067
|
+
let t2;
|
|
1068
|
+
$[6] === onFile ? t2 = $[7] : (t2 = /* @__PURE__ */ jsx("input", {
|
|
1069
|
+
accept: "image/*",
|
|
1070
|
+
hidden: !0,
|
|
1071
|
+
onChange: (event) => {
|
|
1072
|
+
let file = event.currentTarget.files?.[0];
|
|
1073
|
+
event.currentTarget.value = "", file && onFile(file);
|
|
1074
|
+
},
|
|
1075
|
+
ref: inputRef,
|
|
1076
|
+
type: "file"
|
|
1077
|
+
}), $[6] = onFile, $[7] = t2);
|
|
1078
|
+
let t3;
|
|
1079
|
+
return $[8] !== t1 || $[9] !== t2 ? (t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, t2] }), $[8] = t1, $[9] = t2, $[10] = t3) : t3 = $[10], t3;
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Reads the pixels of an image file on device: the image is decoded, drawn
|
|
1083
|
+
* onto a small canvas and read back, so nothing leaves the browser.
|
|
1084
|
+
*
|
|
1085
|
+
* @internal
|
|
1086
|
+
*/
|
|
1087
|
+
async function readImagePixels(file) {
|
|
1088
|
+
let image = await decodeImage(file);
|
|
1089
|
+
try {
|
|
1090
|
+
let scale = Math.min(1, 96 / Math.max(image.width, image.height)), width = Math.max(1, Math.round(image.width * scale)), height = Math.max(1, Math.round(image.height * scale)), canvas = document.createElement("canvas");
|
|
1091
|
+
canvas.width = width, canvas.height = height;
|
|
1092
|
+
let context = canvas.getContext("2d", { willReadFrequently: !0 });
|
|
1093
|
+
if (!context) throw Error("Could not draw the image");
|
|
1094
|
+
return context.drawImage(image, 0, 0, width, height), {
|
|
1095
|
+
data: context.getImageData(0, 0, width, height).data,
|
|
1096
|
+
width,
|
|
1097
|
+
height
|
|
1098
|
+
};
|
|
1099
|
+
} finally {
|
|
1100
|
+
typeof ImageBitmap < "u" && image instanceof ImageBitmap && image.close();
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
async function decodeImage(file) {
|
|
1104
|
+
if (typeof createImageBitmap == "function") try {
|
|
1105
|
+
return await createImageBitmap(file);
|
|
1106
|
+
} catch {}
|
|
1107
|
+
let url = URL.createObjectURL(file);
|
|
1108
|
+
try {
|
|
1109
|
+
return await new Promise((resolve, reject) => {
|
|
1110
|
+
let image = new Image();
|
|
1111
|
+
image.addEventListener("load", () => resolve(image), { once: !0 }), image.addEventListener("error", () => reject(/* @__PURE__ */ Error("Could not decode the image")), { once: !0 }), image.src = url;
|
|
1112
|
+
});
|
|
1113
|
+
} finally {
|
|
1114
|
+
URL.revokeObjectURL(url);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Extracts the palette of image files on device and hands it to `onPalette`,
|
|
1119
|
+
* along with the file it came from. Failures end up as a toast.
|
|
1120
|
+
*
|
|
1121
|
+
* @internal
|
|
1122
|
+
*/
|
|
1123
|
+
function useImagePalette(onPalette) {
|
|
1124
|
+
let $ = c(10), toast = useToast(), [busy, setBusy] = useState(!1), onPaletteRef = useRef(onPalette), mountedRef = useRef(!0), latestPickRef = useRef(0), t0, t1;
|
|
1125
|
+
$[0] === onPalette ? (t0 = $[1], t1 = $[2]) : (t0 = () => {
|
|
1126
|
+
onPaletteRef.current = onPalette;
|
|
1127
|
+
}, t1 = [onPalette], $[0] = onPalette, $[1] = t0, $[2] = t1), useEffect(t0, t1);
|
|
1128
|
+
let t2, t3;
|
|
1129
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t2 = () => (mountedRef.current = !0, () => {
|
|
1130
|
+
mountedRef.current = !1;
|
|
1131
|
+
}), t3 = [], $[3] = t2, $[4] = t3) : (t2 = $[3], t3 = $[4]), useEffect(t2, t3);
|
|
1132
|
+
let t4;
|
|
1133
|
+
$[5] === toast ? t4 = $[6] : (t4 = (file) => {
|
|
1134
|
+
let pick = latestPickRef.current += 1;
|
|
1135
|
+
setBusy(!0);
|
|
1136
|
+
let isCurrent = () => mountedRef.current && latestPickRef.current === pick, extract = async () => {
|
|
1137
|
+
let palette = extractImagePalette(await readImagePixels(file));
|
|
1138
|
+
isCurrent() && (Object.values(palette).every(_temp$3) ? toast.push({
|
|
1139
|
+
status: "warning",
|
|
1140
|
+
title: "Found no colors in that image"
|
|
1141
|
+
}) : onPaletteRef.current(palette, file));
|
|
1142
|
+
};
|
|
1143
|
+
extract().catch(() => {
|
|
1144
|
+
isCurrent() && toast.push({
|
|
1145
|
+
status: "error",
|
|
1146
|
+
title: "Could not read that image"
|
|
1147
|
+
});
|
|
1148
|
+
}).finally(() => {
|
|
1149
|
+
isCurrent() && setBusy(!1);
|
|
1150
|
+
});
|
|
1151
|
+
}, $[5] = toast, $[6] = t4);
|
|
1152
|
+
let pickImage = t4, t5;
|
|
1153
|
+
return $[7] !== busy || $[8] !== pickImage ? (t5 = {
|
|
1154
|
+
busy,
|
|
1155
|
+
pickImage
|
|
1156
|
+
}, $[7] = busy, $[8] = pickImage, $[9] = t5) : t5 = $[9], t5;
|
|
1157
|
+
}
|
|
1158
|
+
function _temp$3(swatch) {
|
|
1159
|
+
return swatch === null;
|
|
1160
|
+
}
|
|
1161
|
+
/** The swatches on display: the vibrant family over the muted one */
|
|
1162
|
+
const TILES = [
|
|
1163
|
+
"vibrant",
|
|
1164
|
+
"lightVibrant",
|
|
1165
|
+
"darkVibrant",
|
|
1166
|
+
"muted",
|
|
1167
|
+
"lightMuted",
|
|
1168
|
+
"darkMuted"
|
|
1169
|
+
], PaletteGrid = styled.div.withConfig({
|
|
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;`;
|
|
1191
|
+
/**
|
|
1192
|
+
* Takes the colors of a theme from an image, on device: the image is read
|
|
1193
|
+
* into a canvas and its palette extracted right there — nothing is uploaded.
|
|
1194
|
+
* Shows the image (while the session lasts) next to its palette, offers a
|
|
1195
|
+
* theme variant built around each swatch as a small preview, and a lucky
|
|
1196
|
+
* button that picks an interesting one.
|
|
1197
|
+
*
|
|
1198
|
+
* @internal
|
|
1199
|
+
*/
|
|
1200
|
+
function ImagePaletteSection(props) {
|
|
1201
|
+
let $ = c(38), { imageUrl, onPalette, onVariant, onLucky, options, palette } = props, { busy, pickImage } = useImagePalette(onPalette), [dragging, setDragging] = useState(!1), dragDepth = useRef(0), t0;
|
|
1202
|
+
$[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), [variantWidth, setVariantWidth] = useState(58), t1;
|
|
1204
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
|
|
1205
|
+
let row = rowRef.current;
|
|
1206
|
+
if (!row) return;
|
|
1207
|
+
let measure = () => {
|
|
1208
|
+
let visible = row.clientWidth - 12 - 16;
|
|
1209
|
+
setVariantWidth(Math.max(24, Math.floor(visible / 2.5) - 8));
|
|
1210
|
+
};
|
|
1211
|
+
measure();
|
|
1212
|
+
let observer = new ResizeObserver(measure);
|
|
1213
|
+
return observer.observe(row), () => observer.disconnect();
|
|
1214
|
+
}, $[3] = t1) : t1 = $[3];
|
|
1215
|
+
let t2;
|
|
1216
|
+
$[4] === palette ? t2 = $[5] : (t2 = [palette], $[4] = palette, $[5] = t2), useEffect(t1, t2);
|
|
1217
|
+
let t3;
|
|
1218
|
+
bb0: {
|
|
1219
|
+
if (!palette) {
|
|
1220
|
+
let t4;
|
|
1221
|
+
$[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = [], $[6] = t4) : t4 = $[6], t3 = t4;
|
|
1222
|
+
break bb0;
|
|
1223
|
+
}
|
|
1224
|
+
let t4;
|
|
1225
|
+
$[7] !== options || $[8] !== palette ? (t4 = IMAGE_PALETTE_VARIANTS.flatMap((variant) => palette[variant] === null ? [] : [{
|
|
1226
|
+
variant,
|
|
1227
|
+
options: applyImagePalette(options, palette, variant)
|
|
1228
|
+
}]), $[7] = options, $[8] = palette, $[9] = t4) : t4 = $[9], t3 = t4;
|
|
1229
|
+
}
|
|
1230
|
+
let variants = t3, t4, t5;
|
|
1231
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t4 = (event) => {
|
|
1232
|
+
event.preventDefault(), dragDepth.current += 1, setDragging(!0);
|
|
1233
|
+
}, t5 = () => {
|
|
1234
|
+
dragDepth.current = Math.max(0, dragDepth.current - 1), dragDepth.current === 0 && setDragging(!1);
|
|
1235
|
+
}, $[10] = t4, $[11] = t5) : (t4 = $[10], t5 = $[11]);
|
|
1236
|
+
let t6;
|
|
1237
|
+
$[12] === pickImage ? t6 = $[13] : (t6 = (event_1) => {
|
|
1238
|
+
event_1.preventDefault(), dragDepth.current = 0, setDragging(!1);
|
|
1239
|
+
let file = event_1.dataTransfer.files[0];
|
|
1240
|
+
file && pickImage(file);
|
|
1241
|
+
}, $[12] = pickImage, $[13] = t6);
|
|
1242
|
+
let t7 = dragging ? "primary" : "default", t8;
|
|
1243
|
+
$[14] === Symbol.for("react.memo_cache_sentinel") ? (t8 = /* @__PURE__ */ jsx(Box, {
|
|
1244
|
+
flex: 1,
|
|
1245
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1246
|
+
size: 1,
|
|
1247
|
+
weight: "medium",
|
|
1248
|
+
children: "Image palette"
|
|
1249
|
+
})
|
|
1250
|
+
}), $[14] = t8) : t8 = $[14];
|
|
1251
|
+
let t9;
|
|
1252
|
+
$[15] !== busy || $[16] !== palette || $[17] !== pickImage ? (t9 = palette && /* @__PURE__ */ jsx(ImageFileButton, {
|
|
1253
|
+
loading: busy,
|
|
1254
|
+
mode: "bleed",
|
|
1255
|
+
onFile: pickImage,
|
|
1256
|
+
padding: 2,
|
|
1257
|
+
tooltip: "Pick another image"
|
|
1258
|
+
}), $[15] = busy, $[16] = palette, $[17] = pickImage, $[18] = t9) : t9 = $[18];
|
|
1259
|
+
let t10;
|
|
1260
|
+
$[19] === t9 ? t10 = $[20] : (t10 = /* @__PURE__ */ jsxs(Flex, {
|
|
1261
|
+
align: "center",
|
|
1262
|
+
gap: 2,
|
|
1263
|
+
children: [t8, t9]
|
|
1264
|
+
}), $[19] = t9, $[20] = t10);
|
|
1265
|
+
let t11;
|
|
1266
|
+
$[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !== variantWidth || $[29] !== variants ? (t11 = palette ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1267
|
+
/* @__PURE__ */ jsxs(PaletteGrid, {
|
|
1268
|
+
"data-with-image": imageUrl !== void 0,
|
|
1269
|
+
children: [imageUrl && /* @__PURE__ */ jsx(ImageTile, {
|
|
1270
|
+
alt: "",
|
|
1271
|
+
src: imageUrl
|
|
1272
|
+
}), TILES.map((key) => {
|
|
1273
|
+
let hex = palette[key], title = IMAGE_PALETTE_TITLES[key];
|
|
1274
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
1275
|
+
animate: !0,
|
|
1276
|
+
content: /* @__PURE__ */ jsx(Text, {
|
|
1277
|
+
size: 1,
|
|
1278
|
+
children: hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`
|
|
1279
|
+
}),
|
|
1280
|
+
placement: "bottom",
|
|
1281
|
+
portal: !0,
|
|
1282
|
+
children: /* @__PURE__ */ jsx(Tile, {
|
|
1283
|
+
"data-empty": hex === null,
|
|
1284
|
+
style: { background: hex ?? void 0 }
|
|
1285
|
+
})
|
|
1286
|
+
}, key);
|
|
1287
|
+
})]
|
|
1288
|
+
}),
|
|
1289
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
1290
|
+
gap: 2,
|
|
1291
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
1292
|
+
muted: !0,
|
|
1293
|
+
size: 0,
|
|
1294
|
+
children: "Pick the swatch to build the theme around"
|
|
1295
|
+
}), /* @__PURE__ */ jsx(VariantRow, {
|
|
1296
|
+
ref: rowRef,
|
|
1297
|
+
style: {
|
|
1298
|
+
"--variant-width": `${variantWidth}px`,
|
|
1299
|
+
"--variant-scale": variantWidth / 144
|
|
1300
|
+
},
|
|
1301
|
+
children: variants.map((t12) => {
|
|
1302
|
+
let { variant: variant_0, options: variantOptions } = t12;
|
|
1303
|
+
return /* @__PURE__ */ jsxs(VariantButton, {
|
|
1304
|
+
"aria-pressed": variant_0 === current,
|
|
1305
|
+
onClick: () => onVariant(variant_0),
|
|
1306
|
+
type: "button",
|
|
1307
|
+
children: [/* @__PURE__ */ jsx(VariantFrame, { children: /* @__PURE__ */ jsx(VariantScale, { children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: variantOptions }) }) }), /* @__PURE__ */ jsx(Box, {
|
|
1308
|
+
paddingTop: 1,
|
|
1309
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1310
|
+
align: "center",
|
|
1311
|
+
size: 0,
|
|
1312
|
+
textOverflow: "ellipsis",
|
|
1313
|
+
weight: variant_0 === current ? "medium" : "regular",
|
|
1314
|
+
children: IMAGE_PALETTE_TITLES[variant_0]
|
|
1315
|
+
})
|
|
1316
|
+
})]
|
|
1317
|
+
}, variant_0);
|
|
1318
|
+
})
|
|
1319
|
+
})]
|
|
1320
|
+
}),
|
|
1321
|
+
/* @__PURE__ */ jsx(TooltipButton, {
|
|
1322
|
+
icon: SparklesIcon,
|
|
1323
|
+
mode: "ghost",
|
|
1324
|
+
onClick: onLucky,
|
|
1325
|
+
text: "I'm feeling lucky",
|
|
1326
|
+
tooltip: "Build the theme around a swatch that looks interesting",
|
|
1327
|
+
width: "fill"
|
|
1328
|
+
})
|
|
1329
|
+
] }) : /* @__PURE__ */ jsxs(Stack, {
|
|
1330
|
+
gap: 3,
|
|
1331
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
1332
|
+
muted: !0,
|
|
1333
|
+
size: 0,
|
|
1334
|
+
children: "Take the accent, text and background colors from an image — read on device, nothing is uploaded."
|
|
1335
|
+
}), /* @__PURE__ */ jsx(ImageFileButton, {
|
|
1336
|
+
loading: busy,
|
|
1337
|
+
mode: "ghost",
|
|
1338
|
+
onFile: pickImage,
|
|
1339
|
+
text: "Pick an image",
|
|
1340
|
+
tooltip: "Take the colors from an image on your device",
|
|
1341
|
+
width: "fill"
|
|
1342
|
+
})]
|
|
1343
|
+
}), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] = variantWidth, $[29] = variants, $[30] = t11) : t11 = $[30];
|
|
1344
|
+
let t12;
|
|
1345
|
+
$[31] !== t10 || $[32] !== t11 ? (t12 = /* @__PURE__ */ jsxs(Stack, {
|
|
1346
|
+
gap: 3,
|
|
1347
|
+
children: [t10, t11]
|
|
1348
|
+
}), $[31] = t10, $[32] = t11, $[33] = t12) : t12 = $[33];
|
|
1349
|
+
let t13;
|
|
1350
|
+
return $[34] !== t12 || $[35] !== t6 || $[36] !== t7 ? (t13 = /* @__PURE__ */ jsx(Card, {
|
|
1351
|
+
border: !0,
|
|
1352
|
+
onDragEnter: t4,
|
|
1353
|
+
onDragLeave: t5,
|
|
1354
|
+
onDragOver: _temp$2,
|
|
1355
|
+
onDrop: t6,
|
|
1356
|
+
padding: 3,
|
|
1357
|
+
radius: 3,
|
|
1358
|
+
tone: t7,
|
|
1359
|
+
children: t12
|
|
1360
|
+
}), $[34] = t12, $[35] = t6, $[36] = t7, $[37] = t13) : t13 = $[37], t13;
|
|
1361
|
+
}
|
|
1362
|
+
function _temp$2(event_0) {
|
|
1363
|
+
event_0.preventDefault();
|
|
1364
|
+
}
|
|
1365
|
+
const SCHEME_TITLES = {
|
|
1366
|
+
dark: "Dark mode",
|
|
1367
|
+
light: "Light mode"
|
|
1368
|
+
}, SPLIT_HINTS = {
|
|
1369
|
+
dark: "Shown on the right",
|
|
1370
|
+
light: "Shown on the left"
|
|
1371
|
+
}, SCHEME_OPTION_KEYS = [
|
|
1372
|
+
"accent",
|
|
1373
|
+
"text",
|
|
1374
|
+
"background",
|
|
1375
|
+
"contrast"
|
|
1376
|
+
], Swatch = styled.input.withConfig({
|
|
1377
|
+
displayName: "Swatch",
|
|
1378
|
+
componentId: "sc-rahyxu-0"
|
|
1379
|
+
})`box-sizing:border-box;flex:none;width:33px;height:33px;padding:0;border:1px solid var(--card-border-color);border-radius:4px;background:none;cursor:pointer;&::-webkit-color-swatch-wrapper{padding:0;}&::-webkit-color-swatch{border:none;border-radius:3px;}&::-moz-color-swatch{border:none;border-radius:3px;}`, Range = styled.input.withConfig({
|
|
1380
|
+
displayName: "Range",
|
|
1381
|
+
componentId: "sc-rahyxu-1"
|
|
1382
|
+
})`display:block;width:100%;margin:0;accent-color:var(--card-focus-ring-color);`;
|
|
1383
|
+
/**
|
|
1384
|
+
* The flow for editing one of the user's own themes: its title, a live
|
|
1385
|
+
* preview, and a card per color scheme with the accent/text/background
|
|
1386
|
+
* pickers and the contrast slider of that scheme. Every change applies to the
|
|
1387
|
+
* whole Studio right away — in the scheme the Studio is showing, or in both
|
|
1388
|
+
* side by side in the split preview.
|
|
1389
|
+
*
|
|
1390
|
+
* @internal
|
|
1391
|
+
*/
|
|
1392
|
+
function ThemeEditor(props) {
|
|
1393
|
+
let $ = c(41), { focusTitle, slug } = props, { themes, images, split, send } = useThemer(), t0;
|
|
1394
|
+
if ($[0] !== slug || $[1] !== themes) {
|
|
1395
|
+
let t1;
|
|
1396
|
+
$[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;
|
|
1397
|
+
} else t0 = $[2];
|
|
1398
|
+
let theme = t0;
|
|
1399
|
+
if (!theme) return null;
|
|
1400
|
+
let t1;
|
|
1401
|
+
$[5] !== send || $[6] !== slug || $[7] !== theme.options || $[8] !== theme.palette ? (t1 = (variant) => {
|
|
1402
|
+
theme.palette && variant !== null && send({
|
|
1403
|
+
type: "theme.update",
|
|
1404
|
+
slug,
|
|
1405
|
+
options: applyImagePalette(theme.options, theme.palette, variant)
|
|
1406
|
+
});
|
|
1407
|
+
}, $[5] = send, $[6] = slug, $[7] = theme.options, $[8] = theme.palette, $[9] = t1) : t1 = $[9];
|
|
1408
|
+
let applyVariant = t1, t2 = images[slug], t3;
|
|
1409
|
+
$[10] === send ? t3 = $[11] : (t3 = () => send({ type: "flow.list" }), $[10] = send, $[11] = t3);
|
|
1410
|
+
let t4;
|
|
1411
|
+
$[12] !== applyVariant || $[13] !== theme.options || $[14] !== theme.palette ? (t4 = () => {
|
|
1412
|
+
theme.palette && applyVariant(pickLuckyVariant(theme.palette, { exclude: currentImageVariant(theme.options, theme.palette) }));
|
|
1413
|
+
}, $[12] = applyVariant, $[13] = theme.options, $[14] = theme.palette, $[15] = t4) : t4 = $[15];
|
|
1414
|
+
let t5;
|
|
1415
|
+
$[16] !== send || $[17] !== slug ? (t5 = (options) => send({
|
|
1416
|
+
type: "theme.update",
|
|
1417
|
+
slug,
|
|
1418
|
+
options
|
|
1419
|
+
}), $[16] = send, $[17] = slug, $[18] = t5) : t5 = $[18];
|
|
1420
|
+
let t6;
|
|
1421
|
+
$[19] !== send || $[20] !== slug || $[21] !== theme.options ? (t6 = (palette, file) => send({
|
|
1422
|
+
type: "theme.update",
|
|
1423
|
+
slug,
|
|
1424
|
+
options: applyImagePalette(theme.options, palette),
|
|
1425
|
+
palette,
|
|
1426
|
+
imageUrl: URL.createObjectURL(file)
|
|
1427
|
+
}), $[19] = send, $[20] = slug, $[21] = theme.options, $[22] = t6) : t6 = $[22];
|
|
1428
|
+
let t7, t8;
|
|
1429
|
+
$[23] !== send || $[24] !== slug ? (t7 = () => send({
|
|
1430
|
+
type: "theme.remove",
|
|
1431
|
+
slug
|
|
1432
|
+
}), t8 = (title) => send({
|
|
1433
|
+
type: "theme.update",
|
|
1434
|
+
slug,
|
|
1435
|
+
title
|
|
1436
|
+
}), $[23] = send, $[24] = slug, $[25] = t7, $[26] = t8) : (t7 = $[25], t8 = $[26]);
|
|
1437
|
+
let t9;
|
|
1438
|
+
return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !== split || $[30] !== t2 || $[31] !== t3 || $[32] !== t4 || $[33] !== t5 || $[34] !== t6 || $[35] !== t7 || $[36] !== t8 || $[37] !== theme.options || $[38] !== theme.palette || $[39] !== theme.title ? (t9 = /* @__PURE__ */ jsx(ThemeEditorForm, {
|
|
1439
|
+
focusTitle,
|
|
1440
|
+
imageUrl: t2,
|
|
1441
|
+
onDone: t3,
|
|
1442
|
+
onLucky: t4,
|
|
1443
|
+
onOptionsChange: t5,
|
|
1444
|
+
onPalette: t6,
|
|
1445
|
+
onRemove: t7,
|
|
1446
|
+
onTitleChange: t8,
|
|
1447
|
+
onVariant: applyVariant,
|
|
1448
|
+
options: theme.options,
|
|
1449
|
+
palette: theme.palette,
|
|
1450
|
+
split,
|
|
1451
|
+
title: theme.title
|
|
1452
|
+
}), $[27] = applyVariant, $[28] = focusTitle, $[29] = split, $[30] = t2, $[31] = t3, $[32] = t4, $[33] = t5, $[34] = t6, $[35] = t7, $[36] = t8, $[37] = theme.options, $[38] = theme.palette, $[39] = theme.title, $[40] = t9) : t9 = $[40], t9;
|
|
1453
|
+
}
|
|
1454
|
+
function ThemeEditorForm(props) {
|
|
1455
|
+
let $ = c(49), { focusTitle, imageUrl, onDone, onLucky, onOptionsChange, onPalette, onRemove, onTitleChange, onVariant, options, palette, split, title } = props, studioScheme = useColorSchemeValue(), t0;
|
|
1456
|
+
$[0] === options ? t0 = $[1] : (t0 = resolveThemeOptions(options), $[0] = options, $[1] = t0);
|
|
1457
|
+
let resolved = t0, t1;
|
|
1458
|
+
$[2] === options ? t1 = $[3] : (t1 = buildPalette(options), $[2] = options, $[3] = t1);
|
|
1459
|
+
let palettes = t1, t2;
|
|
1460
|
+
$[4] !== onOptionsChange || $[5] !== options ? (t2 = (scheme, changes) => {
|
|
1461
|
+
let values = {
|
|
1462
|
+
...options[scheme],
|
|
1463
|
+
...changes
|
|
1464
|
+
};
|
|
1465
|
+
for (let key of SCHEME_OPTION_KEYS) values[key] === void 0 && delete values[key];
|
|
1466
|
+
let next = { ...options };
|
|
1467
|
+
Object.keys(values).length === 0 ? delete next[scheme] : next[scheme] = values, onOptionsChange(next);
|
|
1468
|
+
}, $[4] = onOptionsChange, $[5] = options, $[6] = t2) : t2 = $[6];
|
|
1469
|
+
let patchScheme = t2, t3;
|
|
1470
|
+
$[7] === options ? t3 = $[8] : (t3 = /* @__PURE__ */ jsx(ThemeThumbnail, { options }), $[7] = options, $[8] = t3);
|
|
1471
|
+
let t4;
|
|
1472
|
+
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx(Text, {
|
|
1473
|
+
size: 1,
|
|
1474
|
+
weight: "medium",
|
|
1475
|
+
children: "Title"
|
|
1476
|
+
}), $[9] = t4) : t4 = $[9];
|
|
1477
|
+
let t5;
|
|
1478
|
+
$[10] === onTitleChange ? t5 = $[11] : (t5 = (event) => onTitleChange(event.currentTarget.value), $[10] = onTitleChange, $[11] = t5);
|
|
1479
|
+
let t6 = focusTitle ? _temp$1 : void 0, t7;
|
|
1480
|
+
$[12] !== focusTitle || $[13] !== t5 || $[14] !== t6 || $[15] !== title ? (t7 = /* @__PURE__ */ jsxs(Stack, {
|
|
1481
|
+
gap: 2,
|
|
1482
|
+
children: [t4, /* @__PURE__ */ jsx(TextInput, {
|
|
1483
|
+
autoFocus: focusTitle,
|
|
1484
|
+
fontSize: 1,
|
|
1485
|
+
onChange: t5,
|
|
1486
|
+
onFocus: t6,
|
|
1487
|
+
padding: 2,
|
|
1488
|
+
placeholder: "Untitled theme",
|
|
1489
|
+
value: title
|
|
1490
|
+
})]
|
|
1491
|
+
}), $[12] = focusTitle, $[13] = t5, $[14] = t6, $[15] = title, $[16] = t7) : t7 = $[16];
|
|
1492
|
+
let t8;
|
|
1493
|
+
$[17] !== imageUrl || $[18] !== onLucky || $[19] !== onPalette || $[20] !== onVariant || $[21] !== options || $[22] !== palette ? (t8 = /* @__PURE__ */ jsx(ImagePaletteSection, {
|
|
1494
|
+
imageUrl,
|
|
1495
|
+
onLucky,
|
|
1496
|
+
onPalette,
|
|
1497
|
+
onVariant,
|
|
1498
|
+
options,
|
|
1499
|
+
palette
|
|
1500
|
+
}), $[17] = imageUrl, $[18] = onLucky, $[19] = onPalette, $[20] = onVariant, $[21] = options, $[22] = palette, $[23] = t8) : t8 = $[23];
|
|
1501
|
+
let t9;
|
|
1502
|
+
$[24] !== options || $[25] !== palettes || $[26] !== patchScheme || $[27] !== resolved || $[28] !== split || $[29] !== studioScheme ? (t9 = SCHEMES.map((scheme_0) => /* @__PURE__ */ jsx(SchemeCard, {
|
|
1503
|
+
active: split || scheme_0 === studioScheme,
|
|
1504
|
+
onChange: (changes_0) => patchScheme(scheme_0, changes_0),
|
|
1505
|
+
options: options[scheme_0] ?? {},
|
|
1506
|
+
palette: palettes[scheme_0],
|
|
1507
|
+
resolved: resolved[scheme_0],
|
|
1508
|
+
scheme: scheme_0,
|
|
1509
|
+
split
|
|
1510
|
+
}, scheme_0)), $[24] = options, $[25] = palettes, $[26] = patchScheme, $[27] = resolved, $[28] = split, $[29] = studioScheme, $[30] = t9) : t9 = $[30];
|
|
1511
|
+
let t10;
|
|
1512
|
+
$[31] === t9 ? t10 = $[32] : (t10 = /* @__PURE__ */ jsx(ScrollAreaBleed, { children: t9 }), $[31] = t9, $[32] = t10);
|
|
1513
|
+
let t11;
|
|
1514
|
+
$[33] !== t10 || $[34] !== t3 || $[35] !== t7 || $[36] !== t8 ? (t11 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
1515
|
+
padding: 3,
|
|
1516
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1517
|
+
gap: 4,
|
|
1518
|
+
children: [
|
|
1519
|
+
t3,
|
|
1520
|
+
t7,
|
|
1521
|
+
t8,
|
|
1522
|
+
t10
|
|
1523
|
+
]
|
|
1524
|
+
})
|
|
1525
|
+
}), $[33] = t10, $[34] = t3, $[35] = t7, $[36] = t8, $[37] = t11) : t11 = $[37];
|
|
1526
|
+
let t12;
|
|
1527
|
+
$[38] === onRemove ? t12 = $[39] : (t12 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
1528
|
+
icon: TrashIcon,
|
|
1529
|
+
mode: "ghost",
|
|
1530
|
+
onClick: onRemove,
|
|
1531
|
+
text: "Remove",
|
|
1532
|
+
tone: "critical",
|
|
1533
|
+
tooltip: "Remove the theme — it can be restored until it is deleted"
|
|
1534
|
+
}), $[38] = onRemove, $[39] = t12);
|
|
1535
|
+
let t13;
|
|
1536
|
+
$[40] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Box, { flex: 1 }), $[40] = t13) : t13 = $[40];
|
|
1537
|
+
let t14;
|
|
1538
|
+
$[41] === onDone ? t14 = $[42] : (t14 = /* @__PURE__ */ jsx(Button, {
|
|
1539
|
+
mode: "ghost",
|
|
1540
|
+
onClick: onDone,
|
|
1541
|
+
text: "Done"
|
|
1542
|
+
}), $[41] = onDone, $[42] = t14);
|
|
1543
|
+
let t15;
|
|
1544
|
+
$[43] !== t12 || $[44] !== t14 ? (t15 = /* @__PURE__ */ jsx(Card, {
|
|
1545
|
+
borderTop: !0,
|
|
1546
|
+
padding: 3,
|
|
1547
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1548
|
+
gap: 2,
|
|
1549
|
+
children: [
|
|
1550
|
+
t12,
|
|
1551
|
+
t13,
|
|
1552
|
+
t14
|
|
1553
|
+
]
|
|
1554
|
+
})
|
|
1555
|
+
}), $[43] = t12, $[44] = t14, $[45] = t15) : t15 = $[45];
|
|
1556
|
+
let t16;
|
|
1557
|
+
return $[46] !== t11 || $[47] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Fragment, { children: [t11, t15] }), $[46] = t11, $[47] = t15, $[48] = t16) : t16 = $[48], t16;
|
|
1558
|
+
}
|
|
1559
|
+
function _temp$1(event_0) {
|
|
1560
|
+
return event_0.currentTarget.select();
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* The colors of one scheme. The cards span the sidebar edge to edge, one
|
|
1564
|
+
* after the other with a border between them, in the sidebar's own scheme —
|
|
1565
|
+
* the swatches show the colors they edit. The scheme the Studio is showing is
|
|
1566
|
+
* marked as active: its changes show up in the Studio right away, the other
|
|
1567
|
+
* scheme's only once the appearance setting switches to it — or both are
|
|
1568
|
+
* active, in the split preview.
|
|
1569
|
+
*/
|
|
1570
|
+
function SchemeCard(props) {
|
|
1571
|
+
let $ = c(66), { active, onChange, options, palette, resolved, scheme, split } = props, name = SCHEME_TITLES[scheme], t0;
|
|
1572
|
+
$[0] === name ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Box, {
|
|
1573
|
+
flex: 1,
|
|
1574
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1575
|
+
size: 1,
|
|
1576
|
+
weight: "medium",
|
|
1577
|
+
children: name
|
|
1578
|
+
})
|
|
1579
|
+
}), $[0] = name, $[1] = t0);
|
|
1580
|
+
let t1;
|
|
1581
|
+
$[2] === active ? t1 = $[3] : (t1 = active && /* @__PURE__ */ jsx(Badge, {
|
|
1582
|
+
fontSize: 0,
|
|
1583
|
+
tone: "primary",
|
|
1584
|
+
children: "Active"
|
|
1585
|
+
}), $[2] = active, $[3] = t1);
|
|
1586
|
+
let t2;
|
|
1587
|
+
$[4] !== t0 || $[5] !== t1 ? (t2 = /* @__PURE__ */ jsxs(Flex, {
|
|
1588
|
+
align: "center",
|
|
1589
|
+
gap: 2,
|
|
1590
|
+
children: [t0, t1]
|
|
1591
|
+
}), $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
|
|
1592
|
+
let t3 = split ? SPLIT_HINTS[scheme] : active ? "Shown in the Studio right now" : `Shown once the Studio appearance is ${scheme}`, t4;
|
|
1593
|
+
$[7] === t3 ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
1594
|
+
muted: !0,
|
|
1595
|
+
size: 0,
|
|
1596
|
+
children: t3
|
|
1597
|
+
}), $[7] = t3, $[8] = t4);
|
|
1598
|
+
let t5;
|
|
1599
|
+
$[9] !== t2 || $[10] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Stack, {
|
|
1600
|
+
gap: 2,
|
|
1601
|
+
children: [t2, t4]
|
|
1602
|
+
}), $[9] = t2, $[10] = t4, $[11] = t5) : t5 = $[11];
|
|
1603
|
+
let t6 = options.accent === void 0, t7 = `${name} accent`, t8, t9;
|
|
1604
|
+
$[12] === onChange ? (t8 = $[13], t9 = $[14]) : (t8 = (accent) => onChange({ accent }), t9 = () => onChange({ accent: void 0 }), $[12] = onChange, $[13] = t8, $[14] = t9);
|
|
1605
|
+
let t10;
|
|
1606
|
+
$[15] !== resolved.accent || $[16] !== t6 || $[17] !== t7 || $[18] !== t8 || $[19] !== t9 ? (t10 = /* @__PURE__ */ jsx(ColorRow, {
|
|
1607
|
+
auto: t6,
|
|
1608
|
+
autoLabel: "default",
|
|
1609
|
+
label: t7,
|
|
1610
|
+
onChange: t8,
|
|
1611
|
+
onClear: t9,
|
|
1612
|
+
title: "Accent",
|
|
1613
|
+
value: resolved.accent
|
|
1614
|
+
}), $[15] = resolved.accent, $[16] = t6, $[17] = t7, $[18] = t8, $[19] = t9, $[20] = t10) : t10 = $[20];
|
|
1615
|
+
let t11 = options.text === void 0, t12 = `${name} text`, t13, t14;
|
|
1616
|
+
$[21] === onChange ? (t13 = $[22], t14 = $[23]) : (t13 = (text) => onChange({ text }), t14 = () => onChange({ text: void 0 }), $[21] = onChange, $[22] = t13, $[23] = t14);
|
|
1617
|
+
let t15;
|
|
1618
|
+
$[24] !== resolved.text || $[25] !== t11 || $[26] !== t12 || $[27] !== t13 || $[28] !== t14 ? (t15 = /* @__PURE__ */ jsx(ColorRow, {
|
|
1619
|
+
auto: t11,
|
|
1620
|
+
label: t12,
|
|
1621
|
+
onChange: t13,
|
|
1622
|
+
onClear: t14,
|
|
1623
|
+
title: "Text",
|
|
1624
|
+
value: resolved.text
|
|
1625
|
+
}), $[24] = resolved.text, $[25] = t11, $[26] = t12, $[27] = t13, $[28] = t14, $[29] = t15) : t15 = $[29];
|
|
1626
|
+
let t16 = scheme === "dark" ? palette.black : palette.white, t17 = options.background === void 0, t18 = `${name} background`, t19, t20;
|
|
1627
|
+
$[30] === onChange ? (t19 = $[31], t20 = $[32]) : (t19 = (background) => onChange({ background }), t20 = () => onChange({ background: void 0 }), $[30] = onChange, $[31] = t19, $[32] = t20);
|
|
1628
|
+
let t21;
|
|
1629
|
+
$[33] !== resolved.background || $[34] !== t16 || $[35] !== t17 || $[36] !== t18 || $[37] !== t19 || $[38] !== t20 ? (t21 = /* @__PURE__ */ jsx(ColorRow, {
|
|
1630
|
+
adjusted: t16,
|
|
1631
|
+
auto: t17,
|
|
1632
|
+
label: t18,
|
|
1633
|
+
onChange: t19,
|
|
1634
|
+
onClear: t20,
|
|
1635
|
+
title: "Background",
|
|
1636
|
+
value: resolved.background
|
|
1637
|
+
}), $[33] = resolved.background, $[34] = t16, $[35] = t17, $[36] = t18, $[37] = t19, $[38] = t20, $[39] = t21) : t21 = $[39];
|
|
1638
|
+
let t22;
|
|
1639
|
+
$[40] === Symbol.for("react.memo_cache_sentinel") ? (t22 = /* @__PURE__ */ jsx(Text, {
|
|
1640
|
+
size: 1,
|
|
1641
|
+
children: "Contrast"
|
|
1642
|
+
}), $[40] = t22) : t22 = $[40];
|
|
1643
|
+
let t23 = options.contrast === void 0 ? " · auto" : "", t24;
|
|
1644
|
+
$[41] !== resolved.contrast || $[42] !== t23 ? (t24 = /* @__PURE__ */ jsxs(Stack, {
|
|
1645
|
+
flex: 1,
|
|
1646
|
+
gap: 2,
|
|
1647
|
+
children: [t22, /* @__PURE__ */ jsxs(Text, {
|
|
1648
|
+
muted: !0,
|
|
1649
|
+
size: 0,
|
|
1650
|
+
children: [resolved.contrast, t23]
|
|
1651
|
+
})]
|
|
1652
|
+
}), $[41] = resolved.contrast, $[42] = t23, $[43] = t24) : t24 = $[43];
|
|
1653
|
+
let t25;
|
|
1654
|
+
$[44] !== onChange || $[45] !== options.contrast ? (t25 = options.contrast !== void 0 && /* @__PURE__ */ jsx(TooltipButton, {
|
|
1655
|
+
icon: ResetIcon,
|
|
1656
|
+
mode: "bleed",
|
|
1657
|
+
onClick: () => onChange({ contrast: void 0 }),
|
|
1658
|
+
padding: 2,
|
|
1659
|
+
tooltip: "Reset to auto"
|
|
1660
|
+
}), $[44] = onChange, $[45] = options.contrast, $[46] = t25) : t25 = $[46];
|
|
1661
|
+
let t26;
|
|
1662
|
+
$[47] !== t24 || $[48] !== t25 ? (t26 = /* @__PURE__ */ jsxs(Flex, {
|
|
1663
|
+
align: "center",
|
|
1664
|
+
gap: 2,
|
|
1665
|
+
children: [t24, t25]
|
|
1666
|
+
}), $[47] = t24, $[48] = t25, $[49] = t26) : t26 = $[49];
|
|
1667
|
+
let t27 = `${name} contrast`, t28;
|
|
1668
|
+
$[50] === onChange ? t28 = $[51] : (t28 = (event) => onChange({ contrast: Number(event.currentTarget.value) }), $[50] = onChange, $[51] = t28);
|
|
1669
|
+
let t29;
|
|
1670
|
+
$[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx(Range, {
|
|
1671
|
+
"aria-label": t27,
|
|
1672
|
+
max: 100,
|
|
1673
|
+
min: 15,
|
|
1674
|
+
onChange: t28,
|
|
1675
|
+
step: 1,
|
|
1676
|
+
type: "range",
|
|
1677
|
+
value: resolved.contrast
|
|
1678
|
+
}), $[52] = resolved.contrast, $[53] = t27, $[54] = t28, $[55] = t29) : t29 = $[55];
|
|
1679
|
+
let t30;
|
|
1680
|
+
$[56] === Symbol.for("react.memo_cache_sentinel") ? (t30 = /* @__PURE__ */ jsx(Text, {
|
|
1681
|
+
muted: !0,
|
|
1682
|
+
size: 0,
|
|
1683
|
+
children: "100 keeps text and borders neutral — lower values blend in the accent"
|
|
1684
|
+
}), $[56] = t30) : t30 = $[56];
|
|
1685
|
+
let t31;
|
|
1686
|
+
$[57] !== t26 || $[58] !== t29 ? (t31 = /* @__PURE__ */ jsxs(Stack, {
|
|
1687
|
+
gap: 3,
|
|
1688
|
+
children: [
|
|
1689
|
+
t26,
|
|
1690
|
+
t29,
|
|
1691
|
+
t30
|
|
1692
|
+
]
|
|
1693
|
+
}), $[57] = t26, $[58] = t29, $[59] = t31) : t31 = $[59];
|
|
1694
|
+
let t32;
|
|
1695
|
+
return $[60] !== t10 || $[61] !== t15 || $[62] !== t21 || $[63] !== t31 || $[64] !== t5 ? (t32 = /* @__PURE__ */ jsx(Card, {
|
|
1696
|
+
borderTop: !0,
|
|
1697
|
+
padding: 3,
|
|
1698
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1699
|
+
gap: 4,
|
|
1700
|
+
children: [
|
|
1701
|
+
t5,
|
|
1702
|
+
t10,
|
|
1703
|
+
t15,
|
|
1704
|
+
t21,
|
|
1705
|
+
t31
|
|
1706
|
+
]
|
|
1707
|
+
})
|
|
1708
|
+
}), $[60] = t10, $[61] = t15, $[62] = t21, $[63] = t31, $[64] = t5, $[65] = t32) : t32 = $[65], t32;
|
|
1709
|
+
}
|
|
1710
|
+
/** One color of a scheme: a swatch with its value and an optional reset button */
|
|
1711
|
+
function ColorRow(props) {
|
|
1712
|
+
let $ = c(24), { adjusted, auto, autoLabel: t0, label, onChange, onClear, title, value } = props, autoLabel = t0 === void 0 ? "auto" : t0, t1;
|
|
1713
|
+
$[0] === onChange ? t1 = $[1] : (t1 = (event) => onChange(event.currentTarget.value), $[0] = onChange, $[1] = t1);
|
|
1714
|
+
let t2;
|
|
1715
|
+
$[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx(Swatch, {
|
|
1716
|
+
"aria-label": label,
|
|
1717
|
+
onChange: t1,
|
|
1718
|
+
type: "color",
|
|
1719
|
+
value
|
|
1720
|
+
}), $[2] = label, $[3] = t1, $[4] = value, $[5] = t2) : t2 = $[5];
|
|
1721
|
+
let t3;
|
|
1722
|
+
$[6] === Symbol.for("react.memo_cache_sentinel") ? (t3 = { minWidth: 0 }, $[6] = t3) : t3 = $[6];
|
|
1723
|
+
let t4;
|
|
1724
|
+
$[7] === title ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
1725
|
+
size: 1,
|
|
1726
|
+
children: title
|
|
1727
|
+
}), $[7] = title, $[8] = t4);
|
|
1728
|
+
let t5 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t6 = auto ? ` · ${autoLabel}` : "", t7;
|
|
1729
|
+
$[9] !== t5 || $[10] !== t6 || $[11] !== value ? (t7 = /* @__PURE__ */ jsxs(Text, {
|
|
1730
|
+
muted: !0,
|
|
1731
|
+
size: 0,
|
|
1732
|
+
textOverflow: "ellipsis",
|
|
1733
|
+
children: [
|
|
1734
|
+
value,
|
|
1735
|
+
t5,
|
|
1736
|
+
t6
|
|
1737
|
+
]
|
|
1738
|
+
}), $[9] = t5, $[10] = t6, $[11] = value, $[12] = t7) : t7 = $[12];
|
|
1739
|
+
let t8;
|
|
1740
|
+
$[13] !== t4 || $[14] !== t7 ? (t8 = /* @__PURE__ */ jsxs(Stack, {
|
|
1741
|
+
flex: 1,
|
|
1742
|
+
gap: 2,
|
|
1743
|
+
style: t3,
|
|
1744
|
+
children: [t4, t7]
|
|
1745
|
+
}), $[13] = t4, $[14] = t7, $[15] = t8) : t8 = $[15];
|
|
1746
|
+
let t9;
|
|
1747
|
+
$[16] !== auto || $[17] !== autoLabel || $[18] !== onClear ? (t9 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
|
|
1748
|
+
icon: ResetIcon,
|
|
1749
|
+
mode: "bleed",
|
|
1750
|
+
onClick: onClear,
|
|
1751
|
+
padding: 2,
|
|
1752
|
+
tooltip: `Reset to ${autoLabel}`
|
|
1753
|
+
}), $[16] = auto, $[17] = autoLabel, $[18] = onClear, $[19] = t9) : t9 = $[19];
|
|
1754
|
+
let t10;
|
|
1755
|
+
return $[20] !== t2 || $[21] !== t8 || $[22] !== t9 ? (t10 = /* @__PURE__ */ jsxs(Flex, {
|
|
1756
|
+
align: "center",
|
|
1757
|
+
gap: 2,
|
|
1758
|
+
children: [
|
|
1759
|
+
t2,
|
|
1760
|
+
t8,
|
|
1761
|
+
t9
|
|
1762
|
+
]
|
|
1763
|
+
}), $[20] = t2, $[21] = t8, $[22] = t9, $[23] = t10) : t10 = $[23], t10;
|
|
1764
|
+
}
|
|
1765
|
+
const Root = styled.div.withConfig({
|
|
1766
|
+
displayName: "Root",
|
|
1767
|
+
componentId: "sc-krwbzw-0"
|
|
1768
|
+
})`position:relative;`, PickButton = styled.button.withConfig({
|
|
1769
|
+
displayName: "PickButton",
|
|
1770
|
+
componentId: "sc-krwbzw-1"
|
|
1771
|
+
})`appearance:none;display:block;box-sizing:border-box;width:100%;margin:0;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:center;cursor:pointer;&:focus{outline:none;}`, Frame$1 = styled.span.withConfig({
|
|
1772
|
+
displayName: "Frame",
|
|
1773
|
+
componentId: "sc-krwbzw-2"
|
|
1774
|
+
})`display:block;padding:4px;border-radius:10px;transition:box-shadow 100ms;${PickButton}:hover &{box-shadow:inset 0 0 0 2px var(--card-border-color);}${PickButton}[aria-pressed='true'] &{box-shadow:inset 0 0 0 2px var(--card-focus-ring-color);}${PickButton}:focus-visible &{outline:2px solid var(--card-focus-ring-color);outline-offset:-2px;}`, MenuSlot = styled.div.withConfig({
|
|
1775
|
+
displayName: "MenuSlot",
|
|
1776
|
+
componentId: "sc-krwbzw-3"
|
|
1777
|
+
})`position:absolute;top:10px;right:10px;opacity:0;transition:opacity 100ms;${Root}:hover &,${Root}:focus-within &,&[data-visible='true']{opacity:1;}`;
|
|
1778
|
+
/**
|
|
1779
|
+
* One theme in the list: the floating preview with the title below it, like
|
|
1780
|
+
* an appearance option in macOS System Settings. Clicking it applies the
|
|
1781
|
+
* theme to the whole Studio; its menu holds the edit, duplicate and remove
|
|
1782
|
+
* flows that apply to the theme.
|
|
1783
|
+
*
|
|
1784
|
+
* @internal
|
|
1785
|
+
*/
|
|
1786
|
+
function ThemeCard(props) {
|
|
1787
|
+
let $ = c(52), { active, theme } = props, { send } = useThemer(), { scheme } = useRootTheme(), [menuOpen, setMenuOpen] = useState(!1), t0;
|
|
1788
|
+
$[0] === theme.title ? t0 = $[1] : (t0 = displayTitle(theme.title), $[0] = theme.title, $[1] = t0);
|
|
1789
|
+
let title = t0, t1;
|
|
1790
|
+
$[2] !== send || $[3] !== theme.slug ? (t1 = () => send({
|
|
1791
|
+
type: "theme.pick",
|
|
1792
|
+
slug: theme.slug
|
|
1793
|
+
}), $[2] = send, $[3] = theme.slug, $[4] = t1) : t1 = $[4];
|
|
1794
|
+
let t2;
|
|
1795
|
+
$[5] === theme.options ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx(Frame$1, { children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options }) }), $[5] = theme.options, $[6] = t2);
|
|
1796
|
+
let t3 = active ? "medium" : "regular", t4;
|
|
1797
|
+
$[7] !== t3 || $[8] !== title ? (t4 = /* @__PURE__ */ jsx(Box, {
|
|
1798
|
+
as: "span",
|
|
1799
|
+
display: "block",
|
|
1800
|
+
paddingTop: 2,
|
|
1801
|
+
paddingX: 2,
|
|
1802
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1803
|
+
align: "center",
|
|
1804
|
+
as: "span",
|
|
1805
|
+
size: 1,
|
|
1806
|
+
textOverflow: "ellipsis",
|
|
1807
|
+
weight: t3,
|
|
1808
|
+
children: title
|
|
1809
|
+
})
|
|
1810
|
+
}), $[7] = t3, $[8] = title, $[9] = t4) : t4 = $[9];
|
|
1811
|
+
let t5;
|
|
1812
|
+
$[10] !== active || $[11] !== t1 || $[12] !== t2 || $[13] !== t4 ? (t5 = /* @__PURE__ */ jsxs(PickButton, {
|
|
1813
|
+
"aria-pressed": active,
|
|
1814
|
+
onClick: t1,
|
|
1815
|
+
type: "button",
|
|
1816
|
+
children: [t2, t4]
|
|
1817
|
+
}), $[10] = active, $[11] = t1, $[12] = t2, $[13] = t4, $[14] = t5) : t5 = $[14];
|
|
1818
|
+
let t6;
|
|
1819
|
+
$[15] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsx(Text, {
|
|
1820
|
+
size: 1,
|
|
1821
|
+
children: "Show more"
|
|
1822
|
+
}), $[15] = t6) : t6 = $[15];
|
|
1823
|
+
let t7;
|
|
1824
|
+
$[16] === Symbol.for("react.memo_cache_sentinel") ? (t7 = { display: "inline-block" }, $[16] = t7) : t7 = $[16];
|
|
1825
|
+
let t8 = `Show more for ${title}`, t9;
|
|
1826
|
+
$[17] === t8 ? t9 = $[18] : (t9 = /* @__PURE__ */ jsx(Button, {
|
|
1827
|
+
"aria-label": t8,
|
|
1828
|
+
fontSize: 1,
|
|
1829
|
+
icon: EllipsisHorizontalIcon,
|
|
1830
|
+
mode: "ghost",
|
|
1831
|
+
padding: 1,
|
|
1832
|
+
radius: 2
|
|
1833
|
+
}), $[17] = t8, $[18] = t9);
|
|
1834
|
+
let t10 = `themer-theme-${theme.slug}`, t11;
|
|
1835
|
+
$[19] !== send || $[20] !== theme.slug || $[21] !== theme.source ? (t11 = theme.source === "custom" && /* @__PURE__ */ jsx(MenuItem, {
|
|
1836
|
+
icon: EditIcon,
|
|
1837
|
+
onClick: () => send({
|
|
1838
|
+
type: "theme.edit",
|
|
1839
|
+
slug: theme.slug
|
|
1840
|
+
}),
|
|
1841
|
+
text: "Edit"
|
|
1842
|
+
}), $[19] = send, $[20] = theme.slug, $[21] = theme.source, $[22] = t11) : t11 = $[22];
|
|
1843
|
+
let t12;
|
|
1844
|
+
$[23] !== send || $[24] !== theme.slug ? (t12 = () => send({
|
|
1845
|
+
type: "theme.duplicate",
|
|
1846
|
+
slug: theme.slug
|
|
1847
|
+
}), $[23] = send, $[24] = theme.slug, $[25] = t12) : t12 = $[25];
|
|
1848
|
+
let t13 = theme.source === "custom" ? "Duplicate" : "Duplicate to edit", t14;
|
|
1849
|
+
$[26] !== t12 || $[27] !== t13 ? (t14 = /* @__PURE__ */ jsx(MenuItem, {
|
|
1850
|
+
icon: CopyIcon,
|
|
1851
|
+
onClick: t12,
|
|
1852
|
+
text: t13
|
|
1853
|
+
}), $[26] = t12, $[27] = t13, $[28] = t14) : t14 = $[28];
|
|
1854
|
+
let t15;
|
|
1855
|
+
$[29] !== send || $[30] !== theme.slug || $[31] !== theme.source ? (t15 = theme.source !== "config" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx(MenuItem, {
|
|
1856
|
+
icon: TrashIcon,
|
|
1857
|
+
onClick: () => send({
|
|
1858
|
+
type: "theme.remove",
|
|
1859
|
+
slug: theme.slug
|
|
1860
|
+
}),
|
|
1861
|
+
text: "Remove",
|
|
1862
|
+
tone: "critical"
|
|
1863
|
+
})] }), $[29] = send, $[30] = theme.slug, $[31] = theme.source, $[32] = t15) : t15 = $[32];
|
|
1864
|
+
let t16;
|
|
1865
|
+
$[33] !== t11 || $[34] !== t14 || $[35] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Menu, { children: [
|
|
1866
|
+
t11,
|
|
1867
|
+
t14,
|
|
1868
|
+
t15
|
|
1869
|
+
] }), $[33] = t11, $[34] = t14, $[35] = t15, $[36] = t16) : t16 = $[36];
|
|
1870
|
+
let t17, t18;
|
|
1871
|
+
$[37] === Symbol.for("react.memo_cache_sentinel") ? (t17 = () => setMenuOpen(!1), t18 = () => setMenuOpen(!0), $[37] = t17, $[38] = t18) : (t17 = $[37], t18 = $[38]);
|
|
1872
|
+
let t19;
|
|
1873
|
+
$[39] === scheme ? t19 = $[40] : (t19 = {
|
|
1874
|
+
animate: !0,
|
|
1875
|
+
placement: "bottom-end",
|
|
1876
|
+
portal: !0,
|
|
1877
|
+
scheme
|
|
1878
|
+
}, $[39] = scheme, $[40] = t19);
|
|
1879
|
+
let t20;
|
|
1880
|
+
$[41] !== t10 || $[42] !== t16 || $[43] !== t19 || $[44] !== t9 ? (t20 = /* @__PURE__ */ jsx(Tooltip, {
|
|
1881
|
+
animate: !0,
|
|
1882
|
+
content: t6,
|
|
1883
|
+
placement: "bottom",
|
|
1884
|
+
portal: !0,
|
|
1885
|
+
children: /* @__PURE__ */ jsx(Card, {
|
|
1886
|
+
radius: 2,
|
|
1887
|
+
scheme: "dark",
|
|
1888
|
+
style: t7,
|
|
1889
|
+
children: /* @__PURE__ */ jsx(MenuButton, {
|
|
1890
|
+
button: t9,
|
|
1891
|
+
id: t10,
|
|
1892
|
+
menu: t16,
|
|
1893
|
+
onClose: t17,
|
|
1894
|
+
onOpen: t18,
|
|
1895
|
+
popover: t19
|
|
1896
|
+
})
|
|
1897
|
+
})
|
|
1898
|
+
}), $[41] = t10, $[42] = t16, $[43] = t19, $[44] = t9, $[45] = t20) : t20 = $[45];
|
|
1899
|
+
let t21;
|
|
1900
|
+
$[46] !== menuOpen || $[47] !== t20 ? (t21 = /* @__PURE__ */ jsx(MenuSlot, {
|
|
1901
|
+
"data-visible": menuOpen,
|
|
1902
|
+
children: t20
|
|
1903
|
+
}), $[46] = menuOpen, $[47] = t20, $[48] = t21) : t21 = $[48];
|
|
1904
|
+
let t22;
|
|
1905
|
+
return $[49] !== t21 || $[50] !== t5 ? (t22 = /* @__PURE__ */ jsxs(Root, { children: [t5, t21] }), $[49] = t21, $[50] = t5, $[51] = t22) : t22 = $[51], t22;
|
|
1906
|
+
}
|
|
1907
|
+
/**
|
|
1908
|
+
* The flow for picking a theme: one column of theme cards — the configured
|
|
1909
|
+
* theme, the presets and the user's own themes — with the entry points to
|
|
1910
|
+
* the add and restore flows below.
|
|
1911
|
+
*
|
|
1912
|
+
* @internal
|
|
1913
|
+
*/
|
|
1914
|
+
function ThemeList() {
|
|
1915
|
+
let $ = c(24), { themes, removed, active, send } = useThemer(), t0;
|
|
1916
|
+
$[0] === send ? t0 = $[1] : (t0 = (palette, file) => send({
|
|
1917
|
+
type: "theme.add",
|
|
1918
|
+
title: titleFromFileName(file.name),
|
|
1919
|
+
options: optionsFromImagePalette(palette),
|
|
1920
|
+
palette,
|
|
1921
|
+
imageUrl: URL.createObjectURL(file)
|
|
1922
|
+
}), $[0] = send, $[1] = t0);
|
|
1923
|
+
let { busy, pickImage } = useImagePalette(t0), t1;
|
|
1924
|
+
if ($[2] !== active || $[3] !== themes) {
|
|
1925
|
+
let t2;
|
|
1926
|
+
$[5] === active ? t2 = $[6] : (t2 = (theme) => /* @__PURE__ */ jsx(ThemeCard, {
|
|
1927
|
+
active: theme.slug === active.slug,
|
|
1928
|
+
theme
|
|
1929
|
+
}, theme.slug), $[5] = active, $[6] = t2), t1 = themes.map(t2), $[2] = active, $[3] = themes, $[4] = t1;
|
|
1930
|
+
} else t1 = $[4];
|
|
1931
|
+
let t2;
|
|
1932
|
+
$[7] !== removed.length || $[8] !== send ? (t2 = removed.length > 0 && /* @__PURE__ */ jsx(Button, {
|
|
1933
|
+
icon: RestoreIcon,
|
|
1934
|
+
mode: "bleed",
|
|
1935
|
+
onClick: () => send({ type: "flow.removed" }),
|
|
1936
|
+
text: `Show removed (${removed.length})`,
|
|
1937
|
+
width: "fill"
|
|
1938
|
+
}), $[7] = removed.length, $[8] = send, $[9] = t2) : t2 = $[9];
|
|
1939
|
+
let t3;
|
|
1940
|
+
$[10] !== t1 || $[11] !== t2 ? (t3 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
1941
|
+
padding: 3,
|
|
1942
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1943
|
+
gap: 4,
|
|
1944
|
+
children: [t1, t2]
|
|
1945
|
+
})
|
|
1946
|
+
}), $[10] = t1, $[11] = t2, $[12] = t3) : t3 = $[12];
|
|
1947
|
+
let t4;
|
|
1948
|
+
$[13] === send ? t4 = $[14] : (t4 = /* @__PURE__ */ jsx(Box, {
|
|
1949
|
+
flex: 1,
|
|
1950
|
+
children: /* @__PURE__ */ jsx(TooltipButton, {
|
|
1951
|
+
icon: AddIcon,
|
|
1952
|
+
mode: "ghost",
|
|
1953
|
+
onClick: () => send({ type: "theme.add" }),
|
|
1954
|
+
text: "Add theme",
|
|
1955
|
+
tooltip: "Add a theme based on the applied one",
|
|
1956
|
+
width: "fill"
|
|
1957
|
+
})
|
|
1958
|
+
}), $[13] = send, $[14] = t4);
|
|
1959
|
+
let t5;
|
|
1960
|
+
$[15] !== busy || $[16] !== pickImage ? (t5 = /* @__PURE__ */ jsx(ImageFileButton, {
|
|
1961
|
+
loading: busy,
|
|
1962
|
+
mode: "ghost",
|
|
1963
|
+
onFile: pickImage,
|
|
1964
|
+
tooltip: "Add a theme from the colors of an image"
|
|
1965
|
+
}), $[15] = busy, $[16] = pickImage, $[17] = t5) : t5 = $[17];
|
|
1966
|
+
let t6;
|
|
1967
|
+
$[18] !== t4 || $[19] !== t5 ? (t6 = /* @__PURE__ */ jsx(Card, {
|
|
1968
|
+
borderTop: !0,
|
|
1969
|
+
padding: 3,
|
|
1970
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1971
|
+
gap: 2,
|
|
1972
|
+
children: [t4, t5]
|
|
1973
|
+
})
|
|
1974
|
+
}), $[18] = t4, $[19] = t5, $[20] = t6) : t6 = $[20];
|
|
1975
|
+
let t7;
|
|
1976
|
+
return $[21] !== t3 || $[22] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Fragment, { children: [t3, t6] }), $[21] = t3, $[22] = t6, $[23] = t7) : t7 = $[23], t7;
|
|
51
1977
|
}
|
|
52
1978
|
/**
|
|
53
1979
|
* Serializes theme options into the `buildTheme` call to paste into
|
|
54
|
-
* `sanity.config.ts`, keeping only what differs from the derived defaults
|
|
1980
|
+
* `sanity.config.ts`, keeping only what differs from the derived defaults in
|
|
1981
|
+
* each scheme.
|
|
55
1982
|
*
|
|
56
1983
|
* Options that boil down to the stock Studio theme need nothing from this
|
|
57
1984
|
* package — so they serialize to a bare `buildTheme()` from `@sanity/ui/theme`
|
|
@@ -62,77 +1989,35 @@ function sameOptions(a, b) {
|
|
|
62
1989
|
function createThemeSnippet(options) {
|
|
63
1990
|
let minimized = minimizeOptions(options);
|
|
64
1991
|
if (minimized === null) return "import {buildTheme} from '@sanity/ui/theme'\n\nexport const theme = buildTheme()\n";
|
|
65
|
-
let
|
|
66
|
-
|
|
67
|
-
let
|
|
68
|
-
|
|
1992
|
+
let lines = [];
|
|
1993
|
+
for (let scheme of SCHEMES) {
|
|
1994
|
+
let values = minimized[scheme];
|
|
1995
|
+
values && lines.push(serializeScheme(scheme, values));
|
|
69
1996
|
}
|
|
70
|
-
return
|
|
1997
|
+
return `import {buildTheme} from '@sanity/themer'\n\nexport const theme = buildTheme({\n${lines.join("\n")}\n})\n`;
|
|
1998
|
+
}
|
|
1999
|
+
/** A scheme with up to two options fits on one line, more spread out */
|
|
2000
|
+
function serializeScheme(scheme, values) {
|
|
2001
|
+
let entries = [];
|
|
2002
|
+
return values.accent !== void 0 && entries.push(`accent: '${values.accent}'`), values.text !== void 0 && entries.push(`text: '${values.text}'`), values.background !== void 0 && entries.push(`background: '${values.background}'`), values.contrast !== void 0 && entries.push(`contrast: ${values.contrast}`), entries.length <= 2 ? ` ${scheme}: {${entries.join(", ")}},` : ` ${scheme}: {\n${entries.map((entry) => ` ${entry},`).join("\n")}\n },`;
|
|
71
2003
|
}
|
|
72
2004
|
registerLanguage(typescript);
|
|
73
2005
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*/
|
|
78
|
-
const Swatch = styled.input.withConfig({
|
|
79
|
-
displayName: "Swatch",
|
|
80
|
-
componentId: "sc-7kf8xr-0"
|
|
81
|
-
})`box-sizing:border-box;flex:none;width:33px;height:33px;padding:0;border:1px solid var(--card-border-color);border-radius:4px;background:none;cursor:pointer;&::-webkit-color-swatch-wrapper{padding:0;}&::-webkit-color-swatch{border:none;border-radius:3px;}&::-moz-color-swatch{border:none;border-radius:3px;}`, Range = styled.input.withConfig({
|
|
82
|
-
displayName: "Range",
|
|
83
|
-
componentId: "sc-7kf8xr-1"
|
|
84
|
-
})`display:block;width:100%;margin:0;accent-color:var(--card-focus-ring-color);`;
|
|
85
|
-
/**
|
|
86
|
-
* The themer sidebar: presets, the accent/text/background pickers and the
|
|
87
|
-
* contrast slider that generate the previewed `buildTheme` theme, plus the
|
|
88
|
-
* `buildTheme` snippet to make it permanent.
|
|
2006
|
+
* Shows the `buildTheme` snippet that makes a theme permanent, in a dialog so
|
|
2007
|
+
* that it does not take up sidebar space or make the sidebar scroll as the
|
|
2008
|
+
* snippet changes shape with the theme.
|
|
89
2009
|
*
|
|
90
2010
|
* @internal
|
|
91
2011
|
*/
|
|
92
|
-
function
|
|
93
|
-
let $ = c(
|
|
94
|
-
$[0] ===
|
|
95
|
-
let
|
|
96
|
-
$[2]
|
|
97
|
-
let palette = t1, t2;
|
|
98
|
-
$[4] === active ? t2 = $[5] : (t2 = presets.find((preset) => sameOptions(preset.options, active))?.slug ?? "", $[4] = active, $[5] = t2);
|
|
99
|
-
let activePresetSlug = t2, t3;
|
|
100
|
-
$[6] === active ? t3 = $[7] : (t3 = createThemeSnippet(active), $[6] = active, $[7] = t3);
|
|
101
|
-
let snippet = t3, t4;
|
|
102
|
-
$[8] !== active || $[9] !== setOptions ? (t4 = (changes) => {
|
|
103
|
-
setOptions({
|
|
104
|
-
...active,
|
|
105
|
-
...changes
|
|
106
|
-
});
|
|
107
|
-
}, $[8] = active, $[9] = setOptions, $[10] = t4) : t4 = $[10];
|
|
108
|
-
let patch = t4, t5;
|
|
109
|
-
$[11] !== active || $[12] !== setOptions ? (t5 = (changes_0) => {
|
|
110
|
-
setOptions({
|
|
111
|
-
...active,
|
|
112
|
-
background: {
|
|
113
|
-
...active.background,
|
|
114
|
-
...changes_0
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}, $[11] = active, $[12] = setOptions, $[13] = t5) : t5 = $[13];
|
|
118
|
-
let patchBackground = t5, t6;
|
|
119
|
-
$[14] !== active || $[15] !== setOptions ? (t6 = (field) => {
|
|
120
|
-
let next = { ...active };
|
|
121
|
-
delete next[field], setOptions(next);
|
|
122
|
-
}, $[14] = active, $[15] = setOptions, $[16] = t6) : t6 = $[16];
|
|
123
|
-
let clearField = t6, t7;
|
|
124
|
-
$[17] !== active || $[18] !== setOptions ? (t7 = (key) => {
|
|
125
|
-
let background = { ...active.background };
|
|
126
|
-
delete background[key];
|
|
127
|
-
let next_0 = { ...active };
|
|
128
|
-
background.dark === void 0 && background.light === void 0 ? delete next_0.background : next_0.background = background, setOptions(next_0);
|
|
129
|
-
}, $[17] = active, $[18] = setOptions, $[19] = t7) : t7 = $[19];
|
|
130
|
-
let clearBackground = t7, t8;
|
|
131
|
-
$[20] !== snippet || $[21] !== toast ? (t8 = async () => {
|
|
2012
|
+
function ThemeSnippetDialog(props) {
|
|
2013
|
+
let $ = c(23), { onClose, theme } = props, toast = useToast(), t0;
|
|
2014
|
+
$[0] === theme.options ? t0 = $[1] : (t0 = createThemeSnippet(theme.options), $[0] = theme.options, $[1] = t0);
|
|
2015
|
+
let snippet = t0, t1;
|
|
2016
|
+
$[2] !== snippet || $[3] !== toast ? (t1 = async () => {
|
|
132
2017
|
try {
|
|
133
2018
|
await navigator.clipboard.writeText(snippet), toast.push({
|
|
134
2019
|
status: "success",
|
|
135
|
-
title: "Copied theme to the clipboard"
|
|
2020
|
+
title: "Copied the theme to the clipboard"
|
|
136
2021
|
});
|
|
137
2022
|
} catch {
|
|
138
2023
|
toast.push({
|
|
@@ -140,515 +2025,567 @@ function ThemerSidebar() {
|
|
|
140
2025
|
title: "Could not copy the theme"
|
|
141
2026
|
});
|
|
142
2027
|
}
|
|
143
|
-
}, $[
|
|
144
|
-
let handleCopy =
|
|
145
|
-
$[
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
children: /* @__PURE__ */ jsx(Text, {
|
|
149
|
-
size: 1,
|
|
150
|
-
weight: "semibold",
|
|
151
|
-
children: "Themer"
|
|
152
|
-
})
|
|
153
|
-
}), $[23] = t9) : t9 = $[23];
|
|
154
|
-
let t10;
|
|
155
|
-
$[24] === setOpen ? t10 = $[25] : (t10 = /* @__PURE__ */ jsx(Card, {
|
|
156
|
-
borderBottom: !0,
|
|
2028
|
+
}, $[2] = snippet, $[3] = toast, $[4] = t1) : t1 = $[4];
|
|
2029
|
+
let handleCopy = t1, t2;
|
|
2030
|
+
$[5] === handleCopy ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx(Flex, {
|
|
2031
|
+
gap: 2,
|
|
2032
|
+
justify: "flex-end",
|
|
157
2033
|
padding: 3,
|
|
158
|
-
children: /* @__PURE__ */
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
mode: "bleed",
|
|
164
|
-
onClick: () => setOpen(!1),
|
|
165
|
-
padding: 2,
|
|
166
|
-
title: "Close themer"
|
|
167
|
-
})]
|
|
2034
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
2035
|
+
icon: ClipboardIcon,
|
|
2036
|
+
mode: "ghost",
|
|
2037
|
+
onClick: () => void handleCopy(),
|
|
2038
|
+
text: "Copy"
|
|
168
2039
|
})
|
|
169
|
-
}), $[
|
|
170
|
-
let
|
|
171
|
-
$[
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}), $[
|
|
176
|
-
let
|
|
177
|
-
$[
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
preset: preset_0
|
|
181
|
-
}, preset_0.slug)), $[27] = activePresetSlug, $[28] = setOptions, $[29] = t12) : t12 = $[29];
|
|
182
|
-
let t13;
|
|
183
|
-
$[30] === t12 ? t13 = $[31] : (t13 = /* @__PURE__ */ jsxs(Stack, {
|
|
184
|
-
gap: 3,
|
|
185
|
-
children: [t11, /* @__PURE__ */ jsx(Grid, {
|
|
186
|
-
gap: 2,
|
|
187
|
-
gridTemplateColumns: 2,
|
|
188
|
-
children: t12
|
|
189
|
-
})]
|
|
190
|
-
}), $[30] = t12, $[31] = t13);
|
|
191
|
-
let t14;
|
|
192
|
-
$[32] === Symbol.for("react.memo_cache_sentinel") ? (t14 = /* @__PURE__ */ jsx(Text, {
|
|
193
|
-
size: 1,
|
|
194
|
-
weight: "medium",
|
|
195
|
-
children: "Colors"
|
|
196
|
-
}), $[32] = t14) : t14 = $[32];
|
|
197
|
-
let t15;
|
|
198
|
-
$[33] === patch ? t15 = $[34] : (t15 = (accent) => patch({ accent }), $[33] = patch, $[34] = t15);
|
|
199
|
-
let t16;
|
|
200
|
-
$[35] !== palette.blue || $[36] !== resolved.accent || $[37] !== t15 ? (t16 = /* @__PURE__ */ jsx(ColorRow, {
|
|
201
|
-
onChange: t15,
|
|
202
|
-
tints: palette.blue,
|
|
203
|
-
title: "Accent",
|
|
204
|
-
value: resolved.accent
|
|
205
|
-
}), $[35] = palette.blue, $[36] = resolved.accent, $[37] = t15, $[38] = t16) : t16 = $[38];
|
|
206
|
-
let t17 = active.text === void 0, t18;
|
|
207
|
-
$[39] === patch ? t18 = $[40] : (t18 = (text) => patch({ text }), $[39] = patch, $[40] = t18);
|
|
208
|
-
let t19;
|
|
209
|
-
$[41] === clearField ? t19 = $[42] : (t19 = () => clearField("text"), $[41] = clearField, $[42] = t19);
|
|
210
|
-
let t20;
|
|
211
|
-
$[43] !== palette.gray || $[44] !== resolved.text || $[45] !== t17 || $[46] !== t18 || $[47] !== t19 ? (t20 = /* @__PURE__ */ jsx(ColorRow, {
|
|
212
|
-
auto: t17,
|
|
213
|
-
onChange: t18,
|
|
214
|
-
onClear: t19,
|
|
215
|
-
tints: palette.gray,
|
|
216
|
-
title: "Text",
|
|
217
|
-
value: resolved.text
|
|
218
|
-
}), $[43] = palette.gray, $[44] = resolved.text, $[45] = t17, $[46] = t18, $[47] = t19, $[48] = t20) : t20 = $[48];
|
|
219
|
-
let t21 = active.background?.dark === void 0, t22;
|
|
220
|
-
$[49] === patchBackground ? t22 = $[50] : (t22 = (dark) => patchBackground({ dark }), $[49] = patchBackground, $[50] = t22);
|
|
221
|
-
let t23;
|
|
222
|
-
$[51] === clearBackground ? t23 = $[52] : (t23 = () => clearBackground("dark"), $[51] = clearBackground, $[52] = t23);
|
|
223
|
-
let t24;
|
|
224
|
-
$[53] !== palette.black || $[54] !== resolved.background.dark || $[55] !== t21 || $[56] !== t22 || $[57] !== t23 ? (t24 = /* @__PURE__ */ jsx(ColorRow, {
|
|
225
|
-
adjusted: palette.black,
|
|
226
|
-
auto: t21,
|
|
227
|
-
onChange: t22,
|
|
228
|
-
onClear: t23,
|
|
229
|
-
title: "Background · dark",
|
|
230
|
-
value: resolved.background.dark
|
|
231
|
-
}), $[53] = palette.black, $[54] = resolved.background.dark, $[55] = t21, $[56] = t22, $[57] = t23, $[58] = t24) : t24 = $[58];
|
|
232
|
-
let t25 = active.background?.light === void 0, t26;
|
|
233
|
-
$[59] === patchBackground ? t26 = $[60] : (t26 = (light) => patchBackground({ light }), $[59] = patchBackground, $[60] = t26);
|
|
234
|
-
let t27;
|
|
235
|
-
$[61] === clearBackground ? t27 = $[62] : (t27 = () => clearBackground("light"), $[61] = clearBackground, $[62] = t27);
|
|
236
|
-
let t28;
|
|
237
|
-
$[63] !== palette.white || $[64] !== resolved.background.light || $[65] !== t25 || $[66] !== t26 || $[67] !== t27 ? (t28 = /* @__PURE__ */ jsx(ColorRow, {
|
|
238
|
-
adjusted: palette.white,
|
|
239
|
-
auto: t25,
|
|
240
|
-
onChange: t26,
|
|
241
|
-
onClear: t27,
|
|
242
|
-
title: "Background · light",
|
|
243
|
-
value: resolved.background.light
|
|
244
|
-
}), $[63] = palette.white, $[64] = resolved.background.light, $[65] = t25, $[66] = t26, $[67] = t27, $[68] = t28) : t28 = $[68];
|
|
245
|
-
let t29;
|
|
246
|
-
$[69] !== t16 || $[70] !== t20 || $[71] !== t24 || $[72] !== t28 ? (t29 = /* @__PURE__ */ jsxs(Stack, {
|
|
247
|
-
gap: 3,
|
|
248
|
-
children: [t14, /* @__PURE__ */ jsxs(Stack, {
|
|
249
|
-
gap: 4,
|
|
250
|
-
children: [
|
|
251
|
-
t16,
|
|
252
|
-
t20,
|
|
253
|
-
t24,
|
|
254
|
-
t28
|
|
255
|
-
]
|
|
256
|
-
})]
|
|
257
|
-
}), $[69] = t16, $[70] = t20, $[71] = t24, $[72] = t28, $[73] = t29) : t29 = $[73];
|
|
258
|
-
let t30;
|
|
259
|
-
$[74] === Symbol.for("react.memo_cache_sentinel") ? (t30 = /* @__PURE__ */ jsx(Text, {
|
|
260
|
-
size: 1,
|
|
261
|
-
weight: "medium",
|
|
262
|
-
children: "Contrast"
|
|
263
|
-
}), $[74] = t30) : t30 = $[74];
|
|
264
|
-
let t31 = active.contrast === void 0 ? " · auto" : "", t32;
|
|
265
|
-
$[75] !== resolved.contrast || $[76] !== t31 ? (t32 = /* @__PURE__ */ jsxs(Stack, {
|
|
266
|
-
flex: 1,
|
|
267
|
-
gap: 2,
|
|
268
|
-
children: [t30, /* @__PURE__ */ jsxs(Text, {
|
|
269
|
-
muted: !0,
|
|
270
|
-
size: 0,
|
|
271
|
-
children: [resolved.contrast, t31]
|
|
272
|
-
})]
|
|
273
|
-
}), $[75] = resolved.contrast, $[76] = t31, $[77] = t32) : t32 = $[77];
|
|
274
|
-
let t33;
|
|
275
|
-
$[78] !== active.contrast || $[79] !== clearField ? (t33 = active.contrast !== void 0 && /* @__PURE__ */ jsx(Button, {
|
|
276
|
-
icon: ResetIcon,
|
|
277
|
-
mode: "bleed",
|
|
278
|
-
onClick: () => clearField("contrast"),
|
|
279
|
-
padding: 2,
|
|
280
|
-
title: "Reset to auto"
|
|
281
|
-
}), $[78] = active.contrast, $[79] = clearField, $[80] = t33) : t33 = $[80];
|
|
282
|
-
let t34;
|
|
283
|
-
$[81] !== t32 || $[82] !== t33 ? (t34 = /* @__PURE__ */ jsxs(Flex, {
|
|
284
|
-
align: "center",
|
|
285
|
-
gap: 2,
|
|
286
|
-
children: [t32, t33]
|
|
287
|
-
}), $[81] = t32, $[82] = t33, $[83] = t34) : t34 = $[83];
|
|
288
|
-
let t35;
|
|
289
|
-
$[84] === patch ? t35 = $[85] : (t35 = (event) => patch({ contrast: Number(event.currentTarget.value) }), $[84] = patch, $[85] = t35);
|
|
290
|
-
let t36;
|
|
291
|
-
$[86] !== resolved.contrast || $[87] !== t35 ? (t36 = /* @__PURE__ */ jsx(Range, {
|
|
292
|
-
"aria-label": "Contrast",
|
|
293
|
-
max: 100,
|
|
294
|
-
min: 15,
|
|
295
|
-
onChange: t35,
|
|
296
|
-
step: 1,
|
|
297
|
-
type: "range",
|
|
298
|
-
value: resolved.contrast
|
|
299
|
-
}), $[86] = resolved.contrast, $[87] = t35, $[88] = t36) : t36 = $[88];
|
|
300
|
-
let t37;
|
|
301
|
-
$[89] === Symbol.for("react.memo_cache_sentinel") ? (t37 = /* @__PURE__ */ jsx(Text, {
|
|
2040
|
+
}), $[5] = handleCopy, $[6] = t2);
|
|
2041
|
+
let t3;
|
|
2042
|
+
$[7] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx("code", { children: "sanity.config.ts" }), $[7] = t3) : t3 = $[7];
|
|
2043
|
+
let t4;
|
|
2044
|
+
$[8] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("code", { children: "theme" }), $[8] = t4) : t4 = $[8];
|
|
2045
|
+
let t5;
|
|
2046
|
+
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsx("code", { children: "defineConfig" }), $[9] = t5) : t5 = $[9];
|
|
2047
|
+
let t6;
|
|
2048
|
+
$[10] === theme.title ? t6 = $[11] : (t6 = displayTitle(theme.title), $[10] = theme.title, $[11] = t6);
|
|
2049
|
+
let t7;
|
|
2050
|
+
$[12] === t6 ? t7 = $[13] : (t7 = /* @__PURE__ */ jsxs(Text, {
|
|
302
2051
|
muted: !0,
|
|
303
|
-
size:
|
|
304
|
-
children: "100 keeps text and borders neutral — lower values blend in the accent"
|
|
305
|
-
}), $[89] = t37) : t37 = $[89];
|
|
306
|
-
let t38;
|
|
307
|
-
$[90] !== t34 || $[91] !== t36 ? (t38 = /* @__PURE__ */ jsxs(Stack, {
|
|
308
|
-
gap: 3,
|
|
2052
|
+
size: 1,
|
|
309
2053
|
children: [
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
2054
|
+
"Export this from ",
|
|
2055
|
+
t3,
|
|
2056
|
+
" and pass it as the ",
|
|
2057
|
+
t4,
|
|
2058
|
+
" of",
|
|
2059
|
+
" ",
|
|
2060
|
+
t5,
|
|
2061
|
+
" to make “",
|
|
2062
|
+
t6,
|
|
2063
|
+
"” the Studio theme without this tool."
|
|
313
2064
|
]
|
|
314
|
-
}), $[
|
|
315
|
-
let
|
|
316
|
-
$[
|
|
317
|
-
size: 1,
|
|
318
|
-
weight: "medium",
|
|
319
|
-
children: "Add to your config"
|
|
320
|
-
}), $[93] = t39) : t39 = $[93];
|
|
321
|
-
let t40;
|
|
322
|
-
$[94] === snippet ? t40 = $[95] : (t40 = /* @__PURE__ */ jsx(Card, {
|
|
2065
|
+
}), $[12] = t6, $[13] = t7);
|
|
2066
|
+
let t8;
|
|
2067
|
+
$[14] === snippet ? t8 = $[15] : (t8 = /* @__PURE__ */ jsx(Card, {
|
|
323
2068
|
border: !0,
|
|
324
2069
|
overflow: "auto",
|
|
325
|
-
padding:
|
|
2070
|
+
padding: 3,
|
|
326
2071
|
radius: 2,
|
|
327
2072
|
tone: "transparent",
|
|
328
2073
|
children: /* @__PURE__ */ jsx(Code, {
|
|
329
2074
|
language: "ts",
|
|
330
|
-
size:
|
|
2075
|
+
size: 1,
|
|
331
2076
|
children: snippet
|
|
332
2077
|
})
|
|
333
|
-
}), $[
|
|
334
|
-
let
|
|
335
|
-
$[
|
|
336
|
-
|
|
337
|
-
mode: "ghost",
|
|
338
|
-
onClick: () => void handleCopy(),
|
|
339
|
-
text: "Copy"
|
|
340
|
-
}), $[96] = handleCopy, $[97] = t41);
|
|
341
|
-
let t42 = options === null, t43;
|
|
342
|
-
$[98] === setOptions ? t43 = $[99] : (t43 = () => setOptions(null), $[98] = setOptions, $[99] = t43);
|
|
343
|
-
let t44;
|
|
344
|
-
$[100] !== t42 || $[101] !== t43 ? (t44 = /* @__PURE__ */ jsx(Button, {
|
|
345
|
-
disabled: t42,
|
|
346
|
-
icon: ResetIcon,
|
|
347
|
-
mode: "ghost",
|
|
348
|
-
onClick: t43,
|
|
349
|
-
text: "Reset",
|
|
350
|
-
tone: "critical"
|
|
351
|
-
}), $[100] = t42, $[101] = t43, $[102] = t44) : t44 = $[102];
|
|
352
|
-
let t45;
|
|
353
|
-
$[103] !== t41 || $[104] !== t44 ? (t45 = /* @__PURE__ */ jsxs(Flex, {
|
|
354
|
-
gap: 2,
|
|
355
|
-
children: [t41, t44]
|
|
356
|
-
}), $[103] = t41, $[104] = t44, $[105] = t45) : t45 = $[105];
|
|
357
|
-
let t46;
|
|
358
|
-
$[106] !== t40 || $[107] !== t45 ? (t46 = /* @__PURE__ */ jsxs(Stack, {
|
|
359
|
-
gap: 3,
|
|
360
|
-
children: [
|
|
361
|
-
t39,
|
|
362
|
-
t40,
|
|
363
|
-
t45
|
|
364
|
-
]
|
|
365
|
-
}), $[106] = t40, $[107] = t45, $[108] = t46) : t46 = $[108];
|
|
366
|
-
let t47;
|
|
367
|
-
$[109] !== t13 || $[110] !== t29 || $[111] !== t38 || $[112] !== t46 ? (t47 = /* @__PURE__ */ jsx(Box, {
|
|
368
|
-
flex: 1,
|
|
369
|
-
overflow: "auto",
|
|
370
|
-
padding: 3,
|
|
2078
|
+
}), $[14] = snippet, $[15] = t8);
|
|
2079
|
+
let t9;
|
|
2080
|
+
$[16] !== t7 || $[17] !== t8 ? (t9 = /* @__PURE__ */ jsx(Box, {
|
|
2081
|
+
padding: 4,
|
|
371
2082
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
372
2083
|
gap: 4,
|
|
373
|
-
children: [
|
|
374
|
-
t13,
|
|
375
|
-
t29,
|
|
376
|
-
t38,
|
|
377
|
-
t46
|
|
378
|
-
]
|
|
379
|
-
})
|
|
380
|
-
}), $[109] = t13, $[110] = t29, $[111] = t38, $[112] = t46, $[113] = t47) : t47 = $[113];
|
|
381
|
-
let t48;
|
|
382
|
-
return $[114] !== t10 || $[115] !== t47 ? (t48 = /* @__PURE__ */ jsx(Card, {
|
|
383
|
-
height: "fill",
|
|
384
|
-
children: /* @__PURE__ */ jsxs(Flex, {
|
|
385
|
-
direction: "column",
|
|
386
|
-
height: "fill",
|
|
387
|
-
children: [t10, t47]
|
|
2084
|
+
children: [t7, t8]
|
|
388
2085
|
})
|
|
389
|
-
}), $[
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
function PresetButton(props) {
|
|
402
|
-
let $ = c(27), { active, onClick, preset } = props, t0;
|
|
403
|
-
$[0] === preset.options ? t0 = $[1] : (t0 = resolveThemeOptions(preset.options), $[0] = preset.options, $[1] = t0);
|
|
404
|
-
let resolved = t0, t1;
|
|
405
|
-
$[2] === resolved.accent ? t1 = $[3] : (t1 = ["accent", resolved.accent], $[2] = resolved.accent, $[3] = t1);
|
|
406
|
-
let t2;
|
|
407
|
-
$[4] === resolved.text ? t2 = $[5] : (t2 = ["text", resolved.text], $[4] = resolved.text, $[5] = t2);
|
|
408
|
-
let t3;
|
|
409
|
-
$[6] === resolved.background.dark ? t3 = $[7] : (t3 = ["dark", resolved.background.dark], $[6] = resolved.background.dark, $[7] = t3);
|
|
410
|
-
let t4;
|
|
411
|
-
$[8] === resolved.background.light ? t4 = $[9] : (t4 = ["light", resolved.background.light], $[8] = resolved.background.light, $[9] = t4);
|
|
412
|
-
let t5;
|
|
413
|
-
$[10] !== t1 || $[11] !== t2 || $[12] !== t3 || $[13] !== t4 ? (t5 = [
|
|
414
|
-
t1,
|
|
415
|
-
t2,
|
|
416
|
-
t3,
|
|
417
|
-
t4
|
|
418
|
-
], $[10] = t1, $[11] = t2, $[12] = t3, $[13] = t4, $[14] = t5) : t5 = $[14];
|
|
419
|
-
let swatches = t5, t6;
|
|
420
|
-
$[15] === swatches ? t6 = $[16] : (t6 = /* @__PURE__ */ jsx("span", {
|
|
421
|
-
style: paletteStyle,
|
|
422
|
-
children: swatches.map(_temp$1)
|
|
423
|
-
}), $[15] = swatches, $[16] = t6);
|
|
424
|
-
let t7;
|
|
425
|
-
$[17] === preset.title ? t7 = $[18] : (t7 = /* @__PURE__ */ jsx(Text, {
|
|
426
|
-
align: "left",
|
|
427
|
-
size: 1,
|
|
428
|
-
textOverflow: "ellipsis",
|
|
429
|
-
children: preset.title
|
|
430
|
-
}), $[17] = preset.title, $[18] = t7);
|
|
431
|
-
let t8;
|
|
432
|
-
$[19] !== t6 || $[20] !== t7 ? (t8 = /* @__PURE__ */ jsxs(Stack, {
|
|
433
|
-
as: "span",
|
|
434
|
-
gap: 2,
|
|
435
|
-
children: [t6, t7]
|
|
436
|
-
}), $[19] = t6, $[20] = t7, $[21] = t8) : t8 = $[21];
|
|
437
|
-
let t9;
|
|
438
|
-
return $[22] !== active || $[23] !== onClick || $[24] !== preset.title || $[25] !== t8 ? (t9 = /* @__PURE__ */ jsx(Button, {
|
|
439
|
-
mode: "ghost",
|
|
440
|
-
onClick,
|
|
441
|
-
padding: 2,
|
|
442
|
-
selected: active,
|
|
443
|
-
title: preset.title,
|
|
444
|
-
children: t8
|
|
445
|
-
}), $[22] = active, $[23] = onClick, $[24] = preset.title, $[25] = t8, $[26] = t9) : t9 = $[26], t9;
|
|
446
|
-
}
|
|
447
|
-
function _temp$1(t0) {
|
|
448
|
-
let [key, background] = t0;
|
|
449
|
-
return /* @__PURE__ */ jsx("span", { style: {
|
|
450
|
-
flex: 1,
|
|
451
|
-
background
|
|
452
|
-
} }, key);
|
|
2086
|
+
}), $[16] = t7, $[17] = t8, $[18] = t9) : t9 = $[18];
|
|
2087
|
+
let t10;
|
|
2088
|
+
return $[19] !== onClose || $[20] !== t2 || $[21] !== t9 ? (t10 = /* @__PURE__ */ jsx(Dialog, {
|
|
2089
|
+
animate: !0,
|
|
2090
|
+
footer: t2,
|
|
2091
|
+
header: "Add to your config",
|
|
2092
|
+
id: "themer-snippet",
|
|
2093
|
+
onClickOutside: onClose,
|
|
2094
|
+
onClose,
|
|
2095
|
+
width: 1,
|
|
2096
|
+
children: t9
|
|
2097
|
+
}), $[19] = onClose, $[20] = t2, $[21] = t9, $[22] = t10) : t10 = $[22], t10;
|
|
453
2098
|
}
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
2099
|
+
const VIEW_TITLES = {
|
|
2100
|
+
list: "Themer",
|
|
2101
|
+
edit: "Edit theme",
|
|
2102
|
+
removed: "Removed themes"
|
|
458
2103
|
};
|
|
459
2104
|
/**
|
|
460
|
-
*
|
|
461
|
-
*
|
|
2105
|
+
* The themer sidebar: a header that navigates between the flows and toggles
|
|
2106
|
+
* the split preview, the flow itself — picking a theme, editing one, or
|
|
2107
|
+
* restoring removed ones — and the dialog with the `buildTheme` snippet of
|
|
2108
|
+
* the applied theme.
|
|
2109
|
+
*
|
|
2110
|
+
* @internal
|
|
462
2111
|
*/
|
|
463
|
-
function
|
|
464
|
-
let $ = c(
|
|
465
|
-
$[0]
|
|
2112
|
+
function ThemerSidebar() {
|
|
2113
|
+
let $ = c(41), { active, split, view, send } = useThemer(), [snippetOpen, setSnippetOpen] = useState(!1), inList = view.name === "list", t0;
|
|
2114
|
+
$[0] !== inList || $[1] !== send ? (t0 = !inList && /* @__PURE__ */ jsx(TooltipButton, {
|
|
2115
|
+
icon: ArrowLeftIcon,
|
|
2116
|
+
mode: "bleed",
|
|
2117
|
+
onClick: () => send({ type: "flow.list" }),
|
|
2118
|
+
padding: 2,
|
|
2119
|
+
tooltip: "Back to the themes"
|
|
2120
|
+
}), $[0] = inList, $[1] = send, $[2] = t0) : t0 = $[2];
|
|
2121
|
+
let t1 = +!!inList, t2;
|
|
2122
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t2 = { minWidth: 0 }, $[3] = t2) : t2 = $[3];
|
|
2123
|
+
let t3 = VIEW_TITLES[view.name], t4;
|
|
2124
|
+
$[4] === t3 ? t4 = $[5] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
466
2125
|
size: 1,
|
|
467
|
-
children: title
|
|
468
|
-
}), $[0] = title, $[1] = t0);
|
|
469
|
-
let t1 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t2 = auto ? " · auto" : "", t3;
|
|
470
|
-
$[2] !== t1 || $[3] !== t2 || $[4] !== value ? (t3 = /* @__PURE__ */ jsxs(Text, {
|
|
471
|
-
muted: !0,
|
|
472
|
-
size: 0,
|
|
473
2126
|
textOverflow: "ellipsis",
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
t2
|
|
478
|
-
]
|
|
479
|
-
}), $[2] = t1, $[3] = t2, $[4] = value, $[5] = t3) : t3 = $[5];
|
|
480
|
-
let t4;
|
|
481
|
-
$[6] !== t0 || $[7] !== t3 ? (t4 = /* @__PURE__ */ jsxs(Stack, {
|
|
482
|
-
flex: 1,
|
|
483
|
-
gap: 2,
|
|
484
|
-
children: [t0, t3]
|
|
485
|
-
}), $[6] = t0, $[7] = t3, $[8] = t4) : t4 = $[8];
|
|
2127
|
+
weight: "semibold",
|
|
2128
|
+
children: t3
|
|
2129
|
+
}), $[4] = t3, $[5] = t4);
|
|
486
2130
|
let t5;
|
|
487
|
-
$[
|
|
488
|
-
|
|
2131
|
+
$[6] !== t1 || $[7] !== t4 ? (t5 = /* @__PURE__ */ jsx(Box, {
|
|
2132
|
+
flex: 1,
|
|
2133
|
+
paddingLeft: t1,
|
|
2134
|
+
style: t2,
|
|
2135
|
+
children: t4
|
|
2136
|
+
}), $[6] = t1, $[7] = t4, $[8] = t5) : t5 = $[8];
|
|
2137
|
+
let t6;
|
|
2138
|
+
$[9] !== send || $[10] !== split || $[11] !== view.name ? (t6 = view.name !== "removed" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TooltipButton, {
|
|
2139
|
+
"aria-pressed": split,
|
|
2140
|
+
icon: SplitVerticalIcon,
|
|
489
2141
|
mode: "bleed",
|
|
490
|
-
onClick:
|
|
2142
|
+
onClick: () => send({ type: "preview.toggle" }),
|
|
2143
|
+
padding: 2,
|
|
2144
|
+
selected: split,
|
|
2145
|
+
tooltip: "Show light and dark side by side"
|
|
2146
|
+
}), /* @__PURE__ */ jsx(TooltipButton, {
|
|
2147
|
+
icon: CodeBlockIcon,
|
|
2148
|
+
mode: "bleed",
|
|
2149
|
+
onClick: () => setSnippetOpen(!0),
|
|
2150
|
+
padding: 2,
|
|
2151
|
+
tooltip: "Show the code for the applied theme"
|
|
2152
|
+
})] }), $[9] = send, $[10] = split, $[11] = view.name, $[12] = t6) : t6 = $[12];
|
|
2153
|
+
let t7;
|
|
2154
|
+
$[13] === send ? t7 = $[14] : (t7 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
2155
|
+
icon: CloseIcon,
|
|
2156
|
+
mode: "bleed",
|
|
2157
|
+
onClick: () => send({ type: "sidebar.close" }),
|
|
491
2158
|
padding: 2,
|
|
492
|
-
|
|
493
|
-
}), $[
|
|
494
|
-
let t6 = `${title} color`, t7;
|
|
495
|
-
$[12] === onChange ? t7 = $[13] : (t7 = (event) => onChange(event.currentTarget.value), $[12] = onChange, $[13] = t7);
|
|
2159
|
+
tooltip: "Close themer"
|
|
2160
|
+
}), $[13] = send, $[14] = t7);
|
|
496
2161
|
let t8;
|
|
497
|
-
$[
|
|
498
|
-
"aria-label": t6,
|
|
499
|
-
onChange: t7,
|
|
500
|
-
type: "color",
|
|
501
|
-
value
|
|
502
|
-
}), $[14] = t6, $[15] = t7, $[16] = value, $[17] = t8) : t8 = $[17];
|
|
2162
|
+
$[15] !== t6 || $[16] !== t7 ? (t8 = /* @__PURE__ */ jsxs(Flex, { children: [t6, t7] }), $[15] = t6, $[16] = t7, $[17] = t8) : t8 = $[17];
|
|
503
2163
|
let t9;
|
|
504
|
-
$[18] !==
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
2164
|
+
$[18] !== t0 || $[19] !== t5 || $[20] !== t8 ? (t9 = /* @__PURE__ */ jsx(Card, {
|
|
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];
|
|
513
2176
|
let t10;
|
|
514
|
-
$[22] ===
|
|
515
|
-
style: rampStyle,
|
|
516
|
-
children: COLOR_TINTS.map((tint) => /* @__PURE__ */ jsx("span", { style: {
|
|
517
|
-
flex: 1,
|
|
518
|
-
background: tints[tint]
|
|
519
|
-
} }, tint))
|
|
520
|
-
}), $[22] = tints, $[23] = t10);
|
|
2177
|
+
$[22] === view.name ? t10 = $[23] : (t10 = view.name === "list" && /* @__PURE__ */ jsx(ThemeList, {}), $[22] = view.name, $[23] = t10);
|
|
521
2178
|
let t11;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}), $[24] =
|
|
2179
|
+
$[24] !== view.focusTitle || $[25] !== view.name || $[26] !== view.slug ? (t11 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
|
|
2180
|
+
focusTitle: view.focusTitle,
|
|
2181
|
+
slug: view.slug
|
|
2182
|
+
}), $[24] = view.focusTitle, $[25] = view.name, $[26] = view.slug, $[27] = t11) : t11 = $[27];
|
|
2183
|
+
let t12;
|
|
2184
|
+
$[28] === view.name ? t12 = $[29] : (t12 = view.name === "removed" && /* @__PURE__ */ jsx(RemovedThemes, {}), $[28] = view.name, $[29] = t12);
|
|
2185
|
+
let t13;
|
|
2186
|
+
$[30] !== t10 || $[31] !== t11 || $[32] !== t12 || $[33] !== t9 ? (t13 = /* @__PURE__ */ jsxs(Flex, {
|
|
2187
|
+
direction: "column",
|
|
2188
|
+
height: "fill",
|
|
2189
|
+
children: [
|
|
2190
|
+
t9,
|
|
2191
|
+
t10,
|
|
2192
|
+
t11,
|
|
2193
|
+
t12
|
|
2194
|
+
]
|
|
2195
|
+
}), $[30] = t10, $[31] = t11, $[32] = t12, $[33] = t9, $[34] = t13) : t13 = $[34];
|
|
2196
|
+
let t14;
|
|
2197
|
+
$[35] !== active || $[36] !== snippetOpen ? (t14 = snippetOpen && /* @__PURE__ */ jsx(ThemeSnippetDialog, {
|
|
2198
|
+
onClose: () => setSnippetOpen(!1),
|
|
2199
|
+
theme: active
|
|
2200
|
+
}), $[35] = active, $[36] = snippetOpen, $[37] = t14) : t14 = $[37];
|
|
2201
|
+
let t15;
|
|
2202
|
+
return $[38] !== t13 || $[39] !== t14 ? (t15 = /* @__PURE__ */ jsxs(Card, {
|
|
2203
|
+
height: "fill",
|
|
2204
|
+
children: [t13, t14]
|
|
2205
|
+
}), $[38] = t13, $[39] = t14, $[40] = t15) : t15 = $[40], t15;
|
|
526
2206
|
}
|
|
527
2207
|
/**
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
2208
|
+
* The narrowest the sidebar goes — and its default: narrow enough to leave the
|
|
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.
|
|
531
2211
|
*/
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
2212
|
+
const WIDTH_STORAGE_KEY = "sanityStudio:themer:width";
|
|
2213
|
+
function clampWidth(width) {
|
|
2214
|
+
return Math.min(400, Math.max(200, Math.round(width)));
|
|
2215
|
+
}
|
|
2216
|
+
function readStoredWidth() {
|
|
2217
|
+
try {
|
|
2218
|
+
let stored = Number(localStorage.getItem(WIDTH_STORAGE_KEY));
|
|
2219
|
+
return Number.isFinite(stored) && stored > 0 ? clampWidth(stored) : 200;
|
|
2220
|
+
} catch {
|
|
2221
|
+
return 200;
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
function writeStoredWidth(width) {
|
|
2225
|
+
try {
|
|
2226
|
+
width === 200 ? localStorage.removeItem(WIDTH_STORAGE_KEY) : localStorage.setItem(WIDTH_STORAGE_KEY, String(width));
|
|
2227
|
+
} catch {}
|
|
2228
|
+
}
|
|
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;}`;
|
|
539
2239
|
/**
|
|
540
|
-
*
|
|
541
|
-
*
|
|
2240
|
+
* The themer sidebar, in a layer along the right edge of the Studio. Its left
|
|
2241
|
+
* edge drags (or arrow-keys) it wider, up to twice its default width — the
|
|
2242
|
+
* width sticks between sessions.
|
|
542
2243
|
*
|
|
543
2244
|
* @internal
|
|
544
2245
|
*/
|
|
545
|
-
function
|
|
546
|
-
let $ = c(
|
|
547
|
-
$[0] ===
|
|
548
|
-
let t1;
|
|
549
|
-
$[2] === t0 ? t1 = $[3] : (t1 = /* @__PURE__ */ jsx(Box, {
|
|
550
|
-
flex: 1,
|
|
551
|
-
height: "fill",
|
|
552
|
-
overflow: "auto",
|
|
553
|
-
children: t0
|
|
554
|
-
}), $[2] = t0, $[3] = t1);
|
|
2246
|
+
function ResizableSidebar() {
|
|
2247
|
+
let $ = c(21), [width, setWidth] = useState(readStoredWidth), [dragging, setDragging] = useState(!1), drag = useRef(null), t0, t1;
|
|
2248
|
+
$[0] === width ? (t0 = $[1], t1 = $[2]) : (t0 = () => writeStoredWidth(width), t1 = [width], $[0] = width, $[1] = t0, $[2] = t1), useEffect(t0, t1);
|
|
555
2249
|
let t2;
|
|
556
|
-
$[
|
|
2250
|
+
$[3] === width ? t2 = $[4] : (t2 = (event) => {
|
|
2251
|
+
event.button === 0 && (event.preventDefault(), event.currentTarget.setPointerCapture(event.pointerId), drag.current = {
|
|
2252
|
+
pointerId: event.pointerId,
|
|
2253
|
+
startX: event.clientX,
|
|
2254
|
+
startWidth: width
|
|
2255
|
+
}, setDragging(!0));
|
|
2256
|
+
}, $[3] = width, $[4] = t2);
|
|
2257
|
+
let handlePointerDown = t2, t3;
|
|
2258
|
+
$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = (event_0) => {
|
|
2259
|
+
drag.current && drag.current.pointerId === event_0.pointerId && setWidth(clampWidth(drag.current.startWidth - (event_0.clientX - drag.current.startX)));
|
|
2260
|
+
}, $[5] = t3) : t3 = $[5];
|
|
2261
|
+
let handlePointerMove = t3, t4;
|
|
2262
|
+
$[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = (event_1) => {
|
|
2263
|
+
drag.current && drag.current.pointerId === event_1.pointerId && (drag.current = null, setDragging(!1));
|
|
2264
|
+
}, $[6] = t4) : t4 = $[6];
|
|
2265
|
+
let handlePointerUp = t4, t5;
|
|
2266
|
+
$[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = (event_2) => {
|
|
2267
|
+
let step = {
|
|
2268
|
+
ArrowLeft: 16,
|
|
2269
|
+
ArrowRight: -16,
|
|
2270
|
+
Home: 400,
|
|
2271
|
+
End: -400
|
|
2272
|
+
}[event_2.key];
|
|
2273
|
+
step !== void 0 && (event_2.preventDefault(), setWidth((current) => clampWidth(current + step)));
|
|
2274
|
+
}, $[7] = t5) : t5 = $[7];
|
|
2275
|
+
let handleKeyDown = t5, t6;
|
|
2276
|
+
$[8] === width ? t6 = $[9] : (t6 = { width }, $[8] = width, $[9] = t6);
|
|
2277
|
+
let t7;
|
|
2278
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t7 = () => setWidth(200), $[10] = t7) : t7 = $[10];
|
|
2279
|
+
let t8;
|
|
2280
|
+
$[11] !== dragging || $[12] !== handlePointerDown || $[13] !== width ? (t8 = /* @__PURE__ */ jsx(ResizeHandle, {
|
|
2281
|
+
"aria-label": "Resize the themer",
|
|
2282
|
+
"aria-orientation": "vertical",
|
|
2283
|
+
"aria-valuemax": 400,
|
|
2284
|
+
"aria-valuemin": 200,
|
|
2285
|
+
"aria-valuenow": width,
|
|
2286
|
+
"data-dragging": dragging,
|
|
2287
|
+
onDoubleClick: t7,
|
|
2288
|
+
onKeyDown: handleKeyDown,
|
|
2289
|
+
onPointerCancel: handlePointerUp,
|
|
2290
|
+
onPointerDown: handlePointerDown,
|
|
2291
|
+
onPointerMove: handlePointerMove,
|
|
2292
|
+
onPointerUp: handlePointerUp,
|
|
2293
|
+
role: "separator",
|
|
2294
|
+
tabIndex: 0
|
|
2295
|
+
}), $[11] = dragging, $[12] = handlePointerDown, $[13] = width, $[14] = t8) : t8 = $[14];
|
|
2296
|
+
let t9;
|
|
2297
|
+
$[15] === Symbol.for("react.memo_cache_sentinel") ? (t9 = /* @__PURE__ */ jsx(Box, {
|
|
557
2298
|
height: "fill",
|
|
558
|
-
|
|
559
|
-
zOffset: 100,
|
|
2299
|
+
overflow: "hidden",
|
|
560
2300
|
children: /* @__PURE__ */ jsx(ThemerSidebar, {})
|
|
561
|
-
}), $[
|
|
562
|
-
let
|
|
563
|
-
|
|
2301
|
+
}), $[15] = t9) : t9 = $[15];
|
|
2302
|
+
let t10;
|
|
2303
|
+
$[16] === t8 ? t10 = $[17] : (t10 = /* @__PURE__ */ jsxs(Frame, {
|
|
2304
|
+
borderLeft: !0,
|
|
564
2305
|
height: "fill",
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
2306
|
+
children: [t8, t9]
|
|
2307
|
+
}), $[16] = t8, $[17] = t10);
|
|
2308
|
+
let t11;
|
|
2309
|
+
return $[18] !== t10 || $[19] !== t6 ? (t11 = /* @__PURE__ */ jsx(Sidebar, {
|
|
2310
|
+
style: t6,
|
|
2311
|
+
zOffset: 100,
|
|
2312
|
+
children: t10
|
|
2313
|
+
}), $[18] = t10, $[19] = t6, $[20] = t11) : t11 = $[20], t11;
|
|
568
2314
|
}
|
|
569
|
-
const STORAGE_KEY = "sanityStudio:themer:options";
|
|
2315
|
+
const STORAGE_KEY = "sanityStudio:themer:state", LEGACY_STORAGE_KEY = "sanityStudio:themer:options";
|
|
570
2316
|
function sanitizeColor(value) {
|
|
571
2317
|
return typeof value == "string" && isColor(value) ? value.toLowerCase() : null;
|
|
572
2318
|
}
|
|
573
|
-
function
|
|
574
|
-
|
|
2319
|
+
function sanitizeContrast(value) {
|
|
2320
|
+
return typeof value == "number" && Number.isFinite(value) ? Math.min(100, Math.max(15, value)) : null;
|
|
2321
|
+
}
|
|
2322
|
+
function sanitizeSchemeOptions(value) {
|
|
2323
|
+
let options = {};
|
|
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;
|
|
2327
|
+
}
|
|
2328
|
+
/**
|
|
2329
|
+
* Options from before they were grouped by scheme: one accent, text color and
|
|
2330
|
+
* contrast for both schemes, and a background per scheme. Both schemes get
|
|
2331
|
+
* the shared colors, so the theme keeps looking the same.
|
|
2332
|
+
*/
|
|
2333
|
+
function sanitizeFlatOptions(value) {
|
|
575
2334
|
let accent = sanitizeColor(Reflect.get(value, "accent"));
|
|
576
2335
|
if (!accent) return null;
|
|
577
|
-
let
|
|
578
|
-
text && (
|
|
579
|
-
let
|
|
580
|
-
|
|
581
|
-
let
|
|
582
|
-
|
|
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++;
|
|
583
2381
|
}
|
|
584
|
-
|
|
585
|
-
|
|
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
|
+
};
|
|
586
2411
|
}
|
|
587
2412
|
/**
|
|
588
|
-
* Restores
|
|
589
|
-
* studio reloads.
|
|
2413
|
+
* Restores the themer state from localStorage, so the user's themes survive
|
|
2414
|
+
* studio reloads. Falls back to the initial state when nothing usable is
|
|
2415
|
+
* stored.
|
|
590
2416
|
*
|
|
591
2417
|
* @internal
|
|
592
2418
|
*/
|
|
593
|
-
function
|
|
2419
|
+
function readStoredState() {
|
|
594
2420
|
try {
|
|
595
|
-
if (typeof localStorage > "u") return
|
|
2421
|
+
if (typeof localStorage > "u") return initialThemerState;
|
|
596
2422
|
let raw = localStorage.getItem(STORAGE_KEY);
|
|
597
|
-
return raw ?
|
|
2423
|
+
return raw ? sanitizeState(JSON.parse(raw)) : readLegacyState() ?? initialThemerState;
|
|
598
2424
|
} catch {
|
|
599
|
-
return
|
|
2425
|
+
return initialThemerState;
|
|
600
2426
|
}
|
|
601
2427
|
}
|
|
602
2428
|
/** @internal */
|
|
603
|
-
function
|
|
2429
|
+
function writeStoredState(state) {
|
|
604
2430
|
try {
|
|
605
2431
|
if (typeof localStorage > "u") return;
|
|
606
|
-
|
|
2432
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(state)), localStorage.removeItem(LEGACY_STORAGE_KEY);
|
|
607
2433
|
} catch {}
|
|
608
2434
|
}
|
|
2435
|
+
function sameStoredState(a, b) {
|
|
2436
|
+
return a.active === b.active && a.custom === b.custom && a.removed === b.removed;
|
|
2437
|
+
}
|
|
2438
|
+
function selectView(snapshot) {
|
|
2439
|
+
let { editing } = snapshot.context;
|
|
2440
|
+
return snapshot.matches({ flow: "edit" }) && editing ? {
|
|
2441
|
+
name: "edit",
|
|
2442
|
+
slug: editing.slug,
|
|
2443
|
+
focusTitle: editing.focusTitle
|
|
2444
|
+
} : snapshot.matches({ flow: "removed" }) ? { name: "removed" } : { name: "list" };
|
|
2445
|
+
}
|
|
2446
|
+
function sameView(a, b) {
|
|
2447
|
+
return a.name === b.name ? a.name !== "edit" || b.name !== "edit" || a.slug === b.slug && a.focusTitle === b.focusTitle : !1;
|
|
2448
|
+
}
|
|
609
2449
|
/**
|
|
610
|
-
* Wraps the whole Studio so that
|
|
611
|
-
*
|
|
612
|
-
* navbar toggle and the sidebar share
|
|
2450
|
+
* Wraps the whole Studio so that the theme picked in the themer sidebar
|
|
2451
|
+
* applies everywhere while the user browses around, runs the themer machine
|
|
2452
|
+
* that the navbar toggle and the sidebar share — the user's themes, which one
|
|
2453
|
+
* is applied, which flow the sidebar is in and how the Studio is previewed —
|
|
2454
|
+
* and renders the sidebar next to the Studio. The sidebar sits at the
|
|
2455
|
+
* `layout` level rather than in `activeToolLayout` because the split preview
|
|
2456
|
+
* renders the Studio twice, and the sidebar must not come along.
|
|
613
2457
|
*
|
|
614
|
-
* The
|
|
615
|
-
*
|
|
616
|
-
* theme.
|
|
2458
|
+
* The single preview inherits the color scheme from the Studio, so it follows
|
|
2459
|
+
* the appearance setting (light/dark/system) like any other theme.
|
|
617
2460
|
*
|
|
618
2461
|
* @internal
|
|
619
2462
|
*/
|
|
620
2463
|
function ThemerLayout(props) {
|
|
621
|
-
let $ = c(
|
|
622
|
-
$[0] ===
|
|
623
|
-
let t2;
|
|
624
|
-
$[3] === options ? t2 = $[4] : (t2 = options === null ? null : buildTheme(options), $[3] = options, $[4] = t2);
|
|
625
|
-
let theme = t2, t3;
|
|
626
|
-
$[5] !== baseOptions || $[6] !== open || $[7] !== options ? (t3 = {
|
|
2464
|
+
let $ = c(55), { baseOptions, ...layoutProps } = props, t0;
|
|
2465
|
+
$[0] === baseOptions ? t0 = $[1] : (t0 = () => ({
|
|
627
2466
|
baseOptions,
|
|
628
|
-
|
|
629
|
-
|
|
2467
|
+
stored: readStoredState()
|
|
2468
|
+
}), $[0] = baseOptions, $[1] = t0);
|
|
2469
|
+
let [input] = useState(t0), t1;
|
|
2470
|
+
$[2] === input ? t1 = $[3] : (t1 = { input }, $[2] = input, $[3] = t1);
|
|
2471
|
+
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.matches({ sidebar: "open" }), $[4] = snapshot, $[5] = t2);
|
|
2473
|
+
let open = t2, t3;
|
|
2474
|
+
$[6] === snapshot ? t3 = $[7] : (t3 = snapshot.matches({ preview: "split" }), $[6] = snapshot, $[7] = t3);
|
|
2475
|
+
let split = t3, { images } = snapshot.context, t4, t5;
|
|
2476
|
+
$[8] === stored ? (t4 = $[9], t5 = $[10]) : (t4 = () => writeStoredState(stored), t5 = [stored], $[8] = stored, $[9] = t4, $[10] = t5), useEffect(t4, t5);
|
|
2477
|
+
let previousImages = useRef(images), t6, t7;
|
|
2478
|
+
$[11] === images ? (t6 = $[12], t7 = $[13]) : (t6 = () => {
|
|
2479
|
+
let current = new Set(Object.values(images));
|
|
2480
|
+
for (let url of Object.values(previousImages.current)) current.has(url) || URL.revokeObjectURL(url);
|
|
2481
|
+
previousImages.current = images;
|
|
2482
|
+
}, t7 = [images], $[11] = images, $[12] = t6, $[13] = t7), useEffect(t6, t7);
|
|
2483
|
+
let t8, t9;
|
|
2484
|
+
$[14] === Symbol.for("react.memo_cache_sentinel") ? (t8 = () => () => {
|
|
2485
|
+
for (let url_0 of Object.values(previousImages.current)) URL.revokeObjectURL(url_0);
|
|
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;
|
|
2494
|
+
if (background === void 0) return;
|
|
2495
|
+
let { style } = document.body, previous = style.backgroundColor;
|
|
2496
|
+
return style.backgroundColor = background, () => {
|
|
2497
|
+
style.backgroundColor = previous;
|
|
2498
|
+
};
|
|
2499
|
+
}, $[21] = scheme, $[22] = theme?.v2?.color, $[23] = t12) : t12 = $[23];
|
|
2500
|
+
let t13;
|
|
2501
|
+
$[24] !== scheme || $[25] !== theme ? (t13 = [scheme, theme], $[24] = scheme, $[25] = theme, $[26] = t13) : t13 = $[26], useEffect(t12, t13);
|
|
2502
|
+
let t14;
|
|
2503
|
+
$[27] !== active || $[28] !== baseOptions || $[29] !== images || $[30] !== open || $[31] !== removed || $[32] !== send || $[33] !== split || $[34] !== themes || $[35] !== view ? (t14 = {
|
|
2504
|
+
baseOptions,
|
|
2505
|
+
themes,
|
|
2506
|
+
removed,
|
|
2507
|
+
active,
|
|
2508
|
+
images,
|
|
2509
|
+
view,
|
|
630
2510
|
open,
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
2511
|
+
split,
|
|
2512
|
+
send
|
|
2513
|
+
}, $[27] = active, $[28] = baseOptions, $[29] = images, $[30] = open, $[31] = removed, $[32] = send, $[33] = split, $[34] = themes, $[35] = view, $[36] = t14) : t14 = $[36];
|
|
2514
|
+
let context = t14, studio = layoutProps.renderDefault(layoutProps), t15 = split ? "light" : void 0, t16;
|
|
2515
|
+
$[37] !== studio || $[38] !== t15 || $[39] !== theme ? (t16 = /* @__PURE__ */ jsx(StudioPreview, {
|
|
2516
|
+
scheme: t15,
|
|
634
2517
|
theme,
|
|
635
|
-
children:
|
|
636
|
-
}),
|
|
637
|
-
|
|
2518
|
+
children: studio
|
|
2519
|
+
}), $[37] = studio, $[38] = t15, $[39] = theme, $[40] = t16) : t16 = $[40];
|
|
2520
|
+
let t17;
|
|
2521
|
+
$[41] !== split || $[42] !== studio || $[43] !== theme ? (t17 = split && /* @__PURE__ */ jsx(StudioPreview, {
|
|
2522
|
+
borderLeft: !0,
|
|
2523
|
+
scheme: "dark",
|
|
2524
|
+
theme,
|
|
2525
|
+
children: studio
|
|
2526
|
+
}), $[41] = split, $[42] = studio, $[43] = theme, $[44] = t17) : t17 = $[44];
|
|
2527
|
+
let t18;
|
|
2528
|
+
$[45] !== open || $[46] !== theme ? (t18 = open && /* @__PURE__ */ jsx(ThemeProvider, {
|
|
2529
|
+
theme: theme ?? void 0,
|
|
2530
|
+
children: /* @__PURE__ */ jsx(ResizableSidebar, {})
|
|
2531
|
+
}), $[45] = open, $[46] = theme, $[47] = t18) : t18 = $[47];
|
|
2532
|
+
let t19;
|
|
2533
|
+
$[48] !== t16 || $[49] !== t17 || $[50] !== t18 ? (t19 = /* @__PURE__ */ jsxs(Flex, {
|
|
2534
|
+
height: "fill",
|
|
2535
|
+
sizing: "border",
|
|
2536
|
+
children: [
|
|
2537
|
+
t16,
|
|
2538
|
+
t17,
|
|
2539
|
+
t18
|
|
2540
|
+
]
|
|
2541
|
+
}), $[48] = t16, $[49] = t17, $[50] = t18, $[51] = t19) : t19 = $[51];
|
|
2542
|
+
let t20;
|
|
2543
|
+
return $[52] !== context || $[53] !== t19 ? (t20 = /* @__PURE__ */ jsx(ThemerContext.Provider, {
|
|
638
2544
|
value: context,
|
|
639
|
-
children:
|
|
640
|
-
}), $[
|
|
2545
|
+
children: t19
|
|
2546
|
+
}), $[52] = context, $[53] = t19, $[54] = t20) : t20 = $[54], t20;
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* One copy of the Studio, in the given color scheme — or, without one, in the
|
|
2550
|
+
* scheme the Studio is showing. The configured theme (`null`) goes through
|
|
2551
|
+
* the provider too, inheriting the Studio's, so picking a theme swaps it
|
|
2552
|
+
* instead of remounting the Studio under a new provider.
|
|
2553
|
+
*
|
|
2554
|
+
* The two copies of the split preview share the router, the document store
|
|
2555
|
+
* and every other provider above the layout — only the scheme differs — so
|
|
2556
|
+
* they stay in sync while navigating. The `color-scheme` of a forced scheme
|
|
2557
|
+
* keeps native form controls and scrollbars in step with it.
|
|
2558
|
+
*/
|
|
2559
|
+
function StudioPreview(props) {
|
|
2560
|
+
let $ = c(10), { borderLeft, children, scheme, theme } = props, t0 = theme ?? void 0, t1;
|
|
2561
|
+
$[0] === scheme ? t1 = $[1] : (t1 = scheme ? { colorScheme: scheme } : void 0, $[0] = scheme, $[1] = t1);
|
|
2562
|
+
let t2;
|
|
2563
|
+
$[2] !== borderLeft || $[3] !== children || $[4] !== t1 ? (t2 = /* @__PURE__ */ jsx(Card, {
|
|
2564
|
+
borderLeft,
|
|
2565
|
+
flex: 1,
|
|
2566
|
+
height: "fill",
|
|
2567
|
+
overflow: "hidden",
|
|
2568
|
+
style: t1,
|
|
2569
|
+
children
|
|
2570
|
+
}), $[2] = borderLeft, $[3] = children, $[4] = t1, $[5] = t2) : t2 = $[5];
|
|
2571
|
+
let t3;
|
|
2572
|
+
return $[6] !== scheme || $[7] !== t0 || $[8] !== t2 ? (t3 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
2573
|
+
scheme,
|
|
2574
|
+
theme: t0,
|
|
2575
|
+
children: t2
|
|
2576
|
+
}), $[6] = scheme, $[7] = t0, $[8] = t2, $[9] = t3) : t3 = $[9], t3;
|
|
641
2577
|
}
|
|
642
2578
|
function ThemerNavbarButton() {
|
|
643
|
-
let $ = c(
|
|
2579
|
+
let $ = c(6), { open, send } = useThemer(), t0;
|
|
644
2580
|
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx(Text, {
|
|
645
2581
|
size: 1,
|
|
646
2582
|
children: "Themer"
|
|
647
2583
|
}), $[0] = t0) : t0 = $[0];
|
|
648
2584
|
let t1;
|
|
649
|
-
$[1]
|
|
2585
|
+
$[1] === send ? t1 = $[2] : (t1 = () => send({ type: "sidebar.toggle" }), $[1] = send, $[2] = t1);
|
|
650
2586
|
let t2;
|
|
651
|
-
return $[
|
|
2587
|
+
return $[3] !== open || $[4] !== t1 ? (t2 = /* @__PURE__ */ jsx(Tooltip, {
|
|
2588
|
+
animate: !0,
|
|
652
2589
|
content: t0,
|
|
653
2590
|
portal: !0,
|
|
654
2591
|
children: /* @__PURE__ */ jsx(Button, {
|
|
@@ -659,22 +2596,25 @@ function ThemerNavbarButton() {
|
|
|
659
2596
|
padding: 2,
|
|
660
2597
|
selected: open
|
|
661
2598
|
})
|
|
662
|
-
}), $[
|
|
2599
|
+
}), $[3] = open, $[4] = t1, $[5] = t2) : t2 = $[5], t2;
|
|
663
2600
|
}
|
|
664
2601
|
/**
|
|
665
2602
|
* Adds the toggle that opens and closes the themer sidebar to the Studio
|
|
666
2603
|
* navbar — an icon button with a tooltip in the top bar (like the Tasks
|
|
667
2604
|
* toggle), and a regular titled action in the narrow-screen sidebar menu.
|
|
668
2605
|
*
|
|
2606
|
+
* In the split preview every Studio copy renders its own navbar, so the
|
|
2607
|
+
* toggle shows up in both — they drive the same sidebar.
|
|
2608
|
+
*
|
|
669
2609
|
* @internal
|
|
670
2610
|
*/
|
|
671
2611
|
function ThemerNavbar(props) {
|
|
672
|
-
let $ = c(
|
|
2612
|
+
let $ = c(9), { open, send } = useThemer(), t0;
|
|
673
2613
|
$[0] === props.__internal_actions ? t0 = $[1] : (t0 = props.__internal_actions ?? [], $[0] = props.__internal_actions, $[1] = t0);
|
|
674
2614
|
let t1;
|
|
675
|
-
if ($[2] !== open || $[3] !== props || $[4] !==
|
|
2615
|
+
if ($[2] !== open || $[3] !== props || $[4] !== send || $[5] !== t0) {
|
|
676
2616
|
let t2;
|
|
677
|
-
$[7]
|
|
2617
|
+
$[7] === send ? t2 = $[8] : (t2 = () => send({ type: "sidebar.toggle" }), $[7] = send, $[8] = t2), t1 = props.renderDefault({
|
|
678
2618
|
...props,
|
|
679
2619
|
__internal_actions: [
|
|
680
2620
|
...t0,
|
|
@@ -692,7 +2632,7 @@ function ThemerNavbar(props) {
|
|
|
692
2632
|
title: "Themer"
|
|
693
2633
|
}
|
|
694
2634
|
]
|
|
695
|
-
}), $[2] = open, $[3] = props, $[4] =
|
|
2635
|
+
}), $[2] = open, $[3] = props, $[4] = send, $[5] = t0, $[6] = t1;
|
|
696
2636
|
} else t1 = $[6];
|
|
697
2637
|
return t1;
|
|
698
2638
|
}
|
|
@@ -701,11 +2641,16 @@ function _temp() {
|
|
|
701
2641
|
}
|
|
702
2642
|
/**
|
|
703
2643
|
* A Studio plugin that adds a themer sidebar for `buildTheme` themes: a
|
|
704
|
-
* navbar toggle opens the sidebar next to the
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
*
|
|
2644
|
+
* navbar toggle opens the sidebar next to the Studio, with a list of themes —
|
|
2645
|
+
* the configured theme, the presets and your own — each previewed as a tiny
|
|
2646
|
+
* Studio in both color schemes. Picking one applies it live to the whole
|
|
2647
|
+
* Studio while you browse around; your own themes can be edited with
|
|
2648
|
+
* accent/text/background pickers and a contrast slider per scheme, added,
|
|
2649
|
+
* duplicated, given the colors of an image (its palette is read on device),
|
|
2650
|
+
* removed and restored, and a dialog shows the `buildTheme` snippet that
|
|
2651
|
+
* makes the applied theme permanent. Toggle between light and dark mode with
|
|
2652
|
+
* the regular appearance menu — the preview follows it — or split the
|
|
2653
|
+
* preview to see the whole Studio in light and dark side by side.
|
|
709
2654
|
*
|
|
710
2655
|
* ```ts
|
|
711
2656
|
* import {themerTool} from '@sanity/themer/tool'
|
|
@@ -723,7 +2668,7 @@ function _temp() {
|
|
|
723
2668
|
* @alpha
|
|
724
2669
|
*/
|
|
725
2670
|
const themerTool = definePlugin((options) => {
|
|
726
|
-
let baseOptions = options?.config ?? {
|
|
2671
|
+
let baseOptions = options?.config ?? {};
|
|
727
2672
|
function ThemerLayoutWithOptions(props) {
|
|
728
2673
|
let $ = c(2), t0;
|
|
729
2674
|
return $[0] === props ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(ThemerLayout, {
|
|
@@ -735,8 +2680,7 @@ const themerTool = definePlugin((options) => {
|
|
|
735
2680
|
name: "@sanity/themer/tool",
|
|
736
2681
|
studio: { components: {
|
|
737
2682
|
layout: ThemerLayoutWithOptions,
|
|
738
|
-
navbar: ThemerNavbar
|
|
739
|
-
activeToolLayout: ThemerActiveToolLayout
|
|
2683
|
+
navbar: ThemerNavbar
|
|
740
2684
|
} }
|
|
741
2685
|
};
|
|
742
2686
|
});
|