@sanity/themer 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -19
- package/dist/AnimatedColorWheelIcon-CwWOVAsw.js +171 -0
- package/dist/AnimatedColorWheelIcon-CwWOVAsw.js.map +1 -0
- package/dist/{ResizableSidebar-DD787kQr.js → ResizableSidebar-C1nr3Ls2.js} +1023 -547
- package/dist/ResizableSidebar-C1nr3Ls2.js.map +1 -0
- package/dist/bundle.css +106 -318
- package/dist/index.d.ts +66 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/themes-au1BLKmY.js +139 -0
- package/dist/themes-au1BLKmY.js.map +1 -0
- package/dist/tool.d.ts +3 -14
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js +853 -820
- package/dist/tool.js.map +1 -1
- package/package.json +11 -3
- package/dist/ResizableSidebar-DD787kQr.js.map +0 -1
- package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js +0 -422
- package/dist/ResizableSidebar.css.ts.vanilla-M9EuPu-q.js.map +0 -1
- package/dist/options-CU-emn_p.d.ts +0 -69
- package/dist/options-CU-emn_p.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ResizableSidebar-DD787kQr.js","names":["root","() => lastGutter","() => {\n const element = ref.current\n\n if (!element) return undefined\n\n // The reserved gutter is the part of the box the content cannot use\n const measure = () => {\n lastGutter = element.offsetWidth - element.clientWidth\n setGutter(lastGutter)\n }\n\n measure()\n\n const observer = new ResizeObserver(measure)\n\n observer.observe(element)\n\n return () => observer.disconnect()\n }","[]","{\n left: space[padding],\n right: Math.max(0, space[padding] - gutter),\n bottom: space[padding],\n }","space[padding]","Math.max(0, space[padding] - gutter)","useMemo<ScrollAreaInset>(\n () => ({\n left: space[padding],\n right: Math.max(0, space[padding] - gutter),\n bottom: space[padding],\n }),\n [gutter, padding, space],\n )","{paddingRight: inset.right}","right","<ScrollAreaInsetContext.Provider value={inset}>{children}</ScrollAreaInsetContext.Provider>","ScrollAreaInsetContext.Provider","<Box\n className={root}\n flex={1}\n overflow=\"auto\"\n padding={padding}\n ref={ref}\n style={{paddingRight: inset.right}}\n >\n <ScrollAreaInsetContext.Provider value={inset}>{children}</ScrollAreaInsetContext.Provider>\n </Box>","{marginLeft: -left, marginRight: -right, marginBottom: -bottom}","-left","-right","-bottom","<div style={{marginLeft: -left, marginRight: -right, marginBottom: -bottom}}>\n {props.children}\n </div>","children","_c","_temp","root","root","buildTheme(options)","useMemo(() => buildTheme(options), [options])","<MockStudio scheme=\"light\" />","<ThemeProvider scheme=\"light\" theme={theme} tone=\"default\">\n <MockStudio scheme=\"light\" />\n </ThemeProvider>","<MockStudio scheme=\"dark\" />","<ThemeProvider scheme=\"dark\" theme={theme} tone=\"default\">\n <MockStudio scheme=\"dark\" />\n </ThemeProvider>","<div aria-hidden className={root}>\n <ThemeProvider scheme=\"light\" theme={theme} tone=\"default\">\n <MockStudio scheme=\"light\" />\n </ThemeProvider>\n <ThemeProvider scheme=\"dark\" theme={theme} tone=\"default\">\n <MockStudio scheme=\"dark\" />\n </ThemeProvider>\n </div>","assignInlineVars({\n [colors.bg]: color.bg,\n [colors.fg]: color.fg,\n [colors.mutedFg]: color.muted.fg,\n [colors.border]: color.border,\n [colors.accent]: color.button.default.primary.enabled.bg,\n [colors.avatar]: color.avatar.blue.bg,\n [colors.selectedBg]: selected.bg,\n [colors.selectedFg]: selected.fg,\n [colors.inputBg]: inputColor.bg,\n [colors.inputBorder]: inputColor.border,\n })","bg","border","fg","<div className={logo} />","<div className={navbar}>\n <div className={logo} />\n <div className={line.fg} style={{width: '22%'}} />\n <div className={spacer} />\n <div className={avatar} />\n </div>","<div className={list}>\n {LIST_ROWS.map((width, index) => {\n const isSelected = index === 1\n\n return (\n <div className={listRow} data-selected={isSelected} key={width}>\n <div className={isSelected ? line.selected : line.muted} style={{width}} />\n </div>\n )\n })}\n </div>","(width, index) => {\n const isSelected = index === 1\n\n return (\n <div className={listRow} data-selected={isSelected} key={width}>\n <div className={isSelected ? line.selected : line.muted} style={{width}} />\n </div>\n )\n }","<div className={form}>\n <div className={line.fg} style={{width: '45%'}} />\n {FIELDS.map((width) => (\n <div className={field} key={width}>\n <div className={line.muted} style={{width}} />\n <div className={input} />\n </div>\n ))}\n </div>","(width) => (\n <div className={field} key={width}>\n <div className={line.muted} style={{width}} />\n <div className={input} />\n </div>\n )","<div className={body}>\n <div className={list}>\n {LIST_ROWS.map((width, index) => {\n const isSelected = index === 1\n\n return (\n <div className={listRow} data-selected={isSelected} key={width}>\n <div className={isSelected ? line.selected : line.muted} style={{width}} />\n </div>\n )\n })}\n </div>\n\n <div className={pane}>\n <div className={form}>\n <div className={line.fg} style={{width: '45%'}} />\n {FIELDS.map((width) => (\n <div className={field} key={width}>\n <div className={line.muted} style={{width}} />\n <div className={input} />\n </div>\n ))}\n </div>\n <div className={footer}>\n <div className={button} />\n </div>\n </div>\n </div>","<div\n className={studio[scheme]}\n style={assignInlineVars({\n [colors.bg]: color.bg,\n [colors.fg]: color.fg,\n [colors.mutedFg]: color.muted.fg,\n [colors.border]: color.border,\n [colors.accent]: color.button.default.primary.enabled.bg,\n [colors.avatar]: color.avatar.blue.bg,\n [colors.selectedBg]: selected.bg,\n [colors.selectedFg]: selected.fg,\n [colors.inputBg]: inputColor.bg,\n [colors.inputBorder]: inputColor.border,\n })}\n >\n <div className={navbar}>\n <div className={logo} />\n <div className={line.fg} style={{width: '22%'}} />\n <div className={spacer} />\n <div className={avatar} />\n </div>\n\n <div className={body}>\n <div className={list}>\n {LIST_ROWS.map((width, index) => {\n const isSelected = index === 1\n\n return (\n <div className={listRow} data-selected={isSelected} key={width}>\n <div className={isSelected ? line.selected : line.muted} style={{width}} />\n </div>\n )\n })}\n </div>\n\n <div className={pane}>\n <div className={form}>\n <div className={line.fg} style={{width: '45%'}} />\n {FIELDS.map((width) => (\n <div className={field} key={width}>\n <div className={line.muted} style={{width}} />\n <div className={input} />\n </div>\n ))}\n </div>\n <div className={footer}>\n <div className={button} />\n </div>\n </div>\n </div>\n </div>","studio[scheme]","width","FIELDS","_c","root","_temp","<Card overflow=\"hidden\" radius={3} shadow={1}>\n <ThemePreview options={props.options} />\n </Card>","options","_c","removed.map((theme) => (\n <Stack gap={3} key={theme.slug}>\n <Box className={removedThumbnail}>\n <ThemeThumbnail options={theme.options} />\n </Box>\n <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n {displayTitle(theme.title)}\n </Text>\n <Flex gap={2} justify=\"center\">\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.restore', slug: theme.slug})}\n padding={2}\n text=\"Restore\"\n />\n {theme.source === 'custom' && (\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.delete', slug: theme.slug})}\n padding={2}\n text=\"Delete\"\n tone=\"critical\"\n />\n )}\n </Flex>\n </Stack>\n ))","(theme) => (\n <Stack gap={3} key={theme.slug}>\n <Box className={removedThumbnail}>\n <ThemeThumbnail options={theme.options} />\n </Box>\n <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n {displayTitle(theme.title)}\n </Text>\n <Flex gap={2} justify=\"center\">\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.restore', slug: theme.slug})}\n padding={2}\n text=\"Restore\"\n />\n {theme.source === 'custom' && (\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.delete', slug: theme.slug})}\n padding={2}\n text=\"Delete\"\n tone=\"critical\"\n />\n )}\n </Flex>\n </Stack>\n )","<ScrollArea padding={3}>\n <Stack gap={5}>\n {removed.map((theme) => (\n <Stack gap={3} key={theme.slug}>\n <Box className={removedThumbnail}>\n <ThemeThumbnail options={theme.options} />\n </Box>\n <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n {displayTitle(theme.title)}\n </Text>\n <Flex gap={2} justify=\"center\">\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.restore', slug: theme.slug})}\n padding={2}\n text=\"Restore\"\n />\n {theme.source === 'custom' && (\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.delete', slug: theme.slug})}\n padding={2}\n text=\"Delete\"\n tone=\"critical\"\n />\n )}\n </Flex>\n </Stack>\n ))}\n </Stack>\n </ScrollArea>","_c","<Text size={1}>{tooltip}</Text>","<Button\n aria-label={buttonProps.text === undefined ? tooltip : undefined}\n gap={2}\n padding={2}\n {...buttonProps}\n />","buttonProps.text === undefined ? tooltip : undefined","<Tooltip animate content={<Text size={1}>{tooltip}</Text>} placement=\"bottom\" portal>\n <Button\n aria-label={buttonProps.text === undefined ? tooltip : undefined}\n gap={2}\n padding={2}\n {...buttonProps}\n />\n </Tooltip>","_c","() => inputRef.current?.click()","<TooltipButton {...buttonProps} icon={ImageIcon} onClick={() => inputRef.current?.click()} />","<input\n accept=\"image/*\"\n hidden\n onChange={(event) => {\n const file = event.currentTarget.files?.[0]\n\n // Picking the same file again should work, so the input forgets it\n event.currentTarget.value = ''\n\n if (file) onFile(file)\n }}\n ref={inputRef}\n type=\"file\"\n />","<>\n <TooltipButton {...buttonProps} icon={ImageIcon} onClick={() => inputRef.current?.click()} />\n <input\n accept=\"image/*\"\n hidden\n onChange={(event) => {\n const file = event.currentTarget.files?.[0]\n\n // Picking the same file again should work, so the input forgets it\n event.currentTarget.value = ''\n\n if (file) onFile(file)\n }}\n ref={inputRef}\n type=\"file\"\n />\n </>","_c","_Fragment","() => {\n onPaletteRef.current = onPalette\n }","[onPalette]","() => {\n mountedRef.current = true\n\n return () => {\n mountedRef.current = false\n }\n }","[]","(file: File) => {\n const pick = ++latestPickRef.current\n\n setBusy(true)\n\n // Whether this pick still matters: it is the latest one and the\n // component that asked for it is still around\n const isCurrent = () => mountedRef.current && latestPickRef.current === pick\n\n const extract = async () => {\n const palette = extractImagePalette(await readImagePixels(file))\n\n if (!isCurrent()) return\n\n if (Object.values(palette).every((swatch) => swatch === null)) {\n toast.push({status: 'warning', title: 'Found no colors in that image'})\n } else {\n onPaletteRef.current(palette, file)\n }\n }\n\n extract()\n .catch(() => {\n if (isCurrent()) toast.push({status: 'error', title: 'Could not read that image'})\n })\n .finally(() => {\n if (isCurrent()) setBusy(false)\n })\n }","(swatch) => swatch === null","useCallback(\n (file: File) => {\n const pick = ++latestPickRef.current\n\n setBusy(true)\n\n // Whether this pick still matters: it is the latest one and the\n // component that asked for it is still around\n const isCurrent = () => mountedRef.current && latestPickRef.current === pick\n\n const extract = async () => {\n const palette = extractImagePalette(await readImagePixels(file))\n\n if (!isCurrent()) return\n\n if (Object.values(palette).every((swatch) => swatch === null)) {\n toast.push({status: 'warning', title: 'Found no colors in that image'})\n } else {\n onPaletteRef.current(palette, file)\n }\n }\n\n extract()\n .catch(() => {\n if (isCurrent()) toast.push({status: 'error', title: 'Could not read that image'})\n })\n .finally(() => {\n if (isCurrent()) setBusy(false)\n })\n },\n [toast],\n )","{busy, pickImage}","_c","_temp","palette ? currentImageVariant(options, palette) : null","() => {\n const row = rowRef.current\n\n if (!row) return undefined\n\n const measure = () => {\n const visible =\n row.clientWidth - ROW_PADDING - (Math.ceil(VISIBLE_VARIANTS) - 1) * VARIANT_GAP\n\n // Each variant is its thumbnail plus the frame on either side\n setThumbnailWidth(Math.max(24, Math.floor(visible / VISIBLE_VARIANTS) - VARIANT_FRAME * 2))\n }\n\n measure()\n\n const observer = new ResizeObserver(measure)\n\n observer.observe(row)\n\n return () => observer.disconnect()\n // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the row only renders with a palette, so a new palette has a new row to observe\n }","[palette]","useMemo(() => {\n if (!palette) return []\n\n return IMAGE_PALETTE_VARIANTS.flatMap((variant) =>\n palette[variant] === null\n ? []\n : [\n {\n variant,\n title: IMAGE_PALETTE_TITLES[variant],\n options: applyImagePalette(options, palette, variant),\n },\n ],\n )\n }, [options, palette])","[]","IMAGE_PALETTE_VARIANTS.flatMap((variant) =>\n palette[variant] === null\n ? []\n : [\n {\n variant,\n title: IMAGE_PALETTE_TITLES[variant],\n options: applyImagePalette(options, palette, variant),\n },\n ],\n )","(event) => {\n event.preventDefault()\n dragDepth.current++\n setDragging(true)\n }","() => {\n dragDepth.current = Math.max(0, dragDepth.current - 1)\n\n if (dragDepth.current === 0) setDragging(false)\n }","(event) => {\n event.preventDefault()\n dragDepth.current = 0\n setDragging(false)\n\n const file = event.dataTransfer.files[0]\n\n if (file) pickImage(file)\n }","event","<Box flex={1}>\n <Text size={1} weight=\"medium\">\n Image palette\n </Text>\n </Box>","palette && (\n <ImageFileButton\n loading={busy}\n mode=\"bleed\"\n onFile={pickImage}\n padding={2}\n tooltip=\"Pick another image\"\n />\n )","<Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n Image palette\n </Text>\n </Box>\n {palette && (\n <ImageFileButton\n loading={busy}\n mode=\"bleed\"\n onFile={pickImage}\n padding={2}\n tooltip=\"Pick another image\"\n />\n )}\n </Flex>","palette ? (\n <>\n <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n {TILES.map((key) => {\n const hex = palette[key]\n const title = IMAGE_PALETTE_TITLES[key]\n\n return (\n <Tooltip\n animate\n content={\n <Text size={1}>\n {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n </Text>\n }\n key={key}\n placement=\"bottom\"\n portal\n >\n <span\n className={tile}\n data-empty={hex === null}\n style={{background: hex ?? undefined}}\n />\n </Tooltip>\n )\n })}\n </div>\n\n <Stack gap={2}>\n <Text muted size={0}>\n Pick the swatch to build the theme around\n </Text>\n <div\n className={variantRow}\n ref={rowRef}\n style={assignInlineVars({\n [variantWidth]: `${thumbnailWidth}px`,\n [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n })}\n >\n {variants.map(({variant, title, options: variantOptions}) => (\n // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n <button\n aria-pressed={variant === current}\n className={variantButton}\n key={variant}\n onClick={() => onVariant(variant)}\n type=\"button\"\n >\n <span className={variantFrame}>\n <span className={variantScaleBox}>\n <ThemeThumbnail options={variantOptions} />\n </span>\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={1}>\n <Text\n align=\"center\"\n as=\"span\"\n size={0}\n textOverflow=\"ellipsis\"\n weight={variant === current ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>\n ))}\n </div>\n </Stack>\n\n <TooltipButton\n icon={SparklesIcon}\n mode=\"ghost\"\n onClick={onLucky}\n text=\"I'm feeling lucky\"\n tooltip=\"Build the theme around a swatch that looks interesting\"\n width=\"fill\"\n />\n </>\n ) : (\n <Stack gap={3}>\n <Text muted size={0}>\n Take the accent, text and background colors from an image — read on device, nothing is\n uploaded.\n </Text>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n text=\"Pick an image\"\n tooltip=\"Take the colors from an image on your device\"\n width=\"fill\"\n />\n </Stack>\n )","{variant, title, options: variantOptions}","variant","title","<Stack gap={3}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n Image palette\n </Text>\n </Box>\n {palette && (\n <ImageFileButton\n loading={busy}\n mode=\"bleed\"\n onFile={pickImage}\n padding={2}\n tooltip=\"Pick another image\"\n />\n )}\n </Flex>\n\n {palette ? (\n <>\n <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n {TILES.map((key) => {\n const hex = palette[key]\n const title = IMAGE_PALETTE_TITLES[key]\n\n return (\n <Tooltip\n animate\n content={\n <Text size={1}>\n {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n </Text>\n }\n key={key}\n placement=\"bottom\"\n portal\n >\n <span\n className={tile}\n data-empty={hex === null}\n style={{background: hex ?? undefined}}\n />\n </Tooltip>\n )\n })}\n </div>\n\n <Stack gap={2}>\n <Text muted size={0}>\n Pick the swatch to build the theme around\n </Text>\n <div\n className={variantRow}\n ref={rowRef}\n style={assignInlineVars({\n [variantWidth]: `${thumbnailWidth}px`,\n [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n })}\n >\n {variants.map(({variant, title, options: variantOptions}) => (\n // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n <button\n aria-pressed={variant === current}\n className={variantButton}\n key={variant}\n onClick={() => onVariant(variant)}\n type=\"button\"\n >\n <span className={variantFrame}>\n <span className={variantScaleBox}>\n <ThemeThumbnail options={variantOptions} />\n </span>\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={1}>\n <Text\n align=\"center\"\n as=\"span\"\n size={0}\n textOverflow=\"ellipsis\"\n weight={variant === current ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>\n ))}\n </div>\n </Stack>\n\n <TooltipButton\n icon={SparklesIcon}\n mode=\"ghost\"\n onClick={onLucky}\n text=\"I'm feeling lucky\"\n tooltip=\"Build the theme around a swatch that looks interesting\"\n width=\"fill\"\n />\n </>\n ) : (\n <Stack gap={3}>\n <Text muted size={0}>\n Take the accent, text and background colors from an image — read on device, nothing is\n uploaded.\n </Text>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n text=\"Pick an image\"\n tooltip=\"Take the colors from an image on your device\"\n width=\"fill\"\n />\n </Stack>\n )}\n </Stack>","<Card\n border\n onDragEnter={(event) => {\n event.preventDefault()\n dragDepth.current++\n setDragging(true)\n }}\n onDragLeave={() => {\n dragDepth.current = Math.max(0, dragDepth.current - 1)\n\n if (dragDepth.current === 0) setDragging(false)\n }}\n onDragOver={(event) => {\n event.preventDefault()\n }}\n onDrop={(event) => {\n event.preventDefault()\n dragDepth.current = 0\n setDragging(false)\n\n const file = event.dataTransfer.files[0]\n\n if (file) pickImage(file)\n }}\n padding={3}\n radius={3}\n tone={dragging ? 'primary' : 'default'}\n >\n <Stack gap={3}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n Image palette\n </Text>\n </Box>\n {palette && (\n <ImageFileButton\n loading={busy}\n mode=\"bleed\"\n onFile={pickImage}\n padding={2}\n tooltip=\"Pick another image\"\n />\n )}\n </Flex>\n\n {palette ? (\n <>\n <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n {TILES.map((key) => {\n const hex = palette[key]\n const title = IMAGE_PALETTE_TITLES[key]\n\n return (\n <Tooltip\n animate\n content={\n <Text size={1}>\n {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n </Text>\n }\n key={key}\n placement=\"bottom\"\n portal\n >\n <span\n className={tile}\n data-empty={hex === null}\n style={{background: hex ?? undefined}}\n />\n </Tooltip>\n )\n })}\n </div>\n\n <Stack gap={2}>\n <Text muted size={0}>\n Pick the swatch to build the theme around\n </Text>\n <div\n className={variantRow}\n ref={rowRef}\n style={assignInlineVars({\n [variantWidth]: `${thumbnailWidth}px`,\n [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n })}\n >\n {variants.map(({variant, title, options: variantOptions}) => (\n // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n <button\n aria-pressed={variant === current}\n className={variantButton}\n key={variant}\n onClick={() => onVariant(variant)}\n type=\"button\"\n >\n <span className={variantFrame}>\n <span className={variantScaleBox}>\n <ThemeThumbnail options={variantOptions} />\n </span>\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={1}>\n <Text\n align=\"center\"\n as=\"span\"\n size={0}\n textOverflow=\"ellipsis\"\n weight={variant === current ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>\n ))}\n </div>\n </Stack>\n\n <TooltipButton\n icon={SparklesIcon}\n mode=\"ghost\"\n onClick={onLucky}\n text=\"I'm feeling lucky\"\n tooltip=\"Build the theme around a swatch that looks interesting\"\n width=\"fill\"\n />\n </>\n ) : (\n <Stack gap={3}>\n <Text muted size={0}>\n Take the accent, text and background colors from an image — read on device, nothing is\n uploaded.\n </Text>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n text=\"Pick an image\"\n tooltip=\"Take the colors from an image on your device\"\n width=\"fill\"\n />\n </Stack>\n )}\n </Stack>\n </Card>","dragging ? 'primary' : 'default'","(event) => {\n event.preventDefault()\n }","_c","_Fragment","_temp","themes.find((candidate) => candidate.slug === slug && candidate.source === 'custom')","(candidate) => candidate.slug === slug && candidate.source === 'custom'","(variant: ImagePaletteVariant | null) => {\n if (!theme.palette || variant === null) return\n\n send({\n type: 'theme.update',\n slug,\n options: applyImagePalette(theme.options, theme.palette, variant),\n })\n }","options","palette","() => send({type: 'flow.list'})","() => {\n if (!theme.palette) return\n\n applyVariant(\n pickLuckyVariant(theme.palette, {\n exclude: currentImageVariant(theme.options, theme.palette),\n }),\n )\n }","(options) => send({type: 'theme.update', slug, options})","(palette, file) =>\n send({\n type: 'theme.update',\n slug,\n options: applyImagePalette(theme.options, palette),\n palette,\n imageUrl: URL.createObjectURL(file),\n })","() => send({type: 'theme.remove', slug})","(title) => send({type: 'theme.update', slug, title})","<ThemeEditorForm\n focusTitle={focusTitle}\n imageUrl={images[slug]}\n onDone={() => send({type: 'flow.list'})}\n onLucky={() => {\n if (!theme.palette) return\n\n applyVariant(\n pickLuckyVariant(theme.palette, {\n exclude: currentImageVariant(theme.options, theme.palette),\n }),\n )\n }}\n onOptionsChange={(options) => send({type: 'theme.update', slug, options})}\n onPalette={(palette, file) =>\n send({\n type: 'theme.update',\n slug,\n options: applyImagePalette(theme.options, palette),\n palette,\n imageUrl: URL.createObjectURL(file),\n })\n }\n onRemove={() => send({type: 'theme.remove', slug})}\n onTitleChange={(title) => send({type: 'theme.update', slug, title})}\n onVariant={applyVariant}\n options={theme.options}\n palette={theme.palette}\n split={split}\n mobile={mobile}\n title={theme.title}\n />","images[slug]","title","resolveThemeOptions(options)","useMemo(() => resolveThemeOptions(options), [options])","buildPalette(options)","useMemo(() => buildPalette(options), [options])","(scheme: ThemeColorSchemeKey, changes: Partial<SchemeThemeOptions>) => {\n const values: SchemeThemeOptions = {...options[scheme], ...changes}\n\n // Clearing an option means falling back to its default, which is its absence\n for (const key of SCHEME_OPTION_KEYS) {\n if (values[key] === undefined) delete values[key]\n }\n\n const next: BuildThemeOptions = {...options}\n\n if (Object.keys(values).length === 0) {\n delete next[scheme]\n } else {\n next[scheme] = values\n }\n\n onOptionsChange(next)\n }","<ThemeThumbnail options={options} />","<Text size={1} weight=\"medium\">\n Title\n </Text>","(event) => onTitleChange(event.currentTarget.value)","(event) => event.currentTarget.select()","<Stack gap={2}>\n <Text size={1} weight=\"medium\">\n Title\n </Text>\n <TextInput\n autoFocus={focusTitle}\n fontSize={1}\n onChange={(event) => onTitleChange(event.currentTarget.value)}\n onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n padding={2}\n placeholder=\"Untitled theme\"\n value={title}\n />\n </Stack>","focusTitle ? (event) => event.currentTarget.select() : undefined","<ImagePaletteSection\n imageUrl={imageUrl}\n onLucky={onLucky}\n onPalette={onPalette}\n onVariant={onVariant}\n options={options}\n palette={palette}\n />","SCHEMES.map((scheme) => (\n <SchemeCard\n active={split || scheme === studioScheme}\n key={scheme}\n onChange={(changes) => patchScheme(scheme, changes)}\n options={options[scheme] ?? {}}\n palette={palettes[scheme]}\n resolved={resolved[scheme]}\n scheme={scheme}\n split={split}\n splitHint={splitHint(scheme === studioScheme, mobile)}\n />\n ))","scheme","changes","<ScrollAreaBleed>\n {SCHEMES.map((scheme) => (\n <SchemeCard\n active={split || scheme === studioScheme}\n key={scheme}\n onChange={(changes) => patchScheme(scheme, changes)}\n options={options[scheme] ?? {}}\n palette={palettes[scheme]}\n resolved={resolved[scheme]}\n scheme={scheme}\n split={split}\n splitHint={splitHint(scheme === studioScheme, mobile)}\n />\n ))}\n </ScrollAreaBleed>","<ScrollArea padding={3}>\n <Stack gap={4}>\n <ThemeThumbnail options={options} />\n\n <Stack gap={2}>\n <Text size={1} weight=\"medium\">\n Title\n </Text>\n <TextInput\n autoFocus={focusTitle}\n fontSize={1}\n onChange={(event) => onTitleChange(event.currentTarget.value)}\n onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n padding={2}\n placeholder=\"Untitled theme\"\n value={title}\n />\n </Stack>\n\n <ImagePaletteSection\n imageUrl={imageUrl}\n onLucky={onLucky}\n onPalette={onPalette}\n onVariant={onVariant}\n options={options}\n palette={palette}\n />\n\n <ScrollAreaBleed>\n {SCHEMES.map((scheme) => (\n <SchemeCard\n active={split || scheme === studioScheme}\n key={scheme}\n onChange={(changes) => patchScheme(scheme, changes)}\n options={options[scheme] ?? {}}\n palette={palettes[scheme]}\n resolved={resolved[scheme]}\n scheme={scheme}\n split={split}\n splitHint={splitHint(scheme === studioScheme, mobile)}\n />\n ))}\n </ScrollAreaBleed>\n </Stack>\n </ScrollArea>","<TooltipButton\n icon={TrashIcon}\n mode=\"ghost\"\n onClick={onRemove}\n text=\"Remove\"\n tone=\"critical\"\n tooltip=\"Remove the theme — it can be restored until it is deleted\"\n />","<Box flex={1} />","<Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />","<Card borderTop padding={3}>\n <Flex gap={2}>\n <TooltipButton\n icon={TrashIcon}\n mode=\"ghost\"\n onClick={onRemove}\n text=\"Remove\"\n tone=\"critical\"\n tooltip=\"Remove the theme — it can be restored until it is deleted\"\n />\n <Box flex={1} />\n <Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />\n </Flex>\n </Card>","<>\n <ScrollArea padding={3}>\n <Stack gap={4}>\n <ThemeThumbnail options={options} />\n\n <Stack gap={2}>\n <Text size={1} weight=\"medium\">\n Title\n </Text>\n <TextInput\n autoFocus={focusTitle}\n fontSize={1}\n onChange={(event) => onTitleChange(event.currentTarget.value)}\n onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n padding={2}\n placeholder=\"Untitled theme\"\n value={title}\n />\n </Stack>\n\n <ImagePaletteSection\n imageUrl={imageUrl}\n onLucky={onLucky}\n onPalette={onPalette}\n onVariant={onVariant}\n options={options}\n palette={palette}\n />\n\n <ScrollAreaBleed>\n {SCHEMES.map((scheme) => (\n <SchemeCard\n active={split || scheme === studioScheme}\n key={scheme}\n onChange={(changes) => patchScheme(scheme, changes)}\n options={options[scheme] ?? {}}\n palette={palettes[scheme]}\n resolved={resolved[scheme]}\n scheme={scheme}\n split={split}\n splitHint={splitHint(scheme === studioScheme, mobile)}\n />\n ))}\n </ScrollAreaBleed>\n </Stack>\n </ScrollArea>\n\n <Card borderTop padding={3}>\n <Flex gap={2}>\n <TooltipButton\n icon={TrashIcon}\n mode=\"ghost\"\n onClick={onRemove}\n text=\"Remove\"\n tone=\"critical\"\n tooltip=\"Remove the theme — it can be restored until it is deleted\"\n />\n <Box flex={1} />\n <Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />\n </Flex>\n </Card>\n </>","event","<Box flex={1}>\n <Text size={1} weight=\"medium\">\n {name}\n </Text>\n </Box>","active && (\n <Badge fontSize={0} tone=\"primary\">\n Active\n </Badge>\n )","<Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n {name}\n </Text>\n </Box>\n {active && (\n <Badge fontSize={0} tone=\"primary\">\n Active\n </Badge>\n )}\n </Flex>","<Text muted size={0}>\n {split\n ? splitHint\n : active\n ? 'Shown in the Studio right now'\n : `Shown once the Studio appearance is ${scheme}`}\n </Text>","split\n ? splitHint\n : active\n ? 'Shown in the Studio right now'\n : `Shown once the Studio appearance is ${scheme}`","<Stack gap={2}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n {name}\n </Text>\n </Box>\n {active && (\n <Badge fontSize={0} tone=\"primary\">\n Active\n </Badge>\n )}\n </Flex>\n <Text muted size={0}>\n {split\n ? splitHint\n : active\n ? 'Shown in the Studio right now'\n : `Shown once the Studio appearance is ${scheme}`}\n </Text>\n </Stack>","(accent) => onChange({accent})","() => onChange({accent: undefined})","<ColorRow\n auto={options.accent === undefined}\n autoLabel=\"default\"\n label={`${name} accent`}\n onChange={(accent) => onChange({accent})}\n onClear={() => onChange({accent: undefined})}\n title=\"Accent\"\n value={resolved.accent}\n />","accent","options.accent === undefined","`${name} accent`","(text) => onChange({text})","() => onChange({text: undefined})","<ColorRow\n auto={options.text === undefined}\n label={`${name} text`}\n onChange={(text) => onChange({text})}\n onClear={() => onChange({text: undefined})}\n title=\"Text\"\n value={resolved.text}\n />","text","options.text === undefined","`${name} text`","(background) => onChange({background})","() => onChange({background: undefined})","<ColorRow\n adjusted={scheme === 'dark' ? palette.black : palette.white}\n auto={options.background === undefined}\n label={`${name} background`}\n onChange={(background) => onChange({background})}\n onClear={() => onChange({background: undefined})}\n title=\"Background\"\n value={resolved.background}\n />","background","scheme === 'dark' ? palette.black : palette.white","options.background === undefined","`${name} background`","<Text size={1}>Contrast</Text>","<Stack flex={1} gap={2}>\n <Text size={1}>Contrast</Text>\n <Text muted size={0}>\n {resolved.contrast}\n {options.contrast === undefined ? ' · auto' : ''}\n </Text>\n </Stack>","contrast","options.contrast === undefined ? ' · auto' : ''","options.contrast !== undefined && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={() => onChange({contrast: undefined})}\n padding={2}\n tooltip=\"Reset to auto\"\n />\n )","<Flex align=\"center\" gap={2}>\n <Stack flex={1} gap={2}>\n <Text size={1}>Contrast</Text>\n <Text muted size={0}>\n {resolved.contrast}\n {options.contrast === undefined ? ' · auto' : ''}\n </Text>\n </Stack>\n {options.contrast !== undefined && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={() => onChange({contrast: undefined})}\n padding={2}\n tooltip=\"Reset to auto\"\n />\n )}\n </Flex>","(event) => onChange({contrast: Number(event.currentTarget.value)})","<input\n aria-label={`${name} contrast`}\n className={range}\n max={100}\n min={15}\n onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n step={1}\n type=\"range\"\n value={resolved.contrast}\n />","`${name} contrast`","<Text muted size={0}>\n 100 keeps text and borders neutral — lower values blend in the accent\n </Text>","<Stack gap={3}>\n <Flex align=\"center\" gap={2}>\n <Stack flex={1} gap={2}>\n <Text size={1}>Contrast</Text>\n <Text muted size={0}>\n {resolved.contrast}\n {options.contrast === undefined ? ' · auto' : ''}\n </Text>\n </Stack>\n {options.contrast !== undefined && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={() => onChange({contrast: undefined})}\n padding={2}\n tooltip=\"Reset to auto\"\n />\n )}\n </Flex>\n <input\n aria-label={`${name} contrast`}\n className={range}\n max={100}\n min={15}\n onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n step={1}\n type=\"range\"\n value={resolved.contrast}\n />\n <Text muted size={0}>\n 100 keeps text and borders neutral — lower values blend in the accent\n </Text>\n </Stack>","<Card borderTop padding={3}>\n <Stack gap={4}>\n <Stack gap={2}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n {name}\n </Text>\n </Box>\n {active && (\n <Badge fontSize={0} tone=\"primary\">\n Active\n </Badge>\n )}\n </Flex>\n <Text muted size={0}>\n {split\n ? splitHint\n : active\n ? 'Shown in the Studio right now'\n : `Shown once the Studio appearance is ${scheme}`}\n </Text>\n </Stack>\n\n <ColorRow\n auto={options.accent === undefined}\n autoLabel=\"default\"\n label={`${name} accent`}\n onChange={(accent) => onChange({accent})}\n onClear={() => onChange({accent: undefined})}\n title=\"Accent\"\n value={resolved.accent}\n />\n <ColorRow\n auto={options.text === undefined}\n label={`${name} text`}\n onChange={(text) => onChange({text})}\n onClear={() => onChange({text: undefined})}\n title=\"Text\"\n value={resolved.text}\n />\n <ColorRow\n adjusted={scheme === 'dark' ? palette.black : palette.white}\n auto={options.background === undefined}\n label={`${name} background`}\n onChange={(background) => onChange({background})}\n onClear={() => onChange({background: undefined})}\n title=\"Background\"\n value={resolved.background}\n />\n\n <Stack gap={3}>\n <Flex align=\"center\" gap={2}>\n <Stack flex={1} gap={2}>\n <Text size={1}>Contrast</Text>\n <Text muted size={0}>\n {resolved.contrast}\n {options.contrast === undefined ? ' · auto' : ''}\n </Text>\n </Stack>\n {options.contrast !== undefined && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={() => onChange({contrast: undefined})}\n padding={2}\n tooltip=\"Reset to auto\"\n />\n )}\n </Flex>\n <input\n aria-label={`${name} contrast`}\n className={range}\n max={100}\n min={15}\n onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n step={1}\n type=\"range\"\n value={resolved.contrast}\n />\n <Text muted size={0}>\n 100 keeps text and borders neutral — lower values blend in the accent\n </Text>\n </Stack>\n </Stack>\n </Card>","autoLabel = 'auto'","(event) => onChange(event.currentTarget.value)","<input\n aria-label={label}\n className={swatch}\n onChange={(event) => onChange(event.currentTarget.value)}\n type=\"color\"\n value={value}\n />","<Text size={1}>{title}</Text>","<Text muted size={0} textOverflow=\"ellipsis\">\n {value}\n {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n {auto ? ` · ${autoLabel}` : ''}\n </Text>","adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''","auto ? ` · ${autoLabel}` : ''","<Stack className={colorRowText} flex={1} gap={2}>\n <Text size={1}>{title}</Text>\n <Text muted size={0} textOverflow=\"ellipsis\">\n {value}\n {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n {auto ? ` · ${autoLabel}` : ''}\n </Text>\n </Stack>","onClear && !auto && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={onClear}\n padding={2}\n tooltip={`Reset to ${autoLabel}`}\n />\n )","<Flex align=\"center\" gap={2}>\n <input\n aria-label={label}\n className={swatch}\n onChange={(event) => onChange(event.currentTarget.value)}\n type=\"color\"\n value={value}\n />\n <Stack className={colorRowText} flex={1} gap={2}>\n <Text size={1}>{title}</Text>\n <Text muted size={0} textOverflow=\"ellipsis\">\n {value}\n {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n {auto ? ` · ${autoLabel}` : ''}\n </Text>\n </Stack>\n {onClear && !auto && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={onClear}\n padding={2}\n tooltip={`Reset to ${autoLabel}`}\n />\n )}\n </Flex>","_c","_temp","_Fragment","async (theme: SharedTheme) => {\n const title = displayTitle(theme.title)\n\n try {\n await navigator.clipboard.writeText(encodeTheme(theme))\n toast.push({\n status: 'success',\n title: `Copied ${title} as a code`,\n description: 'Paste it in the themer of another Studio to add the theme there',\n })\n } catch {\n toast.push({status: 'error', title: `Could not copy ${title}`})\n }\n }","(text: string) => {\n const theme = decodeTheme(text)\n\n if (!theme) return false\n\n send({type: 'theme.import', title: theme.title, options: theme.options})\n toast.push({status: 'success', title: `Added ${theme.title}`})\n\n return true\n }","theme","async () => {\n let text: string\n\n try {\n text = await navigator.clipboard.readText()\n } catch {\n return 'no-clipboard'\n }\n\n return addThemeFromText(text) ? 'added' : 'no-theme'\n }","text","{copyTheme, addThemeFromText, addThemeFromClipboard}","() => {\n if (!open) return undefined\n\n const handlePaste = (event: ClipboardEvent) => {\n if (isEditable(event.target)) return\n\n const theme = decodeTheme(event.clipboardData?.getData('text/plain') ?? '')\n\n if (!theme) return\n\n event.preventDefault()\n send({type: 'theme.import', title: theme.title, options: theme.options})\n toast.push({status: 'success', title: `Added ${theme.title}`})\n }\n\n document.addEventListener('paste', handlePaste)\n\n return () => document.removeEventListener('paste', handlePaste)\n }","[open, send, toast]","_c","() => {\n if (addThemeFromText(text)) {\n onClose()\n } else {\n setInvalid(true)\n }\n }","<Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />","text.trim()","<Button\n disabled={text.trim() === ''}\n onClick={add}\n padding={2}\n text=\"Add theme\"\n tone=\"primary\"\n />","text.trim() === ''","<Flex gap={2} justify=\"flex-end\" padding={3}>\n <Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />\n <Button\n disabled={text.trim() === ''}\n onClick={add}\n padding={2}\n text=\"Add theme\"\n tone=\"primary\"\n />\n </Flex>","(event) => {\n event.preventDefault()\n add()\n }","<Text muted size={1}>\n Paste the code someone copied from their themer — the theme is added to your list and\n applied.\n </Text>","(event) => {\n setText(event.currentTarget.value)\n setInvalid(false)\n }","event","<TextInput\n aria-describedby={invalid ? 'themer-paste-error' : undefined}\n aria-invalid={invalid}\n aria-label=\"Theme code\"\n autoFocus\n customValidity={invalid ? 'That is not a theme code' : undefined}\n fontSize={1}\n onChange={(event) => {\n setText(event.currentTarget.value)\n setInvalid(false)\n }}\n placeholder=\"AQ…\"\n value={text}\n />","invalid ? 'themer-paste-error' : undefined","invalid ? 'That is not a theme code' : undefined","invalid && (\n <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n <Text size={1}>\n That is not a theme code — codes are one word, copied from a theme's menu.\n </Text>\n </Card>\n )","<Stack gap={3} padding={4}>\n <Text muted size={1}>\n Paste the code someone copied from their themer — the theme is added to your list and\n applied.\n </Text>\n <TextInput\n aria-describedby={invalid ? 'themer-paste-error' : undefined}\n aria-invalid={invalid}\n aria-label=\"Theme code\"\n autoFocus\n customValidity={invalid ? 'That is not a theme code' : undefined}\n fontSize={1}\n onChange={(event) => {\n setText(event.currentTarget.value)\n setInvalid(false)\n }}\n placeholder=\"AQ…\"\n value={text}\n />\n {invalid && (\n <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n <Text size={1}>\n That is not a theme code — codes are one word, copied from a theme's menu.\n </Text>\n </Card>\n )}\n </Stack>","<form\n onSubmit={(event) => {\n event.preventDefault()\n add()\n }}\n >\n <Stack gap={3} padding={4}>\n <Text muted size={1}>\n Paste the code someone copied from their themer — the theme is added to your list and\n applied.\n </Text>\n <TextInput\n aria-describedby={invalid ? 'themer-paste-error' : undefined}\n aria-invalid={invalid}\n aria-label=\"Theme code\"\n autoFocus\n customValidity={invalid ? 'That is not a theme code' : undefined}\n fontSize={1}\n onChange={(event) => {\n setText(event.currentTarget.value)\n setInvalid(false)\n }}\n placeholder=\"AQ…\"\n value={text}\n />\n {invalid && (\n <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n <Text size={1}>\n That is not a theme code — codes are one word, copied from a theme's menu.\n </Text>\n </Card>\n )}\n </Stack>\n </form>","<Dialog\n animate\n footer={\n <Flex gap={2} justify=\"flex-end\" padding={3}>\n <Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />\n <Button\n disabled={text.trim() === ''}\n onClick={add}\n padding={2}\n text=\"Add theme\"\n tone=\"primary\"\n />\n </Flex>\n }\n header=\"Add a shared theme\"\n id=\"themer-paste\"\n onClickOutside={onClose}\n onClose={onClose}\n width={0}\n >\n <form\n onSubmit={(event) => {\n event.preventDefault()\n add()\n }}\n >\n <Stack gap={3} padding={4}>\n <Text muted size={1}>\n Paste the code someone copied from their themer — the theme is added to your list and\n applied.\n </Text>\n <TextInput\n aria-describedby={invalid ? 'themer-paste-error' : undefined}\n aria-invalid={invalid}\n aria-label=\"Theme code\"\n autoFocus\n customValidity={invalid ? 'That is not a theme code' : undefined}\n fontSize={1}\n onChange={(event) => {\n setText(event.currentTarget.value)\n setInvalid(false)\n }}\n placeholder=\"AQ…\"\n value={text}\n />\n {invalid && (\n <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n <Text size={1}>\n That is not a theme code — codes are one word, copied from a theme's menu.\n </Text>\n </Card>\n )}\n </Stack>\n </form>\n </Dialog>","_c","frame","displayTitle(theme.title)","title","(candidate) => candidate.slug === theme.slug","slug","(to: number) => {\n const order = themes.map((candidate) => candidate.slug)\n\n order.splice(to, 0, ...order.splice(index, 1))\n send({type: 'theme.reorder', order})\n }","(candidate) => candidate.slug","() => {\n // The click lands before the next frame\n requestAnimationFrame(() => {\n dragged.current = false\n })\n }","() => {\n dragged.current = true\n }","{scale: 1.04}","() => {\n if (!dragged.current) send({type: 'theme.pick', slug: theme.slug})\n }","(event) => {\n // A mouse or pen drags the card off the button; a finger scrolls the\n // list instead, and moves themes from the menu\n if (event.pointerType !== 'touch') dragControls.start(event)\n }","<span className={frame}>\n <ThemeThumbnail options={theme.options} />\n </span>","options","<Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n <Text\n align=\"center\"\n as=\"span\"\n size={1}\n textOverflow=\"ellipsis\"\n weight={active ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>","active ? 'medium' : 'regular'","<button\n aria-pressed={active}\n className={pickButton}\n onClick={() => {\n if (!dragged.current) send({type: 'theme.pick', slug: theme.slug})\n }}\n onPointerDown={(event) => {\n // A mouse or pen drags the card off the button; a finger scrolls the\n // list instead, and moves themes from the menu\n if (event.pointerType !== 'touch') dragControls.start(event)\n }}\n type=\"button\"\n >\n <span className={frame}>\n <ThemeThumbnail options={theme.options} />\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n <Text\n align=\"center\"\n as=\"span\"\n size={1}\n textOverflow=\"ellipsis\"\n weight={active ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>","<Text size={1}>Show more</Text>","<Button\n aria-label={`Show more for ${title}`}\n fontSize={1}\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n padding={1}\n radius={2}\n />","`Show more for ${title}`","() => moveTo(index - 1)","<MenuItem\n disabled={index <= 0}\n icon={ArrowUpIcon}\n onClick={() => moveTo(index - 1)}\n text=\"Move up\"\n />","index <= 0","() => moveTo(index + 1)","<MenuItem\n disabled={index >= themes.length - 1}\n icon={ArrowDownIcon}\n onClick={() => moveTo(index + 1)}\n text=\"Move down\"\n />","index >= themes.length - 1","<MenuDivider />","theme.source === 'custom' && (\n <MenuItem\n icon={EditIcon}\n onClick={() => send({type: 'theme.edit', slug: theme.slug})}\n text=\"Edit\"\n />\n )","source","() => send({type: 'theme.duplicate', slug: theme.slug})","<MenuItem\n icon={CopyIcon}\n onClick={() => send({type: 'theme.duplicate', slug: theme.slug})}\n text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n />","theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'","<MenuItem\n icon={ShareIcon}\n onClick={() => void copyTheme(theme)}\n text=\"Copy to share\"\n />","theme.source !== 'config' && (\n <>\n <MenuDivider />\n <MenuItem\n icon={TrashIcon}\n onClick={() => send({type: 'theme.remove', slug: theme.slug})}\n text=\"Remove\"\n tone=\"critical\"\n />\n </>\n )","<Menu>\n <MenuItem\n disabled={index <= 0}\n icon={ArrowUpIcon}\n onClick={() => moveTo(index - 1)}\n text=\"Move up\"\n />\n <MenuItem\n disabled={index >= themes.length - 1}\n icon={ArrowDownIcon}\n onClick={() => moveTo(index + 1)}\n text=\"Move down\"\n />\n <MenuDivider />\n {theme.source === 'custom' && (\n <MenuItem\n icon={EditIcon}\n onClick={() => send({type: 'theme.edit', slug: theme.slug})}\n text=\"Edit\"\n />\n )}\n <MenuItem\n icon={CopyIcon}\n onClick={() => send({type: 'theme.duplicate', slug: theme.slug})}\n text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n />\n <MenuItem\n icon={ShareIcon}\n onClick={() => void copyTheme(theme)}\n text=\"Copy to share\"\n />\n {theme.source !== 'config' && (\n <>\n <MenuDivider />\n <MenuItem\n icon={TrashIcon}\n onClick={() => send({type: 'theme.remove', slug: theme.slug})}\n text=\"Remove\"\n tone=\"critical\"\n />\n </>\n )}\n </Menu>","() => setMenuOpen(false)","() => setMenuOpen(true)","{animate: true, placement: 'bottom-end', portal: true, scheme}","<Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n <Card className={menuCard} radius={2} scheme=\"dark\">\n <MenuButton\n button={\n <Button\n aria-label={`Show more for ${title}`}\n fontSize={1}\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n padding={1}\n radius={2}\n />\n }\n id={`themer-theme-${theme.slug}`}\n menu={\n <Menu>\n <MenuItem\n disabled={index <= 0}\n icon={ArrowUpIcon}\n onClick={() => moveTo(index - 1)}\n text=\"Move up\"\n />\n <MenuItem\n disabled={index >= themes.length - 1}\n icon={ArrowDownIcon}\n onClick={() => moveTo(index + 1)}\n text=\"Move down\"\n />\n <MenuDivider />\n {theme.source === 'custom' && (\n <MenuItem\n icon={EditIcon}\n onClick={() => send({type: 'theme.edit', slug: theme.slug})}\n text=\"Edit\"\n />\n )}\n <MenuItem\n icon={CopyIcon}\n onClick={() => send({type: 'theme.duplicate', slug: theme.slug})}\n text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n />\n <MenuItem\n icon={ShareIcon}\n onClick={() => void copyTheme(theme)}\n text=\"Copy to share\"\n />\n {theme.source !== 'config' && (\n <>\n <MenuDivider />\n <MenuItem\n icon={TrashIcon}\n onClick={() => send({type: 'theme.remove', slug: theme.slug})}\n text=\"Remove\"\n tone=\"critical\"\n />\n </>\n )}\n </Menu>\n }\n onClose={() => setMenuOpen(false)}\n onOpen={() => setMenuOpen(true)}\n popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n />\n </Card>\n </Tooltip>","`themer-theme-${theme.slug}`","<div className={menuSlot} data-visible={menuOpen}>\n <Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n <Card className={menuCard} radius={2} scheme=\"dark\">\n <MenuButton\n button={\n <Button\n aria-label={`Show more for ${title}`}\n fontSize={1}\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n padding={1}\n radius={2}\n />\n }\n id={`themer-theme-${theme.slug}`}\n menu={\n <Menu>\n <MenuItem\n disabled={index <= 0}\n icon={ArrowUpIcon}\n onClick={() => moveTo(index - 1)}\n text=\"Move up\"\n />\n <MenuItem\n disabled={index >= themes.length - 1}\n icon={ArrowDownIcon}\n onClick={() => moveTo(index + 1)}\n text=\"Move down\"\n />\n <MenuDivider />\n {theme.source === 'custom' && (\n <MenuItem\n icon={EditIcon}\n onClick={() => send({type: 'theme.edit', slug: theme.slug})}\n text=\"Edit\"\n />\n )}\n <MenuItem\n icon={CopyIcon}\n onClick={() => send({type: 'theme.duplicate', slug: theme.slug})}\n text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n />\n <MenuItem\n icon={ShareIcon}\n onClick={() => void copyTheme(theme)}\n text=\"Copy to share\"\n />\n {theme.source !== 'config' && (\n <>\n <MenuDivider />\n <MenuItem\n icon={TrashIcon}\n onClick={() => send({type: 'theme.remove', slug: theme.slug})}\n text=\"Remove\"\n tone=\"critical\"\n />\n </>\n )}\n </Menu>\n }\n onClose={() => setMenuOpen(false)}\n onOpen={() => setMenuOpen(true)}\n popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n />\n </Card>\n </Tooltip>\n </div>","<Reorder.Item\n as=\"div\"\n className={root}\n dragControls={dragControls}\n dragListener={false}\n onDragEnd={() => {\n // The click lands before the next frame\n requestAnimationFrame(() => {\n dragged.current = false\n })\n }}\n onDragStart={() => {\n dragged.current = true\n }}\n ref={active ? scrollRefIntoViewIfNeeded : undefined}\n value={theme.slug}\n whileDrag={{scale: 1.04}}\n >\n <button\n aria-pressed={active}\n className={pickButton}\n onClick={() => {\n if (!dragged.current) send({type: 'theme.pick', slug: theme.slug})\n }}\n onPointerDown={(event) => {\n // A mouse or pen drags the card off the button; a finger scrolls the\n // list instead, and moves themes from the menu\n if (event.pointerType !== 'touch') dragControls.start(event)\n }}\n type=\"button\"\n >\n <span className={frame}>\n <ThemeThumbnail options={theme.options} />\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n <Text\n align=\"center\"\n as=\"span\"\n size={1}\n textOverflow=\"ellipsis\"\n weight={active ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>\n\n {/* The tooltip wraps a card rather than the button: the menu button\n clones its button to wire it up, which a tooltip in between would\n swallow. The card keeps the button dark, as it sits on the dark\n half of the thumbnail, while the menu opens in the sidebar's scheme */}\n <div className={menuSlot} data-visible={menuOpen}>\n <Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n <Card className={menuCard} radius={2} scheme=\"dark\">\n <MenuButton\n button={\n <Button\n aria-label={`Show more for ${title}`}\n fontSize={1}\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n padding={1}\n radius={2}\n />\n }\n id={`themer-theme-${theme.slug}`}\n menu={\n <Menu>\n <MenuItem\n disabled={index <= 0}\n icon={ArrowUpIcon}\n onClick={() => moveTo(index - 1)}\n text=\"Move up\"\n />\n <MenuItem\n disabled={index >= themes.length - 1}\n icon={ArrowDownIcon}\n onClick={() => moveTo(index + 1)}\n text=\"Move down\"\n />\n <MenuDivider />\n {theme.source === 'custom' && (\n <MenuItem\n icon={EditIcon}\n onClick={() => send({type: 'theme.edit', slug: theme.slug})}\n text=\"Edit\"\n />\n )}\n <MenuItem\n icon={CopyIcon}\n onClick={() => send({type: 'theme.duplicate', slug: theme.slug})}\n text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n />\n <MenuItem\n icon={ShareIcon}\n onClick={() => void copyTheme(theme)}\n text=\"Copy to share\"\n />\n {theme.source !== 'config' && (\n <>\n <MenuDivider />\n <MenuItem\n icon={TrashIcon}\n onClick={() => send({type: 'theme.remove', slug: theme.slug})}\n text=\"Remove\"\n tone=\"critical\"\n />\n </>\n )}\n </Menu>\n }\n onClose={() => setMenuOpen(false)}\n onOpen={() => setMenuOpen(true)}\n popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n />\n </Card>\n </Tooltip>\n </div>\n </Reorder.Item>","active ? scrollRefIntoViewIfNeeded : undefined","Reorder.Item","candidate","_c","_temp","frame","_Fragment","(palette, file) =>\n send({\n type: 'theme.add',\n title: titleFromFileName(file.name),\n options: optionsFromImagePalette(palette),\n palette,\n imageUrl: URL.createObjectURL(file),\n })","(order: string[]) => send({type: 'theme.reorder', order})","themes.map((theme) => theme.slug)","(theme) => theme.slug","themes.map((theme) => (\n <ThemeCard active={theme.slug === active.slug} key={theme.slug} theme={theme} />\n ))","active.slug","(theme) => (\n <ThemeCard active={theme.slug === active.slug} key={theme.slug} theme={theme} />\n )","theme","<MotionConfig reducedMotion=\"user\">\n <Reorder.Group\n as=\"div\"\n className={cardGrid}\n onReorder={(order: string[]) => send({type: 'theme.reorder', order})}\n values={themes.map((theme) => theme.slug)}\n >\n {themes.map((theme) => (\n <ThemeCard active={theme.slug === active.slug} key={theme.slug} theme={theme} />\n ))}\n </Reorder.Group>\n </MotionConfig>","Reorder.Group","removed.length > 0 && (\n <Button\n gap={2}\n icon={RestoreIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.removed'})}\n padding={2}\n text={`Show removed (${removed.length})`}\n width=\"fill\"\n />\n )","length","<ScrollArea padding={3}>\n <Stack gap={4}>\n {/* The group tells a column from a grid by measuring the cards, and\n lets go of the layout animations for users who prefer reduced motion */}\n <MotionConfig reducedMotion=\"user\">\n <Reorder.Group\n as=\"div\"\n className={cardGrid}\n onReorder={(order: string[]) => send({type: 'theme.reorder', order})}\n values={themes.map((theme) => theme.slug)}\n >\n {themes.map((theme) => (\n <ThemeCard active={theme.slug === active.slug} key={theme.slug} theme={theme} />\n ))}\n </Reorder.Group>\n </MotionConfig>\n {/* Trails the list rather than sitting in the footer, so the footer\n does not shift when the first theme gets removed */}\n {removed.length > 0 && (\n <Button\n gap={2}\n icon={RestoreIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.removed'})}\n padding={2}\n text={`Show removed (${removed.length})`}\n width=\"fill\"\n />\n )}\n </Stack>\n </ScrollArea>","<Box flex={1}>\n <TooltipButton\n icon={AddIcon}\n mode=\"ghost\"\n onClick={() => send({type: 'theme.add'})}\n text=\"Add theme\"\n tooltip=\"Add a theme based on the applied one\"\n width=\"fill\"\n />\n </Box>","<ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n tooltip=\"Add a theme from the colors of an image\"\n />","<TooltipButton\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={async () => {\n // Straight from the clipboard where the browser allows; by hand otherwise\n if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n }}\n tooltip=\"Add a theme from a code someone shared\"\n />","<Card borderTop padding={3}>\n <Flex gap={2}>\n <Box flex={1}>\n <TooltipButton\n icon={AddIcon}\n mode=\"ghost\"\n onClick={() => send({type: 'theme.add'})}\n text=\"Add theme\"\n tooltip=\"Add a theme based on the applied one\"\n width=\"fill\"\n />\n </Box>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n tooltip=\"Add a theme from the colors of an image\"\n />\n <TooltipButton\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={async () => {\n // Straight from the clipboard where the browser allows; by hand otherwise\n if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n }}\n tooltip=\"Add a theme from a code someone shared\"\n />\n </Flex>\n </Card>","pasting && <PasteThemeDialog onClose={() => setPasting(false)} />","<>\n <ScrollArea padding={3}>\n <Stack gap={4}>\n {/* The group tells a column from a grid by measuring the cards, and\n lets go of the layout animations for users who prefer reduced motion */}\n <MotionConfig reducedMotion=\"user\">\n <Reorder.Group\n as=\"div\"\n className={cardGrid}\n onReorder={(order: string[]) => send({type: 'theme.reorder', order})}\n values={themes.map((theme) => theme.slug)}\n >\n {themes.map((theme) => (\n <ThemeCard active={theme.slug === active.slug} key={theme.slug} theme={theme} />\n ))}\n </Reorder.Group>\n </MotionConfig>\n {/* Trails the list rather than sitting in the footer, so the footer\n does not shift when the first theme gets removed */}\n {removed.length > 0 && (\n <Button\n gap={2}\n icon={RestoreIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.removed'})}\n padding={2}\n text={`Show removed (${removed.length})`}\n width=\"fill\"\n />\n )}\n </Stack>\n </ScrollArea>\n\n <Card borderTop padding={3}>\n <Flex gap={2}>\n <Box flex={1}>\n <TooltipButton\n icon={AddIcon}\n mode=\"ghost\"\n onClick={() => send({type: 'theme.add'})}\n text=\"Add theme\"\n tooltip=\"Add a theme based on the applied one\"\n width=\"fill\"\n />\n </Box>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n tooltip=\"Add a theme from the colors of an image\"\n />\n <TooltipButton\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={async () => {\n // Straight from the clipboard where the browser allows; by hand otherwise\n if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n }}\n tooltip=\"Add a theme from a code someone shared\"\n />\n </Flex>\n </Card>\n\n {pasting && <PasteThemeDialog onClose={() => setPasting(false)} />}\n </>","_c","_Fragment","createThemeSnippet(theme.options)","options","async () => {\n try {\n await navigator.clipboard.writeText(snippet)\n toast.push({status: 'success', title: 'Copied the theme to the clipboard'})\n } catch {\n toast.push({status: 'error', title: 'Could not copy the theme'})\n }\n }","<Flex gap={2} justify=\"flex-end\" padding={3}>\n <Button\n gap={2}\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={() => void handleCopy()}\n padding={2}\n text=\"Copy\"\n />\n </Flex>","<code>sanity.config.ts</code>","<code>theme</code>","<code>defineConfig</code>","displayTitle(theme.title)","title","<Text muted size={1}>\n Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n this tool.\n </Text>","<Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={1}>\n {snippet}\n </Code>\n </Card>","<Box padding={4}>\n <Stack gap={4}>\n <Text muted size={1}>\n Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n this tool.\n </Text>\n <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={1}>\n {snippet}\n </Code>\n </Card>\n </Stack>\n </Box>","<Dialog\n animate\n footer={\n <Flex gap={2} justify=\"flex-end\" padding={3}>\n <Button\n gap={2}\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={() => void handleCopy()}\n padding={2}\n text=\"Copy\"\n />\n </Flex>\n }\n header=\"Add to your config\"\n id=\"themer-snippet\"\n onClickOutside={onClose}\n onClose={onClose}\n width={1}\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Text muted size={1}>\n Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n this tool.\n </Text>\n <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={1}>\n {snippet}\n </Code>\n </Card>\n </Stack>\n </Box>\n </Dialog>","_c","navbarHeight === null ? undefined : {height: navbarHeight}","!inList && (\n <TooltipButton\n icon={ArrowLeftIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.list'})}\n padding={2}\n tooltip=\"Back to the themes\"\n />\n )","<Box className={title} flex={1}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n {VIEW_TITLES[view.name]}\n </Text>\n </Box>","VIEW_TITLES[view.name]","view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )","name","<TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />","<Flex>\n {view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )}\n <TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />\n </Flex>","<Flex align=\"center\" gap={1} height=\"fill\">\n {!inList && (\n <TooltipButton\n icon={ArrowLeftIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.list'})}\n padding={2}\n tooltip=\"Back to the themes\"\n />\n )}\n <Box className={title} flex={1}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n {VIEW_TITLES[view.name]}\n </Text>\n </Box>\n {/* Packed without gaps, so the title still fits next to them at the\n narrowest sidebar width */}\n <Flex>\n {view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )}\n <TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />\n </Flex>\n </Flex>","<Card\n borderBottom\n padding={3}\n sizing=\"border\"\n style={navbarHeight === null ? undefined : {height: navbarHeight}}\n >\n <Flex align=\"center\" gap={1} height=\"fill\">\n {!inList && (\n <TooltipButton\n icon={ArrowLeftIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.list'})}\n padding={2}\n tooltip=\"Back to the themes\"\n />\n )}\n <Box className={title} flex={1}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n {VIEW_TITLES[view.name]}\n </Text>\n </Box>\n {/* Packed without gaps, so the title still fits next to them at the\n narrowest sidebar width */}\n <Flex>\n {view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )}\n <TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />\n </Flex>\n </Flex>\n </Card>","view.name === 'list' && <ThemeList />","view.name === 'edit' && <ThemeEditor focusTitle={view.focusTitle} slug={view.slug} />","focusTitle","slug","view.name === 'removed' && <RemovedThemes />","<Flex direction=\"column\" height=\"fill\">\n {/* The header sits next to the Studio navbar and takes its height, so\n the two bottom borders line up — whatever height the Studio, its\n breakpoint or a custom navbar gives it */}\n <Card\n borderBottom\n padding={3}\n sizing=\"border\"\n style={navbarHeight === null ? undefined : {height: navbarHeight}}\n >\n <Flex align=\"center\" gap={1} height=\"fill\">\n {!inList && (\n <TooltipButton\n icon={ArrowLeftIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.list'})}\n padding={2}\n tooltip=\"Back to the themes\"\n />\n )}\n <Box className={title} flex={1}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n {VIEW_TITLES[view.name]}\n </Text>\n </Box>\n {/* Packed without gaps, so the title still fits next to them at the\n narrowest sidebar width */}\n <Flex>\n {view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )}\n <TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />\n </Flex>\n </Flex>\n </Card>\n\n {view.name === 'list' && <ThemeList />}\n {view.name === 'edit' && <ThemeEditor focusTitle={view.focusTitle} slug={view.slug} />}\n {view.name === 'removed' && <RemovedThemes />}\n </Flex>","snippetOpen && <ThemeSnippetDialog onClose={() => setSnippetOpen(false)} theme={active} />","<Card height=\"fill\">\n <Flex direction=\"column\" height=\"fill\">\n {/* The header sits next to the Studio navbar and takes its height, so\n the two bottom borders line up — whatever height the Studio, its\n breakpoint or a custom navbar gives it */}\n <Card\n borderBottom\n padding={3}\n sizing=\"border\"\n style={navbarHeight === null ? undefined : {height: navbarHeight}}\n >\n <Flex align=\"center\" gap={1} height=\"fill\">\n {!inList && (\n <TooltipButton\n icon={ArrowLeftIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.list'})}\n padding={2}\n tooltip=\"Back to the themes\"\n />\n )}\n <Box className={title} flex={1}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n {VIEW_TITLES[view.name]}\n </Text>\n </Box>\n {/* Packed without gaps, so the title still fits next to them at the\n narrowest sidebar width */}\n <Flex>\n {view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )}\n <TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />\n </Flex>\n </Flex>\n </Card>\n\n {view.name === 'list' && <ThemeList />}\n {view.name === 'edit' && <ThemeEditor focusTitle={view.focusTitle} slug={view.slug} />}\n {view.name === 'removed' && <RemovedThemes />}\n </Flex>\n\n {snippetOpen && <ThemeSnippetDialog onClose={() => setSnippetOpen(false)} theme={active} />}\n </Card>","_c","_Fragment","() => writeStoredWidth(width)","[width]","(event: React.PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return\n\n event.preventDefault()\n event.currentTarget.setPointerCapture(event.pointerId)\n drag.current = {pointerId: event.pointerId, startX: event.clientX, startWidth: width}\n setDragging(true)\n }","useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return\n\n event.preventDefault()\n event.currentTarget.setPointerCapture(event.pointerId)\n drag.current = {pointerId: event.pointerId, startX: event.clientX, startWidth: width}\n setDragging(true)\n },\n [width],\n )","(event: React.PointerEvent<HTMLDivElement>) => {\n if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n // The sidebar sits on the right, so dragging left makes it wider\n setWidth(clampWidth(drag.current.startWidth - (event.clientX - drag.current.startX)))\n }","event","useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n // The sidebar sits on the right, so dragging left makes it wider\n setWidth(clampWidth(drag.current.startWidth - (event.clientX - drag.current.startX)))\n }, [])","(event: React.PointerEvent<HTMLDivElement>) => {\n if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n drag.current = null\n setDragging(false)\n }","useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n drag.current = null\n setDragging(false)\n }, [])","(event: React.KeyboardEvent<HTMLDivElement>) => {\n const steps: Record<string, number> = {\n ArrowLeft: KEYBOARD_STEP,\n ArrowRight: -KEYBOARD_STEP,\n Home: MAXIMUM_WIDTH,\n End: -MAXIMUM_WIDTH,\n }\n const step = steps[event.key]\n\n if (step === undefined) return\n\n event.preventDefault()\n setWidth((current) => clampWidth(current + step))\n }","useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n const steps: Record<string, number> = {\n ArrowLeft: KEYBOARD_STEP,\n ArrowRight: -KEYBOARD_STEP,\n Home: MAXIMUM_WIDTH,\n End: -MAXIMUM_WIDTH,\n }\n const step = steps[event.key]\n\n if (step === undefined) return\n\n event.preventDefault()\n setWidth((current) => clampWidth(current + step))\n }, [])","overlay ? undefined : {width}","!overlay && (\n <div\n aria-label=\"Resize the themer\"\n className={resizeHandle}\n aria-orientation=\"vertical\"\n aria-valuemax={MAXIMUM_WIDTH}\n aria-valuemin={MINIMUM_WIDTH}\n aria-valuenow={width}\n data-dragging={dragging}\n onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n onKeyDown={handleKeyDown}\n onPointerCancel={handlePointerUp}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n role=\"separator\"\n tabIndex={0}\n />\n )","<Box className={content} height=\"fill\" overflow=\"hidden\">\n <ThemerSidebar />\n </Box>","<Card borderLeft={!overlay} className={frame} height=\"fill\">\n {!overlay && (\n <div\n aria-label=\"Resize the themer\"\n className={resizeHandle}\n aria-orientation=\"vertical\"\n aria-valuemax={MAXIMUM_WIDTH}\n aria-valuemin={MINIMUM_WIDTH}\n aria-valuenow={width}\n data-dragging={dragging}\n onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n onKeyDown={handleKeyDown}\n onPointerCancel={handlePointerUp}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n role=\"separator\"\n tabIndex={0}\n />\n )}\n <Box className={content} height=\"fill\" overflow=\"hidden\">\n <ThemerSidebar />\n </Box>\n </Card>","!overlay","<Layer\n className={sidebar}\n data-overlay={overlay}\n style={overlay ? undefined : {width}}\n zOffset={100}\n >\n <Card borderLeft={!overlay} className={frame} height=\"fill\">\n {!overlay && (\n <div\n aria-label=\"Resize the themer\"\n className={resizeHandle}\n aria-orientation=\"vertical\"\n aria-valuemax={MAXIMUM_WIDTH}\n aria-valuemin={MINIMUM_WIDTH}\n aria-valuenow={width}\n data-dragging={dragging}\n onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n onKeyDown={handleKeyDown}\n onPointerCancel={handlePointerUp}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n role=\"separator\"\n tabIndex={0}\n />\n )}\n <Box className={content} height=\"fill\" overflow=\"hidden\">\n <ThemerSidebar />\n </Box>\n </Card>\n </Layer>","_c"],"sources":["../src/tool/ScrollArea.css.ts","../src/tool/ScrollArea.tsx","../src/tool/ThemePreview.css.ts","../src/tool/ThemePreview.tsx","../src/tool/ThemeThumbnail.tsx","../src/tool/RemovedThemes.css.ts","../src/tool/RemovedThemes.tsx","../src/tool/TooltipButton.tsx","../src/tool/ImageFileButton.tsx","../src/tool/imageFile.ts","../src/tool/useImagePalette.ts","../src/tool/ImagePaletteSection.css.ts","../src/tool/ImagePaletteSection.tsx","../src/tool/ThemeEditor.css.ts","../src/tool/ThemeEditor.tsx","../src/tool/share.ts","../src/tool/useThemeCodes.ts","../src/tool/PasteThemeDialog.tsx","../src/tool/ThemeCard.css.ts","../src/tool/ThemeCard.tsx","../src/tool/ThemeList.css.ts","../src/tool/ThemeList.tsx","../src/tool/snippet.ts","../src/tool/ThemeSnippetDialog.tsx","../src/tool/ThemerSidebar.css.ts","../src/tool/ThemerSidebar.tsx","../src/tool/ResizableSidebar.css.ts","../src/tool/ResizableSidebar.tsx"],"sourcesContent":["import {style} from '@vanilla-extract/css'\n\n/** Always reserves the scrollbar's space, so the content never shifts */\nexport const root = style({\n scrollbarGutter: 'stable',\n})\n","import {Box, useTheme_v2} from '@sanity/ui'\nimport {createContext, useContext, useEffect, useMemo, useRef, useState} from 'react'\n\nimport {root} from './ScrollArea.css'\n\n/** How far the content of a scroll area sits from its edges, in pixels */\ninterface ScrollAreaInset {\n left: number\n right: number\n bottom: number\n}\n\nconst ScrollAreaInsetContext = createContext<ScrollAreaInset>({left: 0, right: 0, bottom: 0})\n\n/**\n * The gutter the last scroll area measured. It is the same for every scroll\n * area (the reserved gutter does not depend on the content), so the next one\n * starts out with the right padding instead of shifting after its first\n * measurement — which would also throw off anything scrolling into view as\n * the content mounts.\n */\nlet lastGutter = 0\n\n/**\n * The scrolling body of a sidebar flow. It always reserves the scrollbar's\n * space, so the content does not shift when the list grows or shrinks past\n * the point where it needs to scroll — and it takes that space out of its\n * right padding, so the content stays centered rather than hugging the left.\n * With overlay scrollbars there is no gutter and the padding stays even.\n *\n * @internal\n */\nexport function ScrollArea(props: {children: React.ReactNode; padding: number}) {\n const {children, padding} = props\n const {space} = useTheme_v2()\n const ref = useRef<HTMLDivElement | null>(null)\n const [gutter, setGutter] = useState(() => lastGutter)\n\n useEffect(() => {\n const element = ref.current\n\n if (!element) return undefined\n\n // The reserved gutter is the part of the box the content cannot use\n const measure = () => {\n lastGutter = element.offsetWidth - element.clientWidth\n setGutter(lastGutter)\n }\n\n measure()\n\n const observer = new ResizeObserver(measure)\n\n observer.observe(element)\n\n return () => observer.disconnect()\n }, [])\n\n const inset = useMemo<ScrollAreaInset>(\n () => ({\n left: space[padding],\n right: Math.max(0, space[padding] - gutter),\n bottom: space[padding],\n }),\n [gutter, padding, space],\n )\n\n return (\n <Box\n className={root}\n flex={1}\n overflow=\"auto\"\n padding={padding}\n ref={ref}\n style={{paddingRight: inset.right}}\n >\n <ScrollAreaInsetContext.Provider value={inset}>{children}</ScrollAreaInsetContext.Provider>\n </Box>\n )\n}\n\n/**\n * Content that runs edge to edge in a scroll area — up to the scrollbar —\n * instead of sitting inside its padding. It goes last: it runs down to the\n * bottom edge too.\n *\n * @internal\n */\nexport function ScrollAreaBleed(props: {children: React.ReactNode}) {\n const {left, right, bottom} = useContext(ScrollAreaInsetContext)\n\n return (\n <div style={{marginLeft: -left, marginRight: -right, marginBottom: -bottom}}>\n {props.children}\n </div>\n )\n}\n","import {createVar, style, styleVariants} from '@vanilla-extract/css'\n\n/**\n * The dark scheme covers the right side of the preview behind a diagonal cut,\n * like the \"Auto\" appearance preview in macOS System Settings shows both\n * schemes at once.\n */\nconst DARK_CLIP_PATH = 'polygon(58% 0, 100% 0, 100% 100%, 42% 100%)'\n\n/** The thickness of a line of text — bold enough to survive a half-size preview */\nconst LINE = 4\n\n/**\n * The colors a mockup paints with — only the ones the theme options change —\n * assigned per color scheme from the theme it previews\n */\nexport const colors = {\n bg: createVar(),\n fg: createVar(),\n mutedFg: createVar(),\n border: createVar(),\n accent: createVar(),\n avatar: createVar(),\n selectedBg: createVar(),\n selectedFg: createVar(),\n inputBg: createVar(),\n inputBorder: createVar(),\n}\n\nexport const root = style({\n position: 'relative',\n aspectRatio: '16 / 9',\n overflow: 'hidden',\n})\n\nconst studioBase = style({\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n background: colors.bg,\n})\n\nexport const studio = styleVariants({\n light: [studioBase],\n dark: [studioBase, {clipPath: DARK_CLIP_PATH}],\n})\n\nexport const navbar = style({\n flex: 'none',\n display: 'flex',\n alignItems: 'center',\n gap: 5,\n height: '18%',\n padding: '0 5%',\n borderBottom: `1px solid ${colors.border}`,\n})\n\nexport const logo = style({\n flex: 'none',\n width: 8,\n height: 8,\n borderRadius: 2,\n background: colors.accent,\n})\n\nexport const spacer = style({\n flex: 1,\n})\n\nexport const avatar = style({\n flex: 'none',\n width: 8,\n height: 8,\n borderRadius: '50%',\n background: colors.avatar,\n})\n\nexport const body = style({\n flex: 1,\n display: 'flex',\n minHeight: 0,\n})\n\nexport const list = style({\n flex: 'none',\n display: 'flex',\n flexDirection: 'column',\n width: '36%',\n borderRight: `1px solid ${colors.border}`,\n})\n\nexport const listRow = style({\n flex: 'none',\n display: 'flex',\n alignItems: 'center',\n height: '18%',\n padding: '0 9%',\n selectors: {\n \"&[data-selected='true']\": {\n background: colors.selectedBg,\n },\n },\n})\n\nexport const pane = style({\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n minWidth: 0,\n})\n\nexport const form = style({\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n gap: 7,\n padding: '9% 8% 0',\n minHeight: 0,\n overflow: 'hidden',\n})\n\nexport const field = style({\n flex: 'none',\n display: 'flex',\n flexDirection: 'column',\n gap: 3,\n})\n\nexport const input = style({\n height: 12,\n borderRadius: 3,\n background: colors.inputBg,\n boxShadow: `inset 0 0 0 1px ${colors.inputBorder}`,\n})\n\nexport const footer = style({\n flex: 'none',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'flex-end',\n height: '20%',\n padding: '0 8%',\n borderTop: `1px solid ${colors.border}`,\n})\n\nexport const button = style({\n width: '32%',\n height: '50%',\n borderRadius: 3,\n background: colors.accent,\n})\n\nconst lineBase = style({\n flex: 'none',\n height: LINE,\n borderRadius: LINE / 2,\n})\n\n/** A line of text, in one of the text colors — its width is set inline */\nexport const line = styleVariants({\n fg: [lineBase, {background: colors.fg}],\n muted: [lineBase, {background: colors.mutedFg}],\n selected: [lineBase, {background: colors.selectedFg}],\n})\n","import {ThemeProvider, useTheme_v2} from '@sanity/ui'\nimport {type ThemeColorSchemeKey} from '@sanity/ui/theme'\nimport {assignInlineVars} from '@vanilla-extract/dynamic'\nimport {useMemo} from 'react'\n\nimport {buildTheme} from '../theme/buildTheme'\nimport type {BuildThemeOptions} from '../theme/options'\n\nimport {\n avatar,\n body,\n button,\n colors,\n field,\n footer,\n form,\n input,\n line,\n list,\n listRow,\n logo,\n navbar,\n pane,\n root,\n spacer,\n studio,\n} from './ThemePreview.css'\n\n/** The document rows in the list pane — the widths of their title lines */\nconst LIST_ROWS = ['62%', '46%', '70%', '52%']\n\n/** The fields in the document form — the widths of their labels */\nconst FIELDS = ['32%', '24%']\n\n/**\n * A tiny, lo-fi mockup of a Studio in the given theme — the navbar over the\n * structure tool with a list of documents on the left and a document form on\n * the right — in both color schemes at once: the light scheme on the left and\n * the dark scheme on the right, split diagonally. It only paints colors the\n * theme options change (backgrounds, text, borders, the accent) so that a\n * glance shows what the theme does to the Studio — with few and bold enough\n * elements to still read when scaled down to a thumbnail.\n *\n * @internal\n */\nexport function ThemePreview(props: {options: BuildThemeOptions}) {\n const {options} = props\n const theme = useMemo(() => buildTheme(options), [options])\n\n return (\n <div aria-hidden className={root}>\n <ThemeProvider scheme=\"light\" theme={theme} tone=\"default\">\n <MockStudio scheme=\"light\" />\n </ThemeProvider>\n <ThemeProvider scheme=\"dark\" theme={theme} tone=\"default\">\n <MockStudio scheme=\"dark\" />\n </ThemeProvider>\n </div>\n )\n}\n\nfunction MockStudio(props: {scheme: ThemeColorSchemeKey}) {\n const {scheme} = props\n const {color} = useTheme_v2()\n const selected = color.selectable.default.selected\n const inputColor = color.input.default.enabled\n\n return (\n <div\n className={studio[scheme]}\n style={assignInlineVars({\n [colors.bg]: color.bg,\n [colors.fg]: color.fg,\n [colors.mutedFg]: color.muted.fg,\n [colors.border]: color.border,\n [colors.accent]: color.button.default.primary.enabled.bg,\n [colors.avatar]: color.avatar.blue.bg,\n [colors.selectedBg]: selected.bg,\n [colors.selectedFg]: selected.fg,\n [colors.inputBg]: inputColor.bg,\n [colors.inputBorder]: inputColor.border,\n })}\n >\n <div className={navbar}>\n <div className={logo} />\n <div className={line.fg} style={{width: '22%'}} />\n <div className={spacer} />\n <div className={avatar} />\n </div>\n\n <div className={body}>\n <div className={list}>\n {LIST_ROWS.map((width, index) => {\n const isSelected = index === 1\n\n return (\n <div className={listRow} data-selected={isSelected} key={width}>\n <div className={isSelected ? line.selected : line.muted} style={{width}} />\n </div>\n )\n })}\n </div>\n\n <div className={pane}>\n <div className={form}>\n <div className={line.fg} style={{width: '45%'}} />\n {FIELDS.map((width) => (\n <div className={field} key={width}>\n <div className={line.muted} style={{width}} />\n <div className={input} />\n </div>\n ))}\n </div>\n <div className={footer}>\n <div className={button} />\n </div>\n </div>\n </div>\n </div>\n )\n}\n","import {Card} from '@sanity/ui'\n\nimport type {BuildThemeOptions} from '../theme/options'\nimport {ThemePreview} from './ThemePreview'\n\n/**\n * The floating preview card of a theme: the lo-fi studio mockup on a raised,\n * rounded card, like the appearance previews in macOS System Settings.\n *\n * @internal\n */\nexport function ThemeThumbnail(props: {options: BuildThemeOptions}) {\n return (\n <Card overflow=\"hidden\" radius={3} shadow={1}>\n <ThemePreview options={props.options} />\n </Card>\n )\n}\n","import {style} from '@vanilla-extract/css'\n\n/** A removed theme's thumbnail, dimmed to read as removed */\nexport const removedThumbnail = style({\n opacity: 0.6,\n})\n","import {Box, Button, Flex, Stack, Text} from '@sanity/ui'\n\nimport {useThemer} from './context'\nimport {ScrollArea} from './ScrollArea'\nimport {displayTitle} from './themes'\nimport {ThemeThumbnail} from './ThemeThumbnail'\n\nimport {removedThumbnail} from './RemovedThemes.css'\n\n/**\n * The flow for restoring removed themes: the presets and custom themes the\n * user took out of the list, each with a button to put it back — and, for\n * custom themes, one to delete it for good. The machine leaves the flow once\n * the last one is gone.\n *\n * @internal\n */\nexport function RemovedThemes() {\n const {removed, send} = useThemer()\n\n return (\n <ScrollArea padding={3}>\n <Stack gap={5}>\n {removed.map((theme) => (\n <Stack gap={3} key={theme.slug}>\n <Box className={removedThumbnail}>\n <ThemeThumbnail options={theme.options} />\n </Box>\n <Text align=\"center\" size={1} textOverflow=\"ellipsis\">\n {displayTitle(theme.title)}\n </Text>\n <Flex gap={2} justify=\"center\">\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.restore', slug: theme.slug})}\n padding={2}\n text=\"Restore\"\n />\n {theme.source === 'custom' && (\n <Button\n mode=\"ghost\"\n onClick={() => send({type: 'theme.delete', slug: theme.slug})}\n padding={2}\n text=\"Delete\"\n tone=\"critical\"\n />\n )}\n </Flex>\n </Stack>\n ))}\n </Stack>\n </ScrollArea>\n )\n}\n","import {Button, type ButtonProps, Text} from '@sanity/ui'\nimport {Tooltip} from '@sanity/ui/tooltip'\n\n/**\n * A button with an animated tooltip instead of a `title` attribute, sized like\n * the Studio's own buttons (`padding` and `gap` of 2). Icon-only buttons take\n * the tooltip as their accessible name.\n *\n * @internal\n */\nexport function TooltipButton(props: ButtonProps & {tooltip: string}) {\n const {tooltip, ...buttonProps} = props\n\n return (\n <Tooltip animate content={<Text size={1}>{tooltip}</Text>} placement=\"bottom\" portal>\n <Button\n aria-label={buttonProps.text === undefined ? tooltip : undefined}\n gap={2}\n padding={2}\n {...buttonProps}\n />\n </Tooltip>\n )\n}\n","import {ImageIcon} from '@sanity/icons/Image'\nimport type {ButtonProps} from '@sanity/ui'\nimport {useRef} from 'react'\n\nimport {TooltipButton} from './TooltipButton'\n\n/**\n * A button that opens the file picker for an image, and hands the chosen file\n * over — the picker is a hidden file input, so nothing is uploaded anywhere.\n *\n * @internal\n */\nexport function ImageFileButton(\n props: {onFile: (file: File) => void; tooltip: string} & Pick<\n ButtonProps,\n 'disabled' | 'loading' | 'mode' | 'padding' | 'text' | 'width'\n >,\n) {\n const {onFile, ...buttonProps} = props\n const inputRef = useRef<HTMLInputElement | null>(null)\n\n return (\n <>\n <TooltipButton {...buttonProps} icon={ImageIcon} onClick={() => inputRef.current?.click()} />\n <input\n accept=\"image/*\"\n hidden\n onChange={(event) => {\n const file = event.currentTarget.files?.[0]\n\n // Picking the same file again should work, so the input forgets it\n event.currentTarget.value = ''\n\n if (file) onFile(file)\n }}\n ref={inputRef}\n type=\"file\"\n />\n </>\n )\n}\n","import type {PixelData} from './imagePalette'\n\n/**\n * The longest side the image is scaled down to before its colors are read —\n * a few thousand pixels are plenty for a palette, and keep it instant\n */\nconst SAMPLE_SIZE = 96\n\n/**\n * Reads the pixels of an image file on device: the image is decoded, drawn\n * onto a small canvas and read back, so nothing leaves the browser.\n *\n * @internal\n */\nexport async function readImagePixels(file: Blob): Promise<PixelData> {\n const image = await decodeImage(file)\n\n try {\n const scale = Math.min(1, SAMPLE_SIZE / Math.max(image.width, image.height))\n const width = Math.max(1, Math.round(image.width * scale))\n const height = Math.max(1, Math.round(image.height * scale))\n const canvas = document.createElement('canvas')\n\n canvas.width = width\n canvas.height = height\n\n const context = canvas.getContext('2d', {willReadFrequently: true})\n\n if (!context) throw new Error('Could not draw the image')\n\n context.drawImage(image, 0, 0, width, height)\n\n return {data: context.getImageData(0, 0, width, height).data, width, height}\n } finally {\n // Where `createImageBitmap` is missing, `ImageBitmap` may be too\n if (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) image.close()\n }\n}\n\nasync function decodeImage(file: Blob): Promise<ImageBitmap | HTMLImageElement> {\n if (typeof createImageBitmap === 'function') {\n try {\n return await createImageBitmap(file)\n } catch {\n // Some browsers cannot decode every format this way (e.g. SVG) — an\n // image element handles whatever the browser can display\n }\n }\n\n const url = URL.createObjectURL(file)\n\n try {\n return await new Promise<HTMLImageElement>((resolve, reject) => {\n const image = new Image()\n\n image.addEventListener('load', () => resolve(image), {once: true})\n image.addEventListener('error', () => reject(new Error('Could not decode the image')), {\n once: true,\n })\n image.src = url\n })\n } finally {\n URL.revokeObjectURL(url)\n }\n}\n","import {useToast} from '@sanity/ui/toast'\nimport {useCallback, useEffect, useRef, useState} from 'react'\n\nimport {readImagePixels} from './imageFile'\nimport {extractImagePalette, type ImagePalette} from './imagePalette'\n\n/**\n * Extracts the palette of image files on device and hands it to `onPalette`,\n * along with the file it came from. Failures end up as a toast.\n *\n * @internal\n */\nexport function useImagePalette(onPalette: (palette: ImagePalette, file: File) => void): {\n busy: boolean\n pickImage: (file: File) => void\n} {\n const toast = useToast()\n const [busy, setBusy] = useState(false)\n const onPaletteRef = useRef(onPalette)\n const mountedRef = useRef(true)\n // Picks are numbered so that a slow earlier image cannot overwrite a later\n // pick once its extraction finishes\n const latestPickRef = useRef(0)\n\n useEffect(() => {\n onPaletteRef.current = onPalette\n }, [onPalette])\n\n useEffect(() => {\n mountedRef.current = true\n\n return () => {\n mountedRef.current = false\n }\n }, [])\n\n const pickImage = useCallback(\n (file: File) => {\n const pick = ++latestPickRef.current\n\n setBusy(true)\n\n // Whether this pick still matters: it is the latest one and the\n // component that asked for it is still around\n const isCurrent = () => mountedRef.current && latestPickRef.current === pick\n\n const extract = async () => {\n const palette = extractImagePalette(await readImagePixels(file))\n\n if (!isCurrent()) return\n\n if (Object.values(palette).every((swatch) => swatch === null)) {\n toast.push({status: 'warning', title: 'Found no colors in that image'})\n } else {\n onPaletteRef.current(palette, file)\n }\n }\n\n extract()\n .catch(() => {\n if (isCurrent()) toast.push({status: 'error', title: 'Could not read that image'})\n })\n .finally(() => {\n if (isCurrent()) setBusy(false)\n })\n },\n [toast],\n )\n\n return {busy, pickImage}\n}\n","import {createVar, style} from '@vanilla-extract/css'\n\nconst TILE_SIZE = 24\nconst TILE_GAP = 4\n\n/** The image spans both rows of tiles */\nconst IMAGE_SIZE = TILE_SIZE * 2 + TILE_GAP\n\n/** The variant previews are the theme thumbnails, laid out at this width and scaled down */\nexport const VARIANT_WIDTH = 144\n\nexport const VARIANT_GAP = 8\nexport const ROW_PADDING = 12\n\n/** The frame around a variant's thumbnail, on either side */\nexport const VARIANT_FRAME = 4\n\n/** The width of one variant's thumbnail, set on the row once it is measured */\nexport const variantWidth = createVar()\n\n/** How much a variant's thumbnail is scaled down from `VARIANT_WIDTH` */\nexport const variantScale = createVar()\n\nexport const paletteGrid = style({\n display: 'grid',\n gridTemplateColumns: `repeat(3, ${TILE_SIZE}px)`,\n gridAutoRows: TILE_SIZE,\n gap: TILE_GAP,\n selectors: {\n \"&[data-with-image='true']\": {\n gridTemplateColumns: `${IMAGE_SIZE}px repeat(3, ${TILE_SIZE}px)`,\n },\n },\n})\n\nexport const imageTile = style({\n display: 'block',\n gridRow: 'span 2',\n width: IMAGE_SIZE,\n height: IMAGE_SIZE,\n borderRadius: 3,\n objectFit: 'cover',\n boxShadow: 'inset 0 0 0 1px var(--card-border-color)',\n})\n\nexport const tile = style({\n display: 'block',\n borderRadius: 3,\n boxShadow: 'inset 0 0 0 1px var(--card-border-color)',\n selectors: {\n \"&[data-empty='true']\": {\n background:\n 'repeating-linear-gradient(-45deg, transparent 0 3px, var(--card-border-color) 3px 4px)',\n },\n },\n})\n\n/**\n * The variants scroll sideways and snap into place, bleeding into the card's\n * padding so the row runs from edge to edge\n */\nexport const variantRow = style({\n display: 'flex',\n gap: VARIANT_GAP,\n margin: `0 -${ROW_PADDING}px`,\n padding: `0 ${ROW_PADDING}px`,\n overflowX: 'auto',\n scrollSnapType: 'x mandatory',\n scrollPaddingLeft: ROW_PADDING,\n scrollbarWidth: 'thin',\n})\n\nexport const variantButton = style({\n 'appearance': 'none',\n 'flex': 'none',\n 'display': 'block',\n 'boxSizing': 'border-box',\n 'width': `calc(${variantWidth} + ${VARIANT_FRAME * 2}px)`,\n 'margin': 0,\n 'padding': 0,\n 'border': 0,\n 'background': 'none',\n 'color': 'inherit',\n 'font': 'inherit',\n 'textAlign': 'center',\n 'cursor': 'pointer',\n 'scrollSnapAlign': 'start',\n ':focus': {\n outline: 'none',\n },\n})\n\n/**\n * Clips the scaled-down thumbnail to its visual size, with room for the ring\n * — drawn inside the frame, like the theme cards', so the scrolling row\n * never clips it\n */\nexport const variantFrame = style({\n display: 'block',\n boxSizing: 'border-box',\n width: `calc(${variantWidth} + ${VARIANT_FRAME * 2}px)`,\n height: `calc(${variantWidth} * 9 / 16 + ${VARIANT_FRAME * 2}px)`,\n padding: VARIANT_FRAME,\n borderRadius: 7,\n overflow: 'hidden',\n transition: 'box-shadow 100ms',\n selectors: {\n [`${variantButton}:hover &`]: {\n boxShadow: 'inset 0 0 0 2px var(--card-border-color)',\n },\n [`${variantButton}[aria-pressed='true'] &`]: {\n boxShadow: 'inset 0 0 0 2px var(--card-focus-ring-color)',\n },\n [`${variantButton}:focus-visible &`]: {\n outline: '2px solid var(--card-focus-ring-color)',\n outlineOffset: -2,\n },\n },\n})\n\nexport const variantScaleBox = style({\n display: 'block',\n width: VARIANT_WIDTH,\n transform: `scale(${variantScale})`,\n transformOrigin: 'top left',\n})\n","import {SparklesIcon} from '@sanity/icons/Sparkles'\nimport {Box, Card, Flex, Stack, Text} from '@sanity/ui'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {assignInlineVars} from '@vanilla-extract/dynamic'\nimport {useEffect, useMemo, useRef, useState} from 'react'\n\nimport type {BuildThemeOptions} from '../theme/options'\nimport {ImageFileButton} from './ImageFileButton'\nimport {\n applyImagePalette,\n currentImageVariant,\n IMAGE_PALETTE_TITLES,\n IMAGE_PALETTE_VARIANTS,\n type ImagePalette,\n type ImagePaletteKey,\n type ImagePaletteVariant,\n} from './imagePalette'\nimport {ThemeThumbnail} from './ThemeThumbnail'\nimport {TooltipButton} from './TooltipButton'\nimport {useImagePalette} from './useImagePalette'\n\nimport {\n imageTile,\n paletteGrid,\n ROW_PADDING,\n tile,\n VARIANT_FRAME,\n VARIANT_GAP,\n VARIANT_WIDTH,\n variantButton,\n variantFrame,\n variantRow,\n variantScale,\n variantScaleBox,\n variantWidth,\n} from './ImagePaletteSection.css'\n\n/** The swatches on display: the vibrant family over the muted one */\nconst TILES: ImagePaletteKey[] = [\n 'vibrant',\n 'lightVibrant',\n 'darkVibrant',\n 'muted',\n 'lightMuted',\n 'darkMuted',\n]\n\n/**\n * How many variants show at once: two and a half, so that the cut-off third\n * one gives away that the row scrolls\n */\nconst VISIBLE_VARIANTS = 2.5\n\n/** The width of one variant, before the row has been measured */\nconst FALLBACK_VARIANT_WIDTH = 58\n\n/**\n * Takes the colors of a theme from an image, on device: the image is read\n * into a canvas and its palette extracted right there — nothing is uploaded.\n * Shows the image (while the session lasts) next to its palette, offers a\n * theme variant built around each swatch as a small preview, and a lucky\n * button that picks an interesting one.\n *\n * @internal\n */\nexport function ImagePaletteSection(props: {\n imageUrl?: string\n onPalette: (palette: ImagePalette, file: File) => void\n onVariant: (variant: ImagePaletteVariant) => void\n onLucky: () => void\n options: BuildThemeOptions\n palette?: ImagePalette\n}) {\n const {imageUrl, onPalette, onVariant, onLucky, options, palette} = props\n const {busy, pickImage} = useImagePalette(onPalette)\n const [dragging, setDragging] = useState(false)\n // `dragleave` also fires when the pointer crosses into a child, so the\n // highlight tracks how deep the drag is rather than the last event\n const dragDepth = useRef(0)\n const current = palette ? currentImageVariant(options, palette) : null\n const rowRef = useRef<HTMLDivElement | null>(null)\n const [thumbnailWidth, setThumbnailWidth] = useState(FALLBACK_VARIANT_WIDTH)\n\n // Size the variants to the row, so two and a half of them are in view\n useEffect(() => {\n const row = rowRef.current\n\n if (!row) return undefined\n\n const measure = () => {\n const visible =\n row.clientWidth - ROW_PADDING - (Math.ceil(VISIBLE_VARIANTS) - 1) * VARIANT_GAP\n\n // Each variant is its thumbnail plus the frame on either side\n setThumbnailWidth(Math.max(24, Math.floor(visible / VISIBLE_VARIANTS) - VARIANT_FRAME * 2))\n }\n\n measure()\n\n const observer = new ResizeObserver(measure)\n\n observer.observe(row)\n\n return () => observer.disconnect()\n // oxlint-disable-next-line react/exhaustive-effect-dependencies -- the row only renders with a palette, so a new palette has a new row to observe\n }, [palette])\n\n const variants = useMemo(() => {\n if (!palette) return []\n\n return IMAGE_PALETTE_VARIANTS.flatMap((variant) =>\n palette[variant] === null\n ? []\n : [\n {\n variant,\n title: IMAGE_PALETTE_TITLES[variant],\n options: applyImagePalette(options, palette, variant),\n },\n ],\n )\n }, [options, palette])\n\n return (\n <Card\n border\n onDragEnter={(event) => {\n event.preventDefault()\n dragDepth.current++\n setDragging(true)\n }}\n onDragLeave={() => {\n dragDepth.current = Math.max(0, dragDepth.current - 1)\n\n if (dragDepth.current === 0) setDragging(false)\n }}\n onDragOver={(event) => {\n event.preventDefault()\n }}\n onDrop={(event) => {\n event.preventDefault()\n dragDepth.current = 0\n setDragging(false)\n\n const file = event.dataTransfer.files[0]\n\n if (file) pickImage(file)\n }}\n padding={3}\n radius={3}\n tone={dragging ? 'primary' : 'default'}\n >\n <Stack gap={3}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n Image palette\n </Text>\n </Box>\n {palette && (\n <ImageFileButton\n loading={busy}\n mode=\"bleed\"\n onFile={pickImage}\n padding={2}\n tooltip=\"Pick another image\"\n />\n )}\n </Flex>\n\n {palette ? (\n <>\n <div className={paletteGrid} data-with-image={imageUrl !== undefined}>\n {imageUrl && <img alt=\"\" className={imageTile} src={imageUrl} />}\n {TILES.map((key) => {\n const hex = palette[key]\n const title = IMAGE_PALETTE_TITLES[key]\n\n return (\n <Tooltip\n animate\n content={\n <Text size={1}>\n {hex ? `${title} · ${hex}` : `No ${title.toLowerCase()} color`}\n </Text>\n }\n key={key}\n placement=\"bottom\"\n portal\n >\n <span\n className={tile}\n data-empty={hex === null}\n style={{background: hex ?? undefined}}\n />\n </Tooltip>\n )\n })}\n </div>\n\n <Stack gap={2}>\n <Text muted size={0}>\n Pick the swatch to build the theme around\n </Text>\n <div\n className={variantRow}\n ref={rowRef}\n style={assignInlineVars({\n [variantWidth]: `${thumbnailWidth}px`,\n [variantScale]: String(thumbnailWidth / VARIANT_WIDTH),\n })}\n >\n {variants.map(({variant, title, options: variantOptions}) => (\n // oxlint-disable-next-line control-has-associated-label -- the title below the thumbnail is the label, deeper than the rule looks\n <button\n aria-pressed={variant === current}\n className={variantButton}\n key={variant}\n onClick={() => onVariant(variant)}\n type=\"button\"\n >\n <span className={variantFrame}>\n <span className={variantScaleBox}>\n <ThemeThumbnail options={variantOptions} />\n </span>\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={1}>\n <Text\n align=\"center\"\n as=\"span\"\n size={0}\n textOverflow=\"ellipsis\"\n weight={variant === current ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>\n ))}\n </div>\n </Stack>\n\n <TooltipButton\n icon={SparklesIcon}\n mode=\"ghost\"\n onClick={onLucky}\n text=\"I'm feeling lucky\"\n tooltip=\"Build the theme around a swatch that looks interesting\"\n width=\"fill\"\n />\n </>\n ) : (\n <Stack gap={3}>\n <Text muted size={0}>\n Take the accent, text and background colors from an image — read on device, nothing is\n uploaded.\n </Text>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n text=\"Pick an image\"\n tooltip=\"Take the colors from an image on your device\"\n width=\"fill\"\n />\n </Stack>\n )}\n </Stack>\n </Card>\n )\n}\n","import {style} from '@vanilla-extract/css'\n\n/** A native color input, trimmed down to its swatch */\nexport const swatch = style({\n boxSizing: 'border-box',\n flex: 'none',\n width: 33,\n height: 33,\n padding: 0,\n border: '1px solid var(--card-border-color)',\n borderRadius: 4,\n background: 'none',\n cursor: 'pointer',\n selectors: {\n '&::-webkit-color-swatch-wrapper': {\n padding: 0,\n },\n '&::-webkit-color-swatch': {\n border: 'none',\n borderRadius: 3,\n },\n '&::-moz-color-swatch': {\n border: 'none',\n borderRadius: 3,\n },\n },\n})\n\n/** A native range input, themed through `accent-color` */\nexport const range = style({\n display: 'block',\n width: '100%',\n margin: 0,\n accentColor: 'var(--card-focus-ring-color)',\n})\n\n/** Lets the color row's text shrink and truncate instead of widening the row */\nexport const colorRowText = style({\n minWidth: 0,\n})\n","import {ResetIcon} from '@sanity/icons/Reset'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {Badge, Box, Button, Card, Flex, Stack, Text, TextInput} from '@sanity/ui'\nimport {type ThemeColorSchemeKey} from '@sanity/ui/theme'\nimport {useMemo} from 'react'\nimport {useColorSchemeValue} from 'sanity'\n\nimport {buildPalette, type GeneratedColorPalette} from '../theme/buildPalette'\nimport {\n type BuildThemeOptions,\n type ResolvedSchemeOptions,\n resolveThemeOptions,\n SCHEMES,\n type SchemeThemeOptions,\n} from '../theme/options'\nimport {useThemer} from './context'\nimport {\n applyImagePalette,\n currentImageVariant,\n type ImagePalette,\n type ImagePaletteVariant,\n pickLuckyVariant,\n} from './imagePalette'\nimport {ImagePaletteSection} from './ImagePaletteSection'\nimport {ScrollArea, ScrollAreaBleed} from './ScrollArea'\nimport {ThemeThumbnail} from './ThemeThumbnail'\nimport {TooltipButton} from './TooltipButton'\n\nimport {colorRowText, range, swatch} from './ThemeEditor.css'\n\nconst SCHEME_TITLES: Record<ThemeColorSchemeKey, string> = {\n dark: 'Dark mode',\n light: 'Light mode',\n}\n\n/**\n * Where the split preview shows a scheme: the Studio's own scheme stays next\n * to the sidebar (or at the bottom, stacked on small screens), the other one\n * takes the far side\n */\nfunction splitHint(own: boolean, mobile: boolean): string {\n if (mobile) return own ? 'Shown at the bottom' : 'Shown at the top'\n\n return own ? 'Shown on the right, next to the themer' : 'Shown on the left'\n}\n\nconst SCHEME_OPTION_KEYS: Array<keyof SchemeThemeOptions> = [\n 'accent',\n 'text',\n 'background',\n 'contrast',\n]\n\n/**\n * `<input type=\"color\">` paints the color into a shadow-DOM swatch that brings\n * its own border and padding, which then sits inside ours as a second border.\n * Stripping that chrome leaves the themed border as the only one.\n */\n/**\n * The flow for editing one of the user's own themes: its title, a live\n * preview, and a card per color scheme with the accent/text/background\n * pickers and the contrast slider of that scheme. Every change applies to the\n * whole Studio right away — in the scheme the Studio is showing, or in both\n * side by side in the split preview.\n *\n * @internal\n */\nexport function ThemeEditor(props: {focusTitle: boolean; slug: string}) {\n const {focusTitle, slug} = props\n const {themes, images, split, mobile, send} = useThemer()\n const theme = themes.find((candidate) => candidate.slug === slug && candidate.source === 'custom')\n\n // The machine only enters the edit flow for a listed custom theme, and\n // leaves it as soon as the theme is removed or deleted\n if (!theme) return null\n\n const applyVariant = (variant: ImagePaletteVariant | null) => {\n if (!theme.palette || variant === null) return\n\n send({\n type: 'theme.update',\n slug,\n options: applyImagePalette(theme.options, theme.palette, variant),\n })\n }\n\n return (\n <ThemeEditorForm\n focusTitle={focusTitle}\n imageUrl={images[slug]}\n onDone={() => send({type: 'flow.list'})}\n onLucky={() => {\n if (!theme.palette) return\n\n applyVariant(\n pickLuckyVariant(theme.palette, {\n exclude: currentImageVariant(theme.options, theme.palette),\n }),\n )\n }}\n onOptionsChange={(options) => send({type: 'theme.update', slug, options})}\n onPalette={(palette, file) =>\n send({\n type: 'theme.update',\n slug,\n options: applyImagePalette(theme.options, palette),\n palette,\n imageUrl: URL.createObjectURL(file),\n })\n }\n onRemove={() => send({type: 'theme.remove', slug})}\n onTitleChange={(title) => send({type: 'theme.update', slug, title})}\n onVariant={applyVariant}\n options={theme.options}\n palette={theme.palette}\n split={split}\n mobile={mobile}\n title={theme.title}\n />\n )\n}\n\n// Split from `ThemeEditor` so that the derived values below can be hooks\n// while the editor bails out early when the theme is gone\nfunction ThemeEditorForm(props: {\n focusTitle: boolean\n imageUrl?: string\n onDone: () => void\n onLucky: () => void\n onOptionsChange: (options: BuildThemeOptions) => void\n onPalette: (palette: ImagePalette, file: File) => void\n onRemove: () => void\n onTitleChange: (title: string) => void\n onVariant: (variant: ImagePaletteVariant) => void\n options: BuildThemeOptions\n palette?: ImagePalette\n /** Whether the Studio shows in light and dark side by side */\n split: boolean\n /** Whether the split preview stacks, on a small screen */\n mobile: boolean\n title: string\n}) {\n const {\n focusTitle,\n imageUrl,\n onDone,\n onLucky,\n onOptionsChange,\n onPalette,\n onRemove,\n onTitleChange,\n onVariant,\n options,\n palette,\n split,\n mobile,\n title,\n } = props\n // The scheme the Studio is showing, with the appearance setting resolved\n const studioScheme = useColorSchemeValue()\n const resolved = useMemo(() => resolveThemeOptions(options), [options])\n const palettes = useMemo(() => buildPalette(options), [options])\n\n const patchScheme = (scheme: ThemeColorSchemeKey, changes: Partial<SchemeThemeOptions>) => {\n const values: SchemeThemeOptions = {...options[scheme], ...changes}\n\n // Clearing an option means falling back to its default, which is its absence\n for (const key of SCHEME_OPTION_KEYS) {\n if (values[key] === undefined) delete values[key]\n }\n\n const next: BuildThemeOptions = {...options}\n\n if (Object.keys(values).length === 0) {\n delete next[scheme]\n } else {\n next[scheme] = values\n }\n\n onOptionsChange(next)\n }\n\n return (\n <>\n <ScrollArea padding={3}>\n <Stack gap={4}>\n <ThemeThumbnail options={options} />\n\n <Stack gap={2}>\n <Text size={1} weight=\"medium\">\n Title\n </Text>\n <TextInput\n autoFocus={focusTitle}\n fontSize={1}\n onChange={(event) => onTitleChange(event.currentTarget.value)}\n onFocus={focusTitle ? (event) => event.currentTarget.select() : undefined}\n padding={2}\n placeholder=\"Untitled theme\"\n value={title}\n />\n </Stack>\n\n <ImagePaletteSection\n imageUrl={imageUrl}\n onLucky={onLucky}\n onPalette={onPalette}\n onVariant={onVariant}\n options={options}\n palette={palette}\n />\n\n <ScrollAreaBleed>\n {SCHEMES.map((scheme) => (\n <SchemeCard\n active={split || scheme === studioScheme}\n key={scheme}\n onChange={(changes) => patchScheme(scheme, changes)}\n options={options[scheme] ?? {}}\n palette={palettes[scheme]}\n resolved={resolved[scheme]}\n scheme={scheme}\n split={split}\n splitHint={splitHint(scheme === studioScheme, mobile)}\n />\n ))}\n </ScrollAreaBleed>\n </Stack>\n </ScrollArea>\n\n <Card borderTop padding={3}>\n <Flex gap={2}>\n <TooltipButton\n icon={TrashIcon}\n mode=\"ghost\"\n onClick={onRemove}\n text=\"Remove\"\n tone=\"critical\"\n tooltip=\"Remove the theme — it can be restored until it is deleted\"\n />\n <Box flex={1} />\n <Button mode=\"ghost\" onClick={onDone} padding={2} text=\"Done\" />\n </Flex>\n </Card>\n </>\n )\n}\n\n/**\n * The colors of one scheme. The cards span the sidebar edge to edge, one\n * after the other with a border between them, in the sidebar's own scheme —\n * the swatches show the colors they edit. The scheme the Studio is showing is\n * marked as active: its changes show up in the Studio right away, the other\n * scheme's only once the appearance setting switches to it — or both are\n * active, in the split preview.\n */\nfunction SchemeCard(props: {\n active: boolean\n onChange: (changes: Partial<SchemeThemeOptions>) => void\n options: SchemeThemeOptions\n palette: GeneratedColorPalette\n resolved: ResolvedSchemeOptions\n scheme: ThemeColorSchemeKey\n split: boolean\n /** Where the split preview shows this scheme */\n splitHint: string\n}) {\n const {active, onChange, options, palette, resolved, scheme, split, splitHint} = props\n const name = SCHEME_TITLES[scheme]\n\n return (\n <Card borderTop padding={3}>\n <Stack gap={4}>\n <Stack gap={2}>\n <Flex align=\"center\" gap={2}>\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n {name}\n </Text>\n </Box>\n {active && (\n <Badge fontSize={0} tone=\"primary\">\n Active\n </Badge>\n )}\n </Flex>\n <Text muted size={0}>\n {split\n ? splitHint\n : active\n ? 'Shown in the Studio right now'\n : `Shown once the Studio appearance is ${scheme}`}\n </Text>\n </Stack>\n\n <ColorRow\n auto={options.accent === undefined}\n autoLabel=\"default\"\n label={`${name} accent`}\n onChange={(accent) => onChange({accent})}\n onClear={() => onChange({accent: undefined})}\n title=\"Accent\"\n value={resolved.accent}\n />\n <ColorRow\n auto={options.text === undefined}\n label={`${name} text`}\n onChange={(text) => onChange({text})}\n onClear={() => onChange({text: undefined})}\n title=\"Text\"\n value={resolved.text}\n />\n <ColorRow\n adjusted={scheme === 'dark' ? palette.black : palette.white}\n auto={options.background === undefined}\n label={`${name} background`}\n onChange={(background) => onChange({background})}\n onClear={() => onChange({background: undefined})}\n title=\"Background\"\n value={resolved.background}\n />\n\n <Stack gap={3}>\n <Flex align=\"center\" gap={2}>\n <Stack flex={1} gap={2}>\n <Text size={1}>Contrast</Text>\n <Text muted size={0}>\n {resolved.contrast}\n {options.contrast === undefined ? ' · auto' : ''}\n </Text>\n </Stack>\n {options.contrast !== undefined && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={() => onChange({contrast: undefined})}\n padding={2}\n tooltip=\"Reset to auto\"\n />\n )}\n </Flex>\n <input\n aria-label={`${name} contrast`}\n className={range}\n max={100}\n min={15}\n onChange={(event) => onChange({contrast: Number(event.currentTarget.value)})}\n step={1}\n type=\"range\"\n value={resolved.contrast}\n />\n <Text muted size={0}>\n 100 keeps text and borders neutral — lower values blend in the accent\n </Text>\n </Stack>\n </Stack>\n </Card>\n )\n}\n\n/** One color of a scheme: a swatch with its value and an optional reset button */\nfunction ColorRow(props: {\n /** The color the generator actually applied, when it may differ from the input */\n adjusted?: string\n /** Whether the value is derived or a default rather than explicitly set */\n auto?: boolean\n /** What the value is when it is not set: derived (`auto`) or the stock one (`default`) */\n autoLabel?: 'auto' | 'default'\n /** The accessible name of the picker */\n label: string\n onChange: (value: string) => void\n onClear?: () => void\n title: string\n value: string\n}) {\n const {adjusted, auto, autoLabel = 'auto', label, onChange, onClear, title, value} = props\n\n return (\n <Flex align=\"center\" gap={2}>\n <input\n aria-label={label}\n className={swatch}\n onChange={(event) => onChange(event.currentTarget.value)}\n type=\"color\"\n value={value}\n />\n <Stack className={colorRowText} flex={1} gap={2}>\n <Text size={1}>{title}</Text>\n <Text muted size={0} textOverflow=\"ellipsis\">\n {value}\n {adjusted !== undefined && adjusted !== value ? ` → ${adjusted}` : ''}\n {auto ? ` · ${autoLabel}` : ''}\n </Text>\n </Stack>\n {onClear && !auto && (\n <TooltipButton\n icon={ResetIcon}\n mode=\"bleed\"\n onClick={onClear}\n padding={2}\n tooltip={`Reset to ${autoLabel}`}\n />\n )}\n </Flex>\n )\n}\n","import {isColor} from '../lib/mix'\nimport {\n type BuildThemeOptions,\n MAXIMUM_CONTRAST,\n MINIMUM_CONTRAST,\n SCHEMES,\n type SchemeThemeOptions,\n} from '../theme/options'\nimport {displayTitle} from './themes'\n\n/** What a theme code carries: a theme's title and its options @internal */\nexport interface SharedTheme {\n title: string\n options: BuildThemeOptions\n}\n\n/**\n * The version of the code format, the first byte of every code — bumped if\n * the layout below ever changes, so older codes can still be told apart\n */\nconst VERSION = 1\n\n/** The fields a scheme's options can set, in the order their bytes go */\nconst FIELDS = ['accent', 'text', 'background', 'contrast'] as const\n\n/**\n * Turns a theme into a short code to share in a message: `title`, and the\n * colors and contrasts of both schemes, packed into bytes — one flag byte says\n * which of the eight fields are set, each color is its three RGB bytes and a\n * contrast one byte, and the title takes up the rest — then base64url'd, so\n * it is one word without padding, safe in URLs and chat. A theme setting\n * everything comes to about 30 bytes plus its title.\n *\n * @internal\n */\nexport function encodeTheme(theme: SharedTheme): string {\n const bytes: number[] = [VERSION, 0]\n let flags = 0\n\n SCHEMES.forEach((scheme, schemeIndex) => {\n const options: SchemeThemeOptions = theme.options[scheme] ?? {}\n\n FIELDS.forEach((field, fieldIndex) => {\n const value = options[field]\n\n if (value === undefined) return\n\n if (field === 'contrast') {\n if (typeof value !== 'number' || !Number.isFinite(value)) return\n\n bytes.push(Math.round(Math.min(MAXIMUM_CONTRAST, Math.max(MINIMUM_CONTRAST, value))))\n } else {\n if (typeof value !== 'string' || !isColor(value)) return\n\n bytes.push(...rgbBytes(value))\n }\n\n flags |= 1 << (schemeIndex * FIELDS.length + fieldIndex)\n })\n })\n\n bytes[1] = flags\n bytes.push(...new TextEncoder().encode(theme.title.trim()))\n\n return toBase64Url(Uint8Array.from(bytes))\n}\n\n/**\n * Reads a theme back out of a code — as pasted, so surrounding whitespace and\n * words around the code are fine: the first word that is a code counts. `null`\n * when nothing in the text is one.\n *\n * @internal\n */\nexport function decodeTheme(text: string): SharedTheme | null {\n for (const word of text.trim().split(/\\s+/)) {\n const theme = decodeCode(word)\n\n if (theme) return theme\n }\n\n return null\n}\n\nfunction decodeCode(code: string): SharedTheme | null {\n const bytes = fromBase64Url(code)\n\n if (!bytes || bytes.length < 2 || bytes[0] !== VERSION) return null\n\n const flags = bytes[1]\n const options: BuildThemeOptions = {}\n let offset = 2\n\n for (const [schemeIndex, scheme] of SCHEMES.entries()) {\n const schemeOptions: SchemeThemeOptions = {}\n\n for (const [fieldIndex, field] of FIELDS.entries()) {\n if (!(flags & (1 << (schemeIndex * FIELDS.length + fieldIndex)))) continue\n\n if (field === 'contrast') {\n if (offset + 1 > bytes.length) return null\n\n schemeOptions.contrast = Math.min(\n MAXIMUM_CONTRAST,\n Math.max(MINIMUM_CONTRAST, bytes[offset]),\n )\n offset += 1\n } else {\n if (offset + 3 > bytes.length) return null\n\n schemeOptions[field] = hexColor(bytes.subarray(offset, offset + 3))\n offset += 3\n }\n }\n\n if (Object.keys(schemeOptions).length > 0) options[scheme] = schemeOptions\n }\n\n let title: string\n\n try {\n title = new TextDecoder('utf-8', {fatal: true}).decode(bytes.subarray(offset))\n } catch {\n return null\n }\n\n return {title: displayTitle(title), options}\n}\n\n/** The three RGB bytes of a `#rgb` or `#rrggbb` color */\nfunction rgbBytes(color: string): number[] {\n const hex = color.length === 4 ? color.slice(1).replaceAll(/./g, '$&$&') : color.slice(1)\n\n return [0, 2, 4].map((start) => parseInt(hex.slice(start, start + 2), 16))\n}\n\nfunction hexColor(rgb: Uint8Array): string {\n return `#${[...rgb].map((byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\nfunction toBase64Url(bytes: Uint8Array): string {\n let binary = ''\n\n for (const byte of bytes) binary += String.fromCharCode(byte)\n\n return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '')\n}\n\nfunction fromBase64Url(code: string): Uint8Array | null {\n if (!/^[A-Za-z0-9_-]+$/.test(code)) return null\n\n const base64 = code.replaceAll('-', '+').replaceAll('_', '/')\n\n try {\n return Uint8Array.from(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, '=')), (char) =>\n char.charCodeAt(0),\n )\n } catch {\n return null\n }\n}\n","import {useToast} from '@sanity/ui/toast'\nimport {useEffect} from 'react'\n\nimport {useThemer} from './context'\nimport {decodeTheme, encodeTheme, type SharedTheme} from './share'\nimport {displayTitle} from './themes'\n\n/**\n * Copying a theme as a code to share, and adding a theme from a code someone\n * shared — with toasts telling how it went.\n *\n * @internal\n */\nexport function useThemeCodes(): {\n copyTheme: (theme: SharedTheme) => Promise<void>\n /** Adds the theme in the text, if there is one — the result says whether there was */\n addThemeFromText: (text: string) => boolean\n /** Adds the theme on the clipboard, if there is one and the browser hands the clipboard over */\n addThemeFromClipboard: () => Promise<'added' | 'no-theme' | 'no-clipboard'>\n} {\n const {send} = useThemer()\n const toast = useToast()\n\n const copyTheme = async (theme: SharedTheme) => {\n const title = displayTitle(theme.title)\n\n try {\n await navigator.clipboard.writeText(encodeTheme(theme))\n toast.push({\n status: 'success',\n title: `Copied ${title} as a code`,\n description: 'Paste it in the themer of another Studio to add the theme there',\n })\n } catch {\n toast.push({status: 'error', title: `Could not copy ${title}`})\n }\n }\n\n const addThemeFromText = (text: string) => {\n const theme = decodeTheme(text)\n\n if (!theme) return false\n\n send({type: 'theme.import', title: theme.title, options: theme.options})\n toast.push({status: 'success', title: `Added ${theme.title}`})\n\n return true\n }\n\n const addThemeFromClipboard = async () => {\n let text: string\n\n try {\n text = await navigator.clipboard.readText()\n } catch {\n return 'no-clipboard'\n }\n\n return addThemeFromText(text) ? 'added' : 'no-theme'\n }\n\n return {copyTheme, addThemeFromText, addThemeFromClipboard}\n}\n\n/**\n * Adds a theme pasted anywhere in the Studio while the themer's list is\n * showing — pastes into inputs and other editable things are theirs.\n *\n * @internal\n */\nexport function usePasteThemeCodes(): void {\n const {open, send} = useThemer()\n const toast = useToast()\n\n useEffect(() => {\n if (!open) return undefined\n\n const handlePaste = (event: ClipboardEvent) => {\n if (isEditable(event.target)) return\n\n const theme = decodeTheme(event.clipboardData?.getData('text/plain') ?? '')\n\n if (!theme) return\n\n event.preventDefault()\n send({type: 'theme.import', title: theme.title, options: theme.options})\n toast.push({status: 'success', title: `Added ${theme.title}`})\n }\n\n document.addEventListener('paste', handlePaste)\n\n return () => document.removeEventListener('paste', handlePaste)\n }, [open, send, toast])\n}\n\nfunction isEditable(target: EventTarget | null): boolean {\n return (\n target instanceof HTMLElement &&\n (target.isContentEditable || target.matches('input, textarea, select'))\n )\n}\n","import {Button, Card, Dialog, Flex, Stack, Text, TextInput} from '@sanity/ui'\nimport {useState} from 'react'\n\nimport {useThemeCodes} from './useThemeCodes'\n\n/**\n * Where a theme code someone shared gets pasted by hand — for browsers that\n * do not hand the clipboard over, and for codes that are not on it.\n *\n * @internal\n */\nexport function PasteThemeDialog(props: {onClose: () => void}) {\n const {onClose} = props\n const {addThemeFromText} = useThemeCodes()\n const [text, setText] = useState('')\n const [invalid, setInvalid] = useState(false)\n\n const add = () => {\n if (addThemeFromText(text)) {\n onClose()\n } else {\n setInvalid(true)\n }\n }\n\n return (\n <Dialog\n animate\n footer={\n <Flex gap={2} justify=\"flex-end\" padding={3}>\n <Button mode=\"ghost\" onClick={onClose} padding={2} text=\"Cancel\" />\n <Button\n disabled={text.trim() === ''}\n onClick={add}\n padding={2}\n text=\"Add theme\"\n tone=\"primary\"\n />\n </Flex>\n }\n header=\"Add a shared theme\"\n id=\"themer-paste\"\n onClickOutside={onClose}\n onClose={onClose}\n width={0}\n >\n <form\n onSubmit={(event) => {\n event.preventDefault()\n add()\n }}\n >\n <Stack gap={3} padding={4}>\n <Text muted size={1}>\n Paste the code someone copied from their themer — the theme is added to your list and\n applied.\n </Text>\n <TextInput\n aria-describedby={invalid ? 'themer-paste-error' : undefined}\n aria-invalid={invalid}\n aria-label=\"Theme code\"\n autoFocus\n customValidity={invalid ? 'That is not a theme code' : undefined}\n fontSize={1}\n onChange={(event) => {\n setText(event.currentTarget.value)\n setInvalid(false)\n }}\n placeholder=\"AQ…\"\n value={text}\n />\n {invalid && (\n <Card id=\"themer-paste-error\" padding={3} radius={2} role=\"alert\" tone=\"critical\">\n <Text size={1}>\n That is not a theme code — codes are one word, copied from a theme's menu.\n </Text>\n </Card>\n )}\n </Stack>\n </form>\n </Dialog>\n )\n}\n","import {style} from '@vanilla-extract/css'\n\nexport const root = style({\n position: 'relative',\n})\n\n/** A bare button, so that the thumbnail and the title can carry the styling */\nexport const pickButton = style({\n 'appearance': 'none',\n 'display': 'block',\n 'boxSizing': 'border-box',\n 'width': '100%',\n 'margin': 0,\n 'padding': 0,\n 'border': 0,\n 'background': 'none',\n 'color': 'inherit',\n 'font': 'inherit',\n 'textAlign': 'center',\n 'cursor': 'pointer',\n ':focus': {\n outline: 'none',\n },\n})\n\n/**\n * Wraps the thumbnail with room for the ring that marks the applied theme —\n * hovering shows a faint ring, the applied theme the focus ring color, and\n * keyboard focus an outline. The rings are drawn inside the frame's padding,\n * so nothing sticks out to be clipped by the scrolling list.\n */\nexport const frame = style({\n display: 'block',\n padding: 4,\n borderRadius: 10,\n transition: 'box-shadow 100ms',\n selectors: {\n [`${pickButton}:hover &`]: {\n boxShadow: 'inset 0 0 0 2px var(--card-border-color)',\n },\n [`${pickButton}[aria-pressed='true'] &`]: {\n boxShadow: 'inset 0 0 0 2px var(--card-focus-ring-color)',\n },\n [`${pickButton}:focus-visible &`]: {\n outline: '2px solid var(--card-focus-ring-color)',\n outlineOffset: -2,\n },\n },\n})\n\n/**\n * The actions menu sits on the thumbnail's top right corner, like the actions\n * of an image input, and only shows on hover, on keyboard focus, and while it\n * is open — its popover is portaled, so an open menu does not count as focus\n * within\n */\nexport const menuSlot = style({\n position: 'absolute',\n top: 10,\n right: 10,\n opacity: 0,\n transition: 'opacity 100ms',\n selectors: {\n [`${root}:hover &, ${root}:focus-within &, &[data-visible='true']`]: {\n opacity: 1,\n },\n },\n})\n\n/** The dark card behind the menu button sizes to the button, not the slot */\nexport const menuCard = style({\n display: 'inline-block',\n})\n","import {ArrowDownIcon} from '@sanity/icons/ArrowDown'\nimport {ArrowUpIcon} from '@sanity/icons/ArrowUp'\nimport {CopyIcon} from '@sanity/icons/Copy'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {EllipsisHorizontalIcon} from '@sanity/icons/EllipsisHorizontal'\nimport {ShareIcon} from '@sanity/icons/Share'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {Box, Button, Card, Text, useRootTheme} from '@sanity/ui'\nimport {Menu, MenuButton, MenuDivider, MenuItem} from '@sanity/ui/menu'\nimport {Tooltip} from '@sanity/ui/tooltip'\nimport {Reorder, useDragControls} from 'motion/react'\nimport {useRef, useState} from 'react'\nimport scrollIntoView from 'scroll-into-view-if-needed'\n\nimport {useThemer} from './context'\nimport {displayTitle, type ThemerTheme} from './themes'\nimport {ThemeThumbnail} from './ThemeThumbnail'\nimport {useThemeCodes} from './useThemeCodes'\n\nimport {frame, menuCard, menuSlot, pickButton, root} from './ThemeCard.css'\n\n/**\n * Scrolls the applied theme's card into view when it is not already, as a\n * ref: the list scrolls to it as it mounts — coming back from the editor or\n * the removed themes — and when another theme gets applied\n */\nfunction scrollRefIntoViewIfNeeded(node: HTMLElement | null) {\n if (node) scrollIntoView(node, {block: 'nearest', scrollMode: 'if-needed'})\n}\n\n/**\n * One theme in the list: the floating preview with the title below it, like\n * an appearance option in macOS System Settings. Clicking it applies the\n * theme to the whole Studio, dragging it moves the theme to another place in\n * the list; its menu holds the move, edit, duplicate and remove flows that\n * apply to the theme.\n *\n * @internal\n */\nexport function ThemeCard(props: {active: boolean; theme: ThemerTheme}) {\n const {active, theme} = props\n const {themes, send} = useThemer()\n const {copyTheme} = useThemeCodes()\n const {scheme} = useRootTheme()\n const [menuOpen, setMenuOpen] = useState(false)\n const dragControls = useDragControls()\n // Letting go of a drag also clicks the card, and that click must not pick\n const dragged = useRef(false)\n const title = displayTitle(theme.title)\n const index = themes.findIndex((candidate) => candidate.slug === theme.slug)\n\n const moveTo = (to: number) => {\n const order = themes.map((candidate) => candidate.slug)\n\n order.splice(to, 0, ...order.splice(index, 1))\n send({type: 'theme.reorder', order})\n }\n\n return (\n <Reorder.Item\n as=\"div\"\n className={root}\n dragControls={dragControls}\n dragListener={false}\n onDragEnd={() => {\n // The click lands before the next frame\n requestAnimationFrame(() => {\n dragged.current = false\n })\n }}\n onDragStart={() => {\n dragged.current = true\n }}\n ref={active ? scrollRefIntoViewIfNeeded : undefined}\n value={theme.slug}\n whileDrag={{scale: 1.04}}\n >\n <button\n aria-pressed={active}\n className={pickButton}\n onClick={() => {\n if (!dragged.current) send({type: 'theme.pick', slug: theme.slug})\n }}\n onPointerDown={(event) => {\n // A mouse or pen drags the card off the button; a finger scrolls the\n // list instead, and moves themes from the menu\n if (event.pointerType !== 'touch') dragControls.start(event)\n }}\n type=\"button\"\n >\n <span className={frame}>\n <ThemeThumbnail options={theme.options} />\n </span>\n <Box as=\"span\" display=\"block\" paddingTop={2} paddingX={2}>\n <Text\n align=\"center\"\n as=\"span\"\n size={1}\n textOverflow=\"ellipsis\"\n weight={active ? 'medium' : 'regular'}\n >\n {title}\n </Text>\n </Box>\n </button>\n\n {/* The tooltip wraps a card rather than the button: the menu button\n clones its button to wire it up, which a tooltip in between would\n swallow. The card keeps the button dark, as it sits on the dark\n half of the thumbnail, while the menu opens in the sidebar's scheme */}\n <div className={menuSlot} data-visible={menuOpen}>\n <Tooltip animate content={<Text size={1}>Show more</Text>} placement=\"bottom\" portal>\n <Card className={menuCard} radius={2} scheme=\"dark\">\n <MenuButton\n button={\n <Button\n aria-label={`Show more for ${title}`}\n fontSize={1}\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n padding={1}\n radius={2}\n />\n }\n id={`themer-theme-${theme.slug}`}\n menu={\n <Menu>\n <MenuItem\n disabled={index <= 0}\n icon={ArrowUpIcon}\n onClick={() => moveTo(index - 1)}\n text=\"Move up\"\n />\n <MenuItem\n disabled={index >= themes.length - 1}\n icon={ArrowDownIcon}\n onClick={() => moveTo(index + 1)}\n text=\"Move down\"\n />\n <MenuDivider />\n {theme.source === 'custom' && (\n <MenuItem\n icon={EditIcon}\n onClick={() => send({type: 'theme.edit', slug: theme.slug})}\n text=\"Edit\"\n />\n )}\n <MenuItem\n icon={CopyIcon}\n onClick={() => send({type: 'theme.duplicate', slug: theme.slug})}\n text={theme.source === 'custom' ? 'Duplicate' : 'Duplicate to edit'}\n />\n <MenuItem\n icon={ShareIcon}\n onClick={() => void copyTheme(theme)}\n text=\"Copy to share\"\n />\n {theme.source !== 'config' && (\n <>\n <MenuDivider />\n <MenuItem\n icon={TrashIcon}\n onClick={() => send({type: 'theme.remove', slug: theme.slug})}\n text=\"Remove\"\n tone=\"critical\"\n />\n </>\n )}\n </Menu>\n }\n onClose={() => setMenuOpen(false)}\n onOpen={() => setMenuOpen(true)}\n popover={{animate: true, placement: 'bottom-end', portal: true, scheme}}\n />\n </Card>\n </Tooltip>\n </div>\n </Reorder.Item>\n )\n}\n","import {style} from '@vanilla-extract/css'\n\nimport {MAXIMUM_WIDTH, MINIMUM_WIDTH} from './sidebarWidth'\n\nimport {sidebarContent} from './ResizableSidebar.css'\n\nconst CARD_GAP = 16\n\n/**\n * The theme cards flow into two columns once the sidebar has been dragged a\n * third of the way from its narrowest to its widest. The breakpoints are\n * container queries on the sidebar's content (`ResizableSidebar`), which is\n * as wide as the sidebar itself.\n */\nconst TWO_COLUMNS_FROM = MINIMUM_WIDTH + (MAXIMUM_WIDTH - MINIMUM_WIDTH) * 0.3\n\n/** Three columns on the wider small screens the sidebar covers, where two would be huge */\nconst THREE_COLUMNS_FROM = 480\n\n/**\n * The columns share the width equally whatever the titles: a plain `1fr` may\n * not shrink below a card's min-content width, and a card's title does not\n * wrap, so one long title would widen its column past the sidebar\n */\nconst COLUMN = 'minmax(0, 1fr)'\n\nexport const cardGrid = style({\n 'display': 'grid',\n 'gridTemplateColumns': COLUMN,\n 'gap': CARD_GAP,\n '@container': {\n [`${sidebarContent} (min-width: ${TWO_COLUMNS_FROM}px)`]: {\n gridTemplateColumns: `repeat(2, ${COLUMN})`,\n },\n [`${sidebarContent} (min-width: ${THREE_COLUMNS_FROM}px)`]: {\n gridTemplateColumns: `repeat(3, ${COLUMN})`,\n },\n },\n})\n","import {AddIcon} from '@sanity/icons/Add'\nimport {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {RestoreIcon} from '@sanity/icons/Restore'\nimport {Box, Button, Card, Flex, Stack} from '@sanity/ui'\nimport {MotionConfig, Reorder} from 'motion/react'\nimport {useState} from 'react'\n\nimport {useThemer} from './context'\nimport {ImageFileButton} from './ImageFileButton'\nimport {optionsFromImagePalette, titleFromFileName} from './imagePalette'\nimport {PasteThemeDialog} from './PasteThemeDialog'\nimport {ScrollArea} from './ScrollArea'\nimport {ThemeCard} from './ThemeCard'\nimport {TooltipButton} from './TooltipButton'\nimport {useImagePalette} from './useImagePalette'\nimport {usePasteThemeCodes, useThemeCodes} from './useThemeCodes'\n\nimport {cardGrid} from './ThemeList.css'\n\n/**\n * One column at the sidebar's default width; wider sidebars — and the\n * overlay on small screens — fit more cards per row\n */\n/**\n * The flow for picking a theme: a grid of theme cards — the configured theme,\n * the presets and the user's own themes — that drag into the order the user\n * wants, with the entry points to the add and restore flows below. A theme\n * code someone shared pastes right into the list, or through the paste button.\n *\n * @internal\n */\nexport function ThemeList() {\n const {themes, removed, active, send} = useThemer()\n const {addThemeFromClipboard} = useThemeCodes()\n const [pasting, setPasting] = useState(false)\n\n usePasteThemeCodes()\n\n const {busy, pickImage} = useImagePalette((palette, file) =>\n send({\n type: 'theme.add',\n title: titleFromFileName(file.name),\n options: optionsFromImagePalette(palette),\n palette,\n imageUrl: URL.createObjectURL(file),\n }),\n )\n\n return (\n <>\n <ScrollArea padding={3}>\n <Stack gap={4}>\n {/* The group tells a column from a grid by measuring the cards, and\n lets go of the layout animations for users who prefer reduced motion */}\n <MotionConfig reducedMotion=\"user\">\n <Reorder.Group\n as=\"div\"\n className={cardGrid}\n onReorder={(order: string[]) => send({type: 'theme.reorder', order})}\n values={themes.map((theme) => theme.slug)}\n >\n {themes.map((theme) => (\n <ThemeCard active={theme.slug === active.slug} key={theme.slug} theme={theme} />\n ))}\n </Reorder.Group>\n </MotionConfig>\n {/* Trails the list rather than sitting in the footer, so the footer\n does not shift when the first theme gets removed */}\n {removed.length > 0 && (\n <Button\n gap={2}\n icon={RestoreIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.removed'})}\n padding={2}\n text={`Show removed (${removed.length})`}\n width=\"fill\"\n />\n )}\n </Stack>\n </ScrollArea>\n\n <Card borderTop padding={3}>\n <Flex gap={2}>\n <Box flex={1}>\n <TooltipButton\n icon={AddIcon}\n mode=\"ghost\"\n onClick={() => send({type: 'theme.add'})}\n text=\"Add theme\"\n tooltip=\"Add a theme based on the applied one\"\n width=\"fill\"\n />\n </Box>\n <ImageFileButton\n loading={busy}\n mode=\"ghost\"\n onFile={pickImage}\n tooltip=\"Add a theme from the colors of an image\"\n />\n <TooltipButton\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={async () => {\n // Straight from the clipboard where the browser allows; by hand otherwise\n if ((await addThemeFromClipboard()) !== 'added') setPasting(true)\n }}\n tooltip=\"Add a theme from a code someone shared\"\n />\n </Flex>\n </Card>\n\n {pasting && <PasteThemeDialog onClose={() => setPasting(false)} />}\n </>\n )\n}\n","import {type BuildThemeOptions, SCHEMES, type SchemeThemeOptions} from '../theme/options'\nimport {minimizeOptions} from './options'\n\n/**\n * Serializes theme options into the `buildTheme` call to paste into\n * `sanity.config.ts`, keeping only what differs from the derived defaults in\n * each scheme.\n *\n * Options that boil down to the stock Studio theme need nothing from this\n * package — so they serialize to a bare `buildTheme()` from `@sanity/ui/theme`\n * instead.\n *\n * @internal\n */\nexport function createThemeSnippet(options: BuildThemeOptions): string {\n const minimized = minimizeOptions(options)\n\n if (minimized === null) {\n return \"import {buildTheme} from '@sanity/ui/theme'\\n\\nexport const theme = buildTheme()\\n\"\n }\n\n const lines: string[] = []\n\n for (const scheme of SCHEMES) {\n const values = minimized[scheme]\n\n if (values) lines.push(serializeScheme(scheme, values))\n }\n\n return `import {buildTheme} from '@sanity/themer'\\n\\nexport const theme = buildTheme({\\n${lines.join('\\n')}\\n})\\n`\n}\n\n/** A scheme with up to two options fits on one line, more spread out */\nfunction serializeScheme(scheme: string, values: SchemeThemeOptions): string {\n const entries: string[] = []\n\n if (values.accent !== undefined) entries.push(`accent: '${values.accent}'`)\n if (values.text !== undefined) entries.push(`text: '${values.text}'`)\n if (values.background !== undefined) entries.push(`background: '${values.background}'`)\n if (values.contrast !== undefined) entries.push(`contrast: ${values.contrast}`)\n\n if (entries.length <= 2) {\n return ` ${scheme}: {${entries.join(', ')}},`\n }\n\n return ` ${scheme}: {\\n${entries.map((entry) => ` ${entry},`).join('\\n')}\\n },`\n}\n","import {ClipboardIcon} from '@sanity/icons/Clipboard'\nimport {Box, Button, Card, Dialog, Flex, Stack, Text} from '@sanity/ui'\nimport {Code} from '@sanity/ui/code'\nimport {useToast} from '@sanity/ui/toast'\nimport {registerLanguage} from 'react-refractor'\nimport typescript from 'refractor/typescript'\n\nimport {createThemeSnippet} from './snippet'\nimport {displayTitle, type ThemerTheme} from './themes'\n\n// `Code` only highlights languages the surrounding app has registered with\n// react-refractor, and the Studio registers its own set from an async import\n// during startup — a race this dialog keeps losing. Registering the one\n// language the snippet needs keeps it highlighted from the first render.\nregisterLanguage(typescript)\n\n/**\n * Shows the `buildTheme` snippet that makes a theme permanent, in a dialog so\n * that it does not take up sidebar space or make the sidebar scroll as the\n * snippet changes shape with the theme.\n *\n * @internal\n */\nexport function ThemeSnippetDialog(props: {onClose: () => void; theme: ThemerTheme}) {\n const {onClose, theme} = props\n const toast = useToast()\n const snippet = createThemeSnippet(theme.options)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(snippet)\n toast.push({status: 'success', title: 'Copied the theme to the clipboard'})\n } catch {\n toast.push({status: 'error', title: 'Could not copy the theme'})\n }\n }\n\n return (\n <Dialog\n animate\n footer={\n <Flex gap={2} justify=\"flex-end\" padding={3}>\n <Button\n gap={2}\n icon={ClipboardIcon}\n mode=\"ghost\"\n onClick={() => void handleCopy()}\n padding={2}\n text=\"Copy\"\n />\n </Flex>\n }\n header=\"Add to your config\"\n id=\"themer-snippet\"\n onClickOutside={onClose}\n onClose={onClose}\n width={1}\n >\n <Box padding={4}>\n <Stack gap={4}>\n <Text muted size={1}>\n Export this from <code>sanity.config.ts</code> and pass it as the <code>theme</code> of{' '}\n <code>defineConfig</code> to make “{displayTitle(theme.title)}” the Studio theme without\n this tool.\n </Text>\n <Card border overflow=\"auto\" padding={3} radius={2} tone=\"transparent\">\n <Code language=\"ts\" size={1}>\n {snippet}\n </Code>\n </Card>\n </Stack>\n </Box>\n </Dialog>\n )\n}\n","import {style} from '@vanilla-extract/css'\n\n/** Lets the title shrink and truncate instead of pushing the buttons out */\nexport const title = style({\n minWidth: 0,\n})\n","import {ArrowLeftIcon} from '@sanity/icons/ArrowLeft'\nimport {CloseIcon} from '@sanity/icons/Close'\nimport {CodeBlockIcon} from '@sanity/icons/CodeBlock'\nimport {SplitVerticalIcon} from '@sanity/icons/SplitVertical'\nimport {Box, Card, Flex, Text} from '@sanity/ui'\nimport {useState} from 'react'\n\nimport {useThemer} from './context'\nimport {RemovedThemes} from './RemovedThemes'\nimport {ThemeEditor} from './ThemeEditor'\nimport {ThemeList} from './ThemeList'\nimport {ThemeSnippetDialog} from './ThemeSnippetDialog'\nimport {TooltipButton} from './TooltipButton'\n\nimport {title} from './ThemerSidebar.css'\n\nconst VIEW_TITLES = {\n list: 'Themer',\n edit: 'Edit theme',\n removed: 'Removed themes',\n} as const\n\n/**\n * The themer sidebar: a header that navigates between the flows and toggles\n * the split preview, the flow itself — picking a theme, editing one, or\n * restoring removed ones — and the dialog with the `buildTheme` snippet of\n * the applied theme.\n *\n * @internal\n */\nexport function ThemerSidebar() {\n const {active, split, view, navbarHeight, send} = useThemer()\n const [snippetOpen, setSnippetOpen] = useState(false)\n const inList = view.name === 'list'\n\n return (\n <Card height=\"fill\">\n <Flex direction=\"column\" height=\"fill\">\n {/* The header sits next to the Studio navbar and takes its height, so\n the two bottom borders line up — whatever height the Studio, its\n breakpoint or a custom navbar gives it */}\n <Card\n borderBottom\n padding={3}\n sizing=\"border\"\n style={navbarHeight === null ? undefined : {height: navbarHeight}}\n >\n <Flex align=\"center\" gap={1} height=\"fill\">\n {!inList && (\n <TooltipButton\n icon={ArrowLeftIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'flow.list'})}\n padding={2}\n tooltip=\"Back to the themes\"\n />\n )}\n <Box className={title} flex={1}>\n <Text size={1} textOverflow=\"ellipsis\" weight=\"semibold\">\n {VIEW_TITLES[view.name]}\n </Text>\n </Box>\n {/* Packed without gaps, so the title still fits next to them at the\n narrowest sidebar width */}\n <Flex>\n {view.name !== 'removed' && (\n <>\n <TooltipButton\n aria-pressed={split}\n icon={SplitVerticalIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'preview.toggle'})}\n padding={2}\n selected={split}\n tooltip=\"Show light and dark side by side\"\n />\n <TooltipButton\n icon={CodeBlockIcon}\n mode=\"bleed\"\n onClick={() => setSnippetOpen(true)}\n padding={2}\n tooltip=\"Show the code for the applied theme\"\n />\n </>\n )}\n <TooltipButton\n icon={CloseIcon}\n mode=\"bleed\"\n onClick={() => send({type: 'sidebar.close'})}\n padding={2}\n tooltip=\"Close themer\"\n />\n </Flex>\n </Flex>\n </Card>\n\n {view.name === 'list' && <ThemeList />}\n {view.name === 'edit' && <ThemeEditor focusTitle={view.focusTitle} slug={view.slug} />}\n {view.name === 'removed' && <RemovedThemes />}\n </Flex>\n\n {snippetOpen && <ThemeSnippetDialog onClose={() => setSnippetOpen(false)} theme={active} />}\n </Card>\n )\n}\n","import {createContainer, createViewTransition, style} from '@vanilla-extract/css'\n\n/**\n * The view transition group of the sidebar, which the split preview's\n * transition (see `ThemerLayout.css.ts`) leaves alone: it never animates, and\n * the Studio copies animating underneath never paint over it\n */\nexport const sidebarTransition = createViewTransition()\n\n/** The sidebar's content, which the content's layout queries — as wide as the sidebar itself */\nexport const sidebarContent = createContainer()\n\nexport const sidebar = style({\n flex: 'none',\n viewTransitionName: sidebarTransition,\n selectors: {\n // On small screens the sidebar covers the Studio instead of standing next to it\n \"&[data-overlay='true']\": {\n position: 'absolute',\n inset: 0,\n width: 'auto',\n },\n },\n})\n\n/**\n * Draws the sidebar's border and gives the resize handle its card colors. It\n * does not clip, so the handle can straddle the border — the content is\n * clipped one level down instead.\n */\nexport const frame = style({\n position: 'relative',\n})\n\n/**\n * Clips the content, and is the container its layout queries: as wide as\n * the sidebar, whether or not a scrollbar takes room inside — see the theme\n * grid's columns in `ThemeList.css.ts`\n */\nexport const content = style({\n containerType: 'inline-size',\n containerName: sidebarContent,\n})\n\n/**\n * The grab area along the sidebar's left edge. It straddles the border so it\n * is easy to hit, and highlights while hovered, focused or dragged.\n */\nexport const resizeHandle = style({\n 'position': 'absolute',\n 'top': 0,\n 'bottom': 0,\n 'left': -3,\n 'zIndex': 1,\n 'width': 7,\n 'cursor': 'col-resize',\n 'touchAction': 'none',\n '::after': {\n content: '',\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 2,\n width: 3,\n background: 'var(--card-focus-ring-color)',\n opacity: 0,\n transition: 'opacity 100ms',\n },\n ':focus': {\n outline: 'none',\n },\n 'selectors': {\n \"&:hover::after, &:focus-visible::after, &[data-dragging='true']::after\": {\n opacity: 1,\n },\n },\n})\n","import {Box, Card, Layer} from '@sanity/ui'\nimport {useCallback, useEffect, useRef, useState} from 'react'\n\nimport {MAXIMUM_WIDTH, MINIMUM_WIDTH} from './sidebarWidth'\nimport {ThemerSidebar} from './ThemerSidebar'\n\nimport {content, frame, resizeHandle, sidebar} from './ResizableSidebar.css'\n\n/** How far one arrow key press resizes the sidebar */\nconst KEYBOARD_STEP = 16\n\nconst WIDTH_STORAGE_KEY = 'sanityStudio:themer:width'\n\nfunction clampWidth(width: number): number {\n return Math.min(MAXIMUM_WIDTH, Math.max(MINIMUM_WIDTH, Math.round(width)))\n}\n\nfunction readStoredWidth(): number {\n try {\n const stored = Number(localStorage.getItem(WIDTH_STORAGE_KEY))\n\n return Number.isFinite(stored) && stored > 0 ? clampWidth(stored) : MINIMUM_WIDTH\n } catch {\n return MINIMUM_WIDTH\n }\n}\n\nfunction writeStoredWidth(width: number): void {\n try {\n if (width === MINIMUM_WIDTH) {\n localStorage.removeItem(WIDTH_STORAGE_KEY)\n } else {\n localStorage.setItem(WIDTH_STORAGE_KEY, String(width))\n }\n } catch {\n // Storage can be unavailable (e.g. private browsing) — the width just won't persist\n }\n}\n\n/**\n * The themer sidebar, in a layer along the right edge of the Studio. Its left\n * edge drags (or arrow-keys) it wider, up to twice its default width — the\n * width sticks between sessions. As an overlay (small screens) it covers the\n * Studio edge to edge instead, with nothing to resize.\n *\n * @internal\n */\nexport default function ResizableSidebar(props: {overlay: boolean}) {\n const {overlay} = props\n const [width, setWidth] = useState(readStoredWidth)\n const [dragging, setDragging] = useState(false)\n const drag = useRef<{pointerId: number; startX: number; startWidth: number} | null>(null)\n\n useEffect(() => writeStoredWidth(width), [width])\n\n const handlePointerDown = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return\n\n event.preventDefault()\n event.currentTarget.setPointerCapture(event.pointerId)\n drag.current = {pointerId: event.pointerId, startX: event.clientX, startWidth: width}\n setDragging(true)\n },\n [width],\n )\n\n const handlePointerMove = useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n // The sidebar sits on the right, so dragging left makes it wider\n setWidth(clampWidth(drag.current.startWidth - (event.clientX - drag.current.startX)))\n }, [])\n\n const handlePointerUp = useCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (!drag.current || drag.current.pointerId !== event.pointerId) return\n\n drag.current = null\n setDragging(false)\n }, [])\n\n const handleKeyDown = useCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n const steps: Record<string, number> = {\n ArrowLeft: KEYBOARD_STEP,\n ArrowRight: -KEYBOARD_STEP,\n Home: MAXIMUM_WIDTH,\n End: -MAXIMUM_WIDTH,\n }\n const step = steps[event.key]\n\n if (step === undefined) return\n\n event.preventDefault()\n setWidth((current) => clampWidth(current + step))\n }, [])\n\n return (\n <Layer\n className={sidebar}\n data-overlay={overlay}\n style={overlay ? undefined : {width}}\n zOffset={100}\n >\n <Card borderLeft={!overlay} className={frame} height=\"fill\">\n {!overlay && (\n <div\n aria-label=\"Resize the themer\"\n className={resizeHandle}\n aria-orientation=\"vertical\"\n aria-valuemax={MAXIMUM_WIDTH}\n aria-valuemin={MINIMUM_WIDTH}\n aria-valuenow={width}\n data-dragging={dragging}\n onDoubleClick={() => setWidth(MINIMUM_WIDTH)}\n onKeyDown={handleKeyDown}\n onPointerCancel={handlePointerUp}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n // oxlint-disable-next-line prefer-tag-over-role -- a window splitter is a focusable, draggable separator, which an hr is not\n role=\"separator\"\n tabIndex={0}\n />\n )}\n <Box className={content} height=\"fill\" overflow=\"hidden\">\n <ThemerSidebar />\n </Box>\n </Card>\n </Layer>\n )\n}\n"],"mappings":"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"}
|