@morphika/andami 0.1.3 → 0.1.6

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.
Files changed (105) hide show
  1. package/app/(site)/[slug]/page.tsx +7 -4
  2. package/app/(site)/layout.tsx +5 -2
  3. package/app/(site)/page.tsx +2 -2
  4. package/app/(site)/preview/page.tsx +4 -4
  5. package/app/(site)/work/[slug]/page.tsx +7 -4
  6. package/app/admin/layout.tsx +3 -2
  7. package/app/admin/login/page.tsx +5 -5
  8. package/app/admin/navigation/page.tsx +255 -157
  9. package/app/api/admin/assets/health/route.ts +1 -1
  10. package/app/api/admin/assets/register/route.ts +1 -1
  11. package/app/api/admin/assets/registry/route.ts +1 -1
  12. package/app/api/admin/assets/relink/confirm/route.ts +2 -2
  13. package/app/api/admin/assets/relink/route.ts +1 -1
  14. package/app/api/admin/assets/scan/route.ts +1 -1
  15. package/app/api/admin/custom-sections/[slug]/route.ts +1 -1
  16. package/app/api/admin/custom-sections/route.ts +1 -1
  17. package/app/api/admin/database/route.ts +1 -1
  18. package/app/api/admin/pages/[slug]/duplicate/route.ts +1 -1
  19. package/app/api/admin/pages/[slug]/route.ts +2 -2
  20. package/app/api/admin/pages/[slug]/set-home/route.ts +1 -1
  21. package/app/api/admin/pages/route.ts +1 -1
  22. package/app/api/admin/preview/route.ts +1 -1
  23. package/app/api/admin/r2/delete/route.ts +1 -1
  24. package/app/api/admin/r2/rename/route.ts +1 -1
  25. package/app/api/admin/r2/status/route.ts +1 -1
  26. package/app/api/admin/r2/upload-url/route.ts +1 -1
  27. package/app/api/admin/settings/route.ts +41 -16
  28. package/app/api/admin/setup/complete/route.ts +2 -2
  29. package/app/api/admin/setup/route.ts +7 -4
  30. package/app/api/admin/storage/switch/route.ts +1 -1
  31. package/app/api/admin/styles/route.ts +1 -1
  32. package/components/admin/index.ts +7 -0
  33. package/components/admin/nav-builder/NavGeneralSettings.tsx +11 -15
  34. package/components/admin/nav-builder/NavItemSettings.tsx +29 -5
  35. package/components/admin/nav-builder/NavLivePreview.tsx +4 -1
  36. package/components/admin/nav-builder/NavMobileLivePreview.tsx +226 -0
  37. package/components/admin/nav-builder/NavMobileSettings.tsx +223 -0
  38. package/components/admin/nav-builder/index.ts +2 -0
  39. package/components/blocks/BlockRenderer.tsx +65 -13
  40. package/components/blocks/ButtonBlockRenderer.tsx +29 -6
  41. package/components/blocks/CoverBlockRenderer.tsx +36 -14
  42. package/components/blocks/ImageBlockRenderer.tsx +5 -3
  43. package/components/blocks/ImageGridBlockRenderer.tsx +13 -6
  44. package/components/blocks/PageRenderer.tsx +4 -2
  45. package/components/blocks/ProjectGridBlockRenderer.tsx +18 -3
  46. package/components/blocks/SectionRenderer.tsx +9 -8
  47. package/components/blocks/SectionV2Renderer.tsx +8 -8
  48. package/components/blocks/SpacerBlockRenderer.tsx +4 -2
  49. package/components/blocks/TextBlockRenderer.tsx +9 -4
  50. package/components/builder/BuilderCanvas.tsx +10 -4
  51. package/components/builder/ColorPicker.tsx +51 -243
  52. package/components/builder/ColorSwatchPicker.tsx +214 -274
  53. package/components/builder/DndWrapper.tsx +5 -2
  54. package/components/builder/SectionV2Canvas.tsx +15 -4
  55. package/components/builder/asset-browser/useAssetBrowser.ts +9 -1
  56. package/components/builder/color-picker/AlphaSlider.tsx +141 -0
  57. package/components/builder/color-picker/AngleControl.tsx +138 -0
  58. package/components/builder/color-picker/ColorInputs.tsx +105 -0
  59. package/components/builder/color-picker/EyedropperButton.tsx +74 -0
  60. package/components/builder/color-picker/GradientBar.tsx +222 -0
  61. package/components/builder/color-picker/GradientPreview.tsx +53 -0
  62. package/components/builder/color-picker/HueSlider.tsx +124 -0
  63. package/components/builder/color-picker/MeshCanvas.tsx +172 -0
  64. package/components/builder/color-picker/MeshPointEditor.tsx +133 -0
  65. package/components/builder/color-picker/MeshPointList.tsx +200 -0
  66. package/components/builder/color-picker/PositionControl.tsx +158 -0
  67. package/components/builder/color-picker/SaturationCanvas.tsx +142 -0
  68. package/components/builder/color-picker/StopEditor.tsx +178 -0
  69. package/components/builder/color-picker/SwatchBar.tsx +93 -0
  70. package/components/builder/color-picker/UnifiedColorPicker.tsx +713 -0
  71. package/components/builder/color-picker/index.ts +62 -0
  72. package/components/builder/color-picker/types.ts +115 -0
  73. package/components/builder/color-picker/utils.ts +138 -0
  74. package/components/builder/editors/CoverBlockEditor.tsx +86 -32
  75. package/components/builder/editors/ProjectGridEditor.tsx +51 -4
  76. package/components/builder/hooks/useColumnDrag.ts +25 -27
  77. package/components/builder/settings-panel/BlockLayoutTab.tsx +29 -7
  78. package/components/builder/settings-panel/LayoutTab.tsx +382 -310
  79. package/components/builder/settings-panel/PageSettings.tsx +6 -4
  80. package/components/builder/settings-panel/ParallaxSlideSettings.tsx +2 -2
  81. package/components/builder/settings-panel/SectionV2LayoutTab.tsx +392 -312
  82. package/components/builder/settings-panel/SectionV2Settings.tsx +65 -35
  83. package/components/ui/Navbar.tsx +97 -25
  84. package/components/ui/PortfolioTracker.tsx +3 -3
  85. package/lib/assets.ts +1 -1
  86. package/lib/auth.ts +1 -1
  87. package/lib/builder/gradient-presets.ts +128 -0
  88. package/lib/builder/layout-styles.ts +16 -10
  89. package/lib/builder/serializer.ts +1 -0
  90. package/lib/builder/store-blocks.ts +48 -61
  91. package/lib/builder/store-helpers.ts +31 -14
  92. package/lib/builder/store.ts +59 -41
  93. package/lib/builder/types.ts +14 -0
  94. package/lib/color-utils.ts +200 -0
  95. package/lib/revalidate.ts +2 -2
  96. package/lib/sanity/client.ts +16 -0
  97. package/lib/sanity/queries.ts +4 -3
  98. package/lib/sanity/types.ts +76 -1
  99. package/lib/setup/detect.ts +1 -1
  100. package/lib/storage/index.ts +22 -4
  101. package/lib/version.ts +6 -0
  102. package/package.json +8 -2
  103. package/sanity/schemas/siteSettings.ts +34 -0
  104. package/styles/base.css +3 -3
  105. package/app/globals.css +0 -7
