feat: implement footer and brand logo components with internationalization support
This commit is contained in:
@@ -163,6 +163,6 @@
|
|||||||
"quickLinksTitle": "Quick Links",
|
"quickLinksTitle": "Quick Links",
|
||||||
"connectTitle": "Connect",
|
"connectTitle": "Connect",
|
||||||
"backToTop": "Back to top",
|
"backToTop": "Back to top",
|
||||||
"copyright": "Yolando. All Rights Reserved."
|
"copyright": "Simanullang Dev. All Rights Reserved."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,6 +163,6 @@
|
|||||||
"quickLinksTitle": "Tautan Cepat",
|
"quickLinksTitle": "Tautan Cepat",
|
||||||
"connectTitle": "Terhubung",
|
"connectTitle": "Terhubung",
|
||||||
"backToTop": "Kembali ke atas",
|
"backToTop": "Kembali ke atas",
|
||||||
"copyright": "Yolando. Semua Hak Cipta Dilindungi."
|
"copyright": "Simanullang Dev. Semua Hak Cipta Dilindungi."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
public/brand/.gitkeep
Normal file
1
public/brand/.gitkeep
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
BIN
public/brand/icon.png
Normal file
BIN
public/brand/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 444 KiB |
BIN
public/uploads/1775219874524-graphic_Fitures.jpg
Normal file
BIN
public/uploads/1775219874524-graphic_Fitures.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 232 KiB |
BIN
public/uploads/1775219874526-Group_13.png
Normal file
BIN
public/uploads/1775219874526-Group_13.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
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 { GitFork, Link2, Mail, ArrowUp, Heart, MapPin } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import { BrandLogo } from "@/shared/components/brand-logo";
|
||||||
|
|
||||||
const quickLinks = [
|
const quickLinks = [
|
||||||
{ href: "#experience", label: "Experience" },
|
{ href: "#experience", label: "Experience" },
|
||||||
@@ -21,13 +22,8 @@ export function Footer() {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
|
||||||
{/* Brand & tagline */}
|
{/* Brand & tagline */}
|
||||||
<div className="md:col-span-1">
|
<div className="md:col-span-1">
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="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">
|
<BrandLogo />
|
||||||
A
|
|
||||||
</div>
|
|
||||||
<span className="font-mono font-bold text-lg tracking-tight">
|
|
||||||
ando<span className="text-accent">.dev</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground leading-relaxed mb-4 max-w-xs">
|
<p className="text-sm text-muted-foreground leading-relaxed mb-4 max-w-xs">
|
||||||
{t("description")}
|
{t("description")}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useState, useEffect, useTransition } from "react";
|
|||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { Menu, X, Languages } from "lucide-react";
|
import { Menu, X, Languages } from "lucide-react";
|
||||||
import { ThemeToggle } from "@/shared/components/theme-toggle";
|
import { ThemeToggle } from "@/shared/components/theme-toggle";
|
||||||
|
import { BrandLogo } from "@/shared/components/brand-logo";
|
||||||
import { useTranslations, useLocale } from "next-intl";
|
import { useTranslations, useLocale } from "next-intl";
|
||||||
import { usePathname, useRouter } from "@/i18n/routing";
|
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">
|
<nav className="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
|
||||||
{/* #12 Logo with hover glow */}
|
<BrandLogo
|
||||||
<a href="#" className="flex items-center gap-2 group">
|
priority
|
||||||
<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">
|
iconClassName="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>
|
|
||||||
|
|
||||||
{/* Desktop Nav with scroll spy */}
|
{/* Desktop Nav with scroll spy */}
|
||||||
<div className="hidden md:flex items-center gap-1">
|
<div className="hidden md:flex items-center gap-1">
|
||||||
|
|||||||
Reference in New Issue
Block a user