@sanity/themer 0.7.1 → 0.8.1
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 +2 -2
- package/dist/ResizableSidebar-DD787kQr.js +2050 -0
- package/dist/ResizableSidebar-DD787kQr.js.map +1 -0
- package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js +422 -0
- package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js.map +1 -0
- package/dist/bundle.css +555 -555
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/legacy.d.ts +13 -12
- package/dist/legacy.d.ts.map +1 -1
- package/dist/presets-CqBgS3A-.js.map +1 -1
- package/dist/tool.d.ts +2 -2
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js +368 -2576
- package/dist/tool.js.map +1 -1
- package/package.json +16 -21
|
@@ -0,0 +1,2050 @@
|
|
|
1
|
+
import { c as resolveThemeOptions, l as isColor, n as buildTheme, o as SCHEMES, r as buildPalette } from "./presets-CqBgS3A-.js";
|
|
2
|
+
import { _ as titleFromFileName, c as minimizeOptions, d as IMAGE_PALETTE_VARIANTS, f as applyImagePalette, g as pickLuckyVariant, h as optionsFromImagePalette, i as displayTitle, m as extractImagePalette, p as currentImageVariant, u as IMAGE_PALETTE_TITLES, y as useThemer } from "./ResizableSidebar.css.ts.vanilla-M9EuPu-q.js";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import { useColorSchemeValue } from "sanity";
|
|
5
|
+
import { Badge, Box, Button, Card, Dialog, Flex, Layer, Stack, Text, TextInput, ThemeProvider, useRootTheme, useTheme_v2 } from "@sanity/ui";
|
|
6
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Tooltip } from "@sanity/ui/tooltip";
|
|
9
|
+
import { MotionConfig, Reorder, useDragControls } from "motion/react";
|
|
10
|
+
import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
|
|
11
|
+
import { CloseIcon } from "@sanity/icons/Close";
|
|
12
|
+
import { CodeBlockIcon } from "@sanity/icons/CodeBlock";
|
|
13
|
+
import { SplitVerticalIcon } from "@sanity/icons/SplitVertical";
|
|
14
|
+
import { assignInlineVars } from "@vanilla-extract/dynamic";
|
|
15
|
+
import { ResetIcon } from "@sanity/icons/Reset";
|
|
16
|
+
import { TrashIcon } from "@sanity/icons/Trash";
|
|
17
|
+
import { SparklesIcon } from "@sanity/icons/Sparkles";
|
|
18
|
+
import { ImageIcon } from "@sanity/icons/Image";
|
|
19
|
+
import { useToast } from "@sanity/ui/toast";
|
|
20
|
+
import { AddIcon } from "@sanity/icons/Add";
|
|
21
|
+
import { ClipboardIcon } from "@sanity/icons/Clipboard";
|
|
22
|
+
import { RestoreIcon } from "@sanity/icons/Restore";
|
|
23
|
+
import { ArrowDownIcon } from "@sanity/icons/ArrowDown";
|
|
24
|
+
import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
|
|
25
|
+
import { CopyIcon } from "@sanity/icons/Copy";
|
|
26
|
+
import { EditIcon } from "@sanity/icons/Edit";
|
|
27
|
+
import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
|
|
28
|
+
import { ShareIcon } from "@sanity/icons/Share";
|
|
29
|
+
import { Menu, MenuButton, MenuDivider, MenuItem } from "@sanity/ui/menu";
|
|
30
|
+
import scrollIntoView from "scroll-into-view-if-needed";
|
|
31
|
+
import { Code } from "@sanity/ui/code";
|
|
32
|
+
import { registerLanguage } from "react-refractor";
|
|
33
|
+
import typescript from "refractor/typescript";
|
|
34
|
+
var root$2 = "_1o50s7t0";
|
|
35
|
+
const ScrollAreaInsetContext = createContext({
|
|
36
|
+
left: 0,
|
|
37
|
+
right: 0,
|
|
38
|
+
bottom: 0
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* The gutter the last scroll area measured. It is the same for every scroll
|
|
42
|
+
* area (the reserved gutter does not depend on the content), so the next one
|
|
43
|
+
* starts out with the right padding instead of shifting after its first
|
|
44
|
+
* measurement — which would also throw off anything scrolling into view as
|
|
45
|
+
* the content mounts.
|
|
46
|
+
*/
|
|
47
|
+
let lastGutter = 0;
|
|
48
|
+
/**
|
|
49
|
+
* The scrolling body of a sidebar flow. It always reserves the scrollbar's
|
|
50
|
+
* space, so the content does not shift when the list grows or shrinks past
|
|
51
|
+
* the point where it needs to scroll — and it takes that space out of its
|
|
52
|
+
* right padding, so the content stays centered rather than hugging the left.
|
|
53
|
+
* With overlay scrollbars there is no gutter and the padding stays even.
|
|
54
|
+
*
|
|
55
|
+
* @internal
|
|
56
|
+
*/
|
|
57
|
+
function ScrollArea(props) {
|
|
58
|
+
let $ = c(15), { children, padding } = props, { space } = useTheme_v2(), ref = useRef(null), [gutter, setGutter] = useState(_temp$6), t0, t1;
|
|
59
|
+
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => {
|
|
60
|
+
let element = ref.current;
|
|
61
|
+
if (!element) return;
|
|
62
|
+
let measure = () => {
|
|
63
|
+
lastGutter = element.offsetWidth - element.clientWidth, setGutter(lastGutter);
|
|
64
|
+
};
|
|
65
|
+
measure();
|
|
66
|
+
let observer = new ResizeObserver(measure);
|
|
67
|
+
return observer.observe(element), () => observer.disconnect();
|
|
68
|
+
}, t1 = [], $[0] = t0, $[1] = t1) : (t0 = $[0], t1 = $[1]), useEffect(t0, t1);
|
|
69
|
+
let t2 = space[padding], t3 = Math.max(0, space[padding] - gutter), t4 = space[padding], t5;
|
|
70
|
+
$[2] !== t2 || $[3] !== t3 || $[4] !== t4 ? (t5 = {
|
|
71
|
+
left: t2,
|
|
72
|
+
right: t3,
|
|
73
|
+
bottom: t4
|
|
74
|
+
}, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5) : t5 = $[5];
|
|
75
|
+
let inset = t5, t6;
|
|
76
|
+
$[6] === inset.right ? t6 = $[7] : (t6 = { paddingRight: inset.right }, $[6] = inset.right, $[7] = t6);
|
|
77
|
+
let t7;
|
|
78
|
+
$[8] !== children || $[9] !== inset ? (t7 = /* @__PURE__ */ jsx(ScrollAreaInsetContext.Provider, {
|
|
79
|
+
value: inset,
|
|
80
|
+
children
|
|
81
|
+
}), $[8] = children, $[9] = inset, $[10] = t7) : t7 = $[10];
|
|
82
|
+
let t8;
|
|
83
|
+
return $[11] !== padding || $[12] !== t6 || $[13] !== t7 ? (t8 = /* @__PURE__ */ jsx(Box, {
|
|
84
|
+
className: root$2,
|
|
85
|
+
flex: 1,
|
|
86
|
+
overflow: "auto",
|
|
87
|
+
padding,
|
|
88
|
+
ref,
|
|
89
|
+
style: t6,
|
|
90
|
+
children: t7
|
|
91
|
+
}), $[11] = padding, $[12] = t6, $[13] = t7, $[14] = t8) : t8 = $[14], t8;
|
|
92
|
+
}
|
|
93
|
+
function _temp$6() {
|
|
94
|
+
return lastGutter;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Content that runs edge to edge in a scroll area — up to the scrollbar —
|
|
98
|
+
* instead of sitting inside its padding. It goes last: it runs down to the
|
|
99
|
+
* bottom edge too.
|
|
100
|
+
*
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
function ScrollAreaBleed(props) {
|
|
104
|
+
let $ = c(7), { left, right, bottom } = useContext(ScrollAreaInsetContext), t0 = -left, t1 = -right, t2 = -bottom, t3;
|
|
105
|
+
$[0] !== t0 || $[1] !== t1 || $[2] !== t2 ? (t3 = {
|
|
106
|
+
marginLeft: t0,
|
|
107
|
+
marginRight: t1,
|
|
108
|
+
marginBottom: t2
|
|
109
|
+
}, $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3) : t3 = $[3];
|
|
110
|
+
let t4;
|
|
111
|
+
return $[4] !== props.children || $[5] !== t3 ? (t4 = /* @__PURE__ */ jsx("div", {
|
|
112
|
+
style: t3,
|
|
113
|
+
children: props.children
|
|
114
|
+
}), $[4] = props.children, $[5] = t3, $[6] = t4) : t4 = $[6], t4;
|
|
115
|
+
}
|
|
116
|
+
var avatar = "_1aa9huuh", body = "_1aa9huui", button = "_1aa9huuq", colors = {
|
|
117
|
+
bg: "var(--_1aa9huu0)",
|
|
118
|
+
fg: "var(--_1aa9huu1)",
|
|
119
|
+
mutedFg: "var(--_1aa9huu2)",
|
|
120
|
+
border: "var(--_1aa9huu3)",
|
|
121
|
+
accent: "var(--_1aa9huu4)",
|
|
122
|
+
avatar: "var(--_1aa9huu5)",
|
|
123
|
+
selectedBg: "var(--_1aa9huu6)",
|
|
124
|
+
selectedFg: "var(--_1aa9huu7)",
|
|
125
|
+
inputBg: "var(--_1aa9huu8)",
|
|
126
|
+
inputBorder: "var(--_1aa9huu9)"
|
|
127
|
+
}, field = "_1aa9huun", footer = "_1aa9huup", form = "_1aa9huum", input = "_1aa9huuo", line = {
|
|
128
|
+
fg: "_1aa9huus _1aa9huur",
|
|
129
|
+
muted: "_1aa9huut _1aa9huur",
|
|
130
|
+
selected: "_1aa9huuu _1aa9huur"
|
|
131
|
+
}, list = "_1aa9huuj", listRow = "_1aa9huuk", logo = "_1aa9huuf", navbar = "_1aa9huue", pane = "_1aa9huul", root$1 = "_1aa9huua", spacer = "_1aa9huug", studio = {
|
|
132
|
+
light: "_1aa9huub",
|
|
133
|
+
dark: "_1aa9huud _1aa9huub"
|
|
134
|
+
};
|
|
135
|
+
/** The document rows in the list pane — the widths of their title lines */
|
|
136
|
+
const LIST_ROWS = [
|
|
137
|
+
"62%",
|
|
138
|
+
"46%",
|
|
139
|
+
"70%",
|
|
140
|
+
"52%"
|
|
141
|
+
], FIELDS$1 = ["32%", "24%"];
|
|
142
|
+
/**
|
|
143
|
+
* A tiny, lo-fi mockup of a Studio in the given theme — the navbar over the
|
|
144
|
+
* structure tool with a list of documents on the left and a document form on
|
|
145
|
+
* the right — in both color schemes at once: the light scheme on the left and
|
|
146
|
+
* the dark scheme on the right, split diagonally. It only paints colors the
|
|
147
|
+
* theme options change (backgrounds, text, borders, the accent) so that a
|
|
148
|
+
* glance shows what the theme does to the Studio — with few and bold enough
|
|
149
|
+
* elements to still read when scaled down to a thumbnail.
|
|
150
|
+
*
|
|
151
|
+
* @internal
|
|
152
|
+
*/
|
|
153
|
+
function ThemePreview(props) {
|
|
154
|
+
let $ = c(11), { options } = props, t0;
|
|
155
|
+
$[0] === options ? t0 = $[1] : (t0 = buildTheme(options), $[0] = options, $[1] = t0);
|
|
156
|
+
let theme = t0, t1;
|
|
157
|
+
$[2] === Symbol.for("react.memo_cache_sentinel") ? (t1 = /* @__PURE__ */ jsx(MockStudio, { scheme: "light" }), $[2] = t1) : t1 = $[2];
|
|
158
|
+
let t2;
|
|
159
|
+
$[3] === theme ? t2 = $[4] : (t2 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
160
|
+
scheme: "light",
|
|
161
|
+
theme,
|
|
162
|
+
tone: "default",
|
|
163
|
+
children: t1
|
|
164
|
+
}), $[3] = theme, $[4] = t2);
|
|
165
|
+
let t3;
|
|
166
|
+
$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx(MockStudio, { scheme: "dark" }), $[5] = t3) : t3 = $[5];
|
|
167
|
+
let t4;
|
|
168
|
+
$[6] === theme ? t4 = $[7] : (t4 = /* @__PURE__ */ jsx(ThemeProvider, {
|
|
169
|
+
scheme: "dark",
|
|
170
|
+
theme,
|
|
171
|
+
tone: "default",
|
|
172
|
+
children: t3
|
|
173
|
+
}), $[6] = theme, $[7] = t4);
|
|
174
|
+
let t5;
|
|
175
|
+
return $[8] !== t2 || $[9] !== t4 ? (t5 = /* @__PURE__ */ jsxs("div", {
|
|
176
|
+
"aria-hidden": !0,
|
|
177
|
+
className: root$1,
|
|
178
|
+
children: [t2, t4]
|
|
179
|
+
}), $[8] = t2, $[9] = t4, $[10] = t5) : t5 = $[10], t5;
|
|
180
|
+
}
|
|
181
|
+
function MockStudio(props) {
|
|
182
|
+
let $ = c(19), { scheme } = props, { color } = useTheme_v2(), selected = color.selectable.default.selected, inputColor = color.input.default.enabled, t0 = studio[scheme], t1;
|
|
183
|
+
$[0] !== color.avatar.blue.bg || $[1] !== color.bg || $[2] !== color.border || $[3] !== color.button.default.primary.enabled.bg || $[4] !== color.fg || $[5] !== color.muted.fg || $[6] !== inputColor.bg || $[7] !== inputColor.border || $[8] !== selected.bg || $[9] !== selected.fg ? (t1 = assignInlineVars({
|
|
184
|
+
[colors.bg]: color.bg,
|
|
185
|
+
[colors.fg]: color.fg,
|
|
186
|
+
[colors.mutedFg]: color.muted.fg,
|
|
187
|
+
[colors.border]: color.border,
|
|
188
|
+
[colors.accent]: color.button.default.primary.enabled.bg,
|
|
189
|
+
[colors.avatar]: color.avatar.blue.bg,
|
|
190
|
+
[colors.selectedBg]: selected.bg,
|
|
191
|
+
[colors.selectedFg]: selected.fg,
|
|
192
|
+
[colors.inputBg]: inputColor.bg,
|
|
193
|
+
[colors.inputBorder]: inputColor.border
|
|
194
|
+
}), $[0] = color.avatar.blue.bg, $[1] = color.bg, $[2] = color.border, $[3] = color.button.default.primary.enabled.bg, $[4] = color.fg, $[5] = color.muted.fg, $[6] = inputColor.bg, $[7] = inputColor.border, $[8] = selected.bg, $[9] = selected.fg, $[10] = t1) : t1 = $[10];
|
|
195
|
+
let t2;
|
|
196
|
+
$[11] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx("div", { className: logo }), $[11] = t2) : t2 = $[11];
|
|
197
|
+
let t3;
|
|
198
|
+
$[12] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsxs("div", {
|
|
199
|
+
className: navbar,
|
|
200
|
+
children: [
|
|
201
|
+
t2,
|
|
202
|
+
/* @__PURE__ */ jsx("div", {
|
|
203
|
+
className: line.fg,
|
|
204
|
+
style: { width: "22%" }
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ jsx("div", { className: spacer }),
|
|
207
|
+
/* @__PURE__ */ jsx("div", { className: avatar })
|
|
208
|
+
]
|
|
209
|
+
}), $[12] = t3) : t3 = $[12];
|
|
210
|
+
let t4;
|
|
211
|
+
$[13] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("div", {
|
|
212
|
+
className: list,
|
|
213
|
+
children: LIST_ROWS.map(_temp$5)
|
|
214
|
+
}), $[13] = t4) : t4 = $[13];
|
|
215
|
+
let t5;
|
|
216
|
+
$[14] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsxs("div", {
|
|
217
|
+
className: form,
|
|
218
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
219
|
+
className: line.fg,
|
|
220
|
+
style: { width: "45%" }
|
|
221
|
+
}), FIELDS$1.map(_temp2)]
|
|
222
|
+
}), $[14] = t5) : t5 = $[14];
|
|
223
|
+
let t6;
|
|
224
|
+
$[15] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsxs("div", {
|
|
225
|
+
className: body,
|
|
226
|
+
children: [t4, /* @__PURE__ */ jsxs("div", {
|
|
227
|
+
className: pane,
|
|
228
|
+
children: [t5, /* @__PURE__ */ jsx("div", {
|
|
229
|
+
className: footer,
|
|
230
|
+
children: /* @__PURE__ */ jsx("div", { className: button })
|
|
231
|
+
})]
|
|
232
|
+
})]
|
|
233
|
+
}), $[15] = t6) : t6 = $[15];
|
|
234
|
+
let t7;
|
|
235
|
+
return $[16] !== t0 || $[17] !== t1 ? (t7 = /* @__PURE__ */ jsxs("div", {
|
|
236
|
+
className: t0,
|
|
237
|
+
style: t1,
|
|
238
|
+
children: [t3, t6]
|
|
239
|
+
}), $[16] = t0, $[17] = t1, $[18] = t7) : t7 = $[18], t7;
|
|
240
|
+
}
|
|
241
|
+
function _temp2(width_0) {
|
|
242
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
243
|
+
className: field,
|
|
244
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
245
|
+
className: line.muted,
|
|
246
|
+
style: { width: width_0 }
|
|
247
|
+
}), /* @__PURE__ */ jsx("div", { className: input })]
|
|
248
|
+
}, width_0);
|
|
249
|
+
}
|
|
250
|
+
function _temp$5(width, index) {
|
|
251
|
+
let isSelected = index === 1;
|
|
252
|
+
return /* @__PURE__ */ jsx("div", {
|
|
253
|
+
className: listRow,
|
|
254
|
+
"data-selected": isSelected,
|
|
255
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
256
|
+
className: isSelected ? line.selected : line.muted,
|
|
257
|
+
style: { width }
|
|
258
|
+
})
|
|
259
|
+
}, width);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The floating preview card of a theme: the lo-fi studio mockup on a raised,
|
|
263
|
+
* rounded card, like the appearance previews in macOS System Settings.
|
|
264
|
+
*
|
|
265
|
+
* @internal
|
|
266
|
+
*/
|
|
267
|
+
function ThemeThumbnail(props) {
|
|
268
|
+
let $ = c(2), t0;
|
|
269
|
+
return $[0] === props.options ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Card, {
|
|
270
|
+
overflow: "hidden",
|
|
271
|
+
radius: 3,
|
|
272
|
+
shadow: 1,
|
|
273
|
+
children: /* @__PURE__ */ jsx(ThemePreview, { options: props.options })
|
|
274
|
+
}), $[0] = props.options, $[1] = t0), t0;
|
|
275
|
+
}
|
|
276
|
+
var removedThumbnail = "_1vdkp0v0";
|
|
277
|
+
/**
|
|
278
|
+
* The flow for restoring removed themes: the presets and custom themes the
|
|
279
|
+
* user took out of the list, each with a button to put it back — and, for
|
|
280
|
+
* custom themes, one to delete it for good. The machine leaves the flow once
|
|
281
|
+
* the last one is gone.
|
|
282
|
+
*
|
|
283
|
+
* @internal
|
|
284
|
+
*/
|
|
285
|
+
function RemovedThemes() {
|
|
286
|
+
let $ = c(7), { removed, send } = useThemer(), t0;
|
|
287
|
+
if ($[0] !== removed || $[1] !== send) {
|
|
288
|
+
let t1;
|
|
289
|
+
$[3] === send ? t1 = $[4] : (t1 = (theme) => /* @__PURE__ */ jsxs(Stack, {
|
|
290
|
+
gap: 3,
|
|
291
|
+
children: [
|
|
292
|
+
/* @__PURE__ */ jsx(Box, {
|
|
293
|
+
className: removedThumbnail,
|
|
294
|
+
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
|
|
295
|
+
}),
|
|
296
|
+
/* @__PURE__ */ jsx(Text, {
|
|
297
|
+
align: "center",
|
|
298
|
+
size: 1,
|
|
299
|
+
textOverflow: "ellipsis",
|
|
300
|
+
children: displayTitle(theme.title)
|
|
301
|
+
}),
|
|
302
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
303
|
+
gap: 2,
|
|
304
|
+
justify: "center",
|
|
305
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
306
|
+
mode: "ghost",
|
|
307
|
+
onClick: () => send({
|
|
308
|
+
type: "theme.restore",
|
|
309
|
+
slug: theme.slug
|
|
310
|
+
}),
|
|
311
|
+
padding: 2,
|
|
312
|
+
text: "Restore"
|
|
313
|
+
}), theme.source === "custom" && /* @__PURE__ */ jsx(Button, {
|
|
314
|
+
mode: "ghost",
|
|
315
|
+
onClick: () => send({
|
|
316
|
+
type: "theme.delete",
|
|
317
|
+
slug: theme.slug
|
|
318
|
+
}),
|
|
319
|
+
padding: 2,
|
|
320
|
+
text: "Delete",
|
|
321
|
+
tone: "critical"
|
|
322
|
+
})]
|
|
323
|
+
})
|
|
324
|
+
]
|
|
325
|
+
}, theme.slug), $[3] = send, $[4] = t1), t0 = removed.map(t1), $[0] = removed, $[1] = send, $[2] = t0;
|
|
326
|
+
} else t0 = $[2];
|
|
327
|
+
let t1;
|
|
328
|
+
return $[5] === t0 ? t1 = $[6] : (t1 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
329
|
+
padding: 3,
|
|
330
|
+
children: /* @__PURE__ */ jsx(Stack, {
|
|
331
|
+
gap: 5,
|
|
332
|
+
children: t0
|
|
333
|
+
})
|
|
334
|
+
}), $[5] = t0, $[6] = t1), t1;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* A button with an animated tooltip instead of a `title` attribute, sized like
|
|
338
|
+
* the Studio's own buttons (`padding` and `gap` of 2). Icon-only buttons take
|
|
339
|
+
* the tooltip as their accessible name.
|
|
340
|
+
*
|
|
341
|
+
* @internal
|
|
342
|
+
*/
|
|
343
|
+
function TooltipButton(props) {
|
|
344
|
+
let $ = c(11), buttonProps, tooltip;
|
|
345
|
+
$[0] === props ? (buttonProps = $[1], tooltip = $[2]) : ({tooltip, ...buttonProps} = props, $[0] = props, $[1] = buttonProps, $[2] = tooltip);
|
|
346
|
+
let t0;
|
|
347
|
+
$[3] === tooltip ? t0 = $[4] : (t0 = /* @__PURE__ */ jsx(Text, {
|
|
348
|
+
size: 1,
|
|
349
|
+
children: tooltip
|
|
350
|
+
}), $[3] = tooltip, $[4] = t0);
|
|
351
|
+
let t1 = buttonProps.text === void 0 ? tooltip : void 0, t2;
|
|
352
|
+
$[5] !== buttonProps || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(Button, {
|
|
353
|
+
"aria-label": t1,
|
|
354
|
+
gap: 2,
|
|
355
|
+
padding: 2,
|
|
356
|
+
...buttonProps
|
|
357
|
+
}), $[5] = buttonProps, $[6] = t1, $[7] = t2) : t2 = $[7];
|
|
358
|
+
let t3;
|
|
359
|
+
return $[8] !== t0 || $[9] !== t2 ? (t3 = /* @__PURE__ */ jsx(Tooltip, {
|
|
360
|
+
animate: !0,
|
|
361
|
+
content: t0,
|
|
362
|
+
placement: "bottom",
|
|
363
|
+
portal: !0,
|
|
364
|
+
children: t2
|
|
365
|
+
}), $[8] = t0, $[9] = t2, $[10] = t3) : t3 = $[10], t3;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* A button that opens the file picker for an image, and hands the chosen file
|
|
369
|
+
* over — the picker is a hidden file input, so nothing is uploaded anywhere.
|
|
370
|
+
*
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
function ImageFileButton(props) {
|
|
374
|
+
let $ = c(11), buttonProps, onFile;
|
|
375
|
+
$[0] === props ? (buttonProps = $[1], onFile = $[2]) : ({onFile, ...buttonProps} = props, $[0] = props, $[1] = buttonProps, $[2] = onFile);
|
|
376
|
+
let inputRef = useRef(null), t0;
|
|
377
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t0 = () => inputRef.current?.click(), $[3] = t0) : t0 = $[3];
|
|
378
|
+
let t1;
|
|
379
|
+
$[4] === buttonProps ? t1 = $[5] : (t1 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
380
|
+
...buttonProps,
|
|
381
|
+
icon: ImageIcon,
|
|
382
|
+
onClick: t0
|
|
383
|
+
}), $[4] = buttonProps, $[5] = t1);
|
|
384
|
+
let t2;
|
|
385
|
+
$[6] === onFile ? t2 = $[7] : (t2 = /* @__PURE__ */ jsx("input", {
|
|
386
|
+
accept: "image/*",
|
|
387
|
+
hidden: !0,
|
|
388
|
+
onChange: (event) => {
|
|
389
|
+
let file = event.currentTarget.files?.[0];
|
|
390
|
+
event.currentTarget.value = "", file && onFile(file);
|
|
391
|
+
},
|
|
392
|
+
ref: inputRef,
|
|
393
|
+
type: "file"
|
|
394
|
+
}), $[6] = onFile, $[7] = t2);
|
|
395
|
+
let t3;
|
|
396
|
+
return $[8] !== t1 || $[9] !== t2 ? (t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, t2] }), $[8] = t1, $[9] = t2, $[10] = t3) : t3 = $[10], t3;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Reads the pixels of an image file on device: the image is decoded, drawn
|
|
400
|
+
* onto a small canvas and read back, so nothing leaves the browser.
|
|
401
|
+
*
|
|
402
|
+
* @internal
|
|
403
|
+
*/
|
|
404
|
+
async function readImagePixels(file) {
|
|
405
|
+
let image = await decodeImage(file);
|
|
406
|
+
try {
|
|
407
|
+
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");
|
|
408
|
+
canvas.width = width, canvas.height = height;
|
|
409
|
+
let context = canvas.getContext("2d", { willReadFrequently: !0 });
|
|
410
|
+
if (!context) throw Error("Could not draw the image");
|
|
411
|
+
return context.drawImage(image, 0, 0, width, height), {
|
|
412
|
+
data: context.getImageData(0, 0, width, height).data,
|
|
413
|
+
width,
|
|
414
|
+
height
|
|
415
|
+
};
|
|
416
|
+
} finally {
|
|
417
|
+
typeof ImageBitmap < "u" && image instanceof ImageBitmap && image.close();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
async function decodeImage(file) {
|
|
421
|
+
if (typeof createImageBitmap == "function") try {
|
|
422
|
+
return await createImageBitmap(file);
|
|
423
|
+
} catch {}
|
|
424
|
+
let url = URL.createObjectURL(file);
|
|
425
|
+
try {
|
|
426
|
+
return await new Promise((resolve, reject) => {
|
|
427
|
+
let image = new Image();
|
|
428
|
+
image.addEventListener("load", () => resolve(image), { once: !0 }), image.addEventListener("error", () => reject(/* @__PURE__ */ Error("Could not decode the image")), { once: !0 }), image.src = url;
|
|
429
|
+
});
|
|
430
|
+
} finally {
|
|
431
|
+
URL.revokeObjectURL(url);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Extracts the palette of image files on device and hands it to `onPalette`,
|
|
436
|
+
* along with the file it came from. Failures end up as a toast.
|
|
437
|
+
*
|
|
438
|
+
* @internal
|
|
439
|
+
*/
|
|
440
|
+
function useImagePalette(onPalette) {
|
|
441
|
+
let $ = c(10), toast = useToast(), [busy, setBusy] = useState(!1), onPaletteRef = useRef(onPalette), mountedRef = useRef(!0), latestPickRef = useRef(0), t0, t1;
|
|
442
|
+
$[0] === onPalette ? (t0 = $[1], t1 = $[2]) : (t0 = () => {
|
|
443
|
+
onPaletteRef.current = onPalette;
|
|
444
|
+
}, t1 = [onPalette], $[0] = onPalette, $[1] = t0, $[2] = t1), useEffect(t0, t1);
|
|
445
|
+
let t2, t3;
|
|
446
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t2 = () => (mountedRef.current = !0, () => {
|
|
447
|
+
mountedRef.current = !1;
|
|
448
|
+
}), t3 = [], $[3] = t2, $[4] = t3) : (t2 = $[3], t3 = $[4]), useEffect(t2, t3);
|
|
449
|
+
let t4;
|
|
450
|
+
$[5] === toast ? t4 = $[6] : (t4 = (file) => {
|
|
451
|
+
let pick = latestPickRef.current += 1;
|
|
452
|
+
setBusy(!0);
|
|
453
|
+
let isCurrent = () => mountedRef.current && latestPickRef.current === pick, extract = async () => {
|
|
454
|
+
let palette = extractImagePalette(await readImagePixels(file));
|
|
455
|
+
isCurrent() && (Object.values(palette).every(_temp$4) ? toast.push({
|
|
456
|
+
status: "warning",
|
|
457
|
+
title: "Found no colors in that image"
|
|
458
|
+
}) : onPaletteRef.current(palette, file));
|
|
459
|
+
};
|
|
460
|
+
extract().catch(() => {
|
|
461
|
+
isCurrent() && toast.push({
|
|
462
|
+
status: "error",
|
|
463
|
+
title: "Could not read that image"
|
|
464
|
+
});
|
|
465
|
+
}).finally(() => {
|
|
466
|
+
isCurrent() && setBusy(!1);
|
|
467
|
+
});
|
|
468
|
+
}, $[5] = toast, $[6] = t4);
|
|
469
|
+
let pickImage = t4, t5;
|
|
470
|
+
return $[7] !== busy || $[8] !== pickImage ? (t5 = {
|
|
471
|
+
busy,
|
|
472
|
+
pickImage
|
|
473
|
+
}, $[7] = busy, $[8] = pickImage, $[9] = t5) : t5 = $[9], t5;
|
|
474
|
+
}
|
|
475
|
+
function _temp$4(swatch) {
|
|
476
|
+
return swatch === null;
|
|
477
|
+
}
|
|
478
|
+
var paletteGrid = "_17s80v42", tile = "_17s80v44", variantButton = "_17s80v46", variantFrame = "_17s80v47", variantRow = "_17s80v45", variantScale = "var(--_17s80v41)", variantScaleBox = "_17s80v48", variantWidth = "var(--_17s80v40)";
|
|
479
|
+
/** The swatches on display: the vibrant family over the muted one */
|
|
480
|
+
const TILES = [
|
|
481
|
+
"vibrant",
|
|
482
|
+
"lightVibrant",
|
|
483
|
+
"darkVibrant",
|
|
484
|
+
"muted",
|
|
485
|
+
"lightMuted",
|
|
486
|
+
"darkMuted"
|
|
487
|
+
];
|
|
488
|
+
/**
|
|
489
|
+
* Takes the colors of a theme from an image, on device: the image is read
|
|
490
|
+
* into a canvas and its palette extracted right there — nothing is uploaded.
|
|
491
|
+
* Shows the image (while the session lasts) next to its palette, offers a
|
|
492
|
+
* theme variant built around each swatch as a small preview, and a lucky
|
|
493
|
+
* button that picks an interesting one.
|
|
494
|
+
*
|
|
495
|
+
* @internal
|
|
496
|
+
*/
|
|
497
|
+
function ImagePaletteSection(props) {
|
|
498
|
+
let $ = c(38), { imageUrl, onPalette, onVariant, onLucky, options, palette } = props, { busy, pickImage } = useImagePalette(onPalette), [dragging, setDragging] = useState(!1), dragDepth = useRef(0), t0;
|
|
499
|
+
$[0] !== options || $[1] !== palette ? (t0 = palette ? currentImageVariant(options, palette) : null, $[0] = options, $[1] = palette, $[2] = t0) : t0 = $[2];
|
|
500
|
+
let current = t0, rowRef = useRef(null), [thumbnailWidth, setThumbnailWidth] = useState(58), t1;
|
|
501
|
+
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
|
|
502
|
+
let row = rowRef.current;
|
|
503
|
+
if (!row) return;
|
|
504
|
+
let measure = () => {
|
|
505
|
+
let visible = row.clientWidth - 12 - 16;
|
|
506
|
+
setThumbnailWidth(Math.max(24, Math.floor(visible / 2.5) - 8));
|
|
507
|
+
};
|
|
508
|
+
measure();
|
|
509
|
+
let observer = new ResizeObserver(measure);
|
|
510
|
+
return observer.observe(row), () => observer.disconnect();
|
|
511
|
+
}, $[3] = t1) : t1 = $[3];
|
|
512
|
+
let t2;
|
|
513
|
+
$[4] === palette ? t2 = $[5] : (t2 = [palette], $[4] = palette, $[5] = t2), useEffect(t1, t2);
|
|
514
|
+
let t3;
|
|
515
|
+
bb0: {
|
|
516
|
+
if (!palette) {
|
|
517
|
+
let t4;
|
|
518
|
+
$[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = [], $[6] = t4) : t4 = $[6], t3 = t4;
|
|
519
|
+
break bb0;
|
|
520
|
+
}
|
|
521
|
+
let t4;
|
|
522
|
+
$[7] !== options || $[8] !== palette ? (t4 = IMAGE_PALETTE_VARIANTS.flatMap((variant) => palette[variant] === null ? [] : [{
|
|
523
|
+
variant,
|
|
524
|
+
title: IMAGE_PALETTE_TITLES[variant],
|
|
525
|
+
options: applyImagePalette(options, palette, variant)
|
|
526
|
+
}]), $[7] = options, $[8] = palette, $[9] = t4) : t4 = $[9], t3 = t4;
|
|
527
|
+
}
|
|
528
|
+
let variants = t3, t4, t5;
|
|
529
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t4 = (event) => {
|
|
530
|
+
event.preventDefault(), dragDepth.current += 1, setDragging(!0);
|
|
531
|
+
}, t5 = () => {
|
|
532
|
+
dragDepth.current = Math.max(0, dragDepth.current - 1), dragDepth.current === 0 && setDragging(!1);
|
|
533
|
+
}, $[10] = t4, $[11] = t5) : (t4 = $[10], t5 = $[11]);
|
|
534
|
+
let t6;
|
|
535
|
+
$[12] === pickImage ? t6 = $[13] : (t6 = (event_1) => {
|
|
536
|
+
event_1.preventDefault(), dragDepth.current = 0, setDragging(!1);
|
|
537
|
+
let file = event_1.dataTransfer.files[0];
|
|
538
|
+
file && pickImage(file);
|
|
539
|
+
}, $[12] = pickImage, $[13] = t6);
|
|
540
|
+
let t7 = dragging ? "primary" : "default", t8;
|
|
541
|
+
$[14] === Symbol.for("react.memo_cache_sentinel") ? (t8 = /* @__PURE__ */ jsx(Box, {
|
|
542
|
+
flex: 1,
|
|
543
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
544
|
+
size: 1,
|
|
545
|
+
weight: "medium",
|
|
546
|
+
children: "Image palette"
|
|
547
|
+
})
|
|
548
|
+
}), $[14] = t8) : t8 = $[14];
|
|
549
|
+
let t9;
|
|
550
|
+
$[15] !== busy || $[16] !== palette || $[17] !== pickImage ? (t9 = palette && /* @__PURE__ */ jsx(ImageFileButton, {
|
|
551
|
+
loading: busy,
|
|
552
|
+
mode: "bleed",
|
|
553
|
+
onFile: pickImage,
|
|
554
|
+
padding: 2,
|
|
555
|
+
tooltip: "Pick another image"
|
|
556
|
+
}), $[15] = busy, $[16] = palette, $[17] = pickImage, $[18] = t9) : t9 = $[18];
|
|
557
|
+
let t10;
|
|
558
|
+
$[19] === t9 ? t10 = $[20] : (t10 = /* @__PURE__ */ jsxs(Flex, {
|
|
559
|
+
align: "center",
|
|
560
|
+
gap: 2,
|
|
561
|
+
children: [t8, t9]
|
|
562
|
+
}), $[19] = t9, $[20] = t10);
|
|
563
|
+
let t11;
|
|
564
|
+
$[21] !== busy || $[22] !== current || $[23] !== imageUrl || $[24] !== onLucky || $[25] !== onVariant || $[26] !== palette || $[27] !== pickImage || $[28] !== thumbnailWidth || $[29] !== variants ? (t11 = palette ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
565
|
+
/* @__PURE__ */ jsxs("div", {
|
|
566
|
+
className: paletteGrid,
|
|
567
|
+
"data-with-image": imageUrl !== void 0,
|
|
568
|
+
children: [imageUrl && /* @__PURE__ */ jsx("img", {
|
|
569
|
+
alt: "",
|
|
570
|
+
className: "_17s80v43",
|
|
571
|
+
src: imageUrl
|
|
572
|
+
}), TILES.map((key) => {
|
|
573
|
+
let hex = palette[key], title = IMAGE_PALETTE_TITLES[key];
|
|
574
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
575
|
+
animate: !0,
|
|
576
|
+
content: /* @__PURE__ */ jsx(Text, {
|
|
577
|
+
size: 1,
|
|
578
|
+
children: hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`
|
|
579
|
+
}),
|
|
580
|
+
placement: "bottom",
|
|
581
|
+
portal: !0,
|
|
582
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
583
|
+
className: tile,
|
|
584
|
+
"data-empty": hex === null,
|
|
585
|
+
style: { background: hex ?? void 0 }
|
|
586
|
+
})
|
|
587
|
+
}, key);
|
|
588
|
+
})]
|
|
589
|
+
}),
|
|
590
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
591
|
+
gap: 2,
|
|
592
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
593
|
+
muted: !0,
|
|
594
|
+
size: 0,
|
|
595
|
+
children: "Pick the swatch to build the theme around"
|
|
596
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
597
|
+
className: variantRow,
|
|
598
|
+
ref: rowRef,
|
|
599
|
+
style: assignInlineVars({
|
|
600
|
+
[variantWidth]: `${thumbnailWidth}px`,
|
|
601
|
+
[variantScale]: String(thumbnailWidth / 144)
|
|
602
|
+
}),
|
|
603
|
+
children: variants.map((t12) => {
|
|
604
|
+
let { variant: variant_0, title: title_0, options: variantOptions } = t12;
|
|
605
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
606
|
+
"aria-pressed": variant_0 === current,
|
|
607
|
+
className: variantButton,
|
|
608
|
+
onClick: () => onVariant(variant_0),
|
|
609
|
+
type: "button",
|
|
610
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
611
|
+
className: variantFrame,
|
|
612
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
613
|
+
className: variantScaleBox,
|
|
614
|
+
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: variantOptions })
|
|
615
|
+
})
|
|
616
|
+
}), /* @__PURE__ */ jsx(Box, {
|
|
617
|
+
as: "span",
|
|
618
|
+
display: "block",
|
|
619
|
+
paddingTop: 1,
|
|
620
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
621
|
+
align: "center",
|
|
622
|
+
as: "span",
|
|
623
|
+
size: 0,
|
|
624
|
+
textOverflow: "ellipsis",
|
|
625
|
+
weight: variant_0 === current ? "medium" : "regular",
|
|
626
|
+
children: title_0
|
|
627
|
+
})
|
|
628
|
+
})]
|
|
629
|
+
}, variant_0);
|
|
630
|
+
})
|
|
631
|
+
})]
|
|
632
|
+
}),
|
|
633
|
+
/* @__PURE__ */ jsx(TooltipButton, {
|
|
634
|
+
icon: SparklesIcon,
|
|
635
|
+
mode: "ghost",
|
|
636
|
+
onClick: onLucky,
|
|
637
|
+
text: "I'm feeling lucky",
|
|
638
|
+
tooltip: "Build the theme around a swatch that looks interesting",
|
|
639
|
+
width: "fill"
|
|
640
|
+
})
|
|
641
|
+
] }) : /* @__PURE__ */ jsxs(Stack, {
|
|
642
|
+
gap: 3,
|
|
643
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
644
|
+
muted: !0,
|
|
645
|
+
size: 0,
|
|
646
|
+
children: "Take the accent, text and background colors from an image — read on device, nothing is uploaded."
|
|
647
|
+
}), /* @__PURE__ */ jsx(ImageFileButton, {
|
|
648
|
+
loading: busy,
|
|
649
|
+
mode: "ghost",
|
|
650
|
+
onFile: pickImage,
|
|
651
|
+
text: "Pick an image",
|
|
652
|
+
tooltip: "Take the colors from an image on your device",
|
|
653
|
+
width: "fill"
|
|
654
|
+
})]
|
|
655
|
+
}), $[21] = busy, $[22] = current, $[23] = imageUrl, $[24] = onLucky, $[25] = onVariant, $[26] = palette, $[27] = pickImage, $[28] = thumbnailWidth, $[29] = variants, $[30] = t11) : t11 = $[30];
|
|
656
|
+
let t12;
|
|
657
|
+
$[31] !== t10 || $[32] !== t11 ? (t12 = /* @__PURE__ */ jsxs(Stack, {
|
|
658
|
+
gap: 3,
|
|
659
|
+
children: [t10, t11]
|
|
660
|
+
}), $[31] = t10, $[32] = t11, $[33] = t12) : t12 = $[33];
|
|
661
|
+
let t13;
|
|
662
|
+
return $[34] !== t12 || $[35] !== t6 || $[36] !== t7 ? (t13 = /* @__PURE__ */ jsx(Card, {
|
|
663
|
+
border: !0,
|
|
664
|
+
onDragEnter: t4,
|
|
665
|
+
onDragLeave: t5,
|
|
666
|
+
onDragOver: _temp$3,
|
|
667
|
+
onDrop: t6,
|
|
668
|
+
padding: 3,
|
|
669
|
+
radius: 3,
|
|
670
|
+
tone: t7,
|
|
671
|
+
children: t12
|
|
672
|
+
}), $[34] = t12, $[35] = t6, $[36] = t7, $[37] = t13) : t13 = $[37], t13;
|
|
673
|
+
}
|
|
674
|
+
function _temp$3(event_0) {
|
|
675
|
+
event_0.preventDefault();
|
|
676
|
+
}
|
|
677
|
+
var colorRowText = "os3rj2", range = "os3rj1", swatch = "os3rj0";
|
|
678
|
+
const SCHEME_TITLES = {
|
|
679
|
+
dark: "Dark mode",
|
|
680
|
+
light: "Light mode"
|
|
681
|
+
};
|
|
682
|
+
/**
|
|
683
|
+
* Where the split preview shows a scheme: the Studio's own scheme stays next
|
|
684
|
+
* to the sidebar (or at the bottom, stacked on small screens), the other one
|
|
685
|
+
* takes the far side
|
|
686
|
+
*/
|
|
687
|
+
function splitHint(own, mobile) {
|
|
688
|
+
return mobile ? own ? "Shown at the bottom" : "Shown at the top" : own ? "Shown on the right, next to the themer" : "Shown on the left";
|
|
689
|
+
}
|
|
690
|
+
const SCHEME_OPTION_KEYS = [
|
|
691
|
+
"accent",
|
|
692
|
+
"text",
|
|
693
|
+
"background",
|
|
694
|
+
"contrast"
|
|
695
|
+
];
|
|
696
|
+
/**
|
|
697
|
+
* `<input type="color">` paints the color into a shadow-DOM swatch that brings
|
|
698
|
+
* its own border and padding, which then sits inside ours as a second border.
|
|
699
|
+
* Stripping that chrome leaves the themed border as the only one.
|
|
700
|
+
*/
|
|
701
|
+
/**
|
|
702
|
+
* The flow for editing one of the user's own themes: its title, a live
|
|
703
|
+
* preview, and a card per color scheme with the accent/text/background
|
|
704
|
+
* pickers and the contrast slider of that scheme. Every change applies to the
|
|
705
|
+
* whole Studio right away — in the scheme the Studio is showing, or in both
|
|
706
|
+
* side by side in the split preview.
|
|
707
|
+
*
|
|
708
|
+
* @internal
|
|
709
|
+
*/
|
|
710
|
+
function ThemeEditor(props) {
|
|
711
|
+
let $ = c(42), { focusTitle, slug } = props, { themes, images, split, mobile, send } = useThemer(), t0;
|
|
712
|
+
if ($[0] !== slug || $[1] !== themes) {
|
|
713
|
+
let t1;
|
|
714
|
+
$[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;
|
|
715
|
+
} else t0 = $[2];
|
|
716
|
+
let theme = t0;
|
|
717
|
+
if (!theme) return null;
|
|
718
|
+
let t1;
|
|
719
|
+
$[5] !== send || $[6] !== slug || $[7] !== theme.options || $[8] !== theme.palette ? (t1 = (variant) => {
|
|
720
|
+
theme.palette && variant !== null && send({
|
|
721
|
+
type: "theme.update",
|
|
722
|
+
slug,
|
|
723
|
+
options: applyImagePalette(theme.options, theme.palette, variant)
|
|
724
|
+
});
|
|
725
|
+
}, $[5] = send, $[6] = slug, $[7] = theme.options, $[8] = theme.palette, $[9] = t1) : t1 = $[9];
|
|
726
|
+
let applyVariant = t1, t2 = images[slug], t3;
|
|
727
|
+
$[10] === send ? t3 = $[11] : (t3 = () => send({ type: "flow.list" }), $[10] = send, $[11] = t3);
|
|
728
|
+
let t4;
|
|
729
|
+
$[12] !== applyVariant || $[13] !== theme.options || $[14] !== theme.palette ? (t4 = () => {
|
|
730
|
+
theme.palette && applyVariant(pickLuckyVariant(theme.palette, { exclude: currentImageVariant(theme.options, theme.palette) }));
|
|
731
|
+
}, $[12] = applyVariant, $[13] = theme.options, $[14] = theme.palette, $[15] = t4) : t4 = $[15];
|
|
732
|
+
let t5;
|
|
733
|
+
$[16] !== send || $[17] !== slug ? (t5 = (options) => send({
|
|
734
|
+
type: "theme.update",
|
|
735
|
+
slug,
|
|
736
|
+
options
|
|
737
|
+
}), $[16] = send, $[17] = slug, $[18] = t5) : t5 = $[18];
|
|
738
|
+
let t6;
|
|
739
|
+
$[19] !== send || $[20] !== slug || $[21] !== theme.options ? (t6 = (palette, file) => send({
|
|
740
|
+
type: "theme.update",
|
|
741
|
+
slug,
|
|
742
|
+
options: applyImagePalette(theme.options, palette),
|
|
743
|
+
palette,
|
|
744
|
+
imageUrl: URL.createObjectURL(file)
|
|
745
|
+
}), $[19] = send, $[20] = slug, $[21] = theme.options, $[22] = t6) : t6 = $[22];
|
|
746
|
+
let t7, t8;
|
|
747
|
+
$[23] !== send || $[24] !== slug ? (t7 = () => send({
|
|
748
|
+
type: "theme.remove",
|
|
749
|
+
slug
|
|
750
|
+
}), t8 = (title) => send({
|
|
751
|
+
type: "theme.update",
|
|
752
|
+
slug,
|
|
753
|
+
title
|
|
754
|
+
}), $[23] = send, $[24] = slug, $[25] = t7, $[26] = t8) : (t7 = $[25], t8 = $[26]);
|
|
755
|
+
let t9;
|
|
756
|
+
return $[27] !== applyVariant || $[28] !== focusTitle || $[29] !== mobile || $[30] !== split || $[31] !== t2 || $[32] !== t3 || $[33] !== t4 || $[34] !== t5 || $[35] !== t6 || $[36] !== t7 || $[37] !== t8 || $[38] !== theme.options || $[39] !== theme.palette || $[40] !== theme.title ? (t9 = /* @__PURE__ */ jsx(ThemeEditorForm, {
|
|
757
|
+
focusTitle,
|
|
758
|
+
imageUrl: t2,
|
|
759
|
+
onDone: t3,
|
|
760
|
+
onLucky: t4,
|
|
761
|
+
onOptionsChange: t5,
|
|
762
|
+
onPalette: t6,
|
|
763
|
+
onRemove: t7,
|
|
764
|
+
onTitleChange: t8,
|
|
765
|
+
onVariant: applyVariant,
|
|
766
|
+
options: theme.options,
|
|
767
|
+
palette: theme.palette,
|
|
768
|
+
split,
|
|
769
|
+
mobile,
|
|
770
|
+
title: theme.title
|
|
771
|
+
}), $[27] = applyVariant, $[28] = focusTitle, $[29] = mobile, $[30] = split, $[31] = t2, $[32] = t3, $[33] = t4, $[34] = t5, $[35] = t6, $[36] = t7, $[37] = t8, $[38] = theme.options, $[39] = theme.palette, $[40] = theme.title, $[41] = t9) : t9 = $[41], t9;
|
|
772
|
+
}
|
|
773
|
+
function ThemeEditorForm(props) {
|
|
774
|
+
let $ = c(50), { focusTitle, imageUrl, onDone, onLucky, onOptionsChange, onPalette, onRemove, onTitleChange, onVariant, options, palette, split, mobile, title } = props, studioScheme = useColorSchemeValue(), t0;
|
|
775
|
+
$[0] === options ? t0 = $[1] : (t0 = resolveThemeOptions(options), $[0] = options, $[1] = t0);
|
|
776
|
+
let resolved = t0, t1;
|
|
777
|
+
$[2] === options ? t1 = $[3] : (t1 = buildPalette(options), $[2] = options, $[3] = t1);
|
|
778
|
+
let palettes = t1, t2;
|
|
779
|
+
$[4] !== onOptionsChange || $[5] !== options ? (t2 = (scheme, changes) => {
|
|
780
|
+
let values = {
|
|
781
|
+
...options[scheme],
|
|
782
|
+
...changes
|
|
783
|
+
};
|
|
784
|
+
for (let key of SCHEME_OPTION_KEYS) values[key] === void 0 && delete values[key];
|
|
785
|
+
let next = { ...options };
|
|
786
|
+
Object.keys(values).length === 0 ? delete next[scheme] : next[scheme] = values, onOptionsChange(next);
|
|
787
|
+
}, $[4] = onOptionsChange, $[5] = options, $[6] = t2) : t2 = $[6];
|
|
788
|
+
let patchScheme = t2, t3;
|
|
789
|
+
$[7] === options ? t3 = $[8] : (t3 = /* @__PURE__ */ jsx(ThemeThumbnail, { options }), $[7] = options, $[8] = t3);
|
|
790
|
+
let t4;
|
|
791
|
+
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx(Text, {
|
|
792
|
+
size: 1,
|
|
793
|
+
weight: "medium",
|
|
794
|
+
children: "Title"
|
|
795
|
+
}), $[9] = t4) : t4 = $[9];
|
|
796
|
+
let t5;
|
|
797
|
+
$[10] === onTitleChange ? t5 = $[11] : (t5 = (event) => onTitleChange(event.currentTarget.value), $[10] = onTitleChange, $[11] = t5);
|
|
798
|
+
let t6 = focusTitle ? _temp$2 : void 0, t7;
|
|
799
|
+
$[12] !== focusTitle || $[13] !== t5 || $[14] !== t6 || $[15] !== title ? (t7 = /* @__PURE__ */ jsxs(Stack, {
|
|
800
|
+
gap: 2,
|
|
801
|
+
children: [t4, /* @__PURE__ */ jsx(TextInput, {
|
|
802
|
+
autoFocus: focusTitle,
|
|
803
|
+
fontSize: 1,
|
|
804
|
+
onChange: t5,
|
|
805
|
+
onFocus: t6,
|
|
806
|
+
padding: 2,
|
|
807
|
+
placeholder: "Untitled theme",
|
|
808
|
+
value: title
|
|
809
|
+
})]
|
|
810
|
+
}), $[12] = focusTitle, $[13] = t5, $[14] = t6, $[15] = title, $[16] = t7) : t7 = $[16];
|
|
811
|
+
let t8;
|
|
812
|
+
$[17] !== imageUrl || $[18] !== onLucky || $[19] !== onPalette || $[20] !== onVariant || $[21] !== options || $[22] !== palette ? (t8 = /* @__PURE__ */ jsx(ImagePaletteSection, {
|
|
813
|
+
imageUrl,
|
|
814
|
+
onLucky,
|
|
815
|
+
onPalette,
|
|
816
|
+
onVariant,
|
|
817
|
+
options,
|
|
818
|
+
palette
|
|
819
|
+
}), $[17] = imageUrl, $[18] = onLucky, $[19] = onPalette, $[20] = onVariant, $[21] = options, $[22] = palette, $[23] = t8) : t8 = $[23];
|
|
820
|
+
let t9;
|
|
821
|
+
$[24] !== mobile || $[25] !== options || $[26] !== palettes || $[27] !== patchScheme || $[28] !== resolved || $[29] !== split || $[30] !== studioScheme ? (t9 = SCHEMES.map((scheme_0) => /* @__PURE__ */ jsx(SchemeCard, {
|
|
822
|
+
active: split || scheme_0 === studioScheme,
|
|
823
|
+
onChange: (changes_0) => patchScheme(scheme_0, changes_0),
|
|
824
|
+
options: options[scheme_0] ?? {},
|
|
825
|
+
palette: palettes[scheme_0],
|
|
826
|
+
resolved: resolved[scheme_0],
|
|
827
|
+
scheme: scheme_0,
|
|
828
|
+
split,
|
|
829
|
+
splitHint: splitHint(scheme_0 === studioScheme, mobile)
|
|
830
|
+
}, scheme_0)), $[24] = mobile, $[25] = options, $[26] = palettes, $[27] = patchScheme, $[28] = resolved, $[29] = split, $[30] = studioScheme, $[31] = t9) : t9 = $[31];
|
|
831
|
+
let t10;
|
|
832
|
+
$[32] === t9 ? t10 = $[33] : (t10 = /* @__PURE__ */ jsx(ScrollAreaBleed, { children: t9 }), $[32] = t9, $[33] = t10);
|
|
833
|
+
let t11;
|
|
834
|
+
$[34] !== t10 || $[35] !== t3 || $[36] !== t7 || $[37] !== t8 ? (t11 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
835
|
+
padding: 3,
|
|
836
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
837
|
+
gap: 4,
|
|
838
|
+
children: [
|
|
839
|
+
t3,
|
|
840
|
+
t7,
|
|
841
|
+
t8,
|
|
842
|
+
t10
|
|
843
|
+
]
|
|
844
|
+
})
|
|
845
|
+
}), $[34] = t10, $[35] = t3, $[36] = t7, $[37] = t8, $[38] = t11) : t11 = $[38];
|
|
846
|
+
let t12;
|
|
847
|
+
$[39] === onRemove ? t12 = $[40] : (t12 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
848
|
+
icon: TrashIcon,
|
|
849
|
+
mode: "ghost",
|
|
850
|
+
onClick: onRemove,
|
|
851
|
+
text: "Remove",
|
|
852
|
+
tone: "critical",
|
|
853
|
+
tooltip: "Remove the theme — it can be restored until it is deleted"
|
|
854
|
+
}), $[39] = onRemove, $[40] = t12);
|
|
855
|
+
let t13;
|
|
856
|
+
$[41] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Box, { flex: 1 }), $[41] = t13) : t13 = $[41];
|
|
857
|
+
let t14;
|
|
858
|
+
$[42] === onDone ? t14 = $[43] : (t14 = /* @__PURE__ */ jsx(Button, {
|
|
859
|
+
mode: "ghost",
|
|
860
|
+
onClick: onDone,
|
|
861
|
+
padding: 2,
|
|
862
|
+
text: "Done"
|
|
863
|
+
}), $[42] = onDone, $[43] = t14);
|
|
864
|
+
let t15;
|
|
865
|
+
$[44] !== t12 || $[45] !== t14 ? (t15 = /* @__PURE__ */ jsx(Card, {
|
|
866
|
+
borderTop: !0,
|
|
867
|
+
padding: 3,
|
|
868
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
869
|
+
gap: 2,
|
|
870
|
+
children: [
|
|
871
|
+
t12,
|
|
872
|
+
t13,
|
|
873
|
+
t14
|
|
874
|
+
]
|
|
875
|
+
})
|
|
876
|
+
}), $[44] = t12, $[45] = t14, $[46] = t15) : t15 = $[46];
|
|
877
|
+
let t16;
|
|
878
|
+
return $[47] !== t11 || $[48] !== t15 ? (t16 = /* @__PURE__ */ jsxs(Fragment, { children: [t11, t15] }), $[47] = t11, $[48] = t15, $[49] = t16) : t16 = $[49], t16;
|
|
879
|
+
}
|
|
880
|
+
function _temp$2(event_0) {
|
|
881
|
+
return event_0.currentTarget.select();
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* The colors of one scheme. The cards span the sidebar edge to edge, one
|
|
885
|
+
* after the other with a border between them, in the sidebar's own scheme —
|
|
886
|
+
* the swatches show the colors they edit. The scheme the Studio is showing is
|
|
887
|
+
* marked as active: its changes show up in the Studio right away, the other
|
|
888
|
+
* scheme's only once the appearance setting switches to it — or both are
|
|
889
|
+
* active, in the split preview.
|
|
890
|
+
*/
|
|
891
|
+
function SchemeCard(props) {
|
|
892
|
+
let $ = c(66), { active, onChange, options, palette, resolved, scheme, split, splitHint } = props, name = SCHEME_TITLES[scheme], t0;
|
|
893
|
+
$[0] === name ? t0 = $[1] : (t0 = /* @__PURE__ */ jsx(Box, {
|
|
894
|
+
flex: 1,
|
|
895
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
896
|
+
size: 1,
|
|
897
|
+
weight: "medium",
|
|
898
|
+
children: name
|
|
899
|
+
})
|
|
900
|
+
}), $[0] = name, $[1] = t0);
|
|
901
|
+
let t1;
|
|
902
|
+
$[2] === active ? t1 = $[3] : (t1 = active && /* @__PURE__ */ jsx(Badge, {
|
|
903
|
+
fontSize: 0,
|
|
904
|
+
tone: "primary",
|
|
905
|
+
children: "Active"
|
|
906
|
+
}), $[2] = active, $[3] = t1);
|
|
907
|
+
let t2;
|
|
908
|
+
$[4] !== t0 || $[5] !== t1 ? (t2 = /* @__PURE__ */ jsxs(Flex, {
|
|
909
|
+
align: "center",
|
|
910
|
+
gap: 2,
|
|
911
|
+
children: [t0, t1]
|
|
912
|
+
}), $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
|
|
913
|
+
let t3 = split ? splitHint : active ? "Shown in the Studio right now" : `Shown once the Studio appearance is ${scheme}`, t4;
|
|
914
|
+
$[7] === t3 ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(Text, {
|
|
915
|
+
muted: !0,
|
|
916
|
+
size: 0,
|
|
917
|
+
children: t3
|
|
918
|
+
}), $[7] = t3, $[8] = t4);
|
|
919
|
+
let t5;
|
|
920
|
+
$[9] !== t2 || $[10] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Stack, {
|
|
921
|
+
gap: 2,
|
|
922
|
+
children: [t2, t4]
|
|
923
|
+
}), $[9] = t2, $[10] = t4, $[11] = t5) : t5 = $[11];
|
|
924
|
+
let t6 = options.accent === void 0, t7 = `${name} accent`, t8, t9;
|
|
925
|
+
$[12] === onChange ? (t8 = $[13], t9 = $[14]) : (t8 = (accent) => onChange({ accent }), t9 = () => onChange({ accent: void 0 }), $[12] = onChange, $[13] = t8, $[14] = t9);
|
|
926
|
+
let t10;
|
|
927
|
+
$[15] !== resolved.accent || $[16] !== t6 || $[17] !== t7 || $[18] !== t8 || $[19] !== t9 ? (t10 = /* @__PURE__ */ jsx(ColorRow, {
|
|
928
|
+
auto: t6,
|
|
929
|
+
autoLabel: "default",
|
|
930
|
+
label: t7,
|
|
931
|
+
onChange: t8,
|
|
932
|
+
onClear: t9,
|
|
933
|
+
title: "Accent",
|
|
934
|
+
value: resolved.accent
|
|
935
|
+
}), $[15] = resolved.accent, $[16] = t6, $[17] = t7, $[18] = t8, $[19] = t9, $[20] = t10) : t10 = $[20];
|
|
936
|
+
let t11 = options.text === void 0, t12 = `${name} text`, t13, t14;
|
|
937
|
+
$[21] === onChange ? (t13 = $[22], t14 = $[23]) : (t13 = (text) => onChange({ text }), t14 = () => onChange({ text: void 0 }), $[21] = onChange, $[22] = t13, $[23] = t14);
|
|
938
|
+
let t15;
|
|
939
|
+
$[24] !== resolved.text || $[25] !== t11 || $[26] !== t12 || $[27] !== t13 || $[28] !== t14 ? (t15 = /* @__PURE__ */ jsx(ColorRow, {
|
|
940
|
+
auto: t11,
|
|
941
|
+
label: t12,
|
|
942
|
+
onChange: t13,
|
|
943
|
+
onClear: t14,
|
|
944
|
+
title: "Text",
|
|
945
|
+
value: resolved.text
|
|
946
|
+
}), $[24] = resolved.text, $[25] = t11, $[26] = t12, $[27] = t13, $[28] = t14, $[29] = t15) : t15 = $[29];
|
|
947
|
+
let t16 = scheme === "dark" ? palette.black : palette.white, t17 = options.background === void 0, t18 = `${name} background`, t19, t20;
|
|
948
|
+
$[30] === onChange ? (t19 = $[31], t20 = $[32]) : (t19 = (background) => onChange({ background }), t20 = () => onChange({ background: void 0 }), $[30] = onChange, $[31] = t19, $[32] = t20);
|
|
949
|
+
let t21;
|
|
950
|
+
$[33] !== resolved.background || $[34] !== t16 || $[35] !== t17 || $[36] !== t18 || $[37] !== t19 || $[38] !== t20 ? (t21 = /* @__PURE__ */ jsx(ColorRow, {
|
|
951
|
+
adjusted: t16,
|
|
952
|
+
auto: t17,
|
|
953
|
+
label: t18,
|
|
954
|
+
onChange: t19,
|
|
955
|
+
onClear: t20,
|
|
956
|
+
title: "Background",
|
|
957
|
+
value: resolved.background
|
|
958
|
+
}), $[33] = resolved.background, $[34] = t16, $[35] = t17, $[36] = t18, $[37] = t19, $[38] = t20, $[39] = t21) : t21 = $[39];
|
|
959
|
+
let t22;
|
|
960
|
+
$[40] === Symbol.for("react.memo_cache_sentinel") ? (t22 = /* @__PURE__ */ jsx(Text, {
|
|
961
|
+
size: 1,
|
|
962
|
+
children: "Contrast"
|
|
963
|
+
}), $[40] = t22) : t22 = $[40];
|
|
964
|
+
let t23 = options.contrast === void 0 ? " · auto" : "", t24;
|
|
965
|
+
$[41] !== resolved.contrast || $[42] !== t23 ? (t24 = /* @__PURE__ */ jsxs(Stack, {
|
|
966
|
+
flex: 1,
|
|
967
|
+
gap: 2,
|
|
968
|
+
children: [t22, /* @__PURE__ */ jsxs(Text, {
|
|
969
|
+
muted: !0,
|
|
970
|
+
size: 0,
|
|
971
|
+
children: [resolved.contrast, t23]
|
|
972
|
+
})]
|
|
973
|
+
}), $[41] = resolved.contrast, $[42] = t23, $[43] = t24) : t24 = $[43];
|
|
974
|
+
let t25;
|
|
975
|
+
$[44] !== onChange || $[45] !== options.contrast ? (t25 = options.contrast !== void 0 && /* @__PURE__ */ jsx(TooltipButton, {
|
|
976
|
+
icon: ResetIcon,
|
|
977
|
+
mode: "bleed",
|
|
978
|
+
onClick: () => onChange({ contrast: void 0 }),
|
|
979
|
+
padding: 2,
|
|
980
|
+
tooltip: "Reset to auto"
|
|
981
|
+
}), $[44] = onChange, $[45] = options.contrast, $[46] = t25) : t25 = $[46];
|
|
982
|
+
let t26;
|
|
983
|
+
$[47] !== t24 || $[48] !== t25 ? (t26 = /* @__PURE__ */ jsxs(Flex, {
|
|
984
|
+
align: "center",
|
|
985
|
+
gap: 2,
|
|
986
|
+
children: [t24, t25]
|
|
987
|
+
}), $[47] = t24, $[48] = t25, $[49] = t26) : t26 = $[49];
|
|
988
|
+
let t27 = `${name} contrast`, t28;
|
|
989
|
+
$[50] === onChange ? t28 = $[51] : (t28 = (event) => onChange({ contrast: Number(event.currentTarget.value) }), $[50] = onChange, $[51] = t28);
|
|
990
|
+
let t29;
|
|
991
|
+
$[52] !== resolved.contrast || $[53] !== t27 || $[54] !== t28 ? (t29 = /* @__PURE__ */ jsx("input", {
|
|
992
|
+
"aria-label": t27,
|
|
993
|
+
className: range,
|
|
994
|
+
max: 100,
|
|
995
|
+
min: 15,
|
|
996
|
+
onChange: t28,
|
|
997
|
+
step: 1,
|
|
998
|
+
type: "range",
|
|
999
|
+
value: resolved.contrast
|
|
1000
|
+
}), $[52] = resolved.contrast, $[53] = t27, $[54] = t28, $[55] = t29) : t29 = $[55];
|
|
1001
|
+
let t30;
|
|
1002
|
+
$[56] === Symbol.for("react.memo_cache_sentinel") ? (t30 = /* @__PURE__ */ jsx(Text, {
|
|
1003
|
+
muted: !0,
|
|
1004
|
+
size: 0,
|
|
1005
|
+
children: "100 keeps text and borders neutral — lower values blend in the accent"
|
|
1006
|
+
}), $[56] = t30) : t30 = $[56];
|
|
1007
|
+
let t31;
|
|
1008
|
+
$[57] !== t26 || $[58] !== t29 ? (t31 = /* @__PURE__ */ jsxs(Stack, {
|
|
1009
|
+
gap: 3,
|
|
1010
|
+
children: [
|
|
1011
|
+
t26,
|
|
1012
|
+
t29,
|
|
1013
|
+
t30
|
|
1014
|
+
]
|
|
1015
|
+
}), $[57] = t26, $[58] = t29, $[59] = t31) : t31 = $[59];
|
|
1016
|
+
let t32;
|
|
1017
|
+
return $[60] !== t10 || $[61] !== t15 || $[62] !== t21 || $[63] !== t31 || $[64] !== t5 ? (t32 = /* @__PURE__ */ jsx(Card, {
|
|
1018
|
+
borderTop: !0,
|
|
1019
|
+
padding: 3,
|
|
1020
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1021
|
+
gap: 4,
|
|
1022
|
+
children: [
|
|
1023
|
+
t5,
|
|
1024
|
+
t10,
|
|
1025
|
+
t15,
|
|
1026
|
+
t21,
|
|
1027
|
+
t31
|
|
1028
|
+
]
|
|
1029
|
+
})
|
|
1030
|
+
}), $[60] = t10, $[61] = t15, $[62] = t21, $[63] = t31, $[64] = t5, $[65] = t32) : t32 = $[65], t32;
|
|
1031
|
+
}
|
|
1032
|
+
/** One color of a scheme: a swatch with its value and an optional reset button */
|
|
1033
|
+
function ColorRow(props) {
|
|
1034
|
+
let $ = c(23), { adjusted, auto, autoLabel: t0, label, onChange, onClear, title, value } = props, autoLabel = t0 === void 0 ? "auto" : t0, t1;
|
|
1035
|
+
$[0] === onChange ? t1 = $[1] : (t1 = (event) => onChange(event.currentTarget.value), $[0] = onChange, $[1] = t1);
|
|
1036
|
+
let t2;
|
|
1037
|
+
$[2] !== label || $[3] !== t1 || $[4] !== value ? (t2 = /* @__PURE__ */ jsx("input", {
|
|
1038
|
+
"aria-label": label,
|
|
1039
|
+
className: swatch,
|
|
1040
|
+
onChange: t1,
|
|
1041
|
+
type: "color",
|
|
1042
|
+
value
|
|
1043
|
+
}), $[2] = label, $[3] = t1, $[4] = value, $[5] = t2) : t2 = $[5];
|
|
1044
|
+
let t3;
|
|
1045
|
+
$[6] === title ? t3 = $[7] : (t3 = /* @__PURE__ */ jsx(Text, {
|
|
1046
|
+
size: 1,
|
|
1047
|
+
children: title
|
|
1048
|
+
}), $[6] = title, $[7] = t3);
|
|
1049
|
+
let t4 = adjusted !== void 0 && adjusted !== value ? ` → ${adjusted}` : "", t5 = auto ? ` · ${autoLabel}` : "", t6;
|
|
1050
|
+
$[8] !== t4 || $[9] !== t5 || $[10] !== value ? (t6 = /* @__PURE__ */ jsxs(Text, {
|
|
1051
|
+
muted: !0,
|
|
1052
|
+
size: 0,
|
|
1053
|
+
textOverflow: "ellipsis",
|
|
1054
|
+
children: [
|
|
1055
|
+
value,
|
|
1056
|
+
t4,
|
|
1057
|
+
t5
|
|
1058
|
+
]
|
|
1059
|
+
}), $[8] = t4, $[9] = t5, $[10] = value, $[11] = t6) : t6 = $[11];
|
|
1060
|
+
let t7;
|
|
1061
|
+
$[12] !== t3 || $[13] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Stack, {
|
|
1062
|
+
className: colorRowText,
|
|
1063
|
+
flex: 1,
|
|
1064
|
+
gap: 2,
|
|
1065
|
+
children: [t3, t6]
|
|
1066
|
+
}), $[12] = t3, $[13] = t6, $[14] = t7) : t7 = $[14];
|
|
1067
|
+
let t8;
|
|
1068
|
+
$[15] !== auto || $[16] !== autoLabel || $[17] !== onClear ? (t8 = onClear && !auto && /* @__PURE__ */ jsx(TooltipButton, {
|
|
1069
|
+
icon: ResetIcon,
|
|
1070
|
+
mode: "bleed",
|
|
1071
|
+
onClick: onClear,
|
|
1072
|
+
padding: 2,
|
|
1073
|
+
tooltip: `Reset to ${autoLabel}`
|
|
1074
|
+
}), $[15] = auto, $[16] = autoLabel, $[17] = onClear, $[18] = t8) : t8 = $[18];
|
|
1075
|
+
let t9;
|
|
1076
|
+
return $[19] !== t2 || $[20] !== t7 || $[21] !== t8 ? (t9 = /* @__PURE__ */ jsxs(Flex, {
|
|
1077
|
+
align: "center",
|
|
1078
|
+
gap: 2,
|
|
1079
|
+
children: [
|
|
1080
|
+
t2,
|
|
1081
|
+
t7,
|
|
1082
|
+
t8
|
|
1083
|
+
]
|
|
1084
|
+
}), $[19] = t2, $[20] = t7, $[21] = t8, $[22] = t9) : t9 = $[22], t9;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* The version of the code format, the first byte of every code — bumped if
|
|
1088
|
+
* the layout below ever changes, so older codes can still be told apart
|
|
1089
|
+
*/
|
|
1090
|
+
const FIELDS = [
|
|
1091
|
+
"accent",
|
|
1092
|
+
"text",
|
|
1093
|
+
"background",
|
|
1094
|
+
"contrast"
|
|
1095
|
+
];
|
|
1096
|
+
/**
|
|
1097
|
+
* Turns a theme into a short code to share in a message: `title`, and the
|
|
1098
|
+
* colors and contrasts of both schemes, packed into bytes — one flag byte says
|
|
1099
|
+
* which of the eight fields are set, each color is its three RGB bytes and a
|
|
1100
|
+
* contrast one byte, and the title takes up the rest — then base64url'd, so
|
|
1101
|
+
* it is one word without padding, safe in URLs and chat. A theme setting
|
|
1102
|
+
* everything comes to about 30 bytes plus its title.
|
|
1103
|
+
*
|
|
1104
|
+
* @internal
|
|
1105
|
+
*/
|
|
1106
|
+
function encodeTheme(theme) {
|
|
1107
|
+
let bytes = [1, 0], flags = 0;
|
|
1108
|
+
return SCHEMES.forEach((scheme, schemeIndex) => {
|
|
1109
|
+
let options = theme.options[scheme] ?? {};
|
|
1110
|
+
FIELDS.forEach((field, fieldIndex) => {
|
|
1111
|
+
let value = options[field];
|
|
1112
|
+
if (value !== void 0) {
|
|
1113
|
+
if (field === "contrast") {
|
|
1114
|
+
if (typeof value != "number" || !Number.isFinite(value)) return;
|
|
1115
|
+
bytes.push(Math.round(Math.min(100, Math.max(15, value))));
|
|
1116
|
+
} else {
|
|
1117
|
+
if (typeof value != "string" || !isColor(value)) return;
|
|
1118
|
+
bytes.push(...rgbBytes(value));
|
|
1119
|
+
}
|
|
1120
|
+
flags |= 1 << schemeIndex * FIELDS.length + fieldIndex;
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
}), bytes[1] = flags, bytes.push(...new TextEncoder().encode(theme.title.trim())), toBase64Url(Uint8Array.from(bytes));
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Reads a theme back out of a code — as pasted, so surrounding whitespace and
|
|
1127
|
+
* words around the code are fine: the first word that is a code counts. `null`
|
|
1128
|
+
* when nothing in the text is one.
|
|
1129
|
+
*
|
|
1130
|
+
* @internal
|
|
1131
|
+
*/
|
|
1132
|
+
function decodeTheme(text) {
|
|
1133
|
+
for (let word of text.trim().split(/\s+/)) {
|
|
1134
|
+
let theme = decodeCode(word);
|
|
1135
|
+
if (theme) return theme;
|
|
1136
|
+
}
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
function decodeCode(code) {
|
|
1140
|
+
let bytes = fromBase64Url(code);
|
|
1141
|
+
if (!bytes || bytes.length < 2 || bytes[0] !== 1) return null;
|
|
1142
|
+
let flags = bytes[1], options = {}, offset = 2;
|
|
1143
|
+
for (let [schemeIndex, scheme] of SCHEMES.entries()) {
|
|
1144
|
+
let schemeOptions = {};
|
|
1145
|
+
for (let [fieldIndex, field] of FIELDS.entries()) if (flags & 1 << schemeIndex * FIELDS.length + fieldIndex) {
|
|
1146
|
+
if (field === "contrast") {
|
|
1147
|
+
if (offset + 1 > bytes.length) return null;
|
|
1148
|
+
schemeOptions.contrast = Math.min(100, Math.max(15, bytes[offset])), offset += 1;
|
|
1149
|
+
} else {
|
|
1150
|
+
if (offset + 3 > bytes.length) return null;
|
|
1151
|
+
schemeOptions[field] = hexColor(bytes.subarray(offset, offset + 3)), offset += 3;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
Object.keys(schemeOptions).length > 0 && (options[scheme] = schemeOptions);
|
|
1155
|
+
}
|
|
1156
|
+
let title;
|
|
1157
|
+
try {
|
|
1158
|
+
title = new TextDecoder("utf-8", { fatal: !0 }).decode(bytes.subarray(offset));
|
|
1159
|
+
} catch {
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
title: displayTitle(title),
|
|
1164
|
+
options
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
/** The three RGB bytes of a `#rgb` or `#rrggbb` color */
|
|
1168
|
+
function rgbBytes(color) {
|
|
1169
|
+
let hex = color.length === 4 ? color.slice(1).replaceAll(/./g, "$&$&") : color.slice(1);
|
|
1170
|
+
return [
|
|
1171
|
+
0,
|
|
1172
|
+
2,
|
|
1173
|
+
4
|
|
1174
|
+
].map((start) => parseInt(hex.slice(start, start + 2), 16));
|
|
1175
|
+
}
|
|
1176
|
+
function hexColor(rgb) {
|
|
1177
|
+
return `#${[...rgb].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
1178
|
+
}
|
|
1179
|
+
function toBase64Url(bytes) {
|
|
1180
|
+
let binary = "";
|
|
1181
|
+
for (let byte of bytes) binary += String.fromCharCode(byte);
|
|
1182
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
1183
|
+
}
|
|
1184
|
+
function fromBase64Url(code) {
|
|
1185
|
+
if (!/^[A-Za-z0-9_-]+$/.test(code)) return null;
|
|
1186
|
+
let base64 = code.replaceAll("-", "+").replaceAll("_", "/");
|
|
1187
|
+
try {
|
|
1188
|
+
return Uint8Array.from(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "=")), (char) => char.charCodeAt(0));
|
|
1189
|
+
} catch {
|
|
1190
|
+
return null;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Copying a theme as a code to share, and adding a theme from a code someone
|
|
1195
|
+
* shared — with toasts telling how it went.
|
|
1196
|
+
*
|
|
1197
|
+
* @internal
|
|
1198
|
+
*/
|
|
1199
|
+
function useThemeCodes() {
|
|
1200
|
+
let $ = c(11), { send } = useThemer(), toast = useToast(), t0;
|
|
1201
|
+
$[0] === toast ? t0 = $[1] : (t0 = async (theme) => {
|
|
1202
|
+
let title = displayTitle(theme.title);
|
|
1203
|
+
try {
|
|
1204
|
+
await navigator.clipboard.writeText(encodeTheme(theme)), toast.push({
|
|
1205
|
+
status: "success",
|
|
1206
|
+
title: `Copied ${title} as a code`,
|
|
1207
|
+
description: "Paste it in the themer of another Studio to add the theme there"
|
|
1208
|
+
});
|
|
1209
|
+
} catch {
|
|
1210
|
+
toast.push({
|
|
1211
|
+
status: "error",
|
|
1212
|
+
title: `Could not copy ${title}`
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
}, $[0] = toast, $[1] = t0);
|
|
1216
|
+
let copyTheme = t0, t1;
|
|
1217
|
+
$[2] !== send || $[3] !== toast ? (t1 = (text) => {
|
|
1218
|
+
let theme_0 = decodeTheme(text);
|
|
1219
|
+
return theme_0 ? (send({
|
|
1220
|
+
type: "theme.import",
|
|
1221
|
+
title: theme_0.title,
|
|
1222
|
+
options: theme_0.options
|
|
1223
|
+
}), toast.push({
|
|
1224
|
+
status: "success",
|
|
1225
|
+
title: `Added ${theme_0.title}`
|
|
1226
|
+
}), !0) : !1;
|
|
1227
|
+
}, $[2] = send, $[3] = toast, $[4] = t1) : t1 = $[4];
|
|
1228
|
+
let addThemeFromText = t1, t2;
|
|
1229
|
+
$[5] === addThemeFromText ? t2 = $[6] : (t2 = async () => {
|
|
1230
|
+
let text_0;
|
|
1231
|
+
try {
|
|
1232
|
+
text_0 = await navigator.clipboard.readText();
|
|
1233
|
+
} catch {
|
|
1234
|
+
return "no-clipboard";
|
|
1235
|
+
}
|
|
1236
|
+
return addThemeFromText(text_0) ? "added" : "no-theme";
|
|
1237
|
+
}, $[5] = addThemeFromText, $[6] = t2);
|
|
1238
|
+
let addThemeFromClipboard = t2, t3;
|
|
1239
|
+
return $[7] !== addThemeFromClipboard || $[8] !== addThemeFromText || $[9] !== copyTheme ? (t3 = {
|
|
1240
|
+
copyTheme,
|
|
1241
|
+
addThemeFromText,
|
|
1242
|
+
addThemeFromClipboard
|
|
1243
|
+
}, $[7] = addThemeFromClipboard, $[8] = addThemeFromText, $[9] = copyTheme, $[10] = t3) : t3 = $[10], t3;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Adds a theme pasted anywhere in the Studio while the themer's list is
|
|
1247
|
+
* showing — pastes into inputs and other editable things are theirs.
|
|
1248
|
+
*
|
|
1249
|
+
* @internal
|
|
1250
|
+
*/
|
|
1251
|
+
function usePasteThemeCodes() {
|
|
1252
|
+
let $ = c(5), { open, send } = useThemer(), toast = useToast(), t0, t1;
|
|
1253
|
+
$[0] !== open || $[1] !== send || $[2] !== toast ? (t0 = () => {
|
|
1254
|
+
if (!open) return;
|
|
1255
|
+
let handlePaste = (event) => {
|
|
1256
|
+
if (isEditable(event.target)) return;
|
|
1257
|
+
let theme = decodeTheme(event.clipboardData?.getData("text/plain") ?? "");
|
|
1258
|
+
theme && (event.preventDefault(), send({
|
|
1259
|
+
type: "theme.import",
|
|
1260
|
+
title: theme.title,
|
|
1261
|
+
options: theme.options
|
|
1262
|
+
}), toast.push({
|
|
1263
|
+
status: "success",
|
|
1264
|
+
title: `Added ${theme.title}`
|
|
1265
|
+
}));
|
|
1266
|
+
};
|
|
1267
|
+
return document.addEventListener("paste", handlePaste), () => document.removeEventListener("paste", handlePaste);
|
|
1268
|
+
}, t1 = [
|
|
1269
|
+
open,
|
|
1270
|
+
send,
|
|
1271
|
+
toast
|
|
1272
|
+
], $[0] = open, $[1] = send, $[2] = toast, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1);
|
|
1273
|
+
}
|
|
1274
|
+
function isEditable(target) {
|
|
1275
|
+
return target instanceof HTMLElement && (target.isContentEditable || target.matches("input, textarea, select"));
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Where a theme code someone shared gets pasted by hand — for browsers that
|
|
1279
|
+
* do not hand the clipboard over, and for codes that are not on it.
|
|
1280
|
+
*
|
|
1281
|
+
* @internal
|
|
1282
|
+
*/
|
|
1283
|
+
function PasteThemeDialog(props) {
|
|
1284
|
+
let $ = c(35), { onClose } = props, { addThemeFromText } = useThemeCodes(), [text, setText] = useState(""), [invalid, setInvalid] = useState(!1), t0;
|
|
1285
|
+
$[0] !== addThemeFromText || $[1] !== onClose || $[2] !== text ? (t0 = () => {
|
|
1286
|
+
addThemeFromText(text) ? onClose() : setInvalid(!0);
|
|
1287
|
+
}, $[0] = addThemeFromText, $[1] = onClose, $[2] = text, $[3] = t0) : t0 = $[3];
|
|
1288
|
+
let add = t0, t1;
|
|
1289
|
+
$[4] === onClose ? t1 = $[5] : (t1 = /* @__PURE__ */ jsx(Button, {
|
|
1290
|
+
mode: "ghost",
|
|
1291
|
+
onClick: onClose,
|
|
1292
|
+
padding: 2,
|
|
1293
|
+
text: "Cancel"
|
|
1294
|
+
}), $[4] = onClose, $[5] = t1);
|
|
1295
|
+
let t2;
|
|
1296
|
+
$[6] === text ? t2 = $[7] : (t2 = text.trim(), $[6] = text, $[7] = t2);
|
|
1297
|
+
let t3 = t2 === "", t4;
|
|
1298
|
+
$[8] !== add || $[9] !== t3 ? (t4 = /* @__PURE__ */ jsx(Button, {
|
|
1299
|
+
disabled: t3,
|
|
1300
|
+
onClick: add,
|
|
1301
|
+
padding: 2,
|
|
1302
|
+
text: "Add theme",
|
|
1303
|
+
tone: "primary"
|
|
1304
|
+
}), $[8] = add, $[9] = t3, $[10] = t4) : t4 = $[10];
|
|
1305
|
+
let t5;
|
|
1306
|
+
$[11] !== t1 || $[12] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Flex, {
|
|
1307
|
+
gap: 2,
|
|
1308
|
+
justify: "flex-end",
|
|
1309
|
+
padding: 3,
|
|
1310
|
+
children: [t1, t4]
|
|
1311
|
+
}), $[11] = t1, $[12] = t4, $[13] = t5) : t5 = $[13];
|
|
1312
|
+
let t6;
|
|
1313
|
+
$[14] === add ? t6 = $[15] : (t6 = (event) => {
|
|
1314
|
+
event.preventDefault(), add();
|
|
1315
|
+
}, $[14] = add, $[15] = t6);
|
|
1316
|
+
let t7;
|
|
1317
|
+
$[16] === Symbol.for("react.memo_cache_sentinel") ? (t7 = /* @__PURE__ */ jsx(Text, {
|
|
1318
|
+
muted: !0,
|
|
1319
|
+
size: 1,
|
|
1320
|
+
children: "Paste the code someone copied from their themer — the theme is added to your list and applied."
|
|
1321
|
+
}), $[16] = t7) : t7 = $[16];
|
|
1322
|
+
let t8 = invalid ? "themer-paste-error" : void 0, t9 = invalid ? "That is not a theme code" : void 0, t10;
|
|
1323
|
+
$[17] === Symbol.for("react.memo_cache_sentinel") ? (t10 = (event_0) => {
|
|
1324
|
+
setText(event_0.currentTarget.value), setInvalid(!1);
|
|
1325
|
+
}, $[17] = t10) : t10 = $[17];
|
|
1326
|
+
let t11;
|
|
1327
|
+
$[18] !== invalid || $[19] !== t8 || $[20] !== t9 || $[21] !== text ? (t11 = /* @__PURE__ */ jsx(TextInput, {
|
|
1328
|
+
"aria-describedby": t8,
|
|
1329
|
+
"aria-invalid": invalid,
|
|
1330
|
+
"aria-label": "Theme code",
|
|
1331
|
+
autoFocus: !0,
|
|
1332
|
+
customValidity: t9,
|
|
1333
|
+
fontSize: 1,
|
|
1334
|
+
onChange: t10,
|
|
1335
|
+
placeholder: "AQ…",
|
|
1336
|
+
value: text
|
|
1337
|
+
}), $[18] = invalid, $[19] = t8, $[20] = t9, $[21] = text, $[22] = t11) : t11 = $[22];
|
|
1338
|
+
let t12;
|
|
1339
|
+
$[23] === invalid ? t12 = $[24] : (t12 = invalid && /* @__PURE__ */ jsx(Card, {
|
|
1340
|
+
id: "themer-paste-error",
|
|
1341
|
+
padding: 3,
|
|
1342
|
+
radius: 2,
|
|
1343
|
+
role: "alert",
|
|
1344
|
+
tone: "critical",
|
|
1345
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1346
|
+
size: 1,
|
|
1347
|
+
children: "That is not a theme code — codes are one word, copied from a theme's menu."
|
|
1348
|
+
})
|
|
1349
|
+
}), $[23] = invalid, $[24] = t12);
|
|
1350
|
+
let t13;
|
|
1351
|
+
$[25] !== t11 || $[26] !== t12 ? (t13 = /* @__PURE__ */ jsxs(Stack, {
|
|
1352
|
+
gap: 3,
|
|
1353
|
+
padding: 4,
|
|
1354
|
+
children: [
|
|
1355
|
+
t7,
|
|
1356
|
+
t11,
|
|
1357
|
+
t12
|
|
1358
|
+
]
|
|
1359
|
+
}), $[25] = t11, $[26] = t12, $[27] = t13) : t13 = $[27];
|
|
1360
|
+
let t14;
|
|
1361
|
+
$[28] !== t13 || $[29] !== t6 ? (t14 = /* @__PURE__ */ jsx("form", {
|
|
1362
|
+
onSubmit: t6,
|
|
1363
|
+
children: t13
|
|
1364
|
+
}), $[28] = t13, $[29] = t6, $[30] = t14) : t14 = $[30];
|
|
1365
|
+
let t15;
|
|
1366
|
+
return $[31] !== onClose || $[32] !== t14 || $[33] !== t5 ? (t15 = /* @__PURE__ */ jsx(Dialog, {
|
|
1367
|
+
animate: !0,
|
|
1368
|
+
footer: t5,
|
|
1369
|
+
header: "Add a shared theme",
|
|
1370
|
+
id: "themer-paste",
|
|
1371
|
+
onClickOutside: onClose,
|
|
1372
|
+
onClose,
|
|
1373
|
+
width: 0,
|
|
1374
|
+
children: t14
|
|
1375
|
+
}), $[31] = onClose, $[32] = t14, $[33] = t5, $[34] = t15) : t15 = $[34], t15;
|
|
1376
|
+
}
|
|
1377
|
+
var frame$1 = "_1wsn7882", menuCard = "_1wsn7884", menuSlot = "_1wsn7883", pickButton = "_1wsn7881", root = "_1wsn7880";
|
|
1378
|
+
/**
|
|
1379
|
+
* Scrolls the applied theme's card into view when it is not already, as a
|
|
1380
|
+
* ref: the list scrolls to it as it mounts — coming back from the editor or
|
|
1381
|
+
* the removed themes — and when another theme gets applied
|
|
1382
|
+
*/
|
|
1383
|
+
function scrollRefIntoViewIfNeeded(node) {
|
|
1384
|
+
node && scrollIntoView(node, {
|
|
1385
|
+
block: "nearest",
|
|
1386
|
+
scrollMode: "if-needed"
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* One theme in the list: the floating preview with the title below it, like
|
|
1391
|
+
* an appearance option in macOS System Settings. Clicking it applies the
|
|
1392
|
+
* theme to the whole Studio, dragging it moves the theme to another place in
|
|
1393
|
+
* the list; its menu holds the move, edit, duplicate and remove flows that
|
|
1394
|
+
* apply to the theme.
|
|
1395
|
+
*
|
|
1396
|
+
* @internal
|
|
1397
|
+
*/
|
|
1398
|
+
function ThemeCard(props) {
|
|
1399
|
+
let $ = c(85), { active, theme } = props, { themes, send } = useThemer(), { copyTheme } = useThemeCodes(), { scheme } = useRootTheme(), [menuOpen, setMenuOpen] = useState(!1), dragControls = useDragControls(), dragged = useRef(!1), t0;
|
|
1400
|
+
$[0] === theme.title ? t0 = $[1] : (t0 = displayTitle(theme.title), $[0] = theme.title, $[1] = t0);
|
|
1401
|
+
let title = t0, t1;
|
|
1402
|
+
$[2] === theme.slug ? t1 = $[3] : (t1 = (candidate) => candidate.slug === theme.slug, $[2] = theme.slug, $[3] = t1);
|
|
1403
|
+
let index = themes.findIndex(t1), t2;
|
|
1404
|
+
$[4] !== index || $[5] !== send || $[6] !== themes ? (t2 = (to) => {
|
|
1405
|
+
let order = themes.map(_temp$1);
|
|
1406
|
+
order.splice(to, 0, ...order.splice(index, 1)), send({
|
|
1407
|
+
type: "theme.reorder",
|
|
1408
|
+
order
|
|
1409
|
+
});
|
|
1410
|
+
}, $[4] = index, $[5] = send, $[6] = themes, $[7] = t2) : t2 = $[7];
|
|
1411
|
+
let moveTo = t2, t3, t4;
|
|
1412
|
+
$[8] === Symbol.for("react.memo_cache_sentinel") ? (t3 = () => {
|
|
1413
|
+
requestAnimationFrame(() => {
|
|
1414
|
+
dragged.current = !1;
|
|
1415
|
+
});
|
|
1416
|
+
}, t4 = () => {
|
|
1417
|
+
dragged.current = !0;
|
|
1418
|
+
}, $[8] = t3, $[9] = t4) : (t3 = $[8], t4 = $[9]);
|
|
1419
|
+
let t5 = active ? scrollRefIntoViewIfNeeded : void 0, t6;
|
|
1420
|
+
$[10] === Symbol.for("react.memo_cache_sentinel") ? (t6 = { scale: 1.04 }, $[10] = t6) : t6 = $[10];
|
|
1421
|
+
let t7;
|
|
1422
|
+
$[11] !== send || $[12] !== theme.slug ? (t7 = () => {
|
|
1423
|
+
dragged.current || send({
|
|
1424
|
+
type: "theme.pick",
|
|
1425
|
+
slug: theme.slug
|
|
1426
|
+
});
|
|
1427
|
+
}, $[11] = send, $[12] = theme.slug, $[13] = t7) : t7 = $[13];
|
|
1428
|
+
let t8;
|
|
1429
|
+
$[14] === dragControls ? t8 = $[15] : (t8 = (event) => {
|
|
1430
|
+
event.pointerType !== "touch" && dragControls.start(event);
|
|
1431
|
+
}, $[14] = dragControls, $[15] = t8);
|
|
1432
|
+
let t9;
|
|
1433
|
+
$[16] === theme.options ? t9 = $[17] : (t9 = /* @__PURE__ */ jsx("span", {
|
|
1434
|
+
className: frame$1,
|
|
1435
|
+
children: /* @__PURE__ */ jsx(ThemeThumbnail, { options: theme.options })
|
|
1436
|
+
}), $[16] = theme.options, $[17] = t9);
|
|
1437
|
+
let t10 = active ? "medium" : "regular", t11;
|
|
1438
|
+
$[18] !== t10 || $[19] !== title ? (t11 = /* @__PURE__ */ jsx(Box, {
|
|
1439
|
+
as: "span",
|
|
1440
|
+
display: "block",
|
|
1441
|
+
paddingTop: 2,
|
|
1442
|
+
paddingX: 2,
|
|
1443
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1444
|
+
align: "center",
|
|
1445
|
+
as: "span",
|
|
1446
|
+
size: 1,
|
|
1447
|
+
textOverflow: "ellipsis",
|
|
1448
|
+
weight: t10,
|
|
1449
|
+
children: title
|
|
1450
|
+
})
|
|
1451
|
+
}), $[18] = t10, $[19] = title, $[20] = t11) : t11 = $[20];
|
|
1452
|
+
let t12;
|
|
1453
|
+
$[21] !== active || $[22] !== t11 || $[23] !== t7 || $[24] !== t8 || $[25] !== t9 ? (t12 = /* @__PURE__ */ jsxs("button", {
|
|
1454
|
+
"aria-pressed": active,
|
|
1455
|
+
className: pickButton,
|
|
1456
|
+
onClick: t7,
|
|
1457
|
+
onPointerDown: t8,
|
|
1458
|
+
type: "button",
|
|
1459
|
+
children: [t9, t11]
|
|
1460
|
+
}), $[21] = active, $[22] = t11, $[23] = t7, $[24] = t8, $[25] = t9, $[26] = t12) : t12 = $[26];
|
|
1461
|
+
let t13;
|
|
1462
|
+
$[27] === Symbol.for("react.memo_cache_sentinel") ? (t13 = /* @__PURE__ */ jsx(Text, {
|
|
1463
|
+
size: 1,
|
|
1464
|
+
children: "Show more"
|
|
1465
|
+
}), $[27] = t13) : t13 = $[27];
|
|
1466
|
+
let t14 = `Show more for ${title}`, t15;
|
|
1467
|
+
$[28] === t14 ? t15 = $[29] : (t15 = /* @__PURE__ */ jsx(Button, {
|
|
1468
|
+
"aria-label": t14,
|
|
1469
|
+
fontSize: 1,
|
|
1470
|
+
icon: EllipsisHorizontalIcon,
|
|
1471
|
+
mode: "ghost",
|
|
1472
|
+
padding: 1,
|
|
1473
|
+
radius: 2
|
|
1474
|
+
}), $[28] = t14, $[29] = t15);
|
|
1475
|
+
let t16 = `themer-theme-${theme.slug}`, t17 = index <= 0, t18;
|
|
1476
|
+
$[30] !== index || $[31] !== moveTo ? (t18 = () => moveTo(index - 1), $[30] = index, $[31] = moveTo, $[32] = t18) : t18 = $[32];
|
|
1477
|
+
let t19;
|
|
1478
|
+
$[33] !== t17 || $[34] !== t18 ? (t19 = /* @__PURE__ */ jsx(MenuItem, {
|
|
1479
|
+
disabled: t17,
|
|
1480
|
+
icon: ArrowUpIcon,
|
|
1481
|
+
onClick: t18,
|
|
1482
|
+
text: "Move up"
|
|
1483
|
+
}), $[33] = t17, $[34] = t18, $[35] = t19) : t19 = $[35];
|
|
1484
|
+
let t20 = index >= themes.length - 1, t21;
|
|
1485
|
+
$[36] !== index || $[37] !== moveTo ? (t21 = () => moveTo(index + 1), $[36] = index, $[37] = moveTo, $[38] = t21) : t21 = $[38];
|
|
1486
|
+
let t22;
|
|
1487
|
+
$[39] !== t20 || $[40] !== t21 ? (t22 = /* @__PURE__ */ jsx(MenuItem, {
|
|
1488
|
+
disabled: t20,
|
|
1489
|
+
icon: ArrowDownIcon,
|
|
1490
|
+
onClick: t21,
|
|
1491
|
+
text: "Move down"
|
|
1492
|
+
}), $[39] = t20, $[40] = t21, $[41] = t22) : t22 = $[41];
|
|
1493
|
+
let t23;
|
|
1494
|
+
$[42] === Symbol.for("react.memo_cache_sentinel") ? (t23 = /* @__PURE__ */ jsx(MenuDivider, {}), $[42] = t23) : t23 = $[42];
|
|
1495
|
+
let t24;
|
|
1496
|
+
$[43] !== send || $[44] !== theme.slug || $[45] !== theme.source ? (t24 = theme.source === "custom" && /* @__PURE__ */ jsx(MenuItem, {
|
|
1497
|
+
icon: EditIcon,
|
|
1498
|
+
onClick: () => send({
|
|
1499
|
+
type: "theme.edit",
|
|
1500
|
+
slug: theme.slug
|
|
1501
|
+
}),
|
|
1502
|
+
text: "Edit"
|
|
1503
|
+
}), $[43] = send, $[44] = theme.slug, $[45] = theme.source, $[46] = t24) : t24 = $[46];
|
|
1504
|
+
let t25;
|
|
1505
|
+
$[47] !== send || $[48] !== theme.slug ? (t25 = () => send({
|
|
1506
|
+
type: "theme.duplicate",
|
|
1507
|
+
slug: theme.slug
|
|
1508
|
+
}), $[47] = send, $[48] = theme.slug, $[49] = t25) : t25 = $[49];
|
|
1509
|
+
let t26 = theme.source === "custom" ? "Duplicate" : "Duplicate to edit", t27;
|
|
1510
|
+
$[50] !== t25 || $[51] !== t26 ? (t27 = /* @__PURE__ */ jsx(MenuItem, {
|
|
1511
|
+
icon: CopyIcon,
|
|
1512
|
+
onClick: t25,
|
|
1513
|
+
text: t26
|
|
1514
|
+
}), $[50] = t25, $[51] = t26, $[52] = t27) : t27 = $[52];
|
|
1515
|
+
let t28;
|
|
1516
|
+
$[53] !== copyTheme || $[54] !== theme ? (t28 = /* @__PURE__ */ jsx(MenuItem, {
|
|
1517
|
+
icon: ShareIcon,
|
|
1518
|
+
onClick: () => void copyTheme(theme),
|
|
1519
|
+
text: "Copy to share"
|
|
1520
|
+
}), $[53] = copyTheme, $[54] = theme, $[55] = t28) : t28 = $[55];
|
|
1521
|
+
let t29;
|
|
1522
|
+
$[56] !== send || $[57] !== theme.slug || $[58] !== theme.source ? (t29 = theme.source !== "config" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuDivider, {}), /* @__PURE__ */ jsx(MenuItem, {
|
|
1523
|
+
icon: TrashIcon,
|
|
1524
|
+
onClick: () => send({
|
|
1525
|
+
type: "theme.remove",
|
|
1526
|
+
slug: theme.slug
|
|
1527
|
+
}),
|
|
1528
|
+
text: "Remove",
|
|
1529
|
+
tone: "critical"
|
|
1530
|
+
})] }), $[56] = send, $[57] = theme.slug, $[58] = theme.source, $[59] = t29) : t29 = $[59];
|
|
1531
|
+
let t30;
|
|
1532
|
+
$[60] !== t19 || $[61] !== t22 || $[62] !== t24 || $[63] !== t27 || $[64] !== t28 || $[65] !== t29 ? (t30 = /* @__PURE__ */ jsxs(Menu, { children: [
|
|
1533
|
+
t19,
|
|
1534
|
+
t22,
|
|
1535
|
+
t23,
|
|
1536
|
+
t24,
|
|
1537
|
+
t27,
|
|
1538
|
+
t28,
|
|
1539
|
+
t29
|
|
1540
|
+
] }), $[60] = t19, $[61] = t22, $[62] = t24, $[63] = t27, $[64] = t28, $[65] = t29, $[66] = t30) : t30 = $[66];
|
|
1541
|
+
let t31, t32;
|
|
1542
|
+
$[67] === Symbol.for("react.memo_cache_sentinel") ? (t31 = () => setMenuOpen(!1), t32 = () => setMenuOpen(!0), $[67] = t31, $[68] = t32) : (t31 = $[67], t32 = $[68]);
|
|
1543
|
+
let t33;
|
|
1544
|
+
$[69] === scheme ? t33 = $[70] : (t33 = {
|
|
1545
|
+
animate: !0,
|
|
1546
|
+
placement: "bottom-end",
|
|
1547
|
+
portal: !0,
|
|
1548
|
+
scheme
|
|
1549
|
+
}, $[69] = scheme, $[70] = t33);
|
|
1550
|
+
let t34;
|
|
1551
|
+
$[71] !== t15 || $[72] !== t16 || $[73] !== t30 || $[74] !== t33 ? (t34 = /* @__PURE__ */ jsx(Tooltip, {
|
|
1552
|
+
animate: !0,
|
|
1553
|
+
content: t13,
|
|
1554
|
+
placement: "bottom",
|
|
1555
|
+
portal: !0,
|
|
1556
|
+
children: /* @__PURE__ */ jsx(Card, {
|
|
1557
|
+
className: menuCard,
|
|
1558
|
+
radius: 2,
|
|
1559
|
+
scheme: "dark",
|
|
1560
|
+
children: /* @__PURE__ */ jsx(MenuButton, {
|
|
1561
|
+
button: t15,
|
|
1562
|
+
id: t16,
|
|
1563
|
+
menu: t30,
|
|
1564
|
+
onClose: t31,
|
|
1565
|
+
onOpen: t32,
|
|
1566
|
+
popover: t33
|
|
1567
|
+
})
|
|
1568
|
+
})
|
|
1569
|
+
}), $[71] = t15, $[72] = t16, $[73] = t30, $[74] = t33, $[75] = t34) : t34 = $[75];
|
|
1570
|
+
let t35;
|
|
1571
|
+
$[76] !== menuOpen || $[77] !== t34 ? (t35 = /* @__PURE__ */ jsx("div", {
|
|
1572
|
+
className: menuSlot,
|
|
1573
|
+
"data-visible": menuOpen,
|
|
1574
|
+
children: t34
|
|
1575
|
+
}), $[76] = menuOpen, $[77] = t34, $[78] = t35) : t35 = $[78];
|
|
1576
|
+
let t36;
|
|
1577
|
+
return $[79] !== dragControls || $[80] !== t12 || $[81] !== t35 || $[82] !== t5 || $[83] !== theme.slug ? (t36 = /* @__PURE__ */ jsxs(Reorder.Item, {
|
|
1578
|
+
as: "div",
|
|
1579
|
+
className: root,
|
|
1580
|
+
dragControls,
|
|
1581
|
+
dragListener: !1,
|
|
1582
|
+
onDragEnd: t3,
|
|
1583
|
+
onDragStart: t4,
|
|
1584
|
+
ref: t5,
|
|
1585
|
+
value: theme.slug,
|
|
1586
|
+
whileDrag: t6,
|
|
1587
|
+
children: [t12, t35]
|
|
1588
|
+
}), $[79] = dragControls, $[80] = t12, $[81] = t35, $[82] = t5, $[83] = theme.slug, $[84] = t36) : t36 = $[84], t36;
|
|
1589
|
+
}
|
|
1590
|
+
function _temp$1(candidate_0) {
|
|
1591
|
+
return candidate_0.slug;
|
|
1592
|
+
}
|
|
1593
|
+
var cardGrid = "twjqgh0";
|
|
1594
|
+
/**
|
|
1595
|
+
* One column at the sidebar's default width; wider sidebars — and the
|
|
1596
|
+
* overlay on small screens — fit more cards per row
|
|
1597
|
+
*/
|
|
1598
|
+
/**
|
|
1599
|
+
* The flow for picking a theme: a grid of theme cards — the configured theme,
|
|
1600
|
+
* the presets and the user's own themes — that drag into the order the user
|
|
1601
|
+
* wants, with the entry points to the add and restore flows below. A theme
|
|
1602
|
+
* code someone shared pastes right into the list, or through the paste button.
|
|
1603
|
+
*
|
|
1604
|
+
* @internal
|
|
1605
|
+
*/
|
|
1606
|
+
function ThemeList() {
|
|
1607
|
+
let $ = c(38), { themes, removed, active, send } = useThemer(), { addThemeFromClipboard } = useThemeCodes(), [pasting, setPasting] = useState(!1);
|
|
1608
|
+
usePasteThemeCodes();
|
|
1609
|
+
let t0;
|
|
1610
|
+
$[0] === send ? t0 = $[1] : (t0 = (palette, file) => send({
|
|
1611
|
+
type: "theme.add",
|
|
1612
|
+
title: titleFromFileName(file.name),
|
|
1613
|
+
options: optionsFromImagePalette(palette),
|
|
1614
|
+
palette,
|
|
1615
|
+
imageUrl: URL.createObjectURL(file)
|
|
1616
|
+
}), $[0] = send, $[1] = t0);
|
|
1617
|
+
let { busy, pickImage } = useImagePalette(t0), t1;
|
|
1618
|
+
$[2] === send ? t1 = $[3] : (t1 = (order) => send({
|
|
1619
|
+
type: "theme.reorder",
|
|
1620
|
+
order
|
|
1621
|
+
}), $[2] = send, $[3] = t1);
|
|
1622
|
+
let t2;
|
|
1623
|
+
$[4] === themes ? t2 = $[5] : (t2 = themes.map(_temp), $[4] = themes, $[5] = t2);
|
|
1624
|
+
let t3;
|
|
1625
|
+
if ($[6] !== active || $[7] !== themes) {
|
|
1626
|
+
let t4;
|
|
1627
|
+
$[9] === active ? t4 = $[10] : (t4 = (theme_0) => /* @__PURE__ */ jsx(ThemeCard, {
|
|
1628
|
+
active: theme_0.slug === active.slug,
|
|
1629
|
+
theme: theme_0
|
|
1630
|
+
}, theme_0.slug), $[9] = active, $[10] = t4), t3 = themes.map(t4), $[6] = active, $[7] = themes, $[8] = t3;
|
|
1631
|
+
} else t3 = $[8];
|
|
1632
|
+
let t4;
|
|
1633
|
+
$[11] !== t1 || $[12] !== t2 || $[13] !== t3 ? (t4 = /* @__PURE__ */ jsx(MotionConfig, {
|
|
1634
|
+
reducedMotion: "user",
|
|
1635
|
+
children: /* @__PURE__ */ jsx(Reorder.Group, {
|
|
1636
|
+
as: "div",
|
|
1637
|
+
className: cardGrid,
|
|
1638
|
+
onReorder: t1,
|
|
1639
|
+
values: t2,
|
|
1640
|
+
children: t3
|
|
1641
|
+
})
|
|
1642
|
+
}), $[11] = t1, $[12] = t2, $[13] = t3, $[14] = t4) : t4 = $[14];
|
|
1643
|
+
let t5;
|
|
1644
|
+
$[15] !== removed.length || $[16] !== send ? (t5 = removed.length > 0 && /* @__PURE__ */ jsx(Button, {
|
|
1645
|
+
gap: 2,
|
|
1646
|
+
icon: RestoreIcon,
|
|
1647
|
+
mode: "bleed",
|
|
1648
|
+
onClick: () => send({ type: "flow.removed" }),
|
|
1649
|
+
padding: 2,
|
|
1650
|
+
text: `Show removed (${removed.length})`,
|
|
1651
|
+
width: "fill"
|
|
1652
|
+
}), $[15] = removed.length, $[16] = send, $[17] = t5) : t5 = $[17];
|
|
1653
|
+
let t6;
|
|
1654
|
+
$[18] !== t4 || $[19] !== t5 ? (t6 = /* @__PURE__ */ jsx(ScrollArea, {
|
|
1655
|
+
padding: 3,
|
|
1656
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1657
|
+
gap: 4,
|
|
1658
|
+
children: [t4, t5]
|
|
1659
|
+
})
|
|
1660
|
+
}), $[18] = t4, $[19] = t5, $[20] = t6) : t6 = $[20];
|
|
1661
|
+
let t7;
|
|
1662
|
+
$[21] === send ? t7 = $[22] : (t7 = /* @__PURE__ */ jsx(Box, {
|
|
1663
|
+
flex: 1,
|
|
1664
|
+
children: /* @__PURE__ */ jsx(TooltipButton, {
|
|
1665
|
+
icon: AddIcon,
|
|
1666
|
+
mode: "ghost",
|
|
1667
|
+
onClick: () => send({ type: "theme.add" }),
|
|
1668
|
+
text: "Add theme",
|
|
1669
|
+
tooltip: "Add a theme based on the applied one",
|
|
1670
|
+
width: "fill"
|
|
1671
|
+
})
|
|
1672
|
+
}), $[21] = send, $[22] = t7);
|
|
1673
|
+
let t8;
|
|
1674
|
+
$[23] !== busy || $[24] !== pickImage ? (t8 = /* @__PURE__ */ jsx(ImageFileButton, {
|
|
1675
|
+
loading: busy,
|
|
1676
|
+
mode: "ghost",
|
|
1677
|
+
onFile: pickImage,
|
|
1678
|
+
tooltip: "Add a theme from the colors of an image"
|
|
1679
|
+
}), $[23] = busy, $[24] = pickImage, $[25] = t8) : t8 = $[25];
|
|
1680
|
+
let t9;
|
|
1681
|
+
$[26] === addThemeFromClipboard ? t9 = $[27] : (t9 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
1682
|
+
icon: ClipboardIcon,
|
|
1683
|
+
mode: "ghost",
|
|
1684
|
+
onClick: async () => {
|
|
1685
|
+
await addThemeFromClipboard() !== "added" && setPasting(!0);
|
|
1686
|
+
},
|
|
1687
|
+
tooltip: "Add a theme from a code someone shared"
|
|
1688
|
+
}), $[26] = addThemeFromClipboard, $[27] = t9);
|
|
1689
|
+
let t10;
|
|
1690
|
+
$[28] !== t7 || $[29] !== t8 || $[30] !== t9 ? (t10 = /* @__PURE__ */ jsx(Card, {
|
|
1691
|
+
borderTop: !0,
|
|
1692
|
+
padding: 3,
|
|
1693
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1694
|
+
gap: 2,
|
|
1695
|
+
children: [
|
|
1696
|
+
t7,
|
|
1697
|
+
t8,
|
|
1698
|
+
t9
|
|
1699
|
+
]
|
|
1700
|
+
})
|
|
1701
|
+
}), $[28] = t7, $[29] = t8, $[30] = t9, $[31] = t10) : t10 = $[31];
|
|
1702
|
+
let t11;
|
|
1703
|
+
$[32] === pasting ? t11 = $[33] : (t11 = pasting && /* @__PURE__ */ jsx(PasteThemeDialog, { onClose: () => setPasting(!1) }), $[32] = pasting, $[33] = t11);
|
|
1704
|
+
let t12;
|
|
1705
|
+
return $[34] !== t10 || $[35] !== t11 || $[36] !== t6 ? (t12 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1706
|
+
t6,
|
|
1707
|
+
t10,
|
|
1708
|
+
t11
|
|
1709
|
+
] }), $[34] = t10, $[35] = t11, $[36] = t6, $[37] = t12) : t12 = $[37], t12;
|
|
1710
|
+
}
|
|
1711
|
+
function _temp(theme) {
|
|
1712
|
+
return theme.slug;
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Serializes theme options into the `buildTheme` call to paste into
|
|
1716
|
+
* `sanity.config.ts`, keeping only what differs from the derived defaults in
|
|
1717
|
+
* each scheme.
|
|
1718
|
+
*
|
|
1719
|
+
* Options that boil down to the stock Studio theme need nothing from this
|
|
1720
|
+
* package — so they serialize to a bare `buildTheme()` from `@sanity/ui/theme`
|
|
1721
|
+
* instead.
|
|
1722
|
+
*
|
|
1723
|
+
* @internal
|
|
1724
|
+
*/
|
|
1725
|
+
function createThemeSnippet(options) {
|
|
1726
|
+
let minimized = minimizeOptions(options);
|
|
1727
|
+
if (minimized === null) return "import {buildTheme} from '@sanity/ui/theme'\n\nexport const theme = buildTheme()\n";
|
|
1728
|
+
let lines = [];
|
|
1729
|
+
for (let scheme of SCHEMES) {
|
|
1730
|
+
let values = minimized[scheme];
|
|
1731
|
+
values && lines.push(serializeScheme(scheme, values));
|
|
1732
|
+
}
|
|
1733
|
+
return `import {buildTheme} from '@sanity/themer'\n\nexport const theme = buildTheme({\n${lines.join("\n")}\n})\n`;
|
|
1734
|
+
}
|
|
1735
|
+
/** A scheme with up to two options fits on one line, more spread out */
|
|
1736
|
+
function serializeScheme(scheme, values) {
|
|
1737
|
+
let entries = [];
|
|
1738
|
+
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 },`;
|
|
1739
|
+
}
|
|
1740
|
+
registerLanguage(typescript);
|
|
1741
|
+
/**
|
|
1742
|
+
* Shows the `buildTheme` snippet that makes a theme permanent, in a dialog so
|
|
1743
|
+
* that it does not take up sidebar space or make the sidebar scroll as the
|
|
1744
|
+
* snippet changes shape with the theme.
|
|
1745
|
+
*
|
|
1746
|
+
* @internal
|
|
1747
|
+
*/
|
|
1748
|
+
function ThemeSnippetDialog(props) {
|
|
1749
|
+
let $ = c(23), { onClose, theme } = props, toast = useToast(), t0;
|
|
1750
|
+
$[0] === theme.options ? t0 = $[1] : (t0 = createThemeSnippet(theme.options), $[0] = theme.options, $[1] = t0);
|
|
1751
|
+
let snippet = t0, t1;
|
|
1752
|
+
$[2] !== snippet || $[3] !== toast ? (t1 = async () => {
|
|
1753
|
+
try {
|
|
1754
|
+
await navigator.clipboard.writeText(snippet), toast.push({
|
|
1755
|
+
status: "success",
|
|
1756
|
+
title: "Copied the theme to the clipboard"
|
|
1757
|
+
});
|
|
1758
|
+
} catch {
|
|
1759
|
+
toast.push({
|
|
1760
|
+
status: "error",
|
|
1761
|
+
title: "Could not copy the theme"
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
}, $[2] = snippet, $[3] = toast, $[4] = t1) : t1 = $[4];
|
|
1765
|
+
let handleCopy = t1, t2;
|
|
1766
|
+
$[5] === handleCopy ? t2 = $[6] : (t2 = /* @__PURE__ */ jsx(Flex, {
|
|
1767
|
+
gap: 2,
|
|
1768
|
+
justify: "flex-end",
|
|
1769
|
+
padding: 3,
|
|
1770
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
1771
|
+
gap: 2,
|
|
1772
|
+
icon: ClipboardIcon,
|
|
1773
|
+
mode: "ghost",
|
|
1774
|
+
onClick: () => void handleCopy(),
|
|
1775
|
+
padding: 2,
|
|
1776
|
+
text: "Copy"
|
|
1777
|
+
})
|
|
1778
|
+
}), $[5] = handleCopy, $[6] = t2);
|
|
1779
|
+
let t3;
|
|
1780
|
+
$[7] === Symbol.for("react.memo_cache_sentinel") ? (t3 = /* @__PURE__ */ jsx("code", { children: "sanity.config.ts" }), $[7] = t3) : t3 = $[7];
|
|
1781
|
+
let t4;
|
|
1782
|
+
$[8] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx("code", { children: "theme" }), $[8] = t4) : t4 = $[8];
|
|
1783
|
+
let t5;
|
|
1784
|
+
$[9] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsx("code", { children: "defineConfig" }), $[9] = t5) : t5 = $[9];
|
|
1785
|
+
let t6;
|
|
1786
|
+
$[10] === theme.title ? t6 = $[11] : (t6 = displayTitle(theme.title), $[10] = theme.title, $[11] = t6);
|
|
1787
|
+
let t7;
|
|
1788
|
+
$[12] === t6 ? t7 = $[13] : (t7 = /* @__PURE__ */ jsxs(Text, {
|
|
1789
|
+
muted: !0,
|
|
1790
|
+
size: 1,
|
|
1791
|
+
children: [
|
|
1792
|
+
"Export this from ",
|
|
1793
|
+
t3,
|
|
1794
|
+
" and pass it as the ",
|
|
1795
|
+
t4,
|
|
1796
|
+
" of",
|
|
1797
|
+
" ",
|
|
1798
|
+
t5,
|
|
1799
|
+
" to make “",
|
|
1800
|
+
t6,
|
|
1801
|
+
"” the Studio theme without this tool."
|
|
1802
|
+
]
|
|
1803
|
+
}), $[12] = t6, $[13] = t7);
|
|
1804
|
+
let t8;
|
|
1805
|
+
$[14] === snippet ? t8 = $[15] : (t8 = /* @__PURE__ */ jsx(Card, {
|
|
1806
|
+
border: !0,
|
|
1807
|
+
overflow: "auto",
|
|
1808
|
+
padding: 3,
|
|
1809
|
+
radius: 2,
|
|
1810
|
+
tone: "transparent",
|
|
1811
|
+
children: /* @__PURE__ */ jsx(Code, {
|
|
1812
|
+
language: "ts",
|
|
1813
|
+
size: 1,
|
|
1814
|
+
children: snippet
|
|
1815
|
+
})
|
|
1816
|
+
}), $[14] = snippet, $[15] = t8);
|
|
1817
|
+
let t9;
|
|
1818
|
+
$[16] !== t7 || $[17] !== t8 ? (t9 = /* @__PURE__ */ jsx(Box, {
|
|
1819
|
+
padding: 4,
|
|
1820
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1821
|
+
gap: 4,
|
|
1822
|
+
children: [t7, t8]
|
|
1823
|
+
})
|
|
1824
|
+
}), $[16] = t7, $[17] = t8, $[18] = t9) : t9 = $[18];
|
|
1825
|
+
let t10;
|
|
1826
|
+
return $[19] !== onClose || $[20] !== t2 || $[21] !== t9 ? (t10 = /* @__PURE__ */ jsx(Dialog, {
|
|
1827
|
+
animate: !0,
|
|
1828
|
+
footer: t2,
|
|
1829
|
+
header: "Add to your config",
|
|
1830
|
+
id: "themer-snippet",
|
|
1831
|
+
onClickOutside: onClose,
|
|
1832
|
+
onClose,
|
|
1833
|
+
width: 1,
|
|
1834
|
+
children: t9
|
|
1835
|
+
}), $[19] = onClose, $[20] = t2, $[21] = t9, $[22] = t10) : t10 = $[22], t10;
|
|
1836
|
+
}
|
|
1837
|
+
var title = "c2pqej0";
|
|
1838
|
+
const VIEW_TITLES = {
|
|
1839
|
+
list: "Themer",
|
|
1840
|
+
edit: "Edit theme",
|
|
1841
|
+
removed: "Removed themes"
|
|
1842
|
+
};
|
|
1843
|
+
/**
|
|
1844
|
+
* The themer sidebar: a header that navigates between the flows and toggles
|
|
1845
|
+
* the split preview, the flow itself — picking a theme, editing one, or
|
|
1846
|
+
* restoring removed ones — and the dialog with the `buildTheme` snippet of
|
|
1847
|
+
* the applied theme.
|
|
1848
|
+
*
|
|
1849
|
+
* @internal
|
|
1850
|
+
*/
|
|
1851
|
+
function ThemerSidebar() {
|
|
1852
|
+
let $ = c(42), { active, split, view, navbarHeight, send } = useThemer(), [snippetOpen, setSnippetOpen] = useState(!1), inList = view.name === "list", t0;
|
|
1853
|
+
$[0] === navbarHeight ? t0 = $[1] : (t0 = navbarHeight === null ? void 0 : { height: navbarHeight }, $[0] = navbarHeight, $[1] = t0);
|
|
1854
|
+
let t1;
|
|
1855
|
+
$[2] !== inList || $[3] !== send ? (t1 = !inList && /* @__PURE__ */ jsx(TooltipButton, {
|
|
1856
|
+
icon: ArrowLeftIcon,
|
|
1857
|
+
mode: "bleed",
|
|
1858
|
+
onClick: () => send({ type: "flow.list" }),
|
|
1859
|
+
padding: 2,
|
|
1860
|
+
tooltip: "Back to the themes"
|
|
1861
|
+
}), $[2] = inList, $[3] = send, $[4] = t1) : t1 = $[4];
|
|
1862
|
+
let t2 = VIEW_TITLES[view.name], t3;
|
|
1863
|
+
$[5] === t2 ? t3 = $[6] : (t3 = /* @__PURE__ */ jsx(Box, {
|
|
1864
|
+
className: title,
|
|
1865
|
+
flex: 1,
|
|
1866
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1867
|
+
size: 1,
|
|
1868
|
+
textOverflow: "ellipsis",
|
|
1869
|
+
weight: "semibold",
|
|
1870
|
+
children: t2
|
|
1871
|
+
})
|
|
1872
|
+
}), $[5] = t2, $[6] = t3);
|
|
1873
|
+
let t4;
|
|
1874
|
+
$[7] !== send || $[8] !== split || $[9] !== view.name ? (t4 = view.name !== "removed" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(TooltipButton, {
|
|
1875
|
+
"aria-pressed": split,
|
|
1876
|
+
icon: SplitVerticalIcon,
|
|
1877
|
+
mode: "bleed",
|
|
1878
|
+
onClick: () => send({ type: "preview.toggle" }),
|
|
1879
|
+
padding: 2,
|
|
1880
|
+
selected: split,
|
|
1881
|
+
tooltip: "Show light and dark side by side"
|
|
1882
|
+
}), /* @__PURE__ */ jsx(TooltipButton, {
|
|
1883
|
+
icon: CodeBlockIcon,
|
|
1884
|
+
mode: "bleed",
|
|
1885
|
+
onClick: () => setSnippetOpen(!0),
|
|
1886
|
+
padding: 2,
|
|
1887
|
+
tooltip: "Show the code for the applied theme"
|
|
1888
|
+
})] }), $[7] = send, $[8] = split, $[9] = view.name, $[10] = t4) : t4 = $[10];
|
|
1889
|
+
let t5;
|
|
1890
|
+
$[11] === send ? t5 = $[12] : (t5 = /* @__PURE__ */ jsx(TooltipButton, {
|
|
1891
|
+
icon: CloseIcon,
|
|
1892
|
+
mode: "bleed",
|
|
1893
|
+
onClick: () => send({ type: "sidebar.close" }),
|
|
1894
|
+
padding: 2,
|
|
1895
|
+
tooltip: "Close themer"
|
|
1896
|
+
}), $[11] = send, $[12] = t5);
|
|
1897
|
+
let t6;
|
|
1898
|
+
$[13] !== t4 || $[14] !== t5 ? (t6 = /* @__PURE__ */ jsxs(Flex, { children: [t4, t5] }), $[13] = t4, $[14] = t5, $[15] = t6) : t6 = $[15];
|
|
1899
|
+
let t7;
|
|
1900
|
+
$[16] !== t1 || $[17] !== t3 || $[18] !== t6 ? (t7 = /* @__PURE__ */ jsxs(Flex, {
|
|
1901
|
+
align: "center",
|
|
1902
|
+
gap: 1,
|
|
1903
|
+
height: "fill",
|
|
1904
|
+
children: [
|
|
1905
|
+
t1,
|
|
1906
|
+
t3,
|
|
1907
|
+
t6
|
|
1908
|
+
]
|
|
1909
|
+
}), $[16] = t1, $[17] = t3, $[18] = t6, $[19] = t7) : t7 = $[19];
|
|
1910
|
+
let t8;
|
|
1911
|
+
$[20] !== t0 || $[21] !== t7 ? (t8 = /* @__PURE__ */ jsx(Card, {
|
|
1912
|
+
borderBottom: !0,
|
|
1913
|
+
padding: 3,
|
|
1914
|
+
sizing: "border",
|
|
1915
|
+
style: t0,
|
|
1916
|
+
children: t7
|
|
1917
|
+
}), $[20] = t0, $[21] = t7, $[22] = t8) : t8 = $[22];
|
|
1918
|
+
let t9;
|
|
1919
|
+
$[23] === view.name ? t9 = $[24] : (t9 = view.name === "list" && /* @__PURE__ */ jsx(ThemeList, {}), $[23] = view.name, $[24] = t9);
|
|
1920
|
+
let t10;
|
|
1921
|
+
$[25] !== view.focusTitle || $[26] !== view.name || $[27] !== view.slug ? (t10 = view.name === "edit" && /* @__PURE__ */ jsx(ThemeEditor, {
|
|
1922
|
+
focusTitle: view.focusTitle,
|
|
1923
|
+
slug: view.slug
|
|
1924
|
+
}), $[25] = view.focusTitle, $[26] = view.name, $[27] = view.slug, $[28] = t10) : t10 = $[28];
|
|
1925
|
+
let t11;
|
|
1926
|
+
$[29] === view.name ? t11 = $[30] : (t11 = view.name === "removed" && /* @__PURE__ */ jsx(RemovedThemes, {}), $[29] = view.name, $[30] = t11);
|
|
1927
|
+
let t12;
|
|
1928
|
+
$[31] !== t10 || $[32] !== t11 || $[33] !== t8 || $[34] !== t9 ? (t12 = /* @__PURE__ */ jsxs(Flex, {
|
|
1929
|
+
direction: "column",
|
|
1930
|
+
height: "fill",
|
|
1931
|
+
children: [
|
|
1932
|
+
t8,
|
|
1933
|
+
t9,
|
|
1934
|
+
t10,
|
|
1935
|
+
t11
|
|
1936
|
+
]
|
|
1937
|
+
}), $[31] = t10, $[32] = t11, $[33] = t8, $[34] = t9, $[35] = t12) : t12 = $[35];
|
|
1938
|
+
let t13;
|
|
1939
|
+
$[36] !== active || $[37] !== snippetOpen ? (t13 = snippetOpen && /* @__PURE__ */ jsx(ThemeSnippetDialog, {
|
|
1940
|
+
onClose: () => setSnippetOpen(!1),
|
|
1941
|
+
theme: active
|
|
1942
|
+
}), $[36] = active, $[37] = snippetOpen, $[38] = t13) : t13 = $[38];
|
|
1943
|
+
let t14;
|
|
1944
|
+
return $[39] !== t12 || $[40] !== t13 ? (t14 = /* @__PURE__ */ jsxs(Card, {
|
|
1945
|
+
height: "fill",
|
|
1946
|
+
children: [t12, t13]
|
|
1947
|
+
}), $[39] = t12, $[40] = t13, $[41] = t14) : t14 = $[41], t14;
|
|
1948
|
+
}
|
|
1949
|
+
var content = "bgn4np4", frame = "bgn4np3", sidebar = "bgn4np2";
|
|
1950
|
+
/** How far one arrow key press resizes the sidebar */
|
|
1951
|
+
const WIDTH_STORAGE_KEY = "sanityStudio:themer:width";
|
|
1952
|
+
function clampWidth(width) {
|
|
1953
|
+
return Math.min(400, Math.max(200, Math.round(width)));
|
|
1954
|
+
}
|
|
1955
|
+
function readStoredWidth() {
|
|
1956
|
+
try {
|
|
1957
|
+
let stored = Number(localStorage.getItem(WIDTH_STORAGE_KEY));
|
|
1958
|
+
return Number.isFinite(stored) && stored > 0 ? clampWidth(stored) : 200;
|
|
1959
|
+
} catch {
|
|
1960
|
+
return 200;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
function writeStoredWidth(width) {
|
|
1964
|
+
try {
|
|
1965
|
+
width === 200 ? localStorage.removeItem(WIDTH_STORAGE_KEY) : localStorage.setItem(WIDTH_STORAGE_KEY, String(width));
|
|
1966
|
+
} catch {}
|
|
1967
|
+
}
|
|
1968
|
+
/**
|
|
1969
|
+
* The themer sidebar, in a layer along the right edge of the Studio. Its left
|
|
1970
|
+
* edge drags (or arrow-keys) it wider, up to twice its default width — the
|
|
1971
|
+
* width sticks between sessions. As an overlay (small screens) it covers the
|
|
1972
|
+
* Studio edge to edge instead, with nothing to resize.
|
|
1973
|
+
*
|
|
1974
|
+
* @internal
|
|
1975
|
+
*/
|
|
1976
|
+
function ResizableSidebar(props) {
|
|
1977
|
+
let $ = c(24), { overlay } = props, [width, setWidth] = useState(readStoredWidth), [dragging, setDragging] = useState(!1), drag = useRef(null), t0, t1;
|
|
1978
|
+
$[0] === width ? (t0 = $[1], t1 = $[2]) : (t0 = () => writeStoredWidth(width), t1 = [width], $[0] = width, $[1] = t0, $[2] = t1), useEffect(t0, t1);
|
|
1979
|
+
let t2;
|
|
1980
|
+
$[3] === width ? t2 = $[4] : (t2 = (event) => {
|
|
1981
|
+
event.button === 0 && (event.preventDefault(), event.currentTarget.setPointerCapture(event.pointerId), drag.current = {
|
|
1982
|
+
pointerId: event.pointerId,
|
|
1983
|
+
startX: event.clientX,
|
|
1984
|
+
startWidth: width
|
|
1985
|
+
}, setDragging(!0));
|
|
1986
|
+
}, $[3] = width, $[4] = t2);
|
|
1987
|
+
let handlePointerDown = t2, t3;
|
|
1988
|
+
$[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = (event_0) => {
|
|
1989
|
+
drag.current && drag.current.pointerId === event_0.pointerId && setWidth(clampWidth(drag.current.startWidth - (event_0.clientX - drag.current.startX)));
|
|
1990
|
+
}, $[5] = t3) : t3 = $[5];
|
|
1991
|
+
let handlePointerMove = t3, t4;
|
|
1992
|
+
$[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = (event_1) => {
|
|
1993
|
+
drag.current && drag.current.pointerId === event_1.pointerId && (drag.current = null, setDragging(!1));
|
|
1994
|
+
}, $[6] = t4) : t4 = $[6];
|
|
1995
|
+
let handlePointerUp = t4, t5;
|
|
1996
|
+
$[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = (event_2) => {
|
|
1997
|
+
let step = {
|
|
1998
|
+
ArrowLeft: 16,
|
|
1999
|
+
ArrowRight: -16,
|
|
2000
|
+
Home: 400,
|
|
2001
|
+
End: -400
|
|
2002
|
+
}[event_2.key];
|
|
2003
|
+
step !== void 0 && (event_2.preventDefault(), setWidth((current) => clampWidth(current + step)));
|
|
2004
|
+
}, $[7] = t5) : t5 = $[7];
|
|
2005
|
+
let handleKeyDown = t5, t6;
|
|
2006
|
+
$[8] !== overlay || $[9] !== width ? (t6 = overlay ? void 0 : { width }, $[8] = overlay, $[9] = width, $[10] = t6) : t6 = $[10];
|
|
2007
|
+
let t7 = !overlay, t8;
|
|
2008
|
+
$[11] !== dragging || $[12] !== handlePointerDown || $[13] !== overlay || $[14] !== width ? (t8 = !overlay && /* @__PURE__ */ jsx("div", {
|
|
2009
|
+
"aria-label": "Resize the themer",
|
|
2010
|
+
className: "bgn4np5",
|
|
2011
|
+
"aria-orientation": "vertical",
|
|
2012
|
+
"aria-valuemax": 400,
|
|
2013
|
+
"aria-valuemin": 200,
|
|
2014
|
+
"aria-valuenow": width,
|
|
2015
|
+
"data-dragging": dragging,
|
|
2016
|
+
onDoubleClick: () => setWidth(200),
|
|
2017
|
+
onKeyDown: handleKeyDown,
|
|
2018
|
+
onPointerCancel: handlePointerUp,
|
|
2019
|
+
onPointerDown: handlePointerDown,
|
|
2020
|
+
onPointerMove: handlePointerMove,
|
|
2021
|
+
onPointerUp: handlePointerUp,
|
|
2022
|
+
role: "separator",
|
|
2023
|
+
tabIndex: 0
|
|
2024
|
+
}), $[11] = dragging, $[12] = handlePointerDown, $[13] = overlay, $[14] = width, $[15] = t8) : t8 = $[15];
|
|
2025
|
+
let t9;
|
|
2026
|
+
$[16] === Symbol.for("react.memo_cache_sentinel") ? (t9 = /* @__PURE__ */ jsx(Box, {
|
|
2027
|
+
className: content,
|
|
2028
|
+
height: "fill",
|
|
2029
|
+
overflow: "hidden",
|
|
2030
|
+
children: /* @__PURE__ */ jsx(ThemerSidebar, {})
|
|
2031
|
+
}), $[16] = t9) : t9 = $[16];
|
|
2032
|
+
let t10;
|
|
2033
|
+
$[17] !== t7 || $[18] !== t8 ? (t10 = /* @__PURE__ */ jsxs(Card, {
|
|
2034
|
+
borderLeft: t7,
|
|
2035
|
+
className: frame,
|
|
2036
|
+
height: "fill",
|
|
2037
|
+
children: [t8, t9]
|
|
2038
|
+
}), $[17] = t7, $[18] = t8, $[19] = t10) : t10 = $[19];
|
|
2039
|
+
let t11;
|
|
2040
|
+
return $[20] !== overlay || $[21] !== t10 || $[22] !== t6 ? (t11 = /* @__PURE__ */ jsx(Layer, {
|
|
2041
|
+
className: sidebar,
|
|
2042
|
+
"data-overlay": overlay,
|
|
2043
|
+
style: t6,
|
|
2044
|
+
zOffset: 100,
|
|
2045
|
+
children: t10
|
|
2046
|
+
}), $[20] = overlay, $[21] = t10, $[22] = t6, $[23] = t11) : t11 = $[23], t11;
|
|
2047
|
+
}
|
|
2048
|
+
export { ResizableSidebar as default };
|
|
2049
|
+
|
|
2050
|
+
//# sourceMappingURL=ResizableSidebar-DD787kQr.js.map
|