@leviosa-ai/detail-page-editor 0.2.2 → 0.3.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.
Files changed (59) hide show
  1. package/components/cardnews/color-input.tsx +9 -9
  2. package/components/detail-page/ai-generate-panel.tsx +37 -37
  3. package/components/detail-page/annotation-canvas.tsx +9 -9
  4. package/components/detail-page/annotation-dialog.tsx +18 -18
  5. package/components/detail-page/canvas-context-menu.tsx +4 -4
  6. package/components/detail-page/chart-inspector.tsx +23 -23
  7. package/components/detail-page/design-reference-picker.tsx +22 -22
  8. package/components/detail-page/detail-page-basic-shapes.tsx +4 -4
  9. package/components/detail-page/detail-page-brand-gifs-panel.tsx +10 -10
  10. package/components/detail-page/detail-page-brand-kit-panel.tsx +5 -5
  11. package/components/detail-page/detail-page-brand-panel-header.tsx +7 -4
  12. package/components/detail-page/detail-page-charts-panel.tsx +4 -4
  13. package/components/detail-page/detail-page-decorations-panel.tsx +5 -5
  14. package/components/detail-page/detail-page-download-dialog.tsx +19 -19
  15. package/components/detail-page/detail-page-editor.tsx +131 -76
  16. package/components/detail-page/detail-page-elements-panel.tsx +4 -4
  17. package/components/detail-page/detail-page-font-picker.tsx +14 -14
  18. package/components/detail-page/detail-page-history-buttons.tsx +3 -3
  19. package/components/detail-page/detail-page-host-context.tsx +63 -0
  20. package/components/detail-page/detail-page-icons-panel.tsx +13 -13
  21. package/components/detail-page/detail-page-konva-json-preview.tsx +9 -9
  22. package/components/detail-page/detail-page-layers-panel.tsx +14 -14
  23. package/components/detail-page/detail-page-my-images-panel.tsx +29 -14
  24. package/components/detail-page/detail-page-my-shapes-panel.tsx +8 -8
  25. package/components/detail-page/detail-page-page-toolbar.tsx +10 -10
  26. package/components/detail-page/detail-page-pages-panel.tsx +13 -13
  27. package/components/detail-page/detail-page-pages-timeline.tsx +4 -4
  28. package/components/detail-page/detail-page-photos-panel.tsx +13 -13
  29. package/components/detail-page/detail-page-properties-panel.tsx +55 -55
  30. package/components/detail-page/detail-page-qr-panel.tsx +13 -13
  31. package/components/detail-page/detail-page-references-panel.tsx +9 -9
  32. package/components/detail-page/detail-page-sidebar-sections.tsx +1 -1
  33. package/components/detail-page/detail-page-tables-panel.tsx +4 -4
  34. package/components/detail-page/detail-page-text-panel.tsx +4 -4
  35. package/components/detail-page/edit-quota-ui.tsx +3 -3
  36. package/components/detail-page/element-recents-strip.tsx +6 -6
  37. package/components/detail-page/fill-control.tsx +12 -12
  38. package/components/detail-page/find-replace-panel.tsx +8 -8
  39. package/components/detail-page/generation-progress-fill.tsx +4 -4
  40. package/components/detail-page/gif-effect-picker.tsx +9 -9
  41. package/components/detail-page/group-prompt-edit-panel.tsx +3 -3
  42. package/components/detail-page/inspector-controls.tsx +9 -9
  43. package/components/detail-page/panel-search-input.tsx +2 -2
  44. package/components/detail-page/prompt-edit-panel.tsx +3 -3
  45. package/components/detail-page/section-reauthor-controller.tsx +2 -2
  46. package/components/detail-page/spec-prompt-edit-panel.tsx +3 -3
  47. package/components/detail-page/svg-prompt-edit-panel.tsx +3 -3
  48. package/components/detail-page/table-inspector.tsx +24 -24
  49. package/components/ui/button.tsx +6 -6
  50. package/components/ui/command.tsx +5 -5
  51. package/components/ui/dialog.tsx +3 -3
  52. package/components/ui/label.tsx +1 -1
  53. package/components/ui/select.tsx +3 -3
  54. package/components/ui/slider.tsx +1 -1
  55. package/components/ui/tooltip.tsx +1 -1
  56. package/lib/detail-page/use-progressive-reveal.ts +82 -0
  57. package/package.json +4 -1
  58. package/styles/canvas-bridge.css +35 -0
  59. package/styles/tokens.css +103 -0
