@silicajs/components 0.1.0 → 0.1.2

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.
@@ -0,0 +1,7 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ declare function GoogleIcon({ className }: {
4
+ className?: string;
5
+ }): react_jsx_runtime.JSX.Element;
6
+
7
+ export { GoogleIcon };
@@ -0,0 +1,46 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ function GoogleIcon({ className }) {
3
+ return /* @__PURE__ */ jsxs(
4
+ "svg",
5
+ {
6
+ className,
7
+ viewBox: "0 0 24 24",
8
+ "aria-hidden": "true",
9
+ focusable: "false",
10
+ children: [
11
+ /* @__PURE__ */ jsx(
12
+ "path",
13
+ {
14
+ d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z",
15
+ fill: "#4285F4"
16
+ }
17
+ ),
18
+ /* @__PURE__ */ jsx(
19
+ "path",
20
+ {
21
+ d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z",
22
+ fill: "#34A853"
23
+ }
24
+ ),
25
+ /* @__PURE__ */ jsx(
26
+ "path",
27
+ {
28
+ d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z",
29
+ fill: "#FBBC05"
30
+ }
31
+ ),
32
+ /* @__PURE__ */ jsx(
33
+ "path",
34
+ {
35
+ d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z",
36
+ fill: "#EA4335"
37
+ }
38
+ )
39
+ ]
40
+ }
41
+ );
42
+ }
43
+ export {
44
+ GoogleIcon
45
+ };
46
+ //# sourceMappingURL=google-icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/google-icon.tsx"],"sourcesContent":["export function GoogleIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"\n fill=\"#EA4335\"\n />\n </svg>\n );\n}\n"],"mappings":"AAEI,SAME,KANF;AAFG,SAAS,WAAW,EAAE,UAAU,GAA2B;AAChE,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAQ;AAAA,MACR,eAAY;AAAA,MACZ,WAAU;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,GAAE;AAAA,YACF,MAAK;AAAA;AAAA,QACP;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export { Backlinks, BacklinksProps } from './backlinks.js';
2
2
  export { Breadcrumbs, BreadcrumbsProps } from './breadcrumbs.js';
3
3
  export { DarkModeToggle, DarkModeToggleProps } from './dark-mode-toggle.js';
4
+ export { GoogleIcon } from './google-icon.js';
4
5
  export { NotAllowed, NotAllowedProps } from './not-allowed.js';
6
+ export { SignInShell, SignInShellProps } from './sign-in-shell.js';
5
7
  export { NotFound, NotFoundProps } from './not-found.js';
6
8
  export { PageProperties, PagePropertiesProps } from './page-properties.js';
7
9
  export { SearchPalette, SearchPaletteProps, SearchTrigger, SearchTriggerProps } from './search.js';
package/dist/index.js CHANGED
@@ -3,7 +3,9 @@ import { Breadcrumbs } from "./breadcrumbs.js";
3
3
  import {
4
4
  DarkModeToggle
5
5
  } from "./dark-mode-toggle.js";
6
+ import { GoogleIcon } from "./google-icon.js";
6
7
  import { NotAllowed } from "./not-allowed.js";
8
+ import { SignInShell } from "./sign-in-shell.js";
7
9
  import { NotFound } from "./not-found.js";
8
10
  import { PageProperties } from "./page-properties.js";
