@revenexx/studio-shared 0.4.0 → 0.4.1
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 +5 -3
- package/dist/module.json +2 -2
- package/dist/module.mjs +7 -3
- package/dist/runtime/components/Dashboard/DashboardConfirmDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardGrid.vue +45 -1
- package/dist/runtime/components/Dashboard/DashboardNameDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardPickerDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardShareDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetConfigDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.d.vue.ts +2 -2
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.vue +14 -3
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.vue.d.ts +2 -2
- package/dist/runtime/components/DataTable/DataTable.d.vue.ts +73 -34
- package/dist/runtime/components/DataTable/DataTable.vue +352 -52
- package/dist/runtime/components/DataTable/DataTable.vue.d.ts +73 -34
- package/dist/runtime/components/DataTable/FacetPanel.vue +57 -8
- package/dist/runtime/components/DataTable/FilterMenu.vue +5 -5
- package/dist/runtime/components/DataTable/SavedViewsMenu.vue +61 -12
- package/dist/runtime/components/DataTable/SortMenu.vue +4 -1
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.d.vue.ts +23 -0
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.vue +29 -0
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.vue.d.ts +23 -0
- package/dist/runtime/components/DataTable/types.d.ts +17 -0
- package/dist/runtime/components/Form/FieldGrid.vue +1 -1
- package/dist/runtime/components/Form/SaveBar.d.vue.ts +1 -1
- package/dist/runtime/components/Form/SaveBar.vue.d.ts +1 -1
- package/dist/runtime/components/Media/MediaFolderTree.d.vue.ts +4 -4
- package/dist/runtime/components/Media/MediaFolderTree.vue +1 -2
- package/dist/runtime/components/Media/MediaFolderTree.vue.d.ts +4 -4
- package/dist/runtime/components/Media/MediaPickerDialog.d.vue.ts +11 -0
- package/dist/runtime/components/Media/MediaPickerDialog.vue +206 -54
- package/dist/runtime/components/Media/MediaPickerDialog.vue.d.ts +11 -0
- package/dist/runtime/components/Media/MediaUploader.vue +1 -1
- package/dist/runtime/components/Shared/AppIcon.d.vue.ts +1 -1
- package/dist/runtime/components/Shared/AppIcon.vue.d.ts +1 -1
- package/dist/runtime/components/Shared/CardSizeToggle.d.vue.ts +11 -0
- package/dist/runtime/components/Shared/CardSizeToggle.vue +19 -0
- package/dist/runtime/components/Shared/CardSizeToggle.vue.d.ts +11 -0
- package/dist/runtime/components/Shared/DetailSheet.d.vue.ts +1 -1
- package/dist/runtime/components/Shared/DetailSheet.vue +9 -5
- package/dist/runtime/components/Shared/DetailSheet.vue.d.ts +1 -1
- package/dist/runtime/components/Shared/EmptyNote.d.vue.ts +19 -0
- package/dist/runtime/components/Shared/EmptyNote.vue +25 -0
- package/dist/runtime/components/Shared/EmptyNote.vue.d.ts +19 -0
- package/dist/runtime/components/Shared/KpiTile.d.vue.ts +6 -0
- package/dist/runtime/components/Shared/KpiTile.vue +10 -9
- package/dist/runtime/components/Shared/KpiTile.vue.d.ts +6 -0
- package/dist/runtime/components/Shared/PageHeader.vue +15 -4
- package/dist/runtime/components/Shared/RecordLayout.vue +1 -2
- package/dist/runtime/components/Shared/RecordRailCard.vue +3 -3
- package/dist/runtime/components/Shared/SelectionBar.d.vue.ts +22 -0
- package/dist/runtime/components/Shared/SelectionBar.vue +40 -0
- package/dist/runtime/components/Shared/SelectionBar.vue.d.ts +22 -0
- package/dist/runtime/components/Shared/SidebarNav.d.vue.ts +36 -2
- package/dist/runtime/components/Shared/SidebarNav.vue +71 -25
- package/dist/runtime/components/Shared/SidebarNav.vue.d.ts +36 -2
- package/dist/runtime/components/Shared/SidebarNavAreas.d.vue.ts +7 -0
- package/dist/runtime/components/Shared/SidebarNavAreas.vue +291 -0
- package/dist/runtime/components/Shared/SidebarNavAreas.vue.d.ts +7 -0
- package/dist/runtime/components/Shared/SidebarNavLink.d.vue.ts +1 -9
- package/dist/runtime/components/Shared/SidebarNavLink.vue +31 -5
- package/dist/runtime/components/Shared/SidebarNavLink.vue.d.ts +1 -9
- package/dist/runtime/components/Shared/SortHeader.vue +6 -2
- package/dist/runtime/components/Shared/StateCard.vue +1 -1
- package/dist/runtime/components/Shared/TabBar.vue +6 -7
- package/dist/runtime/components/Shared/Wizard.d.vue.ts +11 -1
- package/dist/runtime/components/Shared/Wizard.vue +9 -5
- package/dist/runtime/components/Shared/Wizard.vue.d.ts +11 -1
- package/dist/runtime/composables/useMediaLibrary.d.ts +12 -0
- package/dist/runtime/composables/useSavedViews.d.ts +11 -1
- package/dist/runtime/composables/useSavedViews.js +4 -4
- package/dist/runtime/composables/useWidgetFigures.d.ts +12 -0
- package/dist/runtime/composables/useWidgetFigures.js +24 -0
- package/dist/runtime/composables/useWidgetHeader.d.ts +15 -0
- package/dist/runtime/composables/useWidgetHeader.js +15 -0
- package/dist/runtime/lib/auditEnvelope.d.ts +43 -0
- package/dist/runtime/lib/auditEnvelope.js +55 -0
- package/dist/runtime/lib/cardSize.d.ts +13 -0
- package/dist/runtime/lib/cardSize.js +20 -0
- package/dist/runtime/lib/dashboardIcons.js +2 -0
- package/dist/runtime/lib/dataTableFilters.d.ts +22 -0
- package/dist/runtime/lib/dataTableFilters.js +5 -0
- package/dist/runtime/lib/facets.d.ts +13 -0
- package/dist/runtime/lib/formLayout.d.ts +74 -4
- package/dist/runtime/lib/formLayout.js +53 -6
- package/dist/runtime/lib/gridTracks.d.ts +14 -1
- package/dist/runtime/lib/gridTracks.js +13 -2
- package/dist/runtime/lib/isoLists.d.ts +37 -2
- package/dist/runtime/lib/isoLists.js +54 -1
- package/dist/runtime/lib/notice.d.ts +14 -0
- package/dist/runtime/lib/notice.js +19 -0
- package/dist/runtime/lib/pageSize.d.ts +15 -0
- package/dist/runtime/lib/pageSize.js +26 -0
- package/dist/runtime/lib/sidebarAreas.d.ts +46 -0
- package/dist/runtime/lib/sidebarAreas.js +25 -0
- package/dist/runtime/lib/sidebarNav.d.ts +21 -2
- package/dist/runtime/lib/sidebarNav.js +23 -4
- package/dist/runtime/lib/solarIconMap.d.ts +2 -1
- package/dist/runtime/lib/solarIconMap.js +50 -4
- package/dist/runtime/lib/swipeToClose.d.ts +25 -0
- package/dist/runtime/lib/swipeToClose.js +118 -0
- package/dist/runtime/lib/tableExport.d.ts +31 -0
- package/dist/runtime/lib/tableExport.js +143 -0
- package/dist/runtime/lib/talkback.d.ts +5 -0
- package/dist/runtime/lib/talkback.js +8 -0
- package/dist/runtime/lib/talkbackTokenBatch.d.ts +35 -0
- package/dist/runtime/lib/talkbackTokenBatch.js +101 -0
- package/dist/runtime/types/nav.d.ts +9 -0
- package/dist/types.d.mts +4 -0
- package/package.json +4 -3
|
@@ -29,8 +29,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
29
29
|
onCancel?: (() => any) | undefined;
|
|
30
30
|
}>, {
|
|
31
31
|
dirty: boolean;
|
|
32
|
-
canSubmit: boolean;
|
|
33
32
|
busy: boolean;
|
|
33
|
+
canSubmit: boolean;
|
|
34
34
|
allowClean: boolean;
|
|
35
35
|
hideCancel: boolean;
|
|
36
36
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { StorageFolderNode } from '../../types/storage.js';
|
|
2
2
|
/**
|
|
3
|
-
* Recursive folder tree for the media browser sidebar. Emits `select` with
|
|
4
|
-
* folder id
|
|
3
|
+
* Recursive folder tree for the media browser sidebar. Emits `select` with the
|
|
4
|
+
* clicked folder's id. Self-renders for children.
|
|
5
5
|
*/
|
|
6
6
|
type __VLS_Props = {
|
|
7
7
|
nodes: StorageFolderNode[];
|
|
@@ -10,9 +10,9 @@ type __VLS_Props = {
|
|
|
10
10
|
depth?: number;
|
|
11
11
|
};
|
|
12
12
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
-
select: (id: string
|
|
13
|
+
select: (id: string) => any;
|
|
14
14
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
-
onSelect?: ((id: string
|
|
15
|
+
onSelect?: ((id: string) => any) | undefined;
|
|
16
16
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
17
|
declare const _default: typeof __VLS_export;
|
|
18
18
|
export default _default;
|
|
@@ -38,8 +38,7 @@ const t = useT();
|
|
|
38
38
|
<AltArrowRight
|
|
39
39
|
:size="12"
|
|
40
40
|
class="transition-transform"
|
|
41
|
-
:class="{ 'rotate-90': expanded.has(node.id) }"
|
|
42
|
-
/>
|
|
41
|
+
:class="{ 'rotate-90': expanded.has(node.id) }" weight="Bold" />
|
|
43
42
|
</button>
|
|
44
43
|
<component
|
|
45
44
|
:is="currentId === node.id ? FolderOpen : FolderIcon"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { StorageFolderNode } from '../../types/storage.js';
|
|
2
2
|
/**
|
|
3
|
-
* Recursive folder tree for the media browser sidebar. Emits `select` with
|
|
4
|
-
* folder id
|
|
3
|
+
* Recursive folder tree for the media browser sidebar. Emits `select` with the
|
|
4
|
+
* clicked folder's id. Self-renders for children.
|
|
5
5
|
*/
|
|
6
6
|
type __VLS_Props = {
|
|
7
7
|
nodes: StorageFolderNode[];
|
|
@@ -10,9 +10,9 @@ type __VLS_Props = {
|
|
|
10
10
|
depth?: number;
|
|
11
11
|
};
|
|
12
12
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
-
select: (id: string
|
|
13
|
+
select: (id: string) => any;
|
|
14
14
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
-
onSelect?: ((id: string
|
|
15
|
+
onSelect?: ((id: string) => any) | undefined;
|
|
16
16
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
17
|
declare const _default: typeof __VLS_export;
|
|
18
18
|
export default _default;
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import type { StorageAsset } from '../../types/storage.js';
|
|
2
|
+
export interface PickerCatalogueEntry {
|
|
3
|
+
/** What the record is called — shown instead of the file name. */
|
|
4
|
+
title: string;
|
|
5
|
+
/** One quiet line under it: type, licence. */
|
|
6
|
+
sub?: string;
|
|
7
|
+
}
|
|
2
8
|
type __VLS_Props = {
|
|
3
9
|
open: boolean;
|
|
4
10
|
multiple?: boolean;
|
|
5
11
|
/** Restrict the grid to these asset kinds (e.g. ['image']). */
|
|
6
12
|
kinds?: string[];
|
|
13
|
+
/** Records that manage these files, keyed by storage id — see the header. */
|
|
14
|
+
catalogue?: Record<string, PickerCatalogueEntry> | null;
|
|
7
15
|
};
|
|
8
16
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
17
|
"update:open": (value: boolean) => any;
|
|
10
18
|
select: (assets: StorageAsset[]) => any;
|
|
19
|
+
uploaded: (assets: StorageAsset[]) => any;
|
|
11
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
21
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
13
22
|
onSelect?: ((assets: StorageAsset[]) => any) | undefined;
|
|
23
|
+
onUploaded?: ((assets: StorageAsset[]) => any) | undefined;
|
|
14
24
|
}>, {
|
|
15
25
|
multiple: boolean;
|
|
16
26
|
kinds: string[];
|
|
27
|
+
catalogue: Record<string, PickerCatalogueEntry> | null;
|
|
17
28
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
29
|
declare const _default: typeof __VLS_export;
|
|
19
30
|
export default _default;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { Button, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@revenexx/studio";
|
|
3
|
-
import { CloudUpload, FileText } from "#solar-icons";
|
|
2
|
+
import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, SegmentedToggle, SegmentedToggleItem, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@revenexx/studio";
|
|
3
|
+
import { CloudUpload, FileText, Gallery, ListCheck, Magnifer } from "#solar-icons";
|
|
4
4
|
import MediaFolderTree from "./MediaFolderTree.vue";
|
|
5
5
|
import MediaUploader from "./MediaUploader.vue";
|
|
6
6
|
const props = defineProps({
|
|
7
7
|
open: { type: Boolean, required: true },
|
|
8
8
|
multiple: { type: Boolean, required: false, default: false },
|
|
9
|
-
kinds: { type: Array, required: false, default: void 0 }
|
|
9
|
+
kinds: { type: Array, required: false, default: void 0 },
|
|
10
|
+
catalogue: { type: [Object, null], required: false, default: null }
|
|
10
11
|
});
|
|
11
|
-
const emit = defineEmits(["update:open", "select"]);
|
|
12
|
+
const emit = defineEmits(["update:open", "select", "uploaded"]);
|
|
13
|
+
const lib = useMediaLibrary();
|
|
12
14
|
const {
|
|
13
15
|
assets,
|
|
14
16
|
folderTree,
|
|
@@ -23,15 +25,76 @@ const {
|
|
|
23
25
|
loadMore,
|
|
24
26
|
thumbnailUrl,
|
|
25
27
|
isProcessing
|
|
26
|
-
} =
|
|
28
|
+
} = lib;
|
|
27
29
|
const t = useT();
|
|
28
30
|
const selected = ref([]);
|
|
29
31
|
const uploadOpen = ref(false);
|
|
30
32
|
const failedThumbs = ref(/* @__PURE__ */ new Set());
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const canSearch = computed(() => !!lib.search && !!lib.loadAssets);
|
|
34
|
+
const query = ref("");
|
|
35
|
+
const KIND_CHIPS = [
|
|
36
|
+
{ value: "image", key: "images" },
|
|
37
|
+
{ value: "video", key: "videos" },
|
|
38
|
+
{ value: "pdf", key: "pdfs" },
|
|
39
|
+
{ value: "document", key: "documents" }
|
|
40
|
+
];
|
|
41
|
+
const chips = computed(() => KIND_CHIPS.filter((c) => !props.kinds?.length || props.kinds.includes(c.value)));
|
|
42
|
+
const kindChip = ref(null);
|
|
43
|
+
const sort = ref("-created_at");
|
|
44
|
+
let searchTimer = null;
|
|
45
|
+
function reload() {
|
|
46
|
+
if (!lib.loadAssets) return;
|
|
47
|
+
if (lib.search) lib.search.value = query.value.trim();
|
|
48
|
+
if (lib.kind) lib.kind.value = kindChip.value;
|
|
49
|
+
if (lib.sortKey) lib.sortKey.value = sort.value;
|
|
50
|
+
void lib.loadAssets();
|
|
51
|
+
}
|
|
52
|
+
watch(query, () => {
|
|
53
|
+
if (searchTimer) clearTimeout(searchTimer);
|
|
54
|
+
searchTimer = setTimeout(reload, 300);
|
|
55
|
+
});
|
|
56
|
+
watch([kindChip, sort], reload);
|
|
57
|
+
const scope = ref("assets");
|
|
58
|
+
const hasCatalogue = computed(() => !!props.catalogue);
|
|
59
|
+
const entryOf = (a) => props.catalogue?.[a.id] ?? null;
|
|
60
|
+
const visibleAssets = computed(() => {
|
|
61
|
+
let list = props.kinds?.length ? assets.value.filter((a) => props.kinds.includes(a.kind)) : assets.value;
|
|
62
|
+
if (hasCatalogue.value && scope.value === "assets") list = list.filter((a) => !!entryOf(a));
|
|
63
|
+
return list;
|
|
64
|
+
});
|
|
65
|
+
const titleOf = (a) => entryOf(a)?.title || a.display_name || a.original_name;
|
|
66
|
+
function factsOf(a) {
|
|
67
|
+
const ext = /\.([a-z0-9]{2,5})$/i.exec(a.original_name ?? "")?.[1]?.toUpperCase() ?? (a.mime_type?.split("/")[1] ?? "").toUpperCase();
|
|
68
|
+
const kb = a.size_bytes != null ? a.size_bytes >= 1048576 ? `${(a.size_bytes / 1048576).toFixed(1).replace(".", ",")} MB` : `${Math.max(1, Math.round(a.size_bytes / 1024))} KB` : "";
|
|
69
|
+
const dims = a.width && a.height ? `${a.width} \xD7 ${a.height}` : "";
|
|
70
|
+
return [ext, kb, dims].filter(Boolean).join(" \xB7 ");
|
|
71
|
+
}
|
|
72
|
+
const VIEW_KEY = "rx.media.picker.view";
|
|
73
|
+
function storedView() {
|
|
74
|
+
try {
|
|
75
|
+
return import.meta.client && localStorage.getItem(VIEW_KEY) === "list" ? "list" : "gallery";
|
|
76
|
+
} catch {
|
|
77
|
+
return "gallery";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const view = ref(storedView());
|
|
81
|
+
watch(view, (v) => {
|
|
82
|
+
try {
|
|
83
|
+
localStorage.setItem(VIEW_KEY, v);
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const sentinel = ref(null);
|
|
88
|
+
let observer = null;
|
|
89
|
+
watch(sentinel, (el) => {
|
|
90
|
+
observer?.disconnect();
|
|
91
|
+
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
92
|
+
observer = new IntersectionObserver((entries) => {
|
|
93
|
+
if (entries.some((e) => e.isIntersecting) && hasMore.value && !loadingAssets.value) void loadMore();
|
|
94
|
+
}, { rootMargin: "200px" });
|
|
95
|
+
observer.observe(el);
|
|
96
|
+
});
|
|
97
|
+
onBeforeUnmount(() => observer?.disconnect());
|
|
35
98
|
function isSelected(asset) {
|
|
36
99
|
return selected.value.some((a) => a.id === asset.id);
|
|
37
100
|
}
|
|
@@ -52,31 +115,46 @@ function confirm() {
|
|
|
52
115
|
emit("select", selected.value);
|
|
53
116
|
emit("update:open", false);
|
|
54
117
|
}
|
|
118
|
+
let beforeUpload = /* @__PURE__ */ new Set();
|
|
119
|
+
function startUpload() {
|
|
120
|
+
beforeUpload = new Set(assets.value.map((a) => a.id));
|
|
121
|
+
uploadOpen.value = true;
|
|
122
|
+
}
|
|
55
123
|
function onUploaded() {
|
|
56
124
|
uploadOpen.value = false;
|
|
125
|
+
const fresh = assets.value.filter((a) => !beforeUpload.has(a.id));
|
|
126
|
+
if (fresh.length) emit("uploaded", fresh);
|
|
57
127
|
}
|
|
58
128
|
watch(() => props.open, (open) => {
|
|
59
129
|
if (open) {
|
|
60
130
|
selected.value = [];
|
|
131
|
+
query.value = "";
|
|
132
|
+
kindChip.value = null;
|
|
133
|
+
sort.value = "-created_at";
|
|
134
|
+
scope.value = "assets";
|
|
135
|
+
lib.resetFilters?.();
|
|
61
136
|
void init();
|
|
137
|
+
} else {
|
|
138
|
+
lib.resetFilters?.();
|
|
62
139
|
}
|
|
63
140
|
});
|
|
64
141
|
</script>
|
|
65
142
|
|
|
66
143
|
<template>
|
|
67
144
|
<Dialog :open="open" @update:open="(v) => emit('update:open', v)">
|
|
68
|
-
<DialogContent class="max-w-
|
|
145
|
+
<DialogContent class="sm:max-w-5xl">
|
|
69
146
|
<DialogHeader>
|
|
70
147
|
<DialogTitle>{{ multiple ? t("shared.media.picker.title.multiple") : t("shared.media.picker.title.single") }}</DialogTitle>
|
|
148
|
+
<DialogDescription>{{ multiple ? t("shared.media.picker.description.multiple") : t("shared.media.picker.description.single") }}</DialogDescription>
|
|
71
149
|
</DialogHeader>
|
|
72
150
|
|
|
73
|
-
<div class="flex
|
|
151
|
+
<div class="flex h-[30rem] gap-4">
|
|
74
152
|
<!-- Folder sidebar -->
|
|
75
153
|
<div class="w-56 shrink-0 overflow-y-auto border-r border-black/[0.06] pr-2">
|
|
76
154
|
<button
|
|
77
155
|
type="button"
|
|
78
|
-
class="w-full
|
|
79
|
-
:class="currentView === 'all' ? 'bg-primary/10 text-[#0B0522]
|
|
156
|
+
class="w-full rounded-md px-2 py-1 text-left text-sm transition-colors"
|
|
157
|
+
:class="currentView === 'all' ? 'bg-primary/10 font-medium text-[#0B0522]' : 'text-foreground/80 hover:bg-primary/5'"
|
|
80
158
|
@click="showAllMedia"
|
|
81
159
|
>
|
|
82
160
|
{{ t("shared.media.picker.action.allmedia") }}
|
|
@@ -88,53 +166,127 @@ watch(() => props.open, (open) => {
|
|
|
88
166
|
/>
|
|
89
167
|
</div>
|
|
90
168
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<div class="flex items-center
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
169
|
+
<div class="flex min-w-0 flex-1 flex-col">
|
|
170
|
+
<!-- Toolbar: search, kinds, sort, scope, view, upload -->
|
|
171
|
+
<div class="mb-2 flex flex-wrap items-center gap-2">
|
|
172
|
+
<div v-if="canSearch" class="relative min-w-48 flex-1">
|
|
173
|
+
<Magnifer :size="14" class="pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
|
174
|
+
<Input v-model="query" type="search" class="h-8 pl-8 text-sm" :placeholder="t('shared.media.picker.search')" :aria-label="t('shared.media.picker.search')" />
|
|
175
|
+
</div>
|
|
176
|
+
<Select v-if="canSearch && lib.sortKey" v-model="sort">
|
|
177
|
+
<SelectTrigger class="h-8 w-36 text-sm" :aria-label="t('shared.media.picker.sort.label')"><SelectValue /></SelectTrigger>
|
|
178
|
+
<SelectContent>
|
|
179
|
+
<SelectItem value="-created_at">{{ t("shared.media.picker.sort.newest") }}</SelectItem>
|
|
180
|
+
<SelectItem value="original_name">{{ t("shared.media.picker.sort.name") }}</SelectItem>
|
|
181
|
+
</SelectContent>
|
|
182
|
+
</Select>
|
|
183
|
+
<SegmentedToggle v-model="view" variant="inset" :aria-label="t('shared.media.picker.view.label')">
|
|
184
|
+
<SegmentedToggleItem value="gallery" :aria-label="t('shared.media.picker.view.gallery')"><Gallery :size="14" /></SegmentedToggleItem>
|
|
185
|
+
<SegmentedToggleItem value="list" :aria-label="t('shared.media.picker.view.list')"><ListCheck :size="14" /></SegmentedToggleItem>
|
|
186
|
+
</SegmentedToggle>
|
|
187
|
+
<Button variant="outline" size="sm" class="h-8 text-sm" @click="startUpload">
|
|
98
188
|
<CloudUpload :size="14" /> {{ t("shared.media.picker.action.upload") }}
|
|
99
189
|
</Button>
|
|
100
190
|
</div>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
class="
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
:
|
|
120
|
-
|
|
121
|
-
class="h-full w-full object-cover"
|
|
122
|
-
:class="{ 'opacity-50': isProcessing(asset) }"
|
|
123
|
-
@error="markFailed(thumbnailUrl(asset))"
|
|
191
|
+
<div class="mb-2 flex flex-wrap items-center gap-1.5">
|
|
192
|
+
<template v-if="hasCatalogue">
|
|
193
|
+
<button
|
|
194
|
+
v-for="s in ['assets', 'files']"
|
|
195
|
+
:key="s"
|
|
196
|
+
type="button"
|
|
197
|
+
class="rounded-full border px-2.5 py-0.5 text-xs transition-colors"
|
|
198
|
+
:class="scope === s ? 'border-primary bg-primary/10 text-[#0B0522]' : 'border-black/[0.08] text-muted-foreground hover:border-primary/40'"
|
|
199
|
+
@click="scope = s"
|
|
200
|
+
>
|
|
201
|
+
{{ t(`shared.media.picker.scope.${s}`) }}
|
|
202
|
+
</button>
|
|
203
|
+
<span class="mx-1 h-4 w-px bg-black/[0.08]" />
|
|
204
|
+
</template>
|
|
205
|
+
<template v-if="canSearch && lib.kind && chips.length > 1">
|
|
206
|
+
<button
|
|
207
|
+
type="button"
|
|
208
|
+
class="rounded-full border px-2.5 py-0.5 text-xs transition-colors"
|
|
209
|
+
:class="kindChip === null ? 'border-primary bg-primary/10 text-[#0B0522]' : 'border-black/[0.08] text-muted-foreground hover:border-primary/40'"
|
|
210
|
+
@click="kindChip = null"
|
|
124
211
|
>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
212
|
+
{{ t("shared.media.picker.kind.all") }}
|
|
213
|
+
</button>
|
|
214
|
+
<button
|
|
215
|
+
v-for="c in chips"
|
|
216
|
+
:key="c.value"
|
|
217
|
+
type="button"
|
|
218
|
+
class="rounded-full border px-2.5 py-0.5 text-xs transition-colors"
|
|
219
|
+
:class="kindChip === c.value ? 'border-primary bg-primary/10 text-[#0B0522]' : 'border-black/[0.08] text-muted-foreground hover:border-primary/40'"
|
|
220
|
+
@click="kindChip = kindChip === c.value ? null : c.value"
|
|
221
|
+
>
|
|
222
|
+
{{ t(`shared.media.picker.kind.${c.key}`) }}
|
|
223
|
+
</button>
|
|
224
|
+
</template>
|
|
225
|
+
<span class="ml-auto text-xs text-muted-foreground">{{ t("shared.media.picker.count", visibleAssets.length) }}</span>
|
|
132
226
|
</div>
|
|
133
227
|
|
|
134
|
-
<div
|
|
135
|
-
<
|
|
136
|
-
{{ t("shared.media.picker.
|
|
137
|
-
</
|
|
228
|
+
<div class="min-h-0 flex-1 overflow-y-auto">
|
|
229
|
+
<div v-if="loadingAssets && !visibleAssets.length" class="py-12 text-center text-sm text-muted-foreground">
|
|
230
|
+
{{ t("shared.media.picker.loading") }}
|
|
231
|
+
</div>
|
|
232
|
+
<div v-else-if="!visibleAssets.length" class="py-12 text-center text-sm text-muted-foreground">
|
|
233
|
+
<p class="font-medium text-foreground/80">{{ hasCatalogue && scope === "assets" ? t("shared.media.picker.emptyAssets") : t("shared.media.picker.empty") }}</p>
|
|
234
|
+
<button v-if="hasCatalogue && scope === 'assets'" type="button" class="mt-1 text-primary hover:underline" @click="scope = 'files'">{{ t("shared.media.picker.showFiles") }}</button>
|
|
235
|
+
</div>
|
|
236
|
+
<div v-else-if="view === 'gallery'" class="grid grid-cols-3 gap-3 sm:grid-cols-4">
|
|
237
|
+
<button
|
|
238
|
+
v-for="asset in visibleAssets"
|
|
239
|
+
:key="asset.id"
|
|
240
|
+
type="button"
|
|
241
|
+
class="group relative aspect-square overflow-hidden rounded-md border transition-all"
|
|
242
|
+
:class="isSelected(asset) ? 'border-primary ring-2 ring-primary' : 'border-black/[0.06] hover:border-primary/40'"
|
|
243
|
+
:aria-pressed="isSelected(asset)"
|
|
244
|
+
@click="toggle(asset)"
|
|
245
|
+
>
|
|
246
|
+
<img
|
|
247
|
+
v-if="thumbnailUrl(asset) && !failedThumbs.has(thumbnailUrl(asset))"
|
|
248
|
+
:src="thumbnailUrl(asset)"
|
|
249
|
+
:alt="asset.alt_text ?? titleOf(asset)"
|
|
250
|
+
class="h-full w-full object-cover"
|
|
251
|
+
:class="{ 'opacity-50': isProcessing(asset) }"
|
|
252
|
+
@error="markFailed(thumbnailUrl(asset))"
|
|
253
|
+
>
|
|
254
|
+
<span v-else class="flex h-full w-full items-center justify-center">
|
|
255
|
+
<FileText :size="28" class="text-foreground/30" />
|
|
256
|
+
</span>
|
|
257
|
+
<span class="absolute inset-x-0 bottom-0 bg-black/55 px-1.5 py-0.5 text-left text-[11px] text-white">
|
|
258
|
+
<span class="block truncate">{{ titleOf(asset) }}</span>
|
|
259
|
+
<span v-if="entryOf(asset)?.sub" class="block truncate text-white/75">{{ entryOf(asset).sub }}</span>
|
|
260
|
+
</span>
|
|
261
|
+
</button>
|
|
262
|
+
</div>
|
|
263
|
+
<ul v-else class="divide-y divide-black/[0.06] rounded-md border border-black/[0.06]">
|
|
264
|
+
<li v-for="asset in visibleAssets" :key="asset.id">
|
|
265
|
+
<button
|
|
266
|
+
type="button"
|
|
267
|
+
class="flex w-full items-center gap-3 px-2 py-1.5 text-left text-sm transition-colors"
|
|
268
|
+
:class="isSelected(asset) ? 'bg-primary/10' : 'hover:bg-primary/[0.04]'"
|
|
269
|
+
:aria-pressed="isSelected(asset)"
|
|
270
|
+
@click="toggle(asset)"
|
|
271
|
+
>
|
|
272
|
+
<span class="grid size-9 shrink-0 place-items-center overflow-hidden rounded border border-black/[0.06] bg-muted/40">
|
|
273
|
+
<img v-if="thumbnailUrl(asset, 80) && !failedThumbs.has(thumbnailUrl(asset, 80))" :src="thumbnailUrl(asset, 80)" alt="" class="h-full w-full object-cover" @error="markFailed(thumbnailUrl(asset, 80))">
|
|
274
|
+
<FileText v-else :size="16" class="text-foreground/30" />
|
|
275
|
+
</span>
|
|
276
|
+
<span class="min-w-0 flex-1">
|
|
277
|
+
<span class="block truncate font-medium text-[#0B0522]">{{ titleOf(asset) }}</span>
|
|
278
|
+
<span class="block truncate text-xs text-muted-foreground">{{ [entryOf(asset)?.sub, factsOf(asset)].filter(Boolean).join(" \xB7 ") }}</span>
|
|
279
|
+
</span>
|
|
280
|
+
<span v-if="!asset.alt_text && asset.kind === 'image'" class="shrink-0 rounded-full bg-amber-50 px-2 py-0.5 text-[11px] text-amber-700">{{ t("shared.media.picker.altMissing") }}</span>
|
|
281
|
+
</button>
|
|
282
|
+
</li>
|
|
283
|
+
</ul>
|
|
284
|
+
|
|
285
|
+
<div v-if="hasMore" ref="sentinel" class="mt-3 flex justify-center">
|
|
286
|
+
<Button variant="outline" size="sm" class="h-7 text-sm" :disabled="loadingAssets" @click="loadMore">
|
|
287
|
+
{{ t("shared.media.picker.action.loadmore") }}
|
|
288
|
+
</Button>
|
|
289
|
+
</div>
|
|
138
290
|
</div>
|
|
139
291
|
</div>
|
|
140
292
|
</div>
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import type { StorageAsset } from '../../types/storage.js';
|
|
2
|
+
export interface PickerCatalogueEntry {
|
|
3
|
+
/** What the record is called — shown instead of the file name. */
|
|
4
|
+
title: string;
|
|
5
|
+
/** One quiet line under it: type, licence. */
|
|
6
|
+
sub?: string;
|
|
7
|
+
}
|
|
2
8
|
type __VLS_Props = {
|
|
3
9
|
open: boolean;
|
|
4
10
|
multiple?: boolean;
|
|
5
11
|
/** Restrict the grid to these asset kinds (e.g. ['image']). */
|
|
6
12
|
kinds?: string[];
|
|
13
|
+
/** Records that manage these files, keyed by storage id — see the header. */
|
|
14
|
+
catalogue?: Record<string, PickerCatalogueEntry> | null;
|
|
7
15
|
};
|
|
8
16
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
17
|
"update:open": (value: boolean) => any;
|
|
10
18
|
select: (assets: StorageAsset[]) => any;
|
|
19
|
+
uploaded: (assets: StorageAsset[]) => any;
|
|
11
20
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
21
|
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
13
22
|
onSelect?: ((assets: StorageAsset[]) => any) | undefined;
|
|
23
|
+
onUploaded?: ((assets: StorageAsset[]) => any) | undefined;
|
|
14
24
|
}>, {
|
|
15
25
|
multiple: boolean;
|
|
16
26
|
kinds: string[];
|
|
27
|
+
catalogue: Record<string, PickerCatalogueEntry> | null;
|
|
17
28
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
29
|
declare const _default: typeof __VLS_export;
|
|
19
30
|
export default _default;
|
|
@@ -82,7 +82,7 @@ const folderLabel = computed(() => props.folderName ?? t("shared.media.uploader.
|
|
|
82
82
|
|
|
83
83
|
<template>
|
|
84
84
|
<Dialog :open="open" @update:open="(v) => emit('update:open', v)">
|
|
85
|
-
<DialogContent class="max-w-
|
|
85
|
+
<DialogContent class="sm:max-w-xl">
|
|
86
86
|
<DialogHeader>
|
|
87
87
|
<DialogTitle>{{ t("shared.media.uploader.title") }}</DialogTitle>
|
|
88
88
|
<DialogDescription>
|
|
@@ -13,8 +13,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
13
13
|
size: number;
|
|
14
14
|
icon: string | null;
|
|
15
15
|
fill: boolean;
|
|
16
|
-
navIcon: string | null;
|
|
17
16
|
alt: string;
|
|
17
|
+
navIcon: string | null;
|
|
18
18
|
fallback: Component;
|
|
19
19
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
20
|
declare const _default: typeof __VLS_export;
|
|
@@ -13,8 +13,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
13
13
|
size: number;
|
|
14
14
|
icon: string | null;
|
|
15
15
|
fill: boolean;
|
|
16
|
-
navIcon: string | null;
|
|
17
16
|
alt: string;
|
|
17
|
+
navIcon: string | null;
|
|
18
18
|
fallback: Component;
|
|
19
19
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
20
|
declare const _default: typeof __VLS_export;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CardSize } from '../../lib/cardSize.js';
|
|
2
|
+
type __VLS_ModelProps = {
|
|
3
|
+
modelValue?: CardSize;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"update:modelValue": (value: CardSize) => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
+
"onUpdate:modelValue"?: ((value: CardSize) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { HamburgerMenu, List } from "#solar-icons";
|
|
3
|
+
import { SegmentedToggle, SegmentedToggleItem } from "@revenexx/studio";
|
|
4
|
+
import { useT } from "../../composables/useT";
|
|
5
|
+
const size = defineModel({ type: String, ...{ default: "comfortable" } });
|
|
6
|
+
const t = useT();
|
|
7
|
+
const ITEM = "transition-colors data-[state=on]:text-primary data-[state=off]:hover:text-primary!";
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<SegmentedToggle v-model="size" variant="inset" :aria-label="t('shared.cardSize.label')" data-test="card-size">
|
|
12
|
+
<SegmentedToggleItem value="comfortable" :aria-label="t('shared.cardSize.comfortable')" :class="ITEM">
|
|
13
|
+
<List :size="14" weight="Bold" />
|
|
14
|
+
</SegmentedToggleItem>
|
|
15
|
+
<SegmentedToggleItem value="compact" :aria-label="t('shared.cardSize.compact')" :class="ITEM">
|
|
16
|
+
<HamburgerMenu :size="14" weight="Linear" />
|
|
17
|
+
</SegmentedToggleItem>
|
|
18
|
+
</SegmentedToggle>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CardSize } from '../../lib/cardSize.js';
|
|
2
|
+
type __VLS_ModelProps = {
|
|
3
|
+
modelValue?: CardSize;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"update:modelValue": (value: CardSize) => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
+
"onUpdate:modelValue"?: ((value: CardSize) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -41,9 +41,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
41
41
|
"onUpdate:open"?: ((open: boolean) => any) | undefined;
|
|
42
42
|
onStep?: ((dir: 1 | -1) => any) | undefined;
|
|
43
43
|
}>, {
|
|
44
|
+
busy: boolean;
|
|
44
45
|
width: string;
|
|
45
46
|
top: string;
|
|
46
|
-
busy: boolean;
|
|
47
47
|
returnFocus: () => HTMLElement | null | undefined;
|
|
48
48
|
canStep: {
|
|
49
49
|
prev: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { AltArrowDown, AltArrowLeft, AltArrowUp, CloseCircle } from "#solar-icons";
|
|
3
3
|
import { Sheet, SheetContent, SheetTitle } from "@revenexx/studio";
|
|
4
|
+
import { vSwipeClose } from "../../lib/swipeToClose";
|
|
4
5
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
5
6
|
import { isCloseKey, isRecordStepKey } from "../../lib/detailSheet";
|
|
6
7
|
import { useT } from "../../composables/useT";
|
|
@@ -109,7 +110,7 @@ onBeforeUnmount(() => {
|
|
|
109
110
|
:aria-disabled="canStep.prev ? void 0 : 'true'"
|
|
110
111
|
@click="stepBy(-1)"
|
|
111
112
|
>
|
|
112
|
-
<AltArrowUp :size="18" />
|
|
113
|
+
<AltArrowUp :size="18" weight="Bold" />
|
|
113
114
|
</button>
|
|
114
115
|
<button
|
|
115
116
|
type="button"
|
|
@@ -120,7 +121,7 @@ onBeforeUnmount(() => {
|
|
|
120
121
|
:aria-disabled="canStep.next ? void 0 : 'true'"
|
|
121
122
|
@click="stepBy(1)"
|
|
122
123
|
>
|
|
123
|
-
<AltArrowDown :size="18" />
|
|
124
|
+
<AltArrowDown :size="18" weight="Bold" />
|
|
124
125
|
</button>
|
|
125
126
|
</template>
|
|
126
127
|
<button
|
|
@@ -157,6 +158,9 @@ onBeforeUnmount(() => {
|
|
|
157
158
|
class="w-full gap-0 p-0 sm:max-w-md [&>button.absolute]:hidden motion-reduce:animate-none motion-reduce:transition-none"
|
|
158
159
|
@close-auto-focus="onCloseAutoFocus"
|
|
159
160
|
>
|
|
161
|
+
<div v-swipe-close="close" class="flex shrink-0 justify-center pt-2 md:hidden">
|
|
162
|
+
<span class="h-1.5 w-10 rounded-full bg-black/15" />
|
|
163
|
+
</div>
|
|
160
164
|
<SheetTitle class="sr-only">{{ label }}</SheetTitle>
|
|
161
165
|
<div class="flex shrink-0 items-start gap-2 border-b border-black/[0.06] p-3">
|
|
162
166
|
<button
|
|
@@ -165,7 +169,7 @@ onBeforeUnmount(() => {
|
|
|
165
169
|
:aria-label="t('shared.detailsheet.action.back')"
|
|
166
170
|
@click="close"
|
|
167
171
|
>
|
|
168
|
-
<AltArrowLeft :size="20" />
|
|
172
|
+
<AltArrowLeft :size="20" weight="Bold" />
|
|
169
173
|
</button>
|
|
170
174
|
<div class="min-w-0 flex-1 self-center">
|
|
171
175
|
<slot name="header" />
|
|
@@ -180,7 +184,7 @@ onBeforeUnmount(() => {
|
|
|
180
184
|
:aria-disabled="canStep.prev ? void 0 : 'true'"
|
|
181
185
|
@click="stepBy(-1)"
|
|
182
186
|
>
|
|
183
|
-
<AltArrowUp :size="20" />
|
|
187
|
+
<AltArrowUp :size="20" weight="Bold" />
|
|
184
188
|
</button>
|
|
185
189
|
<button
|
|
186
190
|
type="button"
|
|
@@ -191,7 +195,7 @@ onBeforeUnmount(() => {
|
|
|
191
195
|
:aria-disabled="canStep.next ? void 0 : 'true'"
|
|
192
196
|
@click="stepBy(1)"
|
|
193
197
|
>
|
|
194
|
-
<AltArrowDown :size="20" />
|
|
198
|
+
<AltArrowDown :size="20" weight="Bold" />
|
|
195
199
|
</button>
|
|
196
200
|
</template>
|
|
197
201
|
</div>
|
|
@@ -41,9 +41,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
41
41
|
"onUpdate:open"?: ((open: boolean) => any) | undefined;
|
|
42
42
|
onStep?: ((dir: 1 | -1) => any) | undefined;
|
|
43
43
|
}>, {
|
|
44
|
+
busy: boolean;
|
|
44
45
|
width: string;
|
|
45
46
|
top: string;
|
|
46
|
-
busy: boolean;
|
|
47
47
|
returnFocus: () => HTMLElement | null | undefined;
|
|
48
48
|
canStep: {
|
|
49
49
|
prev: boolean;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
title?: string | null;
|
|
3
|
+
description?: string | null;
|
|
4
|
+
/** One paragraph, split into headline and subtitle at its first sentence. */
|
|
5
|
+
text?: string | null;
|
|
6
|
+
};
|
|
7
|
+
declare var __VLS_1: {};
|
|
8
|
+
type __VLS_Slots = {} & {
|
|
9
|
+
default?: (props: typeof __VLS_1) => any;
|
|
10
|
+
};
|
|
11
|
+
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>;
|
|
12
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|
|
15
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
16
|
+
new (): {
|
|
17
|
+
$slots: S;
|
|
18
|
+
};
|
|
19
|
+
};
|