@panneau/app 5.0.0-alpha.3 → 5.0.0-alpha.5
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 +32 -5
- package/dist/Panneau.css +19 -0
- package/dist/Panneau.d.ts +7 -1
- package/dist/Panneau.d.ts.map +1 -1
- package/dist/Panneau.js +137 -30
- package/dist/Panneau.js.map +1 -1
- package/dist/Panneau.module.js +12 -0
- package/dist/Panneau.module.js.map +1 -0
- package/dist/Shell.d.ts +8 -3
- package/dist/Shell.d.ts.map +1 -1
- package/dist/Shell.js +272 -114
- package/dist/Shell.js.map +1 -1
- package/dist/createPanneauApp.d.ts +3 -0
- package/dist/createPanneauApp.d.ts.map +1 -1
- package/dist/createPanneauApp.js.map +1 -1
- package/dist/cx.d.ts +3 -0
- package/dist/cx.d.ts.map +1 -0
- package/dist/cx.js +9 -0
- package/dist/cx.js.map +1 -0
- package/dist/documentTitle.d.ts +10 -0
- package/dist/documentTitle.d.ts.map +1 -0
- package/dist/documentTitle.js +49 -0
- package/dist/documentTitle.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/location.d.ts +13 -1
- package/dist/location.d.ts.map +1 -1
- package/dist/location.js +55 -48
- package/dist/location.js.map +1 -1
- package/dist/navigation.d.ts +53 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +117 -0
- package/dist/navigation.js.map +1 -0
- package/dist/pages/HomePage.d.ts +11 -0
- package/dist/pages/HomePage.d.ts.map +1 -0
- package/dist/pages/HomePage.js +111 -0
- package/dist/pages/HomePage.js.map +1 -0
- package/dist/pages/ItemPanel.css +164 -0
- package/dist/pages/ItemPanel.d.ts +17 -0
- package/dist/pages/ItemPanel.d.ts.map +1 -0
- package/dist/pages/ItemPanel.js +370 -0
- package/dist/pages/ItemPanel.js.map +1 -0
- package/dist/pages/ItemPanel.module.js +34 -0
- package/dist/pages/ItemPanel.module.js.map +1 -0
- package/dist/pages/ItemPreview.d.ts +15 -0
- package/dist/pages/ItemPreview.d.ts.map +1 -0
- package/dist/pages/ItemPreview.js +179 -0
- package/dist/pages/ItemPreview.js.map +1 -0
- package/dist/pages/NotFoundPage.d.ts +6 -0
- package/dist/pages/NotFoundPage.d.ts.map +1 -0
- package/dist/pages/NotFoundPage.js +93 -0
- package/dist/pages/NotFoundPage.js.map +1 -0
- package/dist/pages/PageHeader.d.ts +21 -0
- package/dist/pages/PageHeader.d.ts.map +1 -0
- package/dist/pages/PageHeader.js +86 -0
- package/dist/pages/PageHeader.js.map +1 -0
- package/dist/pages/ResourceFormPage.d.ts +15 -0
- package/dist/pages/ResourceFormPage.d.ts.map +1 -0
- package/dist/pages/ResourceFormPage.js +204 -0
- package/dist/pages/ResourceFormPage.js.map +1 -0
- package/dist/pages/ResourceListPage.d.ts +15 -0
- package/dist/pages/ResourceListPage.d.ts.map +1 -0
- package/dist/pages/ResourceListPage.js +101 -0
- package/dist/pages/ResourceListPage.js.map +1 -0
- package/dist/pages/itemTitle.d.ts +7 -0
- package/dist/pages/itemTitle.d.ts.map +1 -0
- package/dist/pages/itemTitle.js +18 -0
- package/dist/pages/itemTitle.js.map +1 -0
- package/dist/pages/pages.css +162 -0
- package/dist/pages/pages.module.js +40 -0
- package/dist/pages/pages.module.js.map +1 -0
- package/dist/preferences.d.ts +6 -0
- package/dist/preferences.d.ts.map +1 -0
- package/dist/preferences.js +53 -0
- package/dist/preferences.js.map +1 -0
- package/dist/recentItems.d.ts +15 -0
- package/dist/recentItems.d.ts.map +1 -0
- package/dist/recentItems.js +70 -0
- package/dist/recentItems.js.map +1 -0
- package/dist/shell/AppLayout.css +189 -0
- package/dist/shell/AppLayout.d.ts +22 -0
- package/dist/shell/AppLayout.d.ts.map +1 -0
- package/dist/shell/AppLayout.js +365 -0
- package/dist/shell/AppLayout.js.map +1 -0
- package/dist/shell/AppLayout.module.js +36 -0
- package/dist/shell/AppLayout.module.js.map +1 -0
- package/dist/shell/GoTo.d.ts +20 -0
- package/dist/shell/GoTo.d.ts.map +1 -0
- package/dist/shell/GoTo.js +370 -0
- package/dist/shell/GoTo.js.map +1 -0
- package/dist/shell/Sidebar.css +313 -0
- package/dist/shell/Sidebar.d.ts +29 -0
- package/dist/shell/Sidebar.d.ts.map +1 -0
- package/dist/shell/Sidebar.js +225 -0
- package/dist/shell/Sidebar.js.map +1 -0
- package/dist/shell/Sidebar.module.js +60 -0
- package/dist/shell/Sidebar.module.js.map +1 -0
- package/dist/shell/tokens.d.ts +23 -0
- package/dist/shell/tokens.d.ts.map +1 -0
- package/dist/shell/tokens.js +75 -0
- package/dist/shell/tokens.js.map +1 -0
- package/package.json +15 -6
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# @panneau/app
|
|
2
2
|
|
|
3
|
-
The Panneau admin panel: the app entry (`createPanneauApp`),
|
|
3
|
+
The Panneau admin panel: the app entry (`createPanneauApp`), the shell with its sidebar, and the pages of resources.
|
|
4
4
|
|
|
5
|
-
The shell is a
|
|
5
|
+
The shell is a first version, for Phase 2 of the [roadmap](../../docs/roadmap.md): a sidebar from the `main` menu of the definition, collapsible to a rail of icons (Ctrl+\\ or ⌘+\\), the page on a raised panel, a drawer on small screens, and the home, list, create, edit and plugin pages, built with `@panneau/lists`, `@panneau/forms` and `@panneau/actions`. The show route opens the item's details in a panel next to its list, with its preview when its resource has one: a component of a plugin (`previews`) or its page on the site in an iframe ([decisions/0028](../../docs/decisions/0028-item-panel.md)). **Go to…** (⌘K or Ctrl+K, or its button in the sidebar) opens a command palette: recent items, navigation, "New {resource}", the `commands` of plugins, the app's actions, and the results of the server's search, grouped by resource; an item opens its form ([decisions/0029](../../docs/decisions/0029-go-to-palette.md)). "Search in" narrows it to one resource, until Backspace in the empty field ([decisions/0030](../../docs/decisions/0030-search-parameters-and-scope.md)). Leaving a form with unsaved changes asks first, by a link or by going back or forward. The tab is named after the page, and focus moves to the title of each new page, for screen readers. The entry contract below is stable: see [decisions/0019](../../docs/decisions/0019-app-entry.md).
|
|
6
|
+
|
|
7
|
+
Try it with `npm run playground` at the root of the repository: the whole app on the mock backend of `@panneau/protocol` (`?theme=flat` for a flat frame).
|
|
6
8
|
|
|
7
9
|
```ts
|
|
8
10
|
// resources/js/panneau.tsx
|
|
@@ -20,9 +22,9 @@ The page writes the boot config next to the root element ([protocol.md](../../do
|
|
|
20
22
|
</script>
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
| Export | Content
|
|
24
|
-
| -------------- |
|
|
25
|
-
| `@panneau/app` | `createPanneauApp()`, the `<Panneau>` component, `readBootConfig()` and the types of their options |
|
|
25
|
+
| Export | Content |
|
|
26
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `@panneau/app` | `createPanneauApp()`, the `<Panneau>` component, `readBootConfig()` and the types of their options, the component tokens of the shell |
|
|
26
28
|
|
|
27
29
|
## Setup
|
|
28
30
|
|
|
@@ -33,7 +35,32 @@ npm install --save-dev vite @vitejs/plugin-react
|
|
|
33
35
|
|
|
34
36
|
- Add `@vitejs/plugin-react` to the Vite config, and the entry to its inputs.
|
|
35
37
|
- The entry imports no CSS and no theme: packages import their own styles, and themes come from plugins.
|
|
38
|
+
- Named icons (`"icon": "users"` in the definition) are Lucide icons, each loaded when shown. Pass `iconLoader` to load fewer, or `null` for none.
|
|
36
39
|
- Without `adapter`, the app uses the Laravel preset of the REST adapter (`@panneau/data/laravel`) on `apiBaseUrl`.
|
|
37
40
|
- When the API answers `401` (or `419` from Laravel), the app sends the browser to the login URL. Pass `onUnauthorized` to do something else.
|
|
38
41
|
|
|
42
|
+
## Theming the shell
|
|
43
|
+
|
|
44
|
+
The frame reads component tokens ([decisions/0024](../../docs/decisions/0024-theme-model.md)), which a theme sets like those of `@panneau/ui` once `@panneau/app` is imported:
|
|
45
|
+
|
|
46
|
+
| Tokens | What they style |
|
|
47
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------ |
|
|
48
|
+
| `--panneau-shell-*` | The window's background (`bg`), the inset of the page (`inset`) and its panel (`panel-*`) |
|
|
49
|
+
| `--panneau-item-panel-*` | The widths (normal and widened), background, radius and shadow of the panel of an item's details |
|
|
50
|
+
| `--panneau-sidebar-*` | The width (expanded and collapsed), background and border of the sidebar, its links and its logo |
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { defineTheme } from '@panneau/ui';
|
|
54
|
+
|
|
55
|
+
// A flat frame: the sidebar on a surface, and the page flush against it.
|
|
56
|
+
export const flatTheme = defineTheme({
|
|
57
|
+
tokens: {
|
|
58
|
+
'panneau-shell-inset': '0',
|
|
59
|
+
'panneau-shell-panel-radius': '0',
|
|
60
|
+
'panneau-sidebar-bg': 'var(--panneau-color-surface)',
|
|
61
|
+
'panneau-sidebar-border': 'var(--panneau-border-width) solid var(--panneau-color-border)',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
39
66
|
The package layout, scripts and API reports are explained in [`docs/packages.md`](../../docs/packages.md).
|
package/dist/Panneau.css
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.panneau-panneau-root {
|
|
2
|
+
min-height: 100dvh;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* Loading, a definition that failed to load, and an ended session: centered in the window. */
|
|
6
|
+
.panneau-panneau-state {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
gap: var(--panneau-space-3);
|
|
12
|
+
min-height: 100dvh;
|
|
13
|
+
padding: var(--panneau-space-4);
|
|
14
|
+
text-align: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.panneau-panneau-state p {
|
|
18
|
+
margin: 0;
|
|
19
|
+
}
|
package/dist/Panneau.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { QueryClient } from '@tanstack/react-query';
|
|
|
2
2
|
import { type PanneauPlugin } from '@panneau/core';
|
|
3
3
|
import { type DataAdapter } from '@panneau/data';
|
|
4
4
|
import type { BootConfig } from '@panneau/protocol';
|
|
5
|
+
import { type NamedIconLoader } from '@panneau/ui';
|
|
5
6
|
/** What `onUnauthorized` receives. */
|
|
6
7
|
export interface UnauthorizedContext {
|
|
7
8
|
/**
|
|
@@ -21,6 +22,11 @@ export interface PanneauProps {
|
|
|
21
22
|
plugins?: readonly PanneauPlugin[];
|
|
22
23
|
/** The TanStack Query client. Defaults to a new one. */
|
|
23
24
|
queryClient?: QueryClient;
|
|
25
|
+
/**
|
|
26
|
+
* Loads the Lucide icons that the definition names (`"icon": "users"`). Defaults to every
|
|
27
|
+
* Lucide icon, each one in its own chunk, loaded when shown. `null` shows no named icons.
|
|
28
|
+
*/
|
|
29
|
+
iconLoader?: NamedIconLoader | null;
|
|
24
30
|
/**
|
|
25
31
|
* Called once when the API answers that the user isn't authenticated (`401`, or `419` with the
|
|
26
32
|
* Laravel adapter). The app then shows that the session ended. Defaults to sending the browser
|
|
@@ -35,5 +41,5 @@ export interface PanneauProps {
|
|
|
35
41
|
* It uses the definition inlined in the boot config, or fetches it, then renders the shell. When
|
|
36
42
|
* the API answers that the user isn't authenticated, it calls `onUnauthorized`.
|
|
37
43
|
*/
|
|
38
|
-
export declare function Panneau({ config, adapter, plugins, queryClient, onUnauthorized, }: PanneauProps): import("react").JSX.Element;
|
|
44
|
+
export declare function Panneau({ config, adapter, plugins, queryClient, iconLoader, onUnauthorized, }: PanneauProps): import("react").JSX.Element;
|
|
39
45
|
//# sourceMappingURL=Panneau.d.ts.map
|
package/dist/Panneau.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Panneau.d.ts","sourceRoot":"","sources":["../src/Panneau.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAC;AAGnF,OAAO,
|
|
1
|
+
{"version":3,"file":"Panneau.d.ts","sourceRoot":"","sources":["../src/Panneau.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiC,MAAM,uBAAuB,CAAC;AAGnF,OAAO,EACH,KAAK,aAAa,EAKrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,eAAe,CAAC;AAI7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAU,KAAK,eAAe,EAAwC,MAAM,aAAa,CAAC;AASjG,sCAAsC;AACtC,MAAM,WAAW,mBAAmB;IAChC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IACzB,kGAAkG;IAClG,MAAM,EAAE,UAAU,CAAC;IACnB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,oDAAoD;IACpD,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CAC3D;AAiHD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,OAAO,EACP,OAAY,EACZ,WAAW,EACX,UAA6B,EAC7B,cAAgC,GACnC,EAAE,YAAY,+BA0Bd"}
|
package/dist/Panneau.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
import Panneau_module_default from "./Panneau.module.js";
|
|
2
|
+
import { usePreference } from "./preferences.js";
|
|
3
|
+
import { COLOR_SCHEMES } from "./shell/Sidebar.js";
|
|
1
4
|
import { Shell } from "./Shell.js";
|
|
2
5
|
import { createSessionState, getLoginUrl, watchUnauthorized } from "./unauthorized.js";
|
|
3
6
|
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
7
|
+
import { c } from "react/compiler-runtime";
|
|
4
8
|
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
|
|
5
|
-
import { PanneauProvider, createHistoryRouter } from "@panneau/core";
|
|
9
|
+
import { PanneauProvider, createHistoryRouter, createPluginRegistry, resolveTheme } from "@panneau/core";
|
|
6
10
|
import { isApiError } from "@panneau/data";
|
|
7
11
|
import { createLaravelAdapter } from "@panneau/data/laravel";
|
|
8
12
|
import { DataAdapterProvider, definitionQueryOptions } from "@panneau/data/query";
|
|
13
|
+
import { appMessages } from "@panneau/intl";
|
|
14
|
+
import { Button, PanneauRoot, Spinner, usePanneauIntl } from "@panneau/ui";
|
|
15
|
+
import { lucideIconLoader } from "@panneau/ui/named-icons";
|
|
9
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
17
|
//#region src/Panneau.tsx
|
|
11
18
|
function redirectToLogin({ loginUrl }) {
|
|
@@ -14,47 +21,146 @@ function redirectToLogin({ loginUrl }) {
|
|
|
14
21
|
function createQueryClient() {
|
|
15
22
|
return new QueryClient({ defaultOptions: { queries: { retry: (failureCount, error) => !(isApiError(error) && error.status < 500) && failureCount < 3 } } });
|
|
16
23
|
}
|
|
17
|
-
function Content({ config, adapter, plugins, session, onUnauthorized }) {
|
|
24
|
+
function Content({ config, adapter, plugins, iconLoader, session, onUnauthorized }) {
|
|
18
25
|
const [router] = useState(createHistoryRouter);
|
|
19
26
|
const definitionQuery = useQuery({
|
|
20
27
|
...definitionQueryOptions(adapter),
|
|
21
28
|
initialData: config.definition
|
|
22
29
|
});
|
|
23
30
|
const signedOut = useSyncExternalStore(session.subscribe, session.isSignedOut);
|
|
24
|
-
const
|
|
31
|
+
const [colorScheme, setColorScheme] = usePreference("color-scheme", COLOR_SCHEMES);
|
|
32
|
+
const definition = definitionQuery.data;
|
|
33
|
+
const loginUrl = getLoginUrl(definition, config);
|
|
25
34
|
useEffect(() => {
|
|
26
35
|
if (signedOut) onUnauthorized({ loginUrl });
|
|
27
36
|
}, [signedOut]);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
const scheme = colorScheme ?? definition?.theme?.colorScheme ?? "light";
|
|
38
|
+
return /* @__PURE__ */ jsx(PanneauRoot, {
|
|
39
|
+
theme: definition !== void 0 ? resolveTheme(definition.theme, createPluginRegistry(plugins).themes) : null,
|
|
40
|
+
colorScheme: scheme,
|
|
41
|
+
locale: definition?.locale ?? config.locale,
|
|
42
|
+
iconLoader,
|
|
43
|
+
className: Panneau_module_default.root,
|
|
44
|
+
children: signedOut ? /* @__PURE__ */ jsx(SessionEnded, { loginUrl }) : definition === void 0 ? /* @__PURE__ */ jsx(Loading, {
|
|
45
|
+
isError: definitionQuery.isError,
|
|
46
|
+
onRetry: () => void definitionQuery.refetch()
|
|
47
|
+
}) : /* @__PURE__ */ jsx(PanneauProvider, {
|
|
48
|
+
plugins,
|
|
49
|
+
definition,
|
|
50
|
+
router,
|
|
51
|
+
children: /* @__PURE__ */ jsx(Shell, {
|
|
52
|
+
definition,
|
|
53
|
+
basePath: config.basePath,
|
|
54
|
+
colorScheme: scheme,
|
|
55
|
+
onColorSchemeChange: setColorScheme
|
|
56
|
+
})
|
|
57
|
+
})
|
|
34
58
|
});
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
}
|
|
60
|
+
function SessionEnded(t0) {
|
|
61
|
+
const $ = c(10);
|
|
62
|
+
const { loginUrl } = t0;
|
|
63
|
+
const intl = usePanneauIntl();
|
|
64
|
+
let t1;
|
|
65
|
+
if ($[0] !== intl) {
|
|
66
|
+
t1 = intl.formatMessage(appMessages.sessionEnded);
|
|
67
|
+
$[0] = intl;
|
|
68
|
+
$[1] = t1;
|
|
69
|
+
} else t1 = $[1];
|
|
70
|
+
let t2;
|
|
71
|
+
if ($[2] !== t1) {
|
|
72
|
+
t2 = /* @__PURE__ */ jsx("p", { children: t1 });
|
|
73
|
+
$[2] = t1;
|
|
74
|
+
$[3] = t2;
|
|
75
|
+
} else t2 = $[3];
|
|
76
|
+
let t3;
|
|
77
|
+
if ($[4] !== intl || $[5] !== loginUrl) {
|
|
78
|
+
t3 = loginUrl !== null ? /* @__PURE__ */ jsx("a", {
|
|
79
|
+
href: loginUrl,
|
|
80
|
+
children: intl.formatMessage(appMessages.logIn)
|
|
81
|
+
}) : null;
|
|
82
|
+
$[4] = intl;
|
|
83
|
+
$[5] = loginUrl;
|
|
84
|
+
$[6] = t3;
|
|
85
|
+
} else t3 = $[6];
|
|
86
|
+
let t4;
|
|
87
|
+
if ($[7] !== t2 || $[8] !== t3) {
|
|
88
|
+
t4 = /* @__PURE__ */ jsxs("div", {
|
|
37
89
|
role: "alert",
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
onClick: () => void definitionQuery.refetch(),
|
|
41
|
-
children: "Try again"
|
|
42
|
-
})]
|
|
43
|
-
});
|
|
44
|
-
return /* @__PURE__ */ jsx("p", {
|
|
45
|
-
role: "status",
|
|
46
|
-
children: "Loading…"
|
|
90
|
+
className: Panneau_module_default.state,
|
|
91
|
+
children: [t2, t3]
|
|
47
92
|
});
|
|
93
|
+
$[7] = t2;
|
|
94
|
+
$[8] = t3;
|
|
95
|
+
$[9] = t4;
|
|
96
|
+
} else t4 = $[9];
|
|
97
|
+
return t4;
|
|
98
|
+
}
|
|
99
|
+
function Loading(t0) {
|
|
100
|
+
const $ = c(16);
|
|
101
|
+
const { isError, onRetry } = t0;
|
|
102
|
+
const intl = usePanneauIntl();
|
|
103
|
+
if (isError) {
|
|
104
|
+
let t1;
|
|
105
|
+
if ($[0] !== intl) {
|
|
106
|
+
t1 = intl.formatMessage(appMessages.loadError);
|
|
107
|
+
$[0] = intl;
|
|
108
|
+
$[1] = t1;
|
|
109
|
+
} else t1 = $[1];
|
|
110
|
+
let t2;
|
|
111
|
+
if ($[2] !== t1) {
|
|
112
|
+
t2 = /* @__PURE__ */ jsx("p", { children: t1 });
|
|
113
|
+
$[2] = t1;
|
|
114
|
+
$[3] = t2;
|
|
115
|
+
} else t2 = $[3];
|
|
116
|
+
let t3;
|
|
117
|
+
if ($[4] !== intl) {
|
|
118
|
+
t3 = intl.formatMessage(appMessages.retry);
|
|
119
|
+
$[4] = intl;
|
|
120
|
+
$[5] = t3;
|
|
121
|
+
} else t3 = $[5];
|
|
122
|
+
let t4;
|
|
123
|
+
if ($[6] !== onRetry || $[7] !== t3) {
|
|
124
|
+
t4 = /* @__PURE__ */ jsx(Button, {
|
|
125
|
+
onPress: onRetry,
|
|
126
|
+
children: t3
|
|
127
|
+
});
|
|
128
|
+
$[6] = onRetry;
|
|
129
|
+
$[7] = t3;
|
|
130
|
+
$[8] = t4;
|
|
131
|
+
} else t4 = $[8];
|
|
132
|
+
let t5;
|
|
133
|
+
if ($[9] !== t2 || $[10] !== t4) {
|
|
134
|
+
t5 = /* @__PURE__ */ jsxs("div", {
|
|
135
|
+
role: "alert",
|
|
136
|
+
className: Panneau_module_default.state,
|
|
137
|
+
children: [t2, t4]
|
|
138
|
+
});
|
|
139
|
+
$[9] = t2;
|
|
140
|
+
$[10] = t4;
|
|
141
|
+
$[11] = t5;
|
|
142
|
+
} else t5 = $[11];
|
|
143
|
+
return t5;
|
|
48
144
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
145
|
+
let t1;
|
|
146
|
+
if ($[12] !== intl) {
|
|
147
|
+
t1 = intl.formatMessage(appMessages.loading);
|
|
148
|
+
$[12] = intl;
|
|
149
|
+
$[13] = t1;
|
|
150
|
+
} else t1 = $[13];
|
|
151
|
+
let t2;
|
|
152
|
+
if ($[14] !== t1) {
|
|
153
|
+
t2 = /* @__PURE__ */ jsx("div", {
|
|
154
|
+
className: Panneau_module_default.state,
|
|
155
|
+
children: /* @__PURE__ */ jsx(Spinner, {
|
|
156
|
+
showLabel: true,
|
|
157
|
+
label: t1
|
|
158
|
+
})
|
|
159
|
+
});
|
|
160
|
+
$[14] = t1;
|
|
161
|
+
$[15] = t2;
|
|
162
|
+
} else t2 = $[15];
|
|
163
|
+
return t2;
|
|
58
164
|
}
|
|
59
165
|
/**
|
|
60
166
|
* The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it
|
|
@@ -63,7 +169,7 @@ function Content({ config, adapter, plugins, session, onUnauthorized }) {
|
|
|
63
169
|
* It uses the definition inlined in the boot config, or fetches it, then renders the shell. When
|
|
64
170
|
* the API answers that the user isn't authenticated, it calls `onUnauthorized`.
|
|
65
171
|
*/
|
|
66
|
-
function Panneau({ config, adapter, plugins = [], queryClient, onUnauthorized = redirectToLogin }) {
|
|
172
|
+
function Panneau({ config, adapter, plugins = [], queryClient, iconLoader = lucideIconLoader, onUnauthorized = redirectToLogin }) {
|
|
67
173
|
const [state] = useState(() => {
|
|
68
174
|
const session = createSessionState();
|
|
69
175
|
return {
|
|
@@ -80,6 +186,7 @@ function Panneau({ config, adapter, plugins = [], queryClient, onUnauthorized =
|
|
|
80
186
|
config,
|
|
81
187
|
adapter: state.adapter,
|
|
82
188
|
plugins,
|
|
189
|
+
iconLoader,
|
|
83
190
|
session: state.session,
|
|
84
191
|
onUnauthorized
|
|
85
192
|
})
|
package/dist/Panneau.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Panneau.js","names":[],"sources":["../src/Panneau.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport { type PanneauPlugin, PanneauProvider, createHistoryRouter } from '@panneau/core';\nimport { type DataAdapter, isApiError } from '@panneau/data';\nimport { createLaravelAdapter } from '@panneau/data/laravel';\nimport { DataAdapterProvider, definitionQueryOptions } from '@panneau/data/query';\nimport type { BootConfig } from '@panneau/protocol';\n\nimport { Shell } from './Shell';\nimport { createSessionState, getLoginUrl, watchUnauthorized } from './unauthorized';\n\n/** What `onUnauthorized` receives. */\nexport interface UnauthorizedContext {\n /**\n * Where to send the user: `auth.loginUrl` of the definition in `external` auth mode, or the\n * `loginUrl` of the boot config before the definition is loaded. `null` when there is none, or\n * in `panneau` auth mode, where the login page is part of the app.\n */\n loginUrl: string | null;\n}\n\n/** Props of `<Panneau>`. */\nexport interface PanneauProps {\n /** The boot config, validated (`readBootConfig()`, or `validateBootConfig()` of the protocol). */\n config: BootConfig;\n /** The data adapter. Defaults to `createLaravelAdapter({ baseUrl: config.apiBaseUrl })`. */\n adapter?: DataAdapter;\n /** Plugins: field types, pages, locales, themes… */\n plugins?: readonly PanneauPlugin[];\n /** The TanStack Query client. Defaults to a new one. */\n queryClient?: QueryClient;\n /**\n * Called once when the API answers that the user isn't authenticated (`401`, or `419` with the\n * Laravel adapter). The app then shows that the session ended. Defaults to sending the browser\n * to `loginUrl` when there is one.\n */\n onUnauthorized?: (context: UnauthorizedContext) => void;\n}\n\nfunction redirectToLogin({ loginUrl }: UnauthorizedContext) {\n if (loginUrl !== null) {\n window.location.assign(loginUrl);\n }\n}\n\nfunction createQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n // Client errors (401, 403, 404, 422…) don't change on retry.\n retry: (failureCount, error) =>\n !(isApiError(error) && error.status < 500) && failureCount < 3,\n },\n },\n });\n}\n\nfunction Content({\n config,\n adapter,\n plugins,\n session,\n onUnauthorized,\n}: Required<Pick<PanneauProps, 'config' | 'adapter' | 'onUnauthorized'>> & {\n plugins: readonly PanneauPlugin[];\n session: ReturnType<typeof createSessionState>;\n}) {\n const [router] = useState(createHistoryRouter);\n const definitionQuery = useQuery({\n ...definitionQueryOptions(adapter),\n initialData: config.definition,\n });\n const signedOut = useSyncExternalStore(session.subscribe, session.isSignedOut);\n const loginUrl = getLoginUrl(definitionQuery.data, config);\n\n useEffect(() => {\n if (signedOut) {\n onUnauthorized({ loginUrl });\n }\n // Only when the session ends: `loginUrl` and the callback are read at that time.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [signedOut]);\n\n if (signedOut) {\n return (\n <div role=\"alert\">\n <p>Your session has ended.</p>\n {loginUrl !== null ? <a href={loginUrl}>Log in</a> : null}\n </div>\n );\n }\n if (definitionQuery.data === undefined) {\n if (definitionQuery.isError) {\n return (\n <div role=\"alert\">\n <p>The admin panel could not be loaded.</p>\n <button type=\"button\" onClick={() => void definitionQuery.refetch()}>\n Try again\n </button>\n </div>\n );\n }\n return <p role=\"status\">Loading…</p>;\n }\n return (\n <PanneauProvider plugins={plugins} definition={definitionQuery.data} router={router}>\n <Shell definition={definitionQuery.data} basePath={config.basePath} />\n </PanneauProvider>\n );\n}\n\n/**\n * The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it\n * in an element of the page. The adapter and the query client are read on the first render.\n *\n * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When\n * the API answers that the user isn't authenticated, it calls `onUnauthorized`.\n */\nexport function Panneau({\n config,\n adapter,\n plugins = [],\n queryClient,\n onUnauthorized = redirectToLogin,\n}: PanneauProps) {\n const [state] = useState(() => {\n const session = createSessionState();\n return {\n session,\n adapter: watchUnauthorized(\n adapter ?? createLaravelAdapter({ baseUrl: config.apiBaseUrl }),\n session,\n ),\n queryClient: queryClient ?? createQueryClient(),\n };\n });\n return (\n <QueryClientProvider client={state.queryClient}>\n <DataAdapterProvider adapter={state.adapter}>\n <Content\n config={config}\n adapter={state.adapter}\n plugins={plugins}\n session={state.session}\n onUnauthorized={onUnauthorized}\n />\n </DataAdapterProvider>\n </QueryClientProvider>\n );\n}\n"],"mappings":";;;;;;;;;;AAwCA,SAAS,gBAAgB,EAAE,YAAiC;CACxD,IAAI,aAAa,MACb,OAAO,SAAS,OAAO,QAAQ;AAEvC;AAEA,SAAS,oBAAiC;CACtC,OAAO,IAAI,YAAY,EACnB,gBAAgB,EACZ,SAAS,EAEL,QAAQ,cAAc,UAClB,EAAE,WAAW,KAAK,KAAK,MAAM,SAAS,QAAQ,eAAe,EACrE,EACJ,EACJ,CAAC;AACL;AAEA,SAAS,QAAQ,EACb,QACA,SACA,SACA,SACA,kBAID;CACC,MAAM,CAAC,UAAU,SAAS,mBAAmB;CAC7C,MAAM,kBAAkB,SAAS;EAC7B,GAAG,uBAAuB,OAAO;EACjC,aAAa,OAAO;CACxB,CAAC;CACD,MAAM,YAAY,qBAAqB,QAAQ,WAAW,QAAQ,WAAW;CAC7E,MAAM,WAAW,YAAY,gBAAgB,MAAM,MAAM;CAEzD,gBAAgB;EACZ,IAAI,WACA,eAAe,EAAE,SAAS,CAAC;CAInC,GAAG,CAAC,SAAS,CAAC;CAEd,IAAI,WACA,OACI,qBAAC,OAAD;EAAK,MAAK;EAAV,UAAA,CACI,oBAAC,KAAD,EAAA,UAAG,0BAA0B,CAAA,GAC5B,aAAa,OAAO,oBAAC,KAAD;GAAG,MAAM;GAAU,UAAA;EAAS,CAAA,IAAI,IACpD;;CAGb,IAAI,gBAAgB,SAAS,KAAA,GAAW;EACpC,IAAI,gBAAgB,SAChB,OACI,qBAAC,OAAD;GAAK,MAAK;GAAV,UAAA,CACI,oBAAC,KAAD,EAAA,UAAG,uCAAuC,CAAA,GAC1C,oBAAC,UAAD;IAAQ,MAAK;IAAS,eAAe,KAAK,gBAAgB,QAAQ;IAAE,UAAA;GAE5D,CAAA,CACP;;EAGb,OAAO,oBAAC,KAAD;GAAG,MAAK;GAAS,UAAA;EAAW,CAAA;CACvC;CACA,OACI,oBAAC,iBAAD;EAA0B;EAAS,YAAY,gBAAgB;EAAc;EACzE,UAAA,oBAAC,OAAD;GAAO,YAAY,gBAAgB;GAAM,UAAU,OAAO;EAAS,CAAA;CACtD,CAAA;AAEzB;;;;;;;;AASA,SAAgB,QAAQ,EACpB,QACA,SACA,UAAU,CAAA,GACV,aACA,iBAAiB,mBACJ;CACb,MAAM,CAAC,SAAS,eAAe;EAC3B,MAAM,UAAU,mBAAmB;EACnC,OAAO;GACH;GACA,SAAS,kBACL,WAAW,qBAAqB,EAAE,SAAS,OAAO,WAAW,CAAC,GAC9D,OACJ;GACA,aAAa,eAAe,kBAAkB;EAClD;CACJ,CAAC;CACD,OACI,oBAAC,qBAAD;EAAqB,QAAQ,MAAM;EAC/B,UAAA,oBAAC,qBAAD;GAAqB,SAAS,MAAM;GAChC,UAAA,oBAAC,SAAD;IACY;IACR,SAAS,MAAM;IACN;IACT,SAAS,MAAM;IACC;GAAe,CAAA;EAElB,CAAA;CACJ,CAAA;AAE7B"}
|
|
1
|
+
{"version":3,"file":"Panneau.js","names":["loginUrl","onRetry","styles","_c"],"sources":["../src/Panneau.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';\nimport { useEffect, useState, useSyncExternalStore } from 'react';\n\nimport {\n type PanneauPlugin,\n PanneauProvider,\n createHistoryRouter,\n createPluginRegistry,\n resolveTheme,\n} from '@panneau/core';\nimport { type DataAdapter, isApiError } from '@panneau/data';\nimport { createLaravelAdapter } from '@panneau/data/laravel';\nimport { DataAdapterProvider, definitionQueryOptions } from '@panneau/data/query';\nimport { appMessages } from '@panneau/intl';\nimport type { BootConfig } from '@panneau/protocol';\nimport { Button, type NamedIconLoader, PanneauRoot, Spinner, usePanneauIntl } from '@panneau/ui';\nimport { lucideIconLoader } from '@panneau/ui/named-icons';\n\nimport styles from './Panneau.module.css';\nimport { Shell } from './Shell';\nimport { usePreference } from './preferences';\nimport { COLOR_SCHEMES } from './shell/Sidebar';\nimport { createSessionState, getLoginUrl, watchUnauthorized } from './unauthorized';\n\n/** What `onUnauthorized` receives. */\nexport interface UnauthorizedContext {\n /**\n * Where to send the user: `auth.loginUrl` of the definition in `external` auth mode, or the\n * `loginUrl` of the boot config before the definition is loaded. `null` when there is none, or\n * in `panneau` auth mode, where the login page is part of the app.\n */\n loginUrl: string | null;\n}\n\n/** Props of `<Panneau>`. */\nexport interface PanneauProps {\n /** The boot config, validated (`readBootConfig()`, or `validateBootConfig()` of the protocol). */\n config: BootConfig;\n /** The data adapter. Defaults to `createLaravelAdapter({ baseUrl: config.apiBaseUrl })`. */\n adapter?: DataAdapter;\n /** Plugins: field types, pages, locales, themes… */\n plugins?: readonly PanneauPlugin[];\n /** The TanStack Query client. Defaults to a new one. */\n queryClient?: QueryClient;\n /**\n * Loads the Lucide icons that the definition names (`\"icon\": \"users\"`). Defaults to every\n * Lucide icon, each one in its own chunk, loaded when shown. `null` shows no named icons.\n */\n iconLoader?: NamedIconLoader | null;\n /**\n * Called once when the API answers that the user isn't authenticated (`401`, or `419` with the\n * Laravel adapter). The app then shows that the session ended. Defaults to sending the browser\n * to `loginUrl` when there is one.\n */\n onUnauthorized?: (context: UnauthorizedContext) => void;\n}\n\nfunction redirectToLogin({ loginUrl }: UnauthorizedContext) {\n if (loginUrl !== null) {\n window.location.assign(loginUrl);\n }\n}\n\nfunction createQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: {\n // Client errors (401, 403, 404, 422…) don't change on retry.\n retry: (failureCount, error) =>\n !(isApiError(error) && error.status < 500) && failureCount < 3,\n },\n },\n });\n}\n\nfunction Content({\n config,\n adapter,\n plugins,\n iconLoader,\n session,\n onUnauthorized,\n}: Required<Pick<PanneauProps, 'config' | 'adapter' | 'onUnauthorized'>> & {\n plugins: readonly PanneauPlugin[];\n iconLoader: NamedIconLoader | null;\n session: ReturnType<typeof createSessionState>;\n}) {\n const [router] = useState(createHistoryRouter);\n const definitionQuery = useQuery({\n ...definitionQueryOptions(adapter),\n initialData: config.definition,\n });\n const signedOut = useSyncExternalStore(session.subscribe, session.isSignedOut);\n const [colorScheme, setColorScheme] = usePreference('color-scheme', COLOR_SCHEMES);\n const definition = definitionQuery.data;\n const loginUrl = getLoginUrl(definition, config);\n\n useEffect(() => {\n if (signedOut) {\n onUnauthorized({ loginUrl });\n }\n // Only when the session ends: `loginUrl` and the callback are read at that time.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [signedOut]);\n\n const scheme = colorScheme ?? definition?.theme?.colorScheme ?? 'light';\n return (\n <PanneauRoot\n theme={\n definition !== undefined\n ? resolveTheme(definition.theme, createPluginRegistry(plugins).themes)\n : null\n }\n colorScheme={scheme}\n locale={definition?.locale ?? config.locale}\n iconLoader={iconLoader}\n className={styles.root}\n >\n {signedOut ? (\n <SessionEnded loginUrl={loginUrl} />\n ) : definition === undefined ? (\n <Loading\n isError={definitionQuery.isError}\n onRetry={() => void definitionQuery.refetch()}\n />\n ) : (\n <PanneauProvider plugins={plugins} definition={definition} router={router}>\n <Shell\n definition={definition}\n basePath={config.basePath}\n colorScheme={scheme}\n onColorSchemeChange={setColorScheme}\n />\n </PanneauProvider>\n )}\n </PanneauRoot>\n );\n}\n\nfunction SessionEnded({ loginUrl }: { loginUrl: string | null }) {\n const intl = usePanneauIntl();\n return (\n <div role=\"alert\" className={styles.state}>\n <p>{intl.formatMessage(appMessages.sessionEnded)}</p>\n {loginUrl !== null ? (\n <a href={loginUrl}>{intl.formatMessage(appMessages.logIn)}</a>\n ) : null}\n </div>\n );\n}\n\nfunction Loading({ isError, onRetry }: { isError: boolean; onRetry: () => void }) {\n const intl = usePanneauIntl();\n if (isError) {\n return (\n <div role=\"alert\" className={styles.state}>\n <p>{intl.formatMessage(appMessages.loadError)}</p>\n <Button onPress={onRetry}>{intl.formatMessage(appMessages.retry)}</Button>\n </div>\n );\n }\n return (\n <div className={styles.state}>\n <Spinner showLabel label={intl.formatMessage(appMessages.loading)} />\n </div>\n );\n}\n\n/**\n * The Panneau admin panel, for a React app that renders it itself. `createPanneauApp()` mounts it\n * in an element of the page. The adapter and the query client are read on the first render.\n *\n * It uses the definition inlined in the boot config, or fetches it, then renders the shell. When\n * the API answers that the user isn't authenticated, it calls `onUnauthorized`.\n */\nexport function Panneau({\n config,\n adapter,\n plugins = [],\n queryClient,\n iconLoader = lucideIconLoader,\n onUnauthorized = redirectToLogin,\n}: PanneauProps) {\n const [state] = useState(() => {\n const session = createSessionState();\n return {\n session,\n adapter: watchUnauthorized(\n adapter ?? createLaravelAdapter({ baseUrl: config.apiBaseUrl }),\n session,\n ),\n queryClient: queryClient ?? createQueryClient(),\n };\n });\n return (\n <QueryClientProvider client={state.queryClient}>\n <DataAdapterProvider adapter={state.adapter}>\n <Content\n config={config}\n adapter={state.adapter}\n plugins={plugins}\n iconLoader={iconLoader}\n session={state.session}\n onUnauthorized={onUnauthorized}\n />\n </DataAdapterProvider>\n </QueryClientProvider>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyDA,SAAS,gBAAgB,EAAE,YAAiC;CACxD,IAAI,aAAa,MACb,OAAO,SAAS,OAAO,QAAQ;AAEvC;AAEA,SAAS,oBAAiC;CACtC,OAAO,IAAI,YAAY,EACnB,gBAAgB,EACZ,SAAS,EAEL,QAAQ,cAAc,UAClB,EAAE,WAAW,KAAK,KAAK,MAAM,SAAS,QAAQ,eAAe,EACrE,EACJ,EACJ,CAAC;AACL;AAEA,SAAS,QAAQ,EACb,QACA,SACA,SACA,YACA,SACA,kBAKD;CACC,MAAM,CAAC,UAAU,SAAS,mBAAmB;CAC7C,MAAM,kBAAkB,SAAS;EAC7B,GAAG,uBAAuB,OAAO;EACjC,aAAa,OAAO;CACxB,CAAC;CACD,MAAM,YAAY,qBAAqB,QAAQ,WAAW,QAAQ,WAAW;CAC7E,MAAM,CAAC,aAAa,kBAAkB,cAAc,gBAAgB,aAAa;CACjF,MAAM,aAAa,gBAAgB;CACnC,MAAM,WAAW,YAAY,YAAY,MAAM;CAE/C,gBAAgB;EACZ,IAAI,WACA,eAAe,EAAE,SAAS,CAAC;CAInC,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,SAAS,eAAe,YAAY,OAAO,eAAe;CAChE,OACI,oBAAC,aAAD;EACI,OACI,eAAe,KAAA,IACT,aAAa,WAAW,OAAO,qBAAqB,OAAO,CAAC,CAAC,MAAM,IACnE;EAEV,aAAa;EACb,QAAQ,YAAY,UAAU,OAAO;EACzB;EACZ,WAAWE,uBAAO;EAEjB,UAAA,YACG,oBAAC,cAAD,EAAwB,SAAS,CAAA,IACjC,eAAe,KAAA,IACf,oBAAC,SAAD;GACI,SAAS,gBAAgB;GACzB,eAAe,KAAK,gBAAgB,QAAQ;EAAE,CAAA,IAGlD,oBAAC,iBAAD;GAA0B;GAAqB;GAAoB;GAC/D,UAAA,oBAAC,OAAD;IACgB;IACZ,UAAU,OAAO;IACjB,aAAa;IACb,qBAAqB;GAAe,CAAA;EAE3B,CAAA;CAEZ,CAAA;AAErB;AAEA,SAAA,aAAA,IAAA;CAAA,MAAA,IAAAC,EAAA,EAAA;CAAsB,MAAA,EAAA,aAAA;CAClB,MAAA,OAAa,eAAe;CAAE,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA;EAGlB,KAAA,KAAI,cAAe,YAAW,YAAa;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAhD,KAAA,oBAAA,KAAA,EAAA,UAAI,GAAiD,CAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,QAAA,EAAA,OAAA,UAAA;EACpD,KAAA,aAAa,OACV,oBAAA,KAAA;GAASH,MAAA;GAAW,UAAA,KAAI,cAAe,YAAW,KAAM;EAAM,CAAA,IADjE;EAEO,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAJZ,KAAA,qBAAA,OAAA;GAAU,MAAA;GAAmB,WAAAE,uBAAM;GAAnC,UAAA,CACI,IACC,EAGC;;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OALN;AAKM;AAId,SAAA,QAAA,IAAA;CAAA,MAAA,IAAAC,EAAA,EAAA;CAAiB,MAAA,EAAA,SAAA,YAAA;CACb,MAAA,OAAa,eAAe;CAC5B,IAAI,SAAO;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,MAAA;GAGK,KAAA,KAAI,cAAe,YAAW,SAAU;GAAC,EAAA,KAAA;GAAA,EAAA,KAAA;EAAA,OAAA,KAAA,EAAA;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,IAAA;GAA7C,KAAA,oBAAA,KAAA,EAAA,UAAI,GAA8C,CAAA;GAAA,EAAA,KAAA;GAAA,EAAA,KAAA;EAAA,OAAA,KAAA,EAAA;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,MAAA;GACvB,KAAA,KAAI,cAAe,YAAW,KAAM;GAAC,EAAA,KAAA;GAAA,EAAA,KAAA;EAAA,OAAA,KAAA,EAAA;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,WAAA,EAAA,OAAA,IAAA;GAAhE,KAAA,oBAAC,QAAD;IAAiBF,SAAA;IAAU,UAAA;GAApB,CAAA;GAAmE,EAAA,KAAA;GAAA,EAAA,KAAA;GAAA,EAAA,KAAA;EAAA,OAAA,KAAA,EAAA;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,MAAA,EAAA,QAAA,IAAA;GAF9E,KAAA,qBAAA,OAAA;IAAU,MAAA;IAAmB,WAAAC,uBAAM;IAAnC,UAAA,CACI,IACA,EACE;;GAAA,EAAA,KAAA;GAAA,EAAA,MAAA;GAAA,EAAA,MAAA;EAAA,OAAA,KAAA,EAAA;EAAA,OAHN;CAGM;CAEb,IAAA;CAAA,IAAA,EAAA,QAAA,MAAA;EAGiC,KAAA,KAAI,cAAe,YAAW,OAAQ;EAAC,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,IAAA;EADrE,KAAA,oBAAA,OAAA;GAAgB,WAAAA,uBAAM;GAClB,UAAA,oBAAC,SAAD;IAAS,WAAA;IAAiB,OAAA;GAAuC,CAAA;EAC/D,CAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAFN;AAEM;;;;;;;;AAWd,SAAgB,QAAQ,EACpB,QACA,SACA,UAAU,CAAA,GACV,aACA,aAAa,kBACb,iBAAiB,mBACJ;CACb,MAAM,CAAC,SAAS,eAAe;EAC3B,MAAM,UAAU,mBAAmB;EACnC,OAAO;GACH;GACA,SAAS,kBACL,WAAW,qBAAqB,EAAE,SAAS,OAAO,WAAW,CAAC,GAC9D,OACJ;GACA,aAAa,eAAe,kBAAkB;EAClD;CACJ,CAAC;CACD,OACI,oBAAC,qBAAD;EAAqB,QAAQ,MAAM;EAC/B,UAAA,oBAAC,qBAAD;GAAqB,SAAS,MAAM;GAChC,UAAA,oBAAC,SAAD;IACY;IACR,SAAS,MAAM;IACN;IACG;IACZ,SAAS,MAAM;IACC;GAAe,CAAA;EAElB,CAAA;CACJ,CAAA;AAE7B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "./Panneau.css";
|
|
2
|
+
//#region src/Panneau.module.css
|
|
3
|
+
var root = "panneau-panneau-root";
|
|
4
|
+
var state = "panneau-panneau-state";
|
|
5
|
+
var Panneau_module_default = {
|
|
6
|
+
root,
|
|
7
|
+
state
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { Panneau_module_default as default, root, state };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=Panneau.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Panneau.module.js","names":[],"sources":["../src/Panneau.module.css"],"sourcesContent":[".root {\n min-height: 100dvh;\n}\n\n/* Loading, a definition that failed to load, and an ended session: centered in the window. */\n.state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--panneau-space-3);\n min-height: 100dvh;\n padding: var(--panneau-space-4);\n text-align: center;\n}\n\n.state p {\n margin: 0;\n}\n"],"mappings":""}
|
package/dist/Shell.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { Definition } from '@panneau/protocol';
|
|
2
|
+
import type { ColorSchemePreference } from './shell/Sidebar';
|
|
2
3
|
export interface ShellProps {
|
|
3
4
|
definition: Definition;
|
|
4
5
|
basePath: string;
|
|
6
|
+
colorScheme: ColorSchemePreference;
|
|
7
|
+
onColorSchemeChange: (scheme: ColorSchemePreference) => void;
|
|
5
8
|
}
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
10
|
+
* The app shell: the layout with its sidebar, and the page of the current route. Links go
|
|
11
|
+
* through the history of the browser without reloading the page, and actions run through the
|
|
12
|
+
* adapter, refreshing what their result changed. Leaving a page with unsaved changes, by a link
|
|
13
|
+
* or by going back or forward, asks first.
|
|
9
14
|
*/
|
|
10
|
-
export declare function Shell({ definition, basePath }: ShellProps): import("react").JSX.Element;
|
|
15
|
+
export declare function Shell({ definition, basePath, colorScheme, onColorSchemeChange }: ShellProps): import("react").JSX.Element;
|
|
11
16
|
//# sourceMappingURL=Shell.d.ts.map
|
package/dist/Shell.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Shell.d.ts","sourceRoot":"","sources":["../src/Shell.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Shell.d.ts","sourceRoot":"","sources":["../src/Shell.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAWpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,qBAAqB,CAAC;IACnC,mBAAmB,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAChE;AAuFD;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,mBAAmB,EAAE,EAAE,UAAU,+BAmD3F"}
|