From 3fcef3f0251162b941a472ff2e575cfa1d144010 Mon Sep 17 00:00:00 2001 From: Wisdom Date: Thu, 29 Aug 2024 17:49:32 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=B2=20feat:=20update=20hero=20advanced?= =?UTF-8?q?=20(#35)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 118 ++++++++++++++++++++++++ src/components/HomepageHero/Section.tsx | 18 +++- src/components/HomepageHero/index.tsx | 54 ++++++++++- src/components/MotionWrapper/Flash.tsx | 14 ++- src/components/ui/accordion.tsx | 63 +++++++++++++ src/components/ui/card-hover-effect.tsx | 30 +++++- src/i18n/en.ts | 49 +++++++++- src/i18n/zh.ts | 50 +++++++++- 9 files changed, 381 insertions(+), 16 deletions(-) create mode 100644 src/components/ui/accordion.tsx diff --git a/package.json b/package.json index 4f9d621..8b43d68 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "@emotion/react": "^11.13.0", "@emotion/styled": "^11.13.0", + "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-hover-card": "^1.1.1", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b7950b..fe0980a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@emotion/styled': specifier: ^11.13.0 version: 11.13.0(@emotion/react@11.13.0(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-accordion': + specifier: ^1.2.0 + version: 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-hover-card': specifier: ^1.1.1 version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -633,6 +636,19 @@ packages: '@radix-ui/primitive@1.1.0': resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + '@radix-ui/react-accordion@1.2.0': + resolution: {integrity: sha512-HJOzSX8dQqtsp/3jVxCU3CXEONF7/2jlGAB28oX8TTw1Dz8JYbEI1UcL8355PuLBE41/IRRMvCw7VkiK/jcUOQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-arrow@1.1.0': resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} peerDependencies: @@ -646,6 +662,32 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collapsible@1.1.0': + resolution: {integrity: sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.0': + resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-compose-refs@1.1.0': resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: @@ -664,6 +706,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-direction@1.1.0': + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dismissable-layer@1.1.0': resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} peerDependencies: @@ -690,6 +741,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-popper@1.2.0': resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} peerDependencies: @@ -4929,6 +4989,23 @@ snapshots: '@radix-ui/primitive@1.1.0': {} + '@radix-ui/react-accordion@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collapsible': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -4938,6 +5015,34 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-collapsible@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + + '@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.3)(react@18.3.1)': dependencies: react: 18.3.1 @@ -4950,6 +5055,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + '@radix-ui/react-direction@1.1.0(@types/react@18.3.3)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -4980,6 +5091,13 @@ snapshots: '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + '@radix-ui/react-id@1.1.0(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) diff --git a/src/components/HomepageHero/Section.tsx b/src/components/HomepageHero/Section.tsx index 2ecee26..d7928ba 100644 --- a/src/components/HomepageHero/Section.tsx +++ b/src/components/HomepageHero/Section.tsx @@ -4,20 +4,33 @@ import { MotionWrapperFadeIn, MotionWrapperFlash } from '@/components/MotionWrap interface Props { title?: string + titleProps?: Partial> description?: string children?: ReactNode className?: string + tallPaddingY?: boolean } export const Section = (props: Props) => { - const { className, title, description, children } = props + const { + className, + titleProps, + title, + description, + children, + tallPaddingY = false, + } = props return (
- +

{ 'text-3xl md:text-5xl md:leading-tight pt-4', 'from-neutral-700 to-black', 'dark:from-neutral-800 dark:to-white', + `${tallPaddingY ? 'pt-20 pb-10' : ''}`, )} > { title } diff --git a/src/components/HomepageHero/index.tsx b/src/components/HomepageHero/index.tsx index 437f8ee..6412b9a 100644 --- a/src/components/HomepageHero/index.tsx +++ b/src/components/HomepageHero/index.tsx @@ -1,5 +1,7 @@ import Marquee from 'react-fast-marquee' import { useTheme } from 'nextra-theme-docs' +import { useMemo } from 'react' +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '../ui/accordion' import { SetupHero } from './Setup' import { Section } from './Section' import { HoverEffect } from '@/components/ui/card-hover-effect' @@ -29,9 +31,30 @@ export default function HomepageHero() { const { t } = useLocale() const featureList = t('featureList') + const faqs = t('faqs') const { resolvedTheme } = useTheme() + const processedFeatureList = useMemo(() => { + const icons = [ + 'icon-[material-symbols--rocket-launch-outline]', + 'icon-[icon-park-outline--international]', + 'icon-[nonicons--typescript-16]', + 'icon-[carbon--face-satisfied] hover:icon-[carbon--face-wink]', + 'icon-[teenyicons--tailwind-outline]', + 'icon-[tabler--calendar-code]', + 'icon-[carbon--color-palette]', + 'icon-[carbon--ibm-cloud-transit-gateway]', + 'icon-[carbon--flash]', + ] + return featureList.map((item, index) => { + return { + ...item, + icon: , + } + }) + }, [featureList]) + return ( <> @@ -53,6 +76,9 @@ export default function HomepageHero() {
- +
+
+ + { + faqs.map((faqItem, index) => ( + + {faqItem.question} + + {faqItem.answer} + + + )) + } + +
) diff --git a/src/components/MotionWrapper/Flash.tsx b/src/components/MotionWrapper/Flash.tsx index f503323..a8bdf4a 100644 --- a/src/components/MotionWrapper/Flash.tsx +++ b/src/components/MotionWrapper/Flash.tsx @@ -3,17 +3,29 @@ import { motion } from 'framer-motion' interface Props { className?: string + disabledAnimation?: boolean disabledHover?: boolean children: ReactNode } export const MotionWrapperFlash: React.FC = (props) => { - const { disabledHover = false, children, className } = props + const { + disabledAnimation = true, + disabledHover = false, + children, + className, + } = props + + if (disabledAnimation) { + return children + } + return ( , + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AccordionItem.displayName = 'AccordionItem' + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180', + 'text-[18px] font-bold', + className, + )} + {...props} + > + {children} + + + +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)) + +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/components/ui/card-hover-effect.tsx b/src/components/ui/card-hover-effect.tsx index 5802ae0..2f79a91 100644 --- a/src/components/ui/card-hover-effect.tsx +++ b/src/components/ui/card-hover-effect.tsx @@ -1,5 +1,6 @@ import { AnimatePresence, motion } from 'framer-motion' import Link from 'next/link' +import type { ReactNode } from 'react' import { useState } from 'react' import { cn } from '@/lib/utils' @@ -18,7 +19,7 @@ export const Card = ({ 'border duration-200', 'bg-neutral-50 dark:bg-neutral-800', 'border-neutral-200/[0.5] dark:border-white/[0.1]', - 'group-hover:border-neutral-300/[0.6] dark:group-hover:border-white/[0.3]', + 'group-hover:border-neutral-300/[0.6] dark:group-hover:border-primary/[0.8]', className, )} > @@ -28,6 +29,30 @@ export const Card = ({ ) } + +export const CardIcon = ({ + className, + children, +}: { + className?: string + children?: React.ReactNode +}) => { + return ( +
+ {children} +
+ ) +} export const CardTitle = ({ className, children, @@ -46,6 +71,7 @@ export const CardTitle = ({ ) } + export const CardDescription = ({ className, children, @@ -74,6 +100,7 @@ export const HoverEffect = ({ title: string description: string link?: string + icon: ReactNode }[] className?: string }) => { @@ -111,6 +138,7 @@ export const HoverEffect = ({ )} + {item.icon} {item.title} {item.description} diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 30f31e0..5d3b81e 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -10,20 +10,32 @@ export default { featureList: [ { title: 'Advanced Tech Stack', - description: 'Leveraging efficient React frameworks and type-safe support with Next.js, TypeScript, and Shadcn UI to build modern applications.', + description: 'Leveraging efficient React frameworks and support with Next.js, and Shadcn UI to build modern applications.', }, { - title: 'Tailwind CSS & Iconify Icons', - description: 'Atomic CSS integrated with Tailwind CSS and Iconify icons, enabling efficient design and responsive UI.', + title: 'internationalization (i18n)', + description: 'Built-in multi-language support for easy i18n of your application, expanding your user base.', }, { - title: 'Dark Mode', - description: 'Supports dark mode for an enhanced nighttime experience.', + title: 'TypeScript Safety', + description: 'Fully integrated with TypeScript, offering static type checking to reduce runtime errors and enhance code reliability and maintainability.', + }, + { + title: 'Iconify Icons', + description: 'Integrated with the Iconify icon set, offering a wide range of icons to enhance UI visual presentation.', + }, + { + title: 'Tailwind CSS', + description: 'Atomic CSS integrated with Tailwind CSS, enabling efficient design and responsive UI.', }, { title: 'Code Standards', description: 'Adheres to best practices with code standards and uses ESLint for quality checks and consistency.', }, + { + title: 'Dark Mode', + description: 'Supports dark mode for an enhanced nighttime experience.', + }, { title: 'Rich Components & Extensible Support', description: 'Offers a range of built-in components and supports flexible custom extensions.', @@ -33,5 +45,32 @@ export default { description: 'Employs a lightweight design approach, streamlining project setup to focus on content creation.', }, ], + featuresDesc: 'Easily build modern applications and kickstart your development process.', + faqs: [ + { + question: 'What frameworks and tech stack does this starter template support?', + answer: 'This starter template supports Next.js and Nextra, with integrated modern development technologies like Tailwind CSS, Framer Motion, and Shadcn UI components.', + }, + { + question: 'How do I start developing with this template?', + answer: 'Simply clone our GitHub repository and follow the steps in the documentation to run the installation commands to get started.', + }, + { + question: 'What types of projects is this template suitable for?', + answer: 'This template is ideal for building fast and efficient modern web applications, including corporate sites, personal blogs, and e-commerce platforms.', + }, + { + question: 'How do I add or modify components in the project?', + answer: 'You can use the provided component library and follow the instructions in the documentation to customize and extend them to suit your specific needs.', + }, + { + question: 'Does the template support multiple languages?', + answer: 'Yes, the template includes built-in internationalization (i18n) support, allowing you to easily add and manage multilingual content to expand your app\'s international user base.', + }, + { + question: 'How can I get technical support or help?', + answer: 'If you encounter any issues while using the template, please contact us via GitHub @pdsuwwz.', + }, + ], } diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index f72462d..a464fd8 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -10,20 +10,32 @@ export default { featureList: [ { title: '先进的技术栈', - description: '高效的 React 框架和类型安全支持,使用 Next.js、TypeScript、TypeScript、和 Shadcn UI 打造现代化应用', + description: '高效的 React 框架,使用 Next.js、和 Shadcn UI 打造现代化应用', }, { - title: 'Tailwind CSS & Iconify 图标集', - description: '原子化 CSS, 集成 Tailwind CSS 和 Iconify 图标集,轻松实现高效设计、响应式界面 UI', + title: '国际化支持 (i18n)', + description: '内置多语言支持,轻松实现应用的国际化,扩大用户群体', }, { - title: '暗黑模式', - description: '支持暗黑模式,提供更好的夜间使用体验', + title: 'TypeScript 类型安全', + description: '全面集成 TypeScript,提供静态类型检查,减少运行时错误,提高代码可靠性和可维护性', + }, + { + title: 'Iconify 图标集', + description: '纯 CSS 图标, 集成 Iconify 图标集,提供丰富的图标选择,增强 UI 视觉表现', + }, + { + title: 'Tailwind CSS', + description: '使用原子化 CSS 框架 Tailwind CSS,快速构建高效设计、响应式界面 UI', }, { title: '代码规范', description: '遵循最佳实践的代码规范,结合 ESLint 进行代码质量检查与一致性维护', }, + { + title: '暗黑模式', + description: '支持暗黑模式,提供更好的夜间使用体验', + }, { title: '丰富组件 & 支持自由扩展', description: '提供丰富的预置组件,并支持灵活的自定义扩展', @@ -33,4 +45,32 @@ export default { description: '采用轻量化设计,精简项目设置,专注于内容编写', }, ], + featuresDesc: '轻松构建现代应用,快速启动您的开发流程', + faqs: [ + { + question: '这个启动模板支持哪些框架和技术栈?', + answer: '本启动模板支持 Next.js 和 Nextra,并集成了 Tailwind CSS、Framer Motion、Shadcn UI 组件等现代开发技术栈。', + }, + { + question: '我如何开始使用这个模板进行开发?', + answer: '只需克隆我们的 GitHub 仓库并按照文档中的步骤运行安装命令,即可开始使用本模板进行开发。', + }, + { + question: '这个模板适合哪些类型的项目?', + answer: '该模板适合用于创建快速、高效的现代 Web 应用程序,包括企业站点、个人博客、电子商务平台等。', + }, + { + question: '如何添加或修改项目中的组件?', + answer: '可以使用提供的组件库,按照文档中的说明进行自定义和扩展,以适应您的具体需求。', + }, + { + question: '模板是否提供多语言支持?', + answer: '是的,模板内置国际化 (i18n) 功能,可以轻松添加和管理多语言内容,扩大应用的国际用户群。', + }, + { + question: '如何获得技术支持或帮助?', + answer: '如果在使用过程中遇到问题,请通过 GitHub @pdsuwwz 与我们联系。', + }, + ], + }