@designtools/shadows 0.1.10 → 0.1.12

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.
@@ -1,343 +0,0 @@
1
- import { useState, useRef } from "react";
2
- import {
3
- ChevronRightIcon,
4
- ChevronDownIcon,
5
- Pencil1Icon,
6
- BookmarkIcon,
7
- CheckIcon,
8
- } from "@radix-ui/react-icons";
9
- import { ShadowControls } from "./shadow-controls.js";
10
- import { ShadowPreview } from "./shadow-preview.js";
11
- import type { PreviewSettings } from "./shadow-preview-settings.js";
12
-
13
- interface ShadowListProps {
14
- shadows: any[];
15
- cssFilePath: string;
16
- stylingType: string;
17
- onPreviewShadow: (variableName: string, value: string, shadowName?: string) => void;
18
- previewSettings: PreviewSettings;
19
- }
20
-
21
- export function ShadowList({
22
- shadows,
23
- cssFilePath,
24
- stylingType,
25
- onPreviewShadow,
26
- previewSettings,
27
- }: ShadowListProps) {
28
- const [expandedShadow, setExpandedShadow] = useState<string | null>(null);
29
- const [editMode, setEditMode] = useState<Record<string, "custom" | "preset">>({});
30
-
31
- return (
32
- <div>
33
- {shadows.map((shadow: any) => (
34
- <ShadowRow
35
- key={shadow.name}
36
- shadow={shadow}
37
- isExpanded={expandedShadow === shadow.name}
38
- onToggle={() =>
39
- setExpandedShadow(
40
- expandedShadow === shadow.name ? null : shadow.name
41
- )
42
- }
43
- mode={editMode[shadow.name] || "custom"}
44
- onModeChange={(mode) =>
45
- setEditMode({ ...editMode, [shadow.name]: mode })
46
- }
47
- cssFilePath={cssFilePath}
48
- stylingType={stylingType}
49
- onPreviewShadow={onPreviewShadow}
50
- previewSettings={previewSettings}
51
- />
52
- ))}
53
-
54
- {shadows.length === 0 && (
55
- <div
56
- className="px-4 py-6 text-center text-[11px]"
57
- style={{ color: "var(--studio-text-dimmed)" }}
58
- >
59
- No shadows found. Add shadow CSS variables to your global CSS file.
60
- </div>
61
- )}
62
- </div>
63
- );
64
- }
65
-
66
- function ShadowRow({
67
- shadow,
68
- isExpanded,
69
- onToggle,
70
- mode,
71
- onModeChange,
72
- cssFilePath,
73
- stylingType,
74
- onPreviewShadow,
75
- previewSettings,
76
- }: {
77
- shadow: any;
78
- isExpanded: boolean;
79
- onToggle: () => void;
80
- mode: "custom" | "preset";
81
- onModeChange: (mode: "custom" | "preset") => void;
82
- cssFilePath: string;
83
- stylingType: string;
84
- onPreviewShadow: (variableName: string, value: string, shadowName?: string) => void;
85
- previewSettings: PreviewSettings;
86
- }) {
87
- const [saving, setSaving] = useState(false);
88
- const [currentValue, setCurrentValue] = useState(shadow.value);
89
-
90
- const handleSave = async (newValue: string) => {
91
- setCurrentValue(newValue);
92
- setSaving(true);
93
- try {
94
- // Design token shadows write to their own endpoint
95
- if (shadow.source === "design-token" && shadow.tokenFilePath && shadow.tokenPath) {
96
- const res = await fetch("/api/shadows/design-token", {
97
- method: "POST",
98
- headers: { "Content-Type": "application/json" },
99
- body: JSON.stringify({
100
- filePath: shadow.tokenFilePath,
101
- tokenPath: shadow.tokenPath,
102
- value: newValue,
103
- }),
104
- });
105
- const data = await res.json();
106
- if (!data.ok) console.error("Design token save failed:", data.error);
107
- } else {
108
- // CSS/SCSS shadow writes
109
- const variableName = shadow.sassVariable || shadow.cssVariable || `--${shadow.name}`;
110
- let selector: string;
111
- let filePath = cssFilePath;
112
-
113
- if (stylingType === "tailwind-v4") {
114
- selector = "@theme";
115
- } else if (stylingType === "bootstrap" && shadow.sassVariable) {
116
- selector = "scss";
117
- // Use the SCSS file if available, fall back to CSS file
118
- filePath = shadow.filePath || cssFilePath;
119
- } else {
120
- selector = ":root";
121
- }
122
-
123
- const endpoint = shadow.isOverridden ? "/api/shadows" : "/api/shadows/create";
124
- const res = await fetch(endpoint, {
125
- method: "POST",
126
- headers: { "Content-Type": "application/json" },
127
- body: JSON.stringify({
128
- filePath,
129
- variableName,
130
- value: newValue,
131
- selector,
132
- }),
133
- });
134
- const data = await res.json();
135
- if (!data.ok) console.error("Shadow save failed:", data.error);
136
- }
137
- } catch (err) {
138
- console.error("Shadow save error:", err);
139
- }
140
- setTimeout(() => setSaving(false), 1000);
141
- };
142
-
143
- return (
144
- <div style={{ borderTop: "1px solid var(--studio-border-subtle)" }}>
145
- <button
146
- onClick={onToggle}
147
- className="studio-section-hdr"
148
- style={{ gap: 8 }}
149
- >
150
- {isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}
151
- <ShadowPreview
152
- value={currentValue}
153
- size={24}
154
- showBorder={previewSettings.showBorder}
155
- borderColor={previewSettings.borderColor}
156
- />
157
- <span
158
- className="flex-1 text-[11px] font-mono truncate text-left"
159
- style={{
160
- color: "var(--studio-text)",
161
- fontWeight: 500,
162
- textTransform: "none",
163
- letterSpacing: 0,
164
- }}
165
- >
166
- {shadow.name}
167
- </span>
168
- {shadow.source === "framework-preset" && !shadow.isOverridden && (
169
- <span
170
- className="text-[9px] px-1.5 py-0.5 rounded"
171
- style={{
172
- background: "var(--studio-input-bg)",
173
- color: "var(--studio-text-dimmed)",
174
- }}
175
- >
176
- preset
177
- </span>
178
- )}
179
- {shadow.source === "design-token" && (
180
- <span
181
- className="text-[9px] px-1.5 py-0.5 rounded"
182
- style={{
183
- background: "var(--studio-input-bg)",
184
- color: "var(--studio-text-dimmed)",
185
- }}
186
- >
187
- token
188
- </span>
189
- )}
190
- {saving && (
191
- <span
192
- className="flex items-center gap-0.5 text-[10px]"
193
- style={{ color: "var(--studio-success)" }}
194
- >
195
- <CheckIcon style={{ width: 10, height: 10 }} />
196
- </span>
197
- )}
198
- </button>
199
-
200
- {isExpanded && (
201
- <div className="px-4 pb-3">
202
- {/* Edit mode toggle */}
203
- <div className="studio-segmented mb-3" style={{ width: "100%" }}>
204
- <button
205
- onClick={() => onModeChange("custom")}
206
- className={mode === "custom" ? "active" : ""}
207
- style={{ flex: 1 }}
208
- >
209
- <Pencil1Icon style={{ width: 12, height: 12 }} />
210
- Custom
211
- </button>
212
- <button
213
- onClick={() => onModeChange("preset")}
214
- className={mode === "preset" ? "active" : ""}
215
- style={{ flex: 1 }}
216
- >
217
- <BookmarkIcon style={{ width: 12, height: 12 }} />
218
- Use Preset
219
- </button>
220
- </div>
221
-
222
- {mode === "custom" ? (
223
- <ShadowControls
224
- shadow={{ ...shadow, value: currentValue }}
225
- onPreview={(value) => {
226
- const varName = shadow.cssVariable || `--${shadow.name}`;
227
- onPreviewShadow(varName, value, shadow.name);
228
- }}
229
- onSave={handleSave}
230
- previewSettings={previewSettings}
231
- />
232
- ) : (
233
- <PresetPicker
234
- currentValue={currentValue}
235
- onSelect={(value) => {
236
- const varName = shadow.cssVariable || `--${shadow.name}`;
237
- onPreviewShadow(varName, value, shadow.name);
238
- handleSave(value);
239
- }}
240
- previewSettings={previewSettings}
241
- />
242
- )}
243
- </div>
244
- )}
245
- </div>
246
- );
247
- }
248
-
249
- function PresetPicker({
250
- currentValue,
251
- onSelect,
252
- previewSettings,
253
- }: {
254
- currentValue: string;
255
- onSelect: (value: string) => void;
256
- previewSettings: PreviewSettings;
257
- }) {
258
- // Presets from shadow-explorer: multi-layer approaches at different depths
259
- const presets = [
260
- // Crisp 2-layer
261
- { name: "Crisp 2L", value: "0px 0.3px 0.7px 0px rgb(0 0 0 / 0.1), 0px 0.7px 2.1px 0px rgb(0 0 0 / 0.07)", desc: "Subtle" },
262
- { name: "Crisp 2L +", value: "0px 0.5px 1px 0px rgb(0 0 0 / 0.1), 0px 1px 3px 0px rgb(0 0 0 / 0.07), 0px 2px 6px 0px rgb(0 0 0 / 0.07)", desc: "Elevated" },
263
- // Crisp 3-layer (doubling)
264
- { name: "Crisp 3L", value: "0px 1px 1px 0px rgb(0 0 0 / 0.08), 0px 2px 2px 0px rgb(0 0 0 / 0.08), 0px 4px 4px 0px rgb(0 0 0 / 0.08)", desc: "Card" },
265
- { name: "Crisp 3L +", value: "0px 1px 1px 0px rgb(0 0 0 / 0.08), 0px 2px 2px 0px rgb(0 0 0 / 0.08), 0px 4px 4px 0px rgb(0 0 0 / 0.08), 0px 8px 8px 0px rgb(0 0 0 / 0.08)", desc: "Elevated" },
266
- // Crisp 3-layer tight
267
- { name: "Crisp Tight", value: "0px 0.5px 0.5px 0px rgb(0 0 0 / 0.09), 0px 1px 1.5px 0px rgb(0 0 0 / 0.07), 0px 3px 3px 0px rgb(0 0 0 / 0.06)", desc: "Card" },
268
- { name: "Crisp Tight +", value: "0px 0.5px 0.5px 0px rgb(0 0 0 / 0.09), 0px 1px 1.5px 0px rgb(0 0 0 / 0.07), 0px 3px 3px 0px rgb(0 0 0 / 0.06), 0px 6px 6px 0px rgb(0 0 0 / 0.06)", desc: "Elevated" },
269
- // Crisp 4-layer
270
- { name: "Crisp 4L", value: "0px 0.5px 0.5px 0px rgb(0 0 0 / 0.07), 0px 1px 1px 0px rgb(0 0 0 / 0.06), 0px 2px 2px 0px rgb(0 0 0 / 0.06), 0px 4px 4px 0px rgb(0 0 0 / 0.06)", desc: "Card" },
271
- { name: "Crisp 4L +", value: "0px 0.5px 0.5px 0px rgb(0 0 0 / 0.07), 0px 1px 1px 0px rgb(0 0 0 / 0.06), 0px 2px 2px 0px rgb(0 0 0 / 0.06), 0px 4px 4px 0px rgb(0 0 0 / 0.06), 0px 8px 8px 0px rgb(0 0 0 / 0.06)", desc: "Elevated" },
272
- // Crisp 4-layer with hard edge
273
- { name: "Edge 4L", value: "0px 0px 0.5px -0.5px rgb(0 0 0 / 0.12), 0px 1px 1px 0px rgb(0 0 0 / 0.06), 0px 2px 2px 0px rgb(0 0 0 / 0.06), 0px 4px 4px 0px rgb(0 0 0 / 0.05)", desc: "Card" },
274
- { name: "Edge 4L +", value: "0px 0px 0.5px -0.5px rgb(0 0 0 / 0.12), 0px 1px 1px 0px rgb(0 0 0 / 0.06), 0px 2px 2px 0px rgb(0 0 0 / 0.06), 0px 4px 4px 0px rgb(0 0 0 / 0.05), 0px 8px 8px 0px rgb(0 0 0 / 0.05)", desc: "Elevated" },
275
- // Soft / diffuse
276
- { name: "Soft", value: "0px 1px 2px 0px rgb(0 0 0 / 0.04), 0px 2px 4px 0px rgb(0 0 0 / 0.04), 0px 4px 8px 0px rgb(0 0 0 / 0.04)", desc: "Diffuse" },
277
- { name: "Soft +", value: "0px 1px 2px 0px rgb(0 0 0 / 0.04), 0px 2px 4px 0px rgb(0 0 0 / 0.04), 0px 4px 8px 0px rgb(0 0 0 / 0.04), 0px 8px 16px 0px rgb(0 0 0 / 0.04)", desc: "Elevated" },
278
- // Chunky — solid, hard shadow with minimal blur
279
- { name: "Chunky", value: "0px 2px 0px 0px rgb(0 0 0 / 0.15), 0px 4px 0px 0px rgb(0 0 0 / 0.1)", desc: "Hard" },
280
- { name: "Chunky +", value: "0px 2px 0px 0px rgb(0 0 0 / 0.15), 0px 4px 0px 0px rgb(0 0 0 / 0.1), 0px 8px 0px 0px rgb(0 0 0 / 0.07)", desc: "Elevated" },
281
- // None
282
- { name: "None", value: "none", desc: "Remove" },
283
- ];
284
-
285
- return (
286
- <div
287
- className="grid gap-2"
288
- style={{ gridTemplateColumns: "repeat(2, 1fr)" }}
289
- >
290
- {presets.map((preset) => {
291
- const isActive = currentValue === preset.value;
292
- return (
293
- <button
294
- key={preset.name}
295
- onClick={() => onSelect(preset.value)}
296
- className="flex flex-col items-center gap-1.5 p-3 rounded-lg cursor-pointer"
297
- style={{
298
- background: isActive
299
- ? "var(--studio-accent-muted)"
300
- : "transparent",
301
- border: "1px solid",
302
- borderColor: isActive
303
- ? "var(--studio-accent)"
304
- : "var(--studio-border-subtle)",
305
- }}
306
- >
307
- <div
308
- className="flex items-center justify-center rounded-lg w-full"
309
- style={{
310
- background: previewSettings.previewBg,
311
- height: 72,
312
- }}
313
- >
314
- <ShadowPreview
315
- value={preset.value}
316
- size={48}
317
- background="white"
318
- showBorder={previewSettings.showBorder}
319
- borderColor={previewSettings.borderColor}
320
- />
321
- </div>
322
- <div className="text-center">
323
- <div
324
- className="text-[10px] font-medium"
325
- style={{ color: "var(--studio-text-muted)" }}
326
- >
327
- {preset.name}
328
- </div>
329
- {preset.desc && (
330
- <div
331
- className="text-[9px]"
332
- style={{ color: "var(--studio-text-dimmed)" }}
333
- >
334
- {preset.desc}
335
- </div>
336
- )}
337
- </div>
338
- </button>
339
- );
340
- })}
341
- </div>
342
- );
343
- }
@@ -1,111 +0,0 @@
1
- import { useState } from "react";
2
- import { ShadowPreview } from "./shadow-preview.js";
3
- import type { PreviewSettings } from "./shadow-preview-settings.js";
4
-
5
- interface ShadowOverviewProps {
6
- shadows: any[];
7
- previewSettings: PreviewSettings;
8
- }
9
-
10
- type OverviewSize = "small" | "large";
11
-
12
- export function ShadowOverview({ shadows, previewSettings }: ShadowOverviewProps) {
13
- const [size, setSize] = useState<OverviewSize>("small");
14
-
15
- return (
16
- <div>
17
- {/* Size toggle tabs */}
18
- <div
19
- className="px-4 py-2 shrink-0"
20
- >
21
- <div className="studio-segmented" style={{ width: "100%" }}>
22
- <button
23
- onClick={() => setSize("small")}
24
- className={size === "small" ? "active" : ""}
25
- style={{ flex: 1 }}
26
- >
27
- Small
28
- </button>
29
- <button
30
- onClick={() => setSize("large")}
31
- className={size === "large" ? "active" : ""}
32
- style={{ flex: 1 }}
33
- >
34
- Large
35
- </button>
36
- </div>
37
- </div>
38
-
39
- {/* Shadow grid */}
40
- {size === "small" ? (
41
- <div
42
- className="grid gap-3 px-4 py-3"
43
- style={{ gridTemplateColumns: "repeat(2, 1fr)" }}
44
- >
45
- {shadows.map((shadow: any) => (
46
- <div key={shadow.name} className="flex flex-col items-center gap-2">
47
- <div
48
- className="flex items-center justify-center rounded-xl w-full"
49
- style={{
50
- background: previewSettings.previewBg,
51
- height: 100,
52
- }}
53
- >
54
- <ShadowPreview
55
- value={shadow.value}
56
- size={56}
57
- background="white"
58
- showBorder={previewSettings.showBorder}
59
- borderColor={previewSettings.borderColor}
60
- />
61
- </div>
62
- <span
63
- className="text-[9px] font-mono text-center truncate w-full"
64
- style={{ color: "var(--studio-text-muted)" }}
65
- >
66
- {shadow.name}
67
- </span>
68
- </div>
69
- ))}
70
- </div>
71
- ) : (
72
- <div className="flex flex-col gap-3 px-4 py-3">
73
- {shadows.map((shadow: any) => (
74
- <div key={shadow.name} className="flex flex-col items-center gap-2">
75
- <div
76
- className="flex items-center justify-center rounded-xl w-full"
77
- style={{
78
- background: previewSettings.previewBg,
79
- height: 200,
80
- }}
81
- >
82
- <ShadowPreview
83
- value={shadow.value}
84
- size={96}
85
- background="white"
86
- showBorder={previewSettings.showBorder}
87
- borderColor={previewSettings.borderColor}
88
- />
89
- </div>
90
- <span
91
- className="text-[9px] font-mono text-center truncate w-full"
92
- style={{ color: "var(--studio-text-muted)" }}
93
- >
94
- {shadow.name}
95
- </span>
96
- </div>
97
- ))}
98
- </div>
99
- )}
100
-
101
- {shadows.length === 0 && (
102
- <div
103
- className="px-4 py-6 text-center text-[11px]"
104
- style={{ color: "var(--studio-text-dimmed)" }}
105
- >
106
- No shadows to display
107
- </div>
108
- )}
109
- </div>
110
- );
111
- }
@@ -1,210 +0,0 @@
1
- import { useState, useRef, useEffect } from "react";
2
- import { Half2Icon } from "@radix-ui/react-icons";
3
-
4
- export interface PreviewSettings {
5
- previewBg: string;
6
- showBorder: boolean;
7
- borderColor: string;
8
- }
9
-
10
- export const DEFAULT_PREVIEW_SETTINGS: PreviewSettings = {
11
- previewBg: "rgb(240, 244, 250)",
12
- showBorder: false,
13
- borderColor: "#e8e8e8",
14
- };
15
-
16
- const BG_SWATCHES = [
17
- { name: "Soft Blue", value: "rgb(240, 244, 250)" },
18
- { name: "White", value: "white" },
19
- { name: "Light Gray", value: "#f0f0f0" },
20
- { name: "Gray", value: "#e0e0e0" },
21
- { name: "Mid Gray", value: "#d0d0d0" },
22
- { name: "Dark Gray", value: "#bbb" },
23
- ];
24
-
25
- const BORDER_COLORS = [
26
- { name: "Lightest", value: "#eee" },
27
- { name: "Light", value: "#e0e0e0" },
28
- { name: "Medium", value: "#d0d0d0" },
29
- { name: "Dark", value: "#bbb" },
30
- ];
31
-
32
- interface ShadowPreviewSettingsProps {
33
- settings: PreviewSettings;
34
- onChange: (settings: PreviewSettings) => void;
35
- }
36
-
37
- export function ShadowPreviewSettingsButton({
38
- settings,
39
- onChange,
40
- }: ShadowPreviewSettingsProps) {
41
- const [open, setOpen] = useState(false);
42
- const popoverRef = useRef<HTMLDivElement>(null);
43
- const buttonRef = useRef<HTMLButtonElement>(null);
44
-
45
- useEffect(() => {
46
- if (!open) return;
47
- const handleClick = (e: MouseEvent) => {
48
- if (
49
- popoverRef.current &&
50
- !popoverRef.current.contains(e.target as Node) &&
51
- buttonRef.current &&
52
- !buttonRef.current.contains(e.target as Node)
53
- ) {
54
- setOpen(false);
55
- }
56
- };
57
- document.addEventListener("mousedown", handleClick);
58
- return () => document.removeEventListener("mousedown", handleClick);
59
- }, [open]);
60
-
61
- return (
62
- <div style={{ position: "relative" }}>
63
- <button
64
- ref={buttonRef}
65
- onClick={() => setOpen(!open)}
66
- className="cursor-pointer"
67
- style={{
68
- display: "flex",
69
- alignItems: "center",
70
- gap: 6,
71
- padding: "3px 8px 3px 6px",
72
- borderRadius: 6,
73
- fontSize: 10,
74
- fontWeight: 500,
75
- color: open ? "var(--studio-accent)" : "var(--studio-text-dimmed)",
76
- background: open ? "var(--studio-accent-muted)" : "var(--studio-input-bg)",
77
- border: "1px solid",
78
- borderColor: open ? "var(--studio-accent)" : "var(--studio-border)",
79
- transition: "all 0.15s",
80
- }}
81
- >
82
- <Half2Icon style={{ width: 12, height: 12 }} />
83
- Settings
84
- </button>
85
-
86
- {open && (
87
- <div
88
- ref={popoverRef}
89
- style={{
90
- position: "absolute",
91
- top: "100%",
92
- right: 0,
93
- marginTop: 4,
94
- background: "var(--studio-surface)",
95
- border: "1px solid var(--studio-border)",
96
- borderRadius: 8,
97
- padding: "12px 14px",
98
- zIndex: 100,
99
- width: 248,
100
- boxShadow: "0 8px 24px rgb(0 0 0 / 0.15)",
101
- }}
102
- >
103
- <div className="flex flex-col gap-3.5">
104
- {/* Background */}
105
- <div>
106
- <div
107
- className="text-[9px] font-semibold uppercase tracking-wide mb-2"
108
- style={{ color: "var(--studio-text-dimmed)" }}
109
- >
110
- Preview Background
111
- </div>
112
- <div className="flex gap-1.5">
113
- {BG_SWATCHES.map((bg) => (
114
- <button
115
- key={bg.value}
116
- onClick={() =>
117
- onChange({ ...settings, previewBg: bg.value })
118
- }
119
- className="shrink-0 cursor-pointer"
120
- title={bg.name}
121
- style={{
122
- width: 24,
123
- height: 24,
124
- borderRadius: 5,
125
- background: bg.value,
126
- border:
127
- settings.previewBg === bg.value
128
- ? "2px solid var(--studio-accent)"
129
- : "1px solid var(--studio-border)",
130
- }}
131
- />
132
- ))}
133
- </div>
134
- </div>
135
-
136
- {/* Borders */}
137
- <div>
138
- <div className="flex items-center justify-between mb-2">
139
- <div
140
- className="text-[9px] font-semibold uppercase tracking-wide"
141
- style={{ color: "var(--studio-text-dimmed)" }}
142
- >
143
- Show card borders
144
- </div>
145
- <button
146
- onClick={() =>
147
- onChange({
148
- ...settings,
149
- showBorder: !settings.showBorder,
150
- })
151
- }
152
- className="shrink-0 cursor-pointer"
153
- style={{
154
- width: 34,
155
- height: 20,
156
- borderRadius: 10,
157
- border: "1px solid var(--studio-border)",
158
- background: settings.showBorder
159
- ? "var(--studio-accent)"
160
- : "var(--studio-input-bg)",
161
- position: "relative",
162
- transition: "background 0.15s",
163
- }}
164
- >
165
- <div
166
- style={{
167
- width: 14,
168
- height: 14,
169
- borderRadius: "50%",
170
- background: "white",
171
- position: "absolute",
172
- top: 2,
173
- left: settings.showBorder ? 16 : 2,
174
- transition: "left 0.15s",
175
- boxShadow: "0 1px 2px rgb(0 0 0 / 0.15)",
176
- }}
177
- />
178
- </button>
179
- </div>
180
- {settings.showBorder && (
181
- <div className="flex gap-1.5">
182
- {BORDER_COLORS.map((bc) => (
183
- <button
184
- key={bc.value}
185
- onClick={() =>
186
- onChange({ ...settings, borderColor: bc.value })
187
- }
188
- className="shrink-0 cursor-pointer"
189
- title={bc.name}
190
- style={{
191
- width: 24,
192
- height: 24,
193
- borderRadius: 5,
194
- background: bc.value,
195
- border:
196
- settings.borderColor === bc.value
197
- ? "2px solid var(--studio-accent)"
198
- : "1px solid var(--studio-border)",
199
- }}
200
- />
201
- ))}
202
- </div>
203
- )}
204
- </div>
205
- </div>
206
- </div>
207
- )}
208
- </div>
209
- );
210
- }
@@ -1,34 +0,0 @@
1
- interface ShadowPreviewProps {
2
- value: string;
3
- size?: number;
4
- shape?: "square" | "rounded" | "circle";
5
- background?: string;
6
- showBorder?: boolean;
7
- borderColor?: string;
8
- }
9
-
10
- export function ShadowPreview({
11
- value,
12
- size = 32,
13
- shape = "rounded",
14
- background = "white",
15
- showBorder = false,
16
- borderColor = "#e0e0e0",
17
- }: ShadowPreviewProps) {
18
- const borderRadius =
19
- shape === "circle" ? "50%" : shape === "rounded" ? "4px" : "0";
20
-
21
- return (
22
- <div
23
- className="shrink-0"
24
- style={{
25
- width: size,
26
- height: size,
27
- borderRadius,
28
- background,
29
- boxShadow: value,
30
- border: showBorder ? `1px solid ${borderColor}` : "none",
31
- }}
32
- />
33
- );
34
- }