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 (