diff --git a/src/assets/icons/photos.svg b/src/assets/icons/photos.svg new file mode 100644 index 0000000..8c3b4fd --- /dev/null +++ b/src/assets/icons/photos.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/lib/components/PhotoGrid.svelte b/src/lib/components/PhotoGrid.svelte new file mode 100644 index 0000000..172f341 --- /dev/null +++ b/src/lib/components/PhotoGrid.svelte @@ -0,0 +1,88 @@ + + +
+
+ {#each photoItems as item} + + {/each} +
+
+ +{#if lightboxPhoto} + +{/if} + + \ No newline at end of file diff --git a/src/lib/components/PhotoItem.svelte b/src/lib/components/PhotoItem.svelte new file mode 100644 index 0000000..e21a2f9 --- /dev/null +++ b/src/lib/components/PhotoItem.svelte @@ -0,0 +1,255 @@ + + +
+ +
+ + \ No newline at end of file diff --git a/src/lib/components/PhotoLightbox.svelte b/src/lib/components/PhotoLightbox.svelte new file mode 100644 index 0000000..7716655 --- /dev/null +++ b/src/lib/components/PhotoLightbox.svelte @@ -0,0 +1,364 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/SegmentedController.svelte b/src/lib/components/SegmentedController.svelte index e2dd8e3..38c1c06 100644 --- a/src/lib/components/SegmentedController.svelte +++ b/src/lib/components/SegmentedController.svelte @@ -2,6 +2,7 @@ import WorkIcon from '$icons/work.svg' import LabsIcon from '$icons/labs.svg' import UniverseIcon from '$icons/universe.svg' + import PhotosIcon from '$icons/photos.svg' import { page } from '$app/stores' const currentPath = $derived($page.url.pathname) @@ -10,11 +11,12 @@ icon: typeof WorkIcon text: string href: string - variant: 'work' | 'universe' | 'labs' + variant: 'work' | 'universe' | 'labs' | 'photos' } const navItems: NavItem[] = [ { icon: WorkIcon, text: 'Work', href: '/', variant: 'work' }, + { icon: PhotosIcon, text: 'Photos', href: '/photos', variant: 'photos' }, { icon: LabsIcon, text: 'Labs', href: '#', variant: 'labs' }, { icon: UniverseIcon, text: 'Universe', href: '/universe', variant: 'universe' } ] @@ -25,7 +27,8 @@ // Calculate active index based on current path const activeIndex = $derived( currentPath === '/' ? 0 : - currentPath.startsWith('/universe') ? 2 : + currentPath.startsWith('/photos') ? 1 : + currentPath.startsWith('/universe') ? 3 : -1 ) @@ -64,6 +67,7 @@ function getBgColor(variant: string): string { switch (variant) { case 'work': return '#ffcdc5' // $work-bg + case 'photos': return '#e8c5ff' // $photos-bg (purple) case 'universe': return '#ffebc5' // $universe-bg case 'labs': return '#c5eaff' // $labs-bg default: return '#c5eaff' @@ -74,6 +78,7 @@ function getTextColor(variant: string): string { switch (variant) { case 'work': return '#d0290d' // $work-color + case 'photos': return '#7c3aed' // $photos-color (purple) case 'universe': return '#b97d14' // $universe-color case 'labs': return '#1482c1' // $labs-color default: return '#1482c1' @@ -157,18 +162,23 @@ } // Different animations for each nav item - // First item after the sliding pill is Work (index 1) + // First item is Work (index 1) .nav-item:nth-of-type(1) :global(svg.animate) { animation: cursorWiggle 0.6s ease; } - // Second item is Labs (index 2) + // Second item is Photos (index 2) .nav-item:nth-of-type(2) :global(svg.animate) { + animation: photoFlash 0.6s ease; + } + + // Third item is Labs (index 3) + .nav-item:nth-of-type(3) :global(svg.animate) { animation: tubeBubble 0.6s ease; } - // Third item is Universe (index 3) - .nav-item:nth-of-type(3) :global(svg.animate) { + // Fourth item is Universe (index 4) + .nav-item:nth-of-type(4) :global(svg.animate) { animation: starSpin 0.6s ease; } @@ -178,6 +188,11 @@ 75% { transform: rotate(8deg) scale(1.05); } } + @keyframes photoFlash { + 0%, 100% { transform: scale(1); filter: brightness(1); } + 50% { transform: scale(1.1); filter: brightness(1.3); } + } + @keyframes tubeBubble { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-2px) scale(1.1); } diff --git a/src/lib/types/photos.ts b/src/lib/types/photos.ts new file mode 100644 index 0000000..45c21e4 --- /dev/null +++ b/src/lib/types/photos.ts @@ -0,0 +1,35 @@ +export interface ExifData { + camera?: string + lens?: string + focalLength?: string + aperture?: string + shutterSpeed?: string + iso?: string + dateTaken?: string + location?: string +} + +export interface Photo { + id: string + src: string + alt: string + caption?: string + width: number + height: number + exif?: ExifData +} + +export interface PhotoAlbum { + id: string + title: string + description?: string + coverPhoto: Photo + photos: Photo[] + createdAt: string +} + +export type PhotoItem = Photo | PhotoAlbum + +export function isAlbum(item: PhotoItem): item is PhotoAlbum { + return 'photos' in item && Array.isArray(item.photos) +} \ No newline at end of file diff --git a/src/routes/photos/+page.svelte b/src/routes/photos/+page.svelte new file mode 100644 index 0000000..e64eab4 --- /dev/null +++ b/src/routes/photos/+page.svelte @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/src/routes/photos/+page.ts b/src/routes/photos/+page.ts new file mode 100644 index 0000000..f08f442 --- /dev/null +++ b/src/routes/photos/+page.ts @@ -0,0 +1,413 @@ +import type { PageLoad } from './$types' +import type { PhotoItem } from '$lib/types/photos' + +export const load: PageLoad = async () => { + // Mock data for now - in a real app this would come from an API or CMS + const photoItems: PhotoItem[] = [ + { + id: 'photo-1', + src: 'https://picsum.photos/400/600?random=1', + alt: 'Mountain landscape at sunset', + caption: 'A beautiful landscape captured during golden hour', + width: 400, + height: 600, + exif: { + camera: 'Canon EOS R5', + lens: '24-70mm f/2.8', + focalLength: '35mm', + aperture: 'f/5.6', + shutterSpeed: '1/250s', + iso: '100', + dateTaken: '2024-01-15', + location: 'Yosemite National Park' + } + }, + { + id: 'album-1', + title: 'Tokyo Street Photography', + description: 'A collection of street photography from Tokyo', + coverPhoto: { + id: 'album-1-cover', + src: 'https://picsum.photos/500/400?random=2', + alt: 'Tokyo street scene', + width: 500, + height: 400 + }, + photos: [ + { + id: 'album-1-1', + src: 'https://picsum.photos/500/400?random=2', + alt: 'Tokyo street scene', + caption: 'Busy intersection in Shibuya', + width: 500, + height: 400, + exif: { + camera: 'Fujifilm X-T4', + lens: '23mm f/1.4', + focalLength: '23mm', + aperture: 'f/2.8', + shutterSpeed: '1/60s', + iso: '800', + dateTaken: '2024-02-10' + } + }, + { + id: 'album-1-2', + src: 'https://picsum.photos/600/400?random=25', + alt: 'Tokyo alley', + caption: 'Quiet alley in Shinjuku', + width: 600, + height: 400 + }, + { + id: 'album-1-3', + src: 'https://picsum.photos/500/700?random=26', + alt: 'Neon signs', + caption: 'Colorful neon signs in Harajuku', + width: 500, + height: 700, + exif: { + camera: 'Fujifilm X-T4', + lens: '56mm f/1.2', + focalLength: '56mm', + aperture: 'f/1.8', + shutterSpeed: '1/30s', + iso: '1600', + dateTaken: '2024-02-11' + } + } + ], + createdAt: '2024-02-10' + }, + { + id: 'photo-2', + src: 'https://picsum.photos/300/500?random=4', + alt: 'Modern building', + caption: 'Urban architecture study', + width: 300, + height: 500, + exif: { + camera: 'Sony A7IV', + lens: '85mm f/1.8', + focalLength: '85mm', + aperture: 'f/2.8', + shutterSpeed: '1/125s', + iso: '200', + dateTaken: '2024-01-20' + } + }, + { + id: 'photo-3', + src: 'https://picsum.photos/600/300?random=5', + alt: 'Ocean waves', + caption: 'Minimalist seascape composition', + width: 600, + height: 300 + }, + { + id: 'photo-4', + src: 'https://picsum.photos/400/500?random=6', + alt: 'Forest path', + caption: 'Morning light through the trees', + width: 400, + height: 500, + exif: { + camera: 'Nikon Z6II', + lens: '24-120mm f/4', + focalLength: '50mm', + aperture: 'f/8', + shutterSpeed: '1/60s', + iso: '400', + dateTaken: '2024-03-05', + location: 'Redwood National Park' + } + }, + { + id: 'album-2', + title: 'Portrait Series', + description: 'A collection of environmental portraits', + coverPhoto: { + id: 'album-2-cover', + src: 'https://picsum.photos/400/600?random=7', + alt: 'Portrait of a musician', + width: 400, + height: 600 + }, + photos: [ + { + id: 'album-2-1', + src: 'https://picsum.photos/400/600?random=7', + alt: 'Portrait of a musician', + caption: 'Jazz musician in his studio', + width: 400, + height: 600, + exif: { + camera: 'Canon EOS R6', + lens: '85mm f/1.2', + focalLength: '85mm', + aperture: 'f/1.8', + shutterSpeed: '1/125s', + iso: '640', + dateTaken: '2024-02-20' + } + }, + { + id: 'album-2-2', + src: 'https://picsum.photos/500/650?random=27', + alt: 'Artist in gallery', + caption: 'Painter surrounded by her work', + width: 500, + height: 650 + }, + { + id: 'album-2-3', + src: 'https://picsum.photos/450/600?random=28', + alt: 'Chef in kitchen', + caption: 'Chef preparing for evening service', + width: 450, + height: 600 + } + ], + createdAt: '2024-02-20' + }, + { + id: 'photo-5', + src: 'https://picsum.photos/500/350?random=8', + alt: 'City skyline', + caption: 'Downtown at blue hour', + width: 500, + height: 350, + exif: { + camera: 'Sony A7R V', + lens: '16-35mm f/2.8', + focalLength: '24mm', + aperture: 'f/11', + shutterSpeed: '8s', + iso: '100', + dateTaken: '2024-01-30', + location: 'San Francisco' + } + }, + { + id: 'photo-6', + src: 'https://picsum.photos/350/550?random=9', + alt: 'Vintage motorcycle', + caption: 'Classic bike restoration project', + width: 350, + height: 550 + }, + { + id: 'photo-7', + src: 'https://picsum.photos/450/300?random=10', + alt: 'Coffee and books', + caption: 'Quiet morning ritual', + width: 450, + height: 300, + exif: { + camera: 'Fujifilm X100V', + lens: '23mm f/2', + focalLength: '23mm', + aperture: 'f/2.8', + shutterSpeed: '1/60s', + iso: '320', + dateTaken: '2024-03-01' + } + }, + { + id: 'album-3', + title: 'Nature Macro', + description: 'Close-up studies of natural details', + coverPhoto: { + id: 'album-3-cover', + src: 'https://picsum.photos/400/400?random=11', + alt: 'Dewdrop on leaf', + width: 400, + height: 400 + }, + photos: [ + { + id: 'album-3-1', + src: 'https://picsum.photos/400/400?random=11', + alt: 'Dewdrop on leaf', + caption: 'Morning dew captured with macro lens', + width: 400, + height: 400, + exif: { + camera: 'Canon EOS R5', + lens: '100mm f/2.8 Macro', + focalLength: '100mm', + aperture: 'f/5.6', + shutterSpeed: '1/250s', + iso: '200', + dateTaken: '2024-03-15' + } + }, + { + id: 'album-3-2', + src: 'https://picsum.photos/500/500?random=29', + alt: 'Butterfly wing detail', + caption: 'Intricate patterns on butterfly wing', + width: 500, + height: 500 + }, + { + id: 'album-3-3', + src: 'https://picsum.photos/400/600?random=30', + alt: 'Tree bark texture', + caption: 'Ancient oak bark patterns', + width: 400, + height: 600 + }, + { + id: 'album-3-4', + src: 'https://picsum.photos/350/500?random=31', + alt: 'Flower stamen', + caption: 'Lily stamen in soft light', + width: 350, + height: 500 + } + ], + createdAt: '2024-03-15' + }, + { + id: 'photo-8', + src: 'https://picsum.photos/600/400?random=12', + alt: 'Desert landscape', + caption: 'Vast desert under starry sky', + width: 600, + height: 400, + exif: { + camera: 'Nikon D850', + lens: '14-24mm f/2.8', + focalLength: '14mm', + aperture: 'f/2.8', + shutterSpeed: '25s', + iso: '3200', + dateTaken: '2024-02-25', + location: 'Death Valley' + } + }, + { + id: 'photo-9', + src: 'https://picsum.photos/300/450?random=13', + alt: 'Vintage camera', + caption: 'My grandfather\'s Leica', + width: 300, + height: 450 + }, + { + id: 'photo-10', + src: 'https://picsum.photos/550/350?random=14', + alt: 'Market scene', + caption: 'Colorful spices at local market', + width: 550, + height: 350, + exif: { + camera: 'Fujifilm X-T5', + lens: '18-55mm f/2.8-4', + focalLength: '35mm', + aperture: 'f/4', + shutterSpeed: '1/125s', + iso: '800', + dateTaken: '2024-03-10', + location: 'Marrakech, Morocco' + } + }, + { + id: 'photo-11', + src: 'https://picsum.photos/400/600?random=15', + alt: 'Lighthouse at dawn', + caption: 'Coastal beacon in morning mist', + width: 400, + height: 600, + exif: { + camera: 'Sony A7III', + lens: '70-200mm f/2.8', + focalLength: '135mm', + aperture: 'f/8', + shutterSpeed: '1/200s', + iso: '400', + dateTaken: '2024-02-28', + location: 'Big Sur, California' + } + }, + { + id: 'photo-12', + src: 'https://picsum.photos/500/300?random=16', + alt: 'Train station', + caption: 'Rush hour commuters', + width: 500, + height: 300 + }, + { + id: 'album-4', + title: 'Black & White', + description: 'Monochrome photography collection', + coverPhoto: { + id: 'album-4-cover', + src: 'https://picsum.photos/450/600?random=17', + alt: 'Urban shadows', + width: 450, + height: 600 + }, + photos: [ + { + id: 'album-4-1', + src: 'https://picsum.photos/450/600?random=17', + alt: 'Urban shadows', + caption: 'Dramatic shadows in the financial district', + width: 450, + height: 600, + exif: { + camera: 'Leica M11 Monochrom', + lens: '35mm f/1.4', + focalLength: '35mm', + aperture: 'f/5.6', + shutterSpeed: '1/250s', + iso: '200', + dateTaken: '2024-03-20' + } + }, + { + id: 'album-4-2', + src: 'https://picsum.photos/600/400?random=32', + alt: 'Elderly man reading', + caption: 'Contemplation in the park', + width: 600, + height: 400 + }, + { + id: 'album-4-3', + src: 'https://picsum.photos/400/500?random=33', + alt: 'Rain on window', + caption: 'Storm patterns on glass', + width: 400, + height: 500 + } + ], + createdAt: '2024-03-20' + }, + { + id: 'photo-13', + src: 'https://picsum.photos/350/500?random=18', + alt: 'Street art mural', + caption: 'Vibrant wall art in the Mission District', + width: 350, + height: 500, + exif: { + camera: 'iPhone 15 Pro', + lens: '24mm f/1.8', + focalLength: '24mm', + aperture: 'f/1.8', + shutterSpeed: '1/120s', + iso: '64', + dateTaken: '2024-03-25', + location: 'San Francisco' + } + } + ] + + return { + photoItems + } +} \ No newline at end of file