feat: enhance footer with social links and horizontal mode toggle

This commit is contained in:
javayhu 2025-02-28 23:37:21 +08:00
parent c83bd1ca6a
commit 28f4fc8880
4 changed files with 149 additions and 74 deletions

View File

@ -10,6 +10,8 @@ import type * as React from "react";
import Container from "@/components/container";
import { Logo } from "@/components/logo";
import BuiltWithButton from "@/components/shared/built-with-button";
import { ModeToggleHorizontal } from "@/components/layout/mode-toggle-horizontal";
import { ModeToggle } from "./mode-toggle";
export function Footer({ className }: React.HTMLAttributes<HTMLElement>) {
const { theme } = useTheme();
@ -29,8 +31,80 @@ export function Footer({ className }: React.HTMLAttributes<HTMLElement>) {
<p className="text-muted-foreground text-base p4-4 md:pr-12">
{siteConfig.tagline}
</p>
<BuiltWithButton />
{/* social links */}
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
{siteConfig.links.github && (
<Link
href={siteConfig.links.github}
target="_blank"
rel="noreferrer"
aria-label="GitHub"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.github className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.twitter && (
<Link
href={siteConfig.links.twitter}
target="_blank"
rel="noreferrer"
aria-label="Twitter"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.twitter className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.twitter_cn && (
<Link
href={siteConfig.links.twitter_cn}
target="_blank"
rel="noreferrer"
aria-label="Twitter(CN)"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.twitter className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.bluesky && (
<Link
href={siteConfig.links.bluesky}
target="_blank"
rel="noreferrer"
aria-label="Bluesky"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.bluesky className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.youtube && (
<Link
href={siteConfig.links.youtube}
target="_blank"
rel="noreferrer"
aria-label="YouTube"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.youtube className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.mail && (
<Link
href={`mailto:${siteConfig.mail}`}
target="_blank"
rel="noreferrer"
aria-label="Email"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.email className="size-4" aria-hidden="true" />
</Link>
)}
</div>
</div>
</div>
</div>
@ -69,76 +143,7 @@ export function Footer({ className }: React.HTMLAttributes<HTMLElement>) {
&copy; {new Date().getFullYear()} All Rights Reserved.
</span>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
{siteConfig.links.github && (
<Link
href={siteConfig.links.github}
target="_blank"
rel="noreferrer"
aria-label="GitHub"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.github className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.twitter && (
<Link
href={siteConfig.links.twitter}
target="_blank"
rel="noreferrer"
aria-label="Twitter"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.twitter className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.twitter_cn && (
<Link
href={siteConfig.links.twitter_cn}
target="_blank"
rel="noreferrer"
aria-label="Twitter(CN)"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.twitter className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.bluesky && (
<Link
href={siteConfig.links.bluesky}
target="_blank"
rel="noreferrer"
aria-label="Bluesky"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.bluesky className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.links.youtube && (
<Link
href={siteConfig.links.youtube}
target="_blank"
rel="noreferrer"
aria-label="YouTube"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.youtube className="size-4" aria-hidden="true" />
</Link>
)}
{siteConfig.mail && (
<Link
href={`mailto:${siteConfig.mail}`}
target="_blank"
rel="noreferrer"
aria-label="Email"
className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent hover:text-accent-foreground"
>
<Icons.email className="size-4" aria-hidden="true" />
</Link>
)}
</div>
</div>
<ModeToggleHorizontal />
</Container>
</div>
</footer>

View File

@ -0,0 +1,70 @@
"use client";
import { Button } from "@/components/ui/button";
import { LaptopIcon, MoonIcon, SunIcon } from "lucide-react";
import { useTheme } from "next-themes";
import { cn } from "@/lib/utils";
import { useEffect, useState } from "react";
export function ModeToggleHorizontal() {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
// Only show the UI after hydration to prevent hydration mismatch
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return (
<div className="flex items-center gap-2 rounded-full border bg-background p-1">
<div className="size-6 px-0 rounded-full" />
<div className="size-6 px-0 rounded-full" />
<div className="size-6 px-0 rounded-full" />
</div>
);
}
return (
<div className="flex items-center gap-2 rounded-full border bg-background p-1">
<Button
variant="ghost"
size="icon"
className={cn(
"size-6 px-0 rounded-full",
theme === "light" && "bg-muted text-foreground"
)}
onClick={() => setTheme("light")}
aria-label="Light mode"
>
<SunIcon className="size-4" />
</Button>
<Button
variant="ghost"
size="icon"
className={cn(
"size-6 px-0 rounded-full",
theme === "dark" && "bg-muted text-foreground"
)}
onClick={() => setTheme("dark")}
aria-label="Dark mode"
>
<MoonIcon className="size-4" />
</Button>
<Button
variant="ghost"
size="icon"
className={cn(
"size-6 px-0 rounded-full",
theme === "system" && "bg-muted text-foreground"
)}
onClick={() => setTheme("system")}
aria-label="System mode"
>
<LaptopIcon className="size-4" />
</Button>
</div>
);
}

View File

@ -28,7 +28,7 @@ import { authClient } from "@/lib/auth-client";
export function UserButton() {
const { data: session, error } = authClient.useSession();
const user = session?.user;
console.log('UserButton, user:', user);
// console.log('UserButton, user:', user);
// if (error) {
// console.error("UserButton, error:", error);
// return (

View File

@ -23,8 +23,8 @@ export const siteConfig: SiteConfig = {
links: {
twitter: "https://x.com/javay_hu",
bluesky: "https://bsky.app/profile/javayhu.com",
github: "https://github.com/MkSaaS",
youtube: "https://www.youtube.com/@MkSaaS",
github: "https://github.com/MkSaaSHQ",
youtube: "https://www.youtube.com/@MkSaaSHQ",
docs: "https://docs.mksaas.com",
demo: "https://demo.mksaas.com",
studio: "https://demo.mksaas.com/studio",