@fuf-stack/atelier 0.2.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/README.md +40 -0
- package/dist/index.d.mts +1967 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +280 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/types.ts","../src/core/tanstack.ts","../src/core/createAtelierApp.ts","../src/core/createAuthAdapter.ts","../src/core/navigation.ts","../src/core/renderers.ts","../src/AtelierFrame/AtelierFrame.tsx"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { tv, variantsToClassNames } from "@fuf-stack/pixel-utils";
|
|
3
|
+
import Button from "@fuf-stack/pixels/Button";
|
|
4
|
+
import Drawer from "@fuf-stack/pixels/Drawer";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/core/createAuthAdapter.ts
|
|
7
|
+
/**
|
|
8
|
+
* Built-in role-based access fallback.
|
|
9
|
+
* - No declared roles means public access.
|
|
10
|
+
* - Role checks only pass for authenticated users.
|
|
11
|
+
*/
|
|
12
|
+
const defaultCanAccess = (roles, state) => {
|
|
13
|
+
if (roles === void 0 || roles.length <= 0) return true;
|
|
14
|
+
if (state.status !== "authenticated" || !state.user) return false;
|
|
15
|
+
const userRoles = state.user.roles ?? [];
|
|
16
|
+
return roles.some((role) => {
|
|
17
|
+
return userRoles.includes(role);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Builds an auth adapter with safe defaults.
|
|
22
|
+
*
|
|
23
|
+
* Consumers can override any adapter method; `canAccess` always has a default.
|
|
24
|
+
*/
|
|
25
|
+
const createAuthAdapter = (adapter) => {
|
|
26
|
+
return {
|
|
27
|
+
canAccess: defaultCanAccess,
|
|
28
|
+
...adapter
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/core/navigation.ts
|
|
33
|
+
/**
|
|
34
|
+
* Filters a navigation tree according to auth state, item visibility rules,
|
|
35
|
+
* and adapter-level access checks.
|
|
36
|
+
*/
|
|
37
|
+
const filterNavigationForState = (navigation, state, auth = createAuthAdapter()) => {
|
|
38
|
+
return navigation.map((section) => {
|
|
39
|
+
const items = section.items.filter((item) => {
|
|
40
|
+
if (item.requiresAuth && state.status !== "authenticated") return false;
|
|
41
|
+
if (item.isVisible && !item.isVisible(state)) return false;
|
|
42
|
+
if (!auth.canAccess(item.roles, state, item.id)) return false;
|
|
43
|
+
return true;
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
...section,
|
|
47
|
+
items
|
|
48
|
+
};
|
|
49
|
+
}).filter((section) => {
|
|
50
|
+
return section.items.length > 0;
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/core/renderers.ts
|
|
55
|
+
/**
|
|
56
|
+
* Resolves the renderer for a resource:
|
|
57
|
+
* 1) inline `resource.renderer`
|
|
58
|
+
* 2) registry lookup via `resource.rendererId`
|
|
59
|
+
* 3) text-based fallback renderer for loading/ready/empty/error states
|
|
60
|
+
*/
|
|
61
|
+
const getResourceRenderer = (resource, registry = {}) => {
|
|
62
|
+
if (resource.renderer) return resource.renderer;
|
|
63
|
+
if (resource.rendererId && registry[resource.rendererId]) return registry[resource.rendererId];
|
|
64
|
+
return ({ error, state, title }) => {
|
|
65
|
+
if (state === "loading") return `${title ?? resource.title} is loading...`;
|
|
66
|
+
if (state === "error") {
|
|
67
|
+
const suffix = error instanceof Error ? ` (${error.message})` : "";
|
|
68
|
+
return `${title ?? resource.title} failed${suffix}`;
|
|
69
|
+
}
|
|
70
|
+
if (state === "empty") return `${title ?? resource.title} has no data`;
|
|
71
|
+
return `${title ?? resource.title} is ready`;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/AtelierFrame/AtelierFrame.tsx
|
|
76
|
+
/**
|
|
77
|
+
* Slot-based class recipe for `AtelierFrame`.
|
|
78
|
+
*/
|
|
79
|
+
const atelierFrameVariants = tv({ slots: {
|
|
80
|
+
appName: "text-base font-semibold tracking-tight",
|
|
81
|
+
base: "flex min-h-[32rem] flex-col rounded-xl border border-default-200 bg-content1",
|
|
82
|
+
content: "grid gap-4 p-4 md:grid-cols-[16rem_1fr]",
|
|
83
|
+
header: "flex min-h-14 items-center justify-between border-b border-default-200 px-4",
|
|
84
|
+
navButton: "w-full justify-start rounded-md px-2 py-1 text-sm text-default-700 hover:bg-default-100",
|
|
85
|
+
resourceArea: "rounded-lg border border-default-200 bg-content2 p-4",
|
|
86
|
+
resourceTitle: "mb-2 text-sm font-medium text-default-700",
|
|
87
|
+
shellMeta: "flex items-center gap-2 text-xs text-default-500",
|
|
88
|
+
sidebar: "hidden rounded-lg border border-default-200 bg-content2 p-3 md:block",
|
|
89
|
+
sidebarFooter: "mt-3 border-t border-default-200 pt-3 text-xs text-default-600",
|
|
90
|
+
sidebarSection: "mb-3",
|
|
91
|
+
sidebarSectionLabel: "mb-1 text-xs font-semibold uppercase text-default-500",
|
|
92
|
+
topBarActions: "ml-auto flex items-center gap-2"
|
|
93
|
+
} });
|
|
94
|
+
const defaultResourceId = "default";
|
|
95
|
+
const getResourceById = (resources, resourceId) => {
|
|
96
|
+
return resources.find((resource) => {
|
|
97
|
+
return resource.id === resourceId;
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
const defaultResource = {
|
|
101
|
+
id: defaultResourceId,
|
|
102
|
+
title: "Workspace"
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Reusable frame component for app chrome, navigation, and pluggable
|
|
106
|
+
* resource rendering.
|
|
107
|
+
*/
|
|
108
|
+
const AtelierFrame = ({ appName, authState, className = void 0, currentPath = "/", dataState = "ready", navigation = [], onNavigate = void 0, rendererRegistry = {}, resourceData = void 0, resourceError = void 0, resourceId = defaultResourceId, resources = [], slots = void 0, testId = "atelier-frame", topBarActions = void 0, userMenu = void 0, withMobileDrawer = true }) => {
|
|
109
|
+
const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);
|
|
110
|
+
const classNames = variantsToClassNames(atelierFrameVariants(), className, "base");
|
|
111
|
+
const auth = createAuthAdapter();
|
|
112
|
+
const visibleNavigation = useMemo(() => {
|
|
113
|
+
return filterNavigationForState(navigation, authState, auth);
|
|
114
|
+
}, [
|
|
115
|
+
navigation,
|
|
116
|
+
authState,
|
|
117
|
+
auth
|
|
118
|
+
]);
|
|
119
|
+
const resolvedResource = getResourceById(resources, resourceId) ?? resources[0] ?? {
|
|
120
|
+
...defaultResource,
|
|
121
|
+
id: resourceId
|
|
122
|
+
};
|
|
123
|
+
const renderResource = getResourceRenderer(resolvedResource, rendererRegistry);
|
|
124
|
+
const sharedSlots = slots ?? {};
|
|
125
|
+
const resolvedUserMenu = userMenu ?? sharedSlots.userMenu;
|
|
126
|
+
/**
|
|
127
|
+
* Renders the same navigation structure for desktop and mobile contexts.
|
|
128
|
+
*/
|
|
129
|
+
const renderSidebar = ({ mobile }) => {
|
|
130
|
+
return /* @__PURE__ */ jsxs("aside", {
|
|
131
|
+
className: mobile ? "rounded-lg border border-default-200 bg-content2 p-3" : classNames.sidebar,
|
|
132
|
+
"data-testid": `${testId}__sidebar`,
|
|
133
|
+
children: [visibleNavigation.map((section) => {
|
|
134
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
135
|
+
className: classNames.sidebarSection,
|
|
136
|
+
"data-testid": `${testId}__section-${section.id}`,
|
|
137
|
+
children: [section.label ? /* @__PURE__ */ jsx("div", {
|
|
138
|
+
className: classNames.sidebarSectionLabel,
|
|
139
|
+
children: section.label
|
|
140
|
+
}) : null, /* @__PURE__ */ jsx("nav", {
|
|
141
|
+
className: "grid gap-1",
|
|
142
|
+
children: section.items.map((item) => {
|
|
143
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
144
|
+
className: classNames.navButton,
|
|
145
|
+
color: item.to === currentPath ? "primary" : "default",
|
|
146
|
+
onClick: () => {
|
|
147
|
+
onNavigate?.(item.to);
|
|
148
|
+
setIsMobileNavOpen(false);
|
|
149
|
+
},
|
|
150
|
+
variant: item.to === currentPath ? "solid" : "light",
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ jsx("span", {
|
|
153
|
+
className: "mr-2 inline-flex",
|
|
154
|
+
children: item.icon
|
|
155
|
+
}),
|
|
156
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
157
|
+
item.badge ? /* @__PURE__ */ jsx("span", {
|
|
158
|
+
className: "ml-auto",
|
|
159
|
+
children: item.badge
|
|
160
|
+
}) : null
|
|
161
|
+
]
|
|
162
|
+
}, item.id);
|
|
163
|
+
})
|
|
164
|
+
})]
|
|
165
|
+
}, section.id);
|
|
166
|
+
}), sharedSlots.sidebarFooter ? /* @__PURE__ */ jsx("div", {
|
|
167
|
+
className: classNames.sidebarFooter,
|
|
168
|
+
children: sharedSlots.sidebarFooter
|
|
169
|
+
}) : null]
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
173
|
+
className: classNames.base,
|
|
174
|
+
"data-testid": testId,
|
|
175
|
+
children: [
|
|
176
|
+
/* @__PURE__ */ jsxs("header", {
|
|
177
|
+
className: classNames.header,
|
|
178
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
179
|
+
className: classNames.shellMeta,
|
|
180
|
+
children: [
|
|
181
|
+
withMobileDrawer ? /* @__PURE__ */ jsx(Button, {
|
|
182
|
+
className: "md:hidden",
|
|
183
|
+
onClick: () => {
|
|
184
|
+
setIsMobileNavOpen(true);
|
|
185
|
+
},
|
|
186
|
+
size: "sm",
|
|
187
|
+
variant: "flat",
|
|
188
|
+
children: "Menu"
|
|
189
|
+
}) : null,
|
|
190
|
+
/* @__PURE__ */ jsx("span", {
|
|
191
|
+
className: classNames.appName,
|
|
192
|
+
children: appName
|
|
193
|
+
}),
|
|
194
|
+
/* @__PURE__ */ jsxs("span", { children: ["status: ", authState.status] })
|
|
195
|
+
]
|
|
196
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
197
|
+
className: classNames.topBarActions,
|
|
198
|
+
children: [topBarActions ?? sharedSlots.headerActions, resolvedUserMenu]
|
|
199
|
+
})]
|
|
200
|
+
}),
|
|
201
|
+
/* @__PURE__ */ jsxs("div", {
|
|
202
|
+
className: classNames.content,
|
|
203
|
+
children: [renderSidebar({ mobile: false }), /* @__PURE__ */ jsxs("main", {
|
|
204
|
+
className: classNames.resourceArea,
|
|
205
|
+
children: [
|
|
206
|
+
/* @__PURE__ */ jsx("div", {
|
|
207
|
+
className: classNames.resourceTitle,
|
|
208
|
+
children: resolvedResource.title
|
|
209
|
+
}),
|
|
210
|
+
sharedSlots.pageChrome,
|
|
211
|
+
renderResource({
|
|
212
|
+
data: resourceData,
|
|
213
|
+
error: resourceError,
|
|
214
|
+
resourceId: resolvedResource.id,
|
|
215
|
+
state: dataState,
|
|
216
|
+
title: resolvedResource.title
|
|
217
|
+
})
|
|
218
|
+
]
|
|
219
|
+
})]
|
|
220
|
+
}),
|
|
221
|
+
withMobileDrawer ? /* @__PURE__ */ jsx(Drawer, {
|
|
222
|
+
header: appName,
|
|
223
|
+
isOpen: isMobileNavOpen,
|
|
224
|
+
onClose: () => {
|
|
225
|
+
setIsMobileNavOpen(false);
|
|
226
|
+
},
|
|
227
|
+
placement: "left",
|
|
228
|
+
children: renderSidebar({ mobile: true })
|
|
229
|
+
}) : null
|
|
230
|
+
]
|
|
231
|
+
});
|
|
232
|
+
};
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/core/createAtelierApp.ts
|
|
235
|
+
/**
|
|
236
|
+
* Clones and sanitizes navigation config by dropping empty sections.
|
|
237
|
+
*/
|
|
238
|
+
const normalizeNavigation = (sections) => {
|
|
239
|
+
if (!sections || sections.length <= 0) return [];
|
|
240
|
+
return sections.filter((section) => {
|
|
241
|
+
return section.items.length > 0;
|
|
242
|
+
}).map((section) => {
|
|
243
|
+
return {
|
|
244
|
+
...section,
|
|
245
|
+
items: [...section.items]
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Creates a normalized app config object for shell usage.
|
|
251
|
+
*
|
|
252
|
+
* Normalization goals:
|
|
253
|
+
* - always provide an auth adapter with defaults
|
|
254
|
+
* - always provide collections (`navigation`, `renderers`, `resources`)
|
|
255
|
+
* - remove empty navigation sections
|
|
256
|
+
*/
|
|
257
|
+
const createAtelierApp = (config) => {
|
|
258
|
+
return {
|
|
259
|
+
...config,
|
|
260
|
+
auth: createAuthAdapter(config.auth),
|
|
261
|
+
navigation: normalizeNavigation(config.navigation),
|
|
262
|
+
renderers: config.renderers ?? {},
|
|
263
|
+
resources: config.resources ?? []
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region src/core/tanstack.ts
|
|
268
|
+
/**
|
|
269
|
+
* Lightweight helper to normalize route context creation in consuming apps.
|
|
270
|
+
*/
|
|
271
|
+
const createAtelierRouteContext = (context) => {
|
|
272
|
+
return context;
|
|
273
|
+
};
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/index.ts
|
|
276
|
+
/* v8 ignore stop */
|
|
277
|
+
//#endregion
|
|
278
|
+
export { AtelierFrame, atelierFrameVariants, createAtelierApp, createAtelierRouteContext, createAuthAdapter, filterNavigationForState, getResourceRenderer };
|
|
279
|
+
|
|
280
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/core/createAuthAdapter.ts","../src/core/navigation.ts","../src/core/renderers.ts","../src/AtelierFrame/AtelierFrame.tsx","../src/core/createAtelierApp.ts","../src/core/tanstack.ts","../src/index.ts"],"sourcesContent":["/* eslint-disable import-x/prefer-default-export */\n\nimport type { AtelierAuthAdapter, AtelierAuthState } from './types';\n\n/**\n * Built-in role-based access fallback.\n * - No declared roles means public access.\n * - Role checks only pass for authenticated users.\n */\nconst defaultCanAccess = (\n roles: string[] | undefined,\n state: AtelierAuthState,\n): boolean => {\n if (roles === undefined || roles.length <= 0) {\n return true;\n }\n\n if (state.status !== 'authenticated' || !state.user) {\n return false;\n }\n\n const userRoles = state.user.roles ?? [];\n return roles.some((role) => {\n return userRoles.includes(role);\n });\n};\n\n/**\n * Builds an auth adapter with safe defaults.\n *\n * Consumers can override any adapter method; `canAccess` always has a default.\n */\nexport const createAuthAdapter = (\n adapter?: AtelierAuthAdapter,\n): Required<Pick<AtelierAuthAdapter, 'canAccess'>> & AtelierAuthAdapter => {\n return {\n canAccess: defaultCanAccess,\n ...adapter,\n };\n};\n","/* eslint-disable import-x/prefer-default-export */\n\nimport type { AtelierAuthState, AtelierNavigation } from './types';\n\nimport { createAuthAdapter } from './createAuthAdapter';\n\n/**\n * Filters a navigation tree according to auth state, item visibility rules,\n * and adapter-level access checks.\n */\nexport const filterNavigationForState = (\n navigation: AtelierNavigation,\n state: AtelierAuthState,\n auth = createAuthAdapter(),\n): AtelierNavigation => {\n return navigation\n .map((section) => {\n const items = section.items.filter((item) => {\n if (item.requiresAuth && state.status !== 'authenticated') {\n return false;\n }\n\n if (item.isVisible && !item.isVisible(state)) {\n return false;\n }\n\n if (!auth.canAccess(item.roles, state, item.id)) {\n return false;\n }\n\n return true;\n });\n\n return {\n ...section,\n items,\n };\n })\n .filter((section) => {\n return section.items.length > 0;\n });\n};\n","/* eslint-disable import-x/prefer-default-export */\n\nimport type {\n AtelierRenderer,\n AtelierRendererProps,\n AtelierRendererRegistry,\n AtelierResourceDefinition,\n} from './types';\n\n/**\n * Resolves the renderer for a resource:\n * 1) inline `resource.renderer`\n * 2) registry lookup via `resource.rendererId`\n * 3) text-based fallback renderer for loading/ready/empty/error states\n */\nexport const getResourceRenderer = (\n resource: AtelierResourceDefinition,\n registry: AtelierRendererRegistry = {},\n): AtelierRenderer => {\n if (resource.renderer) {\n return resource.renderer;\n }\n\n if (resource.rendererId && registry[resource.rendererId]) {\n return registry[resource.rendererId];\n }\n\n return ({ error, state, title }: AtelierRendererProps) => {\n if (state === 'loading') {\n return `${title ?? resource.title} is loading...`;\n }\n\n if (state === 'error') {\n const suffix = error instanceof Error ? ` (${error.message})` : '';\n return `${title ?? resource.title} failed${suffix}`;\n }\n\n if (state === 'empty') {\n return `${title ?? resource.title} has no data`;\n }\n\n return `${title ?? resource.title} is ready`;\n };\n};\n","import type { TVClassName } from '@fuf-stack/pixel-utils';\nimport type { ReactNode } from 'react';\nimport type {\n AtelierAuthState,\n AtelierDataState,\n AtelierFrameSlots,\n AtelierNavigation,\n AtelierRendererRegistry,\n AtelierResourceDefinition,\n} from '../core';\n\nimport { useMemo, useState } from 'react';\n\nimport { tv, variantsToClassNames } from '@fuf-stack/pixel-utils';\nimport Button from '@fuf-stack/pixels/Button';\nimport Drawer from '@fuf-stack/pixels/Drawer';\n\nimport { createAuthAdapter } from '../core/createAuthAdapter';\nimport { filterNavigationForState } from '../core/navigation';\nimport { getResourceRenderer } from '../core/renderers';\n\n/**\n * Slot-based class recipe for `AtelierFrame`.\n */\nexport const atelierFrameVariants = tv({\n slots: {\n appName: 'text-base font-semibold tracking-tight',\n base: 'flex min-h-[32rem] flex-col rounded-xl border border-default-200 bg-content1',\n content: 'grid gap-4 p-4 md:grid-cols-[16rem_1fr]',\n header:\n 'flex min-h-14 items-center justify-between border-b border-default-200 px-4',\n navButton:\n 'w-full justify-start rounded-md px-2 py-1 text-sm text-default-700 hover:bg-default-100',\n resourceArea: 'rounded-lg border border-default-200 bg-content2 p-4',\n resourceTitle: 'mb-2 text-sm font-medium text-default-700',\n shellMeta: 'flex items-center gap-2 text-xs text-default-500',\n sidebar:\n 'hidden rounded-lg border border-default-200 bg-content2 p-3 md:block',\n sidebarFooter:\n 'mt-3 border-t border-default-200 pt-3 text-xs text-default-600',\n sidebarSection: 'mb-3',\n sidebarSectionLabel:\n 'mb-1 text-xs font-semibold uppercase text-default-500',\n topBarActions: 'ml-auto flex items-center gap-2',\n },\n});\n\ntype ClassName = TVClassName<typeof atelierFrameVariants>;\n\n/**\n * Props for the core frame component.\n */\nexport interface AtelierFrameProps {\n /** App name shown in the top bar and mobile drawer header. */\n appName: string;\n /** Current auth state used for status and navigation filtering. */\n authState: AtelierAuthState;\n /** Optional slot-based className overrides. */\n className?: ClassName;\n /** Current pathname used to mark active navigation items. */\n currentPath?: string;\n /** Current resource data state passed to renderers. */\n dataState?: AtelierDataState;\n /** Navigation callback triggered when an item is clicked. */\n onNavigate?: (to: string) => void;\n /** Sidebar navigation tree. */\n navigation?: AtelierNavigation;\n /** Resource payload forwarded to the active renderer. */\n resourceData?: unknown;\n /** Resource error forwarded to the active renderer. */\n resourceError?: unknown;\n /** Active resource id. */\n resourceId?: string;\n /** Available resource definitions. */\n resources?: AtelierResourceDefinition[];\n /** Optional slot content overrides. */\n slots?: AtelierFrameSlots;\n /** Prefix for test ids. */\n testId?: string;\n /** Header actions override. */\n topBarActions?: ReactNode;\n /** User menu override. */\n userMenu?: ReactNode;\n /** Enables drawer-based navigation on small screens. */\n withMobileDrawer?: boolean;\n /** Named renderer registry resolved by `rendererId`. */\n rendererRegistry?: AtelierRendererRegistry;\n}\n\nconst defaultResourceId = 'default';\n\nconst getResourceById = (\n resources: AtelierResourceDefinition[],\n resourceId: string,\n): AtelierResourceDefinition | undefined => {\n return resources.find((resource) => {\n return resource.id === resourceId;\n });\n};\n\nconst defaultResource: AtelierResourceDefinition = {\n id: defaultResourceId,\n title: 'Workspace',\n};\n\n/**\n * Reusable frame component for app chrome, navigation, and pluggable\n * resource rendering.\n */\nconst AtelierFrame = ({\n appName,\n authState,\n className = undefined,\n currentPath = '/',\n dataState = 'ready',\n navigation = [],\n onNavigate = undefined,\n rendererRegistry = {},\n resourceData = undefined,\n resourceError = undefined,\n resourceId = defaultResourceId,\n resources = [],\n slots = undefined,\n testId = 'atelier-frame',\n topBarActions = undefined,\n userMenu = undefined,\n withMobileDrawer = true,\n}: AtelierFrameProps) => {\n const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);\n const variants = atelierFrameVariants();\n const classNames = variantsToClassNames(variants, className, 'base');\n\n const auth = createAuthAdapter();\n const visibleNavigation = useMemo(() => {\n return filterNavigationForState(navigation, authState, auth);\n }, [navigation, authState, auth]);\n\n const resolvedResource = getResourceById(resources, resourceId) ??\n resources[0] ?? { ...defaultResource, id: resourceId };\n\n const renderResource = getResourceRenderer(\n resolvedResource,\n rendererRegistry,\n );\n const sharedSlots = slots ?? {};\n const resolvedUserMenu = userMenu ?? sharedSlots.userMenu;\n\n /**\n * Renders the same navigation structure for desktop and mobile contexts.\n */\n const renderSidebar = ({ mobile }: { mobile: boolean }) => {\n return (\n <aside\n className={\n mobile\n ? 'rounded-lg border border-default-200 bg-content2 p-3'\n : classNames.sidebar\n }\n data-testid={`${testId}__sidebar`}\n >\n {visibleNavigation.map((section) => {\n return (\n <div\n key={section.id}\n className={classNames.sidebarSection}\n data-testid={`${testId}__section-${section.id}`}\n >\n {section.label ? (\n <div className={classNames.sidebarSectionLabel}>\n {section.label}\n </div>\n ) : null}\n <nav className=\"grid gap-1\">\n {section.items.map((item) => {\n return (\n <Button\n key={item.id}\n className={classNames.navButton}\n color={item.to === currentPath ? 'primary' : 'default'}\n onClick={() => {\n onNavigate?.(item.to);\n setIsMobileNavOpen(false);\n }}\n variant={item.to === currentPath ? 'solid' : 'light'}\n >\n <span className=\"mr-2 inline-flex\">{item.icon}</span>\n <span>{item.label}</span>\n {item.badge ? (\n <span className=\"ml-auto\">{item.badge}</span>\n ) : null}\n </Button>\n );\n })}\n </nav>\n </div>\n );\n })}\n {sharedSlots.sidebarFooter ? (\n <div className={classNames.sidebarFooter}>\n {sharedSlots.sidebarFooter}\n </div>\n ) : null}\n </aside>\n );\n };\n\n return (\n <section className={classNames.base} data-testid={testId}>\n <header className={classNames.header}>\n <div className={classNames.shellMeta}>\n {withMobileDrawer ? (\n <Button\n className=\"md:hidden\"\n onClick={() => {\n setIsMobileNavOpen(true);\n }}\n size=\"sm\"\n variant=\"flat\"\n >\n Menu\n </Button>\n ) : null}\n <span className={classNames.appName}>{appName}</span>\n <span>status: {authState.status}</span>\n </div>\n <div className={classNames.topBarActions}>\n {topBarActions ?? sharedSlots.headerActions}\n {resolvedUserMenu}\n </div>\n </header>\n <div className={classNames.content}>\n {renderSidebar({ mobile: false })}\n <main className={classNames.resourceArea}>\n <div className={classNames.resourceTitle}>\n {resolvedResource.title}\n </div>\n {sharedSlots.pageChrome}\n {renderResource({\n data: resourceData,\n error: resourceError,\n resourceId: resolvedResource.id,\n state: dataState,\n title: resolvedResource.title,\n })}\n </main>\n </div>\n {withMobileDrawer ? (\n <Drawer\n header={appName}\n isOpen={isMobileNavOpen}\n onClose={() => {\n setIsMobileNavOpen(false);\n }}\n placement=\"left\"\n >\n {renderSidebar({ mobile: true })}\n </Drawer>\n ) : null}\n </section>\n );\n};\n\nexport default AtelierFrame;\n","/* eslint-disable import-x/prefer-default-export */\n\nimport type { AtelierAppConfig, AtelierNavigationSection } from './types';\n\nimport { createAuthAdapter } from './createAuthAdapter';\n\n/**\n * Clones and sanitizes navigation config by dropping empty sections.\n */\nconst normalizeNavigation = (\n sections?: AtelierNavigationSection[],\n): AtelierNavigationSection[] => {\n if (!sections || sections.length <= 0) {\n return [];\n }\n\n return sections\n .filter((section) => {\n return section.items.length > 0;\n })\n .map((section) => {\n return {\n ...section,\n items: [...section.items],\n };\n });\n};\n\n/**\n * Creates a normalized app config object for shell usage.\n *\n * Normalization goals:\n * - always provide an auth adapter with defaults\n * - always provide collections (`navigation`, `renderers`, `resources`)\n * - remove empty navigation sections\n */\nexport const createAtelierApp = (\n config: AtelierAppConfig,\n): Required<\n Pick<AtelierAppConfig, 'appName' | 'navigation' | 'renderers' | 'resources'>\n> &\n AtelierAppConfig => {\n return {\n ...config,\n auth: createAuthAdapter(config.auth),\n navigation: normalizeNavigation(config.navigation),\n renderers: config.renderers ?? {},\n resources: config.resources ?? [],\n };\n};\n","import type { AtelierAuthState, AtelierRendererRegistry } from './types';\n\n/**\n * Shape intended for TanStack Start root route context.\n * Consumers keep route ownership and can extend this interface.\n */\nexport interface AtelierRouteContext {\n authState: AtelierAuthState;\n queryClient?: unknown;\n renderers: AtelierRendererRegistry;\n}\n\n/**\n * Lightweight helper to normalize route context creation in consuming apps.\n */\nexport const createAtelierRouteContext = <T extends AtelierRouteContext>(\n context: T,\n): T => {\n return context;\n};\n","/* v8 ignore start */\n\nexport * from './AtelierFrame';\nexport * from './core';\n\n/* v8 ignore stop */\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fuf-stack/atelier",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "fuf customizable base app package",
|
|
5
|
+
"author": "Fröhlich ∧ Frei",
|
|
6
|
+
"homepage": "https://github.com/fuf-stack/pixels/tree/main/packages/atelier",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.cts",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./AtelierFrame": {
|
|
19
|
+
"import": "./dist/AtelierFrame/index.js",
|
|
20
|
+
"require": "./dist/AtelierFrame/index.cjs"
|
|
21
|
+
},
|
|
22
|
+
"./core": {
|
|
23
|
+
"import": "./dist/core/index.js",
|
|
24
|
+
"require": "./dist/core/index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/fuf-stack/pixels.git",
|
|
37
|
+
"directory": "packages/atelier"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/fuf-stack/pixels/issues"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsdown",
|
|
44
|
+
"prepack": "pnpm build",
|
|
45
|
+
"test": "vitest ./src"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"react": ">=18",
|
|
49
|
+
"react-dom": ">=18"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@fuf-stack/pixel-utils": "workspace:*",
|
|
53
|
+
"@fuf-stack/pixels": "workspace:*"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/react": "19.2.17",
|
|
57
|
+
"@types/react-dom": "19.2.3",
|
|
58
|
+
"react": "19.2.7",
|
|
59
|
+
"react-dom": "19.2.7"
|
|
60
|
+
}
|
|
61
|
+
}
|