feat: update navigation and add new block components
- Disabled development indicators in next.config.ts for cleaner output. - Updated English and Chinese message files to include new block titles for logo, login, signup, and contact sections. - Refactored routes to include new paths for login, signup, and contact blocks. - Introduced new layout and page components for marketing sections, including logo cloud and various call-to-action pages. - Enhanced blocks navigation component to utilize updated paths and improve user experience.
This commit is contained in:
parent
aefe37068b
commit
af94ab6dd0
@ -227,26 +227,47 @@
|
||||
"hero": {
|
||||
"title": "Hero Blocks"
|
||||
},
|
||||
"pricing": {
|
||||
"title": "Pricing Blocks"
|
||||
"logo": {
|
||||
"title": "Logo Cloud Blocks"
|
||||
},
|
||||
"features": {
|
||||
"title": "Features Blocks"
|
||||
},
|
||||
"faq": {
|
||||
"title": "FAQ Blocks"
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Testimonials Blocks"
|
||||
"content": {
|
||||
"title": "Content Blocks"
|
||||
},
|
||||
"stats": {
|
||||
"title": "Stats Blocks"
|
||||
},
|
||||
"team": {
|
||||
"title": "Team Blocks"
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Testimonials Blocks"
|
||||
},
|
||||
"callToAction": {
|
||||
"title": "Call to Action Blocks"
|
||||
},
|
||||
"content": {
|
||||
"title": "Content Blocks"
|
||||
"footer": {
|
||||
"title": "Footer Blocks"
|
||||
},
|
||||
"pricing": {
|
||||
"title": "Pricing Blocks"
|
||||
},
|
||||
"comparator": {
|
||||
"title": "Comparator Blocks"
|
||||
},
|
||||
"faq": {
|
||||
"title": "FAQ Blocks"
|
||||
},
|
||||
"login": {
|
||||
"title": "Login Blocks"
|
||||
},
|
||||
"signup": {
|
||||
"title": "Signup Blocks"
|
||||
},
|
||||
"contact": {
|
||||
"title": "Contact Blocks"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,26 +222,47 @@
|
||||
"hero": {
|
||||
"title": "Hero组件"
|
||||
},
|
||||
"pricing": {
|
||||
"title": "Pricing组件"
|
||||
"logoCloud": {
|
||||
"title": "Logo Cloud组件"
|
||||
},
|
||||
"features": {
|
||||
"title": "Features组件"
|
||||
},
|
||||
"faq": {
|
||||
"title": "FAQ组件"
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Testimonials组件"
|
||||
"content": {
|
||||
"title": "Content组件"
|
||||
},
|
||||
"stats": {
|
||||
"title": "Stats组件"
|
||||
},
|
||||
"team": {
|
||||
"title": "Team组件"
|
||||
},
|
||||
"testimonials": {
|
||||
"title": "Testimonials组件"
|
||||
},
|
||||
"callToAction": {
|
||||
"title": "Call to Action组件"
|
||||
},
|
||||
"content": {
|
||||
"title": "Content组件"
|
||||
"footer": {
|
||||
"title": "Footer组件"
|
||||
},
|
||||
"pricing": {
|
||||
"title": "Pricing组件"
|
||||
},
|
||||
"comparator": {
|
||||
"title": "Comparator组件"
|
||||
},
|
||||
"faqs": {
|
||||
"title": "FAQs组件"
|
||||
},
|
||||
"login": {
|
||||
"title": "Login组件"
|
||||
},
|
||||
"signup": {
|
||||
"title": "Signup组件"
|
||||
},
|
||||
"contact": {
|
||||
"title": "Contact组件"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { withContentCollections } from "@content-collections/next";
|
||||
*/
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
devIndicators: false,
|
||||
|
||||
// https://nextjs.org/docs/architecture/nextjs-compiler#remove-console
|
||||
// Remove all console.* calls in production only
|
||||
|
@ -1,15 +0,0 @@
|
||||
import CategoryNavigation from '@/components/blocks/blocks-nav';
|
||||
import { categories } from '@/components/blocks/blocks';
|
||||
|
||||
export default function CategoryLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<>
|
||||
<CategoryNavigation categories={categories} />
|
||||
<main>{children}</main>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
import BlockPreview from '@/components/blocks/block-preview';
|
||||
import { blocks, categories } from '@/components/blocks/blocks';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ category: string }>;
|
||||
}
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
export const revalidate = 3600;
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return categories.map((category) => ({
|
||||
category: category,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageProps) {
|
||||
const { category } = await params;
|
||||
return {
|
||||
title: `Shadcn ${category} Blocks`,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function CategoryPage({ params }: PageProps) {
|
||||
const { category } = await params;
|
||||
const categoryBlocks = blocks.filter((b) => b.category === category);
|
||||
|
||||
if (categoryBlocks.length === 0) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<section>
|
||||
<h1 className="sr-only text-3xl font-bold sm:text-4xl md:text-nowrap">
|
||||
Shadcn <span className="capitalize">{category}</span> blocks
|
||||
</h1>
|
||||
<p className="sr-only text-base md:text-lg">
|
||||
Speed up your workflow with responsive, pre-built UI blocks designed
|
||||
for marketing websites.
|
||||
</p>
|
||||
<div className="h-6 w-full bg-[repeating-linear-gradient(-45deg,var(--color-border),var(--color-border)_1px,transparent_1px,transparent_6px)] opacity-35"></div>
|
||||
</section>
|
||||
|
||||
{categoryBlocks.map((block, index) => (
|
||||
<BlockPreview {...block} key={index} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
12
src/app/[locale]/(marketing)/blocks/[category]/layout.tsx
Normal file
12
src/app/[locale]/(marketing)/blocks/[category]/layout.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { categories } from '@/components/blocks/blocks';
|
||||
import BlocksNav from '@/components/blocks/blocks-nav';
|
||||
import { PropsWithChildren } from 'react';
|
||||
|
||||
export default function CategoryLayout({ children }: PropsWithChildren) {
|
||||
return (
|
||||
<>
|
||||
<BlocksNav categories={categories} />
|
||||
<main>{children}</main>
|
||||
</>
|
||||
);
|
||||
}
|
54
src/app/[locale]/(marketing)/blocks/[category]/page.tsx
Normal file
54
src/app/[locale]/(marketing)/blocks/[category]/page.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import BlockPreview from '@/components/blocks/block-preview';
|
||||
import { blocks, categories } from '@/components/blocks/blocks';
|
||||
import { constructMetadata } from '@/lib/metadata';
|
||||
import { getBaseUrlWithLocale } from '@/lib/urls/get-base-url';
|
||||
import { Metadata } from 'next';
|
||||
import { Locale } from 'next-intl';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
interface BlockCategoryPageProps {
|
||||
params: Promise<{ category: string }>;
|
||||
}
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
export const revalidate = 3600;
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return categories.map((category) => ({
|
||||
category: category,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: Locale; category: string }>;
|
||||
}): Promise<Metadata | undefined> {
|
||||
const { locale, category } = await params;
|
||||
const t = await getTranslations({ locale, namespace: 'Metadata' });
|
||||
return constructMetadata({
|
||||
title: category + ' | ' + t('title'),
|
||||
description: t('description'),
|
||||
canonicalUrl: `${getBaseUrlWithLocale(locale)}/blocks/${category}`,
|
||||
});
|
||||
}
|
||||
|
||||
export default async function BlockCategoryPage({
|
||||
params,
|
||||
}: BlockCategoryPageProps) {
|
||||
const { category } = await params;
|
||||
const categoryBlocks = blocks.filter((b) => b.category === category);
|
||||
|
||||
if (categoryBlocks.length === 0) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{categoryBlocks.map((block, index) => (
|
||||
<BlockPreview {...block} key={index} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
@ -6,9 +6,9 @@ import { notFound } from 'next/navigation';
|
||||
import { ReactNode } from 'react';
|
||||
import { Toaster } from 'sonner';
|
||||
import { Providers } from './providers';
|
||||
import { TailwindIndicator } from '@/components/tailwind-indicator';
|
||||
|
||||
import '@/styles/globals.css';
|
||||
import { TailwindIndicator } from '@/components/tailwind-indicator';
|
||||
|
||||
interface LocaleLayoutProps {
|
||||
children: ReactNode;
|
||||
@ -52,7 +52,7 @@ export default async function LocaleLayout({
|
||||
|
||||
<Toaster richColors position="top-right" offset={64} />
|
||||
|
||||
<TailwindIndicator />
|
||||
{/* <TailwindIndicator /> */}
|
||||
</Providers>
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
|
@ -1,43 +1,46 @@
|
||||
'use client';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
import { LocaleLink, useLocalePathname } from '@/i18n/navigation';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const BlocksNav = ({ categories }: { categories: string[] }) => {
|
||||
const pathname = usePathname();
|
||||
export default function BlocksNav({ categories }: { categories: string[] }) {
|
||||
const pathname = useLocalePathname();
|
||||
|
||||
return (
|
||||
<div className="dark:border-border/50 relative z-50 border-b">
|
||||
<div className="mt-4 dark:border-border/50 relative z-20 border-t">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<nav className="flex items-center lg:-mx-3">
|
||||
<ul className="relative -mb-px flex h-11 snap-x snap-proximity scroll-px-6 items-center gap-6 overflow-x-auto overflow-y-hidden px-6 lg:scroll-px-2 lg:gap-5">
|
||||
{categories.map((category) => (
|
||||
<li
|
||||
key={category}
|
||||
className={cn(
|
||||
'flex h-full snap-start items-center border-b border-b-transparent',
|
||||
pathname === `/nsui/${category}` && 'border-primary'
|
||||
)}
|
||||
>
|
||||
<Link
|
||||
href={`/nsui/${category}`}
|
||||
prefetch={true}
|
||||
<ul className="relative -mb-px flex h-12 snap-x snap-proximity scroll-px-6 items-center gap-6 overflow-x-auto overflow-y-hidden px-6 lg:scroll-px-2 lg:gap-5">
|
||||
{categories.map((category) => {
|
||||
const href = `/blocks/${category}`;
|
||||
const isActive = pathname.startsWith(href);
|
||||
|
||||
return (
|
||||
<li
|
||||
key={category}
|
||||
className={cn(
|
||||
pathname === `/nsui/${category}` && 'text-foreground!',
|
||||
'hover:bg-muted dark:text-muted-foreground hover:text-foreground flex h-7 w-fit items-center text-nowrap rounded-full px-1 text-sm text-zinc-700 lg:-mx-2 lg:px-3'
|
||||
'flex h-full snap-start items-center border-b border-b-transparent',
|
||||
isActive && 'border-primary'
|
||||
)}
|
||||
>
|
||||
<span className="block w-max text-nowrap capitalize">
|
||||
{category}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
<LocaleLink
|
||||
href={href}
|
||||
prefetch={true}
|
||||
className={cn(
|
||||
isActive && 'text-foreground!',
|
||||
'hover:bg-muted dark:text-muted-foreground hover:text-foreground flex h-7 w-fit items-center text-nowrap rounded-full px-2 text-sm text-zinc-700 lg:-mx-2 lg:px-3'
|
||||
)}
|
||||
>
|
||||
<span className="block w-max text-nowrap capitalize">
|
||||
{category}
|
||||
</span>
|
||||
</LocaleLink>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlocksNav;
|
||||
}
|
||||
|
@ -35,7 +35,13 @@ import {
|
||||
SquareKanbanIcon,
|
||||
SquarePenIcon,
|
||||
ThumbsUpIcon,
|
||||
WandSparklesIcon
|
||||
WandSparklesIcon,
|
||||
SquareCodeIcon,
|
||||
UsersIcon,
|
||||
FootprintsIcon,
|
||||
SplitSquareVerticalIcon,
|
||||
LogInIcon,
|
||||
UserPlusIcon
|
||||
} from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
@ -199,9 +205,9 @@ export function getMenuLinks(): NestedMenuItem[] {
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.pricing.title'),
|
||||
icon: <CircleDollarSignIcon className="site-4 shrink-0" />,
|
||||
href: Routes.PricingBlocks,
|
||||
title: t('Marketing.navbar.blocks.items.logo.title'),
|
||||
icon: <SquareCodeIcon className="site-4 shrink-0" />,
|
||||
href: Routes.LogoBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
@ -211,15 +217,9 @@ export function getMenuLinks(): NestedMenuItem[] {
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.faq.title'),
|
||||
icon: <CircleHelpIcon className="site-4 shrink-0" />,
|
||||
href: Routes.FAQBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.testimonials.title'),
|
||||
icon: <ThumbsUpIcon className="site-4 shrink-0" />,
|
||||
href: Routes.TestimonialsBlocks,
|
||||
title: t('Marketing.navbar.blocks.items.content.title'),
|
||||
icon: <NewspaperIcon className="site-4 shrink-0" />,
|
||||
href: Routes.ContentBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
@ -228,6 +228,18 @@ export function getMenuLinks(): NestedMenuItem[] {
|
||||
href: Routes.StatsBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.team.title'),
|
||||
icon: <UsersIcon className="site-4 shrink-0" />,
|
||||
href: Routes.TeamBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.testimonials.title'),
|
||||
icon: <ThumbsUpIcon className="site-4 shrink-0" />,
|
||||
href: Routes.TestimonialsBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.callToAction.title'),
|
||||
icon: <RocketIcon className="site-4 shrink-0" />,
|
||||
@ -235,9 +247,45 @@ export function getMenuLinks(): NestedMenuItem[] {
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.content.title'),
|
||||
icon: <NewspaperIcon className="site-4 shrink-0" />,
|
||||
href: Routes.ContentBlocks,
|
||||
title: t('Marketing.navbar.blocks.items.footer.title'),
|
||||
icon: <FootprintsIcon className="site-4 shrink-0" />,
|
||||
href: Routes.FooterBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.pricing.title'),
|
||||
icon: <CircleDollarSignIcon className="site-4 shrink-0" />,
|
||||
href: Routes.PricingBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.comparator.title'),
|
||||
icon: <SplitSquareVerticalIcon className="site-4 shrink-0" />,
|
||||
href: Routes.ComparatorBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.faq.title'),
|
||||
icon: <CircleHelpIcon className="site-4 shrink-0" />,
|
||||
href: Routes.FAQBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.login.title'),
|
||||
icon: <LogInIcon className="site-4 shrink-0" />,
|
||||
href: Routes.LoginBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.signup.title'),
|
||||
icon: <UserPlusIcon className="site-4 shrink-0" />,
|
||||
href: Routes.SignupBlocks,
|
||||
external: false,
|
||||
},
|
||||
{
|
||||
title: t('Marketing.navbar.blocks.items.contact.title'),
|
||||
icon: <MailIcon className="site-4 shrink-0" />,
|
||||
href: Routes.ContactBlocks,
|
||||
external: false,
|
||||
},
|
||||
],
|
||||
|
@ -38,14 +38,22 @@ export enum Routes {
|
||||
AIVideo = '/ai/video',
|
||||
AIAudio = '/ai/audio',
|
||||
|
||||
// Block routes
|
||||
HeroBlocks = '/blocks/hero-section',
|
||||
PricingBlocks = '/blocks/pricing',
|
||||
LogoBlocks = '/blocks/logo-cloud',
|
||||
FeaturesBlocks = '/blocks/features',
|
||||
FAQBlocks = '/blocks/faq',
|
||||
TestimonialsBlocks = '/blocks/testimonials',
|
||||
StatsBlocks = '/blocks/stats',
|
||||
CallToActionBlocks = '/blocks/call-to-action',
|
||||
ContentBlocks = '/blocks/content',
|
||||
StatsBlocks = '/blocks/stats',
|
||||
TeamBlocks = '/blocks/team',
|
||||
TestimonialsBlocks = '/blocks/testimonials',
|
||||
CallToActionBlocks = '/blocks/call-to-action',
|
||||
FooterBlocks = '/blocks/footer',
|
||||
PricingBlocks = '/blocks/pricing',
|
||||
ComparatorBlocks = '/blocks/comparator',
|
||||
FAQBlocks = '/blocks/faqs',
|
||||
LoginBlocks = '/blocks/login',
|
||||
SignupBlocks = '/blocks/signup',
|
||||
ContactBlocks = '/blocks/contact',
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user