Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sideboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@types/debug": "^4.1.12",
"debug": "^4.4.3",
"solid-automerge": "^2.0.0",
"lucide-solid": "^1.23.0",
"solid-js": "^1.9.9"
},
"devDependencies": {
Expand Down
7 changes: 7 additions & 0 deletions sideboard/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@ button {
}
}

.document-list-item__icon {
flex: none;
align-self: center;
margin-right: 8px;
color: var(--placeholder-line);
}

.document-list-item__name {
overflow: hidden;
text-overflow: ellipsis;
Expand Down
205 changes: 205 additions & 0 deletions sideboard/src/sideboard/document-list/datatype-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import {
Activity,
ArrowLeft,
ArrowLeftRight,
ArrowRightLeft,
ArrowUpDown,
Backpack,
BookOpen,
Box,
Cable,
Calendar,
Cat,
ChartSpline,
CheckSquare,
CheckSquare2,
CircleDot,
CirclePlus,
CircuitBoard,
Clapperboard,
ClipboardList,
Clock,
Cpu,
Crosshair,
Database,
Dices,
Dumbbell,
Edit,
Eraser,
Eye,
File,
FileEdit,
FilePlus,
FileText,
Film,
Folder,
FolderOpen,
GitBranch,
Glasses,
Grid3x3,
Hash,
History,
Home,
Kanban,
Key,
Layers,
Layout,
LayoutGrid,
Library,
List,
ListChecks,
ListTodo,
MessageCircle,
MessageSquare,
Move,
Music,
Notebook,
Paintbrush,
Palette,
PenLine,
Play,
Plus,
Repeat,
Search,
Settings,
Sheet,
ShieldCheck,
Shuffle,
Sigma,
Sparkles,
Square,
Tag,
Target,
Trash,
Trash2,
TrendingUp,
User,
UserCircle,
Users,
Video,
Wifi,
Zap,
type LucideIcon,
} from "lucide-solid";
import { Dynamic } from "solid-js/web";
import { useDatatypeDescription, type MaybeAccessor } from "../lib/solid-plugins.ts";

// A curated subset of lucide icons, covering every `icon` currently declared
// by datatypes/tools across patchwork-base and patchwork-tools (plus a
// generic fallback). Named imports keep this tree-shakeable — unlike
// `import * as icons from "lucide-solid"`, which pulls all ~1500 icons into
// the bundle. Datatypes with an icon name outside this set (new, third-party,
// or renamed upstream) just render the fallback rather than failing.
const KNOWN_ICONS: Record<string, LucideIcon> = {
Activity,
ArrowLeft,
ArrowLeftRight,
ArrowRightLeft,
ArrowUpDown,
Backpack,
BookOpen,
Box,
Cable,
Calendar,
Cat,
ChartSpline,
CheckSquare,
CheckSquare2,
CircleDot,
CirclePlus,
CircuitBoard,
Clapperboard,
ClipboardList,
Clock,
Cpu,
Crosshair,
Database,
Dices,
Dumbbell,
Edit,
Eraser,
Eye,
File,
FileEdit,
FilePlus,
FileText,
Film,
Folder,
FolderOpen,
GitBranch,
Glasses,
Grid3x3,
Hash,
History,
Home,
Kanban,
Key,
Layers,
Layout,
LayoutGrid,
Library,
List,
ListChecks,
ListTodo,
MessageCircle,
MessageSquare,
Move,
Music,
Notebook,
Paintbrush,
Palette,
PenLine,
Play,
Plus,
Repeat,
Search,
Settings,
Sheet,
ShieldCheck,
Shuffle,
Sigma,
Sparkles,
Square,
Tag,
Target,
Trash,
Trash2,
TrendingUp,
User,
UserCircle,
Users,
Video,
Wifi,
Zap,
};

const FALLBACK_ICON = File;

function resolveIcon(name: string | undefined): LucideIcon {
if (!name) return FALLBACK_ICON;
return (
KNOWN_ICONS[name] ??
KNOWN_ICONS[name[0].toUpperCase() + name.slice(1)] ??
FALLBACK_ICON
);
}

/**
* Renders the icon a document's datatype registered itself with (the
* `icon` field of its `patchwork:datatype` plugin description, a lucide
* icon name e.g. "FileText"). Falls back to a generic file icon for
* datatypes with no icon, or an icon name outside our curated set.
*/
export function DatatypeIcon(props: { type: MaybeAccessor<string> }) {
const datatype = useDatatypeDescription(props.type);
const icon = () => resolveIcon(datatype()?.icon);

return (
<Dynamic
component={icon()}
class="document-list-item__icon"
size={14}
aria-hidden="true"
/>
);
}
2 changes: 2 additions & 0 deletions sideboard/src/sideboard/document-list/document-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
import Folder from "./folder.tsx";
import Item from "./item.tsx";
import { ItemName } from "./name.tsx";
import { DatatypeIcon } from "./datatype-icon.tsx";
import { LoadingRow } from "./loading-row.tsx";
import { NewDocPlaceholder } from "../create-new.tsx";
import { ShareModal } from "../share-modal.tsx";
Expand Down Expand Up @@ -340,6 +341,7 @@ export function DocumentList(props: DocumentListProps) {
: undefined
}
>
<DatatypeIcon type={doc.type} />
<ItemName name={doc.name} id={relid()} rename={rename} />
<Show when={props.hive && !isKeyhiveProtected(doc.url)}>
<span class="document-list-item__unprotected">
Expand Down
Loading