9
11
  import {
@@ -26,11 +28,13 @@ export {
26
28
  Backlinks,
27
29
  Breadcrumbs,
28
30
  DarkModeToggle,
31
+ GoogleIcon,
29
32
  NotAllowed,
30
33
  NotFound,
31
34
  PageProperties,
32
35
  SearchPalette,
33
36
  SearchTrigger,
37
+ SignInShell,
34
38
  SilicaLink,
35
39
  SilicaRoutingProvider,
36
40
  TableOfContents,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { Backlinks, type BacklinksProps } from \"./backlinks.js\";\nexport { Breadcrumbs, type BreadcrumbsProps } from \"./breadcrumbs.js\";\nexport {\n DarkModeToggle,\n type DarkModeToggleProps,\n} from \"./dark-mode-toggle.js\";\nexport { NotAllowed, type NotAllowedProps } from \"./not-allowed.js\";\nexport { NotFound, type NotFoundProps } from \"./not-found.js\";\nexport { PageProperties, type PagePropertiesProps } from \"./page-properties.js\";\nexport {\n SearchPalette,\n SearchTrigger,\n type SearchPaletteProps,\n type SearchTriggerProps,\n} from \"./search.js\";\nexport {\n SilicaLink,\n SilicaRoutingProvider,\n useSilicaRouting,\n type SilicaLinkComponent,\n type SilicaLinkProps,\n type SilicaRoutingContextValue,\n type SilicaRoutingProviderProps,\n} from \"./routing.js\";\nexport {\n TableOfContents,\n type TableOfContentsProps,\n} from \"./table-of-contents.js\";\nexport { TagsList, type TagsListProps } from \"./tags-list.js\";\nexport { UserMenu, type UserMenuProps } from \"./user-menu.js\";\nexport { VaultTree, type VaultTreeProps } from \"./vault-tree.js\";\nexport { breadcrumbSegmentHref, prettySegment, slugToHref } from \"./slug.js\";\n"],"mappings":"AAAA,SAAS,iBAAsC;AAC/C,SAAS,mBAA0C;AACnD;AAAA,EACE;AAAA,OAEK;AACP,SAAS,kBAAwC;AACjD,SAAS,gBAAoC;AAC7C,SAAS,sBAAgD;AACzD;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AACP;AAAA,EACE;AAAA,OAEK;AACP,SAAS,gBAAoC;AAC7C,SAAS,gBAAoC;AAC7C,SAAS,iBAAsC;AAC/C,SAAS,uBAAuB,eAAe,kBAAkB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { Backlinks, type BacklinksProps } from \"./backlinks.js\";\nexport { Breadcrumbs, type BreadcrumbsProps } from \"./breadcrumbs.js\";\nexport {\n DarkModeToggle,\n type DarkModeToggleProps,\n} from \"./dark-mode-toggle.js\";\nexport { GoogleIcon } from \"./google-icon.js\";\nexport { NotAllowed, type NotAllowedProps } from \"./not-allowed.js\";\nexport { SignInShell, type SignInShellProps } from \"./sign-in-shell.js\";\nexport { NotFound, type NotFoundProps } from \"./not-found.js\";\nexport { PageProperties, type PagePropertiesProps } from \"./page-properties.js\";\nexport {\n SearchPalette,\n SearchTrigger,\n type SearchPaletteProps,\n type SearchTriggerProps,\n} from \"./search.js\";\nexport {\n SilicaLink,\n SilicaRoutingProvider,\n useSilicaRouting,\n type SilicaLinkComponent,\n type SilicaLinkProps,\n type SilicaRoutingContextValue,\n type SilicaRoutingProviderProps,\n} from \"./routing.js\";\nexport {\n TableOfContents,\n type TableOfContentsProps,\n} from \"./table-of-contents.js\";\nexport { TagsList, type TagsListProps } from \"./tags-list.js\";\nexport { UserMenu, type UserMenuProps } from \"./user-menu.js\";\nexport { VaultTree, type VaultTreeProps } from \"./vault-tree.js\";\nexport { breadcrumbSegmentHref, prettySegment, slugToHref } from \"./slug.js\";\n"],"mappings":"AAAA,SAAS,iBAAsC;AAC/C,SAAS,mBAA0C;AACnD;AAAA,EACE;AAAA,OAEK;AACP,SAAS,kBAAkB;AAC3B,SAAS,kBAAwC;AACjD,SAAS,mBAA0C;AACnD,SAAS,gBAAoC;AAC7C,SAAS,sBAAgD;AACzD;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AACP;AAAA,EACE;AAAA,OAEK;AACP,SAAS,gBAAoC;AAC7C,SAAS,gBAAoC;AAC7C,SAAS,iBAAsC;AAC/C,SAAS,uBAAuB,eAAe,kBAAkB;","names":[]}
