mirror of
https://github.com/Dvorinka/Dash.git
synced 2026-10-29 00:01:24 +00:00
feat: phase 3 renderers & ergonomics — index/console, ⌘K palette, icon suggest
- Index renderer (editorial): serif masthead + section heads, numbered full-width rows, live stat strip (time/services/up/down/widgets) - Console renderer (terminal): $ dash status banner, bordered stat panels, ## section heads, › prompt rows, [ up ]/[ down ] tags - Renderer contract gains index prop for row/section numbering - Settings: 2x2 renderer radio grid with per-renderer descriptions - ⌘K/Ctrl+K// palette: actions + service endpoints, arrow-key nav, zero-dep implementation on the existing Dialog primitive - Icon picker: dashboard-icons slug suggestion chip + live preview - Fonts: Instrument Serif, JetBrains Mono (fontsource) - Fix: global :focus-visible rule was unlayered and silently overrode all focus-visible: utilities since phase 1 — moved into @layer base Verified: typecheck/lint/build clean, dnd + collapse + popover in both new renderers, palette filter + execute, icon suggest resolves real CDN assets, 360px + light theme, docker image 43.9 MB serving board + widget types. Generated with [Devin](https://devin.ai) Authored By: TDvorak <[email protected]> Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
8afc7df53b
commit
55fb57456e
16 files changed
+803
-51
No files matched your search
@@ -10,6 +10,12 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
|
||||
// dashboard-icons CDN serves png/<slug>.png — slugify the service name for
|
||||
// the one-click suggestion under the icon field.
|
||||
const DI_BASE = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png";
|
||||
const diSlug = (name: string) =>
|
||||
name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
||||
|
||||
// One dialog for both add and edit: item present = edit, absent = add.
|
||||
export function ServiceDialog({
|
||||
open,
|
||||
@@ -164,7 +170,8 @@ export function ServiceDialog({
|
||||
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Label htmlFor="svc-icon">Icon URL</Label>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<IconPreview url={icon} />
|
||||
<Input id="svc-icon" value={icon} onChange={(e) => setIcon(e.target.value)} placeholder="https://…/icon.png" className="font-mono text-[12px]" />
|
||||
<Button type="button" variant="outline" size="icon" aria-label="Upload icon file" onClick={() => fileRef.current?.click()}>
|
||||
<Upload size={13} />
|
||||
@@ -174,6 +181,15 @@ export function ServiceDialog({
|
||||
onChange={() => setErr("")}
|
||||
/>
|
||||
</div>
|
||||
{!icon && diSlug(name) ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIcon(`${DI_BASE}/${diSlug(name)}.png`)}
|
||||
className="w-fit rounded border border-border px-1.5 py-0.5 font-mono text-[10.5px] text-text-faint transition-colors hover:border-border-strong hover:text-text"
|
||||
>
|
||||
suggest: {diSlug(name)}.png
|
||||
</button>
|
||||
) : null}
|
||||
<p className="text-[11px] text-text-faint">URL or uploaded file; blank shows a letter tile.</p>
|
||||
</div>
|
||||
|
||||
@@ -197,3 +213,21 @@ export function ServiceDialog({
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
// Small live preview for the icon URL — hides itself on load failure so a
|
||||
// dead URL reads as "no preview", not a broken image.
|
||||
function IconPreview({ url }: { url: string }) {
|
||||
const [failed, setFailed] = useState(false);
|
||||
useEffect(() => setFailed(false), [url]);
|
||||
if (!url || failed) {
|
||||
return <span className="size-[30px] shrink-0 rounded-[7px] border border-dashed border-border" />;
|
||||
}
|
||||
return (
|
||||
<img
|
||||
src={url}
|
||||
alt=""
|
||||
onError={() => setFailed(true)}
|
||||
className="size-[30px] shrink-0 rounded-[7px] border border-border bg-icon-bg object-contain p-1"
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user