feat: implement footer and brand logo components with internationalization support
This commit is contained in:
53
src/shared/components/brand-logo.tsx
Normal file
53
src/shared/components/brand-logo.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
|
||||
type BrandLogoProps = {
|
||||
href?: string;
|
||||
className?: string;
|
||||
iconClassName?: string;
|
||||
textClassName?: string;
|
||||
iconSize?: number;
|
||||
priority?: boolean;
|
||||
};
|
||||
|
||||
export function BrandLogo({
|
||||
href = "#",
|
||||
className = "",
|
||||
iconClassName = "",
|
||||
textClassName = "font-mono font-bold text-lg tracking-tight",
|
||||
iconSize = 36,
|
||||
priority = false,
|
||||
}: BrandLogoProps) {
|
||||
const [imageFailed, setImageFailed] = useState(false);
|
||||
|
||||
return (
|
||||
<a href={href} className={`flex items-center gap-2 group ${className}`.trim()}>
|
||||
<div
|
||||
className={`relative overflow-hidden rounded-lg bg-gradient-to-br from-accent to-purple-500 text-white shadow-lg shadow-accent/25 ${iconClassName}`.trim()}
|
||||
style={{ width: iconSize, height: iconSize }}
|
||||
>
|
||||
{imageFailed ? (
|
||||
<div className="flex h-full w-full items-center justify-center font-bold text-sm">
|
||||
S
|
||||
</div>
|
||||
) : (
|
||||
<Image
|
||||
src="/brand/icon.png"
|
||||
alt="Simanullang Dev logo"
|
||||
fill
|
||||
sizes={`${iconSize}px`}
|
||||
className="object-cover"
|
||||
priority={priority}
|
||||
onError={() => setImageFailed(true)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<span className={textClassName}>
|
||||
simanullang<span className="text-accent">.dev</span>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { GitFork, Link2, Mail, ArrowUp, Heart, MapPin } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { BrandLogo } from "@/shared/components/brand-logo";
|
||||
|
||||
const quickLinks = [
|
||||
{ href: "#experience", label: "Experience" },
|
||||
@@ -21,13 +22,8 @@ export function Footer() {
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
|
||||
{/* Brand & tagline */}
|
||||
<div className="md:col-span-1">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<div className="w-9 h-9 rounded-lg bg-gradient-to-br from-accent to-purple-500 flex items-center justify-center text-white font-bold text-sm shadow-lg shadow-accent/25">
|
||||
A
|
||||
</div>
|
||||
<span className="font-mono font-bold text-lg tracking-tight">
|
||||
ando<span className="text-accent">.dev</span>
|
||||
</span>
|
||||
<div className="mb-4">
|
||||
<BrandLogo />
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed mb-4 max-w-xs">
|
||||
{t("description")}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState, useEffect, useTransition } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { Menu, X, Languages } from "lucide-react";
|
||||
import { ThemeToggle } from "@/shared/components/theme-toggle";
|
||||
import { BrandLogo } from "@/shared/components/brand-logo";
|
||||
import { useTranslations, useLocale } from "next-intl";
|
||||
import { usePathname, useRouter } from "@/i18n/routing";
|
||||
|
||||
@@ -72,15 +73,10 @@ export function Navbar() {
|
||||
}`}
|
||||
>
|
||||
<nav className="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
||||
{/* #12 Logo with hover glow */}
|
||||
<a href="#" className="flex items-center gap-2 group">
|
||||
<div className="w-9 h-9 rounded-lg bg-gradient-to-br from-accent to-purple-500 flex items-center justify-center text-white font-bold text-sm shadow-lg shadow-accent/25 group-hover:shadow-accent/50 group-hover:scale-110 transition-all duration-300">
|
||||
A
|
||||
</div>
|
||||
<span className="font-mono font-bold text-lg tracking-tight">
|
||||
ando<span className="text-accent">.dev</span>
|
||||
</span>
|
||||
</a>
|
||||
<BrandLogo
|
||||
priority
|
||||
iconClassName="group-hover:shadow-accent/50 group-hover:scale-110 transition-all duration-300"
|
||||
/>
|
||||
|
||||
{/* Desktop Nav with scroll spy */}
|
||||
<div className="hidden md:flex items-center gap-1">
|
||||
|
||||
Reference in New Issue
Block a user