feat(i18n): localize static elements, navbar switcher, and search palette
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import Link from "next/link";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Card, Typography } from "poyraz-ui/atoms";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
export const CONTACT_LINKS = [
|
||||
{
|
||||
@@ -27,6 +28,8 @@ export const CONTACT_LINKS = [
|
||||
] as const;
|
||||
|
||||
export function ContactContent() {
|
||||
const t = useTranslations("Contact");
|
||||
|
||||
return (
|
||||
<section className="grid gap-3 md:grid-cols-3">
|
||||
{CONTACT_LINKS.map((item) => (
|
||||
@@ -42,7 +45,7 @@ export function ContactContent() {
|
||||
<Icon icon={item.icon} width={18} height={18} />
|
||||
</div>
|
||||
<Typography variant="large" className="mt-3 text-base leading-tight">
|
||||
{item.label}
|
||||
{t(item.id)}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-1 text-muted-foreground">
|
||||
{item.value}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Button, Card, Typography } from "poyraz-ui/atoms";
|
||||
import { Modal, ModalContent, ModalTitle } from "poyraz-ui/molecules";
|
||||
import { YoutubeLiteEmbed } from "@/components/youtube-lite-embed";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
type ContentContentProps = {
|
||||
youtubeLinks: readonly string[];
|
||||
@@ -11,6 +12,7 @@ type ContentContentProps = {
|
||||
};
|
||||
|
||||
function PdfFirstPagePreview({ src, title }: { src: string; title: string }) {
|
||||
const t = useTranslations("Content");
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const [failed, setFailed] = useState(false);
|
||||
|
||||
@@ -86,7 +88,7 @@ function PdfFirstPagePreview({ src, title }: { src: string; title: string }) {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center bg-muted/20 p-2">
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
Önizleme yüklenemedi
|
||||
{t("pdfPreviewError")}
|
||||
</Typography>
|
||||
</div>
|
||||
);
|
||||
@@ -107,6 +109,7 @@ export function ContentContent({
|
||||
youtubeLinks,
|
||||
pdfFiles,
|
||||
}: ContentContentProps) {
|
||||
const t = useTranslations("Content");
|
||||
const [pdfModalOpen, setPdfModalOpen] = useState(false);
|
||||
const [activePdfIndex, setActivePdfIndex] = useState(0);
|
||||
|
||||
@@ -128,7 +131,7 @@ export function ContentContent({
|
||||
<section className="flex h-full flex-col gap-3 overflow-y-auto">
|
||||
<section className="space-y-2">
|
||||
<Typography variant="large" className="text-base">
|
||||
Son YouTube Videoları
|
||||
{t("youtubeTitle")}
|
||||
</Typography>
|
||||
<div className="grid gap-2 md:grid-cols-3">
|
||||
{embeddedVideos.map((link) => (
|
||||
@@ -136,7 +139,7 @@ export function ContentContent({
|
||||
key={link}
|
||||
className="overflow-hidden rounded-sm border-border p-0"
|
||||
>
|
||||
<YoutubeLiteEmbed link={link} title="YouTube video oynatici" />
|
||||
<YoutubeLiteEmbed link={link} title={t("youtubeEmbedTitle")} />
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
@@ -144,7 +147,7 @@ export function ContentContent({
|
||||
|
||||
<section className="space-y-2">
|
||||
<Typography variant="large" className="text-base">
|
||||
LinkedIn PDF Notları
|
||||
{t("pdfTitle")}
|
||||
</Typography>
|
||||
<div className="grid grid-cols-2 gap-2 lg:grid-cols-3">
|
||||
{pdfFiles.map((pdf, index) => (
|
||||
@@ -157,7 +160,7 @@ export function ContentContent({
|
||||
<Card className="overflow-hidden rounded-sm border-border p-0 transition-colors hover:border-zinc-700">
|
||||
<PdfFirstPagePreview
|
||||
src={`/pdf/${pdf}`}
|
||||
title={`${pdf} önizleme`}
|
||||
title={t("pdfPreviewTitle", { name: pdf })}
|
||||
/>
|
||||
</Card>
|
||||
</button>
|
||||
@@ -168,7 +171,7 @@ export function ContentContent({
|
||||
<Modal open={pdfModalOpen} onOpenChange={setPdfModalOpen}>
|
||||
<ModalContent size="xl" className="rounded-sm p-4">
|
||||
<ModalTitle>
|
||||
{activePdf ? activePdf.replace(/\.pdf$/i, "") : "PDF Notu"}
|
||||
{activePdf ? activePdf.replace(/\.pdf$/i, "") : t("pdfModalDefaultTitle")}
|
||||
</ModalTitle>
|
||||
|
||||
<div className="mt-3 flex flex-wrap items-center justify-between gap-2">
|
||||
@@ -187,7 +190,7 @@ export function ContentContent({
|
||||
setActivePdfIndex((prev) => Math.max(0, prev - 1))
|
||||
}
|
||||
>
|
||||
Önceki
|
||||
{t("prev")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -200,7 +203,7 @@ export function ContentContent({
|
||||
)
|
||||
}
|
||||
>
|
||||
Sonraki
|
||||
{t("next")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -216,7 +219,7 @@ export function ContentContent({
|
||||
) : (
|
||||
<Card className="mt-3 rounded-sm border-border p-3">
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
`/public/pdf` içinde PDF bulunamadı.
|
||||
{t("pdfNotFound")}
|
||||
</Typography>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
@@ -5,12 +5,14 @@ import { useCallback, useEffect, useState } from "react";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Typography } from "poyraz-ui/atoms";
|
||||
import { StaggerContainer, StaggerItem } from "@/components/motion-wrapper";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
type GalleryContentProps = {
|
||||
images: string[];
|
||||
};
|
||||
|
||||
export function GalleryContent({ images }: GalleryContentProps) {
|
||||
const t = useTranslations("Gallery");
|
||||
const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
|
||||
|
||||
// Keyboard navigation for lightbox
|
||||
@@ -53,7 +55,7 @@ export function GalleryContent({ images }: GalleryContentProps) {
|
||||
<section className="flex h-full items-center justify-center">
|
||||
<div className="rounded-xl border border-dashed border-border py-20 px-10 text-center">
|
||||
<Typography variant="muted">
|
||||
Henüz galeriye görsel eklenmemiş.
|
||||
{t("empty")}
|
||||
</Typography>
|
||||
</div>
|
||||
</section>
|
||||
@@ -95,7 +97,7 @@ export function GalleryContent({ images }: GalleryContentProps) {
|
||||
type="button"
|
||||
className="absolute top-4 right-4 z-10 flex h-12 w-12 cursor-pointer items-center justify-center rounded-full bg-zinc-100 text-zinc-900 transition-colors hover:bg-zinc-200 shadow-sm border border-zinc-200"
|
||||
onClick={closeLightbox}
|
||||
aria-label="Kapat"
|
||||
aria-label={t("close")}
|
||||
>
|
||||
<Icon icon="mdi:close" width={24} height={24} />
|
||||
</button>
|
||||
@@ -109,7 +111,7 @@ export function GalleryContent({ images }: GalleryContentProps) {
|
||||
e.stopPropagation();
|
||||
setLightboxIndex(lightboxIndex - 1);
|
||||
}}
|
||||
aria-label="Önceki"
|
||||
aria-label={t("prev")}
|
||||
>
|
||||
<Icon icon="mdi:chevron-left" width={32} height={32} />
|
||||
</button>
|
||||
@@ -124,7 +126,7 @@ export function GalleryContent({ images }: GalleryContentProps) {
|
||||
e.stopPropagation();
|
||||
setLightboxIndex(lightboxIndex + 1);
|
||||
}}
|
||||
aria-label="Sonraki"
|
||||
aria-label={t("next")}
|
||||
>
|
||||
<Icon icon="mdi:chevron-right" width={32} height={32} />
|
||||
</button>
|
||||
|
||||
@@ -4,6 +4,7 @@ import Image from "next/image";
|
||||
import { useRef, useState } from "react";
|
||||
import { Card, Typography } from "poyraz-ui/atoms";
|
||||
import { NewsCard } from "poyraz-ui/molecules";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
type HomeHeroProps = {
|
||||
news: {
|
||||
@@ -19,6 +20,7 @@ type HomeHeroProps = {
|
||||
export function HomeHero({ news }: HomeHeroProps) {
|
||||
const [frame, setFrame] = useState<1 | 2>(1);
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
const t = useTranslations("Home");
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (intervalRef.current) return;
|
||||
@@ -62,8 +64,7 @@ export function HomeHero({ news }: HomeHeroProps) {
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
Teknolojiyi merak eden bir genç. Yazılım geliştirme, yapay zeka ve
|
||||
teknoloji dünyasındaki gelişmeleri takip ediyor.
|
||||
{t("role")}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import { Icon } from "@iconify/react";
|
||||
import Link from "next/link";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useMemo, useState } from "react";
|
||||
import {
|
||||
Avatar,
|
||||
@@ -23,15 +23,6 @@ import {
|
||||
|
||||
type CategoryFilter = "all" | LinkDirectoryCategory;
|
||||
|
||||
const FILTER_ITEMS: ReadonlyArray<{ id: CategoryFilter; label: string }> = [
|
||||
{ id: "all", label: "Tüm kategoriler" },
|
||||
...LINK_DIRECTORY_CATEGORIES,
|
||||
];
|
||||
|
||||
const CATEGORY_LABELS = Object.fromEntries(
|
||||
LINK_DIRECTORY_CATEGORIES.map((item) => [item.id, item.label]),
|
||||
) as Record<(typeof LINK_DIRECTORY_CATEGORIES)[number]["id"], string>;
|
||||
|
||||
const CATEGORY_ORDER = {
|
||||
resources: 0,
|
||||
navigation: 1,
|
||||
@@ -67,9 +58,20 @@ function formatHref(href: string) {
|
||||
}
|
||||
|
||||
export function LinksContent() {
|
||||
const t = useTranslations("Links");
|
||||
const tNav = useTranslations("Nav");
|
||||
|
||||
const [activeCategory, setActiveCategory] = useState<CategoryFilter>("all");
|
||||
const [query, setQuery] = useState("");
|
||||
|
||||
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());
|
||||
const queryTokens = normalizedQuery.split(/\s+/).filter(Boolean);
|
||||
@@ -84,12 +86,17 @@ export function LinksContent() {
|
||||
}
|
||||
|
||||
const haystack = normalize(
|
||||
[item.label, item.href, CATEGORY_LABELS[item.category], ...item.keywords].join(" "),
|
||||
[
|
||||
tNav.has(item.id) ? tNav(item.id) : item.label,
|
||||
item.href,
|
||||
t(`categories.${item.category}`),
|
||||
...item.keywords,
|
||||
].join(" "),
|
||||
);
|
||||
|
||||
return queryTokens.every((token) => haystack.includes(token));
|
||||
});
|
||||
}, [activeCategory, query]);
|
||||
}, [activeCategory, query, t, tNav]);
|
||||
|
||||
return (
|
||||
<section className="relative isolate min-h-dvh overflow-hidden px-4 py-8 sm:px-6 sm:py-10">
|
||||
@@ -128,8 +135,7 @@ export function LinksContent() {
|
||||
</div>
|
||||
|
||||
<Typography variant="small" className="max-w-lg text-sm leading-6 text-muted-foreground">
|
||||
Burada sosyal hesaplarım, portfolyo sayfalarım ve hızlı erişim linklerimin
|
||||
tamamı tek yerde duruyor. Direkt açıp paylaşabilirsin.
|
||||
{t("desc")}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
@@ -165,7 +171,7 @@ export function LinksContent() {
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
<Typography variant="large" className="truncate text-base">
|
||||
{item.label}
|
||||
{tNav.has(item.id) ? tNav(item.id) : item.label}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="small"
|
||||
@@ -183,10 +189,10 @@ export function LinksContent() {
|
||||
<div className="space-y-3 pt-1">
|
||||
<div>
|
||||
<Typography variant="large" className="text-base">
|
||||
Tüm Linkler
|
||||
{t("allLinks")}
|
||||
</Typography>
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
Sayfalar, kaynaklar ve sosyal profiller
|
||||
{t("allLinksDesc")}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
@@ -196,10 +202,10 @@ export function LinksContent() {
|
||||
onValueChange={(value) => setActiveCategory(value as CategoryFilter)}
|
||||
>
|
||||
<SelectTrigger className="h-11 rounded-2xl border-border bg-background px-4 text-sm">
|
||||
<SelectValue placeholder="Kategori seç" />
|
||||
<SelectValue placeholder={t("selectCategory")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{FILTER_ITEMS.map((item) => (
|
||||
{filterItems.map((item) => (
|
||||
<SelectItem key={item.id} value={item.id}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
@@ -210,8 +216,8 @@ export function LinksContent() {
|
||||
<Input
|
||||
value={query}
|
||||
onChange={(event) => setQuery(event.target.value)}
|
||||
placeholder="Link ara... github, medium, /blog"
|
||||
aria-label="Linklerde arama"
|
||||
placeholder={t("searchPlaceholder")}
|
||||
aria-label={t("allLinks")}
|
||||
className="h-11 rounded-2xl"
|
||||
/>
|
||||
</div>
|
||||
@@ -234,10 +240,10 @@ export function LinksContent() {
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Typography variant="large" className="text-base leading-tight">
|
||||
{item.label}
|
||||
{tNav.has(item.id) ? tNav(item.id) : item.label}
|
||||
</Typography>
|
||||
<span className="inline-flex rounded-full border border-border px-2.5 py-0.5 text-[11px] text-muted-foreground">
|
||||
{CATEGORY_LABELS[item.category]}
|
||||
{t(`categories.${item.category}`)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -264,7 +270,7 @@ export function LinksContent() {
|
||||
{filteredItems.length === 0 ? (
|
||||
<Card className="rounded-2xl border-border px-4 py-5">
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
Seçili filtreye uygun link bulunamadı.
|
||||
{t("empty")}
|
||||
</Typography>
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Icon } from "@iconify/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
import {
|
||||
CommandPalette,
|
||||
CommandPaletteContent,
|
||||
@@ -15,7 +16,7 @@ import {
|
||||
CommandPaletteSeparator,
|
||||
} from "poyraz-ui/molecules";
|
||||
import {
|
||||
COMMAND_PALETTE_GROUPS,
|
||||
getCommandPaletteGroups,
|
||||
type CommandPaletteItem as PaletteItem,
|
||||
} from "@/lib/command-palette-links";
|
||||
import { useKeyboardShortcutLabel } from "@/lib/use-keyboard-shortcut-label";
|
||||
@@ -27,8 +28,17 @@ type SearchCommandProps = {
|
||||
|
||||
export function SearchCommand({ open, onOpenChange }: SearchCommandProps) {
|
||||
const router = useRouter();
|
||||
const locale = useLocale();
|
||||
const tLinks = useTranslations("Links");
|
||||
const tNav = useTranslations("Nav");
|
||||
const t = useTranslations("SearchCommand");
|
||||
const shortcut = useKeyboardShortcutLabel();
|
||||
const [query, setQuery] = useState("");
|
||||
|
||||
const groups = useMemo(() => {
|
||||
return getCommandPaletteGroups(locale, tLinks, tNav);
|
||||
}, [locale, tLinks, tNav]);
|
||||
|
||||
const handleOpenChange = useCallback((nextOpen: boolean) => {
|
||||
if (!nextOpen) {
|
||||
setQuery("");
|
||||
@@ -51,11 +61,11 @@ export function SearchCommand({ open, onOpenChange }: SearchCommandProps) {
|
||||
|
||||
const filteredGroups = useMemo(() => {
|
||||
const value = query.trim().toLowerCase();
|
||||
if (!value) return COMMAND_PALETTE_GROUPS;
|
||||
if (!value) return groups;
|
||||
|
||||
const tokens = value.split(/\s+/).filter(Boolean);
|
||||
|
||||
return COMMAND_PALETTE_GROUPS.map((group) => ({
|
||||
return groups.map((group) => ({
|
||||
...group,
|
||||
items: group.items.filter((item) => {
|
||||
const haystack = [
|
||||
@@ -70,7 +80,7 @@ export function SearchCommand({ open, onOpenChange }: SearchCommandProps) {
|
||||
return tokens.every((token) => haystack.includes(token));
|
||||
}),
|
||||
})).filter((group) => group.items.length > 0);
|
||||
}, [query]);
|
||||
}, [query, groups]);
|
||||
|
||||
const handleCommandSelect = (item: PaletteItem) => {
|
||||
handleOpenChange(false);
|
||||
@@ -87,13 +97,13 @@ export function SearchCommand({ open, onOpenChange }: SearchCommandProps) {
|
||||
<CommandPalette open={open} onOpenChange={handleOpenChange}>
|
||||
<CommandPaletteContent className=" rounded-none p-0 pt-3 w-72 sm:w-full sm:max-w-xl sm:rounded-sm sm:p-0 sm:pt-2">
|
||||
<CommandPaletteInput
|
||||
placeholder="Sayfa ve bağlantılarda ara..."
|
||||
placeholder={t("placeholder")}
|
||||
className="mt-2 pr-10"
|
||||
onValueChange={setQuery}
|
||||
/>
|
||||
<CommandPaletteList>
|
||||
{filteredGroups.length === 0 ? (
|
||||
<CommandPaletteEmpty>Sonuç bulunamadı.</CommandPaletteEmpty>
|
||||
<CommandPaletteEmpty>{t("empty")}</CommandPaletteEmpty>
|
||||
) : (
|
||||
filteredGroups.map((group, index) => (
|
||||
<div key={group.id}>
|
||||
@@ -115,7 +125,7 @@ export function SearchCommand({ open, onOpenChange }: SearchCommandProps) {
|
||||
)}
|
||||
</CommandPaletteList>
|
||||
<CommandPaletteFooter className="text-xs text-muted-foreground">
|
||||
Hızlıca açmak için {shortcut} kullan
|
||||
{t("footer", { shortcut })}
|
||||
</CommandPaletteFooter>
|
||||
</CommandPaletteContent>
|
||||
</CommandPalette>
|
||||
|
||||
+17
-14
@@ -2,8 +2,9 @@
|
||||
|
||||
import { Icon } from "@iconify/react";
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Link, usePathname } from "@/i18n/routing";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { LanguageSwitcher } from "@/components/language-switcher";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Avatar,
|
||||
@@ -45,6 +46,7 @@ export function SiteNavbar() {
|
||||
const pathname = usePathname();
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
const shortcut = useKeyboardShortcutLabel();
|
||||
const t = useTranslations("Nav");
|
||||
|
||||
const isActiveLink = (href: string) => {
|
||||
if (href === "/") return pathname === "/";
|
||||
@@ -60,13 +62,14 @@ export function SiteNavbar() {
|
||||
href={item.href}
|
||||
target={item.external ? "_blank" : undefined}
|
||||
rel={item.external ? "noreferrer" : undefined}
|
||||
aria-label={item.label}
|
||||
title={item.label}
|
||||
aria-label={t.has(item.id) ? t(item.id) : item.label}
|
||||
title={t.has(item.id) ? t(item.id) : item.label}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-sm border border-border text-muted-foreground transition-colors hover:text-foreground"
|
||||
>
|
||||
<Icon icon={item.icon} width={16} height={16} />
|
||||
</Link>
|
||||
))}
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
|
||||
<header className="flex items-center justify-between gap-3 border-b border-border pb-4">
|
||||
@@ -99,7 +102,7 @@ export function SiteNavbar() {
|
||||
href={item.href}
|
||||
className={getNavLinkClass(isActiveLink(item.href))}
|
||||
>
|
||||
{item.label}
|
||||
{t(item.id)}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
@@ -115,11 +118,11 @@ export function SiteNavbar() {
|
||||
type="button"
|
||||
onClick={() => setSearchOpen(true)}
|
||||
className="inline-flex h-8 w-44 cursor-pointer items-center justify-between rounded-sm border border-border px-2.5 text-sm text-muted-foreground transition-colors hover:text-foreground sm:w-52"
|
||||
aria-label="Komut paletini aç"
|
||||
aria-label={t("search")}
|
||||
>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<Icon icon="mdi:magnify" width={16} height={16} />
|
||||
<span>Ara</span>
|
||||
<span>{t("search")}</span>
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">{shortcut}</span>
|
||||
</button>
|
||||
@@ -127,10 +130,10 @@ export function SiteNavbar() {
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger className="inline-flex h-8 cursor-pointer items-center gap-2 rounded-sm border border-border px-2.5 text-sm text-muted-foreground transition-colors hover:text-foreground">
|
||||
<Icon icon="mdi:share-variant" width={16} height={16} />
|
||||
<span>Sosyal</span>
|
||||
<span>{t("social")}</span>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-52 rounded-sm">
|
||||
<DropdownMenuLabel>Sosyal Bağlantılar</DropdownMenuLabel>
|
||||
<DropdownMenuLabel>{t("socialLinks")}</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{SOCIAL_LINKS.map((item) => (
|
||||
<DropdownMenuItem key={item.id} asChild>
|
||||
@@ -153,21 +156,21 @@ export function SiteNavbar() {
|
||||
<Sheet>
|
||||
<SheetTrigger className="inline-flex h-8 cursor-pointer items-center gap-2 rounded-sm border border-border px-2.5 text-sm text-muted-foreground transition-colors hover:text-foreground">
|
||||
<Icon icon="mdi:menu" width={18} height={18} />
|
||||
<span>Menü</span>
|
||||
<span>{t("menu")}</span>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="right" className="w-72 p-4">
|
||||
<SheetTitle className="sr-only">Mobil Menü</SheetTitle>
|
||||
<SheetTitle className="sr-only">{t("mobileMenu")}</SheetTitle>
|
||||
<div className="flex flex-col gap-4">
|
||||
<SheetClose asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSearchOpen(true)}
|
||||
className="inline-flex h-9 w-full cursor-pointer items-center justify-between rounded-sm border border-border px-3 text-sm text-muted-foreground transition-colors hover:text-foreground"
|
||||
aria-label="Komut paletini aç"
|
||||
aria-label={t("search")}
|
||||
>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<Icon icon="mdi:magnify" width={16} height={16} />
|
||||
<span>Ara</span>
|
||||
<span>{t("search")}</span>
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground/80">
|
||||
{shortcut}
|
||||
@@ -186,7 +189,7 @@ export function SiteNavbar() {
|
||||
href={item.href}
|
||||
className={getNavLinkClass(isActiveLink(item.href))}
|
||||
>
|
||||
{item.label}
|
||||
{t(item.id)}
|
||||
</Link>
|
||||
</SheetClose>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user