Feature: Add file removal and print area edit toggles to photo upload
- Add 'Modify print area →' button to navigate from file selection to print area editor - Add 'Remove' button to clear selected file and start over - Add '← Back to file' button in print area editor to return and change files - Persist print area settings while toggling between views Users can now more easily manage their image uploads and refine the print area without losing their settings or being locked into a workflow. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
7fa324bc07
commit
684a837998
@@ -10,7 +10,9 @@ const MIN_SIZE = 6; // percent
|
|||||||
export default function PhotoPrintAreaField({ variant = 'front' }: { variant?: 'front' | 'back' }) {
|
export default function PhotoPrintAreaField({ variant = 'front' }: { variant?: 'front' | 'back' }) {
|
||||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
||||||
const [box, setBox] = useState<Box>(DEFAULT_BOX);
|
const [box, setBox] = useState<Box>(DEFAULT_BOX);
|
||||||
|
const [showPrintAreaEditor, setShowPrintAreaEditor] = useState(false);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const dragState = useRef<{
|
const dragState = useRef<{
|
||||||
mode: 'move' | 'resize';
|
mode: 'move' | 'resize';
|
||||||
startX: number;
|
startX: number;
|
||||||
@@ -25,10 +27,24 @@ export default function PhotoPrintAreaField({ variant = 'front' }: { variant?: '
|
|||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
if (!file) {
|
if (!file) {
|
||||||
setPreviewUrl(null);
|
setPreviewUrl(null);
|
||||||
|
setShowPrintAreaEditor(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setPreviewUrl(URL.createObjectURL(file));
|
setPreviewUrl(URL.createObjectURL(file));
|
||||||
setBox(DEFAULT_BOX);
|
setBox(DEFAULT_BOX);
|
||||||
|
setShowPrintAreaEditor(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClearFile = () => {
|
||||||
|
setPreviewUrl(null);
|
||||||
|
setShowPrintAreaEditor(false);
|
||||||
|
if (fileInputRef.current) {
|
||||||
|
fileInputRef.current.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBackToFile = () => {
|
||||||
|
setShowPrintAreaEditor(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBoxMouseDown = (e: React.MouseEvent) => {
|
const onBoxMouseDown = (e: React.MouseEvent) => {
|
||||||
@@ -73,31 +89,64 @@ export default function PhotoPrintAreaField({ variant = 'front' }: { variant?: '
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input
|
{!previewUrl || !showPrintAreaEditor ? (
|
||||||
id={fieldName}
|
<>
|
||||||
name={fieldName}
|
<input
|
||||||
type="file"
|
ref={fileInputRef}
|
||||||
accept="image/*"
|
id={fieldName}
|
||||||
onChange={handleFileChange}
|
name={fieldName}
|
||||||
className="w-full border border-line bg-paper px-3 py-2 text-sm"
|
type="file"
|
||||||
/>
|
accept="image/*"
|
||||||
{variant === 'front' ? (
|
onChange={handleFileChange}
|
||||||
<p className="mt-1 text-xs text-muted">
|
className="w-full border border-line bg-paper px-3 py-2 text-sm"
|
||||||
Uploading a real photo replaces the illustration everywhere this product is shown. One
|
/>
|
||||||
tradeoff: the color swatches below can no longer recolor a photo the way they recolor the
|
{variant === 'front' ? (
|
||||||
illustration — they'll still be saved with each order, but the picture itself stays
|
<p className="mt-1 text-xs text-muted">
|
||||||
fixed. Leave this blank to keep using the illustration (which does recolor live).
|
Uploading a real photo replaces the illustration everywhere this product is shown. One
|
||||||
</p>
|
tradeoff: the color swatches below can no longer recolor a photo the way they recolor the
|
||||||
) : (
|
illustration — they'll still be saved with each order, but the picture itself stays
|
||||||
<p className="mt-1 text-xs text-muted">
|
fixed. Leave this blank to keep using the illustration (which does recolor live).
|
||||||
If set, customers get a Front/Back toggle and can add a separate design to the back —
|
</p>
|
||||||
drag a print-area box below just like the front.
|
) : (
|
||||||
</p>
|
<p className="mt-1 text-xs text-muted">
|
||||||
)}
|
If set, customers get a Front/Back toggle and can add a separate design to the back —
|
||||||
|
drag a print-area box below just like the front.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
{previewUrl && (
|
{previewUrl && !showPrintAreaEditor && (
|
||||||
|
<div className="mt-3 flex gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowPrintAreaEditor(true)}
|
||||||
|
className="text-sm text-clay hover:text-clay-dark font-medium"
|
||||||
|
>
|
||||||
|
Modify print area →
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleClearFile}
|
||||||
|
className="text-sm text-splash-pink hover:text-splash-pink-dark font-medium"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{previewUrl && showPrintAreaEditor && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<p className="tag-label mb-2">Drag the box to mark the print area</p>
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<p className="tag-label">Drag the box to mark the print area</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleBackToFile}
|
||||||
|
className="text-sm text-clay hover:text-clay-dark font-medium"
|
||||||
|
>
|
||||||
|
← Back to file
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<p className="mb-2 text-xs text-muted">
|
<p className="mb-2 text-xs text-muted">
|
||||||
Cropped to a square here — that's the same crop the design tool uses, so the box
|
Cropped to a square here — that's the same crop the design tool uses, so the box
|
||||||
lines up correctly.
|
lines up correctly.
|
||||||
|
|||||||
Reference in New Issue
Block a user