@abraca/nuxt 2.10.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.mts +14 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +9 -0
- package/dist/runtime/assets/editor.css +1 -1
- package/dist/runtime/components/AConnectionBadge.d.vue.ts +29 -0
- package/dist/runtime/components/AConnectionBadge.vue +79 -0
- package/dist/runtime/components/AConnectionBadge.vue.d.ts +29 -0
- package/dist/runtime/components/ADocPickerModal.d.vue.ts +31 -0
- package/dist/runtime/components/ADocPickerModal.vue +191 -0
- package/dist/runtime/components/ADocPickerModal.vue.d.ts +31 -0
- package/dist/runtime/components/ADocumentTree.vue +65 -0
- package/dist/runtime/components/AEditor.d.vue.ts +19 -12
- package/dist/runtime/components/AEditor.vue +243 -165
- package/dist/runtime/components/AEditor.vue.d.ts +19 -12
- package/dist/runtime/components/AEncryptionModePicker.d.vue.ts +33 -0
- package/dist/runtime/components/AEncryptionModePicker.vue +211 -0
- package/dist/runtime/components/AEncryptionModePicker.vue.d.ts +33 -0
- package/dist/runtime/components/AModalShell.d.vue.ts +48 -0
- package/dist/runtime/components/AModalShell.vue +105 -0
- package/dist/runtime/components/AModalShell.vue.d.ts +48 -0
- package/dist/runtime/components/ANodePanel.d.vue.ts +17 -7
- package/dist/runtime/components/ANodePanel.vue +550 -451
- package/dist/runtime/components/ANodePanel.vue.d.ts +17 -7
- package/dist/runtime/components/ANodePanelHeader.d.vue.ts +20 -10
- package/dist/runtime/components/ANodePanelHeader.vue +17 -3
- package/dist/runtime/components/ANodePanelHeader.vue.d.ts +20 -10
- package/dist/runtime/components/ANodeSettingsPanel.d.vue.ts +2 -0
- package/dist/runtime/components/ANodeSettingsPanel.vue +21 -1
- package/dist/runtime/components/ANodeSettingsPanel.vue.d.ts +2 -0
- package/dist/runtime/components/ASnapshotPreviewModal.d.vue.ts +33 -0
- package/dist/runtime/components/ASnapshotPreviewModal.vue +430 -0
- package/dist/runtime/components/ASnapshotPreviewModal.vue.d.ts +33 -0
- package/dist/runtime/components/ATagsEditor.d.vue.ts +19 -0
- package/dist/runtime/components/ATagsEditor.vue +60 -0
- package/dist/runtime/components/ATagsEditor.vue.d.ts +19 -0
- package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
- package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
- package/dist/runtime/components/chat/AChatInput.d.vue.ts +11 -6
- package/dist/runtime/components/chat/AChatInput.vue +33 -2
- package/dist/runtime/components/chat/AChatInput.vue.d.ts +11 -6
- package/dist/runtime/components/chat/AChatList.d.vue.ts +12 -0
- package/dist/runtime/components/chat/AChatList.vue +76 -32
- package/dist/runtime/components/chat/AChatList.vue.d.ts +12 -0
- package/dist/runtime/components/chat/AChatMessages.d.vue.ts +4 -0
- package/dist/runtime/components/chat/AChatMessages.vue +57 -4
- package/dist/runtime/components/chat/AChatMessages.vue.d.ts +4 -0
- package/dist/runtime/components/chat/AChatPanel.d.vue.ts +6 -2
- package/dist/runtime/components/chat/AChatPanel.vue +17 -1
- package/dist/runtime/components/chat/AChatPanel.vue.d.ts +6 -2
- package/dist/runtime/components/chat/ANodeChatPanel.vue +1 -1
- package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
- package/dist/runtime/components/editor/ALocationPickerPopover.vue +28 -7
- package/dist/runtime/components/registry/APluginDetail.d.vue.ts +2 -2
- package/dist/runtime/components/registry/APluginDetail.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/AChartRenderer.client.d.vue.ts +17 -0
- package/dist/runtime/components/renderers/AChartRenderer.client.vue +622 -0
- package/dist/runtime/components/renderers/AChartRenderer.client.vue.d.ts +17 -0
- package/dist/runtime/components/renderers/AGraphRenderer.vue +64 -15
- package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsGrid.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsGrid.vue.d.ts +2 -2
- package/dist/runtime/components/settings/ASettingsAppearancePanel.d.vue.ts +3 -0
- package/dist/runtime/components/settings/ASettingsAppearancePanel.vue +67 -0
- package/dist/runtime/components/settings/ASettingsAppearancePanel.vue.d.ts +3 -0
- package/dist/runtime/components/settings/ASettingsGroup.d.vue.ts +24 -0
- package/dist/runtime/components/settings/ASettingsGroup.vue +31 -0
- package/dist/runtime/components/settings/ASettingsGroup.vue.d.ts +24 -0
- package/dist/runtime/components/settings/ASettingsModal.vue +84 -53
- package/dist/runtime/components/settings/ASettingsPlaceholder.d.vue.ts +20 -0
- package/dist/runtime/components/settings/ASettingsPlaceholder.vue +32 -0
- package/dist/runtime/components/settings/ASettingsPlaceholder.vue.d.ts +20 -0
- package/dist/runtime/components/settings/ASettingsRow.d.vue.ts +34 -0
- package/dist/runtime/components/settings/ASettingsRow.vue +34 -0
- package/dist/runtime/components/settings/ASettingsRow.vue.d.ts +34 -0
- package/dist/runtime/components/settings/sections.d.ts +37 -0
- package/dist/runtime/components/settings/sections.js +45 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +6 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +75 -3
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +6 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.d.vue.ts +17 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.vue +253 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.vue.d.ts +17 -0
- package/dist/runtime/components/shell/ADocPanelSettings.d.vue.ts +2 -0
- package/dist/runtime/components/shell/ADocPanelSettings.vue +15 -4
- package/dist/runtime/components/shell/ADocPanelSettings.vue.d.ts +2 -0
- package/dist/runtime/components/shell/AUserProfilePopover.d.vue.ts +1 -1
- package/dist/runtime/components/shell/AUserProfilePopover.vue.d.ts +1 -1
- package/dist/runtime/composables/useChat.d.ts +22 -1
- package/dist/runtime/composables/useChat.js +79 -8
- package/dist/runtime/composables/useDocBreadcrumb.d.ts +17 -2
- package/dist/runtime/composables/useDocBreadcrumb.js +17 -3
- package/dist/runtime/composables/useDocSnapshots.d.ts +2 -1
- package/dist/runtime/composables/useDocSnapshots.js +5 -0
- package/dist/runtime/composables/useEditor.d.ts +1 -1
- package/dist/runtime/composables/useEditor.js +120 -0
- package/dist/runtime/composables/useEditorToolbar.d.ts +12 -4
- package/dist/runtime/composables/useEditorToolbar.js +78 -56
- package/dist/runtime/composables/useNodeContextMenu.d.ts +14 -0
- package/dist/runtime/composables/useNodeContextMenu.js +59 -1
- package/dist/runtime/composables/useSettingsModal.d.ts +1 -1
- package/dist/runtime/composables/useSwipeGesture.d.ts +48 -0
- package/dist/runtime/composables/useSwipeGesture.js +140 -0
- package/dist/runtime/extensions/document-header.js +16 -6
- package/dist/runtime/extensions/document-meta.js +344 -19
- package/dist/runtime/extensions/meta-field.js +42 -0
- package/dist/runtime/extensions/views/DocumentMetaView.vue +33 -7
- package/dist/runtime/extensions/views/FieldView.vue +51 -19
- package/dist/runtime/extensions/views/MetaFieldView.vue +30 -4
- package/dist/runtime/locale.d.ts +8 -0
- package/dist/runtime/locale.js +9 -1
- package/dist/runtime/middleware/abracadabra-auth.d.ts +1 -1
- package/dist/runtime/plugin-abracadabra.client.d.ts +1 -1
- package/dist/runtime/plugin-abracadabra.client.js +12 -2
- package/dist/runtime/plugin-abracadabra.server.d.ts +1 -1
- package/dist/runtime/plugin-shared-globals.client.d.ts +1 -1
- package/dist/runtime/utils/chatContent.d.ts +20 -2
- package/dist/runtime/utils/chatContent.js +20 -1
- package/dist/runtime/utils/docTypes.js +43 -0
- package/dist/runtime/utils/titleSync.d.ts +130 -0
- package/dist/runtime/utils/titleSync.js +53 -0
- package/package.json +11 -4
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
icon: { type: String, required: true },
|
|
4
|
+
title: { type: String, required: true },
|
|
5
|
+
description: { type: String, required: true },
|
|
6
|
+
badge: { type: String, required: false, default: void 0 }
|
|
7
|
+
});
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div class="flex flex-col items-center justify-center text-center py-16 px-4 gap-3">
|
|
12
|
+
<div class="size-12 rounded-full bg-(--ui-bg-elevated) flex items-center justify-center">
|
|
13
|
+
<UIcon
|
|
14
|
+
:name="icon"
|
|
15
|
+
class="size-6 text-(--ui-text-muted)"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
<h3 class="text-sm font-semibold text-(--ui-text-highlighted)">
|
|
19
|
+
{{ title }}
|
|
20
|
+
</h3>
|
|
21
|
+
<p class="text-xs text-(--ui-text-muted) max-w-sm leading-relaxed">
|
|
22
|
+
{{ description }}
|
|
23
|
+
</p>
|
|
24
|
+
<UBadge
|
|
25
|
+
v-if="badge"
|
|
26
|
+
color="neutral"
|
|
27
|
+
variant="subtle"
|
|
28
|
+
size="sm"
|
|
29
|
+
:label="badge"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ASettingsPlaceholder>
|
|
3
|
+
*
|
|
4
|
+
* Centered empty-state card for a not-yet-implemented (or empty) settings
|
|
5
|
+
* section: icon bubble + title + description, with an optional badge.
|
|
6
|
+
* Ported from cou-sh SettingsV2/Placeholder.vue — the badge is configurable
|
|
7
|
+
* here (cou-sh hardcoded "Coming next"); omit `badge` to hide it.
|
|
8
|
+
*/
|
|
9
|
+
type __VLS_Props = {
|
|
10
|
+
icon: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
/** Optional badge label (e.g. "Coming next"). Omit to hide the badge. */
|
|
14
|
+
badge?: string;
|
|
15
|
+
};
|
|
16
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
17
|
+
badge: string;
|
|
18
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: typeof __VLS_export;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ASettingsRow>
|
|
3
|
+
*
|
|
4
|
+
* One labelled setting row: label + optional description on the left, the
|
|
5
|
+
* control (default slot) on the right. Bottom-bordered so rows stack into a
|
|
6
|
+
* clean list inside an <ASettingsGroup>. Use `stacked` for wide controls
|
|
7
|
+
* (color grids, lists) that need their own row beneath the label.
|
|
8
|
+
*
|
|
9
|
+
* Shared building block for settings panels — ported from cou-sh
|
|
10
|
+
* SettingsV2/Row.vue so module panels share one consistent row look.
|
|
11
|
+
*/
|
|
12
|
+
type __VLS_Props = {
|
|
13
|
+
label: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
/** Stack label + description above a full-width control row (wide widgets). */
|
|
16
|
+
stacked?: boolean;
|
|
17
|
+
/** Vertical alignment of the control against the label. */
|
|
18
|
+
align?: 'center' | 'start';
|
|
19
|
+
};
|
|
20
|
+
declare var __VLS_1: {};
|
|
21
|
+
type __VLS_Slots = {} & {
|
|
22
|
+
default?: (props: typeof __VLS_1) => any;
|
|
23
|
+
};
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
|
+
align: "center" | "start";
|
|
26
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
27
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
30
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
31
|
+
new (): {
|
|
32
|
+
$slots: S;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
label: { type: String, required: true },
|
|
4
|
+
description: { type: String, required: false },
|
|
5
|
+
stacked: { type: Boolean, required: false },
|
|
6
|
+
align: { type: String, required: false, default: "center" }
|
|
7
|
+
});
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
class="flex gap-4 py-3.5 border-b border-(--ui-border) last:border-b-0"
|
|
13
|
+
:class="[
|
|
14
|
+
stacked ? 'flex-col' : 'flex-col sm:flex-row sm:justify-between',
|
|
15
|
+
!stacked && align === 'center' ? 'sm:items-center' : 'sm:items-start'
|
|
16
|
+
]"
|
|
17
|
+
>
|
|
18
|
+
<div class="flex flex-col gap-0.5 min-w-0">
|
|
19
|
+
<span class="text-sm text-(--ui-text-highlighted)">{{ label }}</span>
|
|
20
|
+
<span
|
|
21
|
+
v-if="description"
|
|
22
|
+
class="text-xs text-(--ui-text-muted) leading-relaxed"
|
|
23
|
+
>
|
|
24
|
+
{{ description }}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
<div
|
|
28
|
+
class="flex items-center gap-2 shrink-0"
|
|
29
|
+
:class="stacked && 'w-full justify-start'"
|
|
30
|
+
>
|
|
31
|
+
<slot />
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ASettingsRow>
|
|
3
|
+
*
|
|
4
|
+
* One labelled setting row: label + optional description on the left, the
|
|
5
|
+
* control (default slot) on the right. Bottom-bordered so rows stack into a
|
|
6
|
+
* clean list inside an <ASettingsGroup>. Use `stacked` for wide controls
|
|
7
|
+
* (color grids, lists) that need their own row beneath the label.
|
|
8
|
+
*
|
|
9
|
+
* Shared building block for settings panels — ported from cou-sh
|
|
10
|
+
* SettingsV2/Row.vue so module panels share one consistent row look.
|
|
11
|
+
*/
|
|
12
|
+
type __VLS_Props = {
|
|
13
|
+
label: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
/** Stack label + description above a full-width control row (wide widgets). */
|
|
16
|
+
stacked?: boolean;
|
|
17
|
+
/** Vertical alignment of the control against the label. */
|
|
18
|
+
align?: 'center' | 'start';
|
|
19
|
+
};
|
|
20
|
+
declare var __VLS_1: {};
|
|
21
|
+
type __VLS_Slots = {} & {
|
|
22
|
+
default?: (props: typeof __VLS_1) => any;
|
|
23
|
+
};
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
|
+
align: "center" | "start";
|
|
26
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
27
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
30
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
31
|
+
new (): {
|
|
32
|
+
$slots: S;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings section registry.
|
|
3
|
+
*
|
|
4
|
+
* The single source of truth for which settings sections exist, how they're
|
|
5
|
+
* labelled/grouped/searched, and which component renders each. <ASettingsModal>
|
|
6
|
+
* builds its nav + content from this list instead of hard-coding them, so a new
|
|
7
|
+
* section is one entry here (no template edits), and the nav gets search +
|
|
8
|
+
* grouping for free.
|
|
9
|
+
*
|
|
10
|
+
* Grouping maps onto the shell's two modes:
|
|
11
|
+
* - 'user' → "User settings"
|
|
12
|
+
* - 'workspace' → "Administration" (workspace-level)
|
|
13
|
+
* - 'admin' → "Administration" (admin/service only; `adminOnly`)
|
|
14
|
+
*/
|
|
15
|
+
import { type Component } from 'vue';
|
|
16
|
+
import type { SettingsTab } from '../../composables/useSettingsModal.js';
|
|
17
|
+
export type SettingsGroup = 'user' | 'workspace' | 'admin';
|
|
18
|
+
export interface SettingsSectionDef {
|
|
19
|
+
key: SettingsTab;
|
|
20
|
+
label: string;
|
|
21
|
+
icon: string;
|
|
22
|
+
group: SettingsGroup;
|
|
23
|
+
/** Extra terms matched by the nav search box (besides the label). */
|
|
24
|
+
keywords?: string[];
|
|
25
|
+
/** Only shown to admin/service roles. */
|
|
26
|
+
adminOnly?: boolean;
|
|
27
|
+
/** The panel component to render for this section. */
|
|
28
|
+
component: Component;
|
|
29
|
+
}
|
|
30
|
+
/** Which shell "mode" each group belongs to. */
|
|
31
|
+
export declare const GROUP_MODE: Record<SettingsGroup, 'user' | 'admin'>;
|
|
32
|
+
export declare const GROUP_LABELS: Record<SettingsGroup, string>;
|
|
33
|
+
export declare const BUILTIN_SETTINGS_SECTIONS: SettingsSectionDef[];
|
|
34
|
+
/** Filter to the sections visible for the current role. */
|
|
35
|
+
export declare function visibleSections(sections: SettingsSectionDef[], isAdmin: boolean): SettingsSectionDef[];
|
|
36
|
+
/** Case-insensitive search over label + keywords. */
|
|
37
|
+
export declare function searchSections(query: string, sections: SettingsSectionDef[]): SettingsSectionDef[];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { markRaw } from "vue";
|
|
2
|
+
import ASettingsProfilePanel from "./ASettingsProfilePanel.vue";
|
|
3
|
+
import ASettingsAppearancePanel from "./ASettingsAppearancePanel.vue";
|
|
4
|
+
import ASettingsSecurityPanel from "./ASettingsSecurityPanel.vue";
|
|
5
|
+
import ASettingsOfflinePanel from "./ASettingsOfflinePanel.vue";
|
|
6
|
+
import ASettingsSpacesPanel from "./ASettingsSpacesPanel.vue";
|
|
7
|
+
import ASettingsMembersPanel from "./ASettingsMembersPanel.vue";
|
|
8
|
+
import ASettingsConnectionPanel from "./ASettingsConnectionPanel.vue";
|
|
9
|
+
import ASettingsTrashPanel from "./ASettingsTrashPanel.vue";
|
|
10
|
+
import ASettingsPluginsPanel from "./ASettingsPluginsPanel.vue";
|
|
11
|
+
import ASettingsInvitesPanel from "./ASettingsInvitesPanel.vue";
|
|
12
|
+
import ASettingsAdminPanel from "./ASettingsAdminPanel.vue";
|
|
13
|
+
export const GROUP_MODE = {
|
|
14
|
+
user: "user",
|
|
15
|
+
workspace: "admin",
|
|
16
|
+
admin: "admin"
|
|
17
|
+
};
|
|
18
|
+
export const GROUP_LABELS = {
|
|
19
|
+
user: "Account",
|
|
20
|
+
workspace: "Workspace",
|
|
21
|
+
admin: "Administration"
|
|
22
|
+
};
|
|
23
|
+
export const BUILTIN_SETTINGS_SECTIONS = [
|
|
24
|
+
{ key: "profile", label: "Profile", icon: "i-lucide-user", group: "user", keywords: ["name", "avatar", "identity", "colour", "color"], component: markRaw(ASettingsProfilePanel) },
|
|
25
|
+
{ key: "appearance", label: "Appearance", icon: "i-lucide-palette", group: "user", keywords: ["theme", "dark", "light", "motion", "font"], component: markRaw(ASettingsAppearancePanel) },
|
|
26
|
+
{ key: "security", label: "Security", icon: "i-lucide-shield", group: "user", keywords: ["passkey", "password", "account", "logout", "wipe"], component: markRaw(ASettingsSecurityPanel) },
|
|
27
|
+
{ key: "offline", label: "Offline", icon: "i-lucide-database", group: "user", keywords: ["sync", "storage", "cache"], component: markRaw(ASettingsOfflinePanel) },
|
|
28
|
+
{ key: "spaces", label: "Spaces", icon: "i-lucide-layers", group: "workspace", keywords: ["workspace", "create", "switch"], component: markRaw(ASettingsSpacesPanel) },
|
|
29
|
+
{ key: "members", label: "Members", icon: "i-lucide-users", group: "workspace", keywords: ["people", "roles", "online"], component: markRaw(ASettingsMembersPanel) },
|
|
30
|
+
{ key: "connection", label: "Connection", icon: "i-lucide-wifi", group: "workspace", keywords: ["server", "p2p", "webrtc", "reconnect"], component: markRaw(ASettingsConnectionPanel) },
|
|
31
|
+
{ key: "trash", label: "Trash", icon: "i-lucide-trash-2", group: "workspace", keywords: ["deleted", "restore", "purge"], component: markRaw(ASettingsTrashPanel) },
|
|
32
|
+
{ key: "plugins", label: "Plugins", icon: "i-lucide-plug", group: "workspace", keywords: ["extensions", "page types"], component: markRaw(ASettingsPluginsPanel) },
|
|
33
|
+
{ key: "invites", label: "Invites", icon: "i-lucide-ticket", group: "admin", adminOnly: true, keywords: ["invite", "code", "join"], component: markRaw(ASettingsInvitesPanel) },
|
|
34
|
+
{ key: "admin", label: "Admin", icon: "i-lucide-shield-alert", group: "admin", adminOnly: true, keywords: ["users", "server", "manage"], component: markRaw(ASettingsAdminPanel) }
|
|
35
|
+
];
|
|
36
|
+
export function visibleSections(sections, isAdmin) {
|
|
37
|
+
return sections.filter((s) => !s.adminOnly || isAdmin);
|
|
38
|
+
}
|
|
39
|
+
export function searchSections(query, sections) {
|
|
40
|
+
const q = query.trim().toLowerCase();
|
|
41
|
+
if (!q) return sections;
|
|
42
|
+
return sections.filter(
|
|
43
|
+
(s) => s.label.toLowerCase().includes(q) || s.keywords?.some((k) => k.toLowerCase().includes(q))
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -3,9 +3,15 @@ type __VLS_Props = {
|
|
|
3
3
|
docId: string | null | undefined;
|
|
4
4
|
/** Maximum ancestors to walk (default 8) */
|
|
5
5
|
maxDepth?: number;
|
|
6
|
+
/**
|
|
7
|
+
* Collapse the middle into a "…" overflow menu once the trail exceeds this
|
|
8
|
+
* many crumbs. 0 (default) renders the full trail with no collapsing.
|
|
9
|
+
*/
|
|
10
|
+
maxVisible?: number;
|
|
6
11
|
};
|
|
7
12
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
8
13
|
maxDepth: number;
|
|
14
|
+
maxVisible: number;
|
|
9
15
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
16
|
declare const _default: typeof __VLS_export;
|
|
11
17
|
export default _default;
|
|
@@ -1,15 +1,87 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
2
3
|
import { useDocBreadcrumb } from "../../composables/useDocBreadcrumb";
|
|
3
4
|
const props = defineProps({
|
|
4
5
|
docId: { type: null, required: true },
|
|
5
|
-
maxDepth: { type: Number, required: false, default: 8 }
|
|
6
|
+
maxDepth: { type: Number, required: false, default: 8 },
|
|
7
|
+
maxVisible: { type: Number, required: false, default: 0 }
|
|
6
8
|
});
|
|
7
|
-
const { items } = useDocBreadcrumb(() => props.docId, {
|
|
9
|
+
const { items, collapsed } = useDocBreadcrumb(() => props.docId, {
|
|
10
|
+
maxDepth: props.maxDepth,
|
|
11
|
+
maxVisible: props.maxVisible
|
|
12
|
+
});
|
|
13
|
+
const overflowItems = computed(
|
|
14
|
+
() => collapsed.value.hidden.map((a) => ({ label: a.label, icon: a.icon, to: a.to }))
|
|
15
|
+
);
|
|
8
16
|
</script>
|
|
9
17
|
|
|
10
18
|
<template>
|
|
19
|
+
<!-- Collapsed single-line variant (overflow menu for the hidden middle) -->
|
|
20
|
+
<nav
|
|
21
|
+
v-if="collapsed.overflowed"
|
|
22
|
+
aria-label="Breadcrumb"
|
|
23
|
+
class="flex items-center gap-0.5 min-w-0 text-(--ui-text-muted)"
|
|
24
|
+
>
|
|
25
|
+
<template
|
|
26
|
+
v-for="ancestor in collapsed.head"
|
|
27
|
+
:key="ancestor.id"
|
|
28
|
+
>
|
|
29
|
+
<ULink
|
|
30
|
+
:to="ancestor.to"
|
|
31
|
+
class="flex items-center gap-1 px-1.5 py-0.5 rounded text-xs hover:bg-(--ui-bg-elevated)/60 hover:text-(--ui-text) transition-colors min-w-0"
|
|
32
|
+
>
|
|
33
|
+
<UIcon
|
|
34
|
+
:name="ancestor.icon"
|
|
35
|
+
class="size-3.5 shrink-0"
|
|
36
|
+
/>
|
|
37
|
+
<span class="truncate max-w-[10ch]">{{ ancestor.label }}</span>
|
|
38
|
+
</ULink>
|
|
39
|
+
<UIcon
|
|
40
|
+
name="i-lucide-chevron-right"
|
|
41
|
+
class="size-3.5 shrink-0 opacity-60"
|
|
42
|
+
/>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<UDropdownMenu :items="overflowItems">
|
|
46
|
+
<button
|
|
47
|
+
type="button"
|
|
48
|
+
class="flex items-center px-1 py-0.5 rounded text-xs hover:bg-(--ui-bg-elevated)/60 hover:text-(--ui-text) transition-colors"
|
|
49
|
+
:aria-label="`Show ${collapsed.hidden.length} hidden`"
|
|
50
|
+
>
|
|
51
|
+
…
|
|
52
|
+
</button>
|
|
53
|
+
</UDropdownMenu>
|
|
54
|
+
<UIcon
|
|
55
|
+
name="i-lucide-chevron-right"
|
|
56
|
+
class="size-3.5 shrink-0 opacity-60"
|
|
57
|
+
/>
|
|
58
|
+
|
|
59
|
+
<template
|
|
60
|
+
v-for="(ancestor, idx) in collapsed.tail"
|
|
61
|
+
:key="ancestor.id"
|
|
62
|
+
>
|
|
63
|
+
<ULink
|
|
64
|
+
:to="ancestor.to"
|
|
65
|
+
class="flex items-center gap-1 px-1.5 py-0.5 rounded text-xs hover:bg-(--ui-bg-elevated)/60 hover:text-(--ui-text) transition-colors min-w-0"
|
|
66
|
+
:class="ancestor.to ? '' : 'pointer-events-none text-(--ui-text)'"
|
|
67
|
+
>
|
|
68
|
+
<UIcon
|
|
69
|
+
:name="ancestor.icon"
|
|
70
|
+
class="size-3.5 shrink-0"
|
|
71
|
+
/>
|
|
72
|
+
<span class="truncate max-w-[10ch]">{{ ancestor.label }}</span>
|
|
73
|
+
</ULink>
|
|
74
|
+
<UIcon
|
|
75
|
+
v-if="idx < collapsed.tail.length - 1"
|
|
76
|
+
name="i-lucide-chevron-right"
|
|
77
|
+
class="size-3.5 shrink-0 opacity-60"
|
|
78
|
+
/>
|
|
79
|
+
</template>
|
|
80
|
+
</nav>
|
|
81
|
+
|
|
82
|
+
<!-- Full-trail variant -->
|
|
11
83
|
<UBreadcrumb
|
|
12
|
-
v-if="items.length > 0"
|
|
84
|
+
v-else-if="items.length > 0"
|
|
13
85
|
:items="items"
|
|
14
86
|
:ui="{ root: 'min-w-0', list: 'min-w-0 flex-nowrap', item: 'truncate', link: 'truncate' }"
|
|
15
87
|
/>
|
|
@@ -3,9 +3,15 @@ type __VLS_Props = {
|
|
|
3
3
|
docId: string | null | undefined;
|
|
4
4
|
/** Maximum ancestors to walk (default 8) */
|
|
5
5
|
maxDepth?: number;
|
|
6
|
+
/**
|
|
7
|
+
* Collapse the middle into a "…" overflow menu once the trail exceeds this
|
|
8
|
+
* many crumbs. 0 (default) renders the full trail with no collapsing.
|
|
9
|
+
*/
|
|
10
|
+
maxVisible?: number;
|
|
6
11
|
};
|
|
7
12
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
8
13
|
maxDepth: number;
|
|
14
|
+
maxVisible: number;
|
|
9
15
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
16
|
declare const _default: typeof __VLS_export;
|
|
11
17
|
export default _default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** Hub document id (informational — the panel reflects the active server). */
|
|
3
|
+
docId?: string;
|
|
4
|
+
};
|
|
5
|
+
declare var __VLS_96: "storage" | "users" | "members" | "invites", __VLS_97: {};
|
|
6
|
+
type __VLS_Slots = {} & {
|
|
7
|
+
[K in NonNullable<typeof __VLS_96>]?: (props: typeof __VLS_97) => any;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
13
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
14
|
+
new (): {
|
|
15
|
+
$slots: S;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, onMounted, reactive, ref, useSlots, watch } from "vue";
|
|
3
|
+
import { useAbracadabra } from "../../composables/useAbracadabra";
|
|
4
|
+
defineProps({
|
|
5
|
+
docId: { type: String, required: false }
|
|
6
|
+
});
|
|
7
|
+
const slots = useSlots();
|
|
8
|
+
const { client, status, synced, effectiveRole, currentServerUrl, reconnect } = useAbracadabra();
|
|
9
|
+
const ROLE_LEVELS = {
|
|
10
|
+
observer: 0,
|
|
11
|
+
viewer: 1,
|
|
12
|
+
editor: 2,
|
|
13
|
+
owner: 3,
|
|
14
|
+
admin: 4,
|
|
15
|
+
service: 5
|
|
16
|
+
};
|
|
17
|
+
const roleLevel = computed(() => ROLE_LEVELS[effectiveRole.value ?? ""] ?? 0);
|
|
18
|
+
const canEdit = computed(() => roleLevel.value >= 2);
|
|
19
|
+
const isAdmin = computed(() => roleLevel.value >= 4);
|
|
20
|
+
const roleBadgeColor = computed(() => {
|
|
21
|
+
const r = effectiveRole.value;
|
|
22
|
+
if (r === "admin" || r === "service") return "warning";
|
|
23
|
+
if (r === "owner") return "primary";
|
|
24
|
+
if (r === "editor") return "success";
|
|
25
|
+
return "neutral";
|
|
26
|
+
});
|
|
27
|
+
const statusDotClass = computed(() => {
|
|
28
|
+
if (status.value === "connected") return "bg-(--ui-success)";
|
|
29
|
+
if (status.value === "connecting") return "bg-(--ui-warning)";
|
|
30
|
+
return "bg-(--ui-error)";
|
|
31
|
+
});
|
|
32
|
+
const serverInfo = ref(null);
|
|
33
|
+
async function loadServerInfo() {
|
|
34
|
+
if (!client.value) return;
|
|
35
|
+
try {
|
|
36
|
+
serverInfo.value = await client.value.serverInfo();
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
watch(client, loadServerInfo, { immediate: true });
|
|
41
|
+
const healthData = ref(null);
|
|
42
|
+
const healthLoading = ref(false);
|
|
43
|
+
async function checkHealth() {
|
|
44
|
+
if (!client.value) return;
|
|
45
|
+
healthLoading.value = true;
|
|
46
|
+
try {
|
|
47
|
+
healthData.value = await client.value.health();
|
|
48
|
+
} catch {
|
|
49
|
+
} finally {
|
|
50
|
+
healthLoading.value = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const expanded = reactive({ members: false, users: false, invites: false, storage: false });
|
|
54
|
+
const adminSections = computed(() => [
|
|
55
|
+
{ key: "members", label: "Members", icon: "i-lucide-users", show: canEdit.value && !!slots.members },
|
|
56
|
+
{ key: "users", label: "Users", icon: "i-lucide-shield-alert", show: isAdmin.value && !!slots.users },
|
|
57
|
+
{ key: "invites", label: "Invites", icon: "i-lucide-ticket", show: isAdmin.value && !!slots.invites },
|
|
58
|
+
{ key: "storage", label: "Storage", icon: "i-lucide-hard-drive", show: isAdmin.value && !!slots.storage }
|
|
59
|
+
].filter((s) => s.show));
|
|
60
|
+
onMounted(loadServerInfo);
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<div class="flex-1 overflow-y-auto px-4 py-3 space-y-3">
|
|
65
|
+
<!-- Connection — read-only URL (single-server) -->
|
|
66
|
+
<div class="rounded-lg bg-(--ui-bg-elevated) overflow-hidden">
|
|
67
|
+
<div class="flex items-center gap-1.5 px-3 py-2 border-b border-(--ui-border)">
|
|
68
|
+
<UIcon
|
|
69
|
+
name="i-lucide-plug"
|
|
70
|
+
class="size-3.5 text-(--ui-text-muted) shrink-0"
|
|
71
|
+
/>
|
|
72
|
+
<span class="text-xs font-semibold uppercase tracking-wider text-(--ui-text-muted)">Connection</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="px-3 py-3 space-y-1.5">
|
|
75
|
+
<div class="flex items-center gap-2">
|
|
76
|
+
<UIcon
|
|
77
|
+
name="i-lucide-server"
|
|
78
|
+
class="size-3.5 text-(--ui-text-dimmed) shrink-0"
|
|
79
|
+
/>
|
|
80
|
+
<span class="text-sm truncate flex-1 min-w-0 text-(--ui-text)">{{ currentServerUrl || "\u2014" }}</span>
|
|
81
|
+
<UButton
|
|
82
|
+
v-if="status !== 'connected'"
|
|
83
|
+
icon="i-lucide-refresh-cw"
|
|
84
|
+
size="xs"
|
|
85
|
+
variant="ghost"
|
|
86
|
+
color="primary"
|
|
87
|
+
@click="reconnect"
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Status -->
|
|
94
|
+
<div class="rounded-lg bg-(--ui-bg-elevated) overflow-hidden">
|
|
95
|
+
<div class="flex items-center gap-1.5 px-3 py-2 border-b border-(--ui-border)">
|
|
96
|
+
<UIcon
|
|
97
|
+
name="i-lucide-info"
|
|
98
|
+
class="size-3.5 text-(--ui-text-muted) shrink-0"
|
|
99
|
+
/>
|
|
100
|
+
<span class="text-xs font-semibold uppercase tracking-wider text-(--ui-text-muted)">Status</span>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="divide-y divide-(--ui-border)">
|
|
103
|
+
<div class="flex items-center justify-between gap-2 px-3 py-2">
|
|
104
|
+
<div class="flex items-center gap-2 text-sm text-(--ui-text-muted) min-w-0">
|
|
105
|
+
<UIcon
|
|
106
|
+
name="i-lucide-activity"
|
|
107
|
+
class="size-3.5 shrink-0"
|
|
108
|
+
/>
|
|
109
|
+
<span class="truncate">Connection</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div class="flex items-center gap-1.5 shrink-0">
|
|
112
|
+
<span :class="['size-1.5 rounded-full', statusDotClass]" />
|
|
113
|
+
<span class="text-sm capitalize">{{ status }}</span>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="flex items-center justify-between gap-2 px-3 py-2">
|
|
117
|
+
<div class="flex items-center gap-2 text-sm text-(--ui-text-muted) min-w-0">
|
|
118
|
+
<UIcon
|
|
119
|
+
name="i-lucide-shield"
|
|
120
|
+
class="size-3.5 shrink-0"
|
|
121
|
+
/>
|
|
122
|
+
<span class="truncate">Your role</span>
|
|
123
|
+
</div>
|
|
124
|
+
<UBadge
|
|
125
|
+
v-if="effectiveRole"
|
|
126
|
+
:color="roleBadgeColor"
|
|
127
|
+
variant="subtle"
|
|
128
|
+
:label="effectiveRole"
|
|
129
|
+
size="sm"
|
|
130
|
+
class="capitalize shrink-0"
|
|
131
|
+
/>
|
|
132
|
+
<span
|
|
133
|
+
v-else
|
|
134
|
+
class="text-sm text-(--ui-text-dimmed)"
|
|
135
|
+
>—</span>
|
|
136
|
+
</div>
|
|
137
|
+
<div class="flex items-center justify-between gap-2 px-3 py-2">
|
|
138
|
+
<div class="flex items-center gap-2 text-sm text-(--ui-text-muted) min-w-0">
|
|
139
|
+
<UIcon
|
|
140
|
+
name="i-lucide-refresh-ccw"
|
|
141
|
+
class="size-3.5 shrink-0"
|
|
142
|
+
/>
|
|
143
|
+
<span class="truncate">Synced</span>
|
|
144
|
+
</div>
|
|
145
|
+
<UBadge
|
|
146
|
+
:color="synced ? 'success' : 'neutral'"
|
|
147
|
+
variant="subtle"
|
|
148
|
+
:label="synced ? 'Yes' : 'No'"
|
|
149
|
+
:icon="synced ? 'i-lucide-check' : 'i-lucide-circle'"
|
|
150
|
+
size="sm"
|
|
151
|
+
class="shrink-0"
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
<div
|
|
155
|
+
v-if="serverInfo?.version"
|
|
156
|
+
class="flex items-center justify-between gap-2 px-3 py-2"
|
|
157
|
+
>
|
|
158
|
+
<div class="flex items-center gap-2 text-sm text-(--ui-text-muted) min-w-0">
|
|
159
|
+
<UIcon
|
|
160
|
+
name="i-lucide-tag"
|
|
161
|
+
class="size-3.5 shrink-0"
|
|
162
|
+
/>
|
|
163
|
+
<span class="truncate">Version</span>
|
|
164
|
+
</div>
|
|
165
|
+
<div class="flex items-center gap-1 shrink-0">
|
|
166
|
+
<UBadge
|
|
167
|
+
color="neutral"
|
|
168
|
+
variant="subtle"
|
|
169
|
+
:label="`v${serverInfo.version}`"
|
|
170
|
+
size="sm"
|
|
171
|
+
/>
|
|
172
|
+
<UBadge
|
|
173
|
+
v-if="serverInfo.protocol_version"
|
|
174
|
+
color="neutral"
|
|
175
|
+
variant="outline"
|
|
176
|
+
:label="`p${serverInfo.protocol_version}`"
|
|
177
|
+
size="sm"
|
|
178
|
+
/>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
<div
|
|
182
|
+
v-if="serverInfo?.invite_only !== void 0"
|
|
183
|
+
class="flex items-center justify-between gap-2 px-3 py-2"
|
|
184
|
+
>
|
|
185
|
+
<div class="flex items-center gap-2 text-sm text-(--ui-text-muted) min-w-0">
|
|
186
|
+
<UIcon
|
|
187
|
+
:name="serverInfo.invite_only ? 'i-lucide-lock' : 'i-lucide-globe'"
|
|
188
|
+
class="size-3.5 shrink-0"
|
|
189
|
+
/>
|
|
190
|
+
<span class="truncate">Invite only</span>
|
|
191
|
+
</div>
|
|
192
|
+
<UBadge
|
|
193
|
+
:color="serverInfo.invite_only ? 'warning' : 'success'"
|
|
194
|
+
variant="subtle"
|
|
195
|
+
:label="serverInfo.invite_only ? 'Yes' : 'No'"
|
|
196
|
+
size="sm"
|
|
197
|
+
class="shrink-0"
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="flex items-center justify-between gap-2 px-3 py-2">
|
|
201
|
+
<div class="flex items-center gap-2 text-sm text-(--ui-text-muted) min-w-0">
|
|
202
|
+
<UIcon
|
|
203
|
+
name="i-lucide-heart-pulse"
|
|
204
|
+
class="size-3.5 shrink-0"
|
|
205
|
+
/>
|
|
206
|
+
<span class="truncate">Health</span>
|
|
207
|
+
</div>
|
|
208
|
+
<UButton
|
|
209
|
+
:label="healthData ? `v${healthData.version}` : 'Check'"
|
|
210
|
+
color="neutral"
|
|
211
|
+
variant="ghost"
|
|
212
|
+
size="xs"
|
|
213
|
+
class="shrink-0"
|
|
214
|
+
:loading="healthLoading"
|
|
215
|
+
@click="checkHealth"
|
|
216
|
+
/>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<!-- Admin surfaces — opt-in via slots, gated by role -->
|
|
222
|
+
<div
|
|
223
|
+
v-for="section in adminSections"
|
|
224
|
+
:key="section.key"
|
|
225
|
+
class="rounded-lg bg-(--ui-bg-elevated) overflow-hidden"
|
|
226
|
+
>
|
|
227
|
+
<button
|
|
228
|
+
type="button"
|
|
229
|
+
class="w-full flex items-center gap-1.5 px-3 py-2 border-b border-(--ui-border) hover:bg-(--ui-bg-accented)/40 transition-colors"
|
|
230
|
+
:class="{ 'border-b-0': !expanded[section.key] }"
|
|
231
|
+
@click="expanded[section.key] = !expanded[section.key]"
|
|
232
|
+
>
|
|
233
|
+
<UIcon
|
|
234
|
+
:name="section.icon"
|
|
235
|
+
class="size-3.5 text-(--ui-text-muted) shrink-0"
|
|
236
|
+
/>
|
|
237
|
+
<span class="text-xs font-semibold uppercase tracking-wider text-(--ui-text-muted) flex-1 text-left">
|
|
238
|
+
{{ section.label }}
|
|
239
|
+
</span>
|
|
240
|
+
<UIcon
|
|
241
|
+
:name="expanded[section.key] ? 'i-lucide-chevron-down' : 'i-lucide-chevron-right'"
|
|
242
|
+
class="size-3.5 text-(--ui-text-dimmed)"
|
|
243
|
+
/>
|
|
244
|
+
</button>
|
|
245
|
+
<div
|
|
246
|
+
v-if="expanded[section.key]"
|
|
247
|
+
class="px-3 py-3"
|
|
248
|
+
>
|
|
249
|
+
<slot :name="section.key" />
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** Hub document id (informational — the panel reflects the active server). */
|
|
3
|
+
docId?: string;
|
|
4
|
+
};
|
|
5
|
+
declare var __VLS_96: "storage" | "users" | "members" | "invites", __VLS_97: {};
|
|
6
|
+
type __VLS_Slots = {} & {
|
|
7
|
+
[K in NonNullable<typeof __VLS_96>]?: (props: typeof __VLS_97) => any;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
11
|
+
declare const _default: typeof __VLS_export;
|
|
12
|
+
export default _default;
|
|
13
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
14
|
+
new (): {
|
|
15
|
+
$slots: S;
|
|
16
|
+
};
|
|
17
|
+
};
|