@fayz-ai/plugin-admin 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.
- package/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/AdminContext.d.ts +20 -0
- package/dist/AdminContext.d.ts.map +1 -0
- package/dist/AdminPage.d.ts +17 -0
- package/dist/AdminPage.d.ts.map +1 -0
- package/dist/contract.test.d.ts +2 -0
- package/dist/contract.test.d.ts.map +1 -0
- package/dist/data/capability.test.d.ts +2 -0
- package/dist/data/capability.test.d.ts.map +1 -0
- package/dist/data/mock.d.ts +8 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/supabase.d.ts +11 -0
- package/dist/data/supabase.d.ts.map +1 -0
- package/dist/data/types.d.ts +12 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/index.cjs +221 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +215 -0
- package/dist/index.js.map +1 -0
- package/dist/locales/en.d.ts +2 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/index.d.ts +2 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/pt-BR.d.ts +2 -0
- package/dist/locales/pt-BR.d.ts.map +1 -0
- package/dist/store.d.ts +9 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +52 -0
- package/src/AdminContext.tsx +24 -0
- package/src/AdminPage.tsx +84 -0
- package/src/contract.test.ts +40 -0
- package/src/data/capability.test.ts +30 -0
- package/src/data/mock.ts +14 -0
- package/src/data/supabase.ts +17 -0
- package/src/data/types.ts +20 -0
- package/src/index.ts +133 -0
- package/src/locales/en.ts +17 -0
- package/src/locales/index.ts +7 -0
- package/src/locales/pt-BR.ts +17 -0
- package/src/store.ts +29 -0
- package/src/types.ts +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Faya Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @fayz-ai/plugin-admin
|
|
2
|
+
|
|
3
|
+
> A Panel view onto your app's own shell config — layout, module nav, and branding, at a glance.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@fayz-ai/plugin-admin)
|
|
6
|
+
[](https://github.com/FayaLabs/fayz-sdk/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
Every SaaS/admin-template app already resolves a shell config — sidebar or topbar layout, rail or tabs for module navigation, a mobile header treatment, whether org/branding settings are shown — from `FayzAppConfig` (`src/config/app.tsx` / `theme.ts`) at build time. Today an operator can't see any of that from the Panel; changing it means hand-editing config files and redeploying. `plugin-admin` adds an `/admin` page that reflects the resolved config so it's visible without reading source.
|
|
9
|
+
|
|
10
|
+
## Foundation status — read this first
|
|
11
|
+
|
|
12
|
+
This is a **foundation pass, not a capability-complete plugin**. It ships a read-only view of `layout` / `moduleNav` / `mobileHeader` / `branding`; there is **no write path** yet. The data provider (mock + Supabase stub) both simply echo back the statically resolved config — there is no shell-config table, and this plugin does not make `FayzAppConfig.layout` (or any of its siblings) mutable at runtime.
|
|
13
|
+
|
|
14
|
+
**Follow-up**: wire real read/write of these fields back into `FayzAppConfig` once a plugin-editable extension point exists for shell-level config. `docs/CUSTOMIZATION.md` already names the gap — the saas shell's slot contracts (named layout/menu slots, published like the storefront's) are `[planned FAY-1248/FAY-1196]`, the "persona/slots phase". `plugin-admin`'s write path is a consumer of that phase, not a substitute for it: it should land once shell slots have a published contract to write through, not by having this plugin reach around `defineSaas` and mutate config ad hoc.
|
|
15
|
+
|
|
16
|
+
## What's inside
|
|
17
|
+
- An `/admin` page: read-only cards for layout, module navigation style, mobile header treatment, and branding visibility
|
|
18
|
+
- Config mirrors `FayzAppConfig` 1:1 (`layout`, `moduleNav`, `mobileHeader`, `navTransition`, `orgSettings`, `branding`) — no new config shape
|
|
19
|
+
- An AI tool, `getShellSettings`, so "what layout is this app using?" already works
|
|
20
|
+
- Mock + Supabase data providers (both stubs today, chosen automatically) and full i18n
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
```bash
|
|
24
|
+
npm install @fayz-ai/plugin-admin
|
|
25
|
+
```
|
|
26
|
+
Peer deps: `react`, `react-dom`. Runtime deps include `@fayz-ai/core`, `@fayz-ai/ui`, and `@fayz-ai/saas`.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
```tsx
|
|
30
|
+
import { defineSaas } from '@fayz-ai/saas'
|
|
31
|
+
import { createAdminPlugin } from '@fayz-ai/plugin-admin'
|
|
32
|
+
|
|
33
|
+
export const app = defineSaas({
|
|
34
|
+
// ...
|
|
35
|
+
layout: 'sidebar',
|
|
36
|
+
moduleNav: 'tabs',
|
|
37
|
+
plugins: [
|
|
38
|
+
createAdminPlugin({
|
|
39
|
+
layout: 'sidebar',
|
|
40
|
+
moduleNav: 'tabs',
|
|
41
|
+
mobileHeader: 'minimal',
|
|
42
|
+
branding: true,
|
|
43
|
+
}),
|
|
44
|
+
],
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
Pass the same values you already give `defineSaas` — the plugin doesn't derive them from the app config automatically (no such wiring exists yet); it just renders what you tell it.
|
|
48
|
+
|
|
49
|
+
## Part of the Fayz SDK
|
|
50
|
+
Targets the saas/admin-template scaffold only (`scaffolds: ['saas']`) — this is Panel-side shell config, not a storefront concern. Pairs with whatever settings surface the app already exposes; it adds visibility, not a new settings system.
|
|
51
|
+
|
|
52
|
+
## Roadmap & contributing
|
|
53
|
+
Built and evolving in the open. See the [Fayz SDK roadmap](../../docs/ROADMAP.md) and `docs/CUSTOMIZATION.md` (persona/slots phase) for the write-path this is scaffolding toward.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AdminDataProvider, AdminSettingsSnapshot } from './data/types';
|
|
2
|
+
import type { AdminUIState } from './store';
|
|
3
|
+
export interface AdminPluginLabels {
|
|
4
|
+
pageTitle: string;
|
|
5
|
+
pageSubtitle: string;
|
|
6
|
+
}
|
|
7
|
+
/** Resolved shell config + labels, handed to AdminPage. Mirrors AdminSettingsSnapshot. */
|
|
8
|
+
export interface ResolvedAdminConfig extends AdminSettingsSnapshot {
|
|
9
|
+
labels: AdminPluginLabels;
|
|
10
|
+
}
|
|
11
|
+
export declare const AdminContextProvider: import("react").FC<{
|
|
12
|
+
config: ResolvedAdminConfig;
|
|
13
|
+
provider: AdminDataProvider;
|
|
14
|
+
store: import("zustand").StoreApi<AdminUIState>;
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const useAdminConfig: () => ResolvedAdminConfig;
|
|
18
|
+
export declare const useAdminProvider: () => AdminDataProvider;
|
|
19
|
+
export declare const useAdminStore: <T>(selector: (state: AdminUIState) => T) => T;
|
|
20
|
+
//# sourceMappingURL=AdminContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminContext.d.ts","sourceRoot":"","sources":["../src/AdminContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAM3C,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAID,eAAO,MAAM,oBAAoB;;;;;EAAsB,CAAA;AACvD,eAAO,MAAM,cAAc,2BAAgB,CAAA;AAC3C,eAAO,MAAM,gBAAgB,yBAAkB,CAAA;AAC/C,eAAO,MAAM,aAAa,gDAAe,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { StoreApi } from 'zustand/vanilla';
|
|
3
|
+
import { type ResolvedAdminConfig } from './AdminContext';
|
|
4
|
+
import type { AdminDataProvider } from './data/types';
|
|
5
|
+
import type { AdminUIState } from './store';
|
|
6
|
+
/**
|
|
7
|
+
* Read-only foundation view. Renders the shell config this app already
|
|
8
|
+
* resolved (layout, module nav, mobile header, branding) so an operator can
|
|
9
|
+
* see it at a glance — it does not yet let them change it. See README.md for
|
|
10
|
+
* the write-path this is scaffolding toward.
|
|
11
|
+
*/
|
|
12
|
+
export declare function AdminPage({ config, provider, store }: {
|
|
13
|
+
config: ResolvedAdminConfig;
|
|
14
|
+
provider: AdminDataProvider;
|
|
15
|
+
store: StoreApi<AdminUIState>;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
//# sourceMappingURL=AdminPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminPage.d.ts","sourceRoot":"","sources":["../src/AdminPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI/C,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAsB3C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IACrD,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;CAC9B,qBA4CA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.test.d.ts","sourceRoot":"","sources":["../src/contract.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.test.d.ts","sourceRoot":"","sources":["../../src/data/capability.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AdminDataProvider, AdminSettingsSnapshot } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Mock provider — returns the statically resolved shell-config snapshot
|
|
4
|
+
* (from plugin options / FayzAppConfig defaults). No in-memory mutation:
|
|
5
|
+
* this plugin doesn't write settings yet.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createMockAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider;
|
|
8
|
+
//# sourceMappingURL=mock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/data/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEvE;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,iBAAiB,CAM1F"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AdminDataProvider, AdminSettingsSnapshot } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Supabase provider — foundation stub. There is no shell-config table yet:
|
|
4
|
+
* layout/moduleNav/mobileHeader/branding are still owned by FayzAppConfig at
|
|
5
|
+
* build time, not a runtime-editable record. This provider exists so the
|
|
6
|
+
* plugin follows the standard createSafeDataProvider(supabase, mock) seam
|
|
7
|
+
* from day one; it returns the same static snapshot the mock provider does
|
|
8
|
+
* until a real read/write path is wired (see README.md).
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSupabaseAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider;
|
|
11
|
+
//# sourceMappingURL=supabase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/data/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEvE;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,qBAAqB,GAAG,iBAAiB,CAM9F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface AdminSettingsSnapshot {
|
|
2
|
+
layout: 'sidebar' | 'topbar' | 'minimal';
|
|
3
|
+
moduleNav: 'rail' | 'tabs';
|
|
4
|
+
mobileHeader: 'minimal' | 'transparent' | 'hidden';
|
|
5
|
+
navTransition: 'slide' | 'fade' | 'none';
|
|
6
|
+
orgSettings: boolean;
|
|
7
|
+
branding: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface AdminDataProvider {
|
|
10
|
+
getSettings(): Promise<AdminSettingsSnapshot>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/data/types.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAA;IACxC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,YAAY,EAAE,SAAS,GAAG,aAAa,GAAG,QAAQ,CAAA;IAClD,aAAa,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;IACxC,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAA;CAC9C"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var core = require('@fayz-ai/core');
|
|
5
|
+
var vanilla = require('zustand/vanilla');
|
|
6
|
+
var saas = require('@fayz-ai/saas');
|
|
7
|
+
var lucideReact = require('lucide-react');
|
|
8
|
+
var ui = require('@fayz-ai/ui');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
14
|
+
|
|
15
|
+
// src/index.ts
|
|
16
|
+
|
|
17
|
+
// src/data/mock.ts
|
|
18
|
+
function createMockAdminProvider(snapshot) {
|
|
19
|
+
return {
|
|
20
|
+
async getSettings() {
|
|
21
|
+
return snapshot;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/data/supabase.ts
|
|
27
|
+
function createSupabaseAdminProvider(snapshot) {
|
|
28
|
+
return {
|
|
29
|
+
async getSettings() {
|
|
30
|
+
return snapshot;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function createAdminStore(provider) {
|
|
35
|
+
return vanilla.createStore((set) => ({
|
|
36
|
+
settings: null,
|
|
37
|
+
settingsLoading: false,
|
|
38
|
+
async fetchSettings() {
|
|
39
|
+
return saas.dedup("admin:settings", async () => {
|
|
40
|
+
set({ settingsLoading: true });
|
|
41
|
+
try {
|
|
42
|
+
const settings = await provider.getSettings();
|
|
43
|
+
set({ settings, settingsLoading: false });
|
|
44
|
+
} catch {
|
|
45
|
+
set({ settingsLoading: false });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/locales/en.ts
|
|
53
|
+
var en = {
|
|
54
|
+
"admin.layout.title": "Layout",
|
|
55
|
+
"admin.layout.sidebar": "Sidebar",
|
|
56
|
+
"admin.layout.topbar": "Topbar",
|
|
57
|
+
"admin.layout.minimal": "Minimal",
|
|
58
|
+
"admin.moduleNav.title": "Module navigation",
|
|
59
|
+
"admin.moduleNav.rail": "Side rail for the installed modules",
|
|
60
|
+
"admin.moduleNav.tabs": "Tabs for the installed modules",
|
|
61
|
+
"admin.mobileHeader.title": "Mobile header",
|
|
62
|
+
"admin.mobileHeader.minimal": "Minimal header bar",
|
|
63
|
+
"admin.mobileHeader.transparent": "Transparent, edge-to-edge content",
|
|
64
|
+
"admin.mobileHeader.hidden": "Hidden",
|
|
65
|
+
"admin.branding.title": "Branding",
|
|
66
|
+
"admin.branding.on": "Org branding settings are visible to operators",
|
|
67
|
+
"admin.branding.off": "Org branding settings are hidden",
|
|
68
|
+
"admin.readOnlyNotice": "Read-only preview. Editing these settings here is coming soon \u2014 for now they are set in your app config."
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/locales/pt-BR.ts
|
|
72
|
+
var ptBR = {
|
|
73
|
+
"admin.layout.title": "Layout",
|
|
74
|
+
"admin.layout.sidebar": "Barra lateral",
|
|
75
|
+
"admin.layout.topbar": "Barra superior",
|
|
76
|
+
"admin.layout.minimal": "Minimalista",
|
|
77
|
+
"admin.moduleNav.title": "Navega\xE7\xE3o dos m\xF3dulos",
|
|
78
|
+
"admin.moduleNav.rail": "Barra lateral para os m\xF3dulos instalados",
|
|
79
|
+
"admin.moduleNav.tabs": "Abas para os m\xF3dulos instalados",
|
|
80
|
+
"admin.mobileHeader.title": "Cabe\xE7alho mobile",
|
|
81
|
+
"admin.mobileHeader.minimal": "Cabe\xE7alho minimalista",
|
|
82
|
+
"admin.mobileHeader.transparent": "Transparente, conte\xFAdo de ponta a ponta",
|
|
83
|
+
"admin.mobileHeader.hidden": "Oculto",
|
|
84
|
+
"admin.branding.title": "Identidade visual",
|
|
85
|
+
"admin.branding.on": "As configura\xE7\xF5es de marca est\xE3o vis\xEDveis para operadores",
|
|
86
|
+
"admin.branding.off": "As configura\xE7\xF5es de marca est\xE3o ocultas",
|
|
87
|
+
"admin.readOnlyNotice": "Pr\xE9-visualiza\xE7\xE3o somente leitura. A edi\xE7\xE3o por aqui chega em breve \u2014 por enquanto essas op\xE7\xF5es s\xE3o definidas na configura\xE7\xE3o do app."
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/locales/index.ts
|
|
91
|
+
var adminLocales = {
|
|
92
|
+
en,
|
|
93
|
+
"pt-BR": ptBR
|
|
94
|
+
};
|
|
95
|
+
var ctx = saas.createPluginContext("AdminPage");
|
|
96
|
+
var AdminContextProvider = ctx.ContextProvider;
|
|
97
|
+
ctx.useConfig;
|
|
98
|
+
ctx.useProvider;
|
|
99
|
+
ctx.useStore;
|
|
100
|
+
var LAYOUT_VARIANTS = ["sidebar", "topbar", "minimal"];
|
|
101
|
+
function SettingCard({ icon: Icon, title, children }) {
|
|
102
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border bg-background/60 p-4", children: [
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 w-8 rounded-lg bg-foreground/[0.04] flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4 text-muted-foreground" }) }),
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium", children: title })
|
|
106
|
+
] }),
|
|
107
|
+
children
|
|
108
|
+
] });
|
|
109
|
+
}
|
|
110
|
+
function AdminPage({ config, provider, store }) {
|
|
111
|
+
const t = core.useTranslation();
|
|
112
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AdminContextProvider, { config, provider, store, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.ModulePage, { title: config.labels.pageTitle, subtitle: config.labels.pageSubtitle, nav: [], children: [
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsx(SettingCard, { icon: config.layout === "topbar" ? lucideReact.PanelTop : lucideReact.LayoutTemplate, title: t("admin.layout.title"), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 text-sm", children: LAYOUT_VARIANTS.map((variant) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
115
|
+
"span",
|
|
116
|
+
{
|
|
117
|
+
className: "rounded-md border px-2.5 py-1.5 " + (config.layout === variant ? "border-primary/40 bg-primary/5 text-foreground" : "border-border text-muted-foreground"),
|
|
118
|
+
children: t(`admin.layout.${variant}`)
|
|
119
|
+
},
|
|
120
|
+
variant
|
|
121
|
+
)) }) }),
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsx(SettingCard, { icon: lucideReact.Settings2, title: t("admin.moduleNav.title"), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: t(`admin.moduleNav.${config.moduleNav}`) }) }),
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsx(SettingCard, { icon: lucideReact.Smartphone, title: t("admin.mobileHeader.title"), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: t(`admin.mobileHeader.${config.mobileHeader}`) }) }),
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsx(SettingCard, { icon: lucideReact.Palette, title: t("admin.branding.title"), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: config.branding ? t("admin.branding.on") : t("admin.branding.off") }) })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-6 text-xs text-muted-foreground", children: t("admin.readOnlyNotice") })
|
|
127
|
+
] }) });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/index.ts
|
|
131
|
+
var DEFAULT_LABELS = {
|
|
132
|
+
pageTitle: "Admin",
|
|
133
|
+
pageSubtitle: "Your app's layout, navigation, and branding."
|
|
134
|
+
};
|
|
135
|
+
function resolveConfig(options) {
|
|
136
|
+
return {
|
|
137
|
+
labels: DEFAULT_LABELS,
|
|
138
|
+
layout: options?.layout ?? "sidebar",
|
|
139
|
+
moduleNav: options?.moduleNav ?? "tabs",
|
|
140
|
+
mobileHeader: options?.mobileHeader ?? "minimal",
|
|
141
|
+
navTransition: options?.navTransition ?? "slide",
|
|
142
|
+
orgSettings: options?.orgSettings ?? true,
|
|
143
|
+
branding: options?.branding ?? true
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function toSnapshot(config) {
|
|
147
|
+
const { labels: _labels, ...snapshot } = config;
|
|
148
|
+
return snapshot;
|
|
149
|
+
}
|
|
150
|
+
function createAdminPlugin(options) {
|
|
151
|
+
const config = resolveConfig(options);
|
|
152
|
+
core.registerTranslations(adminLocales);
|
|
153
|
+
const snapshot = toSnapshot(config);
|
|
154
|
+
const provider = options?.dataProvider ?? core.createSafeDataProvider(
|
|
155
|
+
() => createSupabaseAdminProvider(snapshot),
|
|
156
|
+
() => createMockAdminProvider(snapshot)
|
|
157
|
+
);
|
|
158
|
+
const store = createAdminStore(provider);
|
|
159
|
+
const PageComponent = () => React__default.default.createElement(AdminPage, { config, provider, store });
|
|
160
|
+
return {
|
|
161
|
+
id: "admin",
|
|
162
|
+
name: config.labels.pageTitle,
|
|
163
|
+
icon: "LayoutTemplate",
|
|
164
|
+
version: "1.0.0",
|
|
165
|
+
scope: options?.scope ?? "universal",
|
|
166
|
+
verticalId: options?.verticalId,
|
|
167
|
+
// Shell/admin-config is a Panel-side concept (layout, module nav, branding
|
|
168
|
+
// for an admin app) — targets the saas/admin-template world, not the
|
|
169
|
+
// ecommerce storefront. Same declaration plugin-crm uses for its
|
|
170
|
+
// business-ops surface.
|
|
171
|
+
scaffolds: ["saas"],
|
|
172
|
+
defaultEnabled: true,
|
|
173
|
+
dependencies: [],
|
|
174
|
+
declaredFeatures: [
|
|
175
|
+
{ id: "admin", label: config.labels.pageTitle, group: config.labels.pageTitle }
|
|
176
|
+
],
|
|
177
|
+
navigation: [
|
|
178
|
+
{
|
|
179
|
+
section: "secondary",
|
|
180
|
+
position: 90,
|
|
181
|
+
label: config.labels.pageTitle,
|
|
182
|
+
route: "/admin",
|
|
183
|
+
icon: "LayoutTemplate",
|
|
184
|
+
permission: { feature: "admin", action: "read" }
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
routes: [
|
|
188
|
+
{
|
|
189
|
+
path: "/admin",
|
|
190
|
+
component: PageComponent,
|
|
191
|
+
permission: { feature: "admin", action: "read" }
|
|
192
|
+
}
|
|
193
|
+
],
|
|
194
|
+
widgets: [],
|
|
195
|
+
aiTools: [
|
|
196
|
+
{
|
|
197
|
+
id: "admin.get-shell-settings",
|
|
198
|
+
name: "getShellSettings",
|
|
199
|
+
description: "Returns the app shell configuration: layout variant, module nav style, mobile header treatment, and whether org/branding settings are shown.",
|
|
200
|
+
icon: "LayoutTemplate",
|
|
201
|
+
mode: "read",
|
|
202
|
+
category: "Admin",
|
|
203
|
+
parameters: {
|
|
204
|
+
type: "object",
|
|
205
|
+
properties: {}
|
|
206
|
+
},
|
|
207
|
+
suggestions: [
|
|
208
|
+
{ label: "What layout is this app using?" },
|
|
209
|
+
{ label: "Is branding customization on?" }
|
|
210
|
+
],
|
|
211
|
+
permission: { feature: "admin", action: "read" }
|
|
212
|
+
}
|
|
213
|
+
],
|
|
214
|
+
settings: [],
|
|
215
|
+
locales: adminLocales
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
exports.createAdminPlugin = createAdminPlugin;
|
|
220
|
+
//# sourceMappingURL=index.cjs.map
|
|
221
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/AdminContext.tsx","../src/AdminPage.tsx","../src/index.ts"],"names":["createStore","dedup","createPluginContext","jsxs","jsx","useTranslation","ModulePage","PanelTop","LayoutTemplate","Settings2","Smartphone","Palette","registerTranslations","createSafeDataProvider","React"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AdminDataProvider, AdminSettingsSnapshot } from './types'\n\n/**\n * Mock provider — returns the statically resolved shell-config snapshot\n * (from plugin options / FayzAppConfig defaults). No in-memory mutation:\n * this plugin doesn't write settings yet.\n */\nexport function createMockAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {\n return {\n async getSettings() {\n return snapshot\n },\n }\n}\n","import type { AdminDataProvider, AdminSettingsSnapshot } from './types'\n\n/**\n * Supabase provider — foundation stub. There is no shell-config table yet:\n * layout/moduleNav/mobileHeader/branding are still owned by FayzAppConfig at\n * build time, not a runtime-editable record. This provider exists so the\n * plugin follows the standard createSafeDataProvider(supabase, mock) seam\n * from day one; it returns the same static snapshot the mock provider does\n * until a real read/write path is wired (see README.md).\n */\nexport function createSupabaseAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {\n return {\n async getSettings() {\n return snapshot\n },\n }\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { dedup } from '@fayz-ai/saas'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\n\nexport interface AdminUIState {\n settings: AdminSettingsSnapshot | null\n settingsLoading: boolean\n\n fetchSettings(): Promise<void>\n}\n\nexport function createAdminStore(provider: AdminDataProvider): StoreApi<AdminUIState> {\n return createStore<AdminUIState>((set) => ({\n settings: null,\n settingsLoading: false,\n\n async fetchSettings() {\n return dedup('admin:settings', async () => {\n set({ settingsLoading: true })\n try {\n const settings = await provider.getSettings()\n set({ settings, settingsLoading: false })\n } catch {\n set({ settingsLoading: false })\n }\n })\n },\n }))\n}\n","export const en: Record<string, string> = {\n 'admin.layout.title': 'Layout',\n 'admin.layout.sidebar': 'Sidebar',\n 'admin.layout.topbar': 'Topbar',\n 'admin.layout.minimal': 'Minimal',\n 'admin.moduleNav.title': 'Module navigation',\n 'admin.moduleNav.rail': 'Side rail for the installed modules',\n 'admin.moduleNav.tabs': 'Tabs for the installed modules',\n 'admin.mobileHeader.title': 'Mobile header',\n 'admin.mobileHeader.minimal': 'Minimal header bar',\n 'admin.mobileHeader.transparent': 'Transparent, edge-to-edge content',\n 'admin.mobileHeader.hidden': 'Hidden',\n 'admin.branding.title': 'Branding',\n 'admin.branding.on': 'Org branding settings are visible to operators',\n 'admin.branding.off': 'Org branding settings are hidden',\n 'admin.readOnlyNotice': 'Read-only preview. Editing these settings here is coming soon — for now they are set in your app config.',\n}\n","export const ptBR: Record<string, string> = {\n 'admin.layout.title': 'Layout',\n 'admin.layout.sidebar': 'Barra lateral',\n 'admin.layout.topbar': 'Barra superior',\n 'admin.layout.minimal': 'Minimalista',\n 'admin.moduleNav.title': 'Navegação dos módulos',\n 'admin.moduleNav.rail': 'Barra lateral para os módulos instalados',\n 'admin.moduleNav.tabs': 'Abas para os módulos instalados',\n 'admin.mobileHeader.title': 'Cabeçalho mobile',\n 'admin.mobileHeader.minimal': 'Cabeçalho minimalista',\n 'admin.mobileHeader.transparent': 'Transparente, conteúdo de ponta a ponta',\n 'admin.mobileHeader.hidden': 'Oculto',\n 'admin.branding.title': 'Identidade visual',\n 'admin.branding.on': 'As configurações de marca estão visíveis para operadores',\n 'admin.branding.off': 'As configurações de marca estão ocultas',\n 'admin.readOnlyNotice': 'Pré-visualização somente leitura. A edição por aqui chega em breve — por enquanto essas opções são definidas na configuração do app.',\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const adminLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","import { createPluginContext } from '@fayz-ai/saas'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nimport type { AdminUIState } from './store'\n\n// ---------------------------------------------------------------------------\n// Config\n// ---------------------------------------------------------------------------\n\nexport interface AdminPluginLabels {\n pageTitle: string\n pageSubtitle: string\n}\n\n/** Resolved shell config + labels, handed to AdminPage. Mirrors AdminSettingsSnapshot. */\nexport interface ResolvedAdminConfig extends AdminSettingsSnapshot {\n labels: AdminPluginLabels\n}\n\nconst ctx = createPluginContext<ResolvedAdminConfig, AdminDataProvider, AdminUIState>('AdminPage')\n\nexport const AdminContextProvider = ctx.ContextProvider\nexport const useAdminConfig = ctx.useConfig\nexport const useAdminProvider = ctx.useProvider\nexport const useAdminStore = ctx.useStore\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { LayoutTemplate, PanelTop, Settings2, Smartphone, Palette } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { ModulePage } from '@fayz-ai/ui'\nimport { AdminContextProvider, type ResolvedAdminConfig } from './AdminContext'\nimport type { AdminDataProvider } from './data/types'\nimport type { AdminUIState } from './store'\n\nconst LAYOUT_VARIANTS = ['sidebar', 'topbar', 'minimal'] as const\n\nfunction SettingCard({ icon: Icon, title, children }: {\n icon: typeof LayoutTemplate\n title: string\n children: React.ReactNode\n}) {\n return (\n <div className=\"rounded-xl border border-border bg-background/60 p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <div className=\"h-8 w-8 rounded-lg bg-foreground/[0.04] flex items-center justify-center shrink-0\">\n <Icon className=\"h-4 w-4 text-muted-foreground\" />\n </div>\n <div className=\"text-sm font-medium\">{title}</div>\n </div>\n {children}\n </div>\n )\n}\n\n/**\n * Read-only foundation view. Renders the shell config this app already\n * resolved (layout, module nav, mobile header, branding) so an operator can\n * see it at a glance — it does not yet let them change it. See README.md for\n * the write-path this is scaffolding toward.\n */\nexport function AdminPage({ config, provider, store }: {\n config: ResolvedAdminConfig\n provider: AdminDataProvider\n store: StoreApi<AdminUIState>\n}) {\n const t = useTranslation()\n\n return (\n <AdminContextProvider config={config} provider={provider} store={store}>\n <ModulePage title={config.labels.pageTitle} subtitle={config.labels.pageSubtitle} nav={[]}>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <SettingCard icon={config.layout === 'topbar' ? PanelTop : LayoutTemplate} title={t('admin.layout.title')}>\n <div className=\"flex flex-wrap gap-2 text-sm\">\n {LAYOUT_VARIANTS.map((variant) => (\n <span\n key={variant}\n className={\n 'rounded-md border px-2.5 py-1.5 ' +\n (config.layout === variant\n ? 'border-primary/40 bg-primary/5 text-foreground'\n : 'border-border text-muted-foreground')\n }\n >\n {t(`admin.layout.${variant}`)}\n </span>\n ))}\n </div>\n </SettingCard>\n\n <SettingCard icon={Settings2} title={t('admin.moduleNav.title')}>\n <p className=\"text-xs text-muted-foreground\">{t(`admin.moduleNav.${config.moduleNav}`)}</p>\n </SettingCard>\n\n <SettingCard icon={Smartphone} title={t('admin.mobileHeader.title')}>\n <p className=\"text-xs text-muted-foreground\">{t(`admin.mobileHeader.${config.mobileHeader}`)}</p>\n </SettingCard>\n\n <SettingCard icon={Palette} title={t('admin.branding.title')}>\n <p className=\"text-xs text-muted-foreground\">\n {config.branding ? t('admin.branding.on') : t('admin.branding.off')}\n </p>\n </SettingCard>\n </div>\n\n <p className=\"mt-6 text-xs text-muted-foreground\">{t('admin.readOnlyNotice')}</p>\n </ModulePage>\n </AdminContextProvider>\n )\n}\n","import React from 'react'\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'\nimport type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nimport type { AdminPluginOptions } from './types'\nimport { createMockAdminProvider } from './data/mock'\nimport { createSupabaseAdminProvider } from './data/supabase'\nimport { createAdminStore } from './store'\nimport { adminLocales } from './locales'\nimport { AdminPage } from './AdminPage'\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: AdminPluginLabels = {\n pageTitle: 'Admin',\n pageSubtitle: \"Your app's layout, navigation, and branding.\",\n}\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nfunction resolveConfig(options?: AdminPluginOptions): ResolvedAdminConfig {\n return {\n labels: DEFAULT_LABELS,\n layout: options?.layout ?? 'sidebar',\n moduleNav: options?.moduleNav ?? 'tabs',\n mobileHeader: options?.mobileHeader ?? 'minimal',\n navTransition: options?.navTransition ?? 'slide',\n orgSettings: options?.orgSettings ?? true,\n branding: options?.branding ?? true,\n }\n}\n\nfunction toSnapshot(config: ResolvedAdminConfig): AdminSettingsSnapshot {\n const { labels: _labels, ...snapshot } = config\n return snapshot\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createAdminPlugin(options?: AdminPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n // Register locales globally so the plugin's translations resolve even when the\n // host shell does not mount @fayz-ai/core's I18nProvider (incremental de-bridge).\n registerTranslations(adminLocales)\n const snapshot = toSnapshot(config)\n const provider = options?.dataProvider ?? createSafeDataProvider(\n () => createSupabaseAdminProvider(snapshot),\n () => createMockAdminProvider(snapshot),\n )\n const store = createAdminStore(provider)\n\n const PageComponent: React.FC<unknown> = () =>\n React.createElement(AdminPage, { config, provider, store })\n\n return {\n id: 'admin',\n name: config.labels.pageTitle,\n icon: 'LayoutTemplate',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n // Shell/admin-config is a Panel-side concept (layout, module nav, branding\n // for an admin app) — targets the saas/admin-template world, not the\n // ecommerce storefront. Same declaration plugin-crm uses for its\n // business-ops surface.\n scaffolds: ['saas'],\n defaultEnabled: true,\n dependencies: [],\n declaredFeatures: [\n { id: 'admin', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ],\n\n navigation: [\n {\n section: 'secondary',\n position: 90,\n label: config.labels.pageTitle,\n route: '/admin',\n icon: 'LayoutTemplate',\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n routes: [\n {\n path: '/admin',\n component: PageComponent as unknown as React.ComponentType<unknown>,\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n widgets: [],\n\n aiTools: [\n {\n id: 'admin.get-shell-settings',\n name: 'getShellSettings',\n description: 'Returns the app shell configuration: layout variant, module nav style, mobile header treatment, and whether org/branding settings are shown.',\n icon: 'LayoutTemplate',\n mode: 'read' as const,\n category: 'Admin',\n parameters: {\n type: 'object' as const,\n properties: {},\n },\n suggestions: [\n { label: 'What layout is this app using?' },\n { label: 'Is branding customization on?' },\n ],\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n settings: [],\n\n locales: adminLocales,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nexport type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext'\nexport type { AdminPluginOptions } from './types'\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PluginManifest } from '@fayz-ai/core';
|
|
2
|
+
import type { AdminPluginOptions } from './types';
|
|
3
|
+
export declare function createAdminPlugin(options?: AdminPluginOptions): PluginManifest;
|
|
4
|
+
export type { AdminDataProvider, AdminSettingsSnapshot } from './data/types';
|
|
5
|
+
export type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext';
|
|
6
|
+
export type { AdminPluginOptions } from './types';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAInD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAyCjD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,cAAc,CA8E9E;AAMD,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAC5E,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA"}
|