feat(layout): add animated text component for dynamic text animations

This commit is contained in:
Fatih Kadir Akın
2026-01-06 18:20:02 +03:00
parent dc8d49bbb4
commit b052f0d05d
4 changed files with 61 additions and 6 deletions

View File

@@ -9,6 +9,7 @@
--font-sans: var(--font-inter);
--font-mono: var(--font-geist-mono);
--font-arabic: var(--font-arabic);
--font-display: var(--font-playfair);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@@ -131,6 +132,23 @@
.text-balance {
text-wrap: balance;
}
/* Gradient text animation */
.animate-gradient-text {
animation: gradient-flow 20s ease infinite;
}
}
@keyframes gradient-flow {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
/* Theme Variants */
@@ -299,3 +317,4 @@
.animate-flash {
animation: flash 0.8s ease-out !important;
}

View File

@@ -1,6 +1,6 @@
import type { Metadata } from "next";
import Script from "next/script";
import { Inter, Noto_Sans_Arabic, Geist_Mono } from "next/font/google";
import { Inter, Noto_Sans_Arabic, Geist_Mono, Playfair_Display } from "next/font/google";
import { headers } from "next/headers";
import { getMessages, getLocale } from "next-intl/server";
import { Providers } from "@/components/providers";
@@ -29,6 +29,13 @@ const geistMono = Geist_Mono({
variable: "--font-geist-mono",
});
const playfairDisplay = Playfair_Display({
subsets: ["latin"],
variable: "--font-playfair",
weight: ["400", "500", "600", "700"],
style: ["normal", "italic"],
});
export const metadata: Metadata = {
metadataBase: new URL(process.env.NEXTAUTH_URL || "http://localhost:3000"),
title: {
@@ -165,8 +172,8 @@ export default async function RootLayout({
} as React.CSSProperties;
const fontClasses = isRtl
? `${inter.variable} ${notoSansArabic.variable} ${geistMono.variable} font-arabic`
: `${inter.variable} ${geistMono.variable} font-sans`;
? `${inter.variable} ${notoSansArabic.variable} ${geistMono.variable} ${playfairDisplay.variable} font-arabic`
: `${inter.variable} ${geistMono.variable} ${playfairDisplay.variable} font-sans`;
return (
<html lang={locale} dir={isRtl ? "rtl" : "ltr"} suppressHydrationWarning className={themeClasses} style={themeStyles}>

View File

@@ -9,6 +9,7 @@ import { DiscoveryPrompts } from "@/components/prompts/discovery-prompts";
import { HeroCategories } from "@/components/prompts/hero-categories";
import { CliCommand } from "@/components/layout/cli-command";
import { ExtensionLink } from "@/components/layout/extension-link";
import { AnimatedText } from "@/components/layout/animated-text";
function getOrdinalSuffix(n: number): string {
const s = ["th", "st", "nd", "rd"];
@@ -127,9 +128,9 @@ export default async function HomePage() {
</>
) : (
<>
<h1 className="text-2xl font-bold tracking-tight sm:text-3xl md:text-4xl lg:text-5xl !text-2xl sm:!text-3xl md:!text-4xl lg:!text-5xl">
{tHomepage("heroTitle")}
<span className="block text-primary">{tHomepage("heroSubtitle")}</span>
<h1 className="space-y-0 overflow-visible">
<AnimatedText className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold tracking-tighter leading-none">{tHomepage("heroTitle")}</AnimatedText>
<AnimatedText className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl italic font-display tracking-tight leading-none">{tHomepage("heroSubtitle")}</AnimatedText>
</h1>
<p className="mt-6 text-muted-foreground text-lg max-w-xl">
{tHomepage("heroDescription")}

View File

@@ -0,0 +1,28 @@
"use client";
interface AnimatedTextProps {
children: React.ReactNode;
className?: string;
}
export function AnimatedText({ children, className = "" }: AnimatedTextProps) {
return (
<span className="block whitespace-nowrap overflow-visible">
<span
className={`animate-gradient-text ${className}`}
style={{
background: "linear-gradient(90deg, #3b82f6, #06b6d4, #10b981, #f97316, #ef4444, #3b82f6)",
backgroundSize: "300% 100%",
WebkitBackgroundClip: "text",
backgroundClip: "text",
WebkitTextFillColor: "transparent",
display: "inline-block",
padding: "0.25em 0.15em",
margin: "-0.25em -0.15em",
}}
>
{children}
</span>
</span>
);
}