package/dist/not-found.js CHANGED
@@ -18,7 +18,13 @@ function NotFound({
18
18
  /* @__PURE__ */ jsx(CardTitle, { className: "text-lg", children: title }),
19
19
  /* @__PURE__ */ jsx(CardDescription, { children: description })
20
20
  ] }),
21
- /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(Button, { variant: "outline", render: /* @__PURE__ */ jsx("a", { href: cta.href, children: cta.label }) }) })
21
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
22
+ Button,
23
+ {
24
+ variant: "outline",
25
+ render: /* @__PURE__ */ jsx("a", { href: cta.href, children: cta.label })
26
+ }
27
+ ) })
22
28
  ] }) });
23
29
  }
24
30
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/not-found.tsx"],"sourcesContent":["import { Button } from \"@silicajs/ui/components/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@silicajs/ui/components/card\";\n\nexport type NotFoundProps = {\n title?: string;\n description?: string;\n cta?: { href: string; label: string };\n className?: string;\n};\n\nexport function NotFound({\n title = \"Page not found\",\n description = \"The requested note does not exist or is not published.\",\n cta = { href: \"/\", label: \"Return home\" },\n className,\n}: NotFoundProps) {\n return (\n <main className={className} data-slot=\"not-found\">\n <Card className=\"mx-auto max-w-md\">\n <CardHeader>\n <CardTitle className=\"text-lg\">{title}</CardTitle>\n <CardDescription>{description}</CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"outline\" render={<a href={cta.href}>{cta.label}</a>} />\n </CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":"AAyBQ,SACE,KADF;AAzBR,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASA,SAAS,SAAS;AAAA,EACvB,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM,EAAE,MAAM,KAAK,OAAO,cAAc;AAAA,EACxC;AACF,GAAkB;AAChB,SACE,oBAAC,UAAK,WAAsB,aAAU,aACpC,+BAAC,QAAK,WAAU,oBACd;AAAA,yBAAC,cACC;AAAA,0BAAC,aAAU,WAAU,WAAW,iBAAM;AAAA,MACtC,oBAAC,mBAAiB,uBAAY;AAAA,OAChC;AAAA,IACA,oBAAC,eACC,8BAAC,UAAO,SAAQ,WAAU,QAAQ,oBAAC,OAAE,MAAM,IAAI,MAAO,cAAI,OAAM,GAAM,GACxE;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/not-found.tsx"],"sourcesContent":["import { Button } from \"@silicajs/ui/components/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@silicajs/ui/components/card\";\n\nexport type NotFoundProps = {\n title?: string;\n description?: string;\n cta?: { href: string; label: string };\n className?: string;\n};\n\nexport function NotFound({\n title = \"Page not found\",\n description = \"The requested note does not exist or is not published.\",\n cta = { href: \"/\", label: \"Return home\" },\n className,\n}: NotFoundProps) {\n return (\n <main className={className} data-slot=\"not-found\">\n <Card className=\"mx-auto max-w-md\">\n <CardHeader>\n <CardTitle className=\"text-lg\">{title}</CardTitle>\n <CardDescription>{description}</CardDescription>\n </CardHeader>\n <CardContent>\n <Button\n variant=\"outline\"\n render={<a href={cta.href}>{cta.label}</a>}\n />\n </CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":"AAyBQ,SACE,KADF;AAzBR,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASA,SAAS,SAAS;AAAA,EACvB,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM,EAAE,MAAM,KAAK,OAAO,cAAc;AAAA,EACxC;AACF,GAAkB;AAChB,SACE,oBAAC,UAAK,WAAsB,aAAU,aACpC,+BAAC,QAAK,WAAU,oBACd;AAAA,yBAAC,cACC;AAAA,0BAAC,aAAU,WAAU,WAAW,iBAAM;AAAA,MACtC,oBAAC,mBAAiB,uBAAY;AAAA,OAChC;AAAA,IACA,oBAAC,eACC;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,QAAQ,oBAAC,OAAE,MAAM,IAAI,MAAO,cAAI,OAAM;AAAA;AAAA,IACxC,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -0,0 +1,14 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type SignInShellProps = {
5
+ title: string;
6
+ description?: string;
7
+ logo?: string;
8
+ headline?: string;
9
+ subheadline?: string;
10
+ children: ReactNode;
11
+ };
12
+ declare function SignInShell({ title, description, logo, headline, subheadline, children, }: SignInShellProps): react_jsx_runtime.JSX.Element;
13
+
14
+ export { SignInShell, type SignInShellProps };
@@ -0,0 +1,50 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { BookOpen } from "lucide-react";
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardHeader,
8
+ CardTitle
9
+ } from "@silicajs/ui/components/card";
10
+ function SignInShell({
11
+ title,
12
+ description,
13
+ logo,
14
+ headline = "Sign in required",
15
+ subheadline,
16
+ children
17
+ }) {
18
+ const hint = subheadline ?? (description ? `${description} is private. Sign in with Google to access it.` : "This site is private. Sign in with Google to continue.");
19
+ return /* @__PURE__ */ jsxs(
20
+ "main",
21
+ {
22
+ className: "flex min-h-svh flex-col items-center justify-center gap-6 bg-muted/40 p-6 md:p-10",
23
+ "data-slot": "sign-in",
24
+ children: [
25
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
26
+ logo ? /* @__PURE__ */ jsx(
27
+ "img",
28
+ {
29
+ src: logo,
30
+ alt: "",
31
+ className: "size-8 shrink-0 rounded-md object-contain"
32
+ }
33
+ ) : /* @__PURE__ */ jsx("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-background text-foreground", children: /* @__PURE__ */ jsx(BookOpen, { className: "size-4", "aria-hidden": "true" }) }),
34
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tracking-tight text-foreground", children: title })
35
+ ] }),
36
+ /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-sm shadow-sm", children: [
37
+ /* @__PURE__ */ jsxs(CardHeader, { className: "text-center", children: [
38
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl tracking-tight", children: headline }),
39
+ /* @__PURE__ */ jsx(CardDescription, { children: hint })
40
+ ] }),
41
+ /* @__PURE__ */ jsx(CardContent, { className: "flex flex-col gap-4", children })
42
+ ] })
43
+ ]
44
+ }
45
+ );
46
+ }
47
+ export {
48
+ SignInShell
49
+ };
50
+ //# sourceMappingURL=sign-in-shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sign-in-shell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { BookOpen } from \"lucide-react\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@silicajs/ui/components/card\";\n\nexport type SignInShellProps = {\n title: string;\n description?: string;\n logo?: string;\n headline?: string;\n subheadline?: string;\n children: ReactNode;\n};\n\nexport function SignInShell({\n title,\n description,\n logo,\n headline = \"Sign in required\",\n subheadline,\n children,\n}: SignInShellProps) {\n const hint =\n subheadline ??\n (description\n ? `${description} is private. Sign in with Google to access it.`\n : \"This site is private. Sign in with Google to continue.\");\n\n return (\n <main\n className=\"flex min-h-svh flex-col items-center justify-center gap-6 bg-muted/40 p-6 md:p-10\"\n data-slot=\"sign-in\"\n >\n <div className=\"flex items-center gap-2\">\n {logo ? (\n <img\n src={logo}\n alt=\"\"\n className=\"size-8 shrink-0 rounded-md object-contain\"\n />\n ) : (\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-md border border-border bg-background text-foreground\">\n <BookOpen className=\"size-4\" aria-hidden=\"true\" />\n </span>\n )}\n <span className=\"text-sm font-semibold tracking-tight text-foreground\">\n {title}\n </span>\n </div>\n\n <Card className=\"w-full max-w-sm shadow-sm\">\n <CardHeader className=\"text-center\">\n <CardTitle className=\"text-xl tracking-tight\">{headline}</CardTitle>\n <CardDescription>{hint}</CardDescription>\n </CardHeader>\n <CardContent className=\"flex flex-col gap-4\">{children}</CardContent>\n </Card>\n </main>\n );\n}\n"],"mappings":"AAsCM,SAEI,KAFJ;AArCN,SAAS,gBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWA,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,OACJ,gBACC,cACG,GAAG,WAAW,mDACd;AAEN,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,aAAU;AAAA,MAEV;AAAA,6BAAC,SAAI,WAAU,2BACZ;AAAA,iBACC;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,KAAI;AAAA,cACJ,WAAU;AAAA;AAAA,UACZ,IAEA,oBAAC,UAAK,WAAU,kHACd,8BAAC,YAAS,WAAU,UAAS,eAAY,QAAO,GAClD;AAAA,UAEF,oBAAC,UAAK,WAAU,wDACb,iBACH;AAAA,WACF;AAAA,QAEA,qBAAC,QAAK,WAAU,6BACd;AAAA,+BAAC,cAAW,WAAU,eACpB;AAAA,gCAAC,aAAU,WAAU,0BAA0B,oBAAS;AAAA,YACxD,oBAAC,mBAAiB,gBAAK;AAAA,aACzB;AAAA,UACA,oBAAC,eAAY,WAAU,uBAAuB,UAAS;AAAA,WACzD;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,9 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
3
  type UserMenuProps = {
4
- label?: string;
5
- className?: string;
4
+ logo?: string;
6
5
  };
