-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add dark mode theme system with smooth transition #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,45 +1,49 @@ | ||||||
| import Link from "next/link"; | ||||||
| import Image from "next/image"; | ||||||
| import { Button } from "@/components/common/ui/button"; | ||||||
| import { ThemeToggle } from "@/components/common/theme-toggle"; | ||||||
|
|
||||||
| export default function HomePage(): React.ReactElement { | ||||||
| return ( | ||||||
| <div className="min-h-screen bg-linear-to-b from-slate-50 to-white"> | ||||||
| <div className="min-h-screen bg-linear-to-b from-slate-50 to-white dark:from-gray-950 dark:to-gray-900"> | ||||||
| {/* Header */} | ||||||
| <header className="border-b border-slate-200 bg-white/80 backdrop-blur-sm"> | ||||||
| <header className="border-b border-slate-200 bg-white/80 backdrop-blur-sm dark:border-gray-800 dark:bg-gray-950/80"> | ||||||
| <div className="mx-auto max-w-7xl px-6 py-4"> | ||||||
| <div className="flex items-center justify-between"> | ||||||
| <div className="flex items-center gap-2"> | ||||||
| <div className="flex h-9 w-9 items-center justify-center rounded-lg bg-linear-to-br from-blue-600 to-indigo-600"> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Syntax Error: Replace
Suggested change
|
||||||
| <span className="text-lg font-bold text-white">N</span> | ||||||
| </div> | ||||||
| <span className="text-lg font-semibold text-slate-900"> | ||||||
| <span className="text-lg font-semibold text-slate-900 dark:text-white"> | ||||||
| NextApp | ||||||
| </span> | ||||||
| </div> | ||||||
| <nav className="hidden gap-8 md:flex"> | ||||||
| <Link | ||||||
| href="/" | ||||||
| className="text-sm font-medium text-slate-700 hover:text-blue-600" | ||||||
| className="text-sm font-medium text-slate-700 hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-400" | ||||||
| > | ||||||
| Trang chủ | ||||||
| </Link> | ||||||
| <Link | ||||||
| href="/about" | ||||||
| className="text-sm font-medium text-slate-700 hover:text-blue-600" | ||||||
| className="text-sm font-medium text-slate-700 hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-400" | ||||||
| > | ||||||
| Giới thiệu | ||||||
| </Link> | ||||||
| <Link | ||||||
| href="/contact" | ||||||
| className="text-sm font-medium text-slate-700 hover:text-blue-600" | ||||||
| className="text-sm font-medium text-slate-700 hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-400" | ||||||
| > | ||||||
| Liên hệ | ||||||
| </Link> | ||||||
| </nav> | ||||||
| <Button size="sm" className="bg-blue-600 hover:bg-blue-700"> | ||||||
| Đăng nhập | ||||||
| </Button> | ||||||
| <div className="flex items-center gap-3"> | ||||||
| <ThemeToggle /> | ||||||
| <Button size="sm" className="bg-blue-600 hover:bg-blue-700"> | ||||||
| Đăng nhập | ||||||
| </Button> | ||||||
| </div> | ||||||
| </div> | ||||||
| </div> | ||||||
| </header> | ||||||
|
|
@@ -48,21 +52,21 @@ export default function HomePage(): React.ReactElement { | |||||
| <section className="mx-auto max-w-7xl px-6 py-20 md:py-32"> | ||||||
| <div className="grid gap-12 lg:grid-cols-2 lg:gap-16"> | ||||||
| <div className="flex flex-col justify-center"> | ||||||
| <div className="mb-4 inline-flex w-fit items-center gap-2 rounded-full bg-blue-50 px-4 py-1.5 text-sm font-medium text-blue-700"> | ||||||
| <div className="mb-4 inline-flex w-fit items-center gap-2 rounded-full bg-blue-50 px-4 py-1.5 text-sm font-medium text-blue-700 dark:bg-blue-950 dark:text-blue-300"> | ||||||
| <span className="relative flex h-2 w-2"> | ||||||
| <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-400 opacity-75"></span> | ||||||
| <span className="relative inline-flex h-2 w-2 rounded-full bg-blue-500"></span> | ||||||
| </span> | ||||||
| Mới ra mắt | ||||||
| </div> | ||||||
| <h1 className="mb-6 text-5xl font-bold leading-tight text-slate-900 md:text-6xl"> | ||||||
| <h1 className="mb-6 text-5xl font-bold leading-tight text-slate-900 dark:text-white md:text-6xl"> | ||||||
| Xây dựng sản phẩm | ||||||
| <br /> | ||||||
| <span className="bg-linear-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent"> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Syntax Error: Replace
Suggested change
|
||||||
| nhanh hơn, tốt hơn | ||||||
| </span> | ||||||
| </h1> | ||||||
| <p className="mb-8 text-lg leading-relaxed text-slate-600"> | ||||||
| <p className="mb-8 text-lg leading-relaxed text-slate-600 dark:text-gray-400"> | ||||||
| Nền tảng giúp bạn tập trung vào những gì quan trọng nhất. Đơn | ||||||
| giản, hiệu quả và dễ sử dụng cho mọi dự án. | ||||||
| </p> | ||||||
|
|
@@ -73,15 +77,15 @@ export default function HomePage(): React.ReactElement { | |||||
| <Button | ||||||
| variant="outline" | ||||||
| size="lg" | ||||||
| className="border-slate-600 text-slate-600" | ||||||
| className="border-slate-600 text-slate-600 dark:border-gray-600 dark:text-gray-300" | ||||||
| > | ||||||
| Xem demo | ||||||
| </Button> | ||||||
| </div> | ||||||
| </div> | ||||||
| <div className="relative"> | ||||||
| <div className="absolute -inset-4 rounded-3xl bg-linear-to-r from-blue-100 to-indigo-100 opacity-50 blur-2xl" /> | ||||||
| <div className="relative overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-xl"> | ||||||
| <div className="absolute -inset-4 rounded-3xl bg-linear-to-r from-blue-100 to-indigo-100 opacity-50 blur-2xl dark:from-blue-900 dark:to-indigo-900" /> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Syntax Error: Replace
Suggested change
|
||||||
| <div className="relative overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-xl dark:border-gray-700 dark:bg-gray-800"> | ||||||
| <Image | ||||||
| src="https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&h=600&fit=crop" | ||||||
| alt="Dashboard preview" | ||||||
|
|
@@ -96,13 +100,15 @@ export default function HomePage(): React.ReactElement { | |||||
| </section> | ||||||
|
|
||||||
| {/* Features */} | ||||||
| <section className="border-y border-slate-200 bg-white py-20 md:py-24"> | ||||||
| <section className="border-y border-slate-200 bg-white py-20 md:py-24 dark:border-gray-800 dark:bg-gray-900"> | ||||||
| <div className="mx-auto max-w-7xl px-6"> | ||||||
| <div className="mb-16 text-center"> | ||||||
| <h2 className="mb-4 text-3xl font-bold text-slate-900 md:text-4xl"> | ||||||
| <h2 className="mb-4 text-3xl font-bold text-slate-900 md:text-4xl dark:text-white"> | ||||||
| Tính năng nổi bật | ||||||
| </h2> | ||||||
| <p className="text-lg text-slate-600">Mọi thứ bạn cần để bắt đầu</p> | ||||||
| <p className="text-lg text-slate-600 dark:text-gray-400"> | ||||||
| Mọi thứ bạn cần để bắt đầu | ||||||
| </p> | ||||||
| </div> | ||||||
| <div className="grid gap-8 md:grid-cols-3"> | ||||||
| {[ | ||||||
|
|
@@ -127,17 +133,19 @@ export default function HomePage(): React.ReactElement { | |||||
| ].map((feature, i) => ( | ||||||
| <div | ||||||
| key={i} | ||||||
| className="group rounded-2xl border border-slate-200 bg-linear-to-br from-slate-50 to-white p-8 transition-all hover:border-slate-300 hover:shadow-lg" | ||||||
| className="group rounded-2xl border border-slate-200 bg-linear-to-br from-slate-50 to-white p-8 transition-all hover:border-slate-300 hover:shadow-lg dark:border-gray-700 dark:from-gray-800 dark:to-gray-900 dark:hover:border-gray-600" | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Syntax Error: Replace
Suggested change
|
||||||
| > | ||||||
| <div | ||||||
| className={`mb-4 flex h-14 w-14 items-center justify-center rounded-xl bg-linear-to-br ${feature.color} text-3xl shadow-lg`} | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Syntax Error: Replace
Suggested change
|
||||||
| > | ||||||
| {feature.icon} | ||||||
| </div> | ||||||
| <h3 className="mb-3 text-xl font-semibold text-slate-900"> | ||||||
| <h3 className="mb-3 text-xl font-semibold text-slate-900 dark:text-white"> | ||||||
| {feature.title} | ||||||
| </h3> | ||||||
| <p className="text-slate-600">{feature.desc}</p> | ||||||
| <p className="text-slate-600 dark:text-gray-400"> | ||||||
| {feature.desc} | ||||||
| </p> | ||||||
| </div> | ||||||
| ))} | ||||||
| </div> | ||||||
|
|
@@ -155,21 +163,23 @@ export default function HomePage(): React.ReactElement { | |||||
| ].map((stat, i) => ( | ||||||
| <div | ||||||
| key={i} | ||||||
| className="rounded-2xl border border-slate-200 bg-white p-8 text-center shadow-sm" | ||||||
| className="rounded-2xl border border-slate-200 bg-white p-8 text-center shadow-sm dark:border-gray-700 dark:bg-gray-800" | ||||||
| > | ||||||
| <div className="mb-3 text-4xl">{stat.icon}</div> | ||||||
| <div className="mb-2 text-4xl font-bold text-slate-900"> | ||||||
| <div className="mb-2 text-4xl font-bold text-slate-900 dark:text-white"> | ||||||
| {stat.value} | ||||||
| </div> | ||||||
| <div className="text-slate-600">{stat.label}</div> | ||||||
| <div className="text-slate-600 dark:text-gray-400"> | ||||||
| {stat.label} | ||||||
| </div> | ||||||
| </div> | ||||||
| ))} | ||||||
| </div> | ||||||
| </div> | ||||||
| </section> | ||||||
|
|
||||||
| {/* CTA */} | ||||||
| <section className="border-y border-slate-200 bg-linear-to-br from-blue-600 to-indigo-600 py-20 md:py-24"> | ||||||
| <section className="border-y border-slate-200 bg-linear-to-br from-blue-600 to-indigo-600 py-20 md:py-24 dark:border-gray-800"> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛑 Syntax Error: Replace
Suggested change
|
||||||
| <div className="mx-auto max-w-3xl px-6 text-center"> | ||||||
| <h2 className="mb-4 text-3xl font-bold text-white md:text-4xl"> | ||||||
| Sẵn sàng bắt đầu? | ||||||
|
|
@@ -185,19 +195,19 @@ export default function HomePage(): React.ReactElement { | |||||
| </section> | ||||||
|
|
||||||
| {/* Footer */} | ||||||
| <footer className="border-t border-slate-200 bg-slate-50 py-12"> | ||||||
| <footer className="border-t border-slate-200 bg-slate-50 py-12 dark:border-gray-800 dark:bg-gray-900"> | ||||||
| <div className="mx-auto max-w-7xl px-6"> | ||||||
| <div className="grid gap-8 md:grid-cols-4"> | ||||||
| <div> | ||||||
| <div className="mb-4 flex items-center gap-2"> | ||||||
| <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-linear-to-br from-blue-600 to-indigo-600"> | ||||||
| <span className="text-sm font-bold text-white">N</span> | ||||||
| </div> | ||||||
| <span className="text-lg font-semibold text-slate-900"> | ||||||
| <span className="text-lg font-semibold text-slate-900 dark:text-white"> | ||||||
| NextApp | ||||||
| </span> | ||||||
| </div> | ||||||
| <p className="text-sm text-slate-600"> | ||||||
| <p className="text-sm text-slate-600 dark:text-gray-400"> | ||||||
| Xây dựng sản phẩm tốt hơn mỗi ngày | ||||||
| </p> | ||||||
| </div> | ||||||
|
|
@@ -210,15 +220,15 @@ export default function HomePage(): React.ReactElement { | |||||
| { title: "Hỗ trợ", links: ["Trợ giúp", "Liên hệ", "Điều khoản"] }, | ||||||
| ].map((col, i) => ( | ||||||
| <div key={i}> | ||||||
| <div className="mb-4 text-sm font-semibold text-slate-900"> | ||||||
| <div className="mb-4 text-sm font-semibold text-slate-900 dark:text-white"> | ||||||
| {col.title} | ||||||
| </div> | ||||||
| <ul className="space-y-2"> | ||||||
| {col.links.map((link, j) => ( | ||||||
| <li key={j}> | ||||||
| <Link | ||||||
| href="/" | ||||||
| className="text-sm text-slate-600 hover:text-blue-600" | ||||||
| className="text-sm text-slate-600 hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-400" | ||||||
| > | ||||||
| {link} | ||||||
| </Link> | ||||||
|
|
@@ -228,7 +238,7 @@ export default function HomePage(): React.ReactElement { | |||||
| </div> | ||||||
| ))} | ||||||
| </div> | ||||||
| <div className="mt-12 border-t border-slate-200 pt-8 text-center text-sm text-slate-600"> | ||||||
| <div className="mt-12 border-t border-slate-200 pt-8 text-center text-sm text-slate-600 dark:border-gray-800 dark:text-gray-400"> | ||||||
| © 2024 NextApp. All rights reserved. | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| "use client"; | ||
|
|
||
| import { ThemeProvider as NextThemesProvider } from "next-themes"; | ||
| import type { ThemeProviderProps } from "next-themes"; | ||
|
|
||
| export function ThemeProvider({ children, ...props }: ThemeProviderProps) { | ||
| return <NextThemesProvider {...props}>{children}</NextThemesProvider>; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| "use client"; | ||
|
|
||
| import { useTheme } from "next-themes"; | ||
| import { Sun, Moon } from "lucide-react"; | ||
| import { useMounted } from "@/hooks"; | ||
|
|
||
| export function ThemeToggle() { | ||
| const { resolvedTheme, setTheme } = useTheme(); | ||
| const mounted = useMounted(); | ||
|
|
||
| const isDark = mounted && resolvedTheme === "dark"; | ||
|
|
||
| return ( | ||
| <button | ||
| onClick={() => setTheme(isDark ? "light" : "dark")} | ||
| className="relative flex items-center justify-center rounded-full h-11 w-11 border border-gray-200 bg-white text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 cursor-pointer" | ||
| aria-label="Toggle theme" | ||
| > | ||
| <Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> | ||
| <Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> | ||
| </button> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛑 Syntax Error: Replace
bg-linear-to-bwithbg-gradient-to-b. The current class name is invalid Tailwind CSS syntax and will not render any background gradient.