From 6b2aca3eadc0783b02396f21500c518b716d8431 Mon Sep 17 00:00:00 2001 From: ankitsejwal Date: Sun, 28 Jun 2026 22:28:46 +0530 Subject: [PATCH 1/5] Add PhotoSidebar: black Add-photos button, drag reveals square drop pad --- apps/web/src/components/photo-dropzone.tsx | 69 ---------------------- apps/web/src/components/photo-sidebar.tsx | 69 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 69 deletions(-) delete mode 100644 apps/web/src/components/photo-dropzone.tsx create mode 100644 apps/web/src/components/photo-sidebar.tsx diff --git a/apps/web/src/components/photo-dropzone.tsx b/apps/web/src/components/photo-dropzone.tsx deleted file mode 100644 index 8961b6c..0000000 --- a/apps/web/src/components/photo-dropzone.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useCallback, useState } from 'react' -import { type FileRejection, useDropzone } from 'react-dropzone' -import { ImagePlus } from 'lucide-react' - -import { cn } from '@/lib/utils' -import { usePhotoStore } from '@/stores/photo-store' - -export function PhotoDropzone({ compact = false }: { compact?: boolean }) { - const addFiles = usePhotoStore((state) => state.addFiles) - const [rejectedCount, setRejectedCount] = useState(0) - - const onDrop = useCallback( - (accepted: File[], rejections: FileRejection[]) => { - if (accepted.length > 0) addFiles(accepted) - setRejectedCount(rejections.length) - }, - [addFiles], - ) - - const { getRootProps, getInputProps, isDragActive } = useDropzone({ - onDrop, - accept: { - 'image/jpeg': ['.jpg', '.jpeg'], - 'image/png': ['.png'], - 'image/webp': ['.webp'], - 'image/heic': ['.heic'], - 'image/heif': ['.heif'], - }, - }) - - return ( -
-
- - -
-

- {isDragActive - ? 'Drop your photos…' - : 'Drag photos here, or click to browse'} -

- {!compact && ( -

- JPEG, PNG, WebP, HEIC — processed on your device, never uploaded -

- )} -
-
- {rejectedCount > 0 && ( -

- {rejectedCount} file{rejectedCount > 1 ? 's' : ''} skipped — only - images are supported. -

- )} -
- ) -} diff --git a/apps/web/src/components/photo-sidebar.tsx b/apps/web/src/components/photo-sidebar.tsx new file mode 100644 index 0000000..670fb63 --- /dev/null +++ b/apps/web/src/components/photo-sidebar.tsx @@ -0,0 +1,69 @@ +import { useCallback, useState } from 'react' +import { type FileRejection, useDropzone } from 'react-dropzone' +import { ImagePlus } from 'lucide-react' + +import { PhotoStrip } from '@/components/photo-strip' +import { Button } from '@/components/ui/button' +import { usePhotoStore } from '@/stores/photo-store' + +/** + * Left rail: an "Add photos" button on top, the reorderable strip below. + * The whole rail is a drop target — but stays a clean button until you drag, + * when a square drop pad fades in over a blurred strip. + */ +export function PhotoSidebar() { + const addFiles = usePhotoStore((state) => state.addFiles) + const [rejectedCount, setRejectedCount] = useState(0) + + const onDrop = useCallback( + (accepted: File[], rejections: FileRejection[]) => { + if (accepted.length > 0) addFiles(accepted) + setRejectedCount(rejections.length) + }, + [addFiles], + ) + + const { getRootProps, getInputProps, isDragActive, open } = useDropzone({ + onDrop, + noClick: true, + noKeyboard: true, + accept: { + 'image/jpeg': ['.jpg', '.jpeg'], + 'image/png': ['.png'], + 'image/webp': ['.webp'], + 'image/heic': ['.heic'], + 'image/heif': ['.heif'], + }, + }) + + return ( +
+ + + + + {rejectedCount > 0 && ( +

+ {rejectedCount} file{rejectedCount > 1 ? 's' : ''} skipped — only + images are supported. +

+ )} + + + + {isDragActive && ( +
+
+ +

+ Drop your photos… +

+
+
+ )} +
+ ) +} From 705c65b875762833b6c2becc8ab2fb6bfa9aa344 Mon Sep 17 00:00:00 2001 From: ankitsejwal Date: Sun, 28 Jun 2026 22:28:59 +0530 Subject: [PATCH 2/5] Wire PhotoSidebar into left rail; shorten subhead --- apps/web/src/routes/index.tsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index 661f66d..b4b71a9 100644 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -2,35 +2,29 @@ import { createFileRoute } from '@tanstack/react-router' import { A4Preview } from '@/components/a4-preview' import { OptionsPanel } from '@/components/options-panel' -import { PhotoDropzone } from '@/components/photo-dropzone' -import { PhotoStrip } from '@/components/photo-strip' +import { PhotoSidebar } from '@/components/photo-sidebar' import { ProjectControls } from '@/components/project-controls' -import { usePhotoStore } from '@/stores/photo-store' export const Route = createFileRoute('/')({ component: Home, }) function Home() { - const hasPhotos = usePhotoStore((state) => state.photos.length > 0) - return (

Polaroid

- Build polaroid-style print sheets — edit each frame on the page. - Everything stays on your device. + Edit each frame on the page — everything stays on your device.

-