fix: compact filter popover; feat: i18n (de/en)
Build & Push Docker Image / build (push) Successful in 2m31s
Build & Push Docker Image / build (push) Successful in 2m31s
This commit is contained in:
@@ -1,28 +1,31 @@
|
||||
import { Link, useLocation } from "wouter";
|
||||
import { LayoutDashboard, Wrench, PlusCircle, BarChart3, LogIn, LogOut, User, ShieldCheck, AlertTriangle, Trash2, Bookmark } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useGetVersion, getGetVersionQueryKey } from "@workspace/api-client-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { ThemeToggle } from "@/components/theme-toggle";
|
||||
import { CommandPalette } from "@/components/command-palette";
|
||||
import { LanguageSwitcher } from "@/components/language-switcher";
|
||||
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
const [location] = useLocation();
|
||||
const { t } = useTranslation();
|
||||
const { user, isLoading, isAuthenticated, isAdmin, isLocalMode, tier, hasFeature, login, logout } = useAuth();
|
||||
const { data: version } = useGetVersion({
|
||||
query: { queryKey: getGetVersionQueryKey(), staleTime: Infinity, retry: false },
|
||||
});
|
||||
|
||||
const links = [
|
||||
{ href: "/", label: "Dashboard", icon: LayoutDashboard },
|
||||
{ href: "/tools", label: "Browse Tools", icon: Wrench },
|
||||
{ href: "/tools/new", label: "Add Tool", icon: PlusCircle },
|
||||
{ href: "/analytics", label: "Analytics", icon: BarChart3 },
|
||||
...(hasFeature("watchlist") ? [{ href: "/watchlist", label: "Watchlist", icon: Bookmark }] : []),
|
||||
...(hasFeature("trash") ? [{ href: "/trash", label: "Trash", icon: Trash2 }] : []),
|
||||
...(isAdmin ? [{ href: "/admin", label: "Admin", icon: ShieldCheck }] : []),
|
||||
...(isAdmin ? [{ href: "/admin/redundancy", label: "Redundancy", icon: AlertTriangle }] : []),
|
||||
{ href: "/", label: t("nav.home"), icon: LayoutDashboard },
|
||||
{ href: "/tools", label: t("nav.browseTools"), icon: Wrench },
|
||||
{ href: "/tools/new", label: t("nav.addTool"), icon: PlusCircle },
|
||||
{ href: "/analytics", label: t("nav.analytics"), icon: BarChart3 },
|
||||
...(hasFeature("watchlist") ? [{ href: "/watchlist", label: t("nav.watchlist"), icon: Bookmark }] : []),
|
||||
...(hasFeature("trash") ? [{ href: "/trash", label: t("nav.trash"), icon: Trash2 }] : []),
|
||||
...(isAdmin ? [{ href: "/admin", label: t("nav.admin"), icon: ShieldCheck }] : []),
|
||||
...(isAdmin ? [{ href: "/admin/redundancy", label: t("nav.redundancy"), icon: AlertTriangle }] : []),
|
||||
];
|
||||
|
||||
const activeLink = links.find(
|
||||
@@ -30,11 +33,11 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
);
|
||||
|
||||
const mobileLinks = [
|
||||
{ href: "/", label: "Home", icon: LayoutDashboard },
|
||||
{ href: "/tools", label: "Tools", icon: Wrench },
|
||||
...(hasFeature("watchlist") ? [{ href: "/watchlist", label: "Watchlist", icon: Bookmark }] : []),
|
||||
...(hasFeature("trash") ? [{ href: "/trash", label: "Trash", icon: Trash2 }] : []),
|
||||
{ href: "/analytics", label: "Analytics", icon: BarChart3 },
|
||||
{ href: "/", label: t("nav.home"), icon: LayoutDashboard },
|
||||
{ href: "/tools", label: t("nav.browseTools"), icon: Wrench },
|
||||
...(hasFeature("watchlist") ? [{ href: "/watchlist", label: t("nav.watchlist"), icon: Bookmark }] : []),
|
||||
...(hasFeature("trash") ? [{ href: "/trash", label: t("nav.trash"), icon: Trash2 }] : []),
|
||||
{ href: "/analytics", label: t("nav.analytics"), icon: BarChart3 },
|
||||
].slice(0, 5);
|
||||
|
||||
return (
|
||||
@@ -94,7 +97,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
data-testid="button-logout"
|
||||
>
|
||||
<LogOut className="w-4 h-4" />
|
||||
Sign out
|
||||
{t("auth.signOut")}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -106,7 +109,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
data-testid="button-login"
|
||||
>
|
||||
<LogIn className="w-4 h-4" />
|
||||
{isLocalMode ? "Sign in" : "Sign in with Keycloak"}
|
||||
{isLocalMode ? t("auth.signIn") : t("auth.signInKeycloak")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -135,7 +138,10 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
<h1 className="text-sm font-semibold text-muted-foreground">
|
||||
{activeLink?.label ?? "toolr"}
|
||||
</h1>
|
||||
<ThemeToggle />
|
||||
<div className="flex items-center gap-1">
|
||||
<LanguageSwitcher />
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</header>
|
||||
<header className="md:hidden border-b p-4 flex items-center justify-between bg-card">
|
||||
<Link href="/" className="flex items-center gap-2 text-primary font-bold text-lg">
|
||||
@@ -143,6 +149,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
<span>toolr</span>
|
||||
</Link>
|
||||
<div className="flex items-center gap-1">
|
||||
<LanguageSwitcher />
|
||||
<ThemeToggle />
|
||||
{!isLoading && (
|
||||
isAuthenticated ? (
|
||||
@@ -152,7 +159,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
|
||||
) : (
|
||||
<Button variant="outline" size="sm" onClick={() => login(location)} data-testid="button-login-mobile">
|
||||
<LogIn className="w-4 h-4 mr-1" />
|
||||
Sign in
|
||||
{t("auth.signIn")}
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user