diff --git a/apps/frontend/src/components/ScrollToTopButton.tsx b/apps/frontend/src/components/ScrollToTopButton.tsx index f0133d8..ce3740b 100644 --- a/apps/frontend/src/components/ScrollToTopButton.tsx +++ b/apps/frontend/src/components/ScrollToTopButton.tsx @@ -1,4 +1,6 @@ import { useEffect, useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faArrowUp } from "@fortawesome/free-solid-svg-icons"; /** * Schwebender Button unten rechts, der zum Seitenanfang zurückscrollt. @@ -29,7 +31,7 @@ export function ScrollToTopButton() { transition-opacity hover:bg-white dark:border-white/10 dark:bg-neutral-900/90 dark:text-white/70 dark:hover:bg-neutral-900" > - ⬆️ + ); } diff --git a/apps/frontend/src/routes/HomePage.tsx b/apps/frontend/src/routes/HomePage.tsx index c68b37e..cf0b9cd 100644 --- a/apps/frontend/src/routes/HomePage.tsx +++ b/apps/frontend/src/routes/HomePage.tsx @@ -2,6 +2,8 @@ import { useEffect, useMemo, useRef, useState, type FormEvent } from "react"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Link } from "@tanstack/react-router"; import { SearchInput, StatusBadge, ResultsList, FavoritesBar, Favicon, Button } from "@launchpad/ui"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faGear, faSun, faMoon } from "@fortawesome/free-solid-svg-icons"; import { rankServices, type SearchResult } from "@launchpad/shared"; import { useServices } from "../hooks/useServices.js"; import { useBookmarks } from "../hooks/useBookmarks.js"; @@ -248,7 +250,7 @@ export function HomePage() { className="rounded-full border border-black/10 p-2 text-black/60 transition-colors hover:bg-black/5 dark:border-white/10 dark:text-white/60 dark:hover:bg-white/5" > - ⚙️ + diff --git a/apps/frontend/src/routes/admin/AdminLayout.tsx b/apps/frontend/src/routes/admin/AdminLayout.tsx index d93c475..d6b0138 100644 --- a/apps/frontend/src/routes/admin/AdminLayout.tsx +++ b/apps/frontend/src/routes/admin/AdminLayout.tsx @@ -1,22 +1,39 @@ import { useEffect, useState } from "react"; import { Link, Outlet, useRouterState } from "@tanstack/react-router"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import type { IconDefinition } from "@fortawesome/fontawesome-svg-core"; +import { + faBars, + faXmark, + faHouse, + faChartLine, + faDesktop, + faLink, + faBookmark, + faThumbtack, + faMagnifyingGlass, + faTag, + faPuzzlePiece, + faGear, + faScroll, +} from "@fortawesome/free-solid-svg-icons"; import { StatusBadge } from "@launchpad/ui"; import { useBackendHealth } from "../../hooks/useBackendHealth.js"; import { ScrollToTopButton } from "../../components/ScrollToTopButton.js"; -const NAV_ITEMS = [ - { to: "/", label: "Startseite", icon: "🏠" }, - { to: "/admin/dashboard", label: "Dashboard", icon: "📊" }, - { to: "/admin/devices", label: "Geräte", icon: "🖥️" }, - { to: "/admin/services", label: "Dienste", icon: "🔗" }, - { to: "/admin/bookmarks", label: "Lesezeichen", icon: "🔖" }, - { to: "/admin/read-later", label: "Später lesen", icon: "📌" }, - { to: "/admin/scanner", label: "Scanner", icon: "🔍" }, - { to: "/admin/categories", label: "Kategorien", icon: "🏷️" }, - { to: "/admin/plugins", label: "Plugins", icon: "🧩" }, - { to: "/admin/settings", label: "Einstellungen", icon: "⚙️" }, - { to: "/admin/logs", label: "Logs", icon: "📜" }, -] as const; +const NAV_ITEMS: { to: string; label: string; icon: IconDefinition }[] = [ + { to: "/", label: "Startseite", icon: faHouse }, + { to: "/admin/dashboard", label: "Dashboard", icon: faChartLine }, + { to: "/admin/devices", label: "Geräte", icon: faDesktop }, + { to: "/admin/services", label: "Dienste", icon: faLink }, + { to: "/admin/bookmarks", label: "Lesezeichen", icon: faBookmark }, + { to: "/admin/read-later", label: "Später lesen", icon: faThumbtack }, + { to: "/admin/scanner", label: "Scanner", icon: faMagnifyingGlass }, + { to: "/admin/categories", label: "Kategorien", icon: faTag }, + { to: "/admin/plugins", label: "Plugins", icon: faPuzzlePiece }, + { to: "/admin/settings", label: "Einstellungen", icon: faGear }, + { to: "/admin/logs", label: "Logs", icon: faScroll }, +]; export function AdminLayout() { const pathname = useRouterState({ select: (s) => s.location.pathname }); @@ -45,7 +62,7 @@ export function AdminLayout() { className="rounded-lg p-1.5 text-black/70 hover:bg-black/5 dark:text-white/70 dark:hover:bg-white/10" > - ☰ + @@ -84,7 +101,7 @@ export function AdminLayout() { aria-label="Menü schließen" className="rounded-lg p-1 text-black/50 hover:bg-black/5 dark:text-white/50 dark:hover:bg-white/10 sm:hidden" > - ✕ + @@ -101,7 +118,9 @@ export function AdminLayout() { : "text-black/60 hover:bg-black/5 hover:text-black dark:text-white/60 dark:hover:bg-white/5 dark:hover:text-white" }`} > - {item.icon} + + + {item.label} ); diff --git a/apps/frontend/src/routes/admin/BookmarksPage.tsx b/apps/frontend/src/routes/admin/BookmarksPage.tsx index fea3220..5d885b2 100644 --- a/apps/frontend/src/routes/admin/BookmarksPage.tsx +++ b/apps/frontend/src/routes/admin/BookmarksPage.tsx @@ -1,9 +1,11 @@ import { useMemo, useState, type DragEvent, type FormEvent } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faFloppyDisk, faPen, faTrash, faXmark } from "@fortawesome/free-solid-svg-icons"; +import { faFloppyDisk, faPen, faTrash, faXmark, faSort, faSortUp, faSortDown, faStar as faStarSolid, faEye, faEyeSlash, faArrowLeft } from "@fortawesome/free-solid-svg-icons"; +import { faStar } from "@fortawesome/free-regular-svg-icons"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Button, Favicon } from "@launchpad/ui"; import type { Bookmark } from "@launchpad/shared"; +import { suggestBookmarkCategory } from "@launchpad/shared"; import { useBookmarks } from "../../hooks/useBookmarks.js"; import { useCategories } from "../../hooks/useCategories.js"; import { AdminPageHeader } from "./AdminPageHeader.js"; @@ -16,6 +18,7 @@ interface BookmarkPatch { favorite?: boolean; alias?: string[]; order?: number; + favicon?: string | null; } async function createBookmarkRequest(input: { @@ -139,6 +142,11 @@ function AddBookmarkForm() { mutation.mutate(); } + // Kategorie-Vorschlag anhand der eingegebenen URL (rein heuristisch anhand + // des Hostnamens, siehe suggestBookmarkCategory in @launchpad/shared) - nur + // solange der Nutzer noch keine eigene Kategorie gewählt hat. + const suggestedCategory = category.trim() === "" ? suggestBookmarkCategory(url.trim()) : null; + return (
@@ -157,6 +165,15 @@ function AddBookmarkForm() { Kategorie + {suggestedCategory ? ( + + ) : null}