@leviosa-ai/detail-page-editor 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/cardnews/color-input.tsx +9 -9
- package/components/detail-page/ai-generate-panel.tsx +37 -37
- package/components/detail-page/annotation-canvas.tsx +9 -9
- package/components/detail-page/annotation-dialog.tsx +18 -18
- package/components/detail-page/canvas-context-menu.tsx +4 -4
- package/components/detail-page/chart-inspector.tsx +23 -23
- package/components/detail-page/design-reference-picker.tsx +22 -22
- package/components/detail-page/detail-page-basic-shapes.tsx +4 -4
- package/components/detail-page/detail-page-brand-gifs-panel.tsx +10 -10
- package/components/detail-page/detail-page-brand-kit-panel.tsx +5 -5
- package/components/detail-page/detail-page-brand-panel-header.tsx +7 -4
- package/components/detail-page/detail-page-charts-panel.tsx +4 -4
- package/components/detail-page/detail-page-decorations-panel.tsx +5 -5
- package/components/detail-page/detail-page-download-dialog.tsx +19 -19
- package/components/detail-page/detail-page-editor.tsx +131 -76
- package/components/detail-page/detail-page-elements-panel.tsx +4 -4
- package/components/detail-page/detail-page-font-picker.tsx +14 -14
- package/components/detail-page/detail-page-history-buttons.tsx +3 -3
- package/components/detail-page/detail-page-host-context.tsx +63 -0
- package/components/detail-page/detail-page-icons-panel.tsx +13 -13
- package/components/detail-page/detail-page-konva-json-preview.tsx +9 -9
- package/components/detail-page/detail-page-layers-panel.tsx +14 -14
- package/components/detail-page/detail-page-my-images-panel.tsx +29 -14
- package/components/detail-page/detail-page-my-shapes-panel.tsx +8 -8
- package/components/detail-page/detail-page-page-toolbar.tsx +10 -10
- package/components/detail-page/detail-page-pages-panel.tsx +13 -13
- package/components/detail-page/detail-page-pages-timeline.tsx +4 -4
- package/components/detail-page/detail-page-photos-panel.tsx +13 -13
- package/components/detail-page/detail-page-properties-panel.tsx +55 -55
- package/components/detail-page/detail-page-qr-panel.tsx +13 -13
- package/components/detail-page/detail-page-references-panel.tsx +9 -9
- package/components/detail-page/detail-page-sidebar-sections.tsx +1 -1
- package/components/detail-page/detail-page-tables-panel.tsx +4 -4
- package/components/detail-page/detail-page-text-panel.tsx +4 -4
- package/components/detail-page/edit-quota-ui.tsx +3 -3
- package/components/detail-page/element-recents-strip.tsx +6 -6
- package/components/detail-page/fill-control.tsx +12 -12
- package/components/detail-page/find-replace-panel.tsx +8 -8
- package/components/detail-page/generation-progress-fill.tsx +4 -4
- package/components/detail-page/gif-effect-picker.tsx +9 -9
- package/components/detail-page/group-prompt-edit-panel.tsx +3 -3
- package/components/detail-page/inspector-controls.tsx +9 -9
- package/components/detail-page/panel-search-input.tsx +2 -2
- package/components/detail-page/prompt-edit-panel.tsx +3 -3
- package/components/detail-page/section-reauthor-controller.tsx +2 -2
- package/components/detail-page/spec-prompt-edit-panel.tsx +3 -3
- package/components/detail-page/svg-prompt-edit-panel.tsx +3 -3
- package/components/detail-page/table-inspector.tsx +24 -24
- package/components/ui/button.tsx +6 -6
- package/components/ui/command.tsx +5 -5
- package/components/ui/dialog.tsx +3 -3
- package/components/ui/label.tsx +1 -1
- package/components/ui/select.tsx +3 -3
- package/components/ui/slider.tsx +1 -1
- package/components/ui/tooltip.tsx +1 -1
- package/lib/detail-page/use-progressive-reveal.ts +82 -0
- package/lib/detail-page-canvas/konva-fallback.ts +10 -4
- package/package.json +4 -1
- package/styles/canvas-bridge.css +35 -0
- package/styles/tokens.css +103 -0
|
@@ -80,7 +80,7 @@ function Cell({
|
|
|
80
80
|
(e.target as HTMLInputElement).blur();
|
|
81
81
|
}
|
|
82
82
|
}}
|
|
83
|
-
className={`w-full min-w-0 rounded-md border border-
|
|
83
|
+
className={`w-full min-w-0 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface px-2 py-1.5 text-sm text-dpe-ink-900 outline-none focus:border-dpe-ink-400 ${
|
|
84
84
|
align === "right" ? "text-right tabular-nums" : ""
|
|
85
85
|
}`}
|
|
86
86
|
/>
|
|
@@ -220,10 +220,10 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
220
220
|
type="button"
|
|
221
221
|
aria-pressed={kind === spec.kind}
|
|
222
222
|
onClick={() => apply({ kind })}
|
|
223
|
-
className={`h-8 rounded-md border text-xs transition-colors ${
|
|
223
|
+
className={`h-8 rounded-dpe-md border text-xs transition-colors ${
|
|
224
224
|
kind === spec.kind
|
|
225
|
-
? "border-
|
|
226
|
-
: "border-
|
|
225
|
+
? "border-dpe-ink-300 bg-dpe-ink-100 font-dpe-semibold text-dpe-ink-900"
|
|
226
|
+
: "border-dpe-ink-200 bg-dpe-surface text-dpe-ink-600 hover:bg-dpe-ink-50"
|
|
227
227
|
}`}
|
|
228
228
|
>
|
|
229
229
|
{t(`detailPage.chart.kinds.${kind}`)}
|
|
@@ -231,7 +231,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
231
231
|
))}
|
|
232
232
|
</div>
|
|
233
233
|
{resolved.hiddenSeries > 0 ? (
|
|
234
|
-
<p className="mt-2 text-[11px] text-
|
|
234
|
+
<p className="mt-2 text-[11px] text-dpe-warn-600">
|
|
235
235
|
{t("detailPage.chart.hiddenSeries", { count: resolved.hiddenSeries })}
|
|
236
236
|
</p>
|
|
237
237
|
) : null}
|
|
@@ -239,7 +239,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
239
239
|
|
|
240
240
|
<Section title={t("detailPage.chart.data")}>
|
|
241
241
|
<div onPaste={onPaste}>
|
|
242
|
-
<div className="flex items-center gap-1.5 pb-1 text-[11px] text-
|
|
242
|
+
<div className="flex items-center gap-1.5 pb-1 text-[11px] text-dpe-ink-400">
|
|
243
243
|
<span className="flex-1">{t("detailPage.chart.columnLabel")}</span>
|
|
244
244
|
{spec.data.series.map((series) => (
|
|
245
245
|
<span key={series.name} className="w-20 text-right">
|
|
@@ -296,7 +296,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
296
296
|
},
|
|
297
297
|
})
|
|
298
298
|
}
|
|
299
|
-
className="flex h-8 w-6 shrink-0 items-center justify-center rounded-md text-
|
|
299
|
+
className="flex h-8 w-6 shrink-0 items-center justify-center rounded-dpe-md text-dpe-ink-400 hover:text-dpe-danger-500 disabled:cursor-not-allowed disabled:opacity-30"
|
|
300
300
|
>
|
|
301
301
|
<Trash2 size={14} />
|
|
302
302
|
</button>
|
|
@@ -306,12 +306,12 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
306
306
|
<button
|
|
307
307
|
type="button"
|
|
308
308
|
onClick={() => setData(withRowAdded(spec.data))}
|
|
309
|
-
className="mt-2 inline-flex h-8 w-full items-center justify-center gap-1.5 rounded-md border border-
|
|
309
|
+
className="mt-2 inline-flex h-8 w-full items-center justify-center gap-1.5 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface text-xs font-dpe-medium text-dpe-ink-600 hover:bg-dpe-ink-50"
|
|
310
310
|
>
|
|
311
311
|
<Plus size={14} />
|
|
312
312
|
{t("detailPage.chart.addRow")}
|
|
313
313
|
</button>
|
|
314
|
-
<p className="mt-1.5 text-[11px] text-
|
|
314
|
+
<p className="mt-1.5 text-[11px] text-dpe-ink-400">
|
|
315
315
|
{notice ?? t("detailPage.chart.pasteHint")}
|
|
316
316
|
</p>
|
|
317
317
|
</div>
|
|
@@ -320,7 +320,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
320
320
|
<Section title={t("detailPage.chart.display")}>
|
|
321
321
|
<div className="grid grid-cols-2 gap-2">
|
|
322
322
|
<label className="flex items-center gap-2">
|
|
323
|
-
<span className="w-10 shrink-0 text-xs text-
|
|
323
|
+
<span className="w-10 shrink-0 text-xs text-dpe-ink-500">
|
|
324
324
|
{t("detailPage.chart.unit")}
|
|
325
325
|
</span>
|
|
326
326
|
<Cell
|
|
@@ -331,7 +331,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
331
331
|
/>
|
|
332
332
|
</label>
|
|
333
333
|
<label className="flex items-center gap-2">
|
|
334
|
-
<span className="w-10 shrink-0 text-xs text-
|
|
334
|
+
<span className="w-10 shrink-0 text-xs text-dpe-ink-500">
|
|
335
335
|
{t("detailPage.chart.decimals")}
|
|
336
336
|
</span>
|
|
337
337
|
<NumberField
|
|
@@ -375,14 +375,14 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
375
375
|
|
|
376
376
|
<div className="mt-2 grid grid-cols-2 gap-2">
|
|
377
377
|
<label className="flex items-center gap-2">
|
|
378
|
-
<span className="w-10 shrink-0 text-xs text-
|
|
378
|
+
<span className="w-10 shrink-0 text-xs text-dpe-ink-500">
|
|
379
379
|
{t("detailPage.chart.max")}
|
|
380
380
|
</span>
|
|
381
381
|
{spec.options.max === "auto" ? (
|
|
382
382
|
<button
|
|
383
383
|
type="button"
|
|
384
384
|
onClick={() => setOptions({ max: Math.round(resolved.max) })}
|
|
385
|
-
className="h-8 min-w-0 flex-1 rounded-md border border-
|
|
385
|
+
className="h-8 min-w-0 flex-1 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface text-xs text-dpe-ink-500 hover:bg-dpe-ink-50"
|
|
386
386
|
>
|
|
387
387
|
{t("detailPage.chart.maxAuto")}
|
|
388
388
|
</button>
|
|
@@ -398,7 +398,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
398
398
|
<button
|
|
399
399
|
type="button"
|
|
400
400
|
onClick={() => setOptions({ max: "auto" })}
|
|
401
|
-
className="h-8 rounded-md border border-
|
|
401
|
+
className="h-8 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface text-xs text-dpe-ink-500 hover:bg-dpe-ink-50"
|
|
402
402
|
>
|
|
403
403
|
{t("detailPage.chart.maxToAuto")}
|
|
404
404
|
</button>
|
|
@@ -406,7 +406,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
406
406
|
</div>
|
|
407
407
|
|
|
408
408
|
<label className="mt-2 flex items-center gap-2">
|
|
409
|
-
<span className="w-10 shrink-0 text-xs text-
|
|
409
|
+
<span className="w-10 shrink-0 text-xs text-dpe-ink-500">
|
|
410
410
|
{t("detailPage.chart.highlight")}
|
|
411
411
|
</span>
|
|
412
412
|
<select
|
|
@@ -418,7 +418,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
418
418
|
event.target.value === "" ? null : Number(event.target.value),
|
|
419
419
|
})
|
|
420
420
|
}
|
|
421
|
-
className="h-8 min-w-0 flex-1 rounded-md border border-
|
|
421
|
+
className="h-8 min-w-0 flex-1 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface px-2 text-xs text-dpe-ink-700 outline-none focus:border-dpe-ink-400"
|
|
422
422
|
>
|
|
423
423
|
<option value="">{t("detailPage.chart.highlightNone")}</option>
|
|
424
424
|
{spec.data.labels.map((label, index) => (
|
|
@@ -437,7 +437,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
437
437
|
<div className="flex flex-col gap-2">
|
|
438
438
|
{slots.map((slot) => (
|
|
439
439
|
<label key={slot.index} className="flex items-center gap-2">
|
|
440
|
-
<span className="w-16 shrink-0 truncate text-xs text-
|
|
440
|
+
<span className="w-16 shrink-0 truncate text-xs text-dpe-ink-500">
|
|
441
441
|
{scope === "highlight"
|
|
442
442
|
? t("detailPage.chart.color.accent")
|
|
443
443
|
: slot.name ||
|
|
@@ -457,7 +457,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
457
457
|
</label>
|
|
458
458
|
))}
|
|
459
459
|
{scope !== "highlight" && slotsTruncated ? (
|
|
460
|
-
<p className="text-[11px] leading-relaxed text-
|
|
460
|
+
<p className="text-[11px] leading-relaxed text-dpe-ink-400">
|
|
461
461
|
{t("detailPage.chart.color.moreSlots", { count: MAX_PALETTE_SLOTS })}
|
|
462
462
|
</p>
|
|
463
463
|
) : null}
|
|
@@ -471,7 +471,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
471
471
|
] as const
|
|
472
472
|
).map(([key, value]) => (
|
|
473
473
|
<label key={key} className="flex items-center gap-2">
|
|
474
|
-
<span className="w-16 shrink-0 text-xs text-
|
|
474
|
+
<span className="w-16 shrink-0 text-xs text-dpe-ink-500">
|
|
475
475
|
{t(`detailPage.chart.color.${key}`)}
|
|
476
476
|
</span>
|
|
477
477
|
<ColorInput
|
|
@@ -491,7 +491,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
491
491
|
<Section title={t("detailPage.chart.shape")}>
|
|
492
492
|
<div className="grid grid-cols-2 gap-2">
|
|
493
493
|
<label className="flex items-center gap-2">
|
|
494
|
-
<span className="w-10 shrink-0 text-xs text-
|
|
494
|
+
<span className="w-10 shrink-0 text-xs text-dpe-ink-500">
|
|
495
495
|
{t("detailPage.chart.barSize")}
|
|
496
496
|
</span>
|
|
497
497
|
<NumberField
|
|
@@ -501,7 +501,7 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
501
501
|
/>
|
|
502
502
|
</label>
|
|
503
503
|
<label className="flex items-center gap-2">
|
|
504
|
-
<span className="w-10 shrink-0 text-xs text-
|
|
504
|
+
<span className="w-10 shrink-0 text-xs text-dpe-ink-500">
|
|
505
505
|
{t("detailPage.chart.gap")}
|
|
506
506
|
</span>
|
|
507
507
|
<NumberField
|
|
@@ -517,12 +517,12 @@ export const ChartInspector = observer(function ChartInspector({
|
|
|
517
517
|
<button
|
|
518
518
|
type="button"
|
|
519
519
|
onClick={() => detachChart(el)}
|
|
520
|
-
className="inline-flex h-9 w-full items-center justify-center gap-2 rounded-md border border-
|
|
520
|
+
className="inline-flex h-9 w-full items-center justify-center gap-2 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface text-sm font-dpe-semibold text-dpe-ink-700 hover:bg-dpe-ink-50"
|
|
521
521
|
>
|
|
522
522
|
<Unlink aria-hidden="true" size={15} />
|
|
523
523
|
{t("detailPage.chart.detach")}
|
|
524
524
|
</button>
|
|
525
|
-
<p className="mt-1.5 text-[11px] text-
|
|
525
|
+
<p className="mt-1.5 text-[11px] text-dpe-ink-400">
|
|
526
526
|
{t("detailPage.chart.detachHint")}
|
|
527
527
|
</p>
|
|
528
528
|
</Section>
|
|
@@ -198,10 +198,10 @@ export function DesignReferencePicker({
|
|
|
198
198
|
}, [api, busy, credits, instruction, items, onBriefChange]);
|
|
199
199
|
|
|
200
200
|
return (
|
|
201
|
-
<div className="space-y-3 rounded-lg bg-
|
|
201
|
+
<div className="space-y-3 rounded-dpe-lg bg-dpe-ink-50 p-3">
|
|
202
202
|
<div>
|
|
203
|
-
<p className="text-xs font-medium text-
|
|
204
|
-
<p className="mt-1 text-[11px] text-
|
|
203
|
+
<p className="text-xs font-dpe-medium text-dpe-ink-700">디자인 레퍼런스</p>
|
|
204
|
+
<p className="mt-1 text-[11px] text-dpe-ink-500">
|
|
205
205
|
“이런 디자인으로” 참고할 그림이에요. 상품 사진과 달리 페이지에
|
|
206
206
|
들어가지 않고, 구조와 색을 고르는 근거로만 써요. 최대{" "}
|
|
207
207
|
{MAX_DESIGN_REFERENCES}장.
|
|
@@ -212,13 +212,13 @@ export function DesignReferencePicker({
|
|
|
212
212
|
{items.map((item, index) => (
|
|
213
213
|
<div
|
|
214
214
|
key={item.id}
|
|
215
|
-
className="flex items-start gap-2 rounded-lg border border-
|
|
215
|
+
className="flex items-start gap-2 rounded-dpe-lg border border-dpe-ink-200 bg-dpe-surface p-1.5"
|
|
216
216
|
>
|
|
217
|
-
<div className="relative h-14 w-14 shrink-0 overflow-hidden rounded-md bg-
|
|
217
|
+
<div className="relative h-14 w-14 shrink-0 overflow-hidden rounded-dpe-md bg-dpe-ink-100">
|
|
218
218
|
{/* 붙인 사진은 data URI라 next/image 로 최적화할 것이 없다. */}
|
|
219
219
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
220
220
|
<img src={item.uri} alt="디자인 레퍼런스" className="h-full w-full object-cover" />
|
|
221
|
-
<span className="absolute left-0.5 top-0.5 rounded bg-
|
|
221
|
+
<span className="absolute left-0.5 top-0.5 rounded bg-dpe-ink-900/75 px-1 text-[10px] font-dpe-semibold leading-4 text-dpe-on-accent">
|
|
222
222
|
{referenceOrdinal(index)}
|
|
223
223
|
</span>
|
|
224
224
|
<button
|
|
@@ -226,7 +226,7 @@ export function DesignReferencePicker({
|
|
|
226
226
|
disabled={disabled || busy}
|
|
227
227
|
onClick={() => remove(item.id)}
|
|
228
228
|
aria-label={`${referenceOrdinal(index)} 레퍼런스 빼기`}
|
|
229
|
-
className="absolute right-0.5 top-0.5 flex h-4 w-4 items-center justify-center rounded-full bg-
|
|
229
|
+
className="absolute right-0.5 top-0.5 flex h-4 w-4 items-center justify-center rounded-full bg-dpe-ink-900/70 text-dpe-on-accent disabled:opacity-40"
|
|
230
230
|
>
|
|
231
231
|
<X size={10} />
|
|
232
232
|
</button>
|
|
@@ -245,8 +245,8 @@ export function DesignReferencePicker({
|
|
|
245
245
|
onClick={() => toggleAspect(item.id, aspect.key)}
|
|
246
246
|
className={`rounded-full border px-2 py-0.5 text-[11px] transition-colors disabled:opacity-40 ${
|
|
247
247
|
on
|
|
248
|
-
? "border-
|
|
249
|
-
: "border-
|
|
248
|
+
? "border-dpe-ink-900 bg-dpe-ink-900 text-dpe-on-accent"
|
|
249
|
+
: "border-dpe-ink-200 text-dpe-ink-500 hover:border-dpe-ink-400 hover:text-dpe-ink-700"
|
|
250
250
|
}`}
|
|
251
251
|
>
|
|
252
252
|
{aspect.label}
|
|
@@ -261,7 +261,7 @@ export function DesignReferencePicker({
|
|
|
261
261
|
type="button"
|
|
262
262
|
disabled={disabled || busy}
|
|
263
263
|
onClick={() => fileRef.current?.click()}
|
|
264
|
-
className="flex h-[4.75rem] items-center gap-1.5 rounded-lg border border-dashed border-
|
|
264
|
+
className="flex h-[4.75rem] items-center gap-1.5 rounded-dpe-lg border border-dashed border-dpe-ink-300 bg-dpe-surface px-3 text-xs text-dpe-ink-500 transition-colors hover:border-dpe-ink-400 hover:text-dpe-ink-700 disabled:opacity-40"
|
|
265
265
|
>
|
|
266
266
|
<ImagePlus size={14} />
|
|
267
267
|
레퍼런스 추가
|
|
@@ -285,13 +285,13 @@ export function DesignReferencePicker({
|
|
|
285
285
|
rows={2}
|
|
286
286
|
disabled={disabled || busy}
|
|
287
287
|
placeholder="1번 이미지의 색감과 폰트, 2번 이미지의 레이아웃을 참고해 주세요"
|
|
288
|
-
className="w-full resize-none rounded-lg border border-
|
|
288
|
+
className="w-full resize-none rounded-dpe-lg border border-dpe-ink-200 bg-dpe-surface px-3 py-2 text-xs text-dpe-ink-900 outline-none placeholder:text-dpe-ink-400 focus:border-dpe-ink-400 disabled:bg-dpe-ink-100"
|
|
289
289
|
/>
|
|
290
290
|
<button
|
|
291
291
|
type="button"
|
|
292
292
|
disabled={disabled || busy}
|
|
293
293
|
onClick={() => void analyze()}
|
|
294
|
-
className="inline-flex items-center gap-1.5 rounded-lg border border-
|
|
294
|
+
className="inline-flex items-center gap-1.5 rounded-dpe-lg border border-dpe-ink-900 px-3 py-1.5 text-xs font-dpe-medium text-dpe-ink-900 transition-colors hover:bg-dpe-ink-900 hover:text-dpe-on-accent disabled:opacity-40"
|
|
295
295
|
>
|
|
296
296
|
{busy ? <Loader2 size={13} className="animate-spin" /> : null}
|
|
297
297
|
{busy ? "읽는 중…" : brief ? "다시 읽기" : "레퍼런스 읽기"}
|
|
@@ -299,7 +299,7 @@ export function DesignReferencePicker({
|
|
|
299
299
|
{/* 누르기 전에 값을 알려 준다 — 누른 뒤 402 로 알게 되면 이미 축 고르고
|
|
300
300
|
지시까지 다 적은 뒤다. 장수가 아니라 그림 크기에 붙는 값이라, 큰 그림을
|
|
301
301
|
작은 것으로 바꾸면 줄어든다. */}
|
|
302
|
-
<p className="text-[11px] text-
|
|
302
|
+
<p className="text-[11px] text-dpe-ink-500">
|
|
303
303
|
읽을 때마다 {credits}크레딧이 들어요 (레퍼런스 {items.length}장 · 그림이 크고
|
|
304
304
|
길수록 올라가요).
|
|
305
305
|
</p>
|
|
@@ -307,7 +307,7 @@ export function DesignReferencePicker({
|
|
|
307
307
|
) : null}
|
|
308
308
|
|
|
309
309
|
{brief ? <BriefSummary brief={brief} /> : null}
|
|
310
|
-
{error ? <p className="text-[11px] text-
|
|
310
|
+
{error ? <p className="text-[11px] text-dpe-danger-600">{error}</p> : null}
|
|
311
311
|
</div>
|
|
312
312
|
);
|
|
313
313
|
}
|
|
@@ -339,22 +339,22 @@ function BriefSummary({ brief }: { brief: DetailPageDesignBrief }) {
|
|
|
339
339
|
|
|
340
340
|
if (nothingRead) {
|
|
341
341
|
return (
|
|
342
|
-
<p className="text-[11px] text-
|
|
342
|
+
<p className="text-[11px] text-dpe-ink-500">
|
|
343
343
|
레퍼런스에서 읽어낸 것이 없어요. 판면이 잘 보이는 그림으로 바꿔 보세요.
|
|
344
344
|
</p>
|
|
345
345
|
);
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
return (
|
|
349
|
-
<div className="space-y-1.5 rounded-lg border border-
|
|
349
|
+
<div className="space-y-1.5 rounded-dpe-lg border border-dpe-ink-200 bg-dpe-surface p-2.5">
|
|
350
350
|
<div className="flex flex-wrap items-center gap-1.5">
|
|
351
351
|
{brief.tone ? (
|
|
352
|
-
<span className="rounded-full bg-
|
|
352
|
+
<span className="rounded-full bg-dpe-ink-900 px-2 py-0.5 text-[11px] text-dpe-on-accent">
|
|
353
353
|
{TONE_LABELS[brief.tone] ?? brief.tone}
|
|
354
354
|
</span>
|
|
355
355
|
) : null}
|
|
356
356
|
{brief.density ? (
|
|
357
|
-
<span className="rounded-full border border-
|
|
357
|
+
<span className="rounded-full border border-dpe-ink-300 px-2 py-0.5 text-[11px] text-dpe-ink-600">
|
|
358
358
|
{DENSITY_LABELS[brief.density] ?? brief.density}
|
|
359
359
|
</span>
|
|
360
360
|
) : null}
|
|
@@ -363,19 +363,19 @@ function BriefSummary({ brief }: { brief: DetailPageDesignBrief }) {
|
|
|
363
363
|
key={color}
|
|
364
364
|
title={color}
|
|
365
365
|
style={{ backgroundColor: color }}
|
|
366
|
-
className="h-4 w-4 rounded-full border border-
|
|
366
|
+
className="h-4 w-4 rounded-full border border-dpe-ink-300"
|
|
367
367
|
/>
|
|
368
368
|
))}
|
|
369
369
|
</div>
|
|
370
370
|
{brief.summary ? (
|
|
371
|
-
<p className="text-[11px] text-
|
|
371
|
+
<p className="text-[11px] text-dpe-ink-600">{brief.summary}</p>
|
|
372
372
|
) : null}
|
|
373
373
|
{brief.typography || brief.layout || brief.content ? (
|
|
374
|
-
<p className="text-[11px] text-
|
|
374
|
+
<p className="text-[11px] text-dpe-ink-500">
|
|
375
375
|
{[brief.typography, brief.layout, brief.content].filter(Boolean).join(" · ")}
|
|
376
376
|
</p>
|
|
377
377
|
) : null}
|
|
378
|
-
<p className="text-[11px] text-
|
|
378
|
+
<p className="text-[11px] text-dpe-ink-400">
|
|
379
379
|
읽은 결과는 제안이에요. 위 디자인 톤을 직접 바꾸면 그 선택이 우선해요.
|
|
380
380
|
</p>
|
|
381
381
|
</div>
|
|
@@ -65,7 +65,7 @@ const FIGURE_PATCH: Record<string, Record<string, unknown>> = {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
const CELL =
|
|
68
|
-
"flex aspect-square items-center justify-center rounded-lg border border-
|
|
68
|
+
"flex aspect-square items-center justify-center rounded-dpe-lg border border-dpe-ink-200 p-2 hover:border-dpe-ink-400";
|
|
69
69
|
|
|
70
70
|
function FigureCell({ id, store }: { id: string; store: unknown }) {
|
|
71
71
|
const { t } = useTranslation("branding");
|
|
@@ -79,7 +79,7 @@ function FigureCell({ id, store }: { id: string; store: unknown }) {
|
|
|
79
79
|
>
|
|
80
80
|
<span
|
|
81
81
|
aria-hidden="true"
|
|
82
|
-
className="block h-7 w-7 bg-
|
|
82
|
+
className="block h-7 w-7 bg-dpe-ink-300"
|
|
83
83
|
style={{
|
|
84
84
|
borderRadius: id === "circle" ? "9999px" : id === "rounded" ? 8 : 0,
|
|
85
85
|
}}
|
|
@@ -135,7 +135,7 @@ export function DetailPageBasicShapes({ store }: { store: unknown }) {
|
|
|
135
135
|
<div className="min-h-0 flex-1 overflow-y-auto p-3">
|
|
136
136
|
{found ? (
|
|
137
137
|
found.figures.length + found.shapes.length === 0 ? (
|
|
138
|
-
<div className="flex flex-col items-center gap-2 py-6 text-center text-
|
|
138
|
+
<div className="flex flex-col items-center gap-2 py-6 text-center text-dpe-ink-400">
|
|
139
139
|
<ImageOff aria-hidden="true" size={20} />
|
|
140
140
|
<p className="text-xs">{t("detailPage.shapes.searchEmpty")}</p>
|
|
141
141
|
</div>
|
|
@@ -157,7 +157,7 @@ export function DetailPageBasicShapes({ store }: { store: unknown }) {
|
|
|
157
157
|
if (!shapes.length) return null;
|
|
158
158
|
return (
|
|
159
159
|
<div key={category} className="mb-4 last:mb-0">
|
|
160
|
-
<p className="mb-2 text-xs font-medium text-
|
|
160
|
+
<p className="mb-2 text-xs font-dpe-medium text-dpe-ink-500">
|
|
161
161
|
{t(`detailPage.shapes.categories.${category}`)}
|
|
162
162
|
</p>
|
|
163
163
|
<div className="grid grid-cols-4 gap-2">
|
|
@@ -147,7 +147,7 @@ export function DetailPageBrandGifsPanel({ store }: { store: unknown }) {
|
|
|
147
147
|
<div className="flex h-full flex-col p-4">
|
|
148
148
|
<BrandPanelHeader onRefresh={() => void gifsQuery.refetch()} />
|
|
149
149
|
|
|
150
|
-
<label className="mb-3 flex h-16 cursor-pointer flex-col items-center justify-center gap-1 rounded-md border border-dashed border-
|
|
150
|
+
<label className="mb-3 flex h-16 cursor-pointer flex-col items-center justify-center gap-1 rounded-dpe-md border border-dashed border-dpe-ink-300 text-dpe-ink-400 hover:border-dpe-ink-400 hover:text-dpe-ink-600">
|
|
151
151
|
{uploadMutation.isPending ? (
|
|
152
152
|
<Loader2 aria-hidden="true" className="animate-spin" size={18} />
|
|
153
153
|
) : (
|
|
@@ -166,19 +166,19 @@ export function DetailPageBrandGifsPanel({ store }: { store: unknown }) {
|
|
|
166
166
|
</label>
|
|
167
167
|
|
|
168
168
|
{brandsLoading || gifsQuery.isLoading ? (
|
|
169
|
-
<div className="flex flex-1 items-center justify-center text-
|
|
169
|
+
<div className="flex flex-1 items-center justify-center text-dpe-ink-400">
|
|
170
170
|
<Loader2 aria-hidden="true" className="animate-spin" size={22} />
|
|
171
171
|
</div>
|
|
172
172
|
) : error || gifsQuery.error ? (
|
|
173
|
-
<p className="text-xs font-medium text-
|
|
173
|
+
<p className="text-xs font-dpe-medium text-dpe-danger-600">
|
|
174
174
|
{error ?? t("detailPage.brandAssets.loadFailed")}
|
|
175
175
|
</p>
|
|
176
176
|
) : !activeBrand ? (
|
|
177
|
-
<p className="text-xs text-
|
|
177
|
+
<p className="text-xs text-dpe-ink-400">
|
|
178
178
|
{t("detailPage.brandAssets.noBrand")}
|
|
179
179
|
</p>
|
|
180
180
|
) : sections.length === 0 ? (
|
|
181
|
-
<div className="flex flex-1 flex-col items-center justify-center gap-2 text-center text-
|
|
181
|
+
<div className="flex flex-1 flex-col items-center justify-center gap-2 text-center text-dpe-ink-400">
|
|
182
182
|
<Film aria-hidden="true" size={22} />
|
|
183
183
|
<p className="text-xs">
|
|
184
184
|
{t("detailPage.brandGifs.empty", {
|
|
@@ -191,7 +191,7 @@ export function DetailPageBrandGifsPanel({ store }: { store: unknown }) {
|
|
|
191
191
|
<div className="flex flex-col gap-4 overflow-y-auto">
|
|
192
192
|
{sections.map((section) => (
|
|
193
193
|
<section key={section.kind}>
|
|
194
|
-
<h3 className="mb-1.5 text-[11px] font-semibold text-
|
|
194
|
+
<h3 className="mb-1.5 text-[11px] font-dpe-semibold text-dpe-ink-500">
|
|
195
195
|
{section.kind === "other"
|
|
196
196
|
? t("detailPage.brandGifs.sectionOther", {
|
|
197
197
|
defaultValue: "기타",
|
|
@@ -205,7 +205,7 @@ export function DetailPageBrandGifsPanel({ store }: { store: unknown }) {
|
|
|
205
205
|
)!.fallback,
|
|
206
206
|
},
|
|
207
207
|
)}
|
|
208
|
-
<span className="ml-1 font-normal text-
|
|
208
|
+
<span className="ml-1 font-dpe-normal text-dpe-ink-300">
|
|
209
209
|
{section.items.length}
|
|
210
210
|
</span>
|
|
211
211
|
</h3>
|
|
@@ -213,7 +213,7 @@ export function DetailPageBrandGifsPanel({ store }: { store: unknown }) {
|
|
|
213
213
|
{section.items.map((asset) => (
|
|
214
214
|
<div
|
|
215
215
|
key={asset.id}
|
|
216
|
-
className="group relative overflow-hidden rounded-md border border-
|
|
216
|
+
className="group relative overflow-hidden rounded-dpe-md border border-dpe-ink-200 hover:border-dpe-ink-500"
|
|
217
217
|
>
|
|
218
218
|
<button
|
|
219
219
|
type="button"
|
|
@@ -237,14 +237,14 @@ export function DetailPageBrandGifsPanel({ store }: { store: unknown }) {
|
|
|
237
237
|
className="h-24 w-full object-cover transition group-hover:opacity-90"
|
|
238
238
|
/>
|
|
239
239
|
</button>
|
|
240
|
-
<span className="pointer-events-none absolute bottom-1.5 left-1.5 max-w-[calc(100%-12px)] truncate rounded-sm bg-
|
|
240
|
+
<span className="pointer-events-none absolute bottom-1.5 left-1.5 max-w-[calc(100%-12px)] truncate rounded-dpe-sm bg-dpe-scrim/70 px-1.5 py-0.5 text-[10px] text-dpe-on-accent">
|
|
241
241
|
{String(asset.metadata?.effect ?? "") ||
|
|
242
242
|
(asset.display_name ?? asset.filename)}
|
|
243
243
|
</span>
|
|
244
244
|
<button
|
|
245
245
|
type="button"
|
|
246
246
|
onClick={() => deleteMutation.mutate(asset)}
|
|
247
|
-
className="absolute right-1 top-1 hidden h-6 w-6 items-center justify-center rounded-md bg-
|
|
247
|
+
className="absolute right-1 top-1 hidden h-6 w-6 items-center justify-center rounded-dpe-md bg-dpe-surface/95 text-dpe-ink-400 shadow-sm hover:text-dpe-danger-600 group-hover:flex"
|
|
248
248
|
aria-label={t("detailPage.brandAssets.delete")}
|
|
249
249
|
>
|
|
250
250
|
<Trash2 aria-hidden="true" size={13} />
|
|
@@ -33,7 +33,7 @@ export function DetailPageBrandKitPanel({ store }: { store: unknown }) {
|
|
|
33
33
|
|
|
34
34
|
if (brandsLoading || assetsQuery.isLoading || moodboardQuery.isLoading) {
|
|
35
35
|
return (
|
|
36
|
-
<div className="flex h-full items-center justify-center text-
|
|
36
|
+
<div className="flex h-full items-center justify-center text-dpe-ink-400">
|
|
37
37
|
<Loader2 className="animate-spin" size={20} />
|
|
38
38
|
</div>
|
|
39
39
|
);
|
|
@@ -42,7 +42,7 @@ export function DetailPageBrandKitPanel({ store }: { store: unknown }) {
|
|
|
42
42
|
const KitPanel = slots?.BrandKitPanel;
|
|
43
43
|
if (!activeBrand || !moodboardQuery.data || !KitPanel) {
|
|
44
44
|
return (
|
|
45
|
-
<div className="flex h-full flex-col items-center justify-center gap-2 p-5 text-center text-
|
|
45
|
+
<div className="flex h-full flex-col items-center justify-center gap-2 p-5 text-center text-dpe-ink-400">
|
|
46
46
|
<Palette size={22} />
|
|
47
47
|
<p className="text-xs">{t("detailPage.brandAssets.kitEmpty")}</p>
|
|
48
48
|
</div>
|
|
@@ -51,13 +51,13 @@ export function DetailPageBrandKitPanel({ store }: { store: unknown }) {
|
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
53
|
<div className="flex h-full flex-col overflow-y-auto">
|
|
54
|
-
<div className="border-b border-
|
|
55
|
-
<label className="grid gap-1 text-[11px] font-medium text-
|
|
54
|
+
<div className="border-b border-dpe-ink-200 p-3">
|
|
55
|
+
<label className="grid gap-1 text-[11px] font-dpe-medium text-dpe-ink-500">
|
|
56
56
|
{t("detailPage.brandAssets.activeBrand")}
|
|
57
57
|
<select
|
|
58
58
|
value={activeBrand.id}
|
|
59
59
|
onChange={(event) => setActiveBrandId(event.target.value)}
|
|
60
|
-
className="h-8 rounded-md border border-
|
|
60
|
+
className="h-8 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface px-2 text-xs text-dpe-ink-800"
|
|
61
61
|
>
|
|
62
62
|
{brands.map((brand) => (
|
|
63
63
|
<option key={brand.id} value={brand.id}>
|
|
@@ -16,13 +16,16 @@ export function BrandPanelHeader({ onRefresh }: { onRefresh: () => void }) {
|
|
|
16
16
|
const { brands, activeBrandId, setActiveBrandId } = brand.useBrandWorkspace();
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<div
|
|
20
|
-
|
|
19
|
+
<div
|
|
20
|
+
data-dpe-part="panel-header"
|
|
21
|
+
className="mb-3 flex items-center justify-between gap-2"
|
|
22
|
+
>
|
|
23
|
+
<label className="grid min-w-0 flex-1 gap-1 text-[11px] font-dpe-medium text-dpe-ink-500">
|
|
21
24
|
{t("detailPage.brandAssets.activeBrand")}
|
|
22
25
|
<select
|
|
23
26
|
value={activeBrandId ?? ""}
|
|
24
27
|
onChange={(event) => setActiveBrandId(event.target.value)}
|
|
25
|
-
className="h-8 min-w-0 rounded-md border border-
|
|
28
|
+
className="h-8 min-w-0 rounded-dpe-md border border-dpe-ink-200 bg-dpe-surface px-2 text-xs text-dpe-ink-800"
|
|
26
29
|
>
|
|
27
30
|
{brands.map((brand) => (
|
|
28
31
|
<option key={brand.id} value={brand.id}>
|
|
@@ -34,7 +37,7 @@ export function BrandPanelHeader({ onRefresh }: { onRefresh: () => void }) {
|
|
|
34
37
|
<button
|
|
35
38
|
type="button"
|
|
36
39
|
onClick={onRefresh}
|
|
37
|
-
className="mt-4 flex h-7 w-7 items-center justify-center rounded-md text-
|
|
40
|
+
className="mt-4 flex h-7 w-7 items-center justify-center rounded-dpe-md text-dpe-ink-400 hover:bg-dpe-ink-100 hover:text-dpe-ink-600"
|
|
38
41
|
aria-label={t("detailPage.brandAssets.refresh")}
|
|
39
42
|
>
|
|
40
43
|
<RefreshCw aria-hidden="true" size={14} />
|
|
@@ -74,7 +74,7 @@ export function DetailPageChartsPanel({ store }: { store: unknown }) {
|
|
|
74
74
|
|
|
75
75
|
return (
|
|
76
76
|
<div className="flex h-full flex-col overflow-y-auto p-3">
|
|
77
|
-
<p className="mb-2 text-xs font-medium text-
|
|
77
|
+
<p className="mb-2 text-xs font-dpe-medium text-dpe-ink-500">
|
|
78
78
|
{t("detailPage.chart.panelTitle")}
|
|
79
79
|
</p>
|
|
80
80
|
<div className="grid grid-cols-2 gap-2">
|
|
@@ -84,7 +84,7 @@ export function DetailPageChartsPanel({ store }: { store: unknown }) {
|
|
|
84
84
|
type="button"
|
|
85
85
|
onClick={() => insert(preset)}
|
|
86
86
|
title={t("detailPage.chart.insertHint")}
|
|
87
|
-
className="flex flex-col items-center gap-1.5 rounded-lg border border-
|
|
87
|
+
className="flex flex-col items-center gap-1.5 rounded-dpe-lg border border-dpe-ink-200 p-2 hover:border-dpe-ink-400"
|
|
88
88
|
>
|
|
89
89
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
90
90
|
<img
|
|
@@ -92,11 +92,11 @@ export function DetailPageChartsPanel({ store }: { store: unknown }) {
|
|
|
92
92
|
alt={t(preset.labelKey)}
|
|
93
93
|
className="h-20 w-full object-contain"
|
|
94
94
|
/>
|
|
95
|
-
<span className="text-[11px] text-
|
|
95
|
+
<span className="text-[11px] text-dpe-ink-500">{t(preset.labelKey)}</span>
|
|
96
96
|
</button>
|
|
97
97
|
))}
|
|
98
98
|
</div>
|
|
99
|
-
<p className="mt-3 text-[11px] leading-relaxed text-
|
|
99
|
+
<p className="mt-3 text-[11px] leading-relaxed text-dpe-ink-400">
|
|
100
100
|
{t("detailPage.chart.panelHint")}
|
|
101
101
|
</p>
|
|
102
102
|
</div>
|
|
@@ -72,14 +72,14 @@ export function DetailPageDecorationsPanel({ store }: { store: unknown }) {
|
|
|
72
72
|
if (isError) {
|
|
73
73
|
return (
|
|
74
74
|
<div className="p-3">
|
|
75
|
-
<p className="text-xs text-
|
|
75
|
+
<p className="text-xs text-dpe-danger-600">{t("detailPage.shapes.decorationsFailed")}</p>
|
|
76
76
|
</div>
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (isPending) {
|
|
81
81
|
return (
|
|
82
|
-
<div className="flex h-full items-center justify-center text-
|
|
82
|
+
<div className="flex h-full items-center justify-center text-dpe-ink-400">
|
|
83
83
|
<Loader2 aria-hidden="true" className="animate-spin" size={18} />
|
|
84
84
|
</div>
|
|
85
85
|
);
|
|
@@ -88,7 +88,7 @@ export function DetailPageDecorationsPanel({ store }: { store: unknown }) {
|
|
|
88
88
|
if (!groups.length) {
|
|
89
89
|
return (
|
|
90
90
|
<div className="p-3">
|
|
91
|
-
<p className="text-xs text-
|
|
91
|
+
<p className="text-xs text-dpe-ink-400">{t("detailPage.shapes.decorationsEmpty")}</p>
|
|
92
92
|
</div>
|
|
93
93
|
);
|
|
94
94
|
}
|
|
@@ -97,7 +97,7 @@ export function DetailPageDecorationsPanel({ store }: { store: unknown }) {
|
|
|
97
97
|
<div className="flex h-full flex-col overflow-y-auto p-3">
|
|
98
98
|
{groups.map(({ category, cells }) => (
|
|
99
99
|
<div key={category} className="mb-4 last:mb-0">
|
|
100
|
-
<p className="mb-2 text-xs font-medium text-
|
|
100
|
+
<p className="mb-2 text-xs font-dpe-medium text-dpe-ink-500">
|
|
101
101
|
{t(`detailPage.shapes.decorations.${category}`)}
|
|
102
102
|
</p>
|
|
103
103
|
<div className="grid grid-cols-4 gap-2">
|
|
@@ -106,7 +106,7 @@ export function DetailPageDecorationsPanel({ store }: { store: unknown }) {
|
|
|
106
106
|
key={item.id}
|
|
107
107
|
type="button"
|
|
108
108
|
onClick={() => insert(item)}
|
|
109
|
-
className="flex aspect-square items-center justify-center rounded-lg border border-
|
|
109
|
+
className="flex aspect-square items-center justify-center rounded-dpe-lg border border-dpe-ink-200 p-2 hover:border-dpe-ink-400"
|
|
110
110
|
title={t("detailPage.shapes.insertHint")}
|
|
111
111
|
>
|
|
112
112
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|