7
- declare function UserMenu({ label, className }: UserMenuProps): react_jsx_runtime.JSX.Element;
6
+ declare function UserMenu({ logo }: UserMenuProps): react_jsx_runtime.JSX.Element;
8
7
 
9
8
  export { UserMenu, type UserMenuProps };
package/dist/user-menu.js CHANGED
@@ -1,40 +1,139 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { UserIcon } from "lucide-react";
4
- import { Button } from "@silicajs/ui/components/button";
3
+ import { useEffect, useState } from "react";
4
+ import { EllipsisVertical, LogOut } from "lucide-react";
5
+ import {
6
+ Avatar,
7
+ AvatarFallback,
8
+ AvatarImage
9
+ } from "@silicajs/ui/components/avatar";
5
10
  import {
6
11
  DropdownMenu,
7
12
  DropdownMenuContent,
13
+ DropdownMenuGroup,
8
14
  DropdownMenuItem,
9
- DropdownMenuLabel,
10
15
  DropdownMenuSeparator,
11
16
  DropdownMenuTrigger
12
17
  } from "@silicajs/ui/components/dropdown-menu";
13
- function UserMenu({ label = "Signed in", className }) {
14
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
15
- /* @__PURE__ */ jsx(
18
+ import {
19
+ SidebarMenu,
20
+ SidebarMenuButton,
21
+ SidebarMenuItem,
22
+ useSidebar
23
+ } from "@silicajs/ui/components/sidebar";
24
+ function UserMenu({ logo }) {
25
+ const { isMobile } = useSidebar();
26
+ const [user, setUser] = useState(null);
27
+ useEffect(() => {
28
+ let cancelled = false;
29
+ void fetch("/api/auth/get-session", { credentials: "include" }).then((response) => response.ok ? response.json() : null).then((data) => {
30
+ if (cancelled || !data?.user) return;
31
+ setUser({
32
+ name: data.user.name ?? data.user.email ?? "Account",
33
+ email: data.user.email ?? "",
34
+ image: data.user.image ?? void 0
35
+ });
36
+ }).catch(() => {
37
+ });
38
+ return () => {
39
+ cancelled = true;
40
+ };
41
+ }, []);
42
+ const displayName = user?.name ?? "Account";
43
+ const displayEmail = user?.email ?? "";
44
+ const avatarSrc = user?.image ?? logo;
45
+ const initials = getInitials(user?.name, user?.email);
46
+ return /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
47
+ /* @__PURE__ */ jsxs(
16
48
  DropdownMenuTrigger,
17
49
  {
18
50
  render: /* @__PURE__ */ jsx(
19
- Button,
51
+ SidebarMenuButton,
20
52
  {
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" })
53
+ size: "lg",
54
+ className: "data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground"
27
55
  }
28
- )
56
+ ),
57
+ children: [
58
+ /* @__PURE__ */ jsx(UserAvatar, { src: avatarSrc, alt: displayName, initials }),
59
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
60
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: displayName }),
61
+ displayEmail ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: displayEmail }) : null
62
+ ] }),
63
+ /* @__PURE__ */ jsx(EllipsisVertical, { className: "ml-auto size-4 shrink-0 text-muted-foreground" })
64
+ ]
29
65
  }
