diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx
index f028dd9..f2349a7 100644
--- a/app/[locale]/layout.tsx
+++ b/app/[locale]/layout.tsx
@@ -9,6 +9,7 @@ import { AppShell } from "@/components/app-shell";
import { GoogleAnalytics } from "@/components/google-analytics";
import { PoyrazBottomRightFollower } from "@/components/poyraz-bottom-right-follower";
import { listAnimationSources } from "@/data/animation-sources";
+import { getHomeBlogNews, getLatestAgendaArticle } from "@/data/blog";
export async function generateMetadata({
params,
@@ -116,10 +117,13 @@ export default async function LocaleLayout({
}
// Provide messages for NextIntlClientProvider
- const [messages, animationSources] = await Promise.all([
- getMessages(),
- listAnimationSources(locale),
- ]);
+ const [messages, animationSources, latestAgendaArticle, latestPosts] =
+ await Promise.all([
+ getMessages(),
+ listAnimationSources(locale),
+ getLatestAgendaArticle(locale),
+ getHomeBlogNews(locale, 1),
+ ]);
const animationSourceSearchItems = animationSources.map((source) => ({
slug: source.slug,
title: source.title,
@@ -133,7 +137,25 @@ export default async function LocaleLayout({
-
+
{children}
diff --git a/components/app-shell.tsx b/components/app-shell.tsx
index 0fa9e47..0fca8e1 100644
--- a/components/app-shell.tsx
+++ b/components/app-shell.tsx
@@ -1,7 +1,6 @@
"use client";
import { useEffect, useState } from "react";
import { Icon } from "@iconify/react";
-import { usePathname } from "@/i18n/routing";
import { AnnouncementBar } from "poyraz-ui/organisms";
import { SiteNavbar } from "@/components/site-navbar";
import { NekoFollower } from "@/components/neko-follower";
@@ -10,6 +9,11 @@ import { useLocale } from "next-intl";
import { getLocalizedValue } from "@/lib/locale";
import dynamic from "next/dynamic";
import type { AnimationSourceSearchItem } from "@/lib/command-palette-links";
+import {
+ LayoutLeftPromoRail,
+ LayoutRightPromoRail,
+ type LayoutContentPromo,
+} from "@/components/layout-promo-rails";
const AtaturkWidgetModal = dynamic(
() => import("@/components/ataturk-widget-modal").then((mod) => mod.AtaturkWidgetModal),
@@ -19,6 +23,8 @@ const AtaturkWidgetModal = dynamic(
type AppShellProps = {
children: React.ReactNode;
animationSources: AnimationSourceSearchItem[];
+ latestAgenda: LayoutContentPromo | null;
+ latestPost: LayoutContentPromo | null;
};
export type ThemeMode = "light" | "dark";
@@ -32,15 +38,15 @@ function getInitialTheme(): ThemeMode {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
-export function AppShell({ children, animationSources }: AppShellProps) {
- const pathname = usePathname();
+export function AppShell({
+ children,
+ animationSources,
+ latestAgenda,
+ latestPost,
+}: AppShellProps) {
const locale = useLocale();
const announcement = ANNOUNCEMENT_ITEMS[0];
const [theme, setTheme] = useState(getInitialTheme);
- const isStandaloneLinksPage =
- pathname === "/links" || pathname.startsWith("/links/");
- const isStandaloneMediaKitPage =
- pathname === "/media-kit" || pathname.startsWith("/media-kit/");
useEffect(() => {
document.documentElement.dataset.poyrazTheme = theme;
@@ -48,32 +54,37 @@ export function AppShell({ children, animationSources }: AppShellProps) {
localStorage.setItem("poyraz-theme", theme);
}, [theme]);
- if (isStandaloneLinksPage || isStandaloneMediaKitPage) {
- return children;
- }
-
const localizedText = announcement ? getLocalizedValue(announcement.text, locale) : "";
return (
<>
{ENABLE_NEKO_FOLLOWER ? : null}
-
-
+
- {announcement ? (
- }
- >
- {localizedText}
-
- ) : null}
- {children}
+
+
+
+ {announcement ? (
+
}
+ >
+ {localizedText}
+
+ ) : null}
+
+
{children}
+
+
>
);
diff --git a/components/layout-promo-rails.tsx b/components/layout-promo-rails.tsx
new file mode 100644
index 0000000..68b1dfe
--- /dev/null
+++ b/components/layout-promo-rails.tsx
@@ -0,0 +1,342 @@
+"use client";
+
+import { useState, type KeyboardEvent } from "react";
+import Image from "next/image";
+import { Icon } from "@iconify/react";
+import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
+import { useLocale, useTranslations } from "next-intl";
+import {
+ Badge,
+ Button,
+ ButtonIcon,
+ ButtonLabel,
+ Card,
+ Typography,
+} from "poyraz-ui/atoms";
+import { Link } from "@/i18n/routing";
+import {
+ LEFT_LAYOUT_PROMO_SLIDES,
+ RIGHT_LAYOUT_PROMO_SLIDES,
+ type LayoutPromoCardDefinition,
+ type LayoutPromoSlide,
+} from "@/data/layout-promos";
+import { SPONSORS } from "@/data/sponsors";
+import { getLocalizedValue } from "@/lib/locale";
+
+export type LayoutContentPromo = {
+ title: string;
+ href: string;
+};
+
+type PromoRailSide = "left" | "right";
+
+function RailButton({
+ href,
+ label,
+ icon = "mdi:arrow-right",
+ variant = "outline",
+ external = false,
+}: {
+ href: string;
+ label: string;
+ icon?: string;
+ variant?: "default" | "outline" | "secondary";
+ external?: boolean;
+}) {
+ const content = (
+ <>
+ {label}
+
+
+
+ >
+ );
+
+ return (
+
+ );
+}
+
+function SponsorLogos() {
+ return (
+
+ {SPONSORS.map((sponsor, index) => (
+
+
+
+ ))}
+
+ );
+}
+
+function PromoIcon({
+ card,
+ className,
+}: {
+ card: LayoutPromoCardDefinition;
+ className?: string;
+}) {
+ return (
+
+ );
+}
+
+function PromoCard({
+ card,
+ latestAgenda,
+ latestPost,
+}: {
+ card: LayoutPromoCardDefinition;
+ latestAgenda: LayoutContentPromo | null;
+ latestPost: LayoutContentPromo | null;
+}) {
+ const t = useTranslations("LayoutPromos");
+ const locale = useLocale();
+ const liveContent =
+ card.contentSource === "latestAgenda"
+ ? latestAgenda
+ : card.contentSource === "latestPost"
+ ? latestPost
+ : null;
+ const href = liveContent?.href ?? getLocalizedValue(card.href, locale);
+ const description = liveContent?.title ?? t(card.descriptionKey);
+ const external = card.external ?? false;
+ const iconSurface = card.iconSurface ?? "accent";
+ const cardClassName =
+ card.surface === "primary"
+ ? "rounded-sm border-primary/25 bg-primary/5 p-3"
+ : "rounded-sm border-border p-3";
+ const iconClassName =
+ iconSurface === "primary"
+ ? "bg-primary text-primary-foreground"
+ : iconSurface === "foreground"
+ ? "bg-foreground text-background"
+ : "bg-accent text-foreground";
+
+ return (
+
+ {card.eyebrowKey ? (
+
+
+ {t(card.eyebrowKey)}
+
+
+
+ ) : (
+
+ )}
+
+
+ {t(card.titleKey)}
+
+
+ {description}
+
+
+ {card.kind === "sponsors" ? : null}
+
+
+
+
+
+ );
+}
+
+function PromoRail({
+ side,
+ slides,
+ latestAgenda = null,
+ latestPost = null,
+}: {
+ side: PromoRailSide;
+ slides: readonly LayoutPromoSlide[];
+ latestAgenda?: LayoutContentPromo | null;
+ latestPost?: LayoutContentPromo | null;
+}) {
+ const t = useTranslations("LayoutPromos");
+ const reduceMotion = useReducedMotion();
+ const [activeSlide, setActiveSlide] = useState(0);
+ const direction = side === "left" ? -1 : 1;
+ const activeCards = slides[activeSlide] ?? slides[0];
+ const railId = `${side}-promo-rail`;
+
+ const selectAdjacentSlide = (step: number) => {
+ setActiveSlide((current) => (current + step + slides.length) % slides.length);
+ };
+
+ const handleNavigationKeyDown = (event: KeyboardEvent) => {
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
+
+ event.preventDefault();
+ selectAdjacentSlide(event.key === "ArrowRight" ? 1 : -1);
+ };
+
+ return (
+
+ );
+}
+
+export function LayoutLeftPromoRail({
+ latestAgenda,
+ latestPost,
+}: {
+ latestAgenda: LayoutContentPromo | null;
+ latestPost: LayoutContentPromo | null;
+}) {
+ return (
+
+ );
+}
+
+export function LayoutRightPromoRail() {
+ return ;
+}
diff --git a/data/blog.ts b/data/blog.ts
index 2294d37..73e44b8 100644
--- a/data/blog.ts
+++ b/data/blog.ts
@@ -97,6 +97,11 @@ export async function getAllAgendaArticles(locale?: string): Promise isNewsletterCategory(article.category));
}
+export async function getLatestAgendaArticle(locale?: string) {
+ const articles = await getAllAgendaArticles(locale);
+ return articles[0] ?? null;
+}
+
export async function getHomeBlogNews(locale?: string, limit = 3) {
const articles = await getAllBlogArticles(locale);
diff --git a/data/layout-promos.ts b/data/layout-promos.ts
new file mode 100644
index 0000000..8b0cc75
--- /dev/null
+++ b/data/layout-promos.ts
@@ -0,0 +1,202 @@
+import type { Localized } from "@/lib/locale";
+
+export type LayoutPromoCopyKey =
+ | "weeklyEyebrow"
+ | "weeklyTitle"
+ | "weeklyFallback"
+ | "weeklyCta"
+ | "projectsTitle"
+ | "projectsDescription"
+ | "projectsCta"
+ | "latestPostEyebrow"
+ | "latestPostTitle"
+ | "latestPostFallback"
+ | "latestPostCta"
+ | "anatomyTitle"
+ | "anatomyDescription"
+ | "anatomyCta"
+ | "youtubeEyebrow"
+ | "youtubeTitle"
+ | "youtubeDescription"
+ | "youtubeCta"
+ | "designSystemEyebrow"
+ | "designSystemTitle"
+ | "designSystemDescription"
+ | "designSystemCta"
+ | "communityEyebrow"
+ | "communityTitle"
+ | "communityDescription"
+ | "communityCta"
+ | "referencesEyebrow"
+ | "referencesTitle"
+ | "referencesDescription"
+ | "referencesCta"
+ | "sponsorsEyebrow"
+ | "sponsorsTitle"
+ | "sponsorsDescription"
+ | "sponsorsCta"
+ | "contactTitle"
+ | "contactDescription"
+ | "contactCta"
+ | "linkedinEyebrow"
+ | "linkedinTitle"
+ | "linkedinDescription"
+ | "linkedinCta"
+ | "instagramEyebrow"
+ | "instagramTitle"
+ | "instagramDescription"
+ | "instagramCta";
+
+export type LayoutPromoCardDefinition = {
+ id: string;
+ kind?: "standard" | "sponsors";
+ eyebrowKey?: LayoutPromoCopyKey;
+ titleKey: LayoutPromoCopyKey;
+ descriptionKey: LayoutPromoCopyKey;
+ ctaKey: LayoutPromoCopyKey;
+ href: string | Localized;
+ icon: string;
+ iconSurface?: "accent" | "foreground" | "primary";
+ surface?: "default" | "primary";
+ buttonVariant?: "default" | "outline" | "secondary";
+ external?: boolean;
+ contentSource?: "latestAgenda" | "latestPost";
+};
+
+export type LayoutPromoSlide = readonly LayoutPromoCardDefinition[];
+
+export const LEFT_LAYOUT_PROMO_SLIDES: readonly LayoutPromoSlide[] = [
+ [
+ {
+ id: "weekly-agenda",
+ eyebrowKey: "weeklyEyebrow",
+ titleKey: "weeklyTitle",
+ descriptionKey: "weeklyFallback",
+ ctaKey: "weeklyCta",
+ href: "/agenda",
+ icon: "mdi:newspaper-variant-outline",
+ surface: "primary",
+ buttonVariant: "default",
+ contentSource: "latestAgenda",
+ },
+ {
+ id: "projects",
+ titleKey: "projectsTitle",
+ descriptionKey: "projectsDescription",
+ ctaKey: "projectsCta",
+ href: "/projects",
+ icon: "mdi:layers-triple-outline",
+ },
+ {
+ id: "latest-post",
+ eyebrowKey: "latestPostEyebrow",
+ titleKey: "latestPostTitle",
+ descriptionKey: "latestPostFallback",
+ ctaKey: "latestPostCta",
+ href: "/blog",
+ icon: "mdi:post-outline",
+ contentSource: "latestPost",
+ },
+ {
+ id: "javascript-anatomy",
+ titleKey: "anatomyTitle",
+ descriptionKey: "anatomyDescription",
+ ctaKey: "anatomyCta",
+ href: "/content",
+ icon: "ri:twitter-x-fill",
+ iconSurface: "foreground",
+ },
+ ],
+ [
+ {
+ id: "youtube",
+ eyebrowKey: "youtubeEyebrow",
+ titleKey: "youtubeTitle",
+ descriptionKey: "youtubeDescription",
+ ctaKey: "youtubeCta",
+ href: "https://youtube.com/@poyrazavsever",
+ icon: "mdi:youtube",
+ iconSurface: "primary",
+ external: true,
+ },
+ {
+ id: "poyraz-ui",
+ eyebrowKey: "designSystemEyebrow",
+ titleKey: "designSystemTitle",
+ descriptionKey: "designSystemDescription",
+ ctaKey: "designSystemCta",
+ href: "https://ui.poyrazavsever.com",
+ icon: "mdi:palette-swatch-outline",
+ external: true,
+ },
+ {
+ id: "community",
+ eyebrowKey: "communityEyebrow",
+ titleKey: "communityTitle",
+ descriptionKey: "communityDescription",
+ ctaKey: "communityCta",
+ href: "/about/volunteer-community",
+ icon: "mdi:account-group-outline",
+ },
+ {
+ id: "references",
+ eyebrowKey: "referencesEyebrow",
+ titleKey: "referencesTitle",
+ descriptionKey: "referencesDescription",
+ ctaKey: "referencesCta",
+ href: "/about/references",
+ icon: "mdi:comment-quote-outline",
+ },
+ ],
+];
+
+export const RIGHT_LAYOUT_PROMO_SLIDES: readonly LayoutPromoSlide[] = [
+ [
+ {
+ id: "sponsors",
+ kind: "sponsors",
+ eyebrowKey: "sponsorsEyebrow",
+ titleKey: "sponsorsTitle",
+ descriptionKey: "sponsorsDescription",
+ ctaKey: "sponsorsCta",
+ href: "/media-kit",
+ icon: "mdi:handshake-outline",
+ buttonVariant: "default",
+ },
+ {
+ id: "contact",
+ titleKey: "contactTitle",
+ descriptionKey: "contactDescription",
+ ctaKey: "contactCta",
+ href: "/contact",
+ icon: "mdi:message-text-outline",
+ iconSurface: "primary",
+ surface: "primary",
+ buttonVariant: "default",
+ },
+ ],
+ [
+ {
+ id: "linkedin",
+ eyebrowKey: "linkedinEyebrow",
+ titleKey: "linkedinTitle",
+ descriptionKey: "linkedinDescription",
+ ctaKey: "linkedinCta",
+ href: "https://www.linkedin.com/in/poyrazavsever/",
+ icon: "mdi:linkedin",
+ external: true,
+ },
+ {
+ id: "instagram",
+ eyebrowKey: "instagramEyebrow",
+ titleKey: "instagramTitle",
+ descriptionKey: "instagramDescription",
+ ctaKey: "instagramCta",
+ href: "https://instagram.com/poyraz_avsever",
+ icon: "mdi:instagram",
+ surface: "primary",
+ buttonVariant: "default",
+ external: true,
+ },
+ ],
+];
diff --git a/messages/en.json b/messages/en.json
index 3683387..8a07f96 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -1,5 +1,6 @@
{
"Nav": {
+ "home": "Home",
"about": "About",
"blog": "Blog",
"agenda": "Weekly Agenda",
@@ -12,6 +13,10 @@
"socialLinks": "Social Links",
"others": "Others",
"animationResources": "Animation Resources",
+ "links": "Links",
+ "mediaKit": "Media Kit",
+ "references": "References",
+ "volunteerCommunity": "Volunteering & Community",
"backToMenu": "Back to menu",
"menu": "Menu",
"mobileMenu": "Mobile Menu",
@@ -35,6 +40,58 @@
"sponsors": "Sponsors"
}
},
+ "LayoutPromos": {
+ "leftRailLabel": "Featured content",
+ "rightRailLabel": "Partnerships and contact",
+ "slideNavigationLabel": "Promotional slides",
+ "slideCta": "Go to slide {slide}",
+ "slideStatus": "Slide {current} of {total}",
+ "weeklyEyebrow": "This week",
+ "weeklyTitle": "Have you read this week's agenda?",
+ "weeklyFallback": "Weekly developments from software, technology, design, and artificial intelligence.",
+ "weeklyCta": "Read the agenda",
+ "projectsTitle": "Curious how I build my projects?",
+ "projectsDescription": "Explore the decisions, architecture, and outcomes behind selected products through detailed case studies.",
+ "projectsCta": "Explore projects",
+ "latestPostEyebrow": "New post",
+ "latestPostTitle": "What's new on the blog?",
+ "latestPostFallback": "Read my latest notes on software and product development.",
+ "latestPostCta": "Read the post",
+ "anatomyTitle": "Have you watched JavaScript Anatomy?",
+ "anatomyDescription": "Explore my series explaining JavaScript concepts through concise 1-4 minute landscape videos.",
+ "anatomyCta": "Watch the series",
+ "youtubeEyebrow": "YouTube",
+ "youtubeTitle": "Join a community of 8K+ people.",
+ "youtubeDescription": "Watch practical videos about software, artificial intelligence, and product development.",
+ "youtubeCta": "Visit the channel",
+ "designSystemEyebrow": "Poyraz UI",
+ "designSystemTitle": "Explore the design system behind this site.",
+ "designSystemDescription": "See the components, design decisions, and live examples I use across the portfolio.",
+ "designSystemCta": "Open the docs",
+ "communityEyebrow": "Community",
+ "communityTitle": "What do I do beyond writing code?",
+ "communityDescription": "Explore my workshops, hackathons, mentoring, and volunteer community work.",
+ "communityCta": "Community work",
+ "referencesEyebrow": "References",
+ "referencesTitle": "What do the people I work with say?",
+ "referencesDescription": "Read feedback from teammates and people I have built products with.",
+ "referencesCta": "Read references",
+ "sponsorsEyebrow": "Sponsors",
+ "sponsorsTitle": "These brands have sponsored my work so far.",
+ "sponsorsDescription": "Would you like to introduce your brand to my software and technology-focused audience?",
+ "sponsorsCta": "Become a sponsor",
+ "contactTitle": "Have an idea? Let's build it together.",
+ "contactDescription": "Reach out directly for a project, partnership, or content idea.",
+ "contactCta": "Get in touch",
+ "linkedinEyebrow": "LinkedIn",
+ "linkedinTitle": "Follow my professional journey.",
+ "linkedinDescription": "I share my projects, technical experiences, and notes from the industry on LinkedIn.",
+ "linkedinCta": "Visit LinkedIn",
+ "instagramEyebrow": "Instagram",
+ "instagramTitle": "Technology, in a shorter format.",
+ "instagramDescription": "Follow for concise technical videos, moments from events, and a look behind my creative process.",
+ "instagramCta": "Follow on Instagram"
+ },
"About": {
"title": "About me",
"contactCta": "Contact me",
@@ -134,12 +191,17 @@
"copied": "Copied"
},
"Links": {
+ "title": "My links",
"desc": "Here you can find all my social accounts, portfolio pages, and quick access links in one place. Open and share directly.",
+ "socialLinks": "Social media links",
+ "quickLinks": "Quick access",
+ "quickLinksDesc": "Frequently used projects, resources, and resume",
"allLinks": "All Links",
"allLinksDesc": "Pages, resources, and social profiles",
"selectCategory": "Select category",
"allCategories": "All categories",
"searchPlaceholder": "Search links... github, medium, /blog",
+ "searchAriaLabel": "Search links",
"empty": "No links found matching the selected filter.",
"categories": {
"navigation": "Pages",
diff --git a/messages/tr.json b/messages/tr.json
index acc3e7d..3d97293 100644
--- a/messages/tr.json
+++ b/messages/tr.json
@@ -1,5 +1,6 @@
{
"Nav": {
+ "home": "Ana Sayfa",
"about": "Hakkımda",
"blog": "Blog",
"agenda": "Haftalık Gündem",
@@ -12,6 +13,10 @@
"socialLinks": "Sosyal Bağlantılar",
"others": "Diğerleri",
"animationResources": "Animasyon Kaynakları",
+ "links": "Bağlantılar",
+ "mediaKit": "Medya Kiti",
+ "references": "Referanslar",
+ "volunteerCommunity": "Gönüllük ve Topluluk",
"backToMenu": "Menüye dön",
"menu": "Menü",
"mobileMenu": "Mobil Menü",
@@ -35,6 +40,58 @@
"sponsors": "Sponsorlar"
}
},
+ "LayoutPromos": {
+ "leftRailLabel": "Öne çıkan içerikler",
+ "rightRailLabel": "İş birlikleri ve iletişim",
+ "slideNavigationLabel": "Tanıtım slaytları",
+ "slideCta": "{slide}. slayda git",
+ "slideStatus": "{current} / {total}. slayt",
+ "weeklyEyebrow": "Bu hafta",
+ "weeklyTitle": "Bu haftanın gündemini okudun mu?",
+ "weeklyFallback": "Yazılım, teknoloji, tasarım ve yapay zekâ dünyasından haftalık gelişmeler.",
+ "weeklyCta": "Gündemi oku",
+ "projectsTitle": "Nasıl geliştirdiğimi merak ediyor musun?",
+ "projectsDescription": "Seçili projelerde aldığım kararları, mimariyi ve ortaya çıkan sonuçları vaka çalışmalarıyla incele.",
+ "projectsCta": "Projeleri incele",
+ "latestPostEyebrow": "Yeni yazı",
+ "latestPostTitle": "Blogda yeni ne var?",
+ "latestPostFallback": "Yazılım ve ürün geliştirme üzerine son notlarıma göz at.",
+ "latestPostCta": "Yazıyı oku",
+ "anatomyTitle": "JavaScript Anatomisi'ni izledin mi?",
+ "anatomyDescription": "JavaScript kavramlarını 1-4 dakikalık kısa ve yatay videolarla anlattığım seriyi keşfet.",
+ "anatomyCta": "Seriyi izle",
+ "youtubeEyebrow": "YouTube",
+ "youtubeTitle": "8 B+ kişilik topluluğa katıl.",
+ "youtubeDescription": "Yazılım, yapay zekâ ve ürün geliştirme üzerine uygulamalı videoları izle.",
+ "youtubeCta": "Kanala git",
+ "designSystemEyebrow": "Poyraz UI",
+ "designSystemTitle": "Bu sitenin tasarım sistemini keşfet.",
+ "designSystemDescription": "Kullandığım bileşenleri, tasarım kararlarını ve canlı örnekleri incele.",
+ "designSystemCta": "Dokümantasyonu aç",
+ "communityEyebrow": "Topluluk",
+ "communityTitle": "Kodun dışında neler yapıyorum?",
+ "communityDescription": "Workshop, hackathon, mentörlük ve gönüllülük çalışmalarımı incele.",
+ "communityCta": "Topluluk çalışmaları",
+ "referencesEyebrow": "Referanslar",
+ "referencesTitle": "Birlikte çalıştığım insanlar ne diyor?",
+ "referencesDescription": "Ekip arkadaşlarımdan ve birlikte ürettiğim insanlardan gelen yorumları oku.",
+ "referencesCta": "Referansları oku",
+ "sponsorsEyebrow": "Sponsorlar",
+ "sponsorsTitle": "Bak, bunlar bana şimdiye kadar sponsor oldu.",
+ "sponsorsDescription": "Sen de markanı yazılım ve teknoloji odaklı kitlemle buluşturmak ister misin?",
+ "sponsorsCta": "Sen de sponsor ol",
+ "contactTitle": "Bir fikrin mi var? Birlikte üretelim.",
+ "contactDescription": "Proje, iş birliği veya içerik fikrin için doğrudan iletişime geç.",
+ "contactCta": "İletişime geç",
+ "linkedinEyebrow": "LinkedIn",
+ "linkedinTitle": "Profesyonel yolculuğumu takip et.",
+ "linkedinDescription": "Projelerimi, teknik deneyimlerimi ve sektörden notlarımı LinkedIn'de paylaşıyorum.",
+ "linkedinCta": "LinkedIn'e git",
+ "instagramEyebrow": "Instagram",
+ "instagramTitle": "Teknolojinin daha kısa hâli burada.",
+ "instagramDescription": "Kısa teknik videolar, etkinliklerden anlar ve üretim sürecimin perde arkası için takip et.",
+ "instagramCta": "Instagram'da takip et"
+ },
"About": {
"title": "Hakkımda",
"contactCta": "İletişime geç",
@@ -134,12 +191,17 @@
"copied": "Kopyalandı"
},
"Links": {
+ "title": "Bağlantılarım",
"desc": "Burada sosyal hesaplarım, portfolyo sayfalarım ve hızlı erişim linklerimin tamamı tek yerde duruyor. Direkt açıp paylaşabilirsin.",
+ "socialLinks": "Sosyal medya bağlantıları",
+ "quickLinks": "Hızlı erişim",
+ "quickLinksDesc": "Sık kullanılan projeler, kaynaklar ve özgeçmiş",
"allLinks": "Tüm Linkler",
"allLinksDesc": "Sayfalar, kaynaklar ve sosyal profiller",
"selectCategory": "Kategori seç",
"allCategories": "Tüm kategoriler",
"searchPlaceholder": "Link ara... github, medium, /blog",
+ "searchAriaLabel": "Bağlantılarda ara",
"empty": "Seçili filtreye uygun link bulunamadı.",
"categories": {
"navigation": "Sayfalar",