Skip to content

Commit 88bec71

Browse files
MaskedHunterclaude
authored andcommitted
feat: add 7 more FoodShot hero concepts (batch 4: 17-23)
New concepts: Orbit (3D rotating carousel), Curtain (theatrical scroll reveal), Flip (3D card flip before/after), Accordion (expandable hover panels), Spotlight (cursor light beam), Mosaic (tile assembly), Scramble (pixel resolve). Total now 23 concepts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 05ffbcd commit 88bec71

8 files changed

Lines changed: 1359 additions & 3 deletions

File tree

src/app/demos/foodshot/page.tsx

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,41 @@ const TheMorph = dynamic(
8787
{ ssr: false, loading: () => <SectionLoader label="The Morph" /> }
8888
);
8989

90+
const TheOrbit = dynamic(
91+
() => import("@/components/foodshot/orbit-carousel").then((m) => m.OrbitCarousel),
92+
{ ssr: false, loading: () => <SectionLoader label="The Orbit" /> }
93+
);
94+
95+
const TheCurtain = dynamic(
96+
() => import("@/components/foodshot/curtain-reveal").then((m) => m.CurtainReveal),
97+
{ ssr: false, loading: () => <SectionLoader label="The Curtain" /> }
98+
);
99+
100+
const TheFlip = dynamic(
101+
() => import("@/components/foodshot/flip-card").then((m) => m.FlipCard),
102+
{ ssr: false, loading: () => <SectionLoader label="The Flip" /> }
103+
);
104+
105+
const TheAccordion = dynamic(
106+
() => import("@/components/foodshot/accordion-panels").then((m) => m.AccordionPanels),
107+
{ ssr: false, loading: () => <SectionLoader label="The Accordion" /> }
108+
);
109+
110+
const TheSpotlightBeam = dynamic(
111+
() => import("@/components/foodshot/spotlight-beam").then((m) => m.SpotlightBeam),
112+
{ ssr: false, loading: () => <SectionLoader label="The Spotlight" /> }
113+
);
114+
115+
const TheMosaic = dynamic(
116+
() => import("@/components/foodshot/mosaic-grid").then((m) => m.MosaicGrid),
117+
{ ssr: false, loading: () => <SectionLoader label="The Mosaic" /> }
118+
);
119+
120+
const TheScramble = dynamic(
121+
() => import("@/components/foodshot/scramble-reveal").then((m) => m.ScrambleReveal),
122+
{ ssr: false, loading: () => <SectionLoader label="The Scramble" /> }
123+
);
124+
90125
function SectionLoader({ label }: { label: string }) {
91126
return (
92127
<div className="w-full min-h-screen flex items-center justify-center bg-[#0a0a0a]">
@@ -115,6 +150,13 @@ const concepts = [
115150
{ id: "the-filmstrip", label: "The Filmstrip", desc: "Cinema Reel" },
116151
{ id: "the-counter", label: "The Counter", desc: "Revenue Impact" },
117152
{ id: "the-morph", label: "The Morph", desc: "Circle Reveal" },
153+
{ id: "the-orbit", label: "The Orbit", desc: "3D Carousel" },
154+
{ id: "the-curtain", label: "The Curtain", desc: "Theatrical Reveal" },
155+
{ id: "the-flip", label: "The Flip", desc: "Card Flip" },
156+
{ id: "the-accordion", label: "The Accordion", desc: "Expandable Panels" },
157+
{ id: "the-spotlight-beam", label: "The Spotlight", desc: "Light Beam" },
158+
{ id: "the-mosaic", label: "The Mosaic", desc: "Tile Assembly" },
159+
{ id: "the-scramble", label: "The Scramble", desc: "Pixel Resolve" },
118160
];
119161

120162
export default function FoodShotShowcase() {
@@ -161,7 +203,7 @@ export default function FoodShotShowcase() {
161203
className="relative z-10 text-center max-w-3xl"
162204
>
163205
<span className="inline-block px-4 py-1.5 text-xs font-mono uppercase tracking-wider rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-400 mb-8">
164-
16 Hero Concepts for FoodShot
206+
23 Hero Concepts for FoodShot
165207
</span>
166208
<h1 className="text-5xl md:text-8xl font-bold mb-6 leading-[1.05] tracking-tight">
167209
<span className="bg-gradient-to-r from-amber-400 via-orange-400 to-red-400 bg-clip-text text-transparent">
@@ -173,7 +215,7 @@ export default function FoodShotShowcase() {
173215
</span>
174216
</h1>
175217
<p className="text-zinc-500 text-lg max-w-xl mx-auto mb-10">
176-
16 distinct visual experiences, each selling FoodShot from a unique angle.
218+
23 distinct visual experiences, each selling FoodShot from a unique angle.
177219
Real restaurant photos. No stock imagery.
178220
</p>
179221

@@ -318,13 +360,63 @@ export default function FoodShotShowcase() {
318360
<div id="the-morph">
319361
<TheMorph />
320362
</div>
363+
364+
{/* === BATCH 4: 7 MORE CONCEPTS === */}
365+
<div className="relative py-20 px-6">
366+
<div className="max-w-3xl mx-auto text-center">
367+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/30 to-transparent mb-12" />
368+
<span className="inline-block px-4 py-1.5 text-xs font-mono uppercase tracking-wider rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-400">
369+
7 More Concepts
370+
</span>
371+
</div>
372+
</div>
373+
374+
<div id="the-orbit">
375+
<TheOrbit />
376+
</div>
377+
378+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/10 to-transparent" />
379+
380+
<div id="the-curtain">
381+
<TheCurtain />
382+
</div>
383+
384+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/10 to-transparent" />
385+
386+
<div id="the-flip">
387+
<TheFlip />
388+
</div>
389+
390+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/10 to-transparent" />
391+
392+
<div id="the-accordion">
393+
<TheAccordion />
394+
</div>
395+
396+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/10 to-transparent" />
397+
398+
<div id="the-spotlight-beam">
399+
<TheSpotlightBeam />
400+
</div>
401+
402+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/10 to-transparent" />
403+
404+
<div id="the-mosaic">
405+
<TheMosaic />
406+
</div>
407+
408+
<div className="h-px bg-gradient-to-r from-transparent via-amber-500/10 to-transparent" />
409+
410+
<div id="the-scramble">
411+
<TheScramble />
412+
</div>
321413
</div>
322414

323415
{/* Footer */}
324416
<footer className="relative z-10 py-16 px-6 border-t border-zinc-900">
325417
<div className="max-w-3xl mx-auto text-center">
326418
<p className="text-zinc-600 text-sm mb-6">
327-
16 concepts • Real restaurant photography • Contained images at proper resolution
419+
23 concepts • Real restaurant photography • Contained images at proper resolution
328420
</p>
329421
<div className="flex gap-4 justify-center">
330422
<Link
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
"use client";
2+
3+
import { motion, AnimatePresence } from "framer-motion";
4+
import { useState } from "react";
5+
import Image from "next/image";
6+
import { foodPhotos } from "./photo-data";
7+
8+
/**
9+
* "The Accordion" — Expandable photo panels.
10+
* All 6 photos shown as compressed vertical strips.
11+
* Hover/click one and it expands to take up most of the width
12+
* while the others compress further. Like a visual accordion.
13+
*/
14+
15+
export function AccordionPanels() {
16+
const [activeIndex, setActiveIndex] = useState(0);
17+
18+
return (
19+
<section className="relative w-full bg-[#060606] overflow-hidden px-6 md:px-12 py-24">
20+
{/* Header */}
21+
<motion.div
22+
initial={{ opacity: 0, y: 16 }}
23+
whileInView={{ opacity: 1, y: 0 }}
24+
viewport={{ once: true }}
25+
className="text-center mb-14 max-w-3xl mx-auto"
26+
>
27+
<h2 className="text-4xl md:text-7xl font-bold text-white mb-4 tracking-tight">
28+
Expand your{" "}
29+
<span className="bg-gradient-to-r from-amber-400 to-orange-400 bg-clip-text text-transparent">
30+
menu
31+
</span>
32+
</h2>
33+
<p className="text-zinc-500 text-base max-w-lg mx-auto">
34+
Hover over any panel to expand it. Each restaurant gets its moment to shine.
35+
</p>
36+
</motion.div>
37+
38+
{/* Accordion */}
39+
<div className="max-w-6xl mx-auto">
40+
<div
41+
className="flex gap-2 w-full"
42+
style={{ height: "clamp(400px, 60vh, 600px)" }}
43+
>
44+
{foodPhotos.map((photo, i) => {
45+
const isActive = activeIndex === i;
46+
47+
return (
48+
<motion.div
49+
key={i}
50+
onMouseEnter={() => setActiveIndex(i)}
51+
onClick={() => setActiveIndex(i)}
52+
animate={{
53+
flex: isActive ? 5 : 1,
54+
}}
55+
transition={{ duration: 0.5, ease: [0.23, 1, 0.32, 1] }}
56+
className="relative rounded-2xl overflow-hidden cursor-pointer group"
57+
style={{ minWidth: 0 }}
58+
>
59+
{/* Photo */}
60+
<Image
61+
src={photo.after}
62+
alt={photo.restaurant}
63+
fill
64+
className="object-cover"
65+
sizes={isActive ? "60vw" : "10vw"}
66+
/>
67+
68+
{/* Darkening overlay for inactive panels */}
69+
<motion.div
70+
animate={{ opacity: isActive ? 0 : 0.5 }}
71+
transition={{ duration: 0.4 }}
72+
className="absolute inset-0 bg-black"
73+
/>
74+
75+
{/* Active border glow */}
76+
<motion.div
77+
animate={{
78+
opacity: isActive ? 1 : 0,
79+
borderColor: isActive
80+
? "rgba(245, 158, 11, 0.2)"
81+
: "rgba(63, 63, 70, 0.3)",
82+
}}
83+
className="absolute inset-0 rounded-2xl border-2 pointer-events-none z-10"
84+
/>
85+
86+
{/* Vertical label (for collapsed panels) */}
87+
<AnimatePresence>
88+
{!isActive && (
89+
<motion.div
90+
initial={{ opacity: 0 }}
91+
animate={{ opacity: 1 }}
92+
exit={{ opacity: 0 }}
93+
className="absolute inset-0 flex items-center justify-center z-20"
94+
>
95+
<span
96+
className="text-white/60 text-xs font-mono uppercase tracking-[0.3em] whitespace-nowrap"
97+
style={{
98+
writingMode: "vertical-rl",
99+
textOrientation: "mixed",
100+
}}
101+
>
102+
{photo.restaurant}
103+
</span>
104+
</motion.div>
105+
)}
106+
</AnimatePresence>
107+
108+
{/* Expanded info */}
109+
<AnimatePresence>
110+
{isActive && (
111+
<motion.div
112+
initial={{ opacity: 0, y: 20 }}
113+
animate={{ opacity: 1, y: 0 }}
114+
exit={{ opacity: 0, y: 10 }}
115+
transition={{ delay: 0.2, duration: 0.4 }}
116+
className="absolute bottom-0 inset-x-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent p-6 z-20"
117+
>
118+
<div className="flex items-end justify-between">
119+
<div>
120+
<span className="px-2.5 py-1 rounded-md bg-amber-500/10 border border-amber-500/30 text-amber-400 text-[9px] font-mono uppercase tracking-wider">
121+
Enhanced
122+
</span>
123+
<h3 className="text-white text-xl font-bold mt-3">
124+
{photo.restaurant}
125+
</h3>
126+
<p className="text-zinc-400 text-sm mt-1">
127+
Enhanced by FoodShot AI
128+
</p>
129+
</div>
130+
<div className="hidden md:block text-right">
131+
<p className="text-amber-400 text-2xl font-bold">
132+
+{140 + i * 23}%
133+
</p>
134+
<p className="text-zinc-600 text-[10px] font-mono uppercase">
135+
Engagement
136+
</p>
137+
</div>
138+
</div>
139+
</motion.div>
140+
)}
141+
</AnimatePresence>
142+
143+
{/* Number badge */}
144+
<div className="absolute top-4 left-4 z-20">
145+
<motion.div
146+
animate={{
147+
backgroundColor: isActive
148+
? "rgba(245, 158, 11, 0.1)"
149+
: "rgba(0, 0, 0, 0.4)",
150+
borderColor: isActive
151+
? "rgba(245, 158, 11, 0.3)"
152+
: "rgba(63, 63, 70, 0.3)",
153+
}}
154+
className="w-8 h-8 rounded-full border flex items-center justify-center backdrop-blur-sm"
155+
>
156+
<span
157+
className={`text-xs font-mono ${
158+
isActive ? "text-amber-400" : "text-zinc-500"
159+
}`}
160+
>
161+
{i + 1}
162+
</span>
163+
</motion.div>
164+
</div>
165+
</motion.div>
166+
);
167+
})}
168+
</div>
169+
</div>
170+
171+
{/* Bottom note */}
172+
<motion.p
173+
initial={{ opacity: 0 }}
174+
whileInView={{ opacity: 1 }}
175+
viewport={{ once: true }}
176+
className="text-zinc-700 text-xs text-center mt-8 font-mono"
177+
>
178+
Hover to expand • 6 restaurants, one view
179+
</motion.p>
180+
</section>
181+
);
182+
}

0 commit comments

Comments
 (0)