@jini-ai/admin 0.4.12 → 0.4.13
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/CHANGELOG.md +4 -0
- package/dist/agent-plugins/controllers/agent-plugin-files.controller.js +14 -9
- package/dist/agent-plugins/controllers/agent-plugins.controller.js +12 -9
- package/dist/agent-plugins/package-file-tree.js +54 -51
- package/dist/agent-plugins/react/components/AgentPluginRow.d.ts +1 -1
- package/dist/agent-plugins/react/components/AgentPluginRow.js +9 -2
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.d.ts +5 -5
- package/dist/agent-plugins/react/hooks/AgentPluginInspector.hooks.js +14 -5
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.d.ts +15 -13
- package/dist/agent-plugins/react/hooks/AgentPluginPanel.hooks.js +54 -40
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.d.ts +13 -13
- package/dist/agent-plugins/react/hooks/AgentPluginsPage.hooks.js +23 -11
- package/dist/browser/navigation.js +44 -27
- package/dist/comments/adapters/memory.js +30 -12
- package/dist/comments/conformance/comments-api.conformance.js +55 -33
- package/dist/comments/controllers/comment-queue.controller.js +13 -4
- package/dist/comments/react/hooks/use-comment-queue.hooks.d.ts +17 -2
- package/dist/comments/react/hooks/use-comment-queue.hooks.js +79 -30
- package/dist/comments/react/hooks/use-comment-settings.hooks.js +9 -5
- package/dist/comments/react/index.d.ts +2 -1
- package/dist/comments/react/index.js +1 -1
- package/dist/consent/react/ConsentFields.d.ts +35 -0
- package/dist/consent/react/ConsentFields.js +74 -0
- package/dist/consent/react/ConsentPreviewFrame.d.ts +14 -0
- package/dist/consent/react/ConsentPreviewFrame.js +14 -0
- package/dist/consent/react/ConsentSettingsPanel.d.ts +27 -4
- package/dist/consent/react/ConsentSettingsPanel.js +6 -17
- package/dist/consent/react/index.d.ts +6 -1
- package/dist/consent/react/index.js +2 -0
- package/dist/consent/react/settings-panel.hooks.d.ts +28 -1
- package/dist/consent/react/settings-panel.hooks.js +26 -0
- package/dist/core/entities/rules.js +126 -81
- package/dist/core/manifest/rules.js +10 -10
- package/dist/core/module/create-admin.js +195 -117
- package/dist/core/ports/redirects.d.ts +8 -6
- package/dist/core/ports/redirects.js +8 -6
- package/dist/core/routing/rules.js +9 -4
- package/dist/core/transport/http.js +37 -20
- package/dist/forms/adapters/memory.js +22 -11
- package/dist/forms/conformance/forms-api.conformance.d.ts +6 -4
- package/dist/forms/conformance/forms-api.conformance.js +42 -46
- package/dist/forms/field-settings.js +150 -115
- package/dist/forms/html-rules.js +45 -28
- package/dist/forms/react/components/FieldSettingsRows.d.ts +22 -0
- package/dist/forms/react/components/FieldSettingsRows.js +29 -0
- package/dist/forms/react/components/FieldSettingsSection.d.ts +1 -1
- package/dist/forms/react/components/FieldSettingsSection.js +5 -6
- package/dist/forms/react/components/FormEditorFieldsBody.d.ts +1 -1
- package/dist/forms/react/components/FormEditorFieldsBody.js +4 -15
- package/dist/forms/react/components/FormEditorFieldsBodyParts.d.ts +18 -0
- package/dist/forms/react/components/FormEditorFieldsBodyParts.js +32 -0
- package/dist/forms/react/components/FormSubmissions.d.ts +1 -1
- package/dist/forms/react/components/FormSubmissions.js +4 -20
- package/dist/forms/react/components/FormSubmissionsTable.d.ts +19 -0
- package/dist/forms/react/components/FormSubmissionsTable.js +22 -0
- package/dist/media/adapters/memory.js +31 -26
- package/dist/media/controllers/edit-media.controller.js +2 -1
- package/dist/media/controllers/library.controller.js +48 -35
- package/dist/media/controllers/providers.controller.js +2 -1
- package/dist/media/html-attributes.js +29 -15
- package/dist/media/index.d.ts +1 -1
- package/dist/media/index.js +1 -1
- package/dist/media/react/components/MediaIcons.d.ts +0 -3
- package/dist/media/react/components/MediaIcons.js +0 -9
- package/dist/media/react/components/MediaLightbox.d.ts +2 -1
- package/dist/media/react/components/MediaLightbox.js +11 -5
- package/dist/media/react/hooks/LibraryTab.hooks.d.ts +55 -45
- package/dist/media/react/hooks/LibraryTab.hooks.js +107 -70
- package/dist/media/react/hooks/MediaCard.hooks.d.ts +27 -31
- package/dist/media/react/hooks/MediaCard.hooks.js +52 -26
- package/dist/media/react/hooks/MediaGrid.hooks.d.ts +1 -1
- package/dist/media/react/hooks/MediaLightbox.hooks.d.ts +10 -14
- package/dist/media/react/hooks/MediaLightbox.hooks.js +9 -56
- package/dist/media/react/hooks/MediaPage.hooks.d.ts +6 -0
- package/dist/media/react/hooks/MediaPage.hooks.js +29 -12
- package/dist/media/react/hooks/ProvidersTab.hooks.d.ts +33 -33
- package/dist/media/react/hooks/ProvidersTab.hooks.js +119 -79
- package/dist/media/react/hooks/UploadButton.hooks.d.ts +7 -5
- package/dist/media/react/hooks/UploadButton.hooks.js +36 -24
- package/dist/media/react/index.js +4 -0
- package/dist/media/react/tabs/LibraryTab.d.ts +1 -1
- package/dist/media/react/tabs/LibraryTab.js +2 -2
- package/dist/media/rules.d.ts +7 -0
- package/dist/media/rules.js +25 -2
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js +5 -8
- package/dist/react/components/ConfirmDialog/confirm-dialog-attrs.d.ts +20 -0
- package/dist/react/components/ConfirmDialog/confirm-dialog-attrs.js +24 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +16 -7
- package/dist/react/components/RowMenu/RowMenu.js +16 -10
- package/dist/react/components/Sidebar.js +32 -26
- package/dist/react/entities/EntityEdit.js +17 -14
- package/dist/react/entities/EntityField.d.ts +5 -2
- package/dist/react/entities/EntityField.js +38 -23
- package/dist/react/entities/EntityList.js +6 -5
- package/dist/react/entities/RelationTruncationNotice.d.ts +9 -0
- package/dist/react/entities/RelationTruncationNotice.js +9 -0
- package/dist/react/entities/use-entity-edit.d.ts +4 -2
- package/dist/react/entities/use-entity-edit.js +52 -33
- package/dist/react/shell/AdminShell.js +40 -23
- package/dist/react/shell/model.d.ts +4 -1
- package/dist/react/shell/model.js +3 -2
- package/dist/react/shell/use-admin-shell-session.js +25 -26
- package/dist/redirects/adapters/memory.js +9 -2
- package/dist/redirects/conformance/redirects-api.conformance.js +66 -36
- package/dist/redirects/react/hooks/use-import-redirects-form.hooks.d.ts +1 -1
- package/dist/redirects/react/hooks/use-import-redirects-form.hooks.js +10 -3
- package/dist/redirects/react/hooks/wired.hooks.d.ts +1 -1
- package/dist/security/adapters/http.js +25 -10
- package/dist/security/adapters/memory.js +19 -5
- package/dist/security/controllers/access-tokens.controller.js +27 -26
- package/dist/security/controllers/other-credentials.controller.js +4 -2
- package/dist/security/controllers/root-key.controller.js +17 -9
- package/dist/security/react/hooks/AccessTokensTab.hooks.d.ts +40 -38
- package/dist/security/react/hooks/AccessTokensTab.hooks.js +36 -9
- package/dist/security/react/hooks/RootKeyTab.hooks.d.ts +14 -14
- package/dist/security/react/hooks/RootKeyTab.hooks.js +12 -3
- package/dist/security/react/tabs/RootKeyTab.d.ts +1 -1
- package/dist/security/react/tabs/RootKeyTab.js +12 -3
- package/dist/security/rules.js +45 -25
- package/dist/seo/controllers/seo.controller.js +4 -2
- package/dist/seo/react/components/MediaRefField.d.ts +1 -1
- package/dist/seo/react/components/MediaRefField.js +19 -2
- package/dist/seo/react/hooks/MediaRefField.hooks.js +3 -1
- package/dist/seo/react/hooks/SeoPage.hooks.d.ts +1 -1
- package/dist/seo/react/hooks/use-share-image-warning.hooks.js +48 -34
- package/dist/seo/react/pages/SeoPage.d.ts +4 -4
- package/dist/seo/react/pages/SeoPage.js +26 -6
- package/dist/seo/rules.js +39 -10
- package/dist/source-control/conformance/source-control-api.conformance.js +68 -38
- package/dist/source-control/controllers/source-control.controller.js +20 -8
- package/dist/source-control/react/hooks/ProvidersTab.hooks.d.ts +2 -1
- package/dist/source-control/react/hooks/ProvidersTab.hooks.js +18 -11
- package/dist/widgets/conformance/widgets-api.conformance.js +15 -1
- package/dist/widgets/controllers/instance-editor.controller.js +33 -24
- package/dist/widgets/controllers/library.controller.js +18 -12
- package/dist/widgets/controllers/region-editor.controller.js +6 -5
- package/dist/widgets/react/hooks/page-views.hooks.d.ts +1 -0
- package/dist/widgets/react/hooks/page-views.hooks.js +3 -2
- package/dist/widgets/react/hooks/use-widget-regions.hooks.d.ts +1 -1
- package/dist/widgets/react/hooks/use-widget-regions.hooks.js +9 -3
- package/dist/widgets/react/hooks/use-widgets-library.hooks.js +9 -2
- package/dist/widgets/react/pages/WidgetInstanceEditor.d.ts +1 -1
- package/dist/widgets/react/pages/WidgetInstanceEditor.js +7 -8
- package/dist/widgets/rules.d.ts +14 -2
- package/dist/widgets/rules.js +9 -6
- package/package.json +17 -8
- package/src/themes/default/admin.css +51 -0
- package/src/themes/default/chat.css +21 -0
- package/src/themes/default/manifest.json +29 -0
- package/dist/media/styles.d.ts +0 -4
- package/dist/media/styles.js +0 -5
|
@@ -9,6 +9,14 @@ export async function runWidgetsApiConformance({ api }, _optional = {}) {
|
|
|
9
9
|
catch {
|
|
10
10
|
rejected = true;
|
|
11
11
|
} assert(rejected, name); }
|
|
12
|
+
const probe = { api, assert, rejects };
|
|
13
|
+
const { widget, updated } = await checkInstanceLifecycle({ probe });
|
|
14
|
+
await checkRegionPlacements({ probe, widget, updated });
|
|
15
|
+
await checkAbortsAndMissing({ probe, widget, updated });
|
|
16
|
+
await checkTrash({ probe, widget });
|
|
17
|
+
return checks;
|
|
18
|
+
}
|
|
19
|
+
async function checkInstanceLifecycle({ probe: { api, assert, rejects } }, _optional = {}) {
|
|
12
20
|
const input = { widgetType: 'text', title: 'Conformance widget', config: { body: 'initial' } };
|
|
13
21
|
const { widget } = await api.createWidget(input);
|
|
14
22
|
assert(widget.id.length > 0 && widget.slug.length > 0 && widget.status === 'active', 'create active instance');
|
|
@@ -22,6 +30,9 @@ export async function runWidgetsApiConformance({ api }, _optional = {}) {
|
|
|
22
30
|
assert(updated.title === widget.title && updated.version > widget.version, 'omitted title preserved and version advances');
|
|
23
31
|
assert(widget.config.body === 'initial' && firstList.widgets.find(w => w.id === widget.id)?.version === widget.version, 'prior snapshots stay detached');
|
|
24
32
|
await rejects(() => api.updateWidget({ id: widget.id, baseVersion: widget.version, config: {} }), 'stale instance write rejects');
|
|
33
|
+
return { widget, updated };
|
|
34
|
+
}
|
|
35
|
+
async function checkRegionPlacements({ probe: { api, assert, rejects }, widget, updated }, _optional = {}) {
|
|
25
36
|
const regionKey = `conformance-${widget.id}`;
|
|
26
37
|
const { area } = await api.bindWidgetRegion({ regionKey });
|
|
27
38
|
const initialAreaVersion = area.version;
|
|
@@ -40,6 +51,8 @@ export async function runWidgetsApiConformance({ api }, _optional = {}) {
|
|
|
40
51
|
assert(placed.placements[2]?.broken === true, 'broken reference remains visible');
|
|
41
52
|
assert((await api.listWidgetRegions({})).regions.find(r => r.regionKey === regionKey)?.placementCount === placements.length, 'region list placement count updates');
|
|
42
53
|
await rejects(() => api.mutateWidgetRegionPlacements({ regionKey, baseVersion: area.version, placements: [] }), 'stale region write rejects');
|
|
54
|
+
}
|
|
55
|
+
async function checkAbortsAndMissing({ probe: { api, assert, rejects }, widget, updated }, _optional = {}) {
|
|
43
56
|
const abort = new AbortController();
|
|
44
57
|
abort.abort();
|
|
45
58
|
await rejects(() => api.listWidgets({}, { signal: abort.signal }), 'aborted list rejects');
|
|
@@ -47,9 +60,10 @@ export async function runWidgetsApiConformance({ api }, _optional = {}) {
|
|
|
47
60
|
assert((await api.getWidget({ id: widget.id })).widget.title === widget.title, 'aborted write has no effects');
|
|
48
61
|
await rejects(() => api.getWidget({ id: 'missing-conformance-widget' }), 'missing instance rejects');
|
|
49
62
|
await rejects(() => api.getWidgetRegion({ regionKey: 'missing-conformance-region' }), 'missing region rejects');
|
|
63
|
+
}
|
|
64
|
+
async function checkTrash({ probe: { api, assert }, widget }, _optional = {}) {
|
|
50
65
|
await api.trashWidget({ id: widget.id });
|
|
51
66
|
assert(!(await api.listWidgets({})).widgets.some(w => w.id === widget.id), 'trash removes active listing');
|
|
52
67
|
assert((await api.listWidgets({ includeInactive: true })).widgets.find(w => w.id === widget.id)?.status === 'trash', 'trash retained for shared lifecycle');
|
|
53
|
-
return checks;
|
|
54
68
|
}
|
|
55
69
|
//# sourceMappingURL=widgets-api.conformance.js.map
|
|
@@ -14,6 +14,8 @@ export function createWidgetInstanceEditorController({ api, params: initialParam
|
|
|
14
14
|
config: isNew ? defaultConfig(params.widgetType ?? 'text') : {}, message: null, error: null, fieldErrors: [],
|
|
15
15
|
loading: !isNew, saving: false, widgetType: resolveEditorWidgetType({ isNew, queryWidgetType: params.widgetType, widget: null }),
|
|
16
16
|
} });
|
|
17
|
+
const isLiveLoad = ({ ticket }) => ticket === generation && !store.signal.aborted;
|
|
18
|
+
const isLiveSave = ({ savingFor }) => currentKey() === savingFor && !store.signal.aborted;
|
|
17
19
|
async function load(_required = {}, _optional = {}) {
|
|
18
20
|
const ticket = ++generation;
|
|
19
21
|
const isNew = params.widgetId === null;
|
|
@@ -22,27 +24,31 @@ export function createWidgetInstanceEditorController({ api, params: initialParam
|
|
|
22
24
|
store.set({ patch: { widget: null, title: '', config: defaultConfig(params.widgetType ?? 'text'), whereUsed: { count: 0, references: [] }, loading: false, widgetType: params.widgetType } });
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
|
-
|
|
27
|
+
await loadExisting({ ticket, requestedId: params.widgetId });
|
|
28
|
+
}
|
|
29
|
+
async function loadExisting({ ticket, requestedId }, _optional = {}) {
|
|
26
30
|
store.set({ patch: { loading: true, error: null } });
|
|
27
31
|
try {
|
|
28
32
|
const result = await api.getWidget({ id: requestedId }, { signal: store.signal });
|
|
29
|
-
if (ticket
|
|
30
|
-
|
|
31
|
-
store.set({ patch: { widget: result.widget, title: result.widget.title, config: result.widget.config, whereUsed: result.whereUsed, widgetType: result.widget.widgetType } });
|
|
32
|
-
// Replace rather than push: an old id bookmark should not add a Back-button stop.
|
|
33
|
-
const redirect = widgetSlugRedirectPath({ requestedId, widget: result.widget }, { slugRedirectPath });
|
|
34
|
-
if (redirect)
|
|
35
|
-
navigate?.(redirect, { replace: true });
|
|
33
|
+
if (isLiveLoad({ ticket }))
|
|
34
|
+
applyLoaded({ requestedId, result });
|
|
36
35
|
}
|
|
37
36
|
catch (error) {
|
|
38
|
-
if (ticket
|
|
37
|
+
if (isLiveLoad({ ticket }))
|
|
39
38
|
store.set({ patch: { error: describeApiError({ e: widgetApiError({ error }) ?? error, fallback: t('failed to load widget') }) } });
|
|
40
39
|
}
|
|
41
40
|
finally {
|
|
42
|
-
if (ticket
|
|
41
|
+
if (isLiveLoad({ ticket }))
|
|
43
42
|
store.set({ patch: { loading: false } });
|
|
44
43
|
}
|
|
45
44
|
}
|
|
45
|
+
function applyLoaded({ requestedId, result }, _optional = {}) {
|
|
46
|
+
store.set({ patch: { widget: result.widget, title: result.widget.title, config: result.widget.config, whereUsed: result.whereUsed, widgetType: result.widget.widgetType } });
|
|
47
|
+
// Replace rather than push: an old id bookmark should not add a Back-button stop.
|
|
48
|
+
const redirect = widgetSlugRedirectPath({ requestedId, widget: result.widget }, { slugRedirectPath });
|
|
49
|
+
if (redirect)
|
|
50
|
+
navigate?.(redirect, { replace: true });
|
|
51
|
+
}
|
|
46
52
|
async function save(_required = {}, _optional = {}) {
|
|
47
53
|
const { widgetType, isNew, widget, title, config } = store.getSnapshot();
|
|
48
54
|
if (!widgetType)
|
|
@@ -50,28 +56,31 @@ export function createWidgetInstanceEditorController({ api, params: initialParam
|
|
|
50
56
|
const savingFor = currentKey();
|
|
51
57
|
store.set({ patch: { saving: true, message: null, error: null, fieldErrors: [] } });
|
|
52
58
|
try {
|
|
53
|
-
if (isNew)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
if (!widget)
|
|
60
|
-
return;
|
|
61
|
-
const { widget: saved } = await api.updateWidget({ id: widget.id, baseVersion: widget.version, title, config }, { signal: store.signal });
|
|
62
|
-
if (currentKey() !== savingFor || store.signal.aborted)
|
|
63
|
-
return;
|
|
64
|
-
store.set({ patch: { widget: saved, title: saved.title, config: saved.config, widgetType: saved.widgetType, message: t('Saved · version {version}').replace('{version}', String(saved.version)) } });
|
|
59
|
+
if (isNew)
|
|
60
|
+
await createAndOpen({ widgetType, title, config });
|
|
61
|
+
else if (widget)
|
|
62
|
+
await updateExisting({ widget, title, config, savingFor });
|
|
65
63
|
}
|
|
66
64
|
catch (error) {
|
|
67
|
-
if (
|
|
65
|
+
if (isLiveSave({ savingFor }))
|
|
68
66
|
store.set({ patch: resolveWidgetSaveError({ error }, { t }) });
|
|
69
67
|
}
|
|
70
68
|
finally {
|
|
71
|
-
if (
|
|
69
|
+
if (isLiveSave({ savingFor }))
|
|
72
70
|
store.set({ patch: { saving: false } });
|
|
73
71
|
}
|
|
74
72
|
}
|
|
73
|
+
async function createAndOpen({ widgetType, title, config }, _optional = {}) {
|
|
74
|
+
const { widget: created } = await api.createWidget({ widgetType, title, config }, { signal: store.signal });
|
|
75
|
+
// Creation intentionally navigates even if route identity changed while it was in flight.
|
|
76
|
+
navigate?.(`/widgets/${created.slug}`);
|
|
77
|
+
}
|
|
78
|
+
async function updateExisting({ widget, title, config, savingFor }, _optional = {}) {
|
|
79
|
+
const { widget: saved } = await api.updateWidget({ id: widget.id, baseVersion: widget.version, title, config }, { signal: store.signal });
|
|
80
|
+
if (!isLiveSave({ savingFor }))
|
|
81
|
+
return;
|
|
82
|
+
store.set({ patch: { widget: saved, title: saved.title, config: saved.config, widgetType: saved.widgetType, message: t('Saved · version {version}').replace('{version}', String(saved.version)) } });
|
|
83
|
+
}
|
|
75
84
|
return {
|
|
76
85
|
getSnapshot: store.getSnapshot, subscribe: store.subscribe, load, save,
|
|
77
86
|
setParams({ params: next }, _optional = {}) {
|
|
@@ -6,17 +6,17 @@ import { widgetsEnglish } from '../messages.en.js';
|
|
|
6
6
|
export function createWidgetsLibraryController({ api }, { t = widgetsEnglish } = {}) {
|
|
7
7
|
const store = createControllerStore({ initial: { widgets: null, error: null, skippedCount: 0, skippedIds: [], createType: 'text', pendingTrash: null, trashingId: null } });
|
|
8
8
|
let generation = 0;
|
|
9
|
+
const isLiveRead = ({ ticket }) => ticket === generation && !store.signal.aborted;
|
|
9
10
|
async function load(_required = {}, _optional = {}) {
|
|
10
11
|
const ticket = ++generation;
|
|
11
12
|
try {
|
|
12
13
|
// No includeInactive: trashed widgets belong to the shared Trash screen.
|
|
13
14
|
const result = await api.listWidgets({}, { signal: store.signal });
|
|
14
|
-
if (ticket
|
|
15
|
-
|
|
16
|
-
store.set({ patch: { widgets: result.widgets, skippedCount: result.skippedCount ?? 0, skippedIds: result.skippedIds ?? [] } });
|
|
15
|
+
if (isLiveRead({ ticket }))
|
|
16
|
+
store.set({ patch: { widgets: result.widgets, skippedCount: result.skippedCount ?? 0, skippedIds: result.skippedIds ?? [] } });
|
|
17
17
|
}
|
|
18
18
|
catch (e) {
|
|
19
|
-
if (ticket
|
|
19
|
+
if (isLiveRead({ ticket }))
|
|
20
20
|
store.set({ patch: { error: describeApiError({ e: widgetApiError({ error: e }) ?? e, fallback: t('failed to load widgets') }) } });
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -30,18 +30,24 @@ export function createWidgetsLibraryController({ api }, { t = widgetsEnglish } =
|
|
|
30
30
|
void load();
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
|
-
|
|
34
|
-
if (e?.code === 'NOT_FOUND')
|
|
35
|
-
void load();
|
|
36
|
-
else
|
|
37
|
-
store.set({ patch: { error: e?.code === 'TRASH_VERSION_CHANGED' ? t('This item changed since you loaded it. Reload and try again.') : describeApiError({ e: e ?? error, fallback: t('delete failed') }) } });
|
|
33
|
+
handleTrashFailure({ error });
|
|
38
34
|
}
|
|
39
35
|
finally {
|
|
40
|
-
|
|
41
|
-
const current = store.getSnapshot();
|
|
42
|
-
store.set({ patch: { trashingId: current.trashingId === widget.id ? null : current.trashingId, pendingTrash: current.pendingTrash?.id === widget.id ? null : current.pendingTrash } });
|
|
36
|
+
settleTrash({ widget });
|
|
43
37
|
}
|
|
44
38
|
}
|
|
39
|
+
function handleTrashFailure({ error }, _optional = {}) {
|
|
40
|
+
const e = widgetApiError({ error });
|
|
41
|
+
if (e?.code === 'NOT_FOUND')
|
|
42
|
+
void load();
|
|
43
|
+
else
|
|
44
|
+
store.set({ patch: { error: e?.code === 'TRASH_VERSION_CHANGED' ? t('This item changed since you loaded it. Reload and try again.') : describeApiError({ e: e ?? error, fallback: t('delete failed') }) } });
|
|
45
|
+
}
|
|
46
|
+
function settleTrash({ widget }, _optional = {}) {
|
|
47
|
+
// A's completion cannot close a newly opened confirmation for B.
|
|
48
|
+
const current = store.getSnapshot();
|
|
49
|
+
store.set({ patch: { trashingId: current.trashingId === widget.id ? null : current.trashingId, pendingTrash: current.pendingTrash?.id === widget.id ? null : current.pendingTrash } });
|
|
50
|
+
}
|
|
45
51
|
return {
|
|
46
52
|
getSnapshot: store.getSnapshot, subscribe: store.subscribe, load, confirmTrash,
|
|
47
53
|
setCreateType({ type }, _optional = {}) { store.set({ patch: { createType: type } }); },
|
|
@@ -6,20 +6,21 @@ import { widgetsEnglish } from '../messages.en.js';
|
|
|
6
6
|
export function createWidgetRegionEditorController({ api, regionKey: initialKey }, { t = widgetsEnglish } = {}) {
|
|
7
7
|
const store = createControllerStore({ initial: { area: null, placements: [], message: null, error: null, loading: true, saving: false } });
|
|
8
8
|
let regionKey = initialKey, generation = 0;
|
|
9
|
+
const isLiveRead = ({ ticket }) => ticket === generation && !store.signal.aborted;
|
|
9
10
|
async function load(_required = {}, _optional = {}) {
|
|
10
11
|
const ticket = ++generation;
|
|
11
12
|
store.set({ patch: { loading: true, error: null, saving: false } });
|
|
12
13
|
try {
|
|
13
14
|
const result = await api.getWidgetRegion({ regionKey }, { signal: store.signal });
|
|
14
|
-
if (ticket
|
|
15
|
+
if (isLiveRead({ ticket }))
|
|
15
16
|
store.set({ patch: { area: result.area, placements: result.placements } });
|
|
16
17
|
}
|
|
17
18
|
catch (error) {
|
|
18
|
-
if (ticket
|
|
19
|
+
if (isLiveRead({ ticket }))
|
|
19
20
|
store.set({ patch: { error: describeApiError({ e: widgetApiError({ error }) ?? error, fallback: t('failed to load region') }) } });
|
|
20
21
|
}
|
|
21
22
|
finally {
|
|
22
|
-
if (ticket
|
|
23
|
+
if (isLiveRead({ ticket }))
|
|
23
24
|
store.set({ patch: { loading: false } });
|
|
24
25
|
}
|
|
25
26
|
}
|
|
@@ -40,7 +41,7 @@ export function createWidgetRegionEditorController({ api, regionKey: initialKey
|
|
|
40
41
|
let stale = false;
|
|
41
42
|
try {
|
|
42
43
|
const { area: saved } = await api.mutateWidgetRegionPlacements({ regionKey, baseVersion: area.version, placements: placements.map(p => ({ placementId: p.placementId, widgetEntryId: p.widgetEntryId, enabled: p.enabled })) }, { signal: store.signal });
|
|
43
|
-
stale = ticket
|
|
44
|
+
stale = !isLiveRead({ ticket });
|
|
44
45
|
if (stale)
|
|
45
46
|
return;
|
|
46
47
|
store.set({ patch: { area: saved, message: t('Saved · version {version}').replace('{version}', String(saved.version)) } });
|
|
@@ -48,7 +49,7 @@ export function createWidgetRegionEditorController({ api, regionKey: initialKey
|
|
|
48
49
|
void load();
|
|
49
50
|
}
|
|
50
51
|
catch (error) {
|
|
51
|
-
stale = ticket
|
|
52
|
+
stale = !isLiveRead({ ticket });
|
|
52
53
|
if (!stale)
|
|
53
54
|
store.set({ patch: { error: resolveWidgetRegionSaveError({ error }, { t }) } });
|
|
54
55
|
}
|
|
@@ -61,6 +61,7 @@ export declare function useWidgetInstanceEditorView({ widgetId, widgetType, widg
|
|
|
61
61
|
widgetTypes: readonly WidgetTypeOption[];
|
|
62
62
|
useWidgetInstanceEditorHook?: typeof useWiredWidgetInstanceEditor | undefined;
|
|
63
63
|
}, _optional?: Record<string, never>): {
|
|
64
|
+
gate: import("../../rules.js").WidgetEditorGate;
|
|
64
65
|
guard: import("../../rules.js").WidgetInstanceGuard | null;
|
|
65
66
|
onBackClick: (event: MouseEvent<HTMLAnchorElement>) => void;
|
|
66
67
|
isNew: boolean;
|
|
@@ -19,12 +19,13 @@ export function useWidgetRegionEditorView({ regionKey, useWidgetRegionEditorHook
|
|
|
19
19
|
const state = useWidgetRegionEditorHook(regionKey);
|
|
20
20
|
return { ...state, placementHandles: buildAgentListHandles({ prefix: 'widget-region-placement', ids: state.placements.map(p => p.placementId) }) };
|
|
21
21
|
}
|
|
22
|
-
import {
|
|
22
|
+
import { widgetEditorGate } from '../../rules.js';
|
|
23
23
|
import { useWiredWidgetInstanceEditor } from './use-widget-instance-editor.hooks.js';
|
|
24
24
|
/** The back-link cancellation also stops the host's document-level internal-link interceptor. */
|
|
25
25
|
export function useWidgetInstanceEditorView({ widgetId, widgetType, widgetTypes, useWidgetInstanceEditorHook = useWiredWidgetInstanceEditor }, _optional = {}) {
|
|
26
26
|
const state = useWidgetInstanceEditorHook({ widgetId, widgetType });
|
|
27
|
-
|
|
27
|
+
const gate = widgetEditorGate({ ...state, types: widgetTypes });
|
|
28
|
+
return { ...state, gate, guard: gate.guard, onBackClick: (event) => { if (!state.confirmLeave())
|
|
28
29
|
event.preventDefault(); } };
|
|
29
30
|
}
|
|
30
31
|
//# sourceMappingURL=page-views.hooks.js.map
|
|
@@ -13,7 +13,7 @@ export interface WidgetRegionsController {
|
|
|
13
13
|
import type { AdminWidgetsPort, WidgetsEventsPort } from '../../ports.js';
|
|
14
14
|
export declare function useWidgetRegions({ api }: {
|
|
15
15
|
api: AdminWidgetsPort;
|
|
16
|
-
}, { t,
|
|
16
|
+
}, { t, events, navigate }?: {
|
|
17
17
|
t?: Translate | undefined;
|
|
18
18
|
locale?: string | undefined;
|
|
19
19
|
events?: WidgetsEventsPort | undefined;
|
|
@@ -6,7 +6,8 @@ import { createWidgetRegionsController } from '../../controllers/regions.control
|
|
|
6
6
|
import { widgetsEnglish } from '../../messages.en.js';
|
|
7
7
|
import { WIDGETS_REGIONS_RESOURCE } from '../../rules.js';
|
|
8
8
|
import { useWidgetsPorts, useWidgetsOptions } from './WidgetsPorts.hooks.js';
|
|
9
|
-
|
|
9
|
+
import { useWidgetsNavigate } from './navigation.hooks.js';
|
|
10
|
+
export function useWidgetRegions({ api }, { t = widgetsEnglish, events, navigate } = {}) {
|
|
10
11
|
const cached = useWidgetRegionsQuery({ api });
|
|
11
12
|
const invalidate = useInvalidate();
|
|
12
13
|
const latest = useRef({ t, navigate });
|
|
@@ -14,7 +15,13 @@ export function useWidgetRegions({ api }, { t = widgetsEnglish, locale = 'en', e
|
|
|
14
15
|
const { controller, snapshot } = useController({ create: () => createWidgetRegionsController({ api: cached.api }, { t: key => latest.current.t(key), navigate: path => latest.current.navigate?.(path) }), dependencies: [cached.api] }, { start: ({ controller }) => { void controller.load(); } });
|
|
15
16
|
useEffect(() => { if (!controller)
|
|
16
17
|
return; return events?.subscribe({ resource: WIDGETS_REGIONS_RESOURCE, onRefresh: () => invalidate({ key: WIDGET_QUERY_KEYS.regions }) }); }, [controller, events, invalidate]);
|
|
17
|
-
return { ...(
|
|
18
|
+
return { ...mergeRegionsState({ snapshot, data: cached.query.data, queryError: cached.query.error }), setNewRegionKey: value => controller?.setNewRegionKey({ value }), bind: async () => { await controller?.bind(); }, t };
|
|
19
|
+
}
|
|
20
|
+
const EMPTY_REGIONS_STATE = { regions: null, error: null, newRegionKey: '', binding: false };
|
|
21
|
+
/** Cached query data wins for the list; a controller error wins over a query error. */
|
|
22
|
+
function mergeRegionsState({ snapshot, data, queryError }, _optional = {}) {
|
|
23
|
+
const state = snapshot ?? EMPTY_REGIONS_STATE;
|
|
24
|
+
return { ...state, regions: data?.regions ?? state.regions, error: state.error ?? queryError?.message ?? null };
|
|
18
25
|
}
|
|
19
26
|
export function useWiredWidgetRegions() {
|
|
20
27
|
const { widgetsApi: api, widgetsEvents: events, widgetsNavigation } = useWidgetsPorts();
|
|
@@ -22,5 +29,4 @@ export function useWiredWidgetRegions() {
|
|
|
22
29
|
const navigate = useWidgetsNavigate({ navigation: widgetsNavigation, navigationBase });
|
|
23
30
|
return useWidgetRegions({ api }, { t, locale, events, navigate });
|
|
24
31
|
}
|
|
25
|
-
import { useWidgetsNavigate } from './navigation.hooks.js';
|
|
26
32
|
//# sourceMappingURL=use-widget-regions.hooks.js.map
|
|
@@ -14,11 +14,18 @@ export function useWidgetsLibrary({ api }, { t = widgetsEnglish, locale = 'en',
|
|
|
14
14
|
const { controller, snapshot } = useController({ create: () => createWidgetsLibraryController({ api: cached.api }, { t: key => latestT.current(key) }), dependencies: [cached.api] }, { start: ({ controller }) => { void controller.load(); } });
|
|
15
15
|
useEffect(() => { if (!controller)
|
|
16
16
|
return; return events?.subscribe({ resource: WIDGETS_LIBRARY_RESOURCE, onRefresh: () => invalidate({ key: WIDGET_QUERY_KEYS.library }) }); }, [controller, events, invalidate]);
|
|
17
|
-
|
|
18
|
-
return { ...state, widgets: cached.query.data?.widgets ?? state.widgets, skippedCount: cached.query.data?.skippedCount ?? state.skippedCount, skippedIds: cached.query.data?.skippedIds ?? state.skippedIds, error: state.error ?? cached.query.error?.message ?? null, trashing: state.pendingTrash !== null && state.trashingId === state.pendingTrash.id,
|
|
17
|
+
return { ...mergeLibraryState({ snapshot, data: cached.query.data, queryError: cached.query.error }),
|
|
19
18
|
setCreateType: type => controller?.setCreateType({ type }), requestTrash: widget => controller?.requestTrash({ widget }),
|
|
20
19
|
confirmTrash: async () => { await controller?.confirmTrash(); }, cancelTrash: () => controller?.cancelTrash(), t, locale };
|
|
21
20
|
}
|
|
21
|
+
const EMPTY_LIBRARY_STATE = { widgets: null, error: null, skippedCount: 0, skippedIds: [], createType: 'text', pendingTrash: null, trashingId: null };
|
|
22
|
+
function mergeLibraryState({ snapshot, data, queryError }, _optional = {}) {
|
|
23
|
+
const state = snapshot ?? EMPTY_LIBRARY_STATE;
|
|
24
|
+
return { ...state, ...cachedListFields({ state, data }), error: state.error ?? queryError?.message ?? null, trashing: state.pendingTrash !== null && state.trashingId === state.pendingTrash.id };
|
|
25
|
+
}
|
|
26
|
+
function cachedListFields({ state, data }, _optional = {}) {
|
|
27
|
+
return { widgets: data?.widgets ?? state.widgets, skippedCount: data?.skippedCount ?? state.skippedCount, skippedIds: data?.skippedIds ?? state.skippedIds };
|
|
28
|
+
}
|
|
22
29
|
export function useWiredWidgetsLibrary() {
|
|
23
30
|
const { widgetsApi: api, widgetsEvents: events } = useWidgetsPorts();
|
|
24
31
|
const { t, locale } = useWidgetsOptions();
|
|
@@ -18,6 +18,6 @@ export interface WidgetInstanceEditorProps {
|
|
|
18
18
|
*/
|
|
19
19
|
useWidgetInstanceEditorHook?: typeof useWiredWidgetInstanceEditor | undefined;
|
|
20
20
|
}
|
|
21
|
-
export declare function WidgetInstanceEditor(props: WidgetInstanceEditorProps): import("react").JSX.Element
|
|
21
|
+
export declare function WidgetInstanceEditor(props: WidgetInstanceEditorProps): import("react").JSX.Element;
|
|
22
22
|
export default WidgetInstanceEditor;
|
|
23
23
|
//# sourceMappingURL=WidgetInstanceEditor.d.ts.map
|
|
@@ -18,14 +18,13 @@ import { WhereUsedBanner, WidgetInstanceGuardNotice } from '../components/Widget
|
|
|
18
18
|
export function WidgetInstanceEditor(props) {
|
|
19
19
|
const { slots: { ConfigFields: WidgetConfigFields }, widgetTypes } = useWidgetsOptions();
|
|
20
20
|
const { widgetId, widgetType: queryWidgetType, useWidgetInstanceEditorHook = useWiredWidgetInstanceEditor } = props;
|
|
21
|
-
const { isNew, widget, whereUsed, title, setTitle, config, setConfig, message, error, fieldErrors, loading, saving,
|
|
22
|
-
if (guard)
|
|
23
|
-
return _jsx(WidgetInstanceGuardNotice, { guard: guard, t: t });
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
return null;
|
|
21
|
+
const { isNew, widget, whereUsed, title, setTitle, config, setConfig, message, error, fieldErrors, loading, saving, save, confirmLeave, t, locale, gate, onBackClick, } = useWidgetInstanceEditorView({ widgetId, widgetType: queryWidgetType, useWidgetInstanceEditorHook, widgetTypes });
|
|
22
|
+
if (gate.guard !== null)
|
|
23
|
+
return _jsx(WidgetInstanceGuardNotice, { guard: gate.guard, t: t });
|
|
24
|
+
// `widgetInstanceGuard`'s "no-type" case already covers a null `widgetType` above, but TS can't
|
|
25
|
+
// see through that opaque function call; `widgetEditorGate` hands back the narrowed type so the
|
|
26
|
+
// JSX below needs neither a `!` assertion nor a never-taken null check.
|
|
27
|
+
const { widgetType } = gate;
|
|
29
28
|
// The host slot binds shared-component translations; screen copy uses the module t.
|
|
30
29
|
const sharedT = t;
|
|
31
30
|
return (_jsxs("div", { className: "page", children: [_jsxs("div", { className: "page-header page-header-split", ...agentHandle({ handle: "widget-instance-header" }, {
|
package/dist/widgets/rules.d.ts
CHANGED
|
@@ -79,14 +79,26 @@ export type WidgetInstanceGuard = {
|
|
|
79
79
|
widgetType: string;
|
|
80
80
|
};
|
|
81
81
|
/** Catch a garbage ?type= before a live create editor can save it; existing types are server-validated. */
|
|
82
|
-
export declare function widgetInstanceGuard(
|
|
82
|
+
export declare function widgetInstanceGuard(required: WidgetInstanceGuardInput, _optional?: Record<string, never>): WidgetInstanceGuard | null;
|
|
83
|
+
export interface WidgetInstanceGuardInput {
|
|
83
84
|
error: string | null;
|
|
84
85
|
isNew: boolean;
|
|
85
86
|
widget: AdminWidget | null;
|
|
86
87
|
loading: boolean;
|
|
87
88
|
widgetType: string | null | undefined;
|
|
88
89
|
types: readonly WidgetTypeOption[];
|
|
89
|
-
}
|
|
90
|
+
}
|
|
91
|
+
/** The editor's gate: either the guard to render, or the widget type the live editor needs. Once no
|
|
92
|
+
* guard applies the "no-type" case has already ruled out a missing type, and returning it here
|
|
93
|
+
* carries that narrowing to the page, which otherwise needed its own never-taken null check. */
|
|
94
|
+
export type WidgetEditorGate = {
|
|
95
|
+
guard: WidgetInstanceGuard;
|
|
96
|
+
widgetType?: undefined;
|
|
97
|
+
} | {
|
|
98
|
+
guard: null;
|
|
99
|
+
widgetType: string;
|
|
100
|
+
};
|
|
101
|
+
export declare function widgetEditorGate({ error, isNew, widget, loading, widgetType, types }: WidgetInstanceGuardInput, _optional?: Record<string, never>): WidgetEditorGate;
|
|
90
102
|
/** Match the original save identity, including the query type on /new. */
|
|
91
103
|
export declare function widgetEntityKey({ params }: {
|
|
92
104
|
params: WidgetEditorParams;
|
package/dist/widgets/rules.js
CHANGED
|
@@ -65,16 +65,19 @@ export function widgetSlugRedirectPath({ requestedId, widget }, { slugRedirectPa
|
|
|
65
65
|
return slugRedirectPath?.('/widgets', requestedId, widget) ?? null;
|
|
66
66
|
}
|
|
67
67
|
/** Catch a garbage ?type= before a live create editor can save it; existing types are server-validated. */
|
|
68
|
-
export function widgetInstanceGuard(
|
|
68
|
+
export function widgetInstanceGuard(required, _optional = {}) {
|
|
69
|
+
return widgetEditorGate(required).guard;
|
|
70
|
+
}
|
|
71
|
+
export function widgetEditorGate({ error, isNew, widget, loading, widgetType, types }, _optional = {}) {
|
|
69
72
|
if (error && !isNew && !widget)
|
|
70
|
-
return { kind: 'fetch-error', message: error };
|
|
73
|
+
return { guard: { kind: 'fetch-error', message: error } };
|
|
71
74
|
if (loading)
|
|
72
|
-
return { kind: 'loading' };
|
|
75
|
+
return { guard: { kind: 'loading' } };
|
|
73
76
|
if (!widgetType)
|
|
74
|
-
return { kind: 'no-type' };
|
|
77
|
+
return { guard: { kind: 'no-type' } };
|
|
75
78
|
if (isNew && !isKnownWidgetType({ widgetType, types }))
|
|
76
|
-
return { kind: 'unknown-type', widgetType };
|
|
77
|
-
return null;
|
|
79
|
+
return { guard: { kind: 'unknown-type', widgetType } };
|
|
80
|
+
return { guard: null, widgetType };
|
|
78
81
|
}
|
|
79
82
|
/** Match the original save identity, including the query type on /new. */
|
|
80
83
|
export function widgetEntityKey({ params }, _optional = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/admin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Composable admin surface for Jini-hosted products: framework-free contracts, panel registry, and route model in `/core`; React shell and panels in `/react`. Import only the layers you need.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"kind": "state",
|
|
14
14
|
"runtime": "universal",
|
|
15
15
|
"entries": {
|
|
16
|
+
"./themes/default/admin.css": "browser",
|
|
17
|
+
"./themes/default/chat.css": "browser",
|
|
18
|
+
"./themes/default/manifest.json": "universal",
|
|
16
19
|
".": "universal",
|
|
17
20
|
"./core": "universal",
|
|
18
21
|
"./browser": "browser",
|
|
@@ -95,10 +98,15 @@
|
|
|
95
98
|
}
|
|
96
99
|
},
|
|
97
100
|
"type": "module",
|
|
98
|
-
"sideEffects":
|
|
101
|
+
"sideEffects": [
|
|
102
|
+
"./src/themes/**/*.css"
|
|
103
|
+
],
|
|
99
104
|
"main": "./dist/core/index.js",
|
|
100
105
|
"types": "./dist/core/index.d.ts",
|
|
101
106
|
"exports": {
|
|
107
|
+
"./themes/default/admin.css": "./src/themes/default/admin.css",
|
|
108
|
+
"./themes/default/chat.css": "./src/themes/default/chat.css",
|
|
109
|
+
"./themes/default/manifest.json": "./src/themes/default/manifest.json",
|
|
102
110
|
".": {
|
|
103
111
|
"types": "./dist/core/index.d.ts",
|
|
104
112
|
"import": "./dist/core/index.js",
|
|
@@ -421,6 +429,7 @@
|
|
|
421
429
|
}
|
|
422
430
|
},
|
|
423
431
|
"files": [
|
|
432
|
+
"src/themes",
|
|
424
433
|
"dist",
|
|
425
434
|
"README.md",
|
|
426
435
|
"CHANGELOG.md",
|
|
@@ -482,12 +491,12 @@
|
|
|
482
491
|
"react": "^19.2.0",
|
|
483
492
|
"react-dom": "^19.2.0",
|
|
484
493
|
"@testing-library/user-event": "^14.6.1",
|
|
485
|
-
"@jini-ai/
|
|
486
|
-
"@jini-ai/
|
|
487
|
-
"@jini-ai/
|
|
488
|
-
"@jini-ai/
|
|
489
|
-
"@jini-ai/
|
|
490
|
-
"@jini-ai/ui": "^0.5.
|
|
494
|
+
"@jini-ai/ui-kit": "^0.1.5",
|
|
495
|
+
"@jini-ai/cms": "^0.5.14",
|
|
496
|
+
"@jini-ai/core": "^0.4.9",
|
|
497
|
+
"@jini-ai/agent-plugins": "^0.4.8",
|
|
498
|
+
"@jini-ai/agentic": "^0.4.5",
|
|
499
|
+
"@jini-ai/ui": "^0.5.6"
|
|
491
500
|
},
|
|
492
501
|
"typesVersions": {
|
|
493
502
|
"*": {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* Default theme values, owned by @jini-ai/admin. Load after @jini-ai/ui structural CSS.
|
|
2
|
+
The UI contract keeps its legacy fallbacks during migration; these inputs equal them. */
|
|
3
|
+
:root {
|
|
4
|
+
--jini-theme-light-bg: #ffffff;
|
|
5
|
+
--jini-theme-light-surface: #f5f5f5;
|
|
6
|
+
--jini-theme-light-text: #202020;
|
|
7
|
+
--jini-theme-light-muted: #666666;
|
|
8
|
+
--jini-theme-light-border: #d9d9d9;
|
|
9
|
+
--jini-theme-light-primary: #363636;
|
|
10
|
+
--jini-theme-light-primary-ink: #ffffff;
|
|
11
|
+
--jini-theme-light-danger: #b42318;
|
|
12
|
+
--jini-theme-light-success: #18763b;
|
|
13
|
+
--jini-theme-light-warning: #845800;
|
|
14
|
+
--jini-theme-dark-bg: #171717;
|
|
15
|
+
--jini-theme-dark-surface: #242424;
|
|
16
|
+
--jini-theme-dark-text: #f0f0f0;
|
|
17
|
+
--jini-theme-dark-muted: #b3b3b3;
|
|
18
|
+
--jini-theme-dark-border: #454545;
|
|
19
|
+
--jini-theme-dark-primary: #e0e0e0;
|
|
20
|
+
--jini-theme-dark-primary-ink: #202020;
|
|
21
|
+
--jini-theme-dark-danger: #ff8b80;
|
|
22
|
+
--jini-theme-dark-success: #79d69b;
|
|
23
|
+
--jini-theme-dark-warning: #ebc36b;
|
|
24
|
+
--jini-font-body: system-ui, sans-serif;
|
|
25
|
+
--jini-font-heading: system-ui, sans-serif;
|
|
26
|
+
--jini-font-mono: ui-monospace, monospace;
|
|
27
|
+
--jini-radius: 8px;
|
|
28
|
+
--jini-density: 1;
|
|
29
|
+
|
|
30
|
+
--jini-theme-panel-backdrop: none;
|
|
31
|
+
--jini-theme-panel-texture: none;
|
|
32
|
+
--jini-theme-overlay-backdrop: blur(4px);
|
|
33
|
+
--jini-theme-control-shadow: none;
|
|
34
|
+
--jini-theme-control-shadow-hover: none;
|
|
35
|
+
--jini-theme-control-shadow-pressed: none;
|
|
36
|
+
--jini-theme-control-shadow-inset: none;
|
|
37
|
+
--jini-theme-border-width: 1px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Match existing neutral panels, tabbed-dialog scrims and controls. Role wiring is deferred. */
|
|
41
|
+
/* Re-resolve scheme defaults here without shadowing inherited host --jini-theme-* inputs. */
|
|
42
|
+
:root, [data-admin-theme], [data-color-scheme] {
|
|
43
|
+
--jini-default-app-bg: var(--jini-bg);
|
|
44
|
+
--jini-default-panel-bg: var(--jini-bg-panel);
|
|
45
|
+
--jini-default-panel-border: var(--jini-border);
|
|
46
|
+
--jini-default-panel-shadow: var(--jini-shadow-sm);
|
|
47
|
+
--jini-default-overlay-bg: var(--jini-backdrop);
|
|
48
|
+
--jini-default-overlay-shadow: var(--jini-shadow-lg);
|
|
49
|
+
--jini-default-control-bg: var(--jini-bg-elevated);
|
|
50
|
+
--jini-default-control-border: var(--jini-border-strong);
|
|
51
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* Standalone default chat palette: exactly ChatPane's existing injected values, including
|
|
2
|
+
its scheme-independent sent bubbles. Component defaults are migrated in a later step. */
|
|
3
|
+
:root {
|
|
4
|
+
--jini-theme-chat-bg: #faf9f7;
|
|
5
|
+
--jini-theme-chat-panel: #fdfcfa;
|
|
6
|
+
--jini-theme-chat-text: #1a1916;
|
|
7
|
+
--jini-theme-chat-text-strong: #0d0c0a;
|
|
8
|
+
--jini-theme-chat-muted: #74716b;
|
|
9
|
+
--jini-theme-chat-faint: #b3b0a8;
|
|
10
|
+
--jini-theme-chat-border: #e1e5eb;
|
|
11
|
+
--jini-theme-chat-border-strong: #c9d0da;
|
|
12
|
+
--jini-theme-chat-border-soft: #edf0f4;
|
|
13
|
+
--jini-theme-chat-subtle: #f4f5f7;
|
|
14
|
+
--jini-theme-chat-accent: #c96442;
|
|
15
|
+
--jini-theme-chat-accent-soft: #fbeee5;
|
|
16
|
+
--jini-theme-chat-danger: #e5484d;
|
|
17
|
+
--jini-theme-chat-radius: 8px;
|
|
18
|
+
--jini-theme-chat-radius-lg: 12px;
|
|
19
|
+
--jini-theme-chat-user-bubble: #1a1b1c;
|
|
20
|
+
--jini-theme-chat-user-bubble-ink: #fff;
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "default",
|
|
3
|
+
"name": "Jini Default",
|
|
4
|
+
"schemes": [
|
|
5
|
+
"light",
|
|
6
|
+
"dark"
|
|
7
|
+
],
|
|
8
|
+
"stylesheets": {
|
|
9
|
+
"admin": "./admin.css",
|
|
10
|
+
"chat": "./chat.css"
|
|
11
|
+
},
|
|
12
|
+
"fonts": [],
|
|
13
|
+
"preview": {
|
|
14
|
+
"light": {
|
|
15
|
+
"bg": "#ffffff",
|
|
16
|
+
"surface": "#f5f5f5",
|
|
17
|
+
"text": "#202020",
|
|
18
|
+
"accent": "#363636",
|
|
19
|
+
"border": "#d9d9d9"
|
|
20
|
+
},
|
|
21
|
+
"dark": {
|
|
22
|
+
"bg": "#171717",
|
|
23
|
+
"surface": "#242424",
|
|
24
|
+
"text": "#f0f0f0",
|
|
25
|
+
"accent": "#e0e0e0",
|
|
26
|
+
"border": "#454545"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/media/styles.d.ts
DELETED
package/dist/media/styles.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/** Scoped feature presentation travels with compiled JS. It also overrides host dialog
|
|
2
|
-
* CSS that can accidentally display a closed dialog or shrink a large media preview. */
|
|
3
|
-
// Host CSS now supplies presentation and the closed-dialog safeguards on jini- classes.
|
|
4
|
-
export const mediaStyles = '';
|
|
5
|
-
//# sourceMappingURL=styles.js.map
|