@@ -67,10 +67,10 @@ function IconButton({
67
67
  onClick();
68
68
  }}
69
69
  className={[
70
- "flex h-8 w-8 items-center justify-center rounded-lg transition-colors",
70
+ "flex h-8 w-8 items-center justify-center rounded-dpe-lg transition-colors",
71
71
  disabled
72
- ? "cursor-not-allowed text-neutral-300"
73
- : "text-neutral-500 hover:bg-neutral-100 hover:text-neutral-900",
72
+ ? "cursor-not-allowed text-dpe-ink-300"
73
+ : "text-dpe-ink-500 hover:bg-dpe-ink-100 hover:text-dpe-ink-900",
74
74
  ].join(" ")}
75
75
  >
76
76
  {children}
@@ -110,7 +110,7 @@ export const DetailPagePageToolbar = observer(function DetailPagePageToolbar({
110
110
  };
111
111
 
112
112
  return (
113
- <div className="flex flex-col items-center gap-0.5 rounded-2xl border border-neutral-200 bg-white/95 px-1 py-1.5 shadow-md backdrop-blur-sm">
113
+ <div className="flex flex-col items-center gap-0.5 rounded-2xl border border-dpe-ink-200 bg-dpe-surface/95 px-1 py-1.5 shadow-md backdrop-blur-sm">
114
114
  <button
115
115
  type="button"
116
116
  title={t("detailPage.pageToolbar.aiGenerate")}
@@ -119,9 +119,9 @@ export const DetailPagePageToolbar = observer(function DetailPagePageToolbar({
119
119
  e.stopPropagation();
120
120
  s.openSidePanel?.("ai-generate");
121
121
  }}
122
- className="flex h-8 w-8 items-center justify-center rounded-lg transition-colors hover:bg-neutral-100"
122
+ className="flex h-8 w-8 items-center justify-center rounded-dpe-lg transition-colors hover:bg-dpe-ink-100"
123
123
  >
124
- <Sparkles size={17} className="text-fuchsia-500" />
124
+ <Sparkles size={17} className="text-dpe-ai" />
125
125
  </button>
126
126
 
127
127
  {/* 이 화면만 마크업째 다시 만든다 — 슬롯 카피 편집과 달리 칸 수·표 같은 구조가
@@ -139,13 +139,13 @@ export const DetailPagePageToolbar = observer(function DetailPagePageToolbar({
139
139
  e.stopPropagation();
140
140
  requestSectionReauthor(p.id);
141
141
  }}
142
- className="flex h-8 w-8 items-center justify-center rounded-lg transition-colors hover:bg-neutral-100"
142
+ className="flex h-8 w-8 items-center justify-center rounded-dpe-lg transition-colors hover:bg-dpe-ink-100"
143
143
  >
144
- <Wand2 size={16} className="text-violet-500" />
144
+ <Wand2 size={16} className="text-dpe-ai-alt" />
145
145
  </button>
146
146
  ) : null}
147
147
 
148
- <hr className="my-0.5 w-5 border-neutral-200" />
148
+ <hr className="my-0.5 w-5 border-dpe-ink-200" />
149
149
 
150
150
  <IconButton label={t("detailPage.pageToolbar.moveUp")} onClick={() => p.setZIndex(index - 1)} disabled={isFirst}>
151
151
  <ChevronUp size={17} />
@@ -160,7 +160,7 @@ export const DetailPagePageToolbar = observer(function DetailPagePageToolbar({
160
160
  <Plus size={17} />
161
161
  </IconButton>
162
162
 
163
- <hr className="my-0.5 w-5 border-neutral-200" />
163
+ <hr className="my-0.5 w-5 border-dpe-ink-200" />
164
164
 
165
165
  <IconButton label={t("detailPage.pageToolbar.delete")} onClick={() => s.deletePages([p.id])} disabled={!canDelete}>
166
166
  <Trash2 size={16} />
@@ -138,12 +138,12 @@ const PageRow = observer(function PageRow({
138
138
  if (!isDragging) store.selectPage(page.id);
139
139
  }}
140
140
  className={[
141
- "select-none rounded-xl border bg-white p-2 transition-shadow",
141
+ "select-none rounded-dpe-xl border bg-dpe-surface p-2 transition-shadow",
142
142
  isDragging
143
- ? "border-neutral-800 shadow-lg"
143
+ ? "border-dpe-ink-800 shadow-lg"
144
144
  : active
145
- ? "cursor-pointer border-neutral-800 shadow-sm"
146
- : "cursor-pointer border-neutral-200 hover:border-neutral-300",
145
+ ? "cursor-pointer border-dpe-ink-800 shadow-sm"
146
+ : "cursor-pointer border-dpe-ink-200 hover:border-dpe-ink-300",
147
147
  ].join(" ")}
148
148
  >
149
149
  <div className="flex items-center gap-2">
@@ -151,14 +151,14 @@ const PageRow = observer(function PageRow({
151
151
  {...listeners}
152
152
  aria-label={t("detailPage.pages.reorderHandle")}
153
153
  className={[
154
- "shrink-0 touch-none rounded text-neutral-300 hover:text-neutral-500",
154
+ "shrink-0 touch-none rounded text-dpe-ink-300 hover:text-dpe-ink-500",
155
155
  isDragging ? "cursor-grabbing" : "cursor-grab",
156
156
  ].join(" ")}
157
157
  >
158
158
  <GripVertical aria-hidden="true" size={16} />
159
159
  </span>
160
160
  <div
161
- className="relative shrink-0 overflow-hidden rounded-md border border-neutral-100 bg-neutral-50"
161
+ className="relative shrink-0 overflow-hidden rounded-dpe-md border border-dpe-ink-100 bg-dpe-ink-50"
162
162
  style={{ width: 64, height: Math.min(80, Math.max(40, 64 * ratio)) }}
163
163
  >
164
164
  {thumb ? (
@@ -173,11 +173,11 @@ const PageRow = observer(function PageRow({
173
173
  </div>
174
174
  <div className="min-w-0 flex-1">
175
175
  <p className="truncate text-sm">
176
- <span className="text-neutral-400">{role}</span>
176
+ <span className="text-dpe-ink-400">{role}</span>
177
177
  {title ? (
178
178
  <>
179
- <span className="mx-1 text-neutral-300">|</span>
180
- <span className="font-bold text-neutral-900">{title}</span>
179
+ <span className="mx-1 text-dpe-ink-300">|</span>
180
+ <span className="font-dpe-bold text-dpe-ink-900">{title}</span>
181
181
  </>
182
182
  ) : null}
183
183
  </p>
@@ -196,13 +196,13 @@ const PageRow = observer(function PageRow({
196
196
  aria-label={t("detailPage.pages.background")}
197
197
  aria-expanded={editingBackground}
198
198
  title={t("detailPage.pages.background")}
199
- className="h-6 w-6 shrink-0 rounded-md border border-neutral-200 hover:border-neutral-400"
199
+ className="h-6 w-6 shrink-0 rounded-dpe-md border border-dpe-ink-200 hover:border-dpe-ink-400"
200
200
  style={{ background }}
201
201
  />
202
202
  </div>
203
203
  {editingBackground ? (
204
204
  <div
205
- className="mt-2 border-t border-neutral-100 pt-2"
205
+ className="mt-2 border-t border-dpe-ink-100 pt-2"
206
206
  onClick={(event) => event.stopPropagation()}
207
207
  >
208
208
  <FillControl
@@ -260,10 +260,10 @@ export const DetailPagePagesPanel = observer(function DetailPagePagesPanel({
260
260
  return (
261
261
  <div className="flex h-full flex-col">
262
262
  <div className="flex items-baseline justify-between px-4 py-3">
263
- <p className="text-base font-bold text-neutral-900">
263
+ <p className="text-base font-dpe-bold text-dpe-ink-900">
264
264
  {t("detailPage.pages.totalPages", { count: s.pages.length })}
265
265
  </p>
266
- <p className="text-xs text-neutral-400">
266
+ <p className="text-xs text-dpe-ink-400">
267
267
  {width} × {totalHeight} px
268
268
  </p>
269
269
  </div>
@@ -41,7 +41,7 @@ export const DetailPagePagesTimeline = observer(function DetailPagePagesTimeline
41
41
  return (
42
42
  <div
43
43
  data-dp-pages-timeline=""
44
- className="pointer-events-auto absolute inset-x-0 bottom-0 z-20 flex items-center gap-1.5 overflow-x-auto border-t border-neutral-200 bg-white/95 px-3 py-1.5 backdrop-blur-sm"
44
+ className="pointer-events-auto absolute inset-x-0 bottom-0 z-20 flex items-center gap-1.5 overflow-x-auto border-t border-dpe-ink-200 bg-dpe-surface/95 px-3 py-1.5 backdrop-blur-sm"
45
45
  >
46
46
  {s.pages.map((page, index) => {
47
47
  const active = page.id === activeId;
@@ -54,10 +54,10 @@ export const DetailPagePagesTimeline = observer(function DetailPagePagesTimeline
54
54
  aria-current={active ? "true" : undefined}
55
55
  title={typeof page.name === "string" ? page.name : `${index + 1}`}
56
56
  className={[
57
- "flex h-10 w-8 shrink-0 items-center justify-center overflow-hidden rounded border text-[11px] font-semibold transition-colors",
57
+ "flex h-10 w-8 shrink-0 items-center justify-center overflow-hidden rounded border text-[11px] font-dpe-semibold transition-colors",
58
58
  active
59
- ? "border-neutral-900 bg-neutral-900 text-white"
60
- : "border-neutral-200 bg-white text-neutral-500 hover:border-neutral-400",
59
+ ? "border-dpe-ink-900 bg-dpe-ink-900 text-dpe-on-accent"
60
+ : "border-dpe-ink-200 bg-dpe-surface text-dpe-ink-500 hover:border-dpe-ink-400",
61
61
  ].join(" ")}
62
62
  >
63
63
  {thumb ? (
@@ -116,7 +116,7 @@ export function DetailPagePhotosPanel({
116
116
  type="button"
117
117
  disabled={!uploadFile || busy}
118
118
  onClick={() => inputRef.current?.click()}
119
- className="flex items-center justify-center gap-2 rounded-lg border border-dashed border-neutral-300 px-3 py-4 text-sm font-medium text-neutral-600 hover:border-neutral-400 disabled:cursor-not-allowed disabled:opacity-50"
119
+ className="flex items-center justify-center gap-2 rounded-dpe-lg border border-dashed border-dpe-ink-300 px-3 py-4 text-sm font-dpe-medium text-dpe-ink-600 hover:border-dpe-ink-400 disabled:cursor-not-allowed disabled:opacity-50"
120
120
  >
121
121
  {busy ? (
122
122
  <Loader2 aria-hidden="true" className="animate-spin" size={16} />
@@ -137,7 +137,7 @@ export function DetailPagePhotosPanel({
137
137
  }}
138
138
  />
139
139
 
140
- {error ? <p className="text-xs text-red-600">{error}</p> : null}
140
+ {error ? <p className="text-xs text-dpe-danger-600">{error}</p> : null}
141
141
 
142
142
  {recent.length ? (
143
143
  <div className="grid grid-cols-3 gap-2">
@@ -146,7 +146,7 @@ export function DetailPagePhotosPanel({
146
146
  key={url}
147
147
  type="button"
148
148
  onClick={() => insertPersonalImage(store, url)}
149
- className="aspect-square overflow-hidden rounded-lg border border-neutral-200 hover:border-neutral-400"
149
+ className="aspect-square overflow-hidden rounded-dpe-lg border border-dpe-ink-200 hover:border-dpe-ink-400"
150
150
  title={t("detailPage.shapes.insertHint")}
151
151
  >
152
152
  {/* eslint-disable-next-line @next/next/no-img-element */}
@@ -164,19 +164,19 @@ export function DetailPagePhotosPanel({
164
164
  />
165
165
 
166
166
  {!configured ? (
167
- <p className="px-1 text-xs leading-relaxed text-neutral-500">
167
+ <p className="px-1 text-xs leading-relaxed text-dpe-ink-500">
168
168
  {t("detailPage.photos.stockUnavailable")}
169
169
  </p>
170
170
  ) : stock.isLoading ? (
171
- <div className="flex justify-center py-6 text-neutral-400">
171
+ <div className="flex justify-center py-6 text-dpe-ink-400">
172
172
  <Loader2 aria-hidden="true" className="animate-spin" size={20} />
173
173
  </div>
174
174
  ) : stock.error ? (
175
- <p className="text-xs text-red-600">
175
+ <p className="text-xs text-dpe-danger-600">
176
176
  {t("detailPage.photos.stockFailed")}
177
177
  </p>
178
178
  ) : photos.length === 0 ? (
179
- <div className="flex flex-col items-center gap-2 py-6 text-center text-neutral-400">
179
+ <div className="flex flex-col items-center gap-2 py-6 text-center text-dpe-ink-400">
180
180
  <ImageOff aria-hidden="true" size={20} />
181
181
  <p className="text-xs">{t("detailPage.photos.stockEmpty")}</p>
182
182
  </div>
@@ -186,7 +186,7 @@ export function DetailPagePhotosPanel({
186
186
  {photos.map((photo) => (
187
187
  <div
188
188
  key={photo.id}
189
- className="group relative overflow-hidden rounded-lg border border-neutral-200 hover:border-neutral-400"
189
+ className="group relative overflow-hidden rounded-dpe-lg border border-dpe-ink-200 hover:border-dpe-ink-400"
190
190
  >
191
191
  <button
192
192
  type="button"
@@ -203,10 +203,10 @@ export function DetailPagePhotosPanel({
203
203
  className="h-24 w-full object-cover transition group-hover:opacity-90"
204
204
  />
205
205
  {inserting === photo.id ? (
206
- <span className="absolute inset-0 flex items-center justify-center bg-white/70">
206
+ <span className="absolute inset-0 flex items-center justify-center bg-dpe-surface/70">
207
207
  <Loader2
208
208
  aria-hidden="true"
209
- className="animate-spin text-neutral-500"
209
+ className="animate-spin text-dpe-ink-500"
210
210
  size={18}
211
211
  />
212
212
  </span>
@@ -217,7 +217,7 @@ export function DetailPagePhotosPanel({
217
217
  href={photo.pageUrl}
218
218
  target="_blank"
219
219
  rel="noreferrer noopener"
220
- className="absolute bottom-0 left-0 right-0 hidden truncate bg-black/60 px-1.5 py-1 text-[10px] text-white group-hover:block hover:underline"
220
+ className="absolute bottom-0 left-0 right-0 hidden truncate bg-dpe-scrim/60 px-1.5 py-1 text-[10px] text-dpe-on-accent group-hover:block hover:underline"
221
221
  >
222
222
  {photo.photographer}
223
223
  </a>
@@ -230,7 +230,7 @@ export function DetailPagePhotosPanel({
230
230
  type="button"
231
231
  disabled={stock.isFetchingNextPage}
232
232
  onClick={() => void stock.fetchNextPage()}
233
- className="mx-auto flex items-center gap-1.5 rounded-md border border-neutral-200 px-3 py-1.5 text-xs font-medium text-neutral-600 hover:border-neutral-400 disabled:opacity-50"
233
+ className="mx-auto flex items-center gap-1.5 rounded-dpe-md border border-dpe-ink-200 px-3 py-1.5 text-xs font-dpe-medium text-dpe-ink-600 hover:border-dpe-ink-400 disabled:opacity-50"
234
234
  >
235
235
  {stock.isFetchingNextPage ? (
236
236
  <Loader2 aria-hidden="true" className="animate-spin" size={12} />
@@ -241,7 +241,7 @@ export function DetailPagePhotosPanel({
241
241
  </>
242
242
  )}
243
243
 
244
- <p className="mt-auto px-1 pt-1 text-xs leading-relaxed text-neutral-500">
244
+ <p className="mt-auto px-1 pt-1 text-xs leading-relaxed text-dpe-ink-500">
245
245
  {t("detailPage.photos.hint")}{" "}
246
246
  <a
247
247
  href="https://www.pexels.com"