opacacms 0.1.12 → 0.1.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/dist/admin/index.js +0 -4
- package/dist/admin/webcomponent.d.ts +0 -1
- package/dist/admin/webcomponent.js +0 -4
- package/dist/admin.css +1 -0
- package/package.json +8 -2
- package/bun.lock +0 -34
- package/dist/admin/index.css +0 -47
- package/dist/admin/webcomponent.css +0 -47
- package/global.d.ts +0 -11
- package/src/admin/api-client.ts +0 -63
- package/src/admin/auth-client.ts +0 -40
- package/src/admin/custom-field.ts +0 -179
- package/src/admin/index.ts +0 -15
- package/src/admin/react.tsx +0 -72
- package/src/admin/router.ts +0 -9
- package/src/admin/stores/admin-queries.ts +0 -121
- package/src/admin/stores/auth.ts +0 -61
- package/src/admin/stores/column-visibility.ts +0 -67
- package/src/admin/stores/config.ts +0 -15
- package/src/admin/stores/media.ts +0 -95
- package/src/admin/stores/query.ts +0 -13
- package/src/admin/stores/ui.ts +0 -29
- package/src/admin/ui/admin-client.tsx +0 -283
- package/src/admin/ui/admin-layout.tsx +0 -276
- package/src/admin/ui/components/ColumnVisibilityToggle.tsx +0 -141
- package/src/admin/ui/components/DataDetailSheet.tsx +0 -141
- package/src/admin/ui/components/DataDetailView.tsx +0 -175
- package/src/admin/ui/components/Table.tsx +0 -67
- package/src/admin/ui/components/fields/ArrayField.tsx +0 -166
- package/src/admin/ui/components/fields/BlocksField.tsx +0 -202
- package/src/admin/ui/components/fields/BooleanField.tsx +0 -50
- package/src/admin/ui/components/fields/CollapsibleField.tsx +0 -75
- package/src/admin/ui/components/fields/DateField.tsx +0 -45
- package/src/admin/ui/components/fields/FileField.tsx +0 -322
- package/src/admin/ui/components/fields/GroupField.tsx +0 -50
- package/src/admin/ui/components/fields/JoinField.tsx +0 -23
- package/src/admin/ui/components/fields/NumberField.tsx +0 -46
- package/src/admin/ui/components/fields/RadioField.tsx +0 -62
- package/src/admin/ui/components/fields/RelationshipField.tsx +0 -278
- package/src/admin/ui/components/fields/RowField.tsx +0 -40
- package/src/admin/ui/components/fields/SelectField.tsx +0 -59
- package/src/admin/ui/components/fields/TabsField.tsx +0 -101
- package/src/admin/ui/components/fields/TextAreaField.tsx +0 -54
- package/src/admin/ui/components/fields/TextField.tsx +0 -49
- package/src/admin/ui/components/fields/VirtualField.tsx +0 -53
- package/src/admin/ui/components/fields/index.tsx +0 -371
- package/src/admin/ui/components/fields/richtext-editor/index.tsx +0 -211
- package/src/admin/ui/components/fields/richtext-editor/nodes/ImageComponent.tsx +0 -142
- package/src/admin/ui/components/fields/richtext-editor/nodes/ImageNode.tsx +0 -95
- package/src/admin/ui/components/fields/richtext-editor/plugins/ComponentPickerPlugin.tsx +0 -226
- package/src/admin/ui/components/fields/richtext-editor/plugins/EditableSyncPlugin.tsx +0 -16
- package/src/admin/ui/components/fields/richtext-editor/plugins/NotionToolbarPlugin.tsx +0 -184
- package/src/admin/ui/components/fields/richtext-editor/plugins/SimpleToolbarPlugin.tsx +0 -240
- package/src/admin/ui/components/fields/richtext-editor/plugins/ValueSyncPlugin.tsx +0 -40
- package/src/admin/ui/components/fields/utils.ts +0 -1
- package/src/admin/ui/components/link.tsx +0 -41
- package/src/admin/ui/components/media/AssetManagerModal.tsx +0 -334
- package/src/admin/ui/components/toast.tsx +0 -72
- package/src/admin/ui/components/ui/accordion.tsx +0 -51
- package/src/admin/ui/components/ui/alert-dialog.tsx +0 -98
- package/src/admin/ui/components/ui/blocks.tsx +0 -32
- package/src/admin/ui/components/ui/breadcrumbs.tsx +0 -59
- package/src/admin/ui/components/ui/button.tsx +0 -26
- package/src/admin/ui/components/ui/collapsible.tsx +0 -124
- package/src/admin/ui/components/ui/dialog.tsx +0 -79
- package/src/admin/ui/components/ui/group.tsx +0 -20
- package/src/admin/ui/components/ui/index.ts +0 -17
- package/src/admin/ui/components/ui/input.tsx +0 -12
- package/src/admin/ui/components/ui/join.tsx +0 -53
- package/src/admin/ui/components/ui/label.tsx +0 -11
- package/src/admin/ui/components/ui/radio-group.tsx +0 -75
- package/src/admin/ui/components/ui/relationship-detail-sheet.tsx +0 -122
- package/src/admin/ui/components/ui/relationship.tsx +0 -58
- package/src/admin/ui/components/ui/scroll-area.tsx +0 -19
- package/src/admin/ui/components/ui/select.tsx +0 -187
- package/src/admin/ui/components/ui/separator.tsx +0 -21
- package/src/admin/ui/components/ui/sheet.tsx +0 -106
- package/src/admin/ui/components/ui/tabs.tsx +0 -116
- package/src/admin/ui/components/ui/utils.ts +0 -3
- package/src/admin/ui/hooks/use-debounce.ts +0 -15
- package/src/admin/ui/styles/_locale-switcher.scss +0 -33
- package/src/admin/ui/styles/accordion.scss +0 -60
- package/src/admin/ui/styles/animations.scss +0 -41
- package/src/admin/ui/styles/asset-manager.scss +0 -547
- package/src/admin/ui/styles/badge.scss +0 -13
- package/src/admin/ui/styles/base.scss +0 -22
- package/src/admin/ui/styles/button.scss +0 -161
- package/src/admin/ui/styles/card.scss +0 -13
- package/src/admin/ui/styles/collapsible.scss +0 -75
- package/src/admin/ui/styles/data-detail.scss +0 -92
- package/src/admin/ui/styles/dialog.scss +0 -102
- package/src/admin/ui/styles/empty-state.scss +0 -22
- package/src/admin/ui/styles/group.scss +0 -19
- package/src/admin/ui/styles/index.scss +0 -33
- package/src/admin/ui/styles/input.scss +0 -80
- package/src/admin/ui/styles/label.scss +0 -12
- package/src/admin/ui/styles/layout.scss +0 -56
- package/src/admin/ui/styles/lexical.scss +0 -469
- package/src/admin/ui/styles/loading.scss +0 -102
- package/src/admin/ui/styles/media-registry.scss +0 -597
- package/src/admin/ui/styles/pagination.scss +0 -20
- package/src/admin/ui/styles/radio-group.scss +0 -66
- package/src/admin/ui/styles/row.scss +0 -17
- package/src/admin/ui/styles/scrollbar.scss +0 -36
- package/src/admin/ui/styles/select.scss +0 -121
- package/src/admin/ui/styles/separator.scss +0 -14
- package/src/admin/ui/styles/sheet.scss +0 -152
- package/src/admin/ui/styles/sidebar.scss +0 -148
- package/src/admin/ui/styles/switch.scss +0 -59
- package/src/admin/ui/styles/table.scss +0 -207
- package/src/admin/ui/styles/tabs.scss +0 -62
- package/src/admin/ui/styles/toast.scss +0 -45
- package/src/admin/ui/styles/variables.scss +0 -24
- package/src/admin/ui/views/collection-list-view.tsx +0 -720
- package/src/admin/ui/views/dashboard-view.tsx +0 -263
- package/src/admin/ui/views/document-edit-view.tsx +0 -384
- package/src/admin/ui/views/global-edit-view.tsx +0 -226
- package/src/admin/ui/views/init-view.tsx +0 -182
- package/src/admin/ui/views/login-view.tsx +0 -123
- package/src/admin/ui/views/media-registry-view.tsx +0 -1104
- package/src/admin/ui/views/settings-view.tsx +0 -729
- package/src/admin/webcomponent.tsx +0 -15
- package/src/auth/index.ts +0 -194
- package/src/auth/migrations.ts +0 -87
- package/src/auth/premissions.ts +0 -46
- package/src/cli/commands/generate-types.ts +0 -116
- package/src/cli/commands/init.ts +0 -95
- package/src/cli/commands/migrate-commands.ts +0 -160
- package/src/cli/commands/seed-command.ts +0 -11
- package/src/cli/d1-mock.ts +0 -101
- package/src/cli/index.test.ts +0 -84
- package/src/cli/index.ts +0 -183
- package/src/cli/r2-mock.ts +0 -217
- package/src/cli/seeding.ts +0 -409
- package/src/client.ts +0 -181
- package/src/config-utils.ts +0 -102
- package/src/config.ts +0 -49
- package/src/db/adapter.ts +0 -53
- package/src/db/better-sqlite.ts +0 -657
- package/src/db/bun-sqlite.ts +0 -666
- package/src/db/d1.ts +0 -721
- package/src/db/index.ts +0 -10
- package/src/db/kysely/data-mapper.ts +0 -142
- package/src/db/kysely/field-mapper.ts +0 -149
- package/src/db/kysely/migration-generator.ts +0 -223
- package/src/db/kysely/query-builder.ts +0 -92
- package/src/db/kysely/schema-builder.ts +0 -439
- package/src/db/kysely/sql-utils.ts +0 -13
- package/src/db/postgres.ts +0 -631
- package/src/db/sqlite.ts +0 -670
- package/src/db/system-schema.ts +0 -121
- package/src/index.ts +0 -13
- package/src/runtimes/README.md +0 -59
- package/src/runtimes/bun.ts +0 -49
- package/src/runtimes/cloudflare-workers.ts +0 -38
- package/src/runtimes/next.ts +0 -26
- package/src/runtimes/node.ts +0 -52
- package/src/schema/collection.ts +0 -184
- package/src/schema/fields/base.ts +0 -164
- package/src/schema/fields/index.ts +0 -427
- package/src/schema/global.ts +0 -145
- package/src/schema/index.ts +0 -4
- package/src/schema/infer.ts +0 -72
- package/src/server/admin-router.ts +0 -20
- package/src/server/admin.ts +0 -142
- package/src/server/assets.ts +0 -306
- package/src/server/collection-router.ts +0 -55
- package/src/server/handlers.ts +0 -722
- package/src/server/middlewares/admin.ts +0 -27
- package/src/server/middlewares/auth.ts +0 -89
- package/src/server/middlewares/context.ts +0 -17
- package/src/server/middlewares/cors.ts +0 -24
- package/src/server/middlewares/database-init.ts +0 -74
- package/src/server/middlewares/rate-limit.ts +0 -77
- package/src/server/router.ts +0 -47
- package/src/server/setup-middlewares.ts +0 -58
- package/src/server/system-router.ts +0 -35
- package/src/server.ts +0 -9
- package/src/storage/adapters/cloudflare-r2.ts +0 -136
- package/src/storage/adapters/local.ts +0 -146
- package/src/storage/adapters/s3.ts +0 -186
- package/src/storage/errors.ts +0 -46
- package/src/storage/index.ts +0 -5
- package/src/storage/types.ts +0 -39
- package/src/types.ts +0 -577
- package/src/utils/lexical.ts +0 -37
- package/src/utils/logger.ts +0 -73
- package/src/validation.ts +0 -429
- package/src/validator.ts +0 -179
- package/test/admin-custom-field.test.ts +0 -162
- package/test/admin-react-field.test.tsx +0 -134
- package/test/api-features.test.ts +0 -78
- package/test/api.test.ts +0 -178
- package/test/auth.test.ts +0 -62
- package/test/cli-integration.test.ts +0 -148
- package/test/cli.test.ts +0 -25
- package/test/db/postgres.test.ts +0 -95
- package/test/db/sqlite-filter.test.ts +0 -53
- package/test/db/sqlite.test.ts +0 -82
- package/test/engine-features.test.ts +0 -79
- package/test/globals.test.ts +0 -74
- package/test/integration-tmp/db-app/opacacms.config.ts +0 -15
- package/test/integration-tmp/my-sqlite-app/opacacms.config.ts +0 -25
- package/test/integration-tmp/my-test-app/index.ts +0 -8
- package/test/integration-tmp/my-test-app/opacacms.config.ts +0 -16
- package/test/integration-tmp/my-test-app/package.json +0 -12
- package/test/populate.test.ts +0 -79
- package/test/runtimes.test.ts +0 -43
- package/test/schema-builder.test.ts +0 -107
- package/test/schema-features.test.ts +0 -63
- package/test/seeding.test.ts +0 -68
- package/test/storage/local.test.ts +0 -72
- package/test/storage/s3.test.ts +0 -60
- package/test/structural-data.test.ts +0 -100
- package/test/test-setup.ts +0 -11
- package/test/validation.test.ts +0 -162
- package/tsconfig.json +0 -42
package/dist/admin/index.js
CHANGED
|
@@ -274,7 +274,6 @@ import * as React2 from "react";
|
|
|
274
274
|
function cn(...classes) {
|
|
275
275
|
return classes.filter(Boolean).join(" ");
|
|
276
276
|
}
|
|
277
|
-
|
|
278
277
|
// src/admin/ui/components/ui/accordion.tsx
|
|
279
278
|
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
280
279
|
var Accordion = ({
|
|
@@ -2016,7 +2015,6 @@ var setBucketColor = (bucket, color) => {
|
|
|
2016
2015
|
const current = $bucketColors.get();
|
|
2017
2016
|
$bucketColors.set({ ...current, [bucket]: color });
|
|
2018
2017
|
};
|
|
2019
|
-
|
|
2020
2018
|
// src/admin/ui/components/media/AssetManagerModal.tsx
|
|
2021
2019
|
import { jsxDEV as jsxDEV24, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
2022
2020
|
var AssetManagerModal = ({
|
|
@@ -2977,7 +2975,6 @@ function ValueSyncPlugin({ value }) {
|
|
|
2977
2975
|
}, [editor, value]);
|
|
2978
2976
|
return null;
|
|
2979
2977
|
}
|
|
2980
|
-
|
|
2981
2978
|
// src/admin/ui/components/fields/richtext-editor/index.tsx
|
|
2982
2979
|
import { jsxDEV as jsxDEV28 } from "react/jsx-dev-runtime";
|
|
2983
2980
|
var theme = {
|
|
@@ -3315,7 +3312,6 @@ var DataDetailView = ({
|
|
|
3315
3312
|
children: String(data)
|
|
3316
3313
|
}, undefined, false, undefined, this);
|
|
3317
3314
|
};
|
|
3318
|
-
|
|
3319
3315
|
// src/admin/ui/components/DataDetailSheet.tsx
|
|
3320
3316
|
import { useStore as useStore4 } from "@nanostores/react";
|
|
3321
3317
|
import { jsxDEV as jsxDEV30, Fragment as Fragment6 } from "react/jsx-dev-runtime";
|
|
@@ -278,7 +278,6 @@ import * as React from "react";
|
|
|
278
278
|
function cn(...classes) {
|
|
279
279
|
return classes.filter(Boolean).join(" ");
|
|
280
280
|
}
|
|
281
|
-
|
|
282
281
|
// src/admin/ui/components/ui/accordion.tsx
|
|
283
282
|
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
284
283
|
var Accordion = ({
|
|
@@ -2038,7 +2037,6 @@ var setBucketColor = (bucket, color) => {
|
|
|
2038
2037
|
const current = $bucketColors.get();
|
|
2039
2038
|
$bucketColors.set({ ...current, [bucket]: color });
|
|
2040
2039
|
};
|
|
2041
|
-
|
|
2042
2040
|
// src/admin/ui/components/media/AssetManagerModal.tsx
|
|
2043
2041
|
import { jsxDEV as jsxDEV24, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
2044
2042
|
var AssetManagerModal = ({
|
|
@@ -2999,7 +2997,6 @@ function ValueSyncPlugin({ value }) {
|
|
|
2999
2997
|
}, [editor, value]);
|
|
3000
2998
|
return null;
|
|
3001
2999
|
}
|
|
3002
|
-
|
|
3003
3000
|
// src/admin/ui/components/fields/richtext-editor/index.tsx
|
|
3004
3001
|
import { jsxDEV as jsxDEV28 } from "react/jsx-dev-runtime";
|
|
3005
3002
|
var theme = {
|
|
@@ -3337,7 +3334,6 @@ var DataDetailView = ({
|
|
|
3337
3334
|
children: String(data)
|
|
3338
3335
|
}, undefined, false, undefined, this);
|
|
3339
3336
|
};
|
|
3340
|
-
|
|
3341
3337
|
// src/admin/ui/components/DataDetailSheet.tsx
|
|
3342
3338
|
import { useStore as useStore4 } from "@nanostores/react";
|
|
3343
3339
|
import { jsxDEV as jsxDEV30, Fragment as Fragment6 } from "react/jsx-dev-runtime";
|
package/dist/admin.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--opaca-bg: #09090b;--opaca-sidebar-bg: #0c0c0f;--opaca-card-bg: #111114;--opaca-surface: #16161a;--opaca-border: #1e1e24;--opaca-border-hover: #2a2a32;--opaca-text: #e4e4e7;--opaca-text-muted: #71717a;--opaca-text-dim: #52525b;--opaca-primary: #7c3aed;--opaca-primary-hover: #6d28d9;--opaca-primary-glow: rgba(124, 58, 237, 0.15);--opaca-accent: #a78bfa;--opaca-error: #f87171;--opaca-error-bg: rgba(248, 113, 113, 0.08);--opaca-success: #34d399;--opaca-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;--opaca-radius: 4px;--opaca-radius-lg: 6px;--opaca-transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);--opaca-sidebar-width: 240px;--opaca-sidebar-collapsed-width: 68px}@keyframes opaca-fade-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes opaca-spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}@keyframes opaca-toast-in{from{opacity:0;transform:translateX(100%)}to{opacity:1;transform:translateX(0)}}@keyframes opaca-pulse{0%,100%{transform:scale(1);opacity:.2}50%{transform:scale(1.4);opacity:0}}.opaca-spin{animation:opaca-spin 1s linear infinite}.opaca-admin *,.opaca-admin *::before,.opaca-admin *::after{box-sizing:border-box;margin:0;padding:0}.opaca-admin{background-color:var(--opaca-bg);color:var(--opaca-text);font-family:var(--opaca-font);height:100vh;display:flex;font-size:14px;line-height:1.6;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow:hidden}.opaca-admin ::-webkit-scrollbar{width:6px;height:6px}.opaca-admin ::-webkit-scrollbar-track{background:rgba(0,0,0,0)}.opaca-admin ::-webkit-scrollbar-thumb{background:var(--opaca-border);border-radius:10px}.opaca-admin ::-webkit-scrollbar-thumb:hover{background:var(--opaca-border-hover)}.opaca-scroll-area::-webkit-scrollbar{width:4px}.opaca-scroll-area::-webkit-scrollbar-thumb{background:var(--opaca-border);border-radius:10px}.opaca-scroll-area::-webkit-scrollbar-thumb:hover{background:var(--opaca-accent)}.opaca-sidebar{width:var(--opaca-sidebar-width);background-color:var(--opaca-sidebar-bg);border-right:1px solid var(--opaca-border);height:100%;display:flex;flex-direction:column;transition:width var(--opaca-transition),padding var(--opaca-transition);z-index:100;overflow:visible;backdrop-filter:blur(10px)}.opaca-sidebar.collapsed{width:var(--opaca-sidebar-collapsed-width)}.opaca-sidebar.collapsed .opaca-sidebar-inner{padding-left:.5rem;padding-right:.5rem}.opaca-sidebar.collapsed .opaca-nav-item{padding-left:0;padding-right:0;justify-content:center;gap:0}.opaca-sidebar.collapsed .opaca-nav-label{opacity:0;width:0}.opaca-sidebar.collapsed .opaca-sidebar-toggle{right:-12px}.opaca-sidebar-inner{display:flex;flex-direction:column;height:100%;overflow:hidden;padding:1.25rem .75rem}.opaca-logo{font-size:.875rem;font-weight:600;letter-spacing:-0.01em;padding:0 .75rem;margin-bottom:2rem;color:var(--opaca-accent);transition:all var(--opaca-transition);white-space:nowrap;display:flex;align-items:center;min-height:32px}.opaca-logo-mini{width:32px;height:32px;background-color:rgba(124,58,237,.1);border:1px solid rgba(124,58,237,.2);color:var(--opaca-accent);display:flex;align-items:center;justify-content:center;border-radius:var(--opaca-radius);font-size:.875rem;font-weight:700}.opaca-nav{flex:1;display:flex;flex-direction:column;min-height:0}.opaca-nav-item{display:flex;align-items:center;gap:.625rem;padding:.5rem .75rem;color:var(--opaca-text-muted);text-decoration:none;border-radius:var(--opaca-radius);transition:all var(--opaca-transition);margin-bottom:1px;font-size:.8125rem;font-weight:400;white-space:nowrap;overflow:hidden;border:1px solid rgba(0,0,0,0)}.opaca-nav-item:hover{background-color:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.05);color:var(--opaca-text)}.opaca-nav-item.active{background-color:var(--opaca-primary-glow);color:var(--opaca-accent);font-weight:600;box-shadow:inset 2px 0 0 0 var(--opaca-primary)}.opaca-nav-label{transition:opacity var(--opaca-transition)}.opaca-nav-footer{border-top:1px solid var(--opaca-border);padding-top:.75rem;margin-top:auto;padding-bottom:.5rem}.opaca-sidebar-toggle{position:absolute;top:25px;right:-12px;width:24px;height:24px;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:50%;color:var(--opaca-text-dim);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:101;transition:all var(--opaca-transition);box-shadow:0 2px 4px rgba(0,0,0,.1)}.opaca-sidebar-toggle:hover{border-color:var(--opaca-accent);color:var(--opaca-accent);background-color:var(--opaca-surface)}.opaca-content{flex:1;padding:2.5rem;overflow-y:auto;height:100%;scroll-behavior:smooth}.opaca-content-inner{margin:0 auto;width:100%}.opaca-view-container{opacity:1;transform:translateY(0);transition:opacity var(--opaca-transition),transform var(--opaca-transition)}.opaca-view-container.loading{opacity:.5;pointer-events:none;filter:blur(1px)}.opaca-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:2rem}.opaca-title{font-size:1.375rem;font-weight:600;letter-spacing:-0.02em;color:var(--opaca-text)}.opaca-subtitle{color:var(--opaca-text-muted);font-size:.8125rem;margin-top:.25rem}.opaca-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(260px, 1fr));gap:1rem}.opaca-form-group{margin-bottom:1.5rem}.opaca-card{background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);padding:1.25rem;transition:border-color var(--opaca-transition)}.opaca-card:hover{border-color:var(--opaca-border-hover)}.opaca-table-container{background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);overflow:hidden;position:relative}.opaca-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background-color:rgba(9,9,11,.6);backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:10;animation:opaca-fade-in 200ms ease-out}.opaca-table{width:100%;border-collapse:collapse}.opaca-table th{text-align:left;padding:.625rem 1rem;background-color:var(--opaca-surface);color:var(--opaca-text-dim);font-weight:500;font-size:.6875rem;text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--opaca-border)}.opaca-table td{padding:.625rem 1rem;border-bottom:1px solid var(--opaca-border);font-size:.8125rem;color:var(--opaca-text)}.opaca-table tr:last-child td{border-bottom:none}.opaca-table tr:hover td{background-color:hsla(0,0%,100%,.01)}.opaca-table-wrapper{position:relative;width:100%;overflow:auto;border-radius:var(--opaca-radius-lg);border:1px solid var(--opaca-border);background:var(--opaca-card-bg);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.opaca-table-wrapper::-webkit-scrollbar{height:8px;width:8px}.opaca-table-wrapper::-webkit-scrollbar-track{background:rgba(0,0,0,0)}.opaca-table-wrapper::-webkit-scrollbar-thumb{background:var(--opaca-border);border-radius:10px}.opaca-table-wrapper::-webkit-scrollbar-thumb:hover{background:var(--opaca-text-dim)}.opaca-new-table{width:100%;caption-side:bottom;font-size:.875rem;border-collapse:collapse}.opaca-new-table .opaca-badge{padding:.2rem .5rem;font-size:.7rem;border-radius:4px;background:var(--opaca-surface);color:var(--opaca-text-muted);border:1px solid var(--opaca-border)}.opaca-new-table .opaca-btn-outline{background:rgba(0,0,0,0);border-color:var(--opaca-border);color:var(--opaca-text-muted)}.opaca-new-table .opaca-btn-outline:hover{border-color:var(--opaca-primary);color:var(--opaca-primary)}.opaca-table-header{background-color:hsla(0,0%,100%,.02);border-bottom:1px solid var(--opaca-border)}.opaca-table-head{position:sticky;top:0;z-index:10;background-color:var(--opaca-card-bg);height:3.5rem;padding:0 1rem;text-align:left;vertical-align:middle;font-weight:600;color:var(--opaca-text-muted);font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;white-space:nowrap;min-width:120px;transition:color .2s ease;box-shadow:inset 0 -1px 0 var(--opaca-border)}.opaca-table-head:hover{color:var(--opaca-text)}.opaca-table-head>div{display:flex;align-items:center;white-space:nowrap;gap:.5rem}.opaca-table-row{border-bottom:1px solid var(--opaca-border);transition:background-color var(--opaca-transition)}.opaca-table-row:last-child{border-bottom:0}.opaca-table-row:hover{background-color:var(--opaca-surface)}.opaca-table-cell{padding:1rem;vertical-align:middle;color:var(--opaca-text);font-size:.875rem;border-bottom:1px solid var(--opaca-border);max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opaca-table-cell.opaca-cell-interactive{cursor:pointer;transition:all .2s ease;border-bottom:2px solid rgba(0,0,0,0)}.opaca-table-cell.opaca-cell-interactive:hover{background-color:hsla(0,0%,100%,.04);color:var(--opaca-primary);border-bottom-color:var(--opaca-primary)}.opaca-table-footer{background-color:hsla(0,0%,100%,.02);font-weight:500}.opaca-table-caption{margin-top:1rem;font-size:.875rem;color:var(--opaca-text-muted)}.opaca-item-button:hover{background-color:hsla(0,0%,100%,.05) !important;border-color:var(--opaca-primary) !important}.opaca-item-button.active{background-color:rgba(var(--opaca-primary-rgb), 0.1) !important;border-color:var(--opaca-primary) !important;color:var(--opaca-primary)}.opaca-ui-btn{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;border-radius:var(--opaca-radius);font-size:.875rem;font-weight:500;transition:all var(--opaca-transition);cursor:pointer;border:1px solid rgba(0,0,0,0);outline:none}.opaca-ui-btn:focus-visible{box-shadow:0 0 0 2px var(--opaca-bg),0 0 0 4px var(--opaca-primary)}.opaca-ui-btn:disabled{pointer-events:none;opacity:.5}.opaca-ui-btn-size-default{height:2.25rem;padding:.5rem 1rem}.opaca-ui-btn-size-sm{height:2rem;padding:0 .75rem;font-size:.75rem}.opaca-ui-btn-size-lg{height:2.5rem;padding:0 2rem}.opaca-ui-btn-size-icon{height:2.25rem;width:2.25rem;padding:0}.opaca-ui-btn-default{background-color:var(--opaca-primary);color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.opaca-ui-btn-default:hover{background-color:var(--opaca-primary-hover)}.opaca-ui-btn-destructive{background-color:var(--opaca-error);color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.opaca-ui-btn-destructive:hover{background-color:#ef4444}.opaca-ui-btn-outline{border-color:var(--opaca-border);background-color:rgba(0,0,0,0);color:var(--opaca-text);box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.opaca-ui-btn-outline:hover{background-color:hsla(0,0%,100%,.05)}.opaca-ui-btn-secondary{background-color:var(--opaca-surface);color:var(--opaca-text);border-color:var(--opaca-border);box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.opaca-ui-btn-secondary:hover{background-color:hsla(0,0%,100%,.05)}.opaca-ui-btn-ghost{background-color:rgba(0,0,0,0);color:var(--opaca-text)}.opaca-ui-btn-ghost:hover{background-color:hsla(0,0%,100%,.05)}.opaca-ui-btn-link{background-color:rgba(0,0,0,0);color:var(--opaca-primary);text-decoration:underline;text-underline-offset:4px}.opaca-ui-btn-link:hover{text-decoration:none}.opaca-btn{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;padding:.5rem 1rem;border-radius:var(--opaca-radius);font-weight:500;font-size:.8125rem;cursor:pointer;transition:all var(--opaca-transition);border:none;font-family:inherit;line-height:1.4}.opaca-btn-primary{background-color:var(--opaca-primary);color:#fff}.opaca-btn-primary:hover{background-color:var(--opaca-primary-hover)}.opaca-btn-primary:disabled{opacity:.6;cursor:not-allowed}.opaca-btn-outline{background-color:rgba(0,0,0,0);border:1px solid var(--opaca-border);color:var(--opaca-text-muted)}.opaca-btn-outline:hover{border-color:var(--opaca-border-hover);color:var(--opaca-text);background-color:hsla(0,0%,100%,.02)}.opaca-item-button:hover{background-color:var(--opaca-brand-subtle) !important;border-color:var(--opaca-primary) !important;transform:translateY(-1px)}.opaca-item-button:active{transform:translateY(0)}.opaca-item-button.active{background-color:var(--opaca-brand-subtle) !important;border-color:var(--opaca-primary) !important;box-shadow:0 0 0 1px var(--opaca-primary)}.opaca-ui-input{display:flex;height:2.25rem;width:100%;border-radius:var(--opaca-radius);border:1px solid var(--opaca-border);background-color:var(--opaca-surface);padding:.25rem .75rem;font-size:.875rem;color:var(--opaca-text);box-shadow:0 1px 2px 0 rgba(0,0,0,.05);transition:border-color var(--opaca-transition),box-shadow var(--opaca-transition);outline:none}.opaca-ui-input::placeholder{color:var(--opaca-text-dim)}.opaca-ui-input:focus-visible{border-color:var(--opaca-primary);box-shadow:0 0 0 1px var(--opaca-primary)}.opaca-ui-input:disabled{cursor:not-allowed;opacity:.5}.opaca-ui-input[type=file]{border:0;background-color:rgba(0,0,0,0);font-size:.875rem;font-weight:500}.opaca-label{display:block;font-size:.75rem;font-weight:500;margin-bottom:.375rem;color:var(--opaca-text-muted);text-transform:uppercase;letter-spacing:.03em}.opaca-input{width:100%;padding:.5rem .75rem;border-radius:var(--opaca-radius);background-color:var(--opaca-surface);border:1px solid var(--opaca-border);color:var(--opaca-text);font-family:inherit;font-size:.8125rem;transition:border-color var(--opaca-transition),box-shadow var(--opaca-transition);outline:none}.opaca-input::placeholder{color:var(--opaca-text-dim)}.opaca-input:focus{border-color:var(--opaca-primary);box-shadow:0 0 0 1px var(--opaca-primary-glow)}.opaca-input.error{border-color:var(--opaca-error)}.opaca-input.error:focus{box-shadow:0 0 0 1px var(--opaca-error-bg)}.opaca-field-error{display:block;font-size:.75rem;color:var(--opaca-error);margin-top:.25rem}.opaca-badge{display:inline-flex;align-items:center;padding:.125rem .5rem;font-size:.6875rem;font-weight:500;border-radius:var(--opaca-radius);background-color:var(--opaca-primary-glow);color:var(--opaca-accent);letter-spacing:.02em}.opaca-toast-container{position:fixed;top:1.5rem;right:1.5rem;z-index:9999;display:flex;flex-direction:column;gap:.75rem;pointer-events:none}.opaca-toast{pointer-events:auto;min-width:280px;max-width:400px;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);padding:.875rem 1rem;border-radius:var(--opaca-radius-lg);display:flex;align-items:center;gap:.75rem;box-shadow:0 10px 25px -5px rgba(0,0,0,.4);animation:opaca-toast-in 300ms cubic-bezier(0.16, 1, 0.3, 1);transition:all var(--opaca-transition)}.opaca-toast.exit{opacity:0;transform:translateX(20px)}.opaca-toast-success{border-left:3px solid var(--opaca-success)}.opaca-toast-error{border-left:3px solid var(--opaca-error)}.opaca-toast-info{border-left:3px solid var(--opaca-accent)}.opaca-toast-message{font-size:.8125rem;font-weight:500;color:var(--opaca-text);line-height:1.4}.opaca-switch{position:relative;display:inline-flex;align-items:center;cursor:pointer;user-select:none;gap:.75rem}.opaca-switch input{position:absolute;opacity:0;width:0;height:0}.opaca-switch input:checked+.opaca-switch-track{background-color:var(--opaca-accent);border-color:var(--opaca-accent)}.opaca-switch input:checked+.opaca-switch-track .opaca-switch-thumb{left:18px}.opaca-switch input:disabled+.opaca-switch-track{background:var(--opaca-border);cursor:not-allowed;opacity:.6}.opaca-switch-track{width:36px;height:20px;background-color:var(--opaca-surface);border:1px solid var(--opaca-border);border-radius:20px;position:relative;transition:all var(--opaca-transition)}.opaca-switch-thumb{width:14px;height:14px;background-color:#fff;border-radius:50%;position:absolute;top:2px;left:2px;transition:all var(--opaca-transition);box-shadow:0 2px 4px rgba(0,0,0,.2)}.opaca-switch-label{font-size:.8125rem;font-weight:500}.opaca-pagination{display:flex;align-items:center;justify-content:space-between;padding:1rem;border-top:1px solid var(--opaca-border);background-color:var(--opaca-sidebar-bg)}.opaca-pagination-info{font-size:.75rem;color:var(--opaca-text-dim)}.opaca-pagination-actions{display:flex;gap:.5rem}.opaca-empty{padding:5rem 2rem;text-align:center;display:flex;flex-direction:column;align-items:center;gap:1rem}.opaca-empty-icon{width:48px;height:48px;border-radius:50%;background-color:var(--opaca-surface);display:flex;align-items:center;justify-content:center;color:var(--opaca-text-dim);margin-bottom:.5rem}.opaca-loading-screen{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;width:100%;background-color:var(--opaca-bg);color:var(--opaca-text);gap:2rem}.opaca-loading-logo-container{position:relative;display:flex;align-items:center;justify-content:center}.opaca-loading-logo-pulse{position:absolute;width:64px;height:64px;background-color:var(--opaca-primary);border-radius:var(--opaca-radius);opacity:.2;animation:opaca-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite}.opaca-loading-status{display:flex;align-items:center;gap:.75rem;font-size:.875rem;color:var(--opaca-text-muted);animation:opaca-fade-in 1s ease-out}.opaca-login-container{display:flex;align-items:center;justify-content:center;min-height:100vh;width:100%;background-color:var(--opaca-bg);font-family:var(--opaca-font);color:var(--opaca-text);-webkit-font-smoothing:antialiased}.opaca-login-card{width:100%;max-width:380px;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);padding:2rem}.opaca-login-header{text-align:center;margin-bottom:1.5rem}.opaca-login-logo{width:48px;height:48px;display:flex;align-items:center;justify-content:center;background-color:var(--opaca-primary);border-radius:var(--opaca-radius);margin:0 auto 1rem}.opaca-logo-circle{width:48px;height:48px;display:flex;align-items:center;justify-content:center;background-color:var(--opaca-primary);border-radius:var(--opaca-radius);color:#fff}.opaca-login-error{padding:.625rem .75rem;background-color:var(--opaca-error-bg);border:1px solid rgba(248,113,113,.2);color:var(--opaca-error);border-radius:var(--opaca-radius);margin-bottom:1.25rem;display:flex;align-items:center;gap:.5rem;font-size:.8125rem}.opaca-lexical-wrapper{display:flex;flex-direction:column;gap:.75rem}.opaca-lexical-modes{display:inline-flex;gap:2px;background-color:var(--opaca-surface);padding:3px;border-radius:var(--opaca-radius-lg);border:1px solid var(--opaca-border);align-self:flex-start;margin-bottom:.25rem}.opaca-lexical-modes .opaca-btn{padding:.4rem .8rem;font-size:.75rem;border-radius:var(--opaca-radius);border:none;background-color:rgba(0,0,0,0);color:var(--opaca-text-muted);font-weight:500;min-width:80px;transition:all var(--opaca-transition)}.opaca-lexical-modes .opaca-btn:hover{color:var(--opaca-text);background-color:hsla(0,0%,100%,.05)}.opaca-lexical-modes .opaca-btn.opaca-btn-primary{background-color:var(--opaca-primary);color:#fff;box-shadow:0 2px 4px rgba(0,0,0,.2)}.opaca-lexical-container{border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);background-color:var(--opaca-surface);overflow:hidden;transition:all var(--opaca-transition);display:flex;flex-direction:column}.opaca-lexical-container:focus-within{border-color:var(--opaca-accent);box-shadow:0 0 0 2px var(--opaca-primary-glow)}.opaca-lexical-container.mode-notion .opaca-lexical-content{padding:1.5rem 1rem}.opaca-lexical-container.is-readonly{background-color:hsla(0,0%,100%,.02);cursor:not-allowed}.opaca-lexical-container.is-readonly .opaca-lexical-content{padding:0rem}.opaca-lexical-toolbar{display:flex;flex-wrap:wrap;gap:.125rem;padding:.375rem;border-bottom:1px solid var(--opaca-border);background-color:var(--opaca-card-bg);align-items:center}.opaca-lexical-bubble-menu{background:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);padding:4px;display:flex;gap:4px;box-shadow:0 10px 15px -3px rgba(0,0,0,.4);backdrop-filter:blur(8px)}.opaca-lexical-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:var(--opaca-radius);background:rgba(0,0,0,0);border:none;color:var(--opaca-text-muted);cursor:pointer;transition:all var(--opaca-transition)}.opaca-lexical-btn:hover{background-color:hsla(0,0%,100%,.08);color:var(--opaca-text)}.opaca-lexical-btn.is-active{background-color:var(--opaca-primary-glow);color:var(--opaca-accent)}.opaca-lexical-divider{width:1px;height:18px;background-color:var(--opaca-border);margin:0 .25rem}.opaca-lexical-placeholder{color:var(--opaca-text-dim);position:absolute;top:1rem;left:1rem;pointer-events:none;font-style:normal;font-size:.875rem;opacity:.5}.opaca-lexical-editor-inner{position:relative;flex:1}.opaca-lexical-content{min-height:160px;padding:1rem;outline:none;line-height:1.6;color:var(--opaca-text);font-size:.9375rem}.opaca-lexical-content>*:first-child{margin-top:0}.opaca-lexical-content>*:last-child{margin-bottom:0}.opaca-lexical-content p{margin:.75em 0}.opaca-lexical-content .editor-heading-h1{font-size:2.25rem;font-weight:700;margin-top:1.5rem;margin-bottom:.75rem;color:var(--opaca-text)}.opaca-lexical-content .editor-heading-h2{font-size:1.875rem;font-weight:600;margin-top:1.25rem;margin-bottom:.5rem;color:var(--opaca-text)}.opaca-lexical-content .editor-text-bold{font-weight:700}.opaca-lexical-content .editor-text-italic{font-style:italic}.opaca-lexical-content .editor-text-underline{text-decoration:underline}.opaca-lexical-content .editor-text-strikethrough{text-decoration:line-through}.opaca-lexical-content .editor-text-code{background-color:hsla(0,0%,100%,.05);padding:2px 4px;border-radius:4px;font-family:monospace;font-size:.9em}.opaca-lexical-content ul{list-style-type:disc;padding-left:1.5rem;margin:.5rem 0}.opaca-lexical-content ol{list-style-type:decimal;padding-left:1.5rem;margin:.5rem 0}.opaca-lexical-content .editor-listitem{margin:.25rem 0}.opaca-lexical-content ul[data-type=taskList]{list-style:none;padding:0}.opaca-lexical-content ul[data-type=taskList] p{margin:0}.opaca-lexical-content ul[data-type=taskList] li{display:flex;margin-bottom:.25rem}.opaca-lexical-content ul[data-type=taskList] li>label{flex:0 0 auto;margin-right:.5rem;user-select:none}.opaca-lexical-content ul[data-type=taskList] li>div{flex:1 1 auto}.opaca-lexical-content ul[data-type=taskList] li input[type=checkbox]{cursor:pointer;width:1rem;height:1rem;margin-top:.2rem;accent-color:var(--opaca-primary)}.opaca-lexical-content ul[data-type=taskList] li[data-checked=true]>div>p{text-decoration:line-through;color:var(--opaca-text-muted)}.opaca-lexical-content blockquote{border-left:3px solid var(--opaca-border);padding-left:1rem;margin:1em 0;color:var(--opaca-text-dim);font-style:italic}.opaca-lexical-content .editor-image-wrapper{position:relative;display:inline-block;cursor:default;user-select:none;line-height:0}.opaca-lexical-content .editor-image-wrapper.is-selected{outline:3px solid var(--opaca-primary);outline-offset:2px;border-radius:4px;box-shadow:0 0 0 4px var(--opaca-primary-glow)}.opaca-lexical-content .editor-image-wrapper .editor-image-img{max-width:100%;height:auto;border-radius:var(--opaca-radius)}.opaca-lexical-content .editor-image-wrapper .editor-image-resizer{position:absolute;right:-6px;bottom:-6px;width:14px;height:14px;background-color:var(--opaca-primary);border:2px solid #fff;cursor:nwse-resize;z-index:20;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.3)}.opaca-lexical-content .editor-image-wrapper .editor-image-resizer:hover{background-color:var(--opaca-accent);transform:scale(1.2)}.opaca-lexical-content .editor-image-wrapper .editor-image-delete{position:absolute;top:-8px;right:-8px;width:24px;height:24px;background-color:var(--opaca-error);color:#fff;border:1px solid #fff;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:10;box-shadow:0 2px 4px rgba(0,0,0,.3);padding:0;transition:transform .2s}.opaca-lexical-content .editor-image-wrapper .editor-image-delete:hover{transform:scale(1.1);background-color:#ff4d4d}.opaca-lexical-content a{color:var(--opaca-primary);text-decoration:underline;text-underline-offset:2px}.opaca-lexical-content pre{background-color:var(--opaca-bg);color:var(--opaca-text);padding:1rem;border-radius:var(--opaca-radius);overflow-x:auto;border:1px solid var(--opaca-border);margin:1em 0}.opaca-lexical-content pre code{color:inherit;padding:0;background:none;font-size:.85rem}.opaca-lexical-content [contenteditable=true] p.is-editor-empty:first-child::before,.opaca-lexical-content [contenteditable=true] h1.is-empty::before,.opaca-lexical-content [contenteditable=true] h2.is-empty::before,.opaca-lexical-content [contenteditable=true] h3.is-empty::before,.opaca-lexical-content [contenteditable=true] [data-placeholder]::before{content:attr(data-placeholder);float:left;color:var(--opaca-text-muted);pointer-events:none;height:0;font-style:italic;opacity:.6}.opaca-lexical-bubble-menu{display:flex;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);padding:.25rem;gap:.125rem}.opaca-lexical-floating-menu{display:flex;align-items:center;margin-left:-32px}.opaca-lexical-btn-plus{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background:var(--opaca-surface);border:1px solid var(--opaca-border);color:var(--opaca-text-muted);cursor:pointer;transition:all var(--opaca-transition);font-size:1rem;margin-right:.5rem}.opaca-lexical-btn-plus:hover{background-color:var(--opaca-primary-glow);color:var(--opaca-primary);border-color:var(--opaca-primary)}.opaca-lexical-floating-menu-items{display:none;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);padding:.25rem;gap:.125rem;animation:opaca-fade-in 100ms ease-out}.opaca-lexical-floating-menu:hover .opaca-lexical-floating-menu-items{display:flex}.opaca-slash-menu{display:flex;flex-direction:column;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);padding:.5rem;max-height:300px;overflow-y:auto;min-width:250px}.opaca-slash-menu-item{display:flex;align-items:center;gap:.75rem;padding:.3rem;border:none;background:rgba(0,0,0,0);color:var(--opaca-text);border-radius:var(--opaca-radius);cursor:pointer;text-align:left;transition:background-color var(--opaca-transition)}.opaca-slash-menu-item:hover,.opaca-slash-menu-item.is-selected{background-color:var(--opaca-surface)}.opaca-slash-menu-icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background-color:var(--opaca-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);color:var(--opaca-text-muted)}.opaca-slash-menu-text{display:flex;flex-direction:column}.opaca-slash-menu-title{font-size:.8125rem;font-weight:500;color:var(--opaca-text)}.opaca-slash-menu-desc{font-size:.7rem;color:var(--opaca-text-muted)}.opaca-slash-menu-empty{padding:1rem;color:var(--opaca-text-muted);font-size:.8125rem;text-align:center}.opaca-sidebar-accordion{margin-bottom:.25rem;border:none !important;background:rgba(0,0,0,0) !important}.opaca-sidebar-accordion .opaca-sidebar-accordion-trigger{background:rgba(0,0,0,0);padding:1rem .75rem .5rem .75rem;font-size:.625rem;color:var(--opaca-text-dim);text-transform:uppercase;letter-spacing:.06em;font-weight:500;width:100%;display:flex;align-items:center;justify-content:space-between;cursor:pointer;transition:color var(--opaca-transition);border:none;outline:none}.opaca-sidebar-accordion .opaca-sidebar-accordion-trigger:hover{color:var(--opaca-text)}.opaca-sidebar-accordion .opaca-sidebar-accordion-trigger .opaca-sidebar-accordion-icon{width:12px;height:12px;stroke:var(--opaca-text-dim);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .2s cubic-bezier(0.87, 0, 0.13, 1)}.opaca-sidebar-accordion .opaca-sidebar-accordion-trigger[aria-expanded=true] .opaca-sidebar-accordion-icon{transform:rotate(180deg)}.opaca-sidebar-accordion .opaca-sidebar-accordion-content{display:grid;grid-template-rows:0fr;transition:grid-template-rows .2s cubic-bezier(0.87, 0, 0.13, 1)}.opaca-sidebar-accordion .opaca-sidebar-accordion-content[data-state=open]{grid-template-rows:1fr}.opaca-sidebar-accordion .opaca-sidebar-accordion-content .opaca-sidebar-accordion-content-inner{overflow:hidden;display:flex;flex-direction:column}.asset-manager-overlay{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;background-color:rgba(0,0,0,.5);padding:1rem}.asset-manager-container{background-color:var(--opaca-card-bg);border-radius:var(--opaca-radius);box-shadow:0 25px 50px -12px rgba(0,0,0,.5);width:100%;border:1px solid var(--opaca-border);max-width:56rem;height:600px;display:flex;flex-direction:column;color:var(--opaca-text);overflow:hidden}.asset-manager-header{padding:1.25rem 1.75rem;border-bottom:1px solid var(--opaca-border);display:flex;justify-content:space-between;align-items:center;background-color:var(--opaca-card-bg)}.asset-manager-header h2{font-size:1.125rem;font-weight:600;margin:0}.asset-manager-header .asset-manager-breadcrumbs{display:flex;align-items:center;gap:.5rem;margin-top:.25rem;font-size:.8125rem;color:var(--opaca-text-dim)}.asset-manager-header .asset-manager-breadcrumbs button{background:none;border:none;padding:0;color:inherit;cursor:pointer}.asset-manager-header .asset-manager-breadcrumbs button:hover{color:var(--opaca-accent);text-decoration:underline}.asset-manager-header .asset-manager-breadcrumbs .breadcrumb-separator{opacity:.5}.asset-manager-header .header-actions{display:flex;align-items:center;gap:1rem}.asset-manager-header .header-actions .bucket-selector{min-width:140px;height:36px}.asset-manager-header .close-button{color:var(--opaca-text-dim);background:rgba(0,0,0,0);border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all var(--opaca-transition);padding:.25rem;border-radius:6px}.asset-manager-header .close-button:hover{background-color:var(--opaca-surface);color:var(--opaca-text)}.asset-manager-upload-zone{padding:2rem;border-bottom:2px dashed var(--opaca-border);background-color:rgba(0,0,0,.2);cursor:pointer;text-align:center;position:relative;transition:all .2s;display:flex;flex-direction:column;align-items:center;justify-content:center}.asset-manager-upload-zone.uploading{pointer-events:none;opacity:.7}.asset-manager-upload-zone .upload-icon{margin-bottom:.75rem;color:var(--opaca-text-dim)}.asset-manager-upload-zone .upload-prompt{color:var(--opaca-text-dim);margin:0;font-size:.875rem}.asset-manager-upload-zone .upload-prompt span{color:var(--opaca-accent);font-weight:600}.asset-manager-upload-zone .uploading-status{display:flex;flex-direction:column;align-items:center;gap:.75rem}.asset-manager-upload-zone .uploading-status .status-text{color:var(--opaca-accent);font-weight:600;font-size:.875rem}.asset-manager-grid-container{flex:1;overflow-y:auto;padding:1.5rem;background-color:rgba(0,0,0,.1)}.asset-manager-grid-container .loading-assets,.asset-manager-grid-container .no-assets{display:flex;justify-content:center;align-items:center;height:100%;color:#9ca3af}.asset-manager-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(140px, 1fr));gap:1.25rem}.asset-manager-card{position:relative;background-color:var(--opaca-surface);border-radius:12px;border:1px solid var(--opaca-border);overflow:hidden;cursor:pointer;transition:all var(--opaca-transition);display:flex;flex-direction:column}.asset-manager-card:hover{border-color:var(--opaca-accent);transform:translateY(-2px);box-shadow:var(--opaca-shadow-lg)}.asset-manager-card:hover .selection-overlay{opacity:1}.asset-manager-card .asset-thumb{aspect-ratio:16/10;display:flex;align-items:center;justify-content:center;background-color:var(--opaca-bg-alt);overflow:hidden;position:relative}.asset-manager-card .asset-thumb img{width:100%;height:100%;object-fit:cover}.asset-manager-card .asset-thumb .folder-icon{color:#eab308}.asset-manager-card .asset-info{padding:.75rem;display:flex;flex-direction:column;gap:.25rem;background-color:var(--opaca-card-bg);flex:1}.asset-manager-card .asset-info .filename{font-size:.8125rem;font-weight:500;color:var(--opaca-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.asset-manager-card .asset-info .file-meta{font-size:.6875rem;color:var(--opaca-text-dim)}.asset-manager-card .selection-overlay{position:absolute;inset:0;background-color:rgba(var(--opaca-accent-rgb), 0.1);display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity var(--opaca-transition);pointer-events:none}.asset-manager-card .selection-overlay .select-badge{background-color:var(--opaca-accent);color:#fff;font-size:.75rem;font-weight:600;padding:.375rem .75rem;border-radius:9999px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1)}.asset-manager-card.folder-card .asset-thumb{background-color:rgba(234,179,8,.05)}.file-field-container{margin-bottom:2rem;background-color:rgba(0,0,0,0);padding:0;border:none;box-shadow:none}.file-field-label-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem}.file-field-label-row label{display:block;font-size:.875rem;font-weight:500;color:var(--opaca-text);text-transform:capitalize}.file-field-label-row .upload-error{font-size:.75rem;color:#ef4444;font-weight:500}.file-field-optimistic-card{display:flex;flex-direction:column;gap:.5rem;padding:1rem;border:1px solid var(--opaca-primary);border-radius:var(--opaca-radius);background-color:rgba(var(--opaca-primary-rgb), 0.1)}.file-field-optimistic-card .optimistic-info{display:flex;align-items:center;gap:1rem;opacity:.7}.file-field-optimistic-card .optimistic-info img{width:4rem;height:4rem;object-fit:cover;border-radius:.25rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.file-field-optimistic-card .optimistic-info .file-icon-placeholder{width:4rem;height:4rem;background-color:#e5e7eb;border-radius:.25rem;display:flex;align-items:center;justify-content:center}.file-field-optimistic-card .optimistic-info .file-icon-placeholder span{font-size:.75rem;font-family:monospace}.file-field-optimistic-card .optimistic-info .optimistic-details{display:flex;flex-direction:column;flex:1;min-width:0}.file-field-optimistic-card .optimistic-info .optimistic-details .filename{font-size:.875rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-field-optimistic-card .optimistic-info .optimistic-details .progress-text{font-size:.75rem;color:#2563eb;margin-bottom:.25rem;font-weight:600}.file-field-optimistic-card .optimistic-info .optimistic-details .progress-bar-bg{width:100%;background-color:#bfdbfe;border-radius:9999px;height:.375rem}.file-field-optimistic-card .optimistic-info .optimistic-details .progress-bar-bg .progress-bar-fill{background-color:#2563eb;height:100%;border-radius:9999px;transition:width .3s}.file-field-asset-card{display:flex;flex-direction:column;gap:1rem}.file-field-asset-info{display:flex;align-items:center;padding:1rem;border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);background-color:var(--opaca-card-bg);justify-content:space-between}.file-field-asset-info .asset-preview{display:flex;align-items:center;gap:1rem}.file-field-asset-info .asset-preview img{width:4rem;height:4rem;object-fit:cover;border-radius:.25rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);border:1px solid #e5e7eb}.file-field-asset-info .asset-preview .file-icon-placeholder{width:4rem;height:4rem;background-color:var(--opaca-border);border-radius:.25rem;display:flex;align-items:center;justify-content:center;border:1px solid var(--opaca-border)}.file-field-asset-info .asset-preview .file-icon-placeholder span{font-size:.75rem;font-family:monospace;color:var(--opaca-subtitle)}.file-field-asset-info .asset-preview .asset-details{display:flex;flex-direction:column}.file-field-asset-info .asset-preview .asset-details .filename{font-size:.875rem;font-weight:500;color:var(--opaca-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px}.file-field-asset-info .asset-preview .asset-details .filesize{font-size:.75rem;color:var(--opaca-subtitle);font-family:monospace;margin-top:.125rem}.file-field-asset-info .asset-actions{display:flex;gap:.75rem}.file-field-asset-info .asset-actions button{font-size:.875rem;font-weight:500;background:rgba(0,0,0,0);border:none;cursor:pointer;transition:color .2s}.file-field-asset-info .asset-actions button.replace-button{color:var(--opaca-primary)}.file-field-asset-info .asset-actions button.replace-button:hover{opacity:.8}.file-field-asset-info .asset-actions button.remove-button{color:var(--opaca-error)}.file-field-asset-info .asset-actions button.remove-button:hover{opacity:.8}.file-field-metadata{padding-left:1rem;border-left:2px solid #bfdbfe;display:flex;flex-direction:column;gap:.75rem;padding-top:.5rem}.file-field-metadata h4{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:#6b7280;font-weight:600;margin-bottom:.5rem}.file-field-metadata .metadata-field label{display:block;font-size:.75rem;font-weight:500;color:var(--opaca-subtitle);margin-bottom:.25rem;text-transform:capitalize}.file-field-metadata .metadata-field label .required{color:#ef4444}.file-field-metadata .metadata-field input,.file-field-metadata .metadata-field textarea{width:100%;font-size:.875rem;border:1px solid #d1d5db;border-radius:.375rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05);padding:.5rem .75rem;outline:none;transition:all .2s}.file-field-metadata .metadata-field input:focus,.file-field-metadata .metadata-field textarea:focus{border-color:#3b82f6;outline:1px solid #3b82f6}.file-field-empty-button{width:100%;padding:3.5rem 0;border:2px dashed var(--opaca-border);border-radius:var(--opaca-radius);color:var(--opaca-text-dim);background-color:var(--opaca-surface);cursor:pointer;transition:all var(--opaca-transition);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem}.file-field-empty-button:hover{border-color:var(--opaca-primary);color:var(--opaca-accent);background-color:rgba(124,58,237,.05)}.file-field-empty-button svg{width:2rem;height:2rem;color:#9ca3af}.file-field-empty-button span{font-weight:500;font-size:.875rem}.opaca-ui-collapsible{display:flex;flex-direction:column;border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);background-color:rgba(0,0,0,0);overflow:hidden;margin-bottom:2rem;transition:border-color var(--opaca-transition)}.opaca-ui-collapsible-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:1rem 1.25rem;font-size:.875rem;font-weight:500;text-align:left;background-color:var(--opaca-surface);color:var(--opaca-text);border:none;border-bottom:1px solid rgba(0,0,0,0);cursor:pointer;transition:all var(--opaca-transition)}.opaca-ui-collapsible-trigger:hover{background-color:var(--opaca-border)}.opaca-ui-collapsible-trigger[aria-expanded=true]{border-bottom-color:var(--opaca-border)}.opaca-ui-collapsible-trigger[aria-expanded=true] .opaca-ui-collapsible-icon{transform:rotate(180deg)}.opaca-ui-collapsible-icon{width:.875rem;height:.875rem;transition:transform var(--opaca-transition);fill:none;stroke:var(--opaca-text-muted);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.opaca-ui-collapsible-content{padding:1.25rem;background-color:rgba(0,0,0,0);color:var(--opaca-text)}.opaca-ui-collapsible-content[data-state=closed]{display:none}.opaca-ui-collapsible-content[data-state=open]{animation:collapsible-slide-down 200ms ease-out}@keyframes collapsible-slide-down{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.opaca-ui-dialog-portal{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center}.opaca-ui-dialog-overlay{position:fixed;inset:0;background-color:rgba(0,0,0,.8);backdrop-filter:blur(4px);transition:opacity .2s;border:none;padding:0;margin:0;cursor:default;width:100%;height:100%}.opaca-ui-dialog-wrapper{position:relative;z-index:10000;width:100%;height:100%;padding:1rem;display:flex;flex-direction:column;align-items:center;justify-content:center;pointer-events:none}.opaca-ui-dialog-content{pointer-events:auto;position:relative;width:100%;max-height:calc(100vh - 2rem);overflow-y:auto;border-radius:var(--opaca-radius-lg);border:1px solid var(--opaca-border);background-color:var(--opaca-card-bg);padding:1.5rem;box-shadow:0 20px 25px -5px rgba(0,0,0,.3),0 8px 10px -6px rgba(0,0,0,.2);color:var(--opaca-text);animation:opacaDialogIn .2s cubic-bezier(0.16, 1, 0.3, 1)}.opaca-ui-dialog-content.opaca-dialog-max-w{max-width:425px}@keyframes opacaDialogIn{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}.opaca-ui-dialog-header{display:flex;flex-direction:column;gap:.375rem;text-align:center}@media(min-width: 640px){.opaca-ui-dialog-header{text-align:left}}.opaca-ui-dialog-title{font-size:1.125rem;font-weight:600;line-height:1;letter-spacing:-0.025em;color:var(--opaca-text)}.opaca-ui-dialog-description{font-size:.875rem;color:var(--opaca-text-muted)}.opaca-ui-dialog-footer{display:flex;flex-direction:column-reverse;margin-top:1rem;gap:.5rem}@media(min-width: 640px){.opaca-ui-dialog-footer{flex-direction:row;justify-content:flex-end;gap:.5rem}}.opaca-ui-group{display:flex;flex-direction:column;gap:1.25rem;padding:1.5rem;border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);background-color:rgba(0,0,0,0);margin-bottom:2rem}.opaca-ui-group-header{font-size:.75rem;font-weight:500;margin-bottom:.5rem;color:var(--opaca-text-muted);text-transform:uppercase;letter-spacing:.03em}.media-registry-view{display:flex;flex-direction:column;height:100%}.media-registry-header{margin-bottom:2rem;flex-shrink:0}.media-registry-header .opaca-title{font-size:1.5rem;font-weight:600;letter-spacing:-0.025em}.media-registry-header .opaca-subtitle{font-size:.875rem;color:var(--opaca-text-muted);margin-top:.25rem}.media-registry-header-actions{display:flex;gap:.75rem}.media-registry-icon-mr{margin-right:.5rem}.media-registry-body{flex:1;display:flex;flex-direction:column;padding:0;overflow:visible;border:none;background:rgba(0,0,0,0)}.media-registry-toolbar{display:flex;justify-content:space-between;align-items:center;padding:1rem;background:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg, 0.5rem);margin-bottom:1.5rem;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.media-registry-filters{display:flex;gap:.75rem;align-items:center;width:100%;max-width:600px}.media-registry-search{position:relative;flex:1;min-width:320px}.media-registry-search .search-icon{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--opaca-text-dim)}.media-registry-search .opaca-ui-input{padding-left:2.5rem}.media-registry-select-trigger{width:140px;flex-shrink:0}.media-registry-view-toggles{display:flex;gap:.25rem;background:var(--opaca-surface);padding:.25rem;border-radius:var(--opaca-radius-lg, 0.5rem);border:1px solid var(--opaca-border)}.media-registry-toggle-btn{padding:.4rem;border-radius:var(--opaca-radius, 0.375rem);border:none;cursor:pointer;transition:all .2s;background:rgba(0,0,0,0);color:var(--opaca-text-dim);display:flex;align-items:center;justify-content:center}.media-registry-toggle-btn:hover{color:#fff}.media-registry-toggle-btn.active{background-color:var(--opaca-primary);color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.media-registry-grid{display:grid;grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));gap:1.5rem;margin-top:.5rem}.media-registry-card{position:relative;background:var(--opaca-card-bg);border-radius:.75rem;border:1px solid var(--opaca-border);overflow:hidden;cursor:pointer;transition:all .2s;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.media-registry-card:hover{border-color:var(--opaca-border-hover)}.media-registry-card.active{border-color:var(--opaca-primary);box-shadow:0 0 0 1px var(--opaca-primary)}.media-registry-card-thumb{height:160px;background:var(--opaca-surface);display:flex;align-items:center;justify-content:center;border-bottom:1px solid var(--opaca-border);position:relative;overflow:hidden}.media-registry-card-thumb img{width:100%;height:100%;object-fit:cover;transition:transform .5s}.media-registry-card-thumb svg.folder-icon{color:#eab308;transition:transform .3s}.media-registry-card-thumb .media-registry-overlay{position:absolute;inset:0;background:rgba(0,0,0,.4);opacity:0;transition:opacity .2s;display:flex;align-items:center;justify-content:center}.media-registry-card:hover .media-registry-card-thumb img,.media-registry-card:hover .media-registry-card-thumb svg.folder-icon{transform:scale(1.05)}.media-registry-card:hover .media-registry-overlay{opacity:1}.media-registry-overlay-btn{border-radius:9999px;background-color:hsla(0,0%,100%,.1);backdrop-filter:blur(12px);color:#fff;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;transition:all .2s}.media-registry-overlay-btn:hover{background-color:#fff;color:#000}.media-registry-card-body{padding:1rem}.media-registry-card-title{font-size:.875rem;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--opaca-text)}.media-registry-card-meta{font-size:.75rem;color:var(--opaca-text-dim);display:flex;justify-content:space-between;margin-top:.375rem}.media-registry-card-meta .meta-type{text-transform:uppercase;letter-spacing:.05em;font-size:.65rem;font-weight:600}.media-registry-pagination{display:flex;align-items:center;justify-content:space-between;padding:1rem;background:var(--opaca-surface);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg, 0.5rem);margin-top:2rem}.media-registry-pagination .info{font-size:.875rem;color:var(--opaca-text-muted)}.media-registry-pagination .actions{display:flex;gap:.5rem}.media-sheet-flex{flex:1;display:flex;flex-direction:column}.media-sheet-body{flex:1;overflow-y:auto;padding-right:.5rem;margin-right:-0.5rem}.media-sheet-preview{height:12rem;border-radius:var(--opaca-radius-lg, 0.5rem);background:var(--opaca-surface);border:1px solid var(--opaca-border);display:flex;align-items:center;justify-content:center;overflow:hidden;margin-bottom:1rem;position:relative}.media-sheet-preview img{width:100%;height:100%;object-fit:contain}.media-sheet-preview .overlay{position:absolute;inset:0;background:rgba(0,0,0,.4);opacity:0;transition:opacity .2s;display:flex;align-items:center;justify-content:center}.media-sheet-preview:hover .overlay{opacity:1}.media-sheet-form{display:flex;flex-direction:column;gap:1rem}.media-sheet-group{display:flex;flex-direction:column;gap:.5rem}.media-sheet-textarea{display:flex;min-height:80px;width:100%;border-radius:var(--opaca-radius, 0.375rem);border:1px solid var(--opaca-border);background-color:var(--opaca-surface);padding:.5rem .75rem;font-size:.875rem;color:var(--opaca-text);outline:none;font-family:inherit}.media-sheet-textarea::placeholder{color:var(--opaca-text-dim)}.media-sheet-textarea:focus-visible{border-color:var(--opaca-primary);box-shadow:0 0 0 1px var(--opaca-primary)}.media-sheet-meta-box{background:hsla(0,0%,100%,.02);padding:1rem;border-radius:var(--opaca-radius-lg, 0.5rem);border:1px solid var(--opaca-border);display:flex;flex-direction:column;gap:.75rem;margin-top:1.5rem}.media-sheet-meta-row{display:flex;justify-content:space-between;align-items:center;font-size:.875rem}.media-sheet-meta-row .label{color:var(--opaca-text-dim)}.media-sheet-meta-row .value{color:#fff;font-weight:500}.media-sheet-meta-row .value-mono{font-family:monospace;font-size:.75rem;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.media-sheet-actions{display:flex;gap:.75rem;padding-top:1.5rem;margin-top:1.5rem}.media-sheet-actions button{flex:1}.media-preview-container{flex:1;display:flex;flex-direction:column;padding:1.5rem;background:rgba(15,15,15,.7);backdrop-filter:blur(24px) saturate(180%);border-radius:.5rem;overflow:hidden;border:1px solid hsla(0,0%,100%,.1);box-shadow:0 25px 50px -12px rgba(0,0,0,.5);max-width:90vw;max-height:90vh;animation:opaca-zoom-in .3s cubic-bezier(0.16, 1, 0.3, 1)}@media(min-width: 640px){.media-preview-container{padding:1rem}}@keyframes opaca-zoom-in{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}.media-preview-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem;flex-shrink:0;z-index:10}.media-preview-title-group{display:flex;align-items:center;gap:.75rem}.media-preview-title-group h2{font-size:1.25rem;font-weight:600;color:#fff;margin:0}.media-preview-title-group .badge{padding:.125rem .5rem;border-radius:.25rem;font-size:.75rem;font-family:monospace;background:hsla(0,0%,100%,.1);color:#fff;border:1px solid hsla(0,0%,100%,.2)}.media-preview-close-btn{color:#fff;background:rgba(0,0,0,0);border-radius:9999px;height:2.5rem;width:2.5rem;display:flex;align-items:center;justify-content:center;border:none;cursor:pointer;transition:background .2s}.media-preview-close-btn:hover{background:hsla(0,0%,100%,.1)}.media-preview-body{flex:1;display:flex;align-items:center;justify-content:center;min-height:0;position:relative}.media-preview-body img{max-width:100%;max-height:100%;object-fit:contain;filter:drop-shadow(0 25px 25px rgba(0, 0, 0, 0.5))}.media-preview-no-rich{text-align:center;padding:2rem;background:hsla(0,0%,100%,.05);border-radius:1rem;border:1px solid hsla(0,0%,100%,.1);backdrop-filter:blur(4px)}.media-preview-no-rich .icon-wrapper{display:flex;justify-content:center;margin-bottom:1.5rem}.media-preview-no-rich p{color:var(--opaca-text-dim);margin-bottom:1.5rem}.media-preview-footer{margin-top:2rem;display:flex;justify-content:center;gap:1rem;flex-shrink:0}.media-preview-stat{background:hsla(0,0%,100%,.03);backdrop-filter:blur(8px);padding:.75rem 1.5rem;border-radius:1rem;border:1px solid hsla(0,0%,100%,.05);text-align:center;transition:all .2s}.media-preview-stat:hover{background:hsla(0,0%,100%,.06);transform:translateY(-2px)}.media-preview-stat .label{font-size:.75rem;color:var(--opaca-text-dim);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem}.media-preview-stat .value{font-weight:600;color:#fff}.media-dialog-create-body{padding:1rem 0}.media-bucket-settings{display:flex;flex-direction:column;gap:1.5rem;padding:1rem 0}.media-bucket-settings .bucket-setting-row{display:flex;flex-direction:column;gap:.75rem}.media-bucket-settings .bucket-setting-row .bucket-name{font-size:.75rem;font-weight:600;color:var(--opaca-text-dim);text-transform:uppercase;letter-spacing:.05em}.media-bucket-settings .bucket-setting-row .color-presets{display:flex;flex-wrap:wrap;gap:.5rem}.media-bucket-settings .bucket-setting-row .color-presets .color-bubble{width:24px;height:24px;border-radius:50%;border:2px solid rgba(0,0,0,0);cursor:pointer;transition:all var(--opaca-transition);padding:0;display:flex;align-items:center;justify-content:center}.media-bucket-settings .bucket-setting-row .color-presets .color-bubble:hover{transform:scale(1.1)}.media-bucket-settings .bucket-setting-row .color-presets .color-bubble.active{border-color:#fff;box-shadow:0 0 0 2px var(--opaca-primary)}.media-registry-dialog-sm{max-width:400px}.opaca-ui-radio-group{display:grid;gap:.75rem}.opaca-ui-radio-item{display:flex;align-items:center;gap:.75rem}.opaca-ui-radio-item input[type=radio]{appearance:none;margin:0;width:1.125rem;height:1.125rem;border:1px solid var(--opaca-border);border-radius:50%;outline:none;cursor:pointer;position:relative;background-color:var(--opaca-surface);transition:all var(--opaca-transition)}.opaca-ui-radio-item input[type=radio]:hover:not(:disabled){border-color:var(--opaca-accent)}.opaca-ui-radio-item input[type=radio]:checked{border-color:var(--opaca-primary);background-color:var(--opaca-primary)}.opaca-ui-radio-item input[type=radio]:checked::after{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);width:.375rem;height:.375rem;border-radius:50%;background-color:#fff}.opaca-ui-radio-item input[type=radio]:focus-visible{box-shadow:0 0 0 2px var(--opaca-primary-glow)}.opaca-ui-radio-item input[type=radio]:disabled{cursor:not-allowed;opacity:.5}.opaca-ui-radio-item label{cursor:pointer;font-size:.8125rem;font-weight:400;color:var(--opaca-text)}.opaca-ui-radio-item label.disabled{cursor:not-allowed;opacity:.5}.opaca-ui-select{position:relative;width:100%}.opaca-ui-select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-width:160px;padding:.5rem .75rem;font-size:.8125rem;background-color:var(--opaca-surface);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);color:var(--opaca-text);cursor:pointer;transition:all var(--opaca-transition);text-align:left;outline:none}.opaca-ui-select-trigger:hover{border-color:var(--opaca-border-hover);background-color:hsla(0,0%,100%,.02)}.opaca-ui-select-trigger:focus{border-color:var(--opaca-primary);box-shadow:0 0 0 1px var(--opaca-primary-glow)}.opaca-ui-select-trigger:disabled{opacity:.5;cursor:not-allowed}.opaca-ui-select-trigger .trigger-placeholder{color:var(--opaca-text-dim)}.opaca-ui-select-trigger .trigger-icon{color:var(--opaca-text-dim);transition:transform var(--opaca-transition)}.opaca-ui-select-trigger[data-state=open] .trigger-icon{transform:rotate(180deg)}.opaca-ui-select-portal{position:fixed;z-index:1000;pointer-events:none}.opaca-ui-select-content{pointer-events:auto;min-width:8rem;overflow:hidden;background-color:var(--opaca-card-bg);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);box-shadow:0 10px 25px -5px rgba(0,0,0,.4);padding:.25rem;animation:opaca-select-in 150ms cubic-bezier(0.16, 1, 0.3, 1);transform-origin:top}@keyframes opaca-select-in{from{opacity:0;transform:scale(0.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}.opaca-ui-select-item{display:flex;align-items:center;width:100%;padding:.375rem .5rem;font-size:.8125rem;color:var(--opaca-text-muted);border-radius:var(--opaca-radius);cursor:pointer;transition:all var(--opaca-transition);border:none;background:rgba(0,0,0,0);text-align:left}.opaca-ui-select-item:hover{background-color:hsla(0,0%,100%,.05);color:var(--opaca-text)}.opaca-ui-select-item[data-selected=true]{background-color:var(--opaca-primary-glow);color:var(--opaca-accent);font-weight:500}.opaca-ui-select-label{padding:.375rem .5rem;font-size:.75rem;font-weight:600;color:var(--opaca-text-dim);text-transform:uppercase;letter-spacing:.05em}.opaca-ui-select-separator{height:1px;background-color:var(--opaca-border);margin:.25rem -0.25rem}.opaca-ui-sheet-portal{position:fixed;inset:0;z-index:9999;display:flex;justify-content:flex-end}.opaca-ui-sheet-overlay{position:fixed;inset:0;background-color:rgba(0,0,0,.8);backdrop-filter:blur(4px);transition:opacity .2s;border:none;padding:0;margin:0;cursor:default;width:100%;height:100%}.opaca-ui-sheet-wrapper{position:relative;z-index:10000;height:100%;pointer-events:none;display:flex;justify-content:flex-end;width:100%}.opaca-ui-sheet-content{pointer-events:auto;position:relative;z-index:50;display:flex;height:100%;width:100%;flex-direction:column;border-left:1px solid var(--opaca-border);background-color:var(--opaca-card-bg);padding:1.5rem;box-shadow:-10px 0 25px -5px rgba(0,0,0,.2);overflow-y:auto;animation:opacaSlideInRight .3s cubic-bezier(0.16, 1, 0.3, 1);color:var(--opaca-text)}@media(min-width: 640px){.opaca-ui-sheet-content{width:400px;max-width:100vw}}@media(min-width: 1024px){.opaca-ui-sheet-content{width:500px}}.opaca-ui-sheet-close{position:absolute;right:1rem;top:1rem;border-radius:50%;opacity:.7;transition:all .2s ease;background:rgba(0,0,0,0);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:.5rem}.opaca-ui-sheet-close:hover{opacity:1;background-color:hsla(0,0%,100%,.05);color:var(--opaca-text)}.opaca-ui-sheet-close:focus-visible{outline:none;box-shadow:0 0 0 2px var(--opaca-primary)}.opaca-ui-sheet-close-icon{height:1rem;width:1rem;color:var(--opaca-text-muted)}.opaca-ui-sheet-header{display:flex;flex-direction:column;gap:.5rem;margin-bottom:1.5rem;text-align:center}@media(min-width: 640px){.opaca-ui-sheet-header{text-align:left}}.opaca-ui-sheet-title{font-size:1.125rem;font-weight:600;color:var(--opaca-text);margin:0}.opaca-ui-sheet-description{font-size:.875rem;color:var(--opaca-text-muted);margin:0}.opaca-ui-sheet-footer{display:flex;flex-direction:column-reverse;margin-top:auto;padding-top:1.5rem;border-top:1px solid var(--opaca-border);gap:.75rem}@media(min-width: 640px){.opaca-ui-sheet-footer{flex-direction:row;justify-content:flex-end;gap:.5rem}}.opaca-ui-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}@keyframes opacaSlideInRight{from{transform:translateX(100%)}to{transform:translateX(0)}}.opaca-ui-tabs{display:flex;flex-direction:column;width:100%}.opaca-ui-tabs-list{display:flex;background-color:var(--opaca-surface);padding:.25rem;border-radius:var(--opaca-radius-lg);overflow-x:auto;gap:.25rem;align-items:center;justify-content:flex-start;border:1px solid var(--opaca-border)}.opaca-ui-tabs-trigger{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap;border-radius:var(--opaca-radius);padding:.5rem 1rem;font-size:.8125rem;font-weight:500;color:var(--opaca-text-muted);background-color:rgba(0,0,0,0);border:none;cursor:pointer;transition:all var(--opaca-transition)}.opaca-ui-tabs-trigger:hover{color:var(--opaca-text);background-color:hsla(0,0%,100%,.05)}.opaca-ui-tabs-trigger[data-state=active]{background-color:var(--opaca-primary);color:#fff;box-shadow:0 4px 12px var(--opaca-primary-glow)}.opaca-ui-tabs-trigger:disabled{opacity:.5;cursor:not-allowed}.opaca-ui-tabs-content{margin-top:1rem;padding:1.25rem;border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);background-color:rgba(0,0,0,0);color:var(--opaca-text)}.opaca-ui-tabs-content[data-state=inactive]{display:none}.opaca-data-detail-sheet{width:100% !important}@media(min-width: 640px){.opaca-data-detail-sheet{width:600px !important;max-width:95vw !important}}.opaca-detail-list{display:flex;flex-direction:column;gap:1rem}.opaca-detail-item-card{background:var(--opaca-surface);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius-lg);overflow:hidden;transition:all var(--opaca-transition);box-shadow:0 1px 3px rgba(0,0,0,.05)}.opaca-detail-item-card:hover{border-color:var(--opaca-border-hover);box-shadow:0 4px 12px rgba(0,0,0,.1)}.opaca-detail-item-header{padding:.75rem 1rem;background:hsla(0,0%,100%,.03);border-bottom:1px solid var(--opaca-border);display:flex;align-items:center}.opaca-detail-item-content{padding:1rem}.opaca-detail-grid{display:flex;flex-direction:column;gap:1.25rem}.opaca-detail-grid.nested{padding:1rem;background:hsla(0,0%,100%,.015);border:1px solid var(--opaca-border);border-radius:var(--opaca-radius);margin-top:.5rem}.opaca-detail-row{display:flex;flex-direction:column;gap:.25rem}.opaca-detail-label{font-size:.75rem;font-weight:600;color:var(--opaca-text-muted);text-transform:uppercase;letter-spacing:.05em}.opaca-detail-value-container{font-size:.9375rem;color:var(--opaca-text)}.opaca-detail-value{white-space:pre-wrap;word-break:break-word}.opaca-badge-interactive{cursor:pointer;transition:all .2s ease}.opaca-badge-interactive:hover{background:var(--opaca-surface) !important;border-color:var(--opaca-primary) !important;color:var(--opaca-primary) !important;transform:translateY(-1px);box-shadow:0 2px 4px rgba(0,0,0,.1)}.opaca-row-field{display:flex;flex-wrap:wrap;gap:1rem;margin-bottom:1.25rem}.opaca-row-field .row-item{flex:1;min-width:0}.opaca-row-field .row-item .opaca-form-group{margin-bottom:0}.opaca-separator{flex-shrink:0;background-color:var(--opaca-border)}.opaca-separator.horizontal{height:1px;width:100%}.opaca-separator.vertical{width:1px;height:100%}.opaca-locale-switcher{display:flex;align-items:center;gap:.5rem;background:var(--opaca-card-bg);padding:.25rem;border-radius:var(--opaca-radius);border:1px solid var(--opaca-border);box-shadow:var(--opaca-shadow-sm)}.opaca-locale-btn{background:none;border:none;padding:.375rem .75rem;border-radius:calc(var(--opaca-radius) - 2px);font-size:.75rem;font-weight:600;color:var(--opaca-text-dim);cursor:pointer;transition:all var(--opaca-transition)}.opaca-locale-btn:hover{color:var(--opaca-text);background:hsla(0,0%,100%,.05)}.opaca-locale-btn.active{background:var(--opaca-accent);color:#fff;box-shadow:0 2px 4px rgba(0,0,0,.2)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opacacms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "bun run ../../scripts/build.ts && tsc --emitDeclarationOnly",
|
|
6
6
|
"build:publish": "bun run ../../scripts/build.ts --publish && tsc --emitDeclarationOnly",
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"opacacms": "./dist/cli/index.js"
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
|
+
"./admin.css": {
|
|
31
|
+
"import": "./dist/admin.css"
|
|
32
|
+
},
|
|
30
33
|
".": {
|
|
31
34
|
"types": "./dist/index.d.ts",
|
|
32
35
|
"import": "./dist/index.js"
|
|
@@ -159,5 +162,8 @@
|
|
|
159
162
|
"react": "^19.2.4",
|
|
160
163
|
"react-dom": "^19.2.4",
|
|
161
164
|
"zod": "^4.3.6"
|
|
162
|
-
}
|
|
165
|
+
},
|
|
166
|
+
"files": [
|
|
167
|
+
"dist"
|
|
168
|
+
]
|
|
163
169
|
}
|
package/bun.lock
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"lockfileVersion": 1,
|
|
3
|
-
"configVersion": 1,
|
|
4
|
-
"workspaces": {
|
|
5
|
-
"": {
|
|
6
|
-
"name": "opacacms",
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"hono": "^4.11.4",
|
|
9
|
-
"zod": "^4.3.5",
|
|
10
|
-
},
|
|
11
|
-
"devDependencies": {
|
|
12
|
-
"@types/bun": "latest",
|
|
13
|
-
},
|
|
14
|
-
"peerDependencies": {
|
|
15
|
-
"typescript": "^5",
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
"packages": {
|
|
20
|
-
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
|
|
21
|
-
|
|
22
|
-
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
|
23
|
-
|
|
24
|
-
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
|
|
25
|
-
|
|
26
|
-
"hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="],
|
|
27
|
-
|
|
28
|
-
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
29
|
-
|
|
30
|
-
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
31
|
-
|
|
32
|
-
"zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="],
|
|
33
|
-
}
|
|
34
|
-
}
|
package/dist/admin/index.css
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/* src/admin/ui/styles/accordion.scss */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/* src/admin/ui/styles/button.scss */
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/* src/admin/ui/styles/collapsible.scss */
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/* src/admin/ui/styles/dialog.scss */
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/* src/admin/ui/styles/group.scss */
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/* src/admin/ui/styles/input.scss */
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/* src/admin/ui/styles/label.scss */
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/* src/admin/ui/styles/radio-group.scss */
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/* src/admin/ui/styles/select.scss */
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/* src/admin/ui/styles/sheet.scss */
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/* src/admin/ui/styles/tabs.scss */
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/* src/admin/ui/styles/index.scss */
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/* src/admin/ui/styles/asset-manager.scss */
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/* src/admin/ui/styles/lexical.scss */
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/* src/admin/ui/styles/data-detail.scss */
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/* src/admin/ui/styles/media-registry.scss */
|
|
47
|
-
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/* src/admin/ui/styles/accordion.scss */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/* src/admin/ui/styles/button.scss */
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/* src/admin/ui/styles/collapsible.scss */
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/* src/admin/ui/styles/dialog.scss */
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/* src/admin/ui/styles/group.scss */
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/* src/admin/ui/styles/input.scss */
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/* src/admin/ui/styles/label.scss */
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/* src/admin/ui/styles/radio-group.scss */
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/* src/admin/ui/styles/select.scss */
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/* src/admin/ui/styles/sheet.scss */
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/* src/admin/ui/styles/tabs.scss */
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/* src/admin/ui/styles/index.scss */
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/* src/admin/ui/styles/asset-manager.scss */
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/* src/admin/ui/styles/lexical.scss */
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/* src/admin/ui/styles/data-detail.scss */
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/* src/admin/ui/styles/media-registry.scss */
|
|
47
|
-
|
package/global.d.ts
DELETED
package/src/admin/api-client.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import ky from "ky";
|
|
2
|
-
|
|
3
|
-
let client: typeof ky | null = null;
|
|
4
|
-
let currentBaseURL: string | null = null;
|
|
5
|
-
|
|
6
|
-
export const configureAPI = (serverUrl: string) => {
|
|
7
|
-
if (!serverUrl || !serverUrl.startsWith("http")) return;
|
|
8
|
-
const url = serverUrl;
|
|
9
|
-
const baseURL = url.replace(/\/$/, "");
|
|
10
|
-
if (client && currentBaseURL === baseURL) return;
|
|
11
|
-
|
|
12
|
-
currentBaseURL = baseURL;
|
|
13
|
-
client = ky.create({
|
|
14
|
-
prefixUrl: baseURL,
|
|
15
|
-
credentials: "include",
|
|
16
|
-
retry: 0,
|
|
17
|
-
hooks: {
|
|
18
|
-
afterResponse: [
|
|
19
|
-
async (_request, _options, response) => {
|
|
20
|
-
if (response.status === 401 || response.status === 403) {
|
|
21
|
-
// Se o auth handler do backend falhar globalmente em qualquer requisição da API (sessão morreu/expirada)
|
|
22
|
-
// Lançamos a revalidação da store local para despachar o usuário pra tela de login.
|
|
23
|
-
try {
|
|
24
|
-
const { $session } = await import("./stores/auth");
|
|
25
|
-
const { notify } = await import("./stores/ui");
|
|
26
|
-
$session.set(null);
|
|
27
|
-
notify("Session expired. Please log in again.", "error");
|
|
28
|
-
} catch (e) {}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const getCurrentBaseURL = () => {
|
|
37
|
-
if (!currentBaseURL) {
|
|
38
|
-
throw new Error("API client not configured. Did you provide a valid serverUrl?");
|
|
39
|
-
}
|
|
40
|
-
return currentBaseURL as string;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* A proxy for ky that allows us to configure the baseURL late
|
|
45
|
-
* (e.g. after we have the serverURL from props).
|
|
46
|
-
* @param prop: string
|
|
47
|
-
*/
|
|
48
|
-
export const api = new Proxy({} as typeof ky, {
|
|
49
|
-
get(_, prop) {
|
|
50
|
-
if (!client) {
|
|
51
|
-
// No auto-fallback for web components.
|
|
52
|
-
throw new Error("API client not configured. Did you provide a valid serverUrl?");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (!client) throw new Error("API client not configured");
|
|
56
|
-
|
|
57
|
-
const c = client;
|
|
58
|
-
if (c) {
|
|
59
|
-
return c[prop as keyof typeof ky];
|
|
60
|
-
}
|
|
61
|
-
return undefined;
|
|
62
|
-
},
|
|
63
|
-
});
|
package/src/admin/auth-client.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { createAuthClient } from "better-auth/client";
|
|
2
|
-
import { adminClient } from "better-auth/client/plugins";
|
|
3
|
-
import { logger } from "@/utils/logger";
|
|
4
|
-
|
|
5
|
-
let client: ReturnType<typeof createAuthClient> | null = null;
|
|
6
|
-
let currentURL: string | null = null;
|
|
7
|
-
|
|
8
|
-
export const configureAuth = (serverUrl: string) => {
|
|
9
|
-
if (!serverUrl || !serverUrl.startsWith("http")) return;
|
|
10
|
-
const url = serverUrl;
|
|
11
|
-
const baseURL = url.replace(/\/$/, "") + "/api/auth";
|
|
12
|
-
if (client && currentURL === baseURL) return;
|
|
13
|
-
|
|
14
|
-
currentURL = baseURL;
|
|
15
|
-
client = createAuthClient({
|
|
16
|
-
baseURL,
|
|
17
|
-
autoRefresh: true,
|
|
18
|
-
fetchOptions: {
|
|
19
|
-
credentials: "include",
|
|
20
|
-
},
|
|
21
|
-
plugins: [adminClient()],
|
|
22
|
-
});
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* A proxy for the authClient that allows us to configure it late
|
|
27
|
-
* (e.g. after we have the user's config with serverURL).
|
|
28
|
-
*/
|
|
29
|
-
export const authClient = new Proxy({} as ReturnType<typeof createAuthClient>, {
|
|
30
|
-
get(_, prop) {
|
|
31
|
-
if (!client) {
|
|
32
|
-
// No auto-fallback to origin for web components.
|
|
33
|
-
// AdminClient will call configureAuth when it has the correct prop.
|
|
34
|
-
throw new Error("Auth client not configured. Did you provide a valid serverUrl?");
|
|
35
|
-
}
|
|
36
|
-
return (client as ReturnType<typeof createAuthClient>)[
|
|
37
|
-
prop as keyof ReturnType<typeof createAuthClient>
|
|
38
|
-
];
|
|
39
|
-
},
|
|
40
|
-
});
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
export interface CustomFieldProps<TValue = any, TConfig = Record<string, any>> {
|
|
2
|
-
/** The current value of the field from the CMS database */
|
|
3
|
-
value: TValue;
|
|
4
|
-
/** The full schema configuration of the field */
|
|
5
|
-
fieldConfig: TConfig;
|
|
6
|
-
/** Whether the field is currently disabled by access control */
|
|
7
|
-
disabled: boolean;
|
|
8
|
-
/** Whether the field is currently read-only by access control */
|
|
9
|
-
readOnly: boolean;
|
|
10
|
-
/** A validation error message from the CMS, if any */
|
|
11
|
-
error?: string;
|
|
12
|
-
/** The current full state of the parent form or row */
|
|
13
|
-
parentData?: Record<string, unknown>;
|
|
14
|
-
/** Callback to notify the CMS that the data has changed */
|
|
15
|
-
onChange: (value: TValue) => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface CustomFieldAdapter {
|
|
19
|
-
/**
|
|
20
|
-
* Called exactly once when the field is inserted into the CMS Admin UI.
|
|
21
|
-
* Use this to render your React root, Vue app, or Vanilla DOM nodes.
|
|
22
|
-
*
|
|
23
|
-
* @param container The DOM element acting as the wrapper for your component.
|
|
24
|
-
* @param props The initial properties (value, config, onChange) from the CMS.
|
|
25
|
-
*/
|
|
26
|
-
mount: (container: HTMLElement, props: CustomFieldProps) => void;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Called whenever the CMS pushes new data to the field (e.g. form resets,
|
|
30
|
-
* external value changes).
|
|
31
|
-
*
|
|
32
|
-
* @param container The same DOM element wrapper.
|
|
33
|
-
* @param props The updated properties.
|
|
34
|
-
*/
|
|
35
|
-
update?: (container: HTMLElement, props: CustomFieldProps) => void;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Called exactly once when the field is removed from the DOM (e.g., navigating away).
|
|
39
|
-
* Use this to unmount your React root or Vue app to prevent memory leaks.
|
|
40
|
-
*
|
|
41
|
-
* @param container The same DOM element wrapper.
|
|
42
|
-
*/
|
|
43
|
-
unmount?: (container: HTMLElement) => void;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* A built-in utility to register framework-agnostic Custom Web Components for the OpacaCMS Admin UI.
|
|
48
|
-
*
|
|
49
|
-
* It acts as an adapter, translating the Web Component lifecycle (`connectedCallback`, `disconnectedCallback`,
|
|
50
|
-
* property setters) into a simple `mount` / `update` / `unmount` paradigm that can easily wrap React, Vue, Angular,
|
|
51
|
-
* or plain Javascript applications.
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```tsx
|
|
55
|
-
* import { defineCustomField } from 'opacacms/admin';
|
|
56
|
-
* import { createRoot } from 'react-dom/client';
|
|
57
|
-
*
|
|
58
|
-
* defineCustomField('my-react-picker', {
|
|
59
|
-
* mount: (container, props) => {
|
|
60
|
-
* (container as any)._root = createRoot(container);
|
|
61
|
-
* (container as any)._root.render(<MyPicker {...props} />);
|
|
62
|
-
* },
|
|
63
|
-
* update: (container, props) => {
|
|
64
|
-
* (container as any)._root.render(<MyPicker {...props} />);
|
|
65
|
-
* },
|
|
66
|
-
* unmount: (container) => {
|
|
67
|
-
* (container as any)._root.unmount();
|
|
68
|
-
* }
|
|
69
|
-
* });
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* @param tagName The tag name to register in the browser (e.g., `opaca-color-picker`). Must contain a hyphen.
|
|
73
|
-
* @param adapter The adapter containing `mount`, optional `update`, and optional `unmount` lifecycle methods.
|
|
74
|
-
*/
|
|
75
|
-
export function defineCustomField(tagName: string, adapter: CustomFieldAdapter) {
|
|
76
|
-
if (typeof window === "undefined") return;
|
|
77
|
-
|
|
78
|
-
if (customElements.get(tagName)) {
|
|
79
|
-
console.warn(`[OpacaCMS] Custom field tag "${tagName}" is already defined.`);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
class OpacaCustomFieldElement extends HTMLElement {
|
|
84
|
-
private _value: any;
|
|
85
|
-
private _fieldConfig: any;
|
|
86
|
-
private _error?: string;
|
|
87
|
-
private _parentData?: Record<string, unknown>;
|
|
88
|
-
private _isMounted = false;
|
|
89
|
-
|
|
90
|
-
// Helper to abstract the complex CustomEvent away from the user's DX
|
|
91
|
-
private handleChange = (newValue: any) => {
|
|
92
|
-
this.dispatchEvent(
|
|
93
|
-
new CustomEvent("opacachange", {
|
|
94
|
-
detail: { value: newValue },
|
|
95
|
-
bubbles: true,
|
|
96
|
-
composed: true,
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
private getProps(): CustomFieldProps {
|
|
102
|
-
return {
|
|
103
|
-
value: this._value,
|
|
104
|
-
fieldConfig: this._fieldConfig,
|
|
105
|
-
disabled: this.getAttribute("data-disabled") === "true",
|
|
106
|
-
readOnly: this.getAttribute("data-readonly") === "true",
|
|
107
|
-
error: this._error,
|
|
108
|
-
parentData: this._parentData,
|
|
109
|
-
onChange: this.handleChange,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
set error(err: string | undefined) {
|
|
114
|
-
if (this._error !== err) {
|
|
115
|
-
this._error = err;
|
|
116
|
-
if (this._isMounted && adapter.update) {
|
|
117
|
-
adapter.update(this, this.getProps());
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
get error() {
|
|
123
|
-
return this._error;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
set parentData(data: Record<string, unknown> | undefined) {
|
|
127
|
-
this._parentData = data;
|
|
128
|
-
if (this._isMounted && adapter.update) {
|
|
129
|
-
adapter.update(this, this.getProps());
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
get parentData() {
|
|
134
|
-
return this._parentData;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
set value(val: any) {
|
|
138
|
-
const oldValue = this._value;
|
|
139
|
-
this._value = val;
|
|
140
|
-
// Only call update if the value actually changed and the component is mounted
|
|
141
|
-
if (this._isMounted && adapter.update && oldValue !== val) {
|
|
142
|
-
adapter.update(this, this.getProps());
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
get value() {
|
|
147
|
-
return this._value;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
set fieldConfig(config: any) {
|
|
151
|
-
this._fieldConfig = config;
|
|
152
|
-
if (this._isMounted && adapter.update) {
|
|
153
|
-
adapter.update(this, this.getProps());
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
get fieldConfig() {
|
|
158
|
-
return this._fieldConfig;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
connectedCallback() {
|
|
162
|
-
if (!this._isMounted) {
|
|
163
|
-
adapter.mount(this, this.getProps());
|
|
164
|
-
this._isMounted = true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
disconnectedCallback() {
|
|
169
|
-
if (this._isMounted) {
|
|
170
|
-
if (adapter.unmount) {
|
|
171
|
-
adapter.unmount(this);
|
|
172
|
-
}
|
|
173
|
-
this._isMounted = false;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
customElements.define(tagName, OpacaCustomFieldElement);
|
|
179
|
-
}
|