30
66
  ),
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
- ] })
67
+ /* @__PURE__ */ jsxs(
68
+ DropdownMenuContent,
69
+ {
70
+ className: "min-w-56 rounded-lg",
71
+ side: isMobile ? "bottom" : "right",
72
+ align: "end",
73
+ sideOffset: 4,
74
+ children: [
75
+ /* @__PURE__ */ jsx("div", { className: "px-1 py-1.5 font-normal", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-left text-sm", children: [
76
+ /* @__PURE__ */ jsx(
77
+ UserAvatar,
78
+ {
79
+ src: avatarSrc,
80
+ alt: displayName,
81
+ initials
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
85
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: displayName }),
86
+ displayEmail ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: displayEmail }) : null
87
+ ] })
88
+ ] }) }),
89
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
90
+ /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsxs(
91
+ DropdownMenuItem,
92
+ {
93
+ variant: "destructive",
94
+ onClick: () => {
95
+ void signOut();
96
+ },
97
+ children: [
98
+ /* @__PURE__ */ jsx(LogOut, {}),
99
+ "Sign out"
100
+ ]
101
+ }
102
+ ) })
103
+ ]
104
+ }
105
+ )
106
+ ] }) }) });
107
+ }
108
+ function UserAvatar({
109
+ src,
110
+ alt,
111
+ initials
112
+ }) {
113
+ return /* @__PURE__ */ jsxs(Avatar, { className: "size-8", children: [
114
+ src ? /* @__PURE__ */ jsx(AvatarImage, { src, alt }) : null,
115
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "text-xs", children: initials })
36
116
  ] });
