From fc9d685651088bdd18023e664420d8eced6c88ce Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 19 Jun 2026 21:34:04 +0000 Subject: [PATCH] Fix page titles, dropdown stacking, bookmark editing, and button/select polish - Add missing pageTitles entries so Tunnels, Files, Containers, Remote Desktop, and Host Metrics no longer show "Glance" in the top bar - Raise the TopBar's stacking context above the page-content section so the user-menu dropdown no longer renders behind the hero banner - Support editing and deleting bookmarks (not just adding), via a shared BookmarkModal and per-row edit/delete actions in BookNest - Standardize dropdown panels are OS/browser-rendered and ignore most component styling — without this, options render with a white background - and near-white text, making them unreadable against this dark theme. */ + and near-white text, making them unreadable against this dark theme. + The !important rules below standardize every select's closed-state look + (gold-tinted border, consistent padding/radius) on top of whatever + per-page inline style happens to be set, so dropdowns read as "premium" + and consistent app-wide without having to touch every page. */ select { color-scheme: dark; + border: 1px solid rgba(200, 164, 52, 0.18) !important; + border-radius: 8px !important; + padding: 9px 12px !important; + background-color: rgba(255, 255, 255, 0.04) !important; + cursor: pointer; + transition: border-color 0.15s ease, box-shadow 0.15s ease; +} + +select:hover { + border-color: rgba(200, 164, 52, 0.35) !important; +} + +select:focus { + outline: none; + border-color: rgba(200, 164, 52, 0.55) !important; + box-shadow: 0 0 0 3px rgba(200, 164, 52, 0.1); } select option { diff --git a/src/pages/BookNest.tsx b/src/pages/BookNest.tsx index 7bf7dc9..0d99535 100644 --- a/src/pages/BookNest.tsx +++ b/src/pages/BookNest.tsx @@ -39,6 +39,8 @@ import { Globe2, Container, X, + Pencil, + Trash2, type LucideIcon, } from 'lucide-react' import { api, ApiError, type Bookmark, type BookmarkCategory } from '../lib/api' @@ -187,7 +189,17 @@ function Donut({ data, centerLabel }: { data: { name: string; value: number; col ) } -function LinkRow({ bookmark, onToggleFavorite }: { bookmark: Bookmark; onToggleFavorite: () => void }) { +function LinkRow({ + bookmark, + onToggleFavorite, + onEdit, + onDelete, +}: { + bookmark: Bookmark + onToggleFavorite: () => void + onEdit: () => void + onDelete: () => void +}) { return (
{bookmark.title} - +
+ + + +
) } -function AddBookmarkModal({ +function BookmarkModal({ categories, + bookmark, onClose, onCreated, + onUpdated, onCategoryCreated, }: { categories: BookmarkCategory[] + bookmark?: Bookmark onClose: () => void onCreated: (bookmark: Bookmark) => void + onUpdated: (bookmark: Bookmark) => void onCategoryCreated: (category: BookmarkCategory) => void }) { - const [title, setTitle] = useState('') - const [url, setUrl] = useState('') - const [icon, setIcon] = useState('link2') - const [iconMode, setIconMode] = useState<'auto' | 'manual'>('auto') - const [categoryId, setCategoryId] = useState('') + const isEdit = !!bookmark + const [title, setTitle] = useState(bookmark?.title ?? '') + const [url, setUrl] = useState(bookmark?.url ?? '') + const [icon, setIcon] = useState(bookmark?.icon ?? 'link2') + const [iconMode, setIconMode] = useState<'auto' | 'manual'>(isIconUrl(bookmark?.icon) || !bookmark ? 'auto' : 'manual') + const [categoryId, setCategoryId] = useState(bookmark?.category_id ?? '') const [newCategoryName, setNewCategoryName] = useState('') const [error, setError] = useState('') const [busy, setBusy] = useState(false) @@ -258,26 +288,36 @@ function AddBookmarkModal({ } else if (categoryId !== '') { resolvedCategoryId = categoryId } - const { id } = await api.createBookmark({ - title: title.trim(), - url: url.trim(), - icon, - categoryId: resolvedCategoryId, - }) - onCreated({ - id, - category_id: resolvedCategoryId, - title: title.trim(), - url: url.trim(), - icon, - favorite: 0, - status: 'unknown', - last_checked_at: null, - created_at: new Date().toISOString(), - }) + if (isEdit && bookmark) { + await api.updateBookmark(bookmark.id, { + title: title.trim(), + url: url.trim(), + icon, + categoryId: resolvedCategoryId, + }) + onUpdated({ ...bookmark, title: title.trim(), url: url.trim(), icon, category_id: resolvedCategoryId }) + } else { + const { id } = await api.createBookmark({ + title: title.trim(), + url: url.trim(), + icon, + categoryId: resolvedCategoryId, + }) + onCreated({ + id, + category_id: resolvedCategoryId, + title: title.trim(), + url: url.trim(), + icon, + favorite: 0, + status: 'unknown', + last_checked_at: null, + created_at: new Date().toISOString(), + }) + } onClose() } catch (err) { - setError(err instanceof ApiError ? err.message : 'Failed to create bookmark') + setError(err instanceof ApiError ? err.message : `Failed to ${isEdit ? 'update' : 'create'} bookmark`) } finally { setBusy(false) } @@ -295,7 +335,7 @@ function AddBookmarkModal({ style={{ ...cardBase, width: '420px', padding: '24px', gap: '14px' }} >
-

Add Bookmark

+

{isEdit ? 'Edit Bookmark' : 'Add Bookmark'}

@@ -395,7 +435,7 @@ function AddBookmarkModal({ marginTop: '4px', }} > - {busy ? 'Saving…' : 'Add Bookmark'} + {busy ? 'Saving…' : isEdit ? 'Save Changes' : 'Add Bookmark'}
@@ -406,6 +446,7 @@ export default function BookNest() { const [bookmarks, setBookmarks] = useState(null) const [categories, setCategories] = useState([]) const [showAddModal, setShowAddModal] = useState(false) + const [editingBookmark, setEditingBookmark] = useState(null) useEffect(() => { Promise.all([api.listBookmarks(), api.listBookmarkCategories()]).then(([b, c]) => { @@ -414,6 +455,16 @@ export default function BookNest() { }) }, []) + async function deleteBookmark(bookmark: Bookmark) { + if (!window.confirm(`Delete "${bookmark.title}"?`)) return + setBookmarks((prev) => prev?.filter((b) => b.id !== bookmark.id) ?? prev) + try { + await api.deleteBookmark(bookmark.id) + } catch { + setBookmarks((prev) => (prev ? [...prev, bookmark] : prev)) + } + } + async function toggleFavorite(bookmark: Bookmark) { const next = bookmark.favorite ? false : true setBookmarks((prev) => prev?.map((b) => (b.id === bookmark.id ? { ...b, favorite: next ? 1 : 0 } : b)) ?? prev) @@ -478,11 +529,13 @@ export default function BookNest() { return (
- {showAddModal && ( - setShowAddModal(false)} + bookmark={editingBookmark ?? undefined} + onClose={() => { setShowAddModal(false); setEditingBookmark(null) }} onCreated={(b) => setBookmarks((prev) => [b, ...(prev ?? [])])} + onUpdated={(b) => setBookmarks((prev) => prev?.map((x) => (x.id === b.id ? b : x)) ?? prev)} onCategoryCreated={(c) => setCategories((prev) => [...prev, c])} /> )} @@ -549,7 +602,13 @@ export default function BookNest() {

{group.title}

{group.links.map((link) => ( - toggleFavorite(link)} /> + toggleFavorite(link)} + onEdit={() => setEditingBookmark(link)} + onDelete={() => deleteBookmark(link)} + /> ))}
diff --git a/src/pages/Containers.tsx b/src/pages/Containers.tsx index 256bb11..46c765e 100644 --- a/src/pages/Containers.tsx +++ b/src/pages/Containers.tsx @@ -146,8 +146,8 @@ export default function Containers() { diff --git a/src/pages/Files.tsx b/src/pages/Files.tsx index 05de482..30a4e36 100644 --- a/src/pages/Files.tsx +++ b/src/pages/Files.tsx @@ -295,15 +295,15 @@ export default function Files() { ))}
- -