@@ -1,243 +1,51 @@
1
- "use client";
2
-
3
- /**
4
- * ColorPicker Full-featured HSL color picker with hex/RGB display.
5
- * Used in the Global Styles palette editor and inline block editors.
6
- */
7
-
8
- import { useState, useRef, useCallback, useEffect } from "react";
9
- import { hexToHSL, hsvToHex, hexToHSV, isValidHex } from "../../lib/color-utils";
10
-
11
- // ─── ColorPicker Component ───
12
-
13
- interface ColorPickerProps {
14
- color: string;
15
- onChange: (hex: string) => void;
16
- onClose?: () => void;
17
- /** Label for the confirm button */
18
- confirmLabel?: string;
19
- /** If true, shows a compact version (no confirm/cancel buttons, live onChange) */
20
- compact?: boolean;
21
- }
22
-
23
- export default function ColorPicker({
24
- color,
25
- onChange,
26
- onClose,
27
- confirmLabel = "Confirm",
28
- compact = false,
29
- }: ColorPickerProps) {
30
- const initHsv = hexToHSV(isValidHex(color) ? color : "#ffffff");
31
- const [hue, setHue] = useState(initHsv.h);
32
- const [sat, setSat] = useState(initHsv.s);
33
- const [val, setVal] = useState(initHsv.v);
34
- const [hex, setHex] = useState(isValidHex(color) ? color : "#ffffff");
35
- const canvasRef = useRef<HTMLDivElement>(null);
36
- const hueRef = useRef<HTMLDivElement>(null);
37
- const draggingCanvas = useRef(false);
38
- const draggingHue = useRef(false);
39
-
40
- // Sync hex from HSV
41
- const updateHex = useCallback((h: number, s: number, v: number) => {
42
- const newHex = hsvToHex(h, s, v);
43
- setHex(newHex);
44
- if (compact) onChange(newHex);
45
- }, [compact, onChange]);
46
-
47
- // Canvas (saturation + value) interaction
48
- const handleCanvasMove = useCallback((e: React.MouseEvent | MouseEvent) => {
49
- const rect = canvasRef.current?.getBoundingClientRect();
50
- if (!rect) return;
51
- const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
52
- const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
53
- const s = Math.round(x * 100);
54
- const v = Math.round((1 - y) * 100);
55
- setSat(s);
56
- setVal(v);
57
- updateHex(hue, s, v);
58
- }, [hue, updateHex]);
59
-
60
- // Hue slider interaction
61
- const handleHueMove = useCallback((e: React.MouseEvent | MouseEvent) => {
62
- const rect = hueRef.current?.getBoundingClientRect();
63
- if (!rect) return;
64
- const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
65
- const h = Math.round(x * 360);
66
- setHue(h);
67
- updateHex(h, sat, val);
68
- }, [sat, val, updateHex]);
69
-
70
- // Global mouse up
71
- useEffect(() => {
72
- const handleUp = () => {
73
- draggingCanvas.current = false;
74
- draggingHue.current = false;
75
- };
76
- const handleMove = (e: MouseEvent) => {
77
- if (draggingCanvas.current) handleCanvasMove(e);
78
- if (draggingHue.current) handleHueMove(e);
79
- };
80
- window.addEventListener("mouseup", handleUp);
81
- window.addEventListener("mousemove", handleMove);
82
- return () => {
83
- window.removeEventListener("mouseup", handleUp);
84
- window.removeEventListener("mousemove", handleMove);
85
- };
86
- }, [handleCanvasMove, handleHueMove]);
87
-
88
- const handleHexInput = (v: string) => {
89
- setHex(v);
90
- if (isValidHex(v)) {
91
- const hsv = hexToHSV(v);
92
- setHue(hsv.h);
93
- setSat(hsv.s);
94
- setVal(hsv.v);
95
- if (compact) onChange(v);
96
- }
97
- };
98
-
99
- // Keyboard handlers for canvas (saturation/value) and hue slider
100
- const handleCanvasKeyDown = useCallback((e: React.KeyboardEvent) => {
101
- const step = e.shiftKey ? 10 : 2;
102
- let newSat = sat;
103
- let newVal = val;
104
- switch (e.key) {
105
- case "ArrowRight": newSat = Math.min(100, sat + step); break;
106
- case "ArrowLeft": newSat = Math.max(0, sat - step); break;
107
- case "ArrowUp": newVal = Math.min(100, val + step); break;
108
- case "ArrowDown": newVal = Math.max(0, val - step); break;
109
- default: return;
110
- }
111
- e.preventDefault();
112
- setSat(newSat);
113
- setVal(newVal);
114
- updateHex(hue, newSat, newVal);
115
- }, [sat, val, hue, updateHex]);
116
-
117
- const handleHueKeyDown = useCallback((e: React.KeyboardEvent) => {
118
- const step = e.shiftKey ? 20 : 5;
119
- let newHue = hue;
120
- switch (e.key) {
121
- case "ArrowRight": newHue = Math.min(360, hue + step); break;
122
- case "ArrowLeft": newHue = Math.max(0, hue - step); break;
123
- default: return;
124
- }
125
- e.preventDefault();
126
- setHue(newHue);
127
- updateHex(newHue, sat, val);
128
- }, [hue, sat, val, updateHex]);
129
-
130
- const r = parseInt(hex.slice(1, 3), 16) || 0;
131
- const g = parseInt(hex.slice(3, 5), 16) || 0;
132
- const b = parseInt(hex.slice(5, 7), 16) || 0;
133
-
134
- return (
135
- <div className="bg-white rounded-2xl p-4 w-[260px] shadow-xl border border-neutral-200">
136
- {/* Saturation/Value canvas */}
137
- <div
138
- ref={canvasRef}
139
- role="slider"
140
- tabIndex={0}
141
- aria-label="Color saturation and brightness"
142
- aria-valuetext={`Saturation ${sat}%, Brightness ${val}%`}
143
- className="w-full h-[160px] rounded-xl cursor-crosshair relative select-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#076bff]"
144
- style={{
145
- background: `linear-gradient(to bottom, transparent, #000), linear-gradient(to right, #fff, hsl(${hue}, 100%, 50%))`,
146
- }}
147
- onMouseDown={(e) => { draggingCanvas.current = true; handleCanvasMove(e); }}
148
- onKeyDown={handleCanvasKeyDown}
149
- >
150
- <div
151
- className="absolute w-4 h-4 rounded-full border-2 border-white pointer-events-none"
152
- style={{
153
- left: `${sat}%`,
154
- top: `${100 - val}%`,
155
- transform: "translate(-50%, -50%)",
156
- boxShadow: "0 0 0 1px rgba(0,0,0,0.3), 0 2px 6px rgba(0,0,0,0.3)",
157
- }}
158
- />
159
- </div>
160
-
161
- {/* Hue slider */}
162
- <div
163
- ref={hueRef}
164
- role="slider"
165
- tabIndex={0}
166
- aria-label="Color hue"
167
- aria-valuemin={0}
168
- aria-valuemax={360}
169
- aria-valuenow={hue}
170
- aria-valuetext={`Hue ${hue} degrees`}
171
- className="w-full h-3.5 rounded-full mt-3 cursor-pointer relative select-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#076bff]"
172
- style={{
173
- background: "linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)",
174
- }}
175
- onMouseDown={(e) => { draggingHue.current = true; handleHueMove(e); }}
176
- onKeyDown={handleHueKeyDown}
177
- >
178
- <div
179
- className="absolute w-4 h-4 rounded-full border-2 border-white pointer-events-none"
180
- style={{
181
- left: `${(hue / 360) * 100}%`,
182
- top: "50%",
183
- transform: "translate(-50%, -50%)",
184
- background: `hsl(${hue}, 100%, 50%)`,
185
- boxShadow: "0 1px 3px rgba(0,0,0,0.4)",
186
- }}
187
- />
188
- </div>
189
-
190
- {/* Hex input */}
191
- <div className="flex items-center gap-2.5 mt-3.5">
192
- <div
193
- className="w-8 h-8 rounded-lg border border-neutral-200 shrink-0"
194
- style={{ background: hex }}
195
- />
196
- <input
197
- value={hex.toUpperCase()}
198
- onChange={(e) => handleHexInput(e.target.value)}
199
- className="flex-1 bg-neutral-50 border border-neutral-200 rounded-lg px-2.5 py-1.5 text-neutral-900 text-xs font-mono outline-none focus:border-[#076bff] focus:ring-2 focus:ring-[#076bff]/10 transition-colors"
200
- />
201
- </div>
202
-
203
- {/* RGB readout */}
204
- <div className="flex gap-2 mt-2.5">
205
- {[
206
- { label: "R", val: r },
207
- { label: "G", val: g },
208
- { label: "B", val: b },
209
- ].map(({ label, val: v }) => (
210
- <div key={label} className="flex-1">
211
- <div className="text-[9px] text-neutral-400 uppercase tracking-widest mb-0.5">{label}</div>
212
- <div className="bg-neutral-50 border border-neutral-200 rounded-md px-2 py-1 text-neutral-600 text-[11px] text-center font-mono">
213
- {v}
214
- </div>
215
- </div>
216
- ))}
217
- </div>
218
-
219
- {/* Buttons (non-compact mode) */}
220
- {!compact && (
221
- <div className="flex gap-2 mt-3.5">
222
- {onClose && (
223
- <button
224
- onClick={onClose}
225
- className="flex-1 py-2 rounded-lg border border-neutral-200 bg-transparent text-neutral-500 text-xs font-mono cursor-pointer hover:border-neutral-300 hover:text-neutral-700 transition-colors"
226
- >
227
- Cancel
228
- </button>
229
- )}
230
- <button
231
- onClick={() => { onChange(hex); onClose?.(); }}
232
- className="flex-1 py-2 rounded-lg border-none bg-[#076bff] text-white text-xs font-mono font-semibold cursor-pointer hover:bg-[#0559d4] transition-colors"
233
- >
234
- {confirmLabel}
235
- </button>
236
- </div>
237
- )}
238
- </div>
239
- );
240
- }
241
-
242
- // ─── Export helpers ───
243
- export { isValidHex, hexToHSL, hexToHSV, hsvToHex };
1
+ "use client";
2
+
3
+ /**
4
+ * @deprecated Use `UnifiedColorPicker` from `./color-picker` instead.
5
+ *
6
+ * This file is kept for backward compatibility. It re-exports the new
7
+ * UnifiedColorPicker with an adapter that maps the old props to the new API.
8
+ *
9
+ * Old API: ColorPicker({ color, onChange, onClose, confirmLabel, compact })
10
+ * New API: UnifiedColorPicker({ value, onChange, onClose, confirmLabel, ... })
11
+ */
12
+
13
+ import { UnifiedColorPicker } from "./color-picker";
14
+ import { isValidHex } from "../../lib/color-utils";
15
+
16
+ // Re-export helpers for any consumers that imported from here
17
+ export { isValidHex } from "../../lib/color-utils";
18
+ export { hexToHSL, hexToHSV, hsvToHex } from "../../lib/color-utils";
19
+
20
+ // ─── Legacy ColorPicker Adapter ───
21
+
22
+ interface ColorPickerProps {
23
+ /** @deprecated Use `value` instead */
24
+ color: string;
25
+ onChange: (hex: string) => void;
26
+ onClose?: () => void;
27
+ confirmLabel?: string;
28
+ /** @deprecated Compact mode is no longer supported. Ignored. */
29
+ compact?: boolean;
30
+ }
31
+
32
+ /**
33
+ * @deprecated Use `import { UnifiedColorPicker } from "./color-picker"` instead.
34
+ */
35
+ export default function ColorPicker({
36
+ color,
37
+ onChange,
38
+ onClose,
39
+ confirmLabel = "Confirm",
40
+ }: ColorPickerProps) {
41
+ const handleClose = onClose ?? (() => {});
42
+
43
+ return (
44
+ <UnifiedColorPicker
45
+ value={isValidHex(color) ? color : "#ffffff"}
46
+ onChange={(val) => onChange(typeof val === "string" ? val : "#000000")}
47
+ onClose={handleClose}
48
+ confirmLabel={confirmLabel}
49
+ />
50
+ );
51
+ }