nuxt-ui-tools 1.6.5 → 1.8.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.json +1 -1
- package/dist/module.mjs +20 -0
- package/dist/runtime/dashboard/components/block/dashboard-skeleton.vue +12 -0
- package/dist/runtime/dashboard/components/dashboard-details.d.vue.ts +38 -0
- package/dist/runtime/dashboard/components/dashboard-details.vue +194 -0
- package/dist/runtime/dashboard/components/dashboard-details.vue.d.ts +38 -0
- package/dist/runtime/dashboard/components/dashboard-page.d.vue.ts +8 -0
- package/dist/runtime/dashboard/components/dashboard-page.vue +20 -3
- package/dist/runtime/dashboard/components/dashboard-page.vue.d.ts +8 -0
- package/dist/runtime/dashboard/components/dashboard-view-tabs.d.vue.ts +2 -5
- package/dist/runtime/dashboard/components/dashboard-view-tabs.vue +5 -1
- package/dist/runtime/dashboard/components/dashboard-view-tabs.vue.d.ts +2 -5
- package/dist/runtime/dashboard/composables/use-dashboard-api.js +4 -1
- package/dist/runtime/dashboard/composables/use-dashboard-views.d.ts +4 -1
- package/dist/runtime/dashboard/composables/use-dashboard-views.js +15 -1
- package/dist/runtime/dashboard/schema/index.d.ts +15 -1
- package/dist/runtime/dashboard/types/blocks.d.ts +27 -1
- package/dist/runtime/dashboard/types/runtime.d.ts +3 -0
- package/dist/runtime/dashboard/types/schema.d.ts +23 -4
- package/dist/runtime/dashboard/types/ui.d.ts +27 -0
- package/dist/runtime/dashboard/utils/schema.js +1 -0
- package/dist/runtime/file-preview/components/provider/file-preview-host.d.vue.ts +7 -0
- package/dist/runtime/file-preview/components/provider/file-preview-host.vue +147 -0
- package/dist/runtime/file-preview/components/provider/file-preview-host.vue.d.ts +7 -0
- package/dist/runtime/file-preview/components/provider/file-preview-provider.d.vue.ts +21 -0
- package/dist/runtime/file-preview/components/provider/file-preview-provider.vue +23 -0
- package/dist/runtime/file-preview/components/provider/file-preview-provider.vue.d.ts +21 -0
- package/dist/runtime/file-preview/components/renderers/audio-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/audio-renderer.vue +83 -0
- package/dist/runtime/file-preview/components/renderers/audio-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/csv-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/csv-renderer.vue +116 -0
- package/dist/runtime/file-preview/components/renderers/csv-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/fallback-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/fallback-renderer.vue +41 -0
- package/dist/runtime/file-preview/components/renderers/fallback-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/file-preview-code.d.vue.ts +9 -0
- package/dist/runtime/file-preview/components/renderers/file-preview-code.vue +83 -0
- package/dist/runtime/file-preview/components/renderers/file-preview-code.vue.d.ts +9 -0
- package/dist/runtime/file-preview/components/renderers/file-preview-text-loading.d.vue.ts +3 -0
- package/dist/runtime/file-preview/components/renderers/file-preview-text-loading.vue +14 -0
- package/dist/runtime/file-preview/components/renderers/file-preview-text-loading.vue.d.ts +3 -0
- package/dist/runtime/file-preview/components/renderers/image-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/image-renderer.vue +182 -0
- package/dist/runtime/file-preview/components/renderers/image-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/markdown-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/markdown-renderer.vue +78 -0
- package/dist/runtime/file-preview/components/renderers/markdown-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/media-controls.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/media-controls.vue +145 -0
- package/dist/runtime/file-preview/components/renderers/media-controls.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/pdf-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/pdf-renderer.vue +58 -0
- package/dist/runtime/file-preview/components/renderers/pdf-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/text-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/text-renderer.vue +41 -0
- package/dist/runtime/file-preview/components/renderers/text-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/video-renderer.d.vue.ts +10 -0
- package/dist/runtime/file-preview/components/renderers/video-renderer.vue +110 -0
- package/dist/runtime/file-preview/components/renderers/video-renderer.vue.d.ts +10 -0
- package/dist/runtime/file-preview/components/shell/file-preview-button.d.vue.ts +16 -0
- package/dist/runtime/file-preview/components/shell/file-preview-button.vue +40 -0
- package/dist/runtime/file-preview/components/shell/file-preview-button.vue.d.ts +16 -0
- package/dist/runtime/{form/components/renderer/form-field-error.d.vue.ts → file-preview/components/shell/file-preview-details.d.vue.ts} +4 -2
- package/dist/runtime/file-preview/components/shell/file-preview-details.vue +25 -0
- package/dist/runtime/{form/components/renderer/form-field-error.vue.d.ts → file-preview/components/shell/file-preview-details.vue.d.ts} +4 -2
- package/dist/runtime/file-preview/components/shell/file-preview-header.d.vue.ts +44 -0
- package/dist/runtime/file-preview/components/shell/file-preview-header.vue +163 -0
- package/dist/runtime/file-preview/components/shell/file-preview-header.vue.d.ts +44 -0
- package/dist/runtime/file-preview/components/shell/file-preview-message.d.vue.ts +21 -0
- package/dist/runtime/file-preview/components/shell/file-preview-message.vue +49 -0
- package/dist/runtime/file-preview/components/shell/file-preview-message.vue.d.ts +21 -0
- package/dist/runtime/file-preview/components/shell/file-preview-shell.d.vue.ts +17 -0
- package/dist/runtime/file-preview/components/shell/file-preview-shell.vue +280 -0
- package/dist/runtime/file-preview/components/shell/file-preview-shell.vue.d.ts +17 -0
- package/dist/runtime/file-preview/components/shell/file-preview-stage.d.vue.ts +37 -0
- package/dist/runtime/file-preview/components/shell/file-preview-stage.vue +173 -0
- package/dist/runtime/file-preview/components/shell/file-preview-stage.vue.d.ts +37 -0
- package/dist/runtime/file-preview/components/shell/file-preview-thumb.d.vue.ts +14 -0
- package/dist/runtime/file-preview/components/shell/file-preview-thumb.vue +69 -0
- package/dist/runtime/file-preview/components/shell/file-preview-thumb.vue.d.ts +14 -0
- package/dist/runtime/file-preview/components/shell/file-preview-tools.d.vue.ts +13 -0
- package/dist/runtime/file-preview/components/shell/file-preview-tools.vue +10 -0
- package/dist/runtime/file-preview/components/shell/file-preview-tools.vue.d.ts +13 -0
- package/dist/runtime/file-preview/composables/use-file-preview-api.d.ts +21 -0
- package/dist/runtime/file-preview/composables/use-file-preview-api.js +83 -0
- package/dist/runtime/file-preview/composables/use-file-preview-shell.d.ts +13 -0
- package/dist/runtime/file-preview/composables/use-file-preview-shell.js +30 -0
- package/dist/runtime/file-preview/composables/use-file-preview-source.d.ts +17 -0
- package/dist/runtime/file-preview/composables/use-file-preview-source.js +51 -0
- package/dist/runtime/file-preview/composables/use-file-preview-text.d.ts +14 -0
- package/dist/runtime/file-preview/composables/use-file-preview-text.js +79 -0
- package/dist/runtime/file-preview/index.d.ts +5 -0
- package/dist/runtime/file-preview/index.js +14 -0
- package/dist/runtime/file-preview/plugins/file-preview-api.d.ts +11 -0
- package/dist/runtime/file-preview/plugins/file-preview-api.js +10 -0
- package/dist/runtime/file-preview/types/api.d.ts +74 -0
- package/dist/runtime/file-preview/types/api.js +0 -0
- package/dist/runtime/file-preview/types/file.d.ts +77 -0
- package/dist/runtime/file-preview/types/file.js +0 -0
- package/dist/runtime/file-preview/types/index.d.ts +4 -0
- package/dist/runtime/file-preview/types/index.js +0 -0
- package/dist/runtime/file-preview/types/renderer.d.ts +49 -0
- package/dist/runtime/file-preview/types/renderer.js +0 -0
- package/dist/runtime/file-preview/types/shell.d.ts +12 -0
- package/dist/runtime/file-preview/types/shell.js +0 -0
- package/dist/runtime/file-preview/utils/container.d.ts +4 -0
- package/dist/runtime/file-preview/utils/container.js +10 -0
- package/dist/runtime/file-preview/utils/csv.d.ts +17 -0
- package/dist/runtime/file-preview/utils/csv.js +53 -0
- package/dist/runtime/file-preview/utils/download.d.ts +8 -0
- package/dist/runtime/file-preview/utils/download.js +40 -0
- package/dist/runtime/file-preview/utils/files.d.ts +7 -0
- package/dist/runtime/file-preview/utils/files.js +53 -0
- package/dist/runtime/file-preview/utils/format.d.ts +13 -0
- package/dist/runtime/file-preview/utils/format.js +40 -0
- package/dist/runtime/file-preview/utils/instance.d.ts +9 -0
- package/dist/runtime/file-preview/utils/instance.js +57 -0
- package/dist/runtime/file-preview/utils/renderers.d.ts +36 -0
- package/dist/runtime/file-preview/utils/renderers.js +247 -0
- package/dist/runtime/form/components/page/form-page-header.d.vue.ts +3 -1
- package/dist/runtime/form/components/page/form-page-header.vue +4 -4
- package/dist/runtime/form/components/page/form-page-header.vue.d.ts +3 -1
- package/dist/runtime/form/components/page/form-page-navigation.vue +2 -1
- package/dist/runtime/form/components/page/form-page-section.vue +15 -7
- package/dist/runtime/form/components/page/form-page.vue +0 -1
- package/dist/runtime/form/components/utils/form-file-preview.vue +5 -38
- package/dist/runtime/form/composables/use-field-control.d.ts +1 -1
- package/dist/runtime/form/composables/use-form-api.d.ts +8 -0
- package/dist/runtime/form/composables/use-form-api.js +4 -4
- package/dist/runtime/form/composables/use-form-page.js +3 -1
- package/dist/runtime/form/composables/use-form-runtime.js +3 -0
- package/dist/runtime/form/composables/use-form-upload-registry.d.ts +2 -0
- package/dist/runtime/form/composables/use-form-upload-registry.js +11 -6
- package/dist/runtime/form/composables/use-form-validation.js +5 -1
- package/dist/runtime/form/fields/array-list/use-array-items.d.ts +1 -1
- package/dist/runtime/form/fields/array-table/array-table-cell.d.vue.ts +15 -0
- package/dist/runtime/form/fields/array-table/array-table-cell.vue +58 -0
- package/dist/runtime/form/fields/array-table/array-table-cell.vue.d.ts +15 -0
- package/dist/runtime/form/fields/array-table/component.vue +42 -26
- package/dist/runtime/form/fields/choice-card/use-choice-card.js +4 -1
- package/dist/runtime/form/fields/date/types.d.ts +6 -1
- package/dist/runtime/form/fields/date-family/component.vue +7 -1
- package/dist/runtime/form/fields/date-family/utils.d.ts +8 -1
- package/dist/runtime/form/fields/date-family/utils.js +10 -2
- package/dist/runtime/form/fields/hidden/types.d.ts +8 -1
- package/dist/runtime/form/fields/upload/component.vue +55 -176
- package/dist/runtime/form/fields/upload/types.d.ts +68 -3
- package/dist/runtime/form/fields/upload/upload-item.d.vue.ts +24 -0
- package/dist/runtime/form/fields/upload/upload-item.vue +158 -0
- package/dist/runtime/form/fields/upload/upload-item.vue.d.ts +24 -0
- package/dist/runtime/form/fields/upload/use-upload-items.d.ts +44 -0
- package/dist/runtime/form/fields/upload/use-upload-items.js +317 -0
- package/dist/runtime/form/plugins/form-api.d.ts +10 -0
- package/dist/runtime/form/plugins/form-api.js +10 -0
- package/dist/runtime/form/types/callbacks.d.ts +8 -2
- package/dist/runtime/form/types/controller.d.ts +6 -3
- package/dist/runtime/form/types/field-base.d.ts +5 -5
- package/dist/runtime/form/types/field-output-utils.d.ts +12 -1
- package/dist/runtime/form/types/field-output.d.ts +1 -1
- package/dist/runtime/form/types/field.d.ts +3 -2
- package/dist/runtime/form/types/form-api.d.ts +4 -2
- package/dist/runtime/form/types/options-runtime.d.ts +8 -4
- package/dist/runtime/form/types/options.d.ts +11 -11
- package/dist/runtime/form/types/output.d.ts +33 -10
- package/dist/runtime/form/types/page.d.ts +7 -3
- package/dist/runtime/form/types/transform.d.ts +5 -2
- package/dist/runtime/form/types/ui.d.ts +7 -3
- package/dist/runtime/form/types/upload-runtime.d.ts +4 -0
- package/dist/runtime/form/utils/page.js +24 -5
- package/dist/runtime/form/utils/state.js +14 -11
- package/dist/runtime/i18n/locales/en.js +108 -1
- package/dist/runtime/i18n/locales/fr.js +108 -1
- package/dist/runtime/i18n/types.d.ts +127 -0
- package/dist/runtime/query-state/composables.d.ts +2 -2
- package/dist/runtime/shared/styles/tokens.css +1 -1
- package/dist/runtime/shared/types/utils.d.ts +12 -4
- package/dist/runtime/shared/utils/file.d.ts +11 -0
- package/dist/runtime/shared/utils/file.js +50 -0
- package/dist/runtime/table/components/table/table-renderer.vue +23 -3
- package/dist/runtime/table/components/utils/search-query-input.d.vue.ts +5 -1
- package/dist/runtime/table/components/utils/search-query-input.vue +17 -3
- package/dist/runtime/table/components/utils/search-query-input.vue.d.ts +5 -1
- package/package.json +56 -29
- package/dist/runtime/form/components/renderer/form-field-error.vue +0 -16
|
@@ -4,6 +4,7 @@ import type { LazyTextValue } from '../../shared/types/utils.js';
|
|
|
4
4
|
import type { DashboardOptionsMenuBindings } from './controls.js';
|
|
5
5
|
import type { DashboardFilterBuilder, DashboardFilterLike, DashboardOption } from './filters.js';
|
|
6
6
|
import type { DashboardCondition, DashboardSourceLike, DashboardStage } from './resource.js';
|
|
7
|
+
import type { DashboardViewBadge } from './schema.js';
|
|
7
8
|
/**
|
|
8
9
|
* Runtime (type-erased) view of the schema. The public schema types carry precise generics; the
|
|
9
10
|
* runtime reads the same objects through these shapes after one normalization step.
|
|
@@ -48,6 +49,8 @@ export interface DashboardRuntimeSchema extends DashboardRuntimeScopeInput {
|
|
|
48
49
|
defaultView?: string;
|
|
49
50
|
/** Views in declaration order. Each input is the object the schema declared. */
|
|
50
51
|
views: [key: string, view: DashboardRuntimeScopeInput][];
|
|
52
|
+
/** Badges of the view tabs, read from the root data. */
|
|
53
|
+
badges?: (context: DashboardRuntimeDeriveContext) => Record<string, DashboardViewBadge>;
|
|
51
54
|
}
|
|
52
55
|
/**
|
|
53
56
|
* Option list behind one filter control, static or remote. Both option composables return this
|
|
@@ -78,6 +78,7 @@ export interface DashboardSchema<TFilters extends DashboardFilterMap = Dashboard
|
|
|
78
78
|
readonly derive?: (context: never) => TDerive;
|
|
79
79
|
readonly views?: TViews;
|
|
80
80
|
readonly defaultView?: keyof TViews & string;
|
|
81
|
+
readonly badges?: (context: never) => DashboardViewBadges<keyof TViews & string>;
|
|
81
82
|
}
|
|
82
83
|
/** Structural constraint every schema returned by `defineDashboardSchema` satisfies. */
|
|
83
84
|
export interface DashboardSchemaLike {
|
|
@@ -89,6 +90,7 @@ export interface DashboardSchemaLike {
|
|
|
89
90
|
readonly derive?: (context: never) => DashboardDeriveMap;
|
|
90
91
|
readonly views?: DashboardViewMap;
|
|
91
92
|
readonly defaultView?: string;
|
|
93
|
+
readonly badges?: (context: never) => DashboardViewBadges<string>;
|
|
92
94
|
}
|
|
93
95
|
/** Structural constraint every view returned by `defineDashboardView` satisfies. */
|
|
94
96
|
export interface DashboardViewLike {
|
|
@@ -152,9 +154,29 @@ export interface DashboardScopeMembers<TFilters> {
|
|
|
152
154
|
/** Refetches every active query of this scope. */
|
|
153
155
|
refresh(): Promise<void>;
|
|
154
156
|
}
|
|
157
|
+
/** What a view's `badge` returns: a count or a short text; empty values show nothing. */
|
|
158
|
+
export type DashboardViewBadge = number | string | null | undefined;
|
|
159
|
+
/** Badges of a dashboard's views, by view key; a view left out shows none. */
|
|
160
|
+
export type DashboardViewBadges<TKey extends string> = {
|
|
161
|
+
readonly [K in TKey]?: DashboardViewBadge;
|
|
162
|
+
};
|
|
163
|
+
/** Context received by a schema's `badges`: the data of its root queries and derived values. */
|
|
164
|
+
export interface DashboardBadgesContext<TFilters, TSources> {
|
|
165
|
+
data: DashboardSourceData<TSources>;
|
|
166
|
+
filters: Readonly<DashboardFilterValues<TFilters>>;
|
|
167
|
+
}
|
|
168
|
+
/** One tab of a dashboard's views. */
|
|
169
|
+
export interface DashboardViewItem<TKey extends string> {
|
|
170
|
+
value: TKey;
|
|
171
|
+
label: string;
|
|
172
|
+
/** The view's badge (see the schema's `badges`), when it shows something. */
|
|
173
|
+
badge?: number | string;
|
|
174
|
+
}
|
|
155
175
|
export interface DashboardViewMeta<TKey extends string> {
|
|
156
176
|
readonly key: TKey;
|
|
157
177
|
readonly label: string;
|
|
178
|
+
/** The view's badge (see the schema's `badges`), when it shows something. */
|
|
179
|
+
readonly badge: number | string | undefined;
|
|
158
180
|
/** The view is the current one. */
|
|
159
181
|
readonly active: boolean;
|
|
160
182
|
/** The view's `enabled` condition holds. A disabled view has no tab and cannot be current. */
|
|
@@ -170,10 +192,7 @@ export interface DashboardViewController<TKey extends string> {
|
|
|
170
192
|
*/
|
|
171
193
|
current: TKey;
|
|
172
194
|
/** Enabled views in declaration order, ready for `UTabs` items. */
|
|
173
|
-
readonly items: readonly
|
|
174
|
-
value: TKey;
|
|
175
|
-
label: string;
|
|
176
|
-
}[];
|
|
195
|
+
readonly items: readonly DashboardViewItem<TKey>[];
|
|
177
196
|
}
|
|
178
197
|
/** Handle of one view: its queries, derived values and filters (`consumption.filters.year`). */
|
|
179
198
|
export type DashboardViewHandle<TView, TKey extends string> = Prettify<InferQueries<TView> & DashboardDerivedResources<InferDerive<TView>> & DashboardScopeMembers<InferFilters<TView>> & {
|
|
@@ -46,6 +46,21 @@ export interface DashboardStatUi {
|
|
|
46
46
|
/** Line under the progress bar: goal and completion. */
|
|
47
47
|
goal?: string;
|
|
48
48
|
}
|
|
49
|
+
export interface DashboardDetailsUi {
|
|
50
|
+
/** The description list: a grid of fields. */
|
|
51
|
+
grid?: string;
|
|
52
|
+
/** One field; carries `data-empty` while its value is empty. */
|
|
53
|
+
item?: string;
|
|
54
|
+
label?: string;
|
|
55
|
+
value?: string;
|
|
56
|
+
/** Dash or `placeholder` of an empty value. */
|
|
57
|
+
placeholder?: string;
|
|
58
|
+
hint?: string;
|
|
59
|
+
/** Link of an item with `to`. */
|
|
60
|
+
link?: string;
|
|
61
|
+
/** Copy button of an item with `copy`. */
|
|
62
|
+
copy?: string;
|
|
63
|
+
}
|
|
49
64
|
export interface DashboardStatsUi {
|
|
50
65
|
/** Grid of the figures. */
|
|
51
66
|
grid?: string;
|
|
@@ -219,12 +234,21 @@ export interface DashboardChipsUi {
|
|
|
219
234
|
export interface DashboardPageUi {
|
|
220
235
|
/** The page, and its scroll container: the tabs and filters stick to its top. */
|
|
221
236
|
root?: string;
|
|
237
|
+
/** Carries `data-leading` while the `#leading` slot is filled. */
|
|
222
238
|
header?: string;
|
|
239
|
+
/** Around the `#eyebrow` slot, above the title. */
|
|
240
|
+
eyebrow?: string;
|
|
241
|
+
/** Around the `#leading` slot (an avatar or a logo), beside the title and its line. */
|
|
242
|
+
leading?: string;
|
|
223
243
|
title?: string;
|
|
224
244
|
/** Today's date and when the data was fetched, under the title. */
|
|
225
245
|
description?: string;
|
|
226
246
|
/** Page actions and the refresh control. */
|
|
227
247
|
actions?: string;
|
|
248
|
+
/** Around the `#banner` slot, between the header and the pinned band. */
|
|
249
|
+
banner?: string;
|
|
250
|
+
/** Around the `#details` slot: a full-width row closing the header (key facts of an entity). */
|
|
251
|
+
details?: string;
|
|
228
252
|
/** Pinned band of the tabs and the filter bar. Carries `data-stuck` once content scrolls under it. */
|
|
229
253
|
toolbar?: string;
|
|
230
254
|
tabs?: string;
|
|
@@ -237,6 +261,8 @@ export interface DashboardViewTabsUi {
|
|
|
237
261
|
/** The strip: it scrolls sideways when the tabs overflow. */
|
|
238
262
|
root?: string;
|
|
239
263
|
tab?: string;
|
|
264
|
+
/** Count or text of a view's `badge`, after the tab label. */
|
|
265
|
+
badge?: string;
|
|
240
266
|
}
|
|
241
267
|
/**
|
|
242
268
|
* App-wide dashboard theming, read from `appConfig.nuxtUiTools.dashboard`.
|
|
@@ -258,6 +284,7 @@ export interface DashboardUiConfig {
|
|
|
258
284
|
grid?: DashboardGridUi;
|
|
259
285
|
stat?: DashboardStatUi;
|
|
260
286
|
stats?: DashboardStatsUi;
|
|
287
|
+
details?: DashboardDetailsUi;
|
|
261
288
|
gauge?: DashboardGaugeUi;
|
|
262
289
|
legend?: DashboardLegendUi;
|
|
263
290
|
total?: DashboardTotalUi;
|
|
@@ -16,6 +16,7 @@ export function resolveDashboardRuntimeSchema(schema) {
|
|
|
16
16
|
const views = Object.entries(input.views ?? {});
|
|
17
17
|
return {
|
|
18
18
|
autoRefresh: input.autoRefresh,
|
|
19
|
+
badges: input.badges,
|
|
19
20
|
defaultView: input.defaultView ?? views[0]?.[0],
|
|
20
21
|
derive: input.derive,
|
|
21
22
|
filters: input.filters,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FilePreviewInstance } from '../../types/index.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
instance: FilePreviewInstance;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: 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>;
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import UDrawer from "@nuxt/ui/components/Drawer.vue";
|
|
3
|
+
import UModal from "@nuxt/ui/components/Modal.vue";
|
|
4
|
+
import { useLocalStorage } from "@vueuse/core";
|
|
5
|
+
import { computed, ref } from "vue";
|
|
6
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
7
|
+
import {
|
|
8
|
+
getResponsiveValue,
|
|
9
|
+
useResponsiveValue
|
|
10
|
+
} from "../../../shared/composables/use-responsive-value";
|
|
11
|
+
import { useFilePreview } from "../../composables/use-file-preview-api";
|
|
12
|
+
import { largestFilePreviewContainer, normalizeFilePreviewContainer } from "../../utils/container";
|
|
13
|
+
import { findFilePreviewRenderer } from "../../utils/renderers";
|
|
14
|
+
import FilePreviewShell from "../shell/file-preview-shell.vue";
|
|
15
|
+
const DRAWER_MIN_WIDTH = 420;
|
|
16
|
+
const DRAWER_GUTTER = 56;
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
instance: { type: Object, required: true }
|
|
19
|
+
});
|
|
20
|
+
const { t } = useUiToolsLocale();
|
|
21
|
+
const api = useFilePreview();
|
|
22
|
+
const expanded = ref(false);
|
|
23
|
+
const drawerWidth = useLocalStorage("nut-file-preview-drawer-width", 940);
|
|
24
|
+
const width = useResponsiveValue("narrow md:wide");
|
|
25
|
+
const narrow = computed(() => width.value === "narrow");
|
|
26
|
+
const renderers = computed(
|
|
27
|
+
() => props.instance.files.value.map(
|
|
28
|
+
(item) => findFilePreviewRenderer((item.rendition ?? item).kind, api.renderers.value)
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
const base = computed(() => {
|
|
32
|
+
const explicit = props.instance.options.mode;
|
|
33
|
+
const modes = explicit ? [explicit] : renderers.value.map((renderer) => renderer.mode ?? "modal");
|
|
34
|
+
return largestFilePreviewContainer(
|
|
35
|
+
modes.map((mode) => normalizeFilePreviewContainer(getResponsiveValue(mode, "string")))
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
const container = computed(() => expanded.value ? "fullscreen" : base.value);
|
|
39
|
+
const compact = computed(
|
|
40
|
+
() => base.value === "modal" && renderers.value.every((renderer) => renderer.compact === true)
|
|
41
|
+
);
|
|
42
|
+
const canExpand = computed(() => !narrow.value && (base.value !== "fullscreen" || expanded.value));
|
|
43
|
+
const title = computed(() => {
|
|
44
|
+
const item = props.instance.files.value[props.instance.index.value];
|
|
45
|
+
return item?.name || t("filePreview.untitled");
|
|
46
|
+
});
|
|
47
|
+
const drawerContent = computed(() => ({
|
|
48
|
+
disableOutsidePointerEvents: void 0,
|
|
49
|
+
style: {
|
|
50
|
+
width: expanded.value ? "100vw" : `min(${Math.max(DRAWER_MIN_WIDTH, drawerWidth.value)}px, calc(100vw - ${DRAWER_GUTTER}px))`
|
|
51
|
+
}
|
|
52
|
+
}));
|
|
53
|
+
function close() {
|
|
54
|
+
props.instance.handle.close();
|
|
55
|
+
}
|
|
56
|
+
function handleOpen(open) {
|
|
57
|
+
if (!open) close();
|
|
58
|
+
}
|
|
59
|
+
function handleDrawerAnimation(open) {
|
|
60
|
+
if (!open) props.instance.dispose();
|
|
61
|
+
}
|
|
62
|
+
function resize(event) {
|
|
63
|
+
if (expanded.value || !(event.currentTarget instanceof HTMLElement)) return;
|
|
64
|
+
const handle = event.currentTarget;
|
|
65
|
+
handle.setPointerCapture(event.pointerId);
|
|
66
|
+
const move = (moved) => {
|
|
67
|
+
drawerWidth.value = Math.round(
|
|
68
|
+
Math.min(
|
|
69
|
+
window.innerWidth - DRAWER_GUTTER,
|
|
70
|
+
Math.max(DRAWER_MIN_WIDTH, window.innerWidth - moved.clientX)
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
const stop = () => {
|
|
75
|
+
handle.removeEventListener("pointermove", move);
|
|
76
|
+
handle.removeEventListener("pointerup", stop);
|
|
77
|
+
handle.removeEventListener("pointercancel", stop);
|
|
78
|
+
};
|
|
79
|
+
handle.addEventListener("pointermove", move);
|
|
80
|
+
handle.addEventListener("pointerup", stop);
|
|
81
|
+
handle.addEventListener("pointercancel", stop);
|
|
82
|
+
}
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<template>
|
|
86
|
+
<UDrawer
|
|
87
|
+
v-if="base === 'drawer'"
|
|
88
|
+
:open="instance.open.value"
|
|
89
|
+
:title="title"
|
|
90
|
+
:description="title"
|
|
91
|
+
direction="right"
|
|
92
|
+
:handle="false"
|
|
93
|
+
:content="drawerContent"
|
|
94
|
+
:ui="{
|
|
95
|
+
overlay: 'bg-(--nut-fp-veil)',
|
|
96
|
+
content: 'h-dvh max-w-none overflow-hidden rounded-none border-s border-default p-0',
|
|
97
|
+
container: 'size-full p-0'
|
|
98
|
+
}"
|
|
99
|
+
@update:open="handleOpen"
|
|
100
|
+
@animation-end="handleDrawerAnimation"
|
|
101
|
+
>
|
|
102
|
+
<template #content>
|
|
103
|
+
<div
|
|
104
|
+
v-if="!expanded"
|
|
105
|
+
class="absolute inset-y-0 start-0 z-30 w-1.5 cursor-col-resize touch-none transition-colors hover:bg-primary/40"
|
|
106
|
+
aria-hidden="true"
|
|
107
|
+
data-file-preview-resize=""
|
|
108
|
+
@pointerdown="resize"
|
|
109
|
+
/>
|
|
110
|
+
<FilePreviewShell
|
|
111
|
+
:instance="instance"
|
|
112
|
+
:container="container"
|
|
113
|
+
:narrow="narrow"
|
|
114
|
+
:can-expand="canExpand"
|
|
115
|
+
:expanded="expanded"
|
|
116
|
+
@close="close"
|
|
117
|
+
@expand="expanded = !expanded"
|
|
118
|
+
/>
|
|
119
|
+
</template>
|
|
120
|
+
</UDrawer>
|
|
121
|
+
|
|
122
|
+
<UModal
|
|
123
|
+
v-else
|
|
124
|
+
:open="instance.open.value"
|
|
125
|
+
:title="title"
|
|
126
|
+
:description="title"
|
|
127
|
+
:fullscreen="container === 'fullscreen'"
|
|
128
|
+
:ui="{
|
|
129
|
+
overlay: 'bg-(--nut-fp-veil)',
|
|
130
|
+
content: container === 'fullscreen' ? 'h-dvh max-w-none overflow-hidden rounded-none p-0' : compact ? 'h-auto max-h-[calc(100dvh-32px)] w-[min(468px,calc(100%-32px))] max-w-none overflow-hidden rounded-xl p-0' : 'h-[min(780px,calc(100dvh-48px))] w-[min(1080px,calc(100%-48px))] max-w-none overflow-hidden rounded-xl p-0'
|
|
131
|
+
}"
|
|
132
|
+
@update:open="handleOpen"
|
|
133
|
+
@after:leave="instance.dispose()"
|
|
134
|
+
>
|
|
135
|
+
<template #content>
|
|
136
|
+
<FilePreviewShell
|
|
137
|
+
:instance="instance"
|
|
138
|
+
:container="container"
|
|
139
|
+
:narrow="narrow"
|
|
140
|
+
:can-expand="canExpand"
|
|
141
|
+
:expanded="expanded"
|
|
142
|
+
@close="close"
|
|
143
|
+
@expand="expanded = !expanded"
|
|
144
|
+
/>
|
|
145
|
+
</template>
|
|
146
|
+
</UModal>
|
|
147
|
+
</template>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FilePreviewInstance } from '../../types/index.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
instance: FilePreviewInstance;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: 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>;
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FilePreviewMarkdownRenderer } from '../../types/index.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
/**
|
|
4
|
+
* Renders markdown files as HTML in the markdown preview. It must return sanitized HTML. Without
|
|
5
|
+
* it, markdown files show their source.
|
|
6
|
+
*/
|
|
7
|
+
markdown?: FilePreviewMarkdownRenderer | null;
|
|
8
|
+
};
|
|
9
|
+
declare var __VLS_1: {};
|
|
10
|
+
type __VLS_Slots = {} & {
|
|
11
|
+
default?: (props: typeof __VLS_1) => any;
|
|
12
|
+
};
|
|
13
|
+
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>;
|
|
14
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
17
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
18
|
+
new (): {
|
|
19
|
+
$slots: S;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { onBeforeUnmount, onMounted, provide } from "vue";
|
|
3
|
+
import { provideFilePreview } from "../../composables/use-file-preview-api";
|
|
4
|
+
import { filePreviewMarkdownKey } from "../../composables/use-file-preview-shell";
|
|
5
|
+
import FilePreviewHost from "./file-preview-host.vue";
|
|
6
|
+
const { markdown = null } = defineProps({
|
|
7
|
+
markdown: { type: [Function, null], required: false }
|
|
8
|
+
});
|
|
9
|
+
const filePreview = provideFilePreview();
|
|
10
|
+
const { instances } = filePreview;
|
|
11
|
+
let detach = null;
|
|
12
|
+
provide(filePreviewMarkdownKey, markdown);
|
|
13
|
+
onMounted(() => {
|
|
14
|
+
detach = filePreview.attach();
|
|
15
|
+
});
|
|
16
|
+
onBeforeUnmount(() => detach?.());
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<slot />
|
|
21
|
+
|
|
22
|
+
<FilePreviewHost v-for="instance in instances" :key="instance.id" :instance="instance" />
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FilePreviewMarkdownRenderer } from '../../types/index.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
/**
|
|
4
|
+
* Renders markdown files as HTML in the markdown preview. It must return sanitized HTML. Without
|
|
5
|
+
* it, markdown files show their source.
|
|
6
|
+
*/
|
|
7
|
+
markdown?: FilePreviewMarkdownRenderer | null;
|
|
8
|
+
};
|
|
9
|
+
declare var __VLS_1: {};
|
|
10
|
+
type __VLS_Slots = {} & {
|
|
11
|
+
default?: (props: typeof __VLS_1) => any;
|
|
12
|
+
};
|
|
13
|
+
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>;
|
|
14
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
17
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
18
|
+
new (): {
|
|
19
|
+
$slots: S;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FilePreviewRendererProps } from '../../types/index.js';
|
|
2
|
+
declare const __VLS_export: import("vue").DefineComponent<FilePreviewRendererProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
ready: (details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any;
|
|
4
|
+
error: (error: import("../../types/index.js").FilePreviewRendererError) => any;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<FilePreviewRendererProps> & Readonly<{
|
|
6
|
+
onReady?: ((details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any) | undefined;
|
|
7
|
+
onError?: ((error: import("../../types/index.js").FilePreviewRendererError) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import UIcon from "@nuxt/ui/components/Icon.vue";
|
|
3
|
+
import { useMediaControls } from "@vueuse/core";
|
|
4
|
+
import { computed, useTemplateRef } from "vue";
|
|
5
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
6
|
+
import { onFilePreviewKey } from "../../composables/use-file-preview-shell";
|
|
7
|
+
import { formatFilePreviewDuration } from "../../utils/format";
|
|
8
|
+
import MediaControls from "./media-controls.vue";
|
|
9
|
+
const BARS = Array.from(
|
|
10
|
+
{ length: 28 },
|
|
11
|
+
(_, index) => 18 + Math.abs(Math.sin(index * 1.3) * Math.cos(index * 0.4)) * 62
|
|
12
|
+
);
|
|
13
|
+
defineProps({
|
|
14
|
+
file: { type: Object, required: true },
|
|
15
|
+
url: { type: String, required: true },
|
|
16
|
+
blob: { type: null, required: true },
|
|
17
|
+
container: { type: String, required: true }
|
|
18
|
+
});
|
|
19
|
+
const emit = defineEmits(["ready", "error"]);
|
|
20
|
+
const { t } = useUiToolsLocale();
|
|
21
|
+
const audio = useTemplateRef("audio");
|
|
22
|
+
const controls = useMediaControls(audio);
|
|
23
|
+
const duration = computed(
|
|
24
|
+
() => controls.duration.value > 0 ? formatFilePreviewDuration(controls.duration.value) : null
|
|
25
|
+
);
|
|
26
|
+
function handleMetadata() {
|
|
27
|
+
const element = audio.value;
|
|
28
|
+
if (!element) return;
|
|
29
|
+
emit("ready", [
|
|
30
|
+
{ label: t("filePreview.fields.duration"), value: formatFilePreviewDuration(element.duration) }
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
onFilePreviewKey([" ", "k", "m"], (event) => {
|
|
34
|
+
if (event.key === "m") controls.muted.value = !controls.muted.value;
|
|
35
|
+
else controls.playing.value = !controls.playing.value;
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div class="flex size-full items-center justify-center p-5" data-file-preview-audio="">
|
|
41
|
+
<div class="flex w-full max-w-md flex-col gap-4">
|
|
42
|
+
<div
|
|
43
|
+
class="relative flex h-36 items-center justify-center gap-[3px] overflow-hidden rounded-xl bg-linear-135 from-[#3b2f4a] via-[#b8466e] to-primary px-6"
|
|
44
|
+
aria-hidden="true"
|
|
45
|
+
>
|
|
46
|
+
<img
|
|
47
|
+
v-if="file.file.poster"
|
|
48
|
+
:src="file.file.poster"
|
|
49
|
+
alt=""
|
|
50
|
+
class="absolute inset-0 size-full object-cover"
|
|
51
|
+
/>
|
|
52
|
+
<template v-else>
|
|
53
|
+
<i
|
|
54
|
+
v-for="(height, position) in BARS"
|
|
55
|
+
:key="position"
|
|
56
|
+
:class="[
|
|
57
|
+
'block w-1 rounded-full bg-white/80',
|
|
58
|
+
controls.playing.value ? 'nut-fp-equalizer' : ''
|
|
59
|
+
]"
|
|
60
|
+
:style="{ height: `${height}px`, animationDelay: `${position % 7 * -0.13}s` }"
|
|
61
|
+
/>
|
|
62
|
+
<UIcon
|
|
63
|
+
name="i-lucide-audio-lines"
|
|
64
|
+
class="absolute right-3 bottom-3 size-4 text-white/70"
|
|
65
|
+
/>
|
|
66
|
+
</template>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="min-w-0">
|
|
69
|
+
<p class="m-0 truncate text-sm font-semibold text-highlighted">{{ file.name }}</p>
|
|
70
|
+
<p v-if="duration" class="m-0 text-xs text-muted tabular-nums">{{ duration }}</p>
|
|
71
|
+
</div>
|
|
72
|
+
<audio
|
|
73
|
+
ref="audio"
|
|
74
|
+
:src="url"
|
|
75
|
+
preload="metadata"
|
|
76
|
+
class="hidden"
|
|
77
|
+
@loadedmetadata="handleMetadata"
|
|
78
|
+
@error="emit('error', { reason: 'decode' })"
|
|
79
|
+
/>
|
|
80
|
+
<MediaControls :controls="controls" variant="audio" compact />
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FilePreviewRendererProps } from '../../types/index.js';
|
|
2
|
+
declare const __VLS_export: import("vue").DefineComponent<FilePreviewRendererProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
ready: (details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any;
|
|
4
|
+
error: (error: import("../../types/index.js").FilePreviewRendererError) => any;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<FilePreviewRendererProps> & Readonly<{
|
|
6
|
+
onReady?: ((details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any) | undefined;
|
|
7
|
+
onError?: ((error: import("../../types/index.js").FilePreviewRendererError) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FilePreviewRendererProps } from '../../types/index.js';
|
|
2
|
+
declare const __VLS_export: import("vue").DefineComponent<FilePreviewRendererProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
ready: (details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any;
|
|
4
|
+
error: (error: import("../../types/index.js").FilePreviewRendererError) => any;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<FilePreviewRendererProps> & Readonly<{
|
|
6
|
+
onReady?: ((details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any) | undefined;
|
|
7
|
+
onError?: ((error: import("../../types/index.js").FilePreviewRendererError) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, watch } from "vue";
|
|
3
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
4
|
+
import { useFilePreviewText } from "../../composables/use-file-preview-text";
|
|
5
|
+
import { parseCsv } from "../../utils/csv";
|
|
6
|
+
import FilePreviewTextLoading from "./file-preview-text-loading.vue";
|
|
7
|
+
const MAX_ROWS = 1e3;
|
|
8
|
+
const NUMBER = /^-?[\d\s .,]+%?$/u;
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
file: { type: Object, required: true },
|
|
11
|
+
url: { type: String, required: true },
|
|
12
|
+
blob: { type: null, required: true },
|
|
13
|
+
container: { type: String, required: true }
|
|
14
|
+
});
|
|
15
|
+
const emit = defineEmits(["ready", "error"]);
|
|
16
|
+
const { t } = useUiToolsLocale();
|
|
17
|
+
const content = useFilePreviewText(props);
|
|
18
|
+
const table = computed(() => {
|
|
19
|
+
const parsed = parseCsv(content.text.value, {
|
|
20
|
+
delimiter: props.file.extension === "tsv" ? " " : void 0,
|
|
21
|
+
maxRows: MAX_ROWS + 1
|
|
22
|
+
});
|
|
23
|
+
const [head = [], ...rows] = parsed.rows;
|
|
24
|
+
const width = Math.max(head.length, ...rows.map((row) => row.length));
|
|
25
|
+
const columns = Array.from({ length: width }, (_, index) => head[index] ?? "");
|
|
26
|
+
const numeric = columns.map((_, index) => {
|
|
27
|
+
const values = rows.map((row) => (row[index] ?? "").trim()).filter(Boolean);
|
|
28
|
+
return values.length > 0 && values.every((value) => NUMBER.test(value));
|
|
29
|
+
});
|
|
30
|
+
return { columns, complete: parsed.complete, delimiter: parsed.delimiter, numeric, rows };
|
|
31
|
+
});
|
|
32
|
+
const facts = computed(
|
|
33
|
+
() => [
|
|
34
|
+
t("filePreview.csv.rows", { count: table.value.rows.length.toLocaleString() }),
|
|
35
|
+
t("filePreview.csv.columns", { count: table.value.columns.length }),
|
|
36
|
+
t("filePreview.csv.delimiter", {
|
|
37
|
+
value: table.value.delimiter === " " ? t("filePreview.csv.tab") : table.value.delimiter
|
|
38
|
+
}),
|
|
39
|
+
content.notice.value
|
|
40
|
+
].filter((fact) => fact !== null)
|
|
41
|
+
);
|
|
42
|
+
watch(
|
|
43
|
+
content.status,
|
|
44
|
+
(status) => {
|
|
45
|
+
if (status === "error")
|
|
46
|
+
emit("error", { message: content.error.value?.message, reason: "source" });
|
|
47
|
+
if (status !== "ready") return;
|
|
48
|
+
emit("ready", [
|
|
49
|
+
{ label: t("filePreview.fields.rows"), value: table.value.rows.length.toLocaleString() },
|
|
50
|
+
{ label: t("filePreview.fields.columns"), value: String(table.value.columns.length) }
|
|
51
|
+
]);
|
|
52
|
+
},
|
|
53
|
+
{ immediate: true }
|
|
54
|
+
);
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<template>
|
|
58
|
+
<div
|
|
59
|
+
v-if="content.status.value === 'ready'"
|
|
60
|
+
class="absolute inset-0 flex flex-col bg-default"
|
|
61
|
+
data-file-preview-csv=""
|
|
62
|
+
>
|
|
63
|
+
<div class="min-h-0 flex-1 overflow-auto">
|
|
64
|
+
<table class="min-w-full border-separate border-spacing-0 text-[12.5px] tabular-nums">
|
|
65
|
+
<thead>
|
|
66
|
+
<tr>
|
|
67
|
+
<th
|
|
68
|
+
class="sticky top-0 left-0 z-20 min-w-10 border-e border-b border-default bg-elevated px-3 py-1.5 text-end font-normal text-dimmed"
|
|
69
|
+
scope="col"
|
|
70
|
+
>
|
|
71
|
+
#
|
|
72
|
+
</th>
|
|
73
|
+
<th
|
|
74
|
+
v-for="(column, index) in table.columns"
|
|
75
|
+
:key="index"
|
|
76
|
+
scope="col"
|
|
77
|
+
:class="[
|
|
78
|
+
'sticky top-0 z-10 max-w-72 truncate border-e border-b border-default bg-elevated px-3 py-1.5 font-semibold whitespace-nowrap text-toned',
|
|
79
|
+
table.numeric[index] ? 'text-end' : 'text-start'
|
|
80
|
+
]"
|
|
81
|
+
>
|
|
82
|
+
{{ column }}
|
|
83
|
+
</th>
|
|
84
|
+
</tr>
|
|
85
|
+
</thead>
|
|
86
|
+
<tbody>
|
|
87
|
+
<tr v-for="(row, rowIndex) in table.rows" :key="rowIndex" class="hover:bg-elevated/60">
|
|
88
|
+
<td
|
|
89
|
+
class="sticky left-0 z-10 border-e border-b border-(--ui-border-muted) bg-elevated px-3 py-1.5 text-end text-dimmed"
|
|
90
|
+
>
|
|
91
|
+
{{ rowIndex + 1 }}
|
|
92
|
+
</td>
|
|
93
|
+
<td
|
|
94
|
+
v-for="(_, index) in table.columns"
|
|
95
|
+
:key="index"
|
|
96
|
+
:title="row[index]"
|
|
97
|
+
:class="[
|
|
98
|
+
'max-w-72 truncate border-e border-b border-(--ui-border-muted) px-3 py-1.5 whitespace-nowrap text-default',
|
|
99
|
+
table.numeric[index] ? 'text-end' : 'text-start'
|
|
100
|
+
]"
|
|
101
|
+
>
|
|
102
|
+
{{ row[index] ?? "" }}
|
|
103
|
+
</td>
|
|
104
|
+
</tr>
|
|
105
|
+
</tbody>
|
|
106
|
+
</table>
|
|
107
|
+
</div>
|
|
108
|
+
<div
|
|
109
|
+
class="flex shrink-0 flex-wrap gap-x-3.5 gap-y-1 border-t border-default bg-elevated px-3.5 py-1.5 text-[11.5px] text-muted tabular-nums"
|
|
110
|
+
data-file-preview-facts=""
|
|
111
|
+
>
|
|
112
|
+
<span v-for="fact in facts" :key="fact">{{ fact }}</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
<FilePreviewTextLoading v-else />
|
|
116
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FilePreviewRendererProps } from '../../types/index.js';
|
|
2
|
+
declare const __VLS_export: import("vue").DefineComponent<FilePreviewRendererProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
ready: (details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any;
|
|
4
|
+
error: (error: import("../../types/index.js").FilePreviewRendererError) => any;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<FilePreviewRendererProps> & Readonly<{
|
|
6
|
+
onReady?: ((details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any) | undefined;
|
|
7
|
+
onError?: ((error: import("../../types/index.js").FilePreviewRendererError) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FilePreviewRendererProps } from '../../types/index.js';
|
|
2
|
+
declare const __VLS_export: import("vue").DefineComponent<FilePreviewRendererProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
3
|
+
ready: (details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any;
|
|
4
|
+
error: (error: import("../../types/index.js").FilePreviewRendererError) => any;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<FilePreviewRendererProps> & Readonly<{
|
|
6
|
+
onReady?: ((details?: readonly import("../../types/index.js").FilePreviewDetail[] | undefined) => any) | undefined;
|
|
7
|
+
onError?: ((error: import("../../types/index.js").FilePreviewRendererError) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|