@protobase/ui 0.55.2 → 0.55.3
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/app/nav-from-meta.js +19 -3
- package/dist/app-shell/sidebar-create-link.js +26 -0
- package/dist/app-shell/sidebar-group.js +6 -14
- package/dist/app-shell/sidebar-rows.js +13 -0
- package/dist/app-shell/sidebar.js +11 -5
- package/dist/package.js +1 -1
- package/dist/shell/assets/{app-CTbX0_B2.js → app-CAj-S5YI.js} +7 -7
- package/dist/shell/assets/{index-CY05Rf2z.js → index-CEhwvXIf.js} +2 -2
- package/dist/shell/assets/{records-map-DA9Zv2ST.js → records-map-Cp4sUeC-.js} +2 -2
- package/dist/shell/assets/{shared-protobase-ui-DjAPl6MN.js → shared-protobase-ui-Dd4pdw8C.js} +2 -2
- package/dist/shell/index.html +3 -3
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/shell/protobase.sw.js +2 -2
- package/dist/shell-source-maps/assets/app-CAj-S5YI.js.map +1 -0
- package/dist/shell-source-maps/assets/{index-CY05Rf2z.js.map → index-CEhwvXIf.js.map} +1 -1
- package/dist/shell-source-maps/assets/{records-map-DA9Zv2ST.js.map → records-map-Cp4sUeC-.js.map} +1 -1
- package/dist/shell-source-maps/assets/{shared-protobase-ui-DjAPl6MN.js.map → shared-protobase-ui-Dd4pdw8C.js.map} +1 -1
- package/package.json +4 -4
- package/dist/shell-source-maps/assets/app-CTbX0_B2.js.map +0 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { allowEverything } from "../data/meta-data.js";
|
|
1
2
|
import { humanize } from "../live/naming.js";
|
|
2
3
|
import { text } from "./messages.js";
|
|
4
|
+
import { text as text$1 } from "./create/messages.js";
|
|
3
5
|
import { iconFor } from "./icons.js";
|
|
4
6
|
import { menuIcon } from "./menu-icons.js";
|
|
7
|
+
import { createOffered } from "./create/create-offered.js";
|
|
5
8
|
import { userMenuResources } from "./user-menu-from-meta.js";
|
|
6
9
|
import { LayoutDashboard } from "lucide-react";
|
|
7
10
|
import { appPath } from "@protobase/schema";
|
|
@@ -21,10 +24,21 @@ const schemaGroup = (schema = "public") => {
|
|
|
21
24
|
if (schema === "public") return "";
|
|
22
25
|
return groupLabels[schema] ? text(groupLabels[schema]) : humanize(schema);
|
|
23
26
|
};
|
|
27
|
+
/** The link under an entry whose `nav.create` asks for one, to whoever the list would offer New. */
|
|
28
|
+
const createLink = (meta, view, nav, singular, basePath) => {
|
|
29
|
+
if (!nav?.create || !createOffered(view, meta.pages, meta.permissions[view.resource] ?? allowEverything)) return {};
|
|
30
|
+
return { create: {
|
|
31
|
+
label: nav.create === true ? text$1("title", singular) : nav.create.label,
|
|
32
|
+
href: appPath({
|
|
33
|
+
kind: "create",
|
|
34
|
+
resource: view.resource
|
|
35
|
+
}, basePath)
|
|
36
|
+
} };
|
|
37
|
+
};
|
|
24
38
|
/**
|
|
25
39
|
* One sidebar group per `nav.group` (default: the database schema, none for `public`, and "Pages" for pages); `nav.hidden` and a place in
|
|
26
40
|
* the user menu leave an entry out, `nav.order` sorts within a group, and `recent` (from `useNavRecent`) makes an entry
|
|
27
|
-
* collapsible. Groups with pages come first, so a dashboard leads the sidebar. The resources of a source that cannot be
|
|
41
|
+
* collapsible, and `create` links to the create form under it. Groups with pages come first, so a dashboard leads the sidebar. The resources of a source that cannot be
|
|
28
42
|
* read are listed under its label, each with the problem. A visitor also gets the resources whose views ask them to sign
|
|
29
43
|
* in, where those views place them, under "Account" without a group. Each named list of a view is an entry of its
|
|
30
44
|
* own, placed by its own `nav`.
|
|
@@ -73,7 +87,8 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
|
|
|
73
87
|
kind: "list",
|
|
74
88
|
resource: model.name
|
|
75
89
|
}, basePath),
|
|
76
|
-
...recent[model.name] && { recent: recent[model.name] }
|
|
90
|
+
...recent[model.name] && { recent: recent[model.name] },
|
|
91
|
+
...createLink(meta, view, view.nav, view.names?.singular ?? humanize(model.name), basePath)
|
|
77
92
|
}, view.nav?.order);
|
|
78
93
|
for (const named of view.lists ?? []) {
|
|
79
94
|
if (named.nav?.hidden) continue;
|
|
@@ -85,7 +100,8 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
|
|
|
85
100
|
kind: "list",
|
|
86
101
|
resource: model.name,
|
|
87
102
|
list: named.name
|
|
88
|
-
}, basePath)
|
|
103
|
+
}, basePath),
|
|
104
|
+
...createLink(meta, view, named.nav, named.names.singular, basePath)
|
|
89
105
|
}, named.nav?.order);
|
|
90
106
|
}
|
|
91
107
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { subRow, subRowIndent } from "./sidebar-rows.js";
|
|
3
|
+
import { Plus } from "lucide-react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/app-shell/sidebar-create-link.tsx
|
|
6
|
+
/** The link under a sidebar entry to its resource's create form, such as "New message", lined up with its records. */
|
|
7
|
+
const SidebarCreateLink = ({ create, mode, onNavigate }) => /* @__PURE__ */ jsx("div", {
|
|
8
|
+
className: cn("border-l border-transparent pl-1.5", subRowIndent[mode]),
|
|
9
|
+
children: /* @__PURE__ */ jsxs("a", {
|
|
10
|
+
href: create.href,
|
|
11
|
+
onClick: onNavigate && ((event) => {
|
|
12
|
+
event.preventDefault();
|
|
13
|
+
onNavigate(create.href);
|
|
14
|
+
}),
|
|
15
|
+
className: cn("flex items-center rounded-md text-faint-foreground transition-colors hover:bg-muted hover:text-foreground", subRow[mode]),
|
|
16
|
+
children: [/* @__PURE__ */ jsx(Plus, {
|
|
17
|
+
"aria-hidden": true,
|
|
18
|
+
className: "size-3.5 shrink-0"
|
|
19
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
20
|
+
className: "truncate",
|
|
21
|
+
children: create.label
|
|
22
|
+
})]
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
//#endregion
|
|
26
|
+
export { SidebarCreateLink };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cn } from "../lib/cn.js";
|
|
2
2
|
import { text } from "./messages.js";
|
|
3
|
+
import { subRow, subRowIndent } from "./sidebar-rows.js";
|
|
3
4
|
import { navOpenStorageKey, readNavOpen, writeNavOpen } from "./nav-open-storage.js";
|
|
4
5
|
import { SidebarItem } from "./sidebar-item.js";
|
|
5
6
|
import { StatusDot } from "./status-dot.js";
|
|
@@ -7,15 +8,6 @@ import { useId, useState } from "react";
|
|
|
7
8
|
import { ChevronRight } from "lucide-react";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
//#region src/app-shell/sidebar-group.tsx
|
|
10
|
-
const row = {
|
|
11
|
-
"text-large": "h-8 gap-2.5 px-2.5",
|
|
12
|
-
"text-small": "h-7 gap-2 px-2 text-body"
|
|
13
|
-
};
|
|
14
|
-
/** Lines the records up under the entry's icon. */
|
|
15
|
-
const indent = {
|
|
16
|
-
"text-large": "ml-[20px]",
|
|
17
|
-
"text-small": "ml-[17px]"
|
|
18
|
-
};
|
|
19
11
|
/**
|
|
20
12
|
* A sidebar entry with a few of its records under it. The label opens the list, the chevron shows or hides the
|
|
21
13
|
* records (remembered in this browser), and "View all" at the end opens the list too.
|
|
@@ -58,14 +50,14 @@ const SidebarGroup = ({ item, recent, mode, active, onNavigate }) => {
|
|
|
58
50
|
}), open && /* @__PURE__ */ jsxs("ul", {
|
|
59
51
|
id: listId,
|
|
60
52
|
"aria-label": text("recent", item.label.toLowerCase()),
|
|
61
|
-
className: cn("flex flex-col gap-0.5 border-l pl-1.5",
|
|
53
|
+
className: cn("flex flex-col gap-0.5 border-l pl-1.5", subRowIndent[mode]),
|
|
62
54
|
children: [
|
|
63
55
|
recent.state === "loading" && /* @__PURE__ */ jsx("li", {
|
|
64
|
-
className: cn("flex items-center text-faint-foreground",
|
|
56
|
+
className: cn("flex items-center text-faint-foreground", subRow[mode]),
|
|
65
57
|
children: text("loading")
|
|
66
58
|
}),
|
|
67
59
|
recent.state === "error" && /* @__PURE__ */ jsx("li", {
|
|
68
|
-
className: cn("flex items-center text-faint-foreground",
|
|
60
|
+
className: cn("flex items-center text-faint-foreground", subRow[mode]),
|
|
69
61
|
children: text("couldNotLoad")
|
|
70
62
|
}),
|
|
71
63
|
recent.state === "ready" && recent.records.map((record) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
|
|
@@ -73,7 +65,7 @@ const SidebarGroup = ({ item, recent, mode, active, onNavigate }) => {
|
|
|
73
65
|
"aria-label": record.status ? `${record.label}, ${record.status.label}` : record.label,
|
|
74
66
|
title: record.status ? `${record.label} (${record.status.label})` : record.label,
|
|
75
67
|
"aria-current": record.active ? "page" : void 0,
|
|
76
|
-
className: cn("flex min-w-0 items-center rounded-md font-medium transition-colors",
|
|
68
|
+
className: cn("flex min-w-0 items-center rounded-md font-medium transition-colors", subRow[mode], record.active ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"),
|
|
77
69
|
children: [record.status && /* @__PURE__ */ jsx(StatusDot, {
|
|
78
70
|
tone: record.status.tone,
|
|
79
71
|
pulse: record.status.pulse
|
|
@@ -84,7 +76,7 @@ const SidebarGroup = ({ item, recent, mode, active, onNavigate }) => {
|
|
|
84
76
|
}) }, record.id)),
|
|
85
77
|
/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", {
|
|
86
78
|
...link(href),
|
|
87
|
-
className: cn("flex items-center rounded-md text-faint-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
79
|
+
className: cn("flex items-center rounded-md text-faint-foreground transition-colors hover:bg-muted hover:text-foreground", subRow[mode]),
|
|
88
80
|
children: text("viewAll")
|
|
89
81
|
}) })
|
|
90
82
|
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/app-shell/sidebar-rows.ts
|
|
2
|
+
/** The height and spacing of a row under a sidebar entry, such as a recent record or its create link. */
|
|
3
|
+
const subRow = {
|
|
4
|
+
"text-large": "h-8 gap-2.5 px-2.5",
|
|
5
|
+
"text-small": "h-7 gap-2 px-2 text-body"
|
|
6
|
+
};
|
|
7
|
+
/** Lines the rows under an entry up under the entry's icon. */
|
|
8
|
+
const subRowIndent = {
|
|
9
|
+
"text-large": "ml-[20px]",
|
|
10
|
+
"text-small": "ml-[17px]"
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { subRow, subRowIndent };
|
|
@@ -5,11 +5,13 @@ import { Logo } from "./logo.js";
|
|
|
5
5
|
import { navGroups } from "./nav.js";
|
|
6
6
|
import { ThemeSwitch } from "./theme-switch.js";
|
|
7
7
|
import { ProfileMenu } from "./profile-menu.js";
|
|
8
|
+
import { SidebarCreateLink } from "./sidebar-create-link.js";
|
|
8
9
|
import { isTextMode, sidebarWidth } from "./sidebar-mode.js";
|
|
9
10
|
import { SidebarItem } from "./sidebar-item.js";
|
|
10
11
|
import { SidebarGroup } from "./sidebar-group.js";
|
|
12
|
+
import { Fragment } from "react";
|
|
11
13
|
import { LogIn } from "lucide-react";
|
|
12
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
15
|
//#region src/app-shell/sidebar.tsx
|
|
14
16
|
const Sidebar = ({ mode, activeItem, user, workspace, appName, appIcon, forceExpanded, profileMenuOpen, groups = navGroups, userMenu, account, onNavigate, onSignOut, signIn, organizations, roles, theme, sticky, logo: SidebarLogo = Logo, notice }) => {
|
|
15
17
|
const expanding = mode === "icon-expand";
|
|
@@ -37,18 +39,22 @@ const Sidebar = ({ mode, activeItem, user, workspace, appName, appIcon, forceExp
|
|
|
37
39
|
children: [inline ? group.label && /* @__PURE__ */ jsx("div", {
|
|
38
40
|
className: cn("px-3 pb-1 pt-1 text-xs font-medium uppercase tracking-wide text-faint-foreground", expanding && "h-4 whitespace-nowrap py-0 opacity-0 transition-opacity group-hover/side:opacity-100 group-focus-within/side:opacity-100", expanded && "opacity-100"),
|
|
39
41
|
children: group.label
|
|
40
|
-
}) : index > 0 && /* @__PURE__ */ jsx("div", { className: "mx-auto mb-1 h-px w-6 bg-border" }), group.items.map((item) => item.recent && isTextMode(mode) ? /* @__PURE__ */ jsx(SidebarGroup, {
|
|
42
|
+
}) : index > 0 && /* @__PURE__ */ jsx("div", { className: "mx-auto mb-1 h-px w-6 bg-border" }), group.items.map((item) => /* @__PURE__ */ jsxs(Fragment, { children: [item.recent && isTextMode(mode) ? /* @__PURE__ */ jsx(SidebarGroup, {
|
|
41
43
|
item,
|
|
42
44
|
recent: item.recent,
|
|
43
45
|
mode,
|
|
44
46
|
active: item.id === activeItem,
|
|
45
47
|
onNavigate
|
|
46
|
-
}
|
|
48
|
+
}) : /* @__PURE__ */ jsx(SidebarItem, {
|
|
47
49
|
item,
|
|
48
50
|
mode,
|
|
49
51
|
active: item.id === activeItem,
|
|
50
52
|
onNavigate
|
|
51
|
-
}, item.
|
|
53
|
+
}), item.create && isTextMode(mode) && /* @__PURE__ */ jsx(SidebarCreateLink, {
|
|
54
|
+
create: item.create,
|
|
55
|
+
mode,
|
|
56
|
+
onNavigate
|
|
57
|
+
})] }, item.id))]
|
|
52
58
|
}, group.label))
|
|
53
59
|
}),
|
|
54
60
|
notice,
|
|
@@ -65,7 +71,7 @@ const Sidebar = ({ mode, activeItem, user, workspace, appName, appIcon, forceExp
|
|
|
65
71
|
organizations,
|
|
66
72
|
roles,
|
|
67
73
|
theme
|
|
68
|
-
}) : /* @__PURE__ */ jsxs(Fragment, { children: [theme && inline && /* @__PURE__ */ jsx(ThemeSwitch, {
|
|
74
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [theme && inline && /* @__PURE__ */ jsx(ThemeSwitch, {
|
|
69
75
|
theme,
|
|
70
76
|
className: "flex min-h-11 w-full items-center gap-2.5 whitespace-nowrap p-1.5 text-muted-foreground md:min-h-0"
|
|
71
77
|
}), signIn && /* @__PURE__ */ jsxs(RouteLink, {
|
package/dist/package.js
CHANGED