37
117
  }
118
+ function getInitials(name, email) {
119
+ const trimmedName = name?.trim();
120
+ if (trimmedName) {
121
+ const parts = trimmedName.split(/\s+/).filter(Boolean);
122
+ if (parts.length >= 2) {
123
+ return `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase();
124
+ }
125
+ return trimmedName.slice(0, 2).toUpperCase();
126
+ }
127
+ if (email) return email.slice(0, 2).toUpperCase();
128
+ return "??";
129
+ }
130
+ async function signOut() {
131
+ await fetch("/api/auth/sign-out", {
132
+ method: "POST",
133
+ credentials: "include"
134
+ });
135
+ window.location.assign("/sign-in");
136
+ }
38
137
  export {
39
138
  UserMenu
40
139
  };
@@ -1 +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":[]}
1
+ {"version":3,"sources":["../src/user-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { EllipsisVertical, LogOut } from \"lucide-react\";\n\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n} from \"@silicajs/ui/components/avatar\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@silicajs/ui/components/dropdown-menu\";\nimport {\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n useSidebar,\n} from \"@silicajs/ui/components/sidebar\";\n\nexport type UserMenuProps = {\n logo?: string;\n};\n\ntype SessionUser = {\n name?: string | null;\n email?: string | null;\n image?: string | null;\n};\n\ntype SessionResponse = {\n user?: SessionUser;\n};\n\nexport function UserMenu({ logo }: UserMenuProps) {\n const { isMobile } = useSidebar();\n const [user, setUser] = useState<SessionUser | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n void fetch(\"/api/auth/get-session\", { credentials: \"include\" })\n .then((response) => (response.ok ? response.json() : null))\n .then((data: SessionResponse | null) => {\n if (cancelled || !data?.user) return;\n setUser({\n name: data.user.name ?? data.user.email ?? \"Account\",\n email: data.user.email ?? \"\",\n image: data.user.image ?? undefined,\n });\n })\n .catch(() => {});\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n const displayName = user?.name ?? \"Account\";\n const displayEmail = user?.email ?? \"\";\n const avatarSrc = user?.image ?? logo;\n const initials = getInitials(user?.name, user?.email);\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <SidebarMenuButton\n size=\"lg\"\n className=\"data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground\"\n />\n }\n >\n <UserAvatar src={avatarSrc} alt={displayName} initials={initials} />\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium\">{displayName}</span>\n {displayEmail ? (\n <span className=\"truncate text-xs text-muted-foreground\">\n {displayEmail}\n </span>\n ) : null}\n </div>\n <EllipsisVertical className=\"ml-auto size-4 shrink-0 text-muted-foreground\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"min-w-56 rounded-lg\"\n side={isMobile ? \"bottom\" : \"right\"}\n align=\"end\"\n sideOffset={4}\n >\n <div className=\"px-1 py-1.5 font-normal\">\n <div className=\"flex items-center gap-2 text-left text-sm\">\n <UserAvatar\n src={avatarSrc}\n alt={displayName}\n initials={initials}\n />\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium\">{displayName}</span>\n {displayEmail ? (\n <span className=\"truncate text-xs text-muted-foreground\">\n {displayEmail}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem\n variant=\"destructive\"\n onClick={() => {\n void signOut();\n }}\n >\n <LogOut />\n Sign out\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n );\n}\n\nfunction UserAvatar({\n src,\n alt,\n initials,\n}: {\n src?: string;\n alt: string;\n initials: string;\n}) {\n return (\n <Avatar className=\"size-8\">\n {src ? <AvatarImage src={src} alt={alt} /> : null}\n <AvatarFallback className=\"text-xs\">{initials}</AvatarFallback>\n </Avatar>\n );\n}\n\nfunction getInitials(name?: string | null, email?: string | null): string {\n const trimmedName = name?.trim();\n if (trimmedName) {\n const parts = trimmedName.split(/\\s+/).filter(Boolean);\n if (parts.length >= 2) {\n return `${parts[0]?.[0] ?? \"\"}${parts[1]?.[0] ?? \"\"}`.toUpperCase();\n }\n return trimmedName.slice(0, 2).toUpperCase();\n }\n if (email) return email.slice(0, 2).toUpperCase();\n return \"??\";\n}\n\nasync function signOut(): Promise<void> {\n await fetch(\"/api/auth/sign-out\", {\n method: \"POST\",\n credentials: \"include\",\n });\n window.location.assign(\"/sign-in\");\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@silicajs/components",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Silica-aware, framework-agnostic React composables built on @silicajs/ui.",
5
5
  "type": "module",
6
+ "types": "./dist/index.d.ts",
6
7
  "license": "MIT",
7
8
  "publishConfig": {
8
9
  "access": "public"
@@ -27,10 +28,10 @@
27
28
  "test": "vitest run --passWithNoTests"
28
29
  },
29
30
  "dependencies": {
30
- "@silicajs/core": "^0.1.0",
31
+ "@silicajs/core": "^0.1.1",
31
32
  "@silicajs/remark-obsidian": "^0.1.0",
32
- "@silicajs/ui": "^0.1.0",
33
- "lucide-react": "^1.16.0"
33
+ "@silicajs/ui": "^0.1.2",
34
+ "lucide-react": "^1.17.0"
34
35
  },
35
36
  "peerDependencies": {
36
37
  "react": "^19.2.0",
@@ -40,7 +41,16 @@
40
41
  "@types/react": "^19.2.10",
41
42
  "@types/react-dom": "^19.2.3",
42
43
  "react": "^19.2.6",
43
- "react-dom": "^19.2.6",
44
+ "react-dom": "^19.2.7",
44
45
  "tsup": "^8.5.1"
46
+ },
47
+ "homepage": "https://github.com/agdevhq/silica/tree/main/packages/components#readme",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/agdevhq/silica.git",
51
+ "directory": "packages/components"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/agdevhq/silica/issues"
45
55
  }
46
56
  }