From d55b04d4b87ab9f4d88a8b46afe54d9bda8055fb Mon Sep 17 00:00:00 2001 From: poyrazavsever Date: Mon, 31 Aug 2026 19:39:28 +0300 Subject: [PATCH] feat(links): integrate directory into the main layout --- components/links-content.tsx | 487 ++++++++++++++++++----------------- lib/links.ts | 64 ++++- 2 files changed, 311 insertions(+), 240 deletions(-) diff --git a/components/links-content.tsx b/components/links-content.tsx index fa01422..84928be 100644 --- a/components/links-content.tsx +++ b/components/links-content.tsx @@ -1,19 +1,26 @@ "use client"; -import { Icon } from "@iconify/react"; -import Image from "next/image"; -import { Link } from "@/i18n/routing"; -import { useLocale, useTranslations } from "next-intl"; import { useMemo, useState } from "react"; +import { Icon } from "@iconify/react"; +import { useLocale, useTranslations } from "next-intl"; import { Avatar, AvatarFallback, AvatarImage, + Badge, + Button, Card, Input, Typography, } from "poyraz-ui/atoms"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "poyraz-ui/molecules"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "poyraz-ui/molecules"; +import { Link } from "@/i18n/routing"; import { getResumeHref, LINK_DIRECTORY, @@ -37,12 +44,12 @@ const CATEGORY_ORDER = { } as const; const DIRECTORY_ITEMS = [...LINK_DIRECTORY].sort((left, right) => { - const categoryCompare = CATEGORY_ORDER[left.category] - CATEGORY_ORDER[right.category]; - if (categoryCompare !== 0) { - return categoryCompare; - } + const categoryCompare = + CATEGORY_ORDER[left.category] - CATEGORY_ORDER[right.category]; - return left.label.localeCompare(right.label, "tr"); + return categoryCompare !== 0 + ? categoryCompare + : left.label.localeCompare(right.label, "tr"); }); function normalize(value: string) { @@ -53,13 +60,8 @@ function normalize(value: string) { } function formatHref(href: string) { - if (href.startsWith("mailto:")) { - return href.replace("mailto:", ""); - } - - if (href.startsWith("/")) { - return `poyrazavsever.com${href}`; - } + if (href.startsWith("mailto:")) return href.replace("mailto:", ""); + if (href.startsWith("/")) return `poyrazavsever.com${href}`; return href.replace(/^https?:\/\//, "").replace(/\/$/, ""); } @@ -72,6 +74,10 @@ function parseCategoryFilter(value?: string): CategoryFilter { return "all"; } +function LinkIcon({ icon, size = 18 }: { icon: string; size?: number }) { + return ; +} + export function LinksContent({ initialCategory, initialQuery = "", @@ -79,19 +85,21 @@ export function LinksContent({ const t = useTranslations("Links"); const tNav = useTranslations("Nav"); const locale = useLocale(); - const [activeCategory, setActiveCategory] = useState(() => parseCategoryFilter(initialCategory), ); const [query, setQuery] = useState(initialQuery); - const filterItems = useMemo(() => [ - { id: "all" as const, label: t("allCategories") }, - ...LINK_DIRECTORY_CATEGORIES.map((item) => ({ - id: item.id, - label: t(`categories.${item.id}`), - })), - ], [t]); + const filterItems = useMemo( + () => [ + { id: "all" as const, label: t("allCategories") }, + ...LINK_DIRECTORY_CATEGORIES.map((item) => ({ + id: item.id, + label: t(`categories.${item.id}`), + })), + ], + [t], + ); const filteredItems = useMemo(() => { const normalizedQuery = normalize(query.trim()); @@ -102,9 +110,7 @@ export function LinksContent({ return false; } - if (queryTokens.length === 0) { - return true; - } + if (queryTokens.length === 0) return true; const haystack = normalize( [ @@ -120,212 +126,231 @@ export function LinksContent({ }, [activeCategory, query, t, tNav]); return ( -
+
+
+
+
+ + + + PA + + -
- -
- Poyraz Avsever kapak görseli -
-
- -
-
- - - - PA - - - -
-
- - Poyraz - - - Avsever - -
- - - {t("desc")} - -
- -
- {SOCIAL_LINKS.map((item) => ( - - - - ))} -
- -
- {TOP_ICON_LINKS.map((item) => { - const href = item.id === "cv" ? getResumeHref(locale) : item.href; - return ( - - -
- - - -
- - {tNav.has(item.id) ? tNav(item.id) : item.label} - - - {formatHref(href)} - -
-
-
-
- ); - })} -
- -
-
- - {t("allLinks")} - - - {t("allLinksDesc")} - -
- -
- - - setQuery(event.target.value)} - placeholder={t("searchPlaceholder")} - aria-label={t("allLinks")} - className="h-11 rounded-2xl" - /> -
- -
- {filteredItems.map((item) => { - const href = item.id === "cv" ? getResumeHref(locale) : item.href; - const isStaticOrExternal = item.external || item.id === "rss" || item.id === "cv" || href.endsWith(".xml") || href.endsWith(".pdf"); - const CardContent = ( - -
- - - - -
-
- - {tNav.has(item.id) ? tNav(item.id) : item.label} - - - {t(`categories.${item.category}`)} - -
- - - {formatHref(href)} - -
- - - - -
-
- ); - - return isStaticOrExternal ? ( - - {CardContent} - - ) : ( - - {CardContent} - - ); - })} - - {filteredItems.length === 0 ? ( - - - {t("empty")} - - - ) : null} -
-
+
+ + {t("title")} + + + {t("desc")} +
- -
+ +
+ {SOCIAL_LINKS.map((item) => ( + + ))} +
+
+
+ +
+
+ + {t("quickLinks")} + + + {t("quickLinksDesc")} + +
+ +
+ {TOP_ICON_LINKS.map((item) => { + const href = item.id === "cv" ? getResumeHref(locale) : item.href; + + return ( + + + + + + + {tNav.has(item.id) ? tNav(item.id) : item.label} + + + {formatHref(href)} + + + + ); + })} +
+
+ +
+
+
+ + {t("allLinks")} + + + {t("allLinksDesc")} + +
+ +
+ + + setQuery(event.target.value)} + placeholder={t("searchPlaceholder")} + aria-label={t("searchAriaLabel")} + className="h-10 rounded-sm" + /> +
+
+ +
+ {filteredItems.map((item) => { + const href = item.id === "cv" ? getResumeHref(locale) : item.href; + const isStaticOrExternal = + item.external || + item.id === "rss" || + item.id === "cv" || + href.endsWith(".xml") || + href.endsWith(".pdf"); + const content = ( + +
+ + + + +
+
+ + {tNav.has(item.id) ? tNav(item.id) : item.label} + + + {t(`categories.${item.category}`)} + +
+ + {formatHref(href)} + +
+ + +
+
+ ); + + return isStaticOrExternal ? ( + + {content} + + ) : ( + + {content} + + ); + })} + + {filteredItems.length === 0 ? ( + + + {t("empty")} + + + ) : null} +
+
); } diff --git a/lib/links.ts b/lib/links.ts index 5e2391a..7285513 100644 --- a/lib/links.ts +++ b/lib/links.ts @@ -56,12 +56,6 @@ export const SOCIAL_LINKS = [ href: "https://behance.net/poyrazavsever", icon: "mdi:behance", }, - { - id: "spotify", - label: "Spotify", - href: "https://open.spotify.com/user/3136fdjkc5p4cbzmuxhvqdd4b2hu", - icon: "mdi:spotify", - }, { id: "buy-me-a-coffee", label: "Bana kahve ısmarla", @@ -153,15 +147,67 @@ export const LINK_DIRECTORY_CATEGORIES: ReadonlyArray<{ { id: "resources", label: "Kaynaklar" }, ]; -export const LINK_DIRECTORY: LinkDirectoryItem[] = [ +const STATIC_PAGE_LINKS = [ + { + id: "home", + label: "Ana Sayfa", + href: "/", + icon: "mdi:home-outline", + keywords: ["ana sayfa", "home", "portfolio"], + }, ...NAV_LINKS.map((item) => ({ + ...item, + icon: "mdi:compass-outline", + keywords: [item.label, item.href, "sayfa", "navigasyon", "internal"], + })), + ...NAV_DROPDOWN_GROUPS.flatMap((group) => + group.items.map((item) => ({ + id: item.id, + label: item.label, + href: item.href, + icon: item.icon, + keywords: [...item.keywords], + })), + ), + { + id: "references", + label: "Referanslar", + href: "/about/references", + icon: "mdi:comment-quote-outline", + keywords: ["referans", "references", "testimonial", "yorum"], + }, + { + id: "volunteerCommunity", + label: "Gönüllülük ve Topluluk", + href: "/about/volunteer-community", + icon: "mdi:account-group-outline", + keywords: ["gönüllülük", "topluluk", "volunteer", "community"], + }, + { + id: "mediaKit", + label: "Medya Kiti", + href: "/media-kit", + icon: "mdi:chart-box-outline", + keywords: ["medya kiti", "media kit", "sponsor", "iş birliği"], + }, + { + id: "links", + label: "Bağlantılar", + href: "/links", + icon: "mdi:link-variant", + keywords: ["bağlantılar", "links", "link in bio"], + }, +] as const; + +export const LINK_DIRECTORY: LinkDirectoryItem[] = [ + ...STATIC_PAGE_LINKS.map((item) => ({ id: item.id, label: item.label, href: item.href, - icon: "mdi:compass-outline", + icon: item.icon, external: false, category: "navigation" as const, - keywords: [item.label, item.href, "sayfa", "navigasyon", "internal"], + keywords: [...item.keywords], })), ...SOCIAL_LINKS.map((item) => ({ id: item.id,