@silicajs/components 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backlinks.d.ts +12 -0
- package/dist/backlinks.js +36 -0
- package/dist/backlinks.js.map +1 -0
- package/dist/breadcrumbs.d.ts +10 -0
- package/dist/breadcrumbs.js +37 -0
- package/dist/breadcrumbs.js.map +1 -0
- package/dist/dark-mode-toggle.d.ts +8 -0
- package/dist/dark-mode-toggle.js +107 -0
- package/dist/dark-mode-toggle.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/not-allowed.d.ts +14 -0
- package/dist/not-allowed.js +27 -0
- package/dist/not-allowed.js.map +1 -0
- package/dist/not-found.d.ts +14 -0
- package/dist/not-found.js +27 -0
- package/dist/not-found.js.map +1 -0
- package/dist/page-properties.d.ts +10 -0
- package/dist/page-properties.js +80 -0
- package/dist/page-properties.js.map +1 -0
- package/dist/routing.d.ts +22 -0
- package/dist/routing.js +42 -0
- package/dist/routing.js.map +1 -0
- package/dist/search.d.ts +14 -0
- package/dist/search.js +158 -0
- package/dist/search.js.map +1 -0
- package/dist/slug.d.ts +6 -0
- package/dist/slug.js +20 -0
- package/dist/slug.js.map +1 -0
- package/dist/table-of-contents.d.ts +13 -0
- package/dist/table-of-contents.js +25 -0
- package/dist/table-of-contents.js.map +1 -0
- package/dist/tags-list.d.ts +11 -0
- package/dist/tags-list.js +68 -0
- package/dist/tags-list.js.map +1 -0
- package/dist/user-menu.d.ts +9 -0
- package/dist/user-menu.js +41 -0
- package/dist/user-menu.js.map +1 -0
- package/dist/vault-tree.d.ts +15 -0
- package/dist/vault-tree.js +248 -0
- package/dist/vault-tree.js.map +1 -0
- package/package.json +46 -0
package/dist/search.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
Command,
|
|
6
|
+
CommandEmpty,
|
|
7
|
+
CommandInput,
|
|
8
|
+
CommandItem,
|
|
9
|
+
CommandList
|
|
10
|
+
} from "@silicajs/ui/components/command";
|
|
11
|
+
import {
|
|
12
|
+
Dialog,
|
|
13
|
+
DialogContent,
|
|
14
|
+
DialogDescription,
|
|
15
|
+
DialogHeader,
|
|
16
|
+
DialogTitle
|
|
17
|
+
} from "@silicajs/ui/components/dialog";
|
|
18
|
+
import { Button } from "@silicajs/ui/components/button";
|
|
19
|
+
import { SearchIcon } from "lucide-react";
|
|
20
|
+
import { useSilicaRouting } from "./routing.js";
|
|
21
|
+
import { slugToHref } from "./slug.js";
|
|
22
|
+
function SearchTrigger({
|
|
23
|
+
placeholder = "Search\u2026",
|
|
24
|
+
className
|
|
25
|
+
}) {
|
|
26
|
+
const [open, setOpen] = React.useState(false);
|
|
27
|
+
React.useEffect(() => {
|
|
28
|
+
const onKeyDown = (event) => {
|
|
29
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
setOpen((value) => !value);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
window.addEventListener("keydown", onKeyDown);
|
|
35
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
36
|
+
}, []);
|
|
37
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38
|
+
/* @__PURE__ */ jsxs(
|
|
39
|
+
Button,
|
|
40
|
+
{
|
|
41
|
+
type: "button",
|
|
42
|
+
variant: "outline",
|
|
43
|
+
size: "sm",
|
|
44
|
+
onClick: () => setOpen(true),
|
|
45
|
+
className,
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
SearchIcon,
|
|
49
|
+
{
|
|
50
|
+
"data-icon": "inline-start",
|
|
51
|
+
className: "text-muted-foreground"
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-left text-muted-foreground", children: placeholder }),
|
|
55
|
+
/* @__PURE__ */ jsxs(
|
|
56
|
+
"kbd",
|
|
57
|
+
{
|
|
58
|
+
"data-icon": "inline-end",
|
|
59
|
+
className: "pointer-events-none ml-2 inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground",
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs", children: "\u2318" }),
|
|
62
|
+
"K"
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
/* @__PURE__ */ jsx(SearchPalette, { open, onOpenChange: setOpen })
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
function SearchPalette({ open, onOpenChange }) {
|
|
73
|
+
const { navigate } = useSilicaRouting();
|
|
74
|
+
const [query, setQuery] = React.useState("");
|
|
75
|
+
const [results, setResults] = React.useState([]);
|
|
76
|
+
const [isLoading, setIsLoading] = React.useState(false);
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
if (!open) {
|
|
79
|
+
setQuery("");
|
|
80
|
+
setResults([]);
|
|
81
|
+
setIsLoading(false);
|
|
82
|
+
}
|
|
83
|
+
}, [open]);
|
|
84
|
+
React.useEffect(() => {
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
const trimmed = query.trim();
|
|
87
|
+
if (!trimmed) {
|
|
88
|
+
setResults([]);
|
|
89
|
+
setIsLoading(false);
|
|
90
|
+
return () => controller.abort();
|
|
91
|
+
}
|
|
92
|
+
setIsLoading(true);
|
|
93
|
+
const timeout = window.setTimeout(() => {
|
|
94
|
+
fetch(`/api/search?q=${encodeURIComponent(trimmed)}`, {
|
|
95
|
+
signal: controller.signal
|
|
96
|
+
}).then((response) => response.ok ? response.json() : { results: [] }).then((payload) => {
|
|
97
|
+
setResults(payload.results ?? []);
|
|
98
|
+
}).catch((error) => {
|
|
99
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
100
|
+
return;
|
|
101
|
+
setResults([]);
|
|
102
|
+
}).finally(() => setIsLoading(false));
|
|
103
|
+
}, 120);
|
|
104
|
+
return () => {
|
|
105
|
+
window.clearTimeout(timeout);
|
|
106
|
+
controller.abort();
|
|
107
|
+
};
|
|
108
|
+
}, [query]);
|
|
109
|
+
const close = () => onOpenChange(false);
|
|
110
|
+
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange, children: [
|
|
111
|
+
/* @__PURE__ */ jsxs(DialogHeader, { className: "sr-only", children: [
|
|
112
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Search" }),
|
|
113
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "Search your vault." })
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
116
|
+
DialogContent,
|
|
117
|
+
{
|
|
118
|
+
className: "top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0",
|
|
119
|
+
showCloseButton: false,
|
|
120
|
+
children: /* @__PURE__ */ jsxs(Command, { shouldFilter: false, children: [
|
|
121
|
+
/* @__PURE__ */ jsx(
|
|
122
|
+
CommandInput,
|
|
123
|
+
{
|
|
124
|
+
autoFocus: true,
|
|
125
|
+
placeholder: "Search your vault\u2026",
|
|
126
|
+
value: query,
|
|
127
|
+
onValueChange: setQuery
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
131
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-muted-foreground", children: "Searching\u2026" }) : null,
|
|
132
|
+
!isLoading && query.trim() && results.length === 0 ? /* @__PURE__ */ jsx(CommandEmpty, { children: "No results" }) : null,
|
|
133
|
+
results.map((result) => /* @__PURE__ */ jsx(
|
|
134
|
+
CommandItem,
|
|
135
|
+
{
|
|
136
|
+
value: `${result.title} ${result.slug}`,
|
|
137
|
+
onSelect: () => {
|
|
138
|
+
navigate(slugToHref(result.slug));
|
|
139
|
+
close();
|
|
140
|
+
},
|
|
141
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
142
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium text-foreground", children: result.title }),
|
|
143
|
+
result.excerpt ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: result.excerpt }) : null
|
|
144
|
+
] })
|
|
145
|
+
},
|
|
146
|
+
result.slug
|
|
147
|
+
))
|
|
148
|
+
] })
|
|
149
|
+
] })
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
] });
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
SearchPalette,
|
|
156
|
+
SearchTrigger
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/search.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport {\n Command,\n CommandEmpty,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@silicajs/ui/components/command\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"@silicajs/ui/components/dialog\";\nimport { Button } from \"@silicajs/ui/components/button\";\nimport { SearchIcon } from \"lucide-react\";\n\nimport { useSilicaRouting } from \"./routing.js\";\nimport { slugToHref } from \"./slug.js\";\n\ntype SearchResult = {\n slug: string;\n title: string;\n excerpt: string;\n};\n\nexport type SearchTriggerProps = {\n placeholder?: string;\n className?: string;\n};\n\nexport function SearchTrigger({\n placeholder = \"Search…\",\n className,\n}: SearchTriggerProps) {\n const [open, setOpen] = React.useState(false);\n\n React.useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n setOpen((value) => !value);\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, []);\n\n return (\n <>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setOpen(true)}\n className={className}\n >\n <SearchIcon\n data-icon=\"inline-start\"\n className=\"text-muted-foreground\"\n />\n <span className=\"flex-1 text-left text-muted-foreground\">\n {placeholder}\n </span>\n <kbd\n data-icon=\"inline-end\"\n className=\"pointer-events-none ml-2 inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground\"\n >\n <span className=\"text-xs\">⌘</span>K\n </kbd>\n </Button>\n <SearchPalette open={open} onOpenChange={setOpen} />\n </>\n );\n}\n\nexport type SearchPaletteProps = {\n open: boolean;\n onOpenChange: (next: boolean) => void;\n};\n\nexport function SearchPalette({ open, onOpenChange }: SearchPaletteProps) {\n const { navigate } = useSilicaRouting();\n const [query, setQuery] = React.useState(\"\");\n const [results, setResults] = React.useState<SearchResult[]>([]);\n const [isLoading, setIsLoading] = React.useState(false);\n\n React.useEffect(() => {\n if (!open) {\n setQuery(\"\");\n setResults([]);\n setIsLoading(false);\n }\n }, [open]);\n\n React.useEffect(() => {\n const controller = new AbortController();\n const trimmed = query.trim();\n if (!trimmed) {\n setResults([]);\n setIsLoading(false);\n return () => controller.abort();\n }\n\n setIsLoading(true);\n const timeout = window.setTimeout(() => {\n fetch(`/api/search?q=${encodeURIComponent(trimmed)}`, {\n signal: controller.signal,\n })\n .then((response) => (response.ok ? response.json() : { results: [] }))\n .then((payload: { results?: SearchResult[] }) => {\n setResults(payload.results ?? []);\n })\n .catch((error: unknown) => {\n if (error instanceof DOMException && error.name === \"AbortError\")\n return;\n setResults([]);\n })\n .finally(() => setIsLoading(false));\n }, 120);\n\n return () => {\n window.clearTimeout(timeout);\n controller.abort();\n };\n }, [query]);\n\n const close = () => onOpenChange(false);\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogHeader className=\"sr-only\">\n <DialogTitle>Search</DialogTitle>\n <DialogDescription>Search your vault.</DialogDescription>\n </DialogHeader>\n <DialogContent\n className=\"top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0\"\n showCloseButton={false}\n >\n <Command shouldFilter={false}>\n <CommandInput\n autoFocus\n placeholder=\"Search your vault…\"\n value={query}\n onValueChange={setQuery}\n />\n <CommandList>\n {isLoading ? (\n <div className=\"px-4 py-6 text-center text-sm text-muted-foreground\">\n Searching…\n </div>\n ) : null}\n {!isLoading && query.trim() && results.length === 0 ? (\n <CommandEmpty>No results</CommandEmpty>\n ) : null}\n {results.map((result) => (\n <CommandItem\n key={result.slug}\n value={`${result.title} ${result.slug}`}\n onSelect={() => {\n navigate(slugToHref(result.slug));\n close();\n }}\n >\n <div className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"truncate font-medium text-foreground\">\n {result.title}\n </span>\n {result.excerpt ? (\n <span className=\"truncate text-xs text-muted-foreground\">\n {result.excerpt}\n </span>\n ) : null}\n </div>\n </CommandItem>\n ))}\n </CommandList>\n </Command>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/slug.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare function slugToHref(slug: string): string;
|
|
2
|
+
/** Returns an href when `segmentPath` maps to a real page; otherwise undefined. */
|
|
3
|
+
declare function breadcrumbSegmentHref(segmentPath: string, allSlugs: readonly string[]): string | undefined;
|
|
4
|
+
declare function prettySegment(segment: string): string;
|
|
5
|
+
|
|
6
|
+
export { breadcrumbSegmentHref, prettySegment, slugToHref };
|
package/dist/slug.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function slugToHref(slug) {
|
|
2
|
+
if (slug === "index") return "/";
|
|
3
|
+
return `/${slug.replace(/\/index$/, "")}`;
|
|
4
|
+
}
|
|
5
|
+
function breadcrumbSegmentHref(segmentPath, allSlugs) {
|
|
6
|
+
const slugs = new Set(allSlugs);
|
|
7
|
+
if (slugs.has(segmentPath)) return slugToHref(segmentPath);
|
|
8
|
+
const indexSlug = `${segmentPath}/index`;
|
|
9
|
+
if (slugs.has(indexSlug)) return slugToHref(indexSlug);
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
function prettySegment(segment) {
|
|
13
|
+
return segment.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
breadcrumbSegmentHref,
|
|
17
|
+
prettySegment,
|
|
18
|
+
slugToHref
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=slug.js.map
|
package/dist/slug.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/slug.ts"],"sourcesContent":["export function slugToHref(slug: string): string {\n if (slug === \"index\") return \"/\";\n return `/${slug.replace(/\\/index$/, \"\")}`;\n}\n\n/** Returns an href when `segmentPath` maps to a real page; otherwise undefined. */\nexport function breadcrumbSegmentHref(\n segmentPath: string,\n allSlugs: readonly string[],\n): string | undefined {\n const slugs = new Set(allSlugs);\n if (slugs.has(segmentPath)) return slugToHref(segmentPath);\n const indexSlug = `${segmentPath}/index`;\n if (slugs.has(indexSlug)) return slugToHref(indexSlug);\n return undefined;\n}\n\nexport function prettySegment(segment: string): string {\n return segment\n .replace(/[-_]/g, \" \")\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n"],"mappings":"AAAO,SAAS,WAAW,MAAsB;AAC/C,MAAI,SAAS,QAAS,QAAO;AAC7B,SAAO,IAAI,KAAK,QAAQ,YAAY,EAAE,CAAC;AACzC;AAGO,SAAS,sBACd,aACA,UACoB;AACpB,QAAM,QAAQ,IAAI,IAAI,QAAQ;AAC9B,MAAI,MAAM,IAAI,WAAW,EAAG,QAAO,WAAW,WAAW;AACzD,QAAM,YAAY,GAAG,WAAW;AAChC,MAAI,MAAM,IAAI,SAAS,EAAG,QAAO,WAAW,SAAS;AACrD,SAAO;AACT;AAEO,SAAS,cAAc,SAAyB;AACrD,SAAO,QACJ,QAAQ,SAAS,GAAG,EACpB,QAAQ,SAAS,CAAC,WAAW,OAAO,YAAY,CAAC;AACtD;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { TocItem } from '@silicajs/core/runtime';
|
|
4
|
+
|
|
5
|
+
type TableOfContentsProps = {
|
|
6
|
+
toc: TocItem[];
|
|
7
|
+
activeId?: string;
|
|
8
|
+
heading?: React.ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
declare function TableOfContents({ toc, activeId, heading, className, }: TableOfContentsProps): react_jsx_runtime.JSX.Element | null;
|
|
12
|
+
|
|
13
|
+
export { TableOfContents, type TableOfContentsProps };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { TocList } from "@silicajs/ui/components/toc-list";
|
|
3
|
+
function TableOfContents({
|
|
4
|
+
toc,
|
|
5
|
+
activeId,
|
|
6
|
+
heading = "On this page",
|
|
7
|
+
className
|
|
8
|
+
}) {
|
|
9
|
+
if (toc.length === 0) return null;
|
|
10
|
+
const minDepth = Math.min(...toc.map((item) => item.depth));
|
|
11
|
+
const items = toc.map((item) => ({
|
|
12
|
+
id: item.id,
|
|
13
|
+
label: item.text,
|
|
14
|
+
href: `#${item.id}`,
|
|
15
|
+
depth: Math.max(0, item.depth - minDepth)
|
|
16
|
+
}));
|
|
17
|
+
return /* @__PURE__ */ jsxs("nav", { "aria-label": "Table of contents", className, children: [
|
|
18
|
+
heading ? /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-medium tracking-wider text-muted-foreground uppercase", children: heading }) : null,
|
|
19
|
+
/* @__PURE__ */ jsx(TocList, { items, activeId })
|
|
20
|
+
] });
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
TableOfContents
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=table-of-contents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/table-of-contents.tsx"],"sourcesContent":["import * as React from \"react\";\nimport type { TocItem } from \"@silicajs/core/runtime\";\n\nimport { TocList, type TocListItem } from \"@silicajs/ui/components/toc-list\";\n\nexport type TableOfContentsProps = {\n toc: TocItem[];\n activeId?: string;\n heading?: React.ReactNode;\n className?: string;\n};\n\nexport function TableOfContents({\n toc,\n activeId,\n heading = \"On this page\",\n className,\n}: TableOfContentsProps) {\n if (toc.length === 0) return null;\n\n const minDepth = Math.min(...toc.map((item) => item.depth));\n const items: TocListItem[] = toc.map((item) => ({\n id: item.id,\n label: item.text,\n href: `#${item.id}`,\n depth: Math.max(0, item.depth - minDepth),\n }));\n\n return (\n <nav aria-label=\"Table of contents\" className={className}>\n {heading ? (\n <p className=\"mb-2 text-xs font-medium tracking-wider text-muted-foreground uppercase\">\n {heading}\n </p>\n ) : null}\n <TocList items={items} activeId={activeId} />\n </nav>\n );\n}\n"],"mappings":"AA6BI,SAEI,KAFJ;AA1BJ,SAAS,eAAiC;AASnC,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AACF,GAAyB;AACvB,MAAI,IAAI,WAAW,EAAG,QAAO;AAE7B,QAAM,WAAW,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAC1D,QAAM,QAAuB,IAAI,IAAI,CAAC,UAAU;AAAA,IAC9C,IAAI,KAAK;AAAA,IACT,OAAO,KAAK;AAAA,IACZ,MAAM,IAAI,KAAK,EAAE;AAAA,IACjB,OAAO,KAAK,IAAI,GAAG,KAAK,QAAQ,QAAQ;AAAA,EAC1C,EAAE;AAEF,SACE,qBAAC,SAAI,cAAW,qBAAoB,WACjC;AAAA,cACC,oBAAC,OAAE,WAAU,2EACV,mBACH,IACE;AAAA,IACJ,oBAAC,WAAQ,OAAc,UAAoB;AAAA,KAC7C;AAEJ;","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { Manifest } from '@silicajs/core/runtime';
|
|
3
|
+
|
|
4
|
+
type TagsListProps = {
|
|
5
|
+
manifest: Manifest;
|
|
6
|
+
tag: string;
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
declare function TagsList({ manifest, tag, className }: TagsListProps): react_jsx_runtime.JSX.Element;
|
|
10
|
+
|
|
11
|
+
export { TagsList, type TagsListProps };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { tagMatches } from "@silicajs/remark-obsidian";
|
|
4
|
+
import { tagToHref } from "@silicajs/core/runtime";
|
|
5
|
+
import { TagBadge } from "@silicajs/ui/components/tag-badge";
|
|
6
|
+
import { SilicaLink } from "./routing.js";
|
|
7
|
+
import { slugToHref } from "./slug.js";
|
|
8
|
+
function TagsList({ manifest, tag, className }) {
|
|
9
|
+
const entries = React.useMemo(
|
|
10
|
+
() => manifest.entries.filter(
|
|
11
|
+
(entry) => entry.tags.some((entryTag) => tagMatches(entryTag, tag))
|
|
12
|
+
).sort((a, b) => a.title.localeCompare(b.title)),
|
|
13
|
+
[manifest.entries, tag]
|
|
14
|
+
);
|
|
15
|
+
const relatedTags = React.useMemo(() => {
|
|
16
|
+
const counts = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
for (const t of entry.tags) {
|
|
19
|
+
if (tagMatches(t, tag) && tagMatches(tag, t)) continue;
|
|
20
|
+
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 12).map(([t]) => t);
|
|
24
|
+
}, [entries, tag]);
|
|
25
|
+
return /* @__PURE__ */ jsxs("section", { className, "data-slot": "tags-list", children: [
|
|
26
|
+
/* @__PURE__ */ jsxs("header", { className: "mb-6 flex items-baseline gap-3", children: [
|
|
27
|
+
/* @__PURE__ */ jsxs("h1", { className: "text-2xl font-semibold tracking-tight", children: [
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "#" }),
|
|
29
|
+
tag
|
|
30
|
+
] }),
|
|
31
|
+
/* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
32
|
+
entries.length,
|
|
33
|
+
" ",
|
|
34
|
+
entries.length === 1 ? "page" : "pages"
|
|
35
|
+
] })
|
|
36
|
+
] }),
|
|
37
|
+
relatedTags.length > 0 ? /* @__PURE__ */ jsx("div", { className: "mb-6 flex flex-wrap gap-2", children: relatedTags.map((t) => /* @__PURE__ */ jsx(
|
|
38
|
+
TagBadge,
|
|
39
|
+
{
|
|
40
|
+
tag: t,
|
|
41
|
+
href: tagToHref(t),
|
|
42
|
+
render: /* @__PURE__ */ jsx(
|
|
43
|
+
SilicaLink,
|
|
44
|
+
{
|
|
45
|
+
href: tagToHref(t),
|
|
46
|
+
className: "cursor-pointer text-foreground/80 no-underline transition-colors hover:text-foreground"
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
},
|
|
50
|
+
t
|
|
51
|
+
)) }) : null,
|
|
52
|
+
/* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2", children: entries.map((entry) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
53
|
+
SilicaLink,
|
|
54
|
+
{
|
|
55
|
+
href: slugToHref(entry.slug),
|
|
56
|
+
className: "block rounded-md px-3 py-2 transition-colors hover:bg-muted",
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-foreground", children: entry.title }),
|
|
59
|
+
entry.description ? /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: entry.description }) : null
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
) }, entry.slug)) })
|
|
63
|
+
] });
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
TagsList
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=tags-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tags-list.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { tagMatches } from \"@silicajs/remark-obsidian\";\nimport { tagToHref, type Manifest } from \"@silicajs/core/runtime\";\n\nimport { TagBadge } from \"@silicajs/ui/components/tag-badge\";\n\nimport { SilicaLink } from \"./routing.js\";\nimport { slugToHref } from \"./slug.js\";\n\nexport type TagsListProps = {\n manifest: Manifest;\n tag: string;\n className?: string;\n};\n\nexport function TagsList({ manifest, tag, className }: TagsListProps) {\n const entries = React.useMemo(\n () =>\n manifest.entries\n .filter((entry) =>\n entry.tags.some((entryTag) => tagMatches(entryTag, tag)),\n )\n .sort((a, b) => a.title.localeCompare(b.title)),\n [manifest.entries, tag],\n );\n const relatedTags = React.useMemo(() => {\n const counts = new Map<string, number>();\n for (const entry of entries) {\n for (const t of entry.tags) {\n if (tagMatches(t, tag) && tagMatches(tag, t)) continue;\n counts.set(t, (counts.get(t) ?? 0) + 1);\n }\n }\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 12)\n .map(([t]) => t);\n }, [entries, tag]);\n\n return (\n <section className={className} data-slot=\"tags-list\">\n <header className=\"mb-6 flex items-baseline gap-3\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <span className=\"text-muted-foreground\">#</span>\n {tag}\n </h1>\n <span className=\"text-sm text-muted-foreground\">\n {entries.length} {entries.length === 1 ? \"page\" : \"pages\"}\n </span>\n </header>\n {relatedTags.length > 0 ? (\n <div className=\"mb-6 flex flex-wrap gap-2\">\n {relatedTags.map((t) => (\n <TagBadge\n key={t}\n tag={t}\n href={tagToHref(t)}\n render={\n <SilicaLink\n href={tagToHref(t)}\n className=\"cursor-pointer text-foreground/80 no-underline transition-colors hover:text-foreground\"\n />\n }\n />\n ))}\n </div>\n ) : null}\n <ul className=\"flex flex-col gap-2\">\n {entries.map((entry) => (\n <li key={entry.slug}>\n <SilicaLink\n href={slugToHref(entry.slug)}\n className=\"block rounded-md px-3 py-2 transition-colors hover:bg-muted\"\n >\n <div className=\"font-medium text-foreground\">{entry.title}</div>\n {entry.description ? (\n <div className=\"text-sm text-muted-foreground\">\n {entry.description}\n </div>\n ) : null}\n </SilicaLink>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n"],"mappings":"AA0CQ,SACE,KADF;AA1CR,YAAY,WAAW;AACvB,SAAS,kBAAkB;AAC3B,SAAS,iBAAgC;AAEzC,SAAS,gBAAgB;AAEzB,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAQpB,SAAS,SAAS,EAAE,UAAU,KAAK,UAAU,GAAkB;AACpE,QAAM,UAAU,MAAM;AAAA,IACpB,MACE,SAAS,QACN;AAAA,MAAO,CAAC,UACP,MAAM,KAAK,KAAK,CAAC,aAAa,WAAW,UAAU,GAAG,CAAC;AAAA,IACzD,EACC,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAAA,IAClD,CAAC,SAAS,SAAS,GAAG;AAAA,EACxB;AACA,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,UAAM,SAAS,oBAAI,IAAoB;AACvC,eAAW,SAAS,SAAS;AAC3B,iBAAW,KAAK,MAAM,MAAM;AAC1B,YAAI,WAAW,GAAG,GAAG,KAAK,WAAW,KAAK,CAAC,EAAG;AAC9C,eAAO,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC;AAAA,MACxC;AAAA,IACF;AACA,WAAO,CAAC,GAAG,OAAO,QAAQ,CAAC,EACxB,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,EACnB,GAAG,CAAC,SAAS,GAAG,CAAC;AAEjB,SACE,qBAAC,aAAQ,WAAsB,aAAU,aACvC;AAAA,yBAAC,YAAO,WAAU,kCAChB;AAAA,2BAAC,QAAG,WAAU,yCACZ;AAAA,4BAAC,UAAK,WAAU,yBAAwB,eAAC;AAAA,QACxC;AAAA,SACH;AAAA,MACA,qBAAC,UAAK,WAAU,iCACb;AAAA,gBAAQ;AAAA,QAAO;AAAA,QAAE,QAAQ,WAAW,IAAI,SAAS;AAAA,SACpD;AAAA,OACF;AAAA,IACC,YAAY,SAAS,IACpB,oBAAC,SAAI,WAAU,6BACZ,sBAAY,IAAI,CAAC,MAChB;AAAA,MAAC;AAAA;AAAA,QAEC,KAAK;AAAA,QACL,MAAM,UAAU,CAAC;AAAA,QACjB,QACE;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,UAAU,CAAC;AAAA,YACjB,WAAU;AAAA;AAAA,QACZ;AAAA;AAAA,MAPG;AAAA,IASP,CACD,GACH,IACE;AAAA,IACJ,oBAAC,QAAG,WAAU,uBACX,kBAAQ,IAAI,CAAC,UACZ,oBAAC,QACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,WAAW,MAAM,IAAI;AAAA,QAC3B,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAU,+BAA+B,gBAAM,OAAM;AAAA,UACzD,MAAM,cACL,oBAAC,SAAI,WAAU,iCACZ,gBAAM,aACT,IACE;AAAA;AAAA;AAAA,IACN,KAXO,MAAM,IAYf,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type UserMenuProps = {
|
|
4
|
+
label?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
};
|
|
7
|
+
declare function UserMenu({ label, className }: UserMenuProps): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
export { UserMenu, type UserMenuProps };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { UserIcon } from "lucide-react";
|
|
4
|
+
import { Button } from "@silicajs/ui/components/button";
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuLabel,
|
|
10
|
+
DropdownMenuSeparator,
|
|
11
|
+
DropdownMenuTrigger
|
|
12
|
+
} from "@silicajs/ui/components/dropdown-menu";
|
|
13
|
+
function UserMenu({ label = "Signed in", className }) {
|
|
14
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
15
|
+
/* @__PURE__ */ jsx(
|
|
16
|
+
DropdownMenuTrigger,
|
|
17
|
+
{
|
|
18
|
+
render: /* @__PURE__ */ jsx(
|
|
19
|
+
Button,
|
|
20
|
+
{
|
|
21
|
+
type: "button",
|
|
22
|
+
variant: "ghost",
|
|
23
|
+
size: "icon-sm",
|
|
24
|
+
"aria-label": "User menu",
|
|
25
|
+
className,
|
|
26
|
+
children: /* @__PURE__ */ jsx(UserIcon, { "aria-hidden": "true" })
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "min-w-44", children: [
|
|
32
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: label }),
|
|
33
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
34
|
+
/* @__PURE__ */ jsx(DropdownMenuItem, { render: /* @__PURE__ */ jsx("a", { href: "/api/auth/sign-out", children: "Sign out" }) })
|
|
35
|
+
] })
|
|
36
|
+
] });
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
UserMenu
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=user-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/user-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { UserIcon } from \"lucide-react\";\n\nimport { Button } from \"@silicajs/ui/components/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@silicajs/ui/components/dropdown-menu\";\n\nexport type UserMenuProps = {\n label?: string;\n className?: string;\n};\n\nexport function UserMenu({ label = \"Signed in\", className }: UserMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label=\"User menu\"\n className={className}\n >\n <UserIcon aria-hidden=\"true\" />\n </Button>\n }\n />\n <DropdownMenuContent align=\"end\" sideOffset={6} className=\"min-w-44\">\n <DropdownMenuLabel>{label}</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuItem render={<a href=\"/api/auth/sign-out\">Sign out</a>} />\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":";AA+BY,cAIN,YAJM;AA7BZ,SAAS,gBAAgB;AAEzB,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAOA,SAAS,SAAS,EAAE,QAAQ,aAAa,UAAU,GAAkB;AAC1E,SACE,qBAAC,gBACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,QACE;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,cAAW;AAAA,YACX;AAAA,YAEA,8BAAC,YAAS,eAAY,QAAO;AAAA;AAAA,QAC/B;AAAA;AAAA,IAEJ;AAAA,IACA,qBAAC,uBAAoB,OAAM,OAAM,YAAY,GAAG,WAAU,YACxD;AAAA,0BAAC,qBAAmB,iBAAM;AAAA,MAC1B,oBAAC,yBAAsB;AAAA,MACvB,oBAAC,oBAAiB,QAAQ,oBAAC,OAAE,MAAK,sBAAqB,sBAAQ,GAAM;AAAA,OACvE;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type VaultTreeEntry = {
|
|
4
|
+
slug: string;
|
|
5
|
+
title: string;
|
|
6
|
+
sortKey?: string;
|
|
7
|
+
};
|
|
8
|
+
type VaultTreeProps = {
|
|
9
|
+
entries: VaultTreeEntry[];
|
|
10
|
+
currentSlug?: string;
|
|
11
|
+
showHomeLink?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare function VaultTree({ entries, currentSlug: currentSlugProp, showHomeLink, }: VaultTreeProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { VaultTree, type VaultTreeEntry, type VaultTreeProps };
|