@forjio/portal-ui 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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Sidebar.tsx"],"sourcesContent":["'use client';\n\nimport Link from 'next/link';\nimport { usePathname } from 'next/navigation';\nimport { ChevronUp, X, LogOut, BookOpen, FileText, Shield } from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\nimport type {\n LucideIcon,\n NavSection,\n PortalWorkspace,\n SessionUser,\n WorkspacePersistMode,\n} from './types';\nimport { activeHrefFor, titleCase, writeActiveWorkspace } from './utils';\n\n/**\n * Forjio family sidebar — workspace switcher on top, nav sections in\n * the middle, profile dropdown at the bottom. Extracted from\n * saas-plugipay 2026-05-19 as the canonical reference.\n *\n * The shell is style-agnostic: every visual is inline CSS driven by\n * CSS custom properties so consumers can theme via a single brandColor\n * prop without depending on Tailwind or any specific token system.\n */\nexport interface SidebarProps {\n /** Slug for cookie/localStorage namespace, e.g. \"plugipay\". */\n brandSlug: string;\n /** Display name shown at the top of the sidebar. */\n brandName: string;\n /** Brand accent color — used for the active-link pill + workspace\n * chiclet + profile avatar. Forjio family default `#1a1a2e`. */\n brandColor: string;\n /** Sidebar logo. Provide a Lucide icon or an `<img>` — anything that\n * renders next to the brand name. */\n brandIcon?: React.ReactNode;\n /** Persistence flavor — see WorkspacePersistMode docs. */\n workspacePersist: WorkspacePersistMode;\n /** Only used when workspacePersist='api'. Should contain `{id}` as\n * a placeholder. Example: `/api/v1/account/workspaces/{id}/switch`. */\n apiSwitchPath?: string;\n /** Loaded workspace list — fetched by the host product. */\n workspaces: PortalWorkspace[];\n /** Active workspace id — host product reads from\n * readActiveWorkspaceId or session state. */\n activeWorkspaceId: string | null;\n /** Nav sections rendered in order. Most-specific href wins for the\n * active highlight. */\n sections: NavSection[];\n /** Bottom-of-sidebar user info. */\n user: SessionUser | null;\n /** Called when the user picks a different workspace. After the\n * helper writes persistence, the host should refetch its data —\n * the default behavior is to reload the page, but the host can\n * override (e.g. invalidate a SWR cache instead). */\n onWorkspaceSwitch?: (id: string) => void | Promise<void>;\n /** Called when the user clicks Sign out. */\n onLogout: () => void | Promise<void>;\n /** Drawer open state on mobile. */\n open: boolean;\n /** Close handler for the mobile drawer. */\n onClose: () => void;\n /** Optional footer links inside the profile dropdown.\n * Defaults to Docs / Terms / Privacy. */\n dropdownLinks?: { href: string; label: string; icon: LucideIcon }[];\n}\n\nconst DEFAULT_DROPDOWN_LINKS: { href: string; label: string; icon: LucideIcon }[] = [\n { href: '/docs', label: 'Documentation', icon: BookOpen },\n { href: '/terms', label: 'Terms of Service', icon: FileText },\n { href: '/privacy', label: 'Privacy Policy', icon: Shield },\n];\n\nexport function Sidebar({\n brandSlug,\n brandName,\n brandColor,\n brandIcon,\n workspacePersist,\n apiSwitchPath,\n workspaces,\n activeWorkspaceId,\n sections,\n user,\n onWorkspaceSwitch,\n onLogout,\n open,\n onClose,\n dropdownLinks = DEFAULT_DROPDOWN_LINKS,\n}: SidebarProps) {\n const pathname = usePathname() ?? '';\n const active = workspaces.find((w) => w.id === activeWorkspaceId) ?? null;\n const others = workspaces.filter((w) => w.id !== activeWorkspaceId);\n\n // Theme variables expressed as CSS custom properties; consumers can\n // override on their own root if needed but the props are the canonical\n // surface.\n const themeVars: React.CSSProperties = {\n ['--brand-color' as string]: brandColor,\n ['--brand-soft' as string]: `${brandColor}26`, // 15% alpha\n };\n\n async function switchWorkspace(id: string) {\n await writeActiveWorkspace(workspacePersist, brandSlug, id, apiSwitchPath);\n if (onWorkspaceSwitch) {\n await onWorkspaceSwitch(id);\n } else if (typeof window !== 'undefined') {\n window.location.reload();\n }\n }\n\n return (\n <>\n {open && (\n <div\n onClick={onClose}\n aria-hidden=\"true\"\n style={{\n position: 'fixed',\n inset: 0,\n background: 'rgba(0,0,0,0.5)',\n zIndex: 40,\n }}\n className=\"lg:hidden\"\n />\n )}\n\n <aside\n style={{\n ...themeVars,\n borderRight: '1px solid hsl(var(--border, 220 14% 90%))',\n background: 'hsl(var(--card, 0 0% 100%))',\n color: 'hsl(var(--foreground, 222 47% 11%))',\n width: 248,\n display: 'flex',\n flexDirection: 'column',\n }}\n className={`fixed inset-y-0 left-0 z-50 h-screen transition-transform lg:sticky lg:top-0 lg:translate-x-0 ${\n open ? 'translate-x-0' : '-translate-x-full'\n }`}\n >\n {/* Brand row */}\n <div\n style={{\n padding: '20px 20px 18px',\n borderBottom: '1px solid hsl(var(--border, 220 14% 90%))',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <Link\n href=\"/dashboard\"\n onClick={onClose}\n aria-label={`${brandName} dashboard`}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n fontSize: 18,\n fontWeight: 700,\n letterSpacing: '-0.02em',\n textDecoration: 'none',\n color: 'inherit',\n }}\n >\n {brandIcon}\n {brandName}\n </Link>\n <button\n onClick={onClose}\n className=\"lg:hidden\"\n style={{\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n padding: 4,\n }}\n aria-label=\"Close navigation\"\n >\n <X size={18} />\n </button>\n </div>\n\n <WorkspaceSwitcher\n active={active}\n others={others}\n hasAny={workspaces.length > 0}\n onSwitch={switchWorkspace}\n onNavigate={onClose}\n />\n\n <div style={{ flex: 1, padding: '16px 10px', overflowY: 'auto' }}>\n <NavList pathname={pathname} sections={sections} onNavigate={onClose} />\n </div>\n\n <ProfileDropdown user={user} onLogout={onLogout} onNavigate={onClose} dropdownLinks={dropdownLinks} />\n </aside>\n </>\n );\n}\n\nfunction NavList({\n pathname,\n sections,\n onNavigate,\n}: {\n pathname: string;\n sections: NavSection[];\n onNavigate?: () => void;\n}) {\n const activeHref = activeHrefFor(pathname, sections);\n return (\n <nav aria-label=\"Dashboard\" style={{ display: 'grid', gap: 16 }}>\n {sections.map((section) => (\n <div key={section.label}>\n <div\n style={{\n fontSize: 10.5,\n letterSpacing: '0.12em',\n textTransform: 'uppercase',\n color: 'hsl(var(--muted-foreground, 220 9% 46%) / 0.6)',\n padding: '0 10px 6px',\n fontWeight: 600,\n }}\n >\n {section.label}\n </div>\n <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'grid', gap: 1 }}>\n {section.items.map((item) => {\n const isActive = item.href === activeHref;\n const Icon = item.icon as LucideIcon;\n const linkStyle: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n fontSize: 13.5,\n fontWeight: isActive ? 600 : 500,\n color: isActive\n ? 'hsl(var(--foreground, 222 47% 11%))'\n : 'hsl(var(--muted-foreground, 220 9% 46%))',\n padding: '7px 10px',\n borderRadius: 8,\n background: isActive ? 'var(--brand-soft)' : 'transparent',\n cursor: 'pointer',\n textDecoration: 'none',\n };\n return (\n <li key={item.href}>\n <Link href={item.href} onClick={onNavigate} style={linkStyle}>\n <Icon size={15} strokeWidth={2} />\n <span style={{ flex: 1 }}>{item.label}</span>\n </Link>\n </li>\n );\n })}\n </ul>\n </div>\n ))}\n </nav>\n );\n}\n\nfunction WorkspaceChiclet({ name }: { name: string }) {\n return (\n <span\n aria-hidden\n style={{\n width: 28,\n height: 28,\n flex: '0 0 28px',\n borderRadius: 8,\n background: 'var(--brand-soft)',\n color: 'var(--brand-color)',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 13,\n fontWeight: 700,\n textTransform: 'uppercase',\n border: '1px solid var(--brand-soft)',\n }}\n >\n {name.slice(0, 1)}\n </span>\n );\n}\n\nfunction ForjioBadge() {\n return (\n <span\n title=\"Forjio-operated workspace\"\n style={{\n fontSize: 10,\n textTransform: 'uppercase',\n letterSpacing: '0.06em',\n color: 'var(--brand-color)',\n background: 'var(--brand-soft)',\n border: '1px solid var(--brand-soft)',\n padding: '1px 6px',\n borderRadius: 4,\n flex: '0 0 auto',\n }}\n >\n forjio\n </span>\n );\n}\n\nfunction WorkspaceSwitcher({\n active,\n others,\n hasAny,\n onSwitch,\n onNavigate,\n}: {\n active: PortalWorkspace | null;\n others: PortalWorkspace[];\n hasAny: boolean;\n onSwitch: (id: string) => void;\n onNavigate?: () => void;\n}) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n function onClick(e: MouseEvent) {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n }\n document.addEventListener('mousedown', onClick);\n return () => document.removeEventListener('mousedown', onClick);\n }, []);\n\n if (!hasAny) return null;\n\n return (\n <div\n ref={ref}\n style={{\n position: 'relative',\n padding: '12px 10px',\n borderBottom: '1px solid hsl(var(--border, 220 14% 90%))',\n }}\n >\n {open && others.length > 0 && (\n <div\n style={{\n position: 'absolute',\n top: '100%',\n left: 10,\n right: 10,\n marginTop: 6,\n borderRadius: 10,\n border: '1px solid hsl(var(--border, 220 14% 90%))',\n background: 'hsl(var(--card, 0 0% 100%))',\n boxShadow: '0 10px 30px -12px rgba(0, 0, 0, 0.5)',\n padding: 4,\n zIndex: 20,\n }}\n >\n {others.map((w) => (\n <button\n key={w.id}\n type=\"button\"\n onClick={() => {\n setOpen(false);\n onSwitch(w.id);\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n width: '100%',\n padding: '8px 10px',\n border: 'none',\n background: 'transparent',\n textAlign: 'left',\n cursor: 'pointer',\n borderRadius: 6,\n color: 'inherit',\n }}\n >\n <WorkspaceChiclet name={w.name} />\n <span style={{ flex: 1, minWidth: 0 }}>\n <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span\n style={{\n fontSize: 13,\n fontWeight: 600,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {w.name}\n </span>\n {w.isForjioInternal && <ForjioBadge />}\n </span>\n <span\n style={{\n display: 'block',\n fontSize: 11.5,\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n }}\n >\n {titleCase(w.role)}\n </span>\n </span>\n </button>\n ))}\n <div style={{ borderTop: '1px solid hsl(var(--border, 220 14% 90%))', margin: '4px 0' }} />\n <Link\n href=\"/dashboard/workspaces\"\n onClick={() => {\n setOpen(false);\n onNavigate?.();\n }}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '8px 10px',\n fontSize: 13,\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n textDecoration: 'none',\n borderRadius: 6,\n }}\n >\n + Manage workspaces\n </Link>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n disabled={!active}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n width: '100%',\n padding: '6px 6px',\n border: 'none',\n borderRadius: 8,\n background: 'transparent',\n cursor: active ? 'pointer' : 'default',\n textAlign: 'left',\n color: 'inherit',\n }}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n >\n <WorkspaceChiclet name={active?.name ?? '?'} />\n <span style={{ minWidth: 0, flex: 1 }}>\n <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>\n <span\n style={{\n fontSize: 13,\n fontWeight: 600,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {active?.name ?? 'Loading…'}\n </span>\n {active?.isForjioInternal && <ForjioBadge />}\n </span>\n <span\n style={{\n display: 'block',\n fontSize: 11.5,\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n }}\n >\n {active ? titleCase(active.role) : ''}\n </span>\n </span>\n <ChevronUp\n size={14}\n strokeWidth={2}\n style={{\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n transform: open ? 'rotate(180deg)' : '',\n transition: 'transform 120ms ease',\n }}\n />\n </button>\n </div>\n );\n}\n\nfunction ProfileDropdown({\n user,\n onLogout,\n onNavigate,\n dropdownLinks,\n}: {\n user: SessionUser | null;\n onLogout: () => void | Promise<void>;\n onNavigate?: () => void;\n dropdownLinks: { href: string; label: string; icon: LucideIcon }[];\n}) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n function onClick(e: MouseEvent) {\n if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);\n }\n document.addEventListener('mousedown', onClick);\n return () => document.removeEventListener('mousedown', onClick);\n }, []);\n\n const name = user?.name || 'You';\n const email = user?.email || '';\n const initial = (user?.name || user?.email || '?').slice(0, 1).toUpperCase();\n\n const itemStyle: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n padding: '8px 12px',\n fontSize: 13,\n color: 'inherit',\n borderRadius: 6,\n textDecoration: 'none',\n };\n\n return (\n <div\n ref={ref}\n style={{\n position: 'relative',\n borderTop: '1px solid hsl(var(--border, 220 14% 90%))',\n padding: '12px 10px',\n }}\n >\n {open && (\n <div\n style={{\n position: 'absolute',\n bottom: '100%',\n left: 10,\n right: 10,\n marginBottom: 6,\n borderRadius: 10,\n border: '1px solid hsl(var(--border, 220 14% 90%))',\n background: 'hsl(var(--card, 0 0% 100%))',\n boxShadow: '0 10px 30px -12px rgba(0, 0, 0, 0.5)',\n padding: 4,\n zIndex: 20,\n }}\n >\n <div\n style={{\n padding: '10px 12px',\n borderBottom: '1px solid hsl(var(--border, 220 14% 90%))',\n }}\n >\n <div style={{ fontSize: 13, fontWeight: 600 }}>{name}</div>\n <div\n style={{\n fontSize: 12,\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n wordBreak: 'break-all',\n }}\n >\n {email}\n </div>\n </div>\n {dropdownLinks.map((link) => {\n const Icon = link.icon;\n return (\n <Link\n key={link.href}\n href={link.href}\n onClick={() => {\n setOpen(false);\n onNavigate?.();\n }}\n style={itemStyle}\n >\n <Icon size={14} /> {link.label}\n </Link>\n );\n })}\n <div style={{ borderTop: '1px solid hsl(var(--border, 220 14% 90%))', margin: '4px 0' }} />\n <button\n type=\"button\"\n onClick={() => {\n setOpen(false);\n onLogout();\n }}\n style={{\n ...itemStyle,\n color: 'hsl(var(--destructive, 0 84% 60%))',\n width: '100%',\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <LogOut size={14} /> Sign out\n </button>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n width: '100%',\n padding: '8px 8px',\n border: 'none',\n borderRadius: 8,\n background: 'transparent',\n cursor: 'pointer',\n textAlign: 'left',\n color: 'inherit',\n }}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n >\n <span\n style={{\n width: 32,\n height: 32,\n flex: '0 0 32px',\n borderRadius: '50%',\n background: 'var(--brand-color)',\n color: '#0b0b10',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 13,\n fontWeight: 700,\n }}\n >\n {initial}\n </span>\n <span style={{ minWidth: 0, flex: 1 }}>\n <span\n style={{\n display: 'block',\n fontSize: 13,\n fontWeight: 600,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {name}\n </span>\n <span\n style={{\n display: 'block',\n fontSize: 11.5,\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {email}\n </span>\n </span>\n <ChevronUp\n size={14}\n strokeWidth={2}\n style={{\n color: 'hsl(var(--muted-foreground, 220 9% 46%))',\n transform: open ? '' : 'rotate(180deg)',\n transition: 'transform 120ms ease',\n }}\n />\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var index_exports = {};
20
+ __export(index_exports, {
21
+ Sidebar: () => import_Sidebar.Sidebar,
22
+ activeHrefFor: () => import_utils.activeHrefFor,
23
+ readActiveWorkspaceId: () => import_utils.readActiveWorkspaceId,
24
+ titleCase: () => import_utils.titleCase,
25
+ writeActiveWorkspace: () => import_utils.writeActiveWorkspace
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+ var import_Sidebar = require("./Sidebar");
29
+ var import_utils = require("./utils");
30
+ // Annotate the CommonJS export names for ESM import in node:
31
+ 0 && (module.exports = {
32
+ Sidebar,
33
+ activeHrefFor,
34
+ readActiveWorkspaceId,
35
+ titleCase,
36
+ writeActiveWorkspace
37
+ });
38
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { Sidebar } from './Sidebar';\nexport type { SidebarProps } from './Sidebar';\nexport type {\n NavItem,\n NavSection,\n PortalWorkspace,\n SessionUser,\n WorkspacePersistMode,\n LucideIcon,\n} from './types';\nexport {\n activeHrefFor,\n titleCase,\n writeActiveWorkspace,\n readActiveWorkspaceId,\n} from './utils';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAwB;AAUxB,mBAKO;","names":[]}
@@ -0,0 +1,4 @@
1
+ export { Sidebar, SidebarProps } from './Sidebar.cjs';
2
+ export { LucideIcon, NavItem, NavSection, PortalWorkspace, SessionUser, WorkspacePersistMode } from './types.cjs';
3
+ export { activeHrefFor, readActiveWorkspaceId, titleCase, writeActiveWorkspace } from './utils.cjs';
4
+ import 'react';
@@ -0,0 +1,4 @@
1
+ export { Sidebar, SidebarProps } from './Sidebar.js';
2
+ export { LucideIcon, NavItem, NavSection, PortalWorkspace, SessionUser, WorkspacePersistMode } from './types.js';
3
+ export { activeHrefFor, readActiveWorkspaceId, titleCase, writeActiveWorkspace } from './utils.js';
4
+ import 'react';
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import { Sidebar } from "./Sidebar";
2
+ import {
3
+ activeHrefFor,
4
+ titleCase,
5
+ writeActiveWorkspace,
6
+ readActiveWorkspaceId
7
+ } from "./utils";
8
+ export {
9
+ Sidebar,
10
+ activeHrefFor,
11
+ readActiveWorkspaceId,
12
+ titleCase,
13
+ writeActiveWorkspace
14
+ };
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { Sidebar } from './Sidebar';\nexport type { SidebarProps } from './Sidebar';\nexport type {\n NavItem,\n NavSection,\n PortalWorkspace,\n SessionUser,\n WorkspacePersistMode,\n LucideIcon,\n} from './types';\nexport {\n activeHrefFor,\n titleCase,\n writeActiveWorkspace,\n readActiveWorkspaceId,\n} from './utils';\n"],"mappings":"AAAA,SAAS,eAAe;AAUxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}
package/dist/types.cjs ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
17
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { ComponentType, ReactNode, SVGProps } from 'react';\n\nexport type LucideIcon = ComponentType<{\n size?: number;\n strokeWidth?: number;\n style?: React.CSSProperties;\n}>;\n\nexport interface NavItem {\n href: string;\n label: string;\n icon: LucideIcon;\n}\n\nexport interface NavSection {\n label: string;\n items: NavItem[];\n}\n\nexport interface PortalWorkspace {\n id: string;\n name: string;\n slug?: string;\n plan?: string;\n role?: 'owner' | 'admin' | 'member';\n /** Forjio-internal workspaces get a tiny \"forjio\" badge in the\n * switcher — set on bang's own workspaces, never on customer\n * ones. */\n isForjioInternal?: boolean;\n}\n\nexport interface SessionUser {\n name?: string;\n email?: string;\n}\n\n/**\n * How the active workspace is persisted across page reloads.\n *\n * - `cookie`: writes `<brand>_active_workspace` cookie. Recommended.\n * The backend's auth middleware can read it without a header round-\n * trip. Survives reloads cleanly across subdomains.\n * - `local`: writes `<brand>_active_workspace` to localStorage AND\n * sends `X-Account-Id` header on every request. Legacy pattern\n * from storlaunch/linksnap; works but more fragile.\n * - `api`: POSTs to a `/account/workspaces/<id>/switch` endpoint\n * that mutates server-side session state. Legacy pattern from\n * huudis itself.\n */\nexport type WorkspacePersistMode = 'cookie' | 'local' | 'api';\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,47 @@
1
+ import { ComponentType } from 'react';
2
+
3
+ type LucideIcon = ComponentType<{
4
+ size?: number;
5
+ strokeWidth?: number;
6
+ style?: React.CSSProperties;
7
+ }>;
8
+ interface NavItem {
9
+ href: string;
10
+ label: string;
11
+ icon: LucideIcon;
12
+ }
13
+ interface NavSection {
14
+ label: string;
15
+ items: NavItem[];
16
+ }
17
+ interface PortalWorkspace {
18
+ id: string;
19
+ name: string;
20
+ slug?: string;
21
+ plan?: string;
22
+ role?: 'owner' | 'admin' | 'member';
23
+ /** Forjio-internal workspaces get a tiny "forjio" badge in the
24
+ * switcher — set on bang's own workspaces, never on customer
25
+ * ones. */
26
+ isForjioInternal?: boolean;
27
+ }
28
+ interface SessionUser {
29
+ name?: string;
30
+ email?: string;
31
+ }
32
+ /**
33
+ * How the active workspace is persisted across page reloads.
34
+ *
35
+ * - `cookie`: writes `<brand>_active_workspace` cookie. Recommended.
36
+ * The backend's auth middleware can read it without a header round-
37
+ * trip. Survives reloads cleanly across subdomains.
38
+ * - `local`: writes `<brand>_active_workspace` to localStorage AND
39
+ * sends `X-Account-Id` header on every request. Legacy pattern
40
+ * from storlaunch/linksnap; works but more fragile.
41
+ * - `api`: POSTs to a `/account/workspaces/<id>/switch` endpoint
42
+ * that mutates server-side session state. Legacy pattern from
43
+ * huudis itself.
44
+ */
45
+ type WorkspacePersistMode = 'cookie' | 'local' | 'api';
46
+
47
+ export type { LucideIcon, NavItem, NavSection, PortalWorkspace, SessionUser, WorkspacePersistMode };
@@ -0,0 +1,47 @@
1
+ import { ComponentType } from 'react';
2
+
3
+ type LucideIcon = ComponentType<{
4
+ size?: number;
5
+ strokeWidth?: number;
6
+ style?: React.CSSProperties;
7
+ }>;
8
+ interface NavItem {
9
+ href: string;
10
+ label: string;
11
+ icon: LucideIcon;
12
+ }
13
+ interface NavSection {
14
+ label: string;
15
+ items: NavItem[];
16
+ }
17
+ interface PortalWorkspace {
18
+ id: string;
19
+ name: string;
20
+ slug?: string;
21
+ plan?: string;
22
+ role?: 'owner' | 'admin' | 'member';
23
+ /** Forjio-internal workspaces get a tiny "forjio" badge in the
24
+ * switcher — set on bang's own workspaces, never on customer
25
+ * ones. */
26
+ isForjioInternal?: boolean;
27
+ }
28
+ interface SessionUser {
29
+ name?: string;
30
+ email?: string;
31
+ }
32
+ /**
33
+ * How the active workspace is persisted across page reloads.
34
+ *
35
+ * - `cookie`: writes `<brand>_active_workspace` cookie. Recommended.
36
+ * The backend's auth middleware can read it without a header round-
37
+ * trip. Survives reloads cleanly across subdomains.
38
+ * - `local`: writes `<brand>_active_workspace` to localStorage AND
39
+ * sends `X-Account-Id` header on every request. Legacy pattern
40
+ * from storlaunch/linksnap; works but more fragile.
41
+ * - `api`: POSTs to a `/account/workspaces/<id>/switch` endpoint
42
+ * that mutates server-side session state. Legacy pattern from
43
+ * huudis itself.
44
+ */
45
+ type WorkspacePersistMode = 'cookie' | 'local' | 'api';
46
+
47
+ export type { LucideIcon, NavItem, NavSection, PortalWorkspace, SessionUser, WorkspacePersistMode };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/utils.cjs ADDED
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var utils_exports = {};
20
+ __export(utils_exports, {
21
+ activeHrefFor: () => activeHrefFor,
22
+ readActiveWorkspaceId: () => readActiveWorkspaceId,
23
+ titleCase: () => titleCase,
24
+ writeActiveWorkspace: () => writeActiveWorkspace
25
+ });
26
+ module.exports = __toCommonJS(utils_exports);
27
+ function activeHrefFor(pathname, sections) {
28
+ const candidates = sections.flatMap((s) => s.items.map((i) => i.href));
29
+ let best = null;
30
+ for (const href of candidates) {
31
+ const matches = href === "/dashboard" ? pathname === "/dashboard" : pathname === href || pathname.startsWith(href + "/");
32
+ if (matches && (best === null || href.length > best.length)) best = href;
33
+ }
34
+ return best;
35
+ }
36
+ function titleCase(s) {
37
+ if (!s) return "";
38
+ return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
39
+ }
40
+ function writeActiveWorkspace(mode, brandSlug, workspaceId, apiSwitchPath) {
41
+ if (typeof window === "undefined") return;
42
+ if (mode === "cookie") {
43
+ const secure = location.protocol === "https:" ? "; Secure" : "";
44
+ document.cookie = `${brandSlug}_active_workspace=${encodeURIComponent(
45
+ workspaceId
46
+ )}; path=/; max-age=${30 * 24 * 60 * 60}; SameSite=Lax${secure}`;
47
+ return;
48
+ }
49
+ if (mode === "local") {
50
+ localStorage.setItem(`${brandSlug}_active_workspace`, workspaceId);
51
+ return;
52
+ }
53
+ if (mode === "api" && apiSwitchPath) {
54
+ return fetch(apiSwitchPath.replace("{id}", encodeURIComponent(workspaceId)), {
55
+ method: "POST",
56
+ credentials: "include"
57
+ }).then(() => void 0);
58
+ }
59
+ }
60
+ function readActiveWorkspaceId(mode, brandSlug) {
61
+ if (typeof window === "undefined") return null;
62
+ if (mode === "cookie") {
63
+ const match = document.cookie.split("; ").find((r) => r.startsWith(`${brandSlug}_active_workspace=`));
64
+ if (!match) return null;
65
+ return decodeURIComponent(match.split("=").slice(1).join("="));
66
+ }
67
+ if (mode === "local") {
68
+ return localStorage.getItem(`${brandSlug}_active_workspace`);
69
+ }
70
+ return null;
71
+ }
72
+ // Annotate the CommonJS export names for ESM import in node:
73
+ 0 && (module.exports = {
74
+ activeHrefFor,
75
+ readActiveWorkspaceId,
76
+ titleCase,
77
+ writeActiveWorkspace
78
+ });
79
+ //# sourceMappingURL=utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import type { NavSection } from './types';\n\n/** Find the longest-prefix-matching href in `sections` for the\n * current pathname. Used by Sidebar to highlight the active item. */\nexport function activeHrefFor(pathname: string, sections: NavSection[]): string | null {\n const candidates = sections.flatMap((s) => s.items.map((i) => i.href));\n let best: string | null = null;\n for (const href of candidates) {\n const matches =\n href === '/dashboard'\n ? pathname === '/dashboard'\n : pathname === href || pathname.startsWith(href + '/');\n if (matches && (best === null || href.length > best.length)) best = href;\n }\n return best;\n}\n\nexport function titleCase(s: string | null | undefined): string {\n if (!s) return '';\n return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\n/**\n * Persist + reload pattern shared across the three storage modes.\n * Sidebar passes whichever flavor the consuming product uses; this\n * util encapsulates the cookie/localStorage/API call.\n */\nexport function writeActiveWorkspace(\n mode: 'cookie' | 'local' | 'api',\n brandSlug: string,\n workspaceId: string,\n apiSwitchPath?: string,\n): void | Promise<void> {\n if (typeof window === 'undefined') return;\n if (mode === 'cookie') {\n const secure = location.protocol === 'https:' ? '; Secure' : '';\n document.cookie = `${brandSlug}_active_workspace=${encodeURIComponent(\n workspaceId,\n )}; path=/; max-age=${30 * 24 * 60 * 60}; SameSite=Lax${secure}`;\n return;\n }\n if (mode === 'local') {\n localStorage.setItem(`${brandSlug}_active_workspace`, workspaceId);\n return;\n }\n if (mode === 'api' && apiSwitchPath) {\n return fetch(apiSwitchPath.replace('{id}', encodeURIComponent(workspaceId)), {\n method: 'POST',\n credentials: 'include',\n }).then(() => undefined);\n }\n}\n\n/** Read whichever persistence the consumer uses. Returns null on SSR\n * (no window). For `api` mode the caller should pull from session\n * themselves — there's no stable client-side cache. */\nexport function readActiveWorkspaceId(\n mode: 'cookie' | 'local' | 'api',\n brandSlug: string,\n): string | null {\n if (typeof window === 'undefined') return null;\n if (mode === 'cookie') {\n const match = document.cookie\n .split('; ')\n .find((r) => r.startsWith(`${brandSlug}_active_workspace=`));\n if (!match) return null;\n return decodeURIComponent(match.split('=').slice(1).join('='));\n }\n if (mode === 'local') {\n return localStorage.getItem(`${brandSlug}_active_workspace`);\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,SAAS,cAAc,UAAkB,UAAuC;AACrF,QAAM,aAAa,SAAS,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACrE,MAAI,OAAsB;AAC1B,aAAW,QAAQ,YAAY;AAC7B,UAAM,UACJ,SAAS,eACL,aAAa,eACb,aAAa,QAAQ,SAAS,WAAW,OAAO,GAAG;AACzD,QAAI,YAAY,SAAS,QAAQ,KAAK,SAAS,KAAK,QAAS,QAAO;AAAA,EACtE;AACA,SAAO;AACT;AAEO,SAAS,UAAU,GAAsC;AAC9D,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY;AAC5D;AAOO,SAAS,qBACd,MACA,WACA,aACA,eACsB;AACtB,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI,SAAS,UAAU;AACrB,UAAM,SAAS,SAAS,aAAa,WAAW,aAAa;AAC7D,aAAS,SAAS,GAAG,SAAS,qBAAqB;AAAA,MACjD;AAAA,IACF,CAAC,qBAAqB,KAAK,KAAK,KAAK,EAAE,iBAAiB,MAAM;AAC9D;AAAA,EACF;AACA,MAAI,SAAS,SAAS;AACpB,iBAAa,QAAQ,GAAG,SAAS,qBAAqB,WAAW;AACjE;AAAA,EACF;AACA,MAAI,SAAS,SAAS,eAAe;AACnC,WAAO,MAAM,cAAc,QAAQ,QAAQ,mBAAmB,WAAW,CAAC,GAAG;AAAA,MAC3E,QAAQ;AAAA,MACR,aAAa;AAAA,IACf,CAAC,EAAE,KAAK,MAAM,MAAS;AAAA,EACzB;AACF;AAKO,SAAS,sBACd,MACA,WACe;AACf,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI,SAAS,UAAU;AACrB,UAAM,QAAQ,SAAS,OACpB,MAAM,IAAI,EACV,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,oBAAoB,CAAC;AAC7D,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,mBAAmB,MAAM,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC;AAAA,EAC/D;AACA,MAAI,SAAS,SAAS;AACpB,WAAO,aAAa,QAAQ,GAAG,SAAS,mBAAmB;AAAA,EAC7D;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,19 @@
1
+ import { NavSection } from './types.cjs';
2
+ import 'react';
3
+
4
+ /** Find the longest-prefix-matching href in `sections` for the
5
+ * current pathname. Used by Sidebar to highlight the active item. */
6
+ declare function activeHrefFor(pathname: string, sections: NavSection[]): string | null;
7
+ declare function titleCase(s: string | null | undefined): string;
8
+ /**
9
+ * Persist + reload pattern shared across the three storage modes.
10
+ * Sidebar passes whichever flavor the consuming product uses; this
11
+ * util encapsulates the cookie/localStorage/API call.
12
+ */
13
+ declare function writeActiveWorkspace(mode: 'cookie' | 'local' | 'api', brandSlug: string, workspaceId: string, apiSwitchPath?: string): void | Promise<void>;
14
+ /** Read whichever persistence the consumer uses. Returns null on SSR
15
+ * (no window). For `api` mode the caller should pull from session
16
+ * themselves — there's no stable client-side cache. */
17
+ declare function readActiveWorkspaceId(mode: 'cookie' | 'local' | 'api', brandSlug: string): string | null;
18
+
19
+ export { activeHrefFor, readActiveWorkspaceId, titleCase, writeActiveWorkspace };
@@ -0,0 +1,19 @@
1
+ import { NavSection } from './types.js';
2
+ import 'react';
3
+
4
+ /** Find the longest-prefix-matching href in `sections` for the
5
+ * current pathname. Used by Sidebar to highlight the active item. */
6
+ declare function activeHrefFor(pathname: string, sections: NavSection[]): string | null;
7
+ declare function titleCase(s: string | null | undefined): string;
8
+ /**
9
+ * Persist + reload pattern shared across the three storage modes.
10
+ * Sidebar passes whichever flavor the consuming product uses; this
11
+ * util encapsulates the cookie/localStorage/API call.
12
+ */
13
+ declare function writeActiveWorkspace(mode: 'cookie' | 'local' | 'api', brandSlug: string, workspaceId: string, apiSwitchPath?: string): void | Promise<void>;
14
+ /** Read whichever persistence the consumer uses. Returns null on SSR
15
+ * (no window). For `api` mode the caller should pull from session
16
+ * themselves — there's no stable client-side cache. */
17
+ declare function readActiveWorkspaceId(mode: 'cookie' | 'local' | 'api', brandSlug: string): string | null;
18
+
19
+ export { activeHrefFor, readActiveWorkspaceId, titleCase, writeActiveWorkspace };
package/dist/utils.js ADDED
@@ -0,0 +1,52 @@
1
+ function activeHrefFor(pathname, sections) {
2
+ const candidates = sections.flatMap((s) => s.items.map((i) => i.href));
3
+ let best = null;
4
+ for (const href of candidates) {
5
+ const matches = href === "/dashboard" ? pathname === "/dashboard" : pathname === href || pathname.startsWith(href + "/");
6
+ if (matches && (best === null || href.length > best.length)) best = href;
7
+ }
8
+ return best;
9
+ }
10
+ function titleCase(s) {
11
+ if (!s) return "";
12
+ return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
13
+ }
14
+ function writeActiveWorkspace(mode, brandSlug, workspaceId, apiSwitchPath) {
15
+ if (typeof window === "undefined") return;
16
+ if (mode === "cookie") {
17
+ const secure = location.protocol === "https:" ? "; Secure" : "";
18
+ document.cookie = `${brandSlug}_active_workspace=${encodeURIComponent(
19
+ workspaceId
20
+ )}; path=/; max-age=${30 * 24 * 60 * 60}; SameSite=Lax${secure}`;
21
+ return;
22
+ }
23
+ if (mode === "local") {
24
+ localStorage.setItem(`${brandSlug}_active_workspace`, workspaceId);
25
+ return;
26
+ }
27
+ if (mode === "api" && apiSwitchPath) {
28
+ return fetch(apiSwitchPath.replace("{id}", encodeURIComponent(workspaceId)), {
29
+ method: "POST",
30
+ credentials: "include"
31
+ }).then(() => void 0);
32
+ }
33
+ }
34
+ function readActiveWorkspaceId(mode, brandSlug) {
35
+ if (typeof window === "undefined") return null;
36
+ if (mode === "cookie") {
37
+ const match = document.cookie.split("; ").find((r) => r.startsWith(`${brandSlug}_active_workspace=`));
38
+ if (!match) return null;
39
+ return decodeURIComponent(match.split("=").slice(1).join("="));
40
+ }
41
+ if (mode === "local") {
42
+ return localStorage.getItem(`${brandSlug}_active_workspace`);
43
+ }
44
+ return null;
45
+ }
46
+ export {
47
+ activeHrefFor,
48
+ readActiveWorkspaceId,
49
+ titleCase,
50
+ writeActiveWorkspace
51
+ };
52
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import type { NavSection } from './types';\n\n/** Find the longest-prefix-matching href in `sections` for the\n * current pathname. Used by Sidebar to highlight the active item. */\nexport function activeHrefFor(pathname: string, sections: NavSection[]): string | null {\n const candidates = sections.flatMap((s) => s.items.map((i) => i.href));\n let best: string | null = null;\n for (const href of candidates) {\n const matches =\n href === '/dashboard'\n ? pathname === '/dashboard'\n : pathname === href || pathname.startsWith(href + '/');\n if (matches && (best === null || href.length > best.length)) best = href;\n }\n return best;\n}\n\nexport function titleCase(s: string | null | undefined): string {\n if (!s) return '';\n return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\n/**\n * Persist + reload pattern shared across the three storage modes.\n * Sidebar passes whichever flavor the consuming product uses; this\n * util encapsulates the cookie/localStorage/API call.\n */\nexport function writeActiveWorkspace(\n mode: 'cookie' | 'local' | 'api',\n brandSlug: string,\n workspaceId: string,\n apiSwitchPath?: string,\n): void | Promise<void> {\n if (typeof window === 'undefined') return;\n if (mode === 'cookie') {\n const secure = location.protocol === 'https:' ? '; Secure' : '';\n document.cookie = `${brandSlug}_active_workspace=${encodeURIComponent(\n workspaceId,\n )}; path=/; max-age=${30 * 24 * 60 * 60}; SameSite=Lax${secure}`;\n return;\n }\n if (mode === 'local') {\n localStorage.setItem(`${brandSlug}_active_workspace`, workspaceId);\n return;\n }\n if (mode === 'api' && apiSwitchPath) {\n return fetch(apiSwitchPath.replace('{id}', encodeURIComponent(workspaceId)), {\n method: 'POST',\n credentials: 'include',\n }).then(() => undefined);\n }\n}\n\n/** Read whichever persistence the consumer uses. Returns null on SSR\n * (no window). For `api` mode the caller should pull from session\n * themselves — there's no stable client-side cache. */\nexport function readActiveWorkspaceId(\n mode: 'cookie' | 'local' | 'api',\n brandSlug: string,\n): string | null {\n if (typeof window === 'undefined') return null;\n if (mode === 'cookie') {\n const match = document.cookie\n .split('; ')\n .find((r) => r.startsWith(`${brandSlug}_active_workspace=`));\n if (!match) return null;\n return decodeURIComponent(match.split('=').slice(1).join('='));\n }\n if (mode === 'local') {\n return localStorage.getItem(`${brandSlug}_active_workspace`);\n }\n return null;\n}\n"],"mappings":"AAIO,SAAS,cAAc,UAAkB,UAAuC;AACrF,QAAM,aAAa,SAAS,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACrE,MAAI,OAAsB;AAC1B,aAAW,QAAQ,YAAY;AAC7B,UAAM,UACJ,SAAS,eACL,aAAa,eACb,aAAa,QAAQ,SAAS,WAAW,OAAO,GAAG;AACzD,QAAI,YAAY,SAAS,QAAQ,KAAK,SAAS,KAAK,QAAS,QAAO;AAAA,EACtE;AACA,SAAO;AACT;AAEO,SAAS,UAAU,GAAsC;AAC9D,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY;AAC5D;AAOO,SAAS,qBACd,MACA,WACA,aACA,eACsB;AACtB,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI,SAAS,UAAU;AACrB,UAAM,SAAS,SAAS,aAAa,WAAW,aAAa;AAC7D,aAAS,SAAS,GAAG,SAAS,qBAAqB;AAAA,MACjD;AAAA,IACF,CAAC,qBAAqB,KAAK,KAAK,KAAK,EAAE,iBAAiB,MAAM;AAC9D;AAAA,EACF;AACA,MAAI,SAAS,SAAS;AACpB,iBAAa,QAAQ,GAAG,SAAS,qBAAqB,WAAW;AACjE;AAAA,EACF;AACA,MAAI,SAAS,SAAS,eAAe;AACnC,WAAO,MAAM,cAAc,QAAQ,QAAQ,mBAAmB,WAAW,CAAC,GAAG;AAAA,MAC3E,QAAQ;AAAA,MACR,aAAa;AAAA,IACf,CAAC,EAAE,KAAK,MAAM,MAAS;AAAA,EACzB;AACF;AAKO,SAAS,sBACd,MACA,WACe;AACf,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI,SAAS,UAAU;AACrB,UAAM,QAAQ,SAAS,OACpB,MAAM,IAAI,EACV,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,oBAAoB,CAAC;AAC7D,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,mBAAmB,MAAM,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC;AAAA,EAC/D;AACA,MAAI,SAAS,SAAS;AACpB,WAAO,aAAa,QAAQ,GAAG,SAAS,mBAAmB;AAAA,EAC7D;AACA,SAAO;AACT;","names":[]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@forjio/portal-ui",
3
+ "version": "0.1.0",
4
+ "description": "Shared portal chrome (sidebar, workspace switcher, profile dropdown, portal shell) for the Forjio family of SaaS products. Mirrors @forjio/website-ui but for the authenticated dashboard side.",
5
+ "license": "UNLICENSED",
6
+ "private": false,
7
+ "author": "Forjio <support@forjio.com>",
8
+ "homepage": "https://github.com/hachimi-cat/forjio-portal-ui",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/hachimi-cat/forjio-portal-ui.git"
12
+ },
13
+ "type": "module",
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "typecheck": "tsc --noEmit",
31
+ "prepublishOnly": "npm run build"
32
+ },
33
+ "peerDependencies": {
34
+ "lucide-react": ">=0.300.0",
35
+ "next": ">=14.0.0",
36
+ "react": ">=18.0.0",
37
+ "react-dom": ">=18.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "@types/react": "^19.0.0",
42
+ "@types/react-dom": "^19.0.0",
43
+ "lucide-react": "^0.400.0",
44
+ "next": "^15.5.0",
45
+ "react": "^19.0.0",
46
+ "react-dom": "^19.0.0",
47
+ "tsup": "^8.3.0",
48
+ "typescript": "^5.5.0"
49
+ },
50
+ "keywords": [
51
+ "forjio",
52
+ "portal",
53
+ "ui",
54
+ "sidebar",
55
+ "workspace",
56
+ "dashboard"
57
+ ]
58
+ }