nuxt-ui-tools 1.7.0 → 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 +18 -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-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/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/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 +104 -1
- package/dist/runtime/i18n/locales/fr.js +104 -1
- package/dist/runtime/i18n/types.d.ts +121 -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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useClipboard } from "@vueuse/core";
|
|
3
|
+
import { computed, ref } from "vue";
|
|
4
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
5
|
+
import { tintFilePreviewJsonLine } from "../../utils/format";
|
|
6
|
+
import FilePreviewButton from "../shell/file-preview-button.vue";
|
|
7
|
+
import FilePreviewTools from "../shell/file-preview-tools.vue";
|
|
8
|
+
const {
|
|
9
|
+
json,
|
|
10
|
+
text,
|
|
11
|
+
tools = true
|
|
12
|
+
} = defineProps({
|
|
13
|
+
text: { type: String, required: true },
|
|
14
|
+
json: { type: Boolean, required: true },
|
|
15
|
+
facts: { type: Array, required: true },
|
|
16
|
+
tools: { type: Boolean, required: false }
|
|
17
|
+
});
|
|
18
|
+
const { t } = useUiToolsLocale();
|
|
19
|
+
const wrap = ref(false);
|
|
20
|
+
const clipboard = useClipboard({ copiedDuring: 1500, legacy: true });
|
|
21
|
+
const source = computed(() => {
|
|
22
|
+
if (!json) return { formatted: false, text };
|
|
23
|
+
try {
|
|
24
|
+
return { formatted: true, text: JSON.stringify(JSON.parse(text), null, 2) };
|
|
25
|
+
} catch {
|
|
26
|
+
return { formatted: false, text };
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
const lines = computed(() => source.value.text.split(/\r?\n/u));
|
|
30
|
+
const tinted = computed(
|
|
31
|
+
() => source.value.formatted ? lines.value.map(tintFilePreviewJsonLine) : null
|
|
32
|
+
);
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<div class="absolute inset-0 flex flex-col bg-default" data-file-preview-code="">
|
|
37
|
+
<div
|
|
38
|
+
class="nut-fp-code min-h-0 flex-1 overflow-auto font-mono text-[12.5px] leading-[1.65] text-default [tab-size:2]"
|
|
39
|
+
>
|
|
40
|
+
<div :class="['py-2.5', wrap ? '' : 'min-w-max']">
|
|
41
|
+
<div v-for="(line, position) in lines" :key="position" class="flex">
|
|
42
|
+
<span
|
|
43
|
+
class="sticky left-0 w-13 shrink-0 bg-default pe-3.5 text-end text-dimmed tabular-nums select-none"
|
|
44
|
+
aria-hidden="true"
|
|
45
|
+
>
|
|
46
|
+
{{ position + 1 }}
|
|
47
|
+
</span>
|
|
48
|
+
<!-- eslint-disable-next-line vue/no-v-html -- each line is escaped before tinting -->
|
|
49
|
+
<span
|
|
50
|
+
v-if="tinted"
|
|
51
|
+
:class="['pe-6', wrap ? 'break-all whitespace-pre-wrap' : 'whitespace-pre']"
|
|
52
|
+
v-html="tinted[position] || ' '"
|
|
53
|
+
/>
|
|
54
|
+
<span v-else :class="['pe-6', wrap ? 'break-all whitespace-pre-wrap' : 'whitespace-pre']">
|
|
55
|
+
{{ line || " " }}
|
|
56
|
+
</span>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div
|
|
61
|
+
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"
|
|
62
|
+
data-file-preview-facts=""
|
|
63
|
+
>
|
|
64
|
+
<span>{{ t("filePreview.text.lines", { count: lines.length.toLocaleString() }) }}</span>
|
|
65
|
+
<span v-if="source.formatted">{{ t("filePreview.text.formatted") }}</span>
|
|
66
|
+
<span v-for="fact in facts" :key="fact">{{ fact }}</span>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<FilePreviewTools v-if="tools">
|
|
70
|
+
<FilePreviewButton
|
|
71
|
+
icon="i-lucide-wrap-text"
|
|
72
|
+
:label="t('filePreview.text.wrap')"
|
|
73
|
+
:pressed="wrap"
|
|
74
|
+
@click="wrap = !wrap"
|
|
75
|
+
/>
|
|
76
|
+
<FilePreviewButton
|
|
77
|
+
:icon="clipboard.copied.value ? 'i-lucide-check' : 'i-lucide-copy'"
|
|
78
|
+
:label="clipboard.copied.value ? t('filePreview.text.copied') : t('filePreview.text.copy')"
|
|
79
|
+
@click="clipboard.copy(source.text)"
|
|
80
|
+
/>
|
|
81
|
+
</FilePreviewTools>
|
|
82
|
+
</div>
|
|
83
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
text: string;
|
|
3
|
+
json: boolean;
|
|
4
|
+
facts: readonly string[];
|
|
5
|
+
tools?: boolean;
|
|
6
|
+
};
|
|
7
|
+
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>;
|
|
8
|
+
declare const _default: typeof __VLS_export;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const WIDTHS = [62, 84, 45, 91, 70, 38, 77, 58, 88, 49, 66, 80];
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<div class="absolute inset-0 flex flex-col gap-2.5 bg-default px-6 py-5" aria-hidden="true">
|
|
7
|
+
<span
|
|
8
|
+
v-for="(width, position) in WIDTHS"
|
|
9
|
+
:key="position"
|
|
10
|
+
class="block h-2.5 animate-pulse rounded bg-accented"
|
|
11
|
+
:style="{ width: `${width}%` }"
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
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,182 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useElementSize, useEventListener } from "@vueuse/core";
|
|
3
|
+
import { computed, ref, shallowRef, useTemplateRef } from "vue";
|
|
4
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
5
|
+
import { onFilePreviewKey } from "../../composables/use-file-preview-shell";
|
|
6
|
+
import FilePreviewButton from "../shell/file-preview-button.vue";
|
|
7
|
+
import FilePreviewTools from "../shell/file-preview-tools.vue";
|
|
8
|
+
const TRANSPARENT = /* @__PURE__ */ new Set(["apng", "avif", "gif", "ico", "png", "svg", "webp"]);
|
|
9
|
+
const PADDING = 24;
|
|
10
|
+
const MAX_ZOOM = 4;
|
|
11
|
+
const props = defineProps({
|
|
12
|
+
file: { type: Object, required: true },
|
|
13
|
+
url: { type: String, required: true },
|
|
14
|
+
blob: { type: null, required: true },
|
|
15
|
+
container: { type: String, required: true }
|
|
16
|
+
});
|
|
17
|
+
const emit = defineEmits(["ready", "error"]);
|
|
18
|
+
const { t } = useUiToolsLocale();
|
|
19
|
+
const viewport = useTemplateRef("viewport");
|
|
20
|
+
const { height, width } = useElementSize(viewport);
|
|
21
|
+
const natural = shallowRef(null);
|
|
22
|
+
const scale = ref(1);
|
|
23
|
+
const offset = ref({ x: 0, y: 0 });
|
|
24
|
+
const rotation = ref(0);
|
|
25
|
+
const dragging = ref(false);
|
|
26
|
+
const transparent = computed(
|
|
27
|
+
() => props.file.mime === "image/svg+xml" || TRANSPARENT.has(props.file.extension ?? "")
|
|
28
|
+
);
|
|
29
|
+
const turned = computed(() => rotation.value % 180 !== 0);
|
|
30
|
+
const fit = computed(() => {
|
|
31
|
+
const size = natural.value;
|
|
32
|
+
if (!size || width.value <= 0 || height.value <= 0) return 1;
|
|
33
|
+
const shownWidth = turned.value ? size.height : size.width;
|
|
34
|
+
const shownHeight = turned.value ? size.width : size.height;
|
|
35
|
+
return Math.min(
|
|
36
|
+
(width.value - PADDING * 2) / shownWidth,
|
|
37
|
+
(height.value - PADDING * 2) / shownHeight,
|
|
38
|
+
1
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
const maxScale = computed(() => Math.max(MAX_ZOOM / fit.value, 2));
|
|
42
|
+
const zoomed = computed(() => scale.value > 1.001);
|
|
43
|
+
const percent = computed(() => `${Math.round(fit.value * scale.value * 100)}%`);
|
|
44
|
+
const imageStyle = computed(() => {
|
|
45
|
+
const size = natural.value;
|
|
46
|
+
return {
|
|
47
|
+
height: size ? `${size.height * fit.value}px` : void 0,
|
|
48
|
+
transform: `translate(-50%, -50%) translate(${offset.value.x}px, ${offset.value.y}px) scale(${scale.value}) rotate(${rotation.value}deg)`,
|
|
49
|
+
width: size ? `${size.width * fit.value}px` : void 0
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
function zoomTo(next, point) {
|
|
53
|
+
const target = Math.min(Math.max(next, 1), maxScale.value);
|
|
54
|
+
const box = viewport.value?.getBoundingClientRect();
|
|
55
|
+
const x = point && box ? point.x - (box.left + box.width / 2) : 0;
|
|
56
|
+
const y = point && box ? point.y - (box.top + box.height / 2) : 0;
|
|
57
|
+
const ratio = target / scale.value;
|
|
58
|
+
offset.value = target <= 1.001 ? { x: 0, y: 0 } : { x: x - (x - offset.value.x) * ratio, y: y - (y - offset.value.y) * ratio };
|
|
59
|
+
scale.value = target <= 1.001 ? 1 : target;
|
|
60
|
+
}
|
|
61
|
+
function reset() {
|
|
62
|
+
scale.value = 1;
|
|
63
|
+
offset.value = { x: 0, y: 0 };
|
|
64
|
+
}
|
|
65
|
+
function rotate() {
|
|
66
|
+
rotation.value = (rotation.value + 90) % 360;
|
|
67
|
+
reset();
|
|
68
|
+
}
|
|
69
|
+
function handleLoad(event) {
|
|
70
|
+
if (!(event.target instanceof HTMLImageElement)) return;
|
|
71
|
+
const size = {
|
|
72
|
+
height: event.target.naturalHeight || 600,
|
|
73
|
+
width: event.target.naturalWidth || 800
|
|
74
|
+
};
|
|
75
|
+
natural.value = size;
|
|
76
|
+
emit("ready", [
|
|
77
|
+
{ label: t("filePreview.fields.dimensions"), value: `${size.width} \xD7 ${size.height} px` }
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
function toggleZoom(event) {
|
|
81
|
+
if (zoomed.value) return reset();
|
|
82
|
+
zoomTo(Math.max(2.5, 1 / fit.value), { x: event.clientX, y: event.clientY });
|
|
83
|
+
}
|
|
84
|
+
function startDrag(event) {
|
|
85
|
+
if (!zoomed.value || !(event.currentTarget instanceof HTMLElement)) return;
|
|
86
|
+
const origin = { x: event.clientX - offset.value.x, y: event.clientY - offset.value.y };
|
|
87
|
+
const surface = event.currentTarget;
|
|
88
|
+
surface.setPointerCapture(event.pointerId);
|
|
89
|
+
dragging.value = true;
|
|
90
|
+
const move = (moved) => {
|
|
91
|
+
offset.value = { x: moved.clientX - origin.x, y: moved.clientY - origin.y };
|
|
92
|
+
};
|
|
93
|
+
const stop = () => {
|
|
94
|
+
dragging.value = false;
|
|
95
|
+
surface.removeEventListener("pointermove", move);
|
|
96
|
+
surface.removeEventListener("pointerup", stop);
|
|
97
|
+
surface.removeEventListener("pointercancel", stop);
|
|
98
|
+
};
|
|
99
|
+
surface.addEventListener("pointermove", move);
|
|
100
|
+
surface.addEventListener("pointerup", stop);
|
|
101
|
+
surface.addEventListener("pointercancel", stop);
|
|
102
|
+
}
|
|
103
|
+
useEventListener(
|
|
104
|
+
viewport,
|
|
105
|
+
"wheel",
|
|
106
|
+
(event) => {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
const speed = event.ctrlKey ? 0.01 : 18e-4;
|
|
109
|
+
zoomTo(scale.value * Math.exp(-event.deltaY * speed), { x: event.clientX, y: event.clientY });
|
|
110
|
+
},
|
|
111
|
+
{ passive: false }
|
|
112
|
+
);
|
|
113
|
+
onFilePreviewKey(["+", "=", "-", "0", "r", "R"], (event) => {
|
|
114
|
+
if (event.key === "+" || event.key === "=") zoomTo(scale.value * 1.5);
|
|
115
|
+
else if (event.key === "-") zoomTo(scale.value / 1.5);
|
|
116
|
+
else if (event.key === "0") reset();
|
|
117
|
+
else rotate();
|
|
118
|
+
});
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<template>
|
|
122
|
+
<div
|
|
123
|
+
ref="viewport"
|
|
124
|
+
:class="[
|
|
125
|
+
'absolute inset-0 touch-none overflow-hidden select-none',
|
|
126
|
+
transparent ? 'nut-fp-checker' : '',
|
|
127
|
+
zoomed ? dragging ? 'cursor-grabbing' : 'cursor-grab' : 'cursor-zoom-in'
|
|
128
|
+
]"
|
|
129
|
+
:data-file-preview-zoomed="zoomed ? '' : void 0"
|
|
130
|
+
data-file-preview-image=""
|
|
131
|
+
@dblclick="toggleZoom"
|
|
132
|
+
@pointerdown="startDrag"
|
|
133
|
+
>
|
|
134
|
+
<img
|
|
135
|
+
:src="url"
|
|
136
|
+
:alt="file.name"
|
|
137
|
+
draggable="false"
|
|
138
|
+
:class="[
|
|
139
|
+
'absolute top-1/2 left-1/2 max-w-none origin-center',
|
|
140
|
+
dragging ? '' : 'transition-transform duration-150 ease-out motion-reduce:transition-none',
|
|
141
|
+
natural ? '' : 'opacity-0',
|
|
142
|
+
transparent ? '' : 'shadow-[0_1px_3px_rgba(0,0,0,0.12)]'
|
|
143
|
+
]"
|
|
144
|
+
:style="imageStyle"
|
|
145
|
+
@load="handleLoad"
|
|
146
|
+
@error="emit('error', { reason: 'decode' })"
|
|
147
|
+
/>
|
|
148
|
+
|
|
149
|
+
<FilePreviewTools>
|
|
150
|
+
<FilePreviewButton
|
|
151
|
+
icon="i-lucide-zoom-out"
|
|
152
|
+
:label="t('filePreview.image.zoomOut')"
|
|
153
|
+
:kbds="['-']"
|
|
154
|
+
:disabled="!zoomed"
|
|
155
|
+
@click="zoomTo(scale / 1.5)"
|
|
156
|
+
/>
|
|
157
|
+
<button
|
|
158
|
+
type="button"
|
|
159
|
+
class="min-w-12 rounded-md px-1.5 py-1 text-xs font-medium text-toned tabular-nums hover:bg-elevated"
|
|
160
|
+
:aria-label="t('filePreview.image.fit')"
|
|
161
|
+
:title="t('filePreview.image.fit')"
|
|
162
|
+
data-file-preview-zoom=""
|
|
163
|
+
@click="reset"
|
|
164
|
+
>
|
|
165
|
+
{{ percent }}
|
|
166
|
+
</button>
|
|
167
|
+
<FilePreviewButton
|
|
168
|
+
icon="i-lucide-zoom-in"
|
|
169
|
+
:label="t('filePreview.image.zoomIn')"
|
|
170
|
+
:kbds="['+']"
|
|
171
|
+
:disabled="scale >= maxScale"
|
|
172
|
+
@click="zoomTo(scale * 1.5)"
|
|
173
|
+
/>
|
|
174
|
+
<FilePreviewButton
|
|
175
|
+
icon="i-lucide-rotate-cw"
|
|
176
|
+
:label="t('filePreview.image.rotate')"
|
|
177
|
+
:kbds="['R']"
|
|
178
|
+
@click="rotate"
|
|
179
|
+
/>
|
|
180
|
+
</FilePreviewTools>
|
|
181
|
+
</div>
|
|
182
|
+
</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,78 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
4
|
+
import { useFilePreviewShell } from "../../composables/use-file-preview-shell";
|
|
5
|
+
import { useFilePreviewText } from "../../composables/use-file-preview-text";
|
|
6
|
+
import FilePreviewTools from "../shell/file-preview-tools.vue";
|
|
7
|
+
import FilePreviewCode from "./file-preview-code.vue";
|
|
8
|
+
import FilePreviewTextLoading from "./file-preview-text-loading.vue";
|
|
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 shell = useFilePreviewShell();
|
|
18
|
+
const content = useFilePreviewText(props);
|
|
19
|
+
const view = ref(shell.markdown ? "preview" : "source");
|
|
20
|
+
const html = ref(null);
|
|
21
|
+
const facts = computed(() => content.notice.value ? [content.notice.value] : []);
|
|
22
|
+
watch(
|
|
23
|
+
content.status,
|
|
24
|
+
async (status) => {
|
|
25
|
+
if (status === "error")
|
|
26
|
+
emit("error", { message: content.error.value?.message, reason: "source" });
|
|
27
|
+
if (status !== "ready") return;
|
|
28
|
+
if (shell.markdown) {
|
|
29
|
+
try {
|
|
30
|
+
html.value = await shell.markdown(content.text.value);
|
|
31
|
+
} catch {
|
|
32
|
+
view.value = "source";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
emit("ready");
|
|
36
|
+
},
|
|
37
|
+
{ immediate: true }
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<template v-if="content.status.value === 'ready'">
|
|
43
|
+
<div
|
|
44
|
+
v-if="view === 'preview' && html !== null"
|
|
45
|
+
class="absolute inset-0 overflow-auto bg-default px-6 py-7 sm:px-10"
|
|
46
|
+
data-file-preview-markdown=""
|
|
47
|
+
>
|
|
48
|
+
<!-- eslint-disable-next-line vue/no-v-html -- the app's markdown renderer returns sanitized HTML -->
|
|
49
|
+
<article class="nut-fp-prose mx-auto max-w-[68ch]" v-html="html" />
|
|
50
|
+
</div>
|
|
51
|
+
<FilePreviewCode
|
|
52
|
+
v-else
|
|
53
|
+
:text="content.text.value"
|
|
54
|
+
:json="false"
|
|
55
|
+
:facts="facts"
|
|
56
|
+
:tools="view === 'source'"
|
|
57
|
+
/>
|
|
58
|
+
|
|
59
|
+
<FilePreviewTools v-if="shell.markdown">
|
|
60
|
+
<div class="flex gap-0.5 rounded-md border border-default bg-elevated p-0.5" role="group">
|
|
61
|
+
<button
|
|
62
|
+
v-for="option in ['preview', 'source']"
|
|
63
|
+
:key="option"
|
|
64
|
+
type="button"
|
|
65
|
+
:aria-pressed="view === option"
|
|
66
|
+
:class="[
|
|
67
|
+
'rounded px-2 py-0.5 text-xs font-medium transition',
|
|
68
|
+
view === option ? 'bg-default text-highlighted shadow-xs ring ring-default' : 'text-muted hover:text-highlighted'
|
|
69
|
+
]"
|
|
70
|
+
@click="view = option"
|
|
71
|
+
>
|
|
72
|
+
{{ t(`filePreview.markdown.${option}`) }}
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</FilePreviewTools>
|
|
76
|
+
</template>
|
|
77
|
+
<FilePreviewTextLoading v-else />
|
|
78
|
+
</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 { useFullscreen, useMediaControls } from '@vueuse/core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
controls: ReturnType<typeof useMediaControls>;
|
|
4
|
+
variant: 'video' | 'audio';
|
|
5
|
+
fullscreen?: ReturnType<typeof useFullscreen> | null;
|
|
6
|
+
compact?: boolean;
|
|
7
|
+
};
|
|
8
|
+
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>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import UButton from "@nuxt/ui/components/Button.vue";
|
|
3
|
+
import UDropdownMenu from "@nuxt/ui/components/DropdownMenu.vue";
|
|
4
|
+
import USlider from "@nuxt/ui/components/Slider.vue";
|
|
5
|
+
import { computed } from "vue";
|
|
6
|
+
import { useUiToolsLocale } from "../../../i18n/use-locale";
|
|
7
|
+
import { formatFilePreviewDuration } from "../../utils/format";
|
|
8
|
+
import FilePreviewButton from "../shell/file-preview-button.vue";
|
|
9
|
+
const RATES = [0.5, 0.75, 1, 1.25, 1.5, 2];
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
controls: { type: null, required: true },
|
|
12
|
+
variant: { type: String, required: true },
|
|
13
|
+
fullscreen: { type: null, required: false },
|
|
14
|
+
compact: { type: Boolean, required: false }
|
|
15
|
+
});
|
|
16
|
+
const { t } = useUiToolsLocale();
|
|
17
|
+
const tone = computed(() => props.variant === "video" ? "inverted" : "default");
|
|
18
|
+
const time = computed(
|
|
19
|
+
() => `${formatFilePreviewDuration(props.controls.currentTime.value)} / ${formatFilePreviewDuration(props.controls.duration.value)}`
|
|
20
|
+
);
|
|
21
|
+
const silent = computed(() => props.controls.muted.value || props.controls.volume.value === 0);
|
|
22
|
+
const captions = computed(() => props.controls.selectedTrack.value !== -1);
|
|
23
|
+
const sliderUi = computed(
|
|
24
|
+
() => props.variant === "video" ? { range: "bg-white", thumb: "bg-white ring-white", track: "bg-white/30" } : void 0
|
|
25
|
+
);
|
|
26
|
+
const rates = computed(
|
|
27
|
+
() => RATES.map((rate) => ({
|
|
28
|
+
checked: props.controls.rate.value === rate,
|
|
29
|
+
label: `${rate}\xD7`,
|
|
30
|
+
onSelect: () => {
|
|
31
|
+
props.controls.rate.value = rate;
|
|
32
|
+
},
|
|
33
|
+
type: "checkbox"
|
|
34
|
+
}))
|
|
35
|
+
);
|
|
36
|
+
function toggle() {
|
|
37
|
+
props.controls.playing.value = !props.controls.playing.value;
|
|
38
|
+
}
|
|
39
|
+
function seek(value) {
|
|
40
|
+
const next = Array.isArray(value) ? value[0] : value;
|
|
41
|
+
if (next !== void 0) props.controls.currentTime.value = next;
|
|
42
|
+
}
|
|
43
|
+
function setVolume(value) {
|
|
44
|
+
const next = Array.isArray(value) ? value[0] : value;
|
|
45
|
+
if (next === void 0) return;
|
|
46
|
+
props.controls.volume.value = next;
|
|
47
|
+
props.controls.muted.value = next === 0;
|
|
48
|
+
}
|
|
49
|
+
function toggleCaptions() {
|
|
50
|
+
if (captions.value) props.controls.disableTrack();
|
|
51
|
+
else props.controls.enableTrack(0);
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<div
|
|
57
|
+
:class="[
|
|
58
|
+
'flex items-center gap-1',
|
|
59
|
+
variant === 'video' ? 'bg-linear-to-t from-black/75 via-black/40 to-transparent px-2.5 pt-10 pb-2 text-white' : 'rounded-full border border-default bg-elevated py-1 ps-1 pe-2 text-toned'
|
|
60
|
+
]"
|
|
61
|
+
data-file-preview-media-controls=""
|
|
62
|
+
>
|
|
63
|
+
<FilePreviewButton
|
|
64
|
+
:icon="controls.playing.value ? 'i-lucide-pause' : 'i-lucide-play'"
|
|
65
|
+
:label="controls.playing.value ? t('filePreview.media.pause') : t('filePreview.media.play')"
|
|
66
|
+
:kbds="['space']"
|
|
67
|
+
:tone="tone"
|
|
68
|
+
data-file-preview-play=""
|
|
69
|
+
@click="toggle"
|
|
70
|
+
/>
|
|
71
|
+
<span class="shrink-0 px-1 text-xs whitespace-nowrap tabular-nums" data-file-preview-time="">
|
|
72
|
+
{{ time }}
|
|
73
|
+
</span>
|
|
74
|
+
<USlider
|
|
75
|
+
:model-value="controls.currentTime.value"
|
|
76
|
+
:min="0"
|
|
77
|
+
:max="Math.max(controls.duration.value, 0.1)"
|
|
78
|
+
:step="0.1"
|
|
79
|
+
size="xs"
|
|
80
|
+
color="neutral"
|
|
81
|
+
:aria-label="t('filePreview.media.seek')"
|
|
82
|
+
:ui="sliderUi"
|
|
83
|
+
class="mx-1.5 min-w-16 flex-1"
|
|
84
|
+
@update:model-value="seek"
|
|
85
|
+
/>
|
|
86
|
+
<FilePreviewButton
|
|
87
|
+
:icon="silent ? 'i-lucide-volume-x' : 'i-lucide-volume-2'"
|
|
88
|
+
:label="silent ? t('filePreview.media.unmute') : t('filePreview.media.mute')"
|
|
89
|
+
:kbds="['M']"
|
|
90
|
+
:tone="tone"
|
|
91
|
+
@click="controls.muted.value = !controls.muted.value"
|
|
92
|
+
/>
|
|
93
|
+
<USlider
|
|
94
|
+
v-if="!compact"
|
|
95
|
+
:model-value="silent ? 0 : controls.volume.value"
|
|
96
|
+
:min="0"
|
|
97
|
+
:max="1"
|
|
98
|
+
:step="0.05"
|
|
99
|
+
size="xs"
|
|
100
|
+
color="neutral"
|
|
101
|
+
:aria-label="t('filePreview.media.volume')"
|
|
102
|
+
:ui="sliderUi"
|
|
103
|
+
class="w-16 shrink-0"
|
|
104
|
+
@update:model-value="setVolume"
|
|
105
|
+
/>
|
|
106
|
+
<UDropdownMenu :items="rates" :content="{ align: 'end', side: 'top' }">
|
|
107
|
+
<UButton
|
|
108
|
+
:label="`${controls.rate.value}\xD7`"
|
|
109
|
+
:aria-label="t('filePreview.media.speed')"
|
|
110
|
+
color="neutral"
|
|
111
|
+
variant="ghost"
|
|
112
|
+
size="sm"
|
|
113
|
+
:class="[
|
|
114
|
+
'min-w-10 shrink-0 justify-center text-xs tabular-nums',
|
|
115
|
+
variant === 'video' ? 'text-white hover:bg-white/15 hover:text-white' : 'text-muted'
|
|
116
|
+
]"
|
|
117
|
+
/>
|
|
118
|
+
</UDropdownMenu>
|
|
119
|
+
<FilePreviewButton
|
|
120
|
+
v-if="controls.tracks.value.length > 0"
|
|
121
|
+
icon="i-lucide-captions"
|
|
122
|
+
:label="t('filePreview.media.captions')"
|
|
123
|
+
:pressed="captions"
|
|
124
|
+
:tone="tone"
|
|
125
|
+
@click="toggleCaptions"
|
|
126
|
+
/>
|
|
127
|
+
<FilePreviewButton
|
|
128
|
+
v-if="variant === 'video' && controls.supportsPictureInPicture"
|
|
129
|
+
icon="i-lucide-picture-in-picture-2"
|
|
130
|
+
:label="t('filePreview.media.pictureInPicture')"
|
|
131
|
+
:tone="tone"
|
|
132
|
+
@click="controls.togglePictureInPicture()"
|
|
133
|
+
/>
|
|
134
|
+
<FilePreviewButton
|
|
135
|
+
v-if="fullscreen?.isSupported.value"
|
|
136
|
+
:icon="fullscreen.isFullscreen.value ? 'i-lucide-minimize' : 'i-lucide-maximize'"
|
|
137
|
+
:label="
|
|
138
|
+
fullscreen.isFullscreen.value ? t('filePreview.media.exitFullscreen') : t('filePreview.media.fullscreen')
|
|
139
|
+
"
|
|
140
|
+
:kbds="['F']"
|
|
141
|
+
:tone="tone"
|
|
142
|
+
@click="fullscreen.toggle()"
|
|
143
|
+
/>
|
|
144
|
+
</div>
|
|
145
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { useFullscreen, useMediaControls } from '@vueuse/core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
controls: ReturnType<typeof useMediaControls>;
|
|
4
|
+
variant: 'video' | 'audio';
|
|
5
|
+
fullscreen?: ReturnType<typeof useFullscreen> | null;
|
|
6
|
+
compact?: boolean;
|
|
7
|
+
};
|
|
8
|
+
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>;
|
|
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;
|