Template
Extract a shared Logo component for the header and footer
The header inlined its own logo/wordmark fallback markup. Pull it into components/logo.tsx so the footer can show the same mark, and drop the now-unneeded 'use client' from the root layout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUttSNLkLPvvR6Xf75QA1K
This commit is contained in:
co-authored by
Claude Opus 5
parent
b139b30273
commit
ebdb0bee2f
@@ -1,5 +1,3 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './globals.css';
|
import './globals.css';
|
||||||
import { Geist, Geist_Mono } from 'next/font/google';
|
import { Geist, Geist_Mono } from 'next/font/google';
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
interface LogoProps {
|
||||||
|
/** Logo image URL. Falls back to the store name as a wordmark when absent. */
|
||||||
|
src?: string | null;
|
||||||
|
/** Wordmark text, and the image's alt text. */
|
||||||
|
storeName?: string;
|
||||||
|
/** Where the logo links to. Pass null to render it unwrapped. */
|
||||||
|
href?: string | null;
|
||||||
|
/** Sizing for the image — height only, so the aspect ratio is preserved. */
|
||||||
|
imageClassName?: string;
|
||||||
|
/** Sizing and weight for the wordmark fallback. */
|
||||||
|
textClassName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Logo: React.FC<LogoProps> = ({
|
||||||
|
src,
|
||||||
|
storeName = 'Shop',
|
||||||
|
href = '/',
|
||||||
|
imageClassName = 'h-6',
|
||||||
|
textClassName = 'text-xl',
|
||||||
|
}) => {
|
||||||
|
const mark = src ? (
|
||||||
|
<img
|
||||||
|
src={src}
|
||||||
|
alt={storeName}
|
||||||
|
className={`w-auto object-contain ${imageClassName}`}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span
|
||||||
|
className={`font-medium tracking-tight text-foreground ${textClassName}`}
|
||||||
|
>
|
||||||
|
{storeName}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (href === null) {
|
||||||
|
return <span className="flex items-center">{mark}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link href={href} className="flex items-center">
|
||||||
|
{mark}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
RiTiktokLine,
|
RiTiktokLine,
|
||||||
RiFacebookFill,
|
RiFacebookFill,
|
||||||
} from '@remixicon/react';
|
} from '@remixicon/react';
|
||||||
|
import Logo from '@/components/logo';
|
||||||
|
|
||||||
export interface FooterLink {
|
export interface FooterLink {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -12,6 +13,7 @@ export interface FooterLink {
|
|||||||
|
|
||||||
interface FooterProps {
|
interface FooterProps {
|
||||||
storeName?: string;
|
storeName?: string;
|
||||||
|
logoUrl?: string;
|
||||||
copyright?: string;
|
copyright?: string;
|
||||||
links?: FooterLink[];
|
links?: FooterLink[];
|
||||||
instagramUrl?: string;
|
instagramUrl?: string;
|
||||||
@@ -21,6 +23,7 @@ interface FooterProps {
|
|||||||
|
|
||||||
const Footer: React.FC<FooterProps> = ({
|
const Footer: React.FC<FooterProps> = ({
|
||||||
storeName = 'Shop',
|
storeName = 'Shop',
|
||||||
|
logoUrl,
|
||||||
copyright,
|
copyright,
|
||||||
links = [
|
links = [
|
||||||
{ label: 'Terms of Service', url: '/policies/terms-of-service' },
|
{ label: 'Terms of Service', url: '/policies/terms-of-service' },
|
||||||
@@ -46,6 +49,13 @@ const Footer: React.FC<FooterProps> = ({
|
|||||||
assistant launcher. Links and socials sit on separate rows so the
|
assistant launcher. Links and socials sit on separate rows so the
|
||||||
icons aren't crammed onto the end of the link list. */}
|
icons aren't crammed onto the end of the link list. */}
|
||||||
<div className="flex flex-col items-center gap-y-5 sm:items-start">
|
<div className="flex flex-col items-center gap-y-5 sm:items-start">
|
||||||
|
<Logo
|
||||||
|
src={logoUrl}
|
||||||
|
storeName={storeName}
|
||||||
|
imageClassName="h-5"
|
||||||
|
textClassName="text-base"
|
||||||
|
/>
|
||||||
|
|
||||||
<nav className="flex flex-wrap items-center justify-center gap-x-5 gap-y-2 sm:justify-start">
|
<nav className="flex flex-wrap items-center justify-center gap-x-5 gap-y-2 sm:justify-start">
|
||||||
{links.map((link) => (
|
{links.map((link) => (
|
||||||
<a
|
<a
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import SearchDialog from '@/components/shopify/search-dialog';
|
|||||||
import AccountMenu from '@/components/shopify/account-menu';
|
import AccountMenu from '@/components/shopify/account-menu';
|
||||||
import { RiShoppingBagLine, RiCloseLine, RiMenu3Line } from '@remixicon/react';
|
import { RiShoppingBagLine, RiCloseLine, RiMenu3Line } from '@remixicon/react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import Logo from '@/components/logo';
|
||||||
|
|
||||||
const CartIcon: React.FC = () => {
|
const CartIcon: React.FC = () => {
|
||||||
const toggleCart = useCartStore((s) => s.toggleCart);
|
const toggleCart = useCartStore((s) => s.toggleCart);
|
||||||
@@ -83,19 +84,7 @@ const Header: React.FC<HeaderProps> = ({
|
|||||||
<div className="max-w-screen-2xl mx-auto px-8">
|
<div className="max-w-screen-2xl mx-auto px-8">
|
||||||
<div className="flex justify-between items-center h-14">
|
<div className="flex justify-between items-center h-14">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<Link href="/" className="flex items-center">
|
<Logo src={logoUrl} storeName={storeName} />
|
||||||
{logoUrl ? (
|
|
||||||
<img
|
|
||||||
src={logoUrl}
|
|
||||||
alt={storeName}
|
|
||||||
className="h-6 w-auto object-contain"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span className="text-xl font-medium tracking-tight text-foreground">
|
|
||||||
{storeName}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
{/* Desktop Navigation */}
|
{/* Desktop Navigation */}
|
||||||
<div className="hidden md:flex items-center gap-x-8 text-sm">
|
<div className="hidden md:flex items-center gap-x-8 text-sm">
|
||||||
|
|||||||
Reference in New Issue
Block a user