dev #55

Merged
root merged 17 commits from dev into main 2026-05-26 23:42:29 +03:00
3 changed files with 74 additions and 31 deletions
Showing only changes of commit 681a25ec2e - Show all commits

View File

@@ -0,0 +1,67 @@
import { type Locale, useTranslation } from "@/lib/i18n";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@sase/ui";
import { Check, Globe } from "lucide-react";
const LOCALES: { code: Locale; label: string; name: string }[] = [
{ code: "tr", label: "TR", name: "Türkçe" },
{ code: "en", label: "EN", name: "English" },
];
/**
* Language switcher wired to the i18n store.
* - `inline`: segmented TR/EN row (footer)
* - `dropdown`: round Globe icon button + menu (app header)
*/
export function LanguageSwitcher({ variant = "inline" }: { variant?: "inline" | "dropdown" }) {
const { t, locale, setLocale } = useTranslation();
if (variant === "dropdown") {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
aria-label={t("footer.language")}
className="flex size-9 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
>
<Globe className="size-4" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-40">
{LOCALES.map(({ code, name }) => (
<DropdownMenuItem
key={code}
onSelect={() => setLocale(code)}
className="justify-between"
>
{name}
{locale === code && <Check className="size-4 text-brand" />}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
}
return (
// biome-ignore lint/a11y/useSemanticElements: a button group, not a form fieldset; role="group" is the correct ARIA here
<div className="flex items-center gap-1 text-sm" role="group" aria-label={t("footer.language")}>
<Globe className="mr-1 size-4 text-muted-foreground" aria-hidden="true" />
{LOCALES.map(({ code, label }) => (
<button
key={code}
type="button"
onClick={() => setLocale(code)}
aria-pressed={locale === code}
className={`rounded-md px-2 py-1 transition-colors ${
locale === code
? "font-semibold text-foreground"
: "text-muted-foreground hover:text-foreground"
}`}
>
{label}
</button>
))}
</div>
);
}

View File

@@ -1,12 +1,8 @@
import { type Locale, useTranslation } from "@/lib/i18n";
import { LanguageSwitcher } from "@/components/language-switcher";
import { useTranslation } from "@/lib/i18n";
import { Separator } from "@sase/ui";
import { Link } from "@tanstack/react-router";
import { Facebook, Globe, Instagram, Linkedin } from "lucide-react";
const LOCALES: { code: Locale; label: string }[] = [
{ code: "tr", label: "TR" },
{ code: "en", label: "EN" },
];
import { Facebook, Instagram, Linkedin } from "lucide-react";
const SOCIALS: {
label: string;
@@ -23,29 +19,7 @@ const SOCIALS: {
];
export function SiteFooter({ variant = "full" }: { variant?: "full" | "compact" }) {
const { t, locale, setLocale } = useTranslation();
const languageSwitcher = (
// biome-ignore lint/a11y/useSemanticElements: a button group, not a form fieldset; role="group" is the correct ARIA here
<div className="flex items-center gap-1 text-sm" role="group" aria-label={t("footer.language")}>
<Globe className="mr-1 size-4 text-muted-foreground" aria-hidden="true" />
{LOCALES.map(({ code, label }) => (
<button
key={code}
type="button"
onClick={() => setLocale(code)}
aria-pressed={locale === code}
className={`rounded-md px-2 py-1 transition-colors ${
locale === code
? "font-semibold text-foreground"
: "text-muted-foreground hover:text-foreground"
}`}
>
{label}
</button>
))}
</div>
);
const { t } = useTranslation();
// Compact variant — single line for app/dashboard layouts.
if (variant === "compact") {
@@ -183,7 +157,7 @@ export function SiteFooter({ variant = "full" }: { variant?: "full" | "compact"
<p className="text-sm text-muted-foreground">
&copy; {new Date().getFullYear()} Sase.tr. {t("footer.rights")}
</p>
{languageSwitcher}
<LanguageSwitcher variant="inline" />
</div>
</div>
</footer>

View File

@@ -1,3 +1,4 @@
import { LanguageSwitcher } from "@/components/language-switcher";
import { SiteFooter } from "@/components/site-footer";
import { TrialUrgencyBanner } from "@/components/trial-urgency-banner";
import { useAuth } from "@/hooks/use-auth";
@@ -493,6 +494,7 @@ function DashboardLayout() {
</Button>
</Link>
)}
<LanguageSwitcher variant="dropdown" />
<button
type="button"
onClick={toggleTheme}