export const projects = [ { id: "lunary", title: "Lunary", techStack: "Next.js, Prisma, PostgreSQL", info: "A real-time astrology platform with birth charts, transit tracking, and synastry analysis.", }, // ... ]; CODE_BLOCK: export const projects = [ { id: "lunary", title: "Lunary", techStack: "Next.js, Prisma, PostgreSQL", info: "A real-time astrology platform with birth charts, transit tracking, and synastry analysis.", }, // ... ]; CODE_BLOCK: export const projects = [ { id: "lunary", title: "Lunary", techStack: "Next.js, Prisma, PostgreSQL", info: "A real-time astrology platform with birth charts, transit tracking, and synastry analysis.", }, // ... ]; COMMAND_BLOCK: interface ProjectItemProps { project: Project; isGrid: boolean; } export function ProjectItem({ project, isGrid }: ProjectItemProps) { if (isGrid) { return ( ### {project.title} {project.info} {project.techStack} [[Code]]({`https://github.com/sammii-hk/${project.id}`}) ); } return ( ## {project.title} [[Code]]({`https://github.com/sammii-hk/${project.id}`}) {project.info} {project.techStack} ); } COMMAND_BLOCK: interface ProjectItemProps { project: Project; isGrid: boolean; } export function ProjectItem({ project, isGrid }: ProjectItemProps) { if (isGrid) { return ( ### {project.title} {project.info} {project.techStack} [[Code]]({`https://github.com/sammii-hk/${project.id}`}) ); } return ( ## {project.title} [[Code]]({`https://github.com/sammii-hk/${project.id}`}) {project.info} {project.techStack} ); } COMMAND_BLOCK: interface ProjectItemProps { project: Project; isGrid: boolean; } export function ProjectItem({ project, isGrid }: ProjectItemProps) { if (isGrid) { return ( ### {project.title} {project.info} {project.techStack} [[Code]]({`https://github.com/sammii-hk/${project.id}`}) ); } return ( ## {project.title} [[Code]]({`https://github.com/sammii-hk/${project.id}`}) {project.info} {project.techStack} ); } COMMAND_BLOCK: export function ProjectGrid() { const [selected, setSelected] = useState(null); return ( <> {projects.map((project) => ( setSelected(project)}> ))} {selected && ( setSelected(null)} /> )} ); } COMMAND_BLOCK: export function ProjectGrid() { const [selected, setSelected] = useState(null); return ( <> {projects.map((project) => ( setSelected(project)}> ))} {selected && ( setSelected(null)} /> )} ); } COMMAND_BLOCK: export function ProjectGrid() { const [selected, setSelected] = useState(null); return ( <> {projects.map((project) => ( setSelected(project)}> ))} {selected && ( setSelected(null)} /> )} ); } COMMAND_BLOCK: export function ProjectView() { const { scrollRef, activePageIndex, goTo, snapPointIndexes } = useSnapCarousel({ axis: "y" }); return ( {projects.map((project, i) => ( ))} ); } COMMAND_BLOCK: export function ProjectView() { const { scrollRef, activePageIndex, goTo, snapPointIndexes } = useSnapCarousel({ axis: "y" }); return ( {projects.map((project, i) => ( ))} ); } COMMAND_BLOCK: export function ProjectView() { const { scrollRef, activePageIndex, goTo, snapPointIndexes } = useSnapCarousel({ axis: "y" }); return ( {projects.map((project, i) => ( ))} ); } CODE_BLOCK: export function ViewToggle({ view, onChange }: ViewToggleProps) { return ( onChange("grid")} > Grid onChange("list")} > List ); } CODE_BLOCK: export function ViewToggle({ view, onChange }: ViewToggleProps) { return ( onChange("grid")} > Grid onChange("list")} > List ); } CODE_BLOCK: export function ViewToggle({ view, onChange }: ViewToggleProps) { return ( onChange("grid")} > Grid onChange("list")} > List ); } COMMAND_BLOCK: const [view, setView] = useState<"grid" | "list">(() => { if (typeof window === "undefined") return "grid"; return (localStorage.getItem("portfolioView") as "grid" | "list") ?? "grid"; }); const handleViewChange = (next: "grid" | "list") => { setView(next); localStorage.setItem("portfolioView", next); }; COMMAND_BLOCK: const [view, setView] = useState<"grid" | "list">(() => { if (typeof window === "undefined") return "grid"; return (localStorage.getItem("portfolioView") as "grid" | "list") ?? "grid"; }); const handleViewChange = (next: "grid" | "list") => { setView(next); localStorage.setItem("portfolioView", next); }; COMMAND_BLOCK: const [view, setView] = useState<"grid" | "list">(() => { if (typeof window === "undefined") return "grid"; return (localStorage.getItem("portfolioView") as "grid" | "list") ?? "grid"; }); const handleViewChange = (next: "grid" | "list") => { setView(next); localStorage.setItem("portfolioView", next); };
- The same data needs different densities (list vs grid vs card)
- The same data serves different interaction models (browse vs deep-dive)
- You want mobile and desktop to feel fundamentally different without duplicating state
- The two layouts are genuinely complementary rather than redundant
- The prop branching gets deeply nested. If isGrid starts controlling more than layout — data fetching, event handling, child components — you have two components wearing one coat. Split them.
- Performance matters. Both branches of ProjectItem render on every mount even if only one is shown. For large lists or heavy components, lazy-loading separate implementations is worth the duplication.
- The data shapes diverge. If the grid needs a summary and the carousel needs the full object, the shared component will grow an awkward prop surface. Two components sharing a type is cleaner than one component doing too much.