RSS Git Download  Clone
Raw Blame History 4kB 132 lines
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useDisplay } from 'vuetify'
import { useVirtualizer } from '@tanstack/vue-virtual'
import { useI18nStore } from '../stores/i18n'
import P3xrDialog from '../components/P3xrDialog.vue'

const ROW_HEIGHT = 40

const props = defineProps<{
    open: boolean
    data: { keys: any[] } | null
}>()

const emit = defineEmits<{
    close: [result: { pending: boolean; keys: any[]; conflictMode: string } | null]
}>()

const i18n = useI18nStore()
const strings = computed(() => i18n.strings)
const { width } = useDisplay()
const isWide = computed(() => width.value >= 600)

const conflictMode = ref('overwrite')
const keys = computed(() => props.data?.keys || [])
const parentRef = ref<HTMLDivElement | null>(null)

const virtualizer = useVirtualizer(computed(() => ({
    count: keys.value.length,
    getScrollElement: () => parentRef.value,
    estimateSize: () => ROW_HEIGHT,
    overscan: 10,
})))

function cancel() {
    emit('close', null)
}

function doImport() {
    emit('close', { pending: true, keys: keys.value, conflictMode: conflictMode.value })
}
</script>

<template>
    <P3xrDialog v-if="open && keys.length > 0" :open="true"
        :title="strings?.intention?.importKeys"
        @close="cancel()">

        <!-- Preview label -->
        <div style="margin-bottom: 8px; font-size: 13px; opacity: 0.7;">
            {{ keys.length }} {{ strings?.label?.keysToImport }}
        </div>

        <!-- Virtual scrolled key preview list (300px height, 40px rows) -->
        <div ref="parentRef" class="p3xr-import-preview-list">
            <div :style="{ height: virtualizer.getTotalSize() + 'px', width: '100%', position: 'relative' }">
                <div
                    v-for="virtualRow in virtualizer.getVirtualItems()"
                    :key="keys[virtualRow.index].key"
                    class="p3xr-import-preview-row"
                    :style="{
                        position: 'absolute', top: 0, left: 0, width: '100%',
                        height: ROW_HEIGHT + 'px',
                        transform: 'translateY(' + virtualRow.start + 'px)',
                    }"
                >
                    <span class="p3xr-import-key-name">{{ keys[virtualRow.index].key }}</span>
                    <kbd v-if="keys[virtualRow.index].type" class="p3xr-import-key-type">{{ keys[virtualRow.index].type }}</kbd>
                </div>
            </div>
        </div>

        <!-- Conflict mode radio -->
        <div style="margin-top: 12px;">
            <v-radio-group v-model="conflictMode" inline hide-details>
                <v-radio value="overwrite" :label="strings?.label?.importOverwrite" />
                <v-radio value="skip" :label="strings?.label?.importSkip" />
            </v-radio-group>
        </div>

        <template #actions>
            <v-btn variant="flat" color="warning" @click="cancel()">
                <v-icon :class="{ 'mr-1': isWide }">mdi-close-circle</v-icon>
                <span v-if="isWide">{{ strings?.intention?.cancel }}</span>
                <v-tooltip v-if="!isWide" activator="parent" location="top">{{ strings?.intention?.cancel }}</v-tooltip>
            </v-btn>
            <v-btn variant="flat" color="primary" @click="doImport()">
                <v-icon class="mr-1">mdi-upload</v-icon>
                <span>{{ strings?.intention?.import }}</span>
            </v-btn>
        </template>
    </P3xrDialog>
</template>

<style scoped>
.p3xr-import-preview-list {
    height: 300px;
    overflow-y: auto;
    border: 1px solid rgba(var(--v-border-color), 0.12);
    border-radius: 4px;
}

.p3xr-import-preview-row {
    display: flex;
    align-items: center;
    padding: 0 12px;
    border-bottom: 1px solid rgba(var(--v-border-color), 0.06);
    gap: 8px;
    box-sizing: border-box;
}

.p3xr-import-key-name {
    flex: 1;
    font-family: 'Roboto Mono', monospace;
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.p3xr-import-key-type {
    display: inline-block;
    font-family: 'Roboto Mono', monospace;
    font-size: 11px;
    padding: 1px 6px;
    border: 1px solid rgba(var(--v-border-color), 0.2);
    border-radius: 3px;
    background: rgba(128, 128, 128, 0.1);
    white-space: nowrap;
}
</style>