fix(desktop): align import and tab bar chrome
This commit is contained in:
1 parent
05e64ad43a
commit
c27fee19d6
2 files changed
+63
-15
No files matched your search
@@ -102,6 +102,7 @@ const progressPercent = computed(() => {
|
|||||||
if (!p || p.totalRows <= 0) return 0;
|
if (!p || p.totalRows <= 0) return 0;
|
||||||
return Math.min(100, Math.round((p.rowsImported / p.totalRows) * 100));
|
return Math.min(100, Math.round((p.rowsImported / p.totalRows) * 100));
|
||||||
});
|
});
|
||||||
|
const currentStepIndex = computed(() => wizardSteps.findIndex((step) => step.value === wizardStep.value));
|
||||||
const targetLabel = computed(() => {
|
const targetLabel = computed(() => {
|
||||||
const pieces = [selectedConnection.value?.name, props.prefillDatabase, props.prefillSchema, props.prefillTable].filter(Boolean);
|
const pieces = [selectedConnection.value?.name, props.prefillDatabase, props.prefillSchema, props.prefillTable].filter(Boolean);
|
||||||
return pieces.join(" / ");
|
return pieces.join(" / ");
|
||||||
@@ -269,6 +270,34 @@ function canOpenStep(step: TableImportWizardStep) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wizardStepIndex(step: TableImportWizardStep) {
|
||||||
|
return wizardSteps.findIndex((item) => item.value === step);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWizardStepActive(step: TableImportWizardStep) {
|
||||||
|
return step === wizardStep.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWizardStepComplete(step: TableImportWizardStep) {
|
||||||
|
return wizardStepIndex(step) < currentStepIndex.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wizardStepConnectorClass(index: number, leading: boolean) {
|
||||||
|
return (leading ? index <= currentStepIndex.value : index < currentStepIndex.value) ? "bg-primary/60" : "bg-border";
|
||||||
|
}
|
||||||
|
|
||||||
|
function wizardStepTextClass(step: TableImportWizardStep) {
|
||||||
|
if (isWizardStepActive(step)) return "text-foreground";
|
||||||
|
if (isWizardStepComplete(step)) return "text-foreground hover:bg-muted/40";
|
||||||
|
return "text-muted-foreground";
|
||||||
|
}
|
||||||
|
|
||||||
|
function wizardStepCircleClass(step: TableImportWizardStep) {
|
||||||
|
if (isWizardStepActive(step)) return "border-primary bg-primary text-primary-foreground shadow-sm";
|
||||||
|
if (isWizardStepComplete(step)) return "border-primary/70 bg-background text-primary";
|
||||||
|
return "border-border bg-background text-muted-foreground";
|
||||||
|
}
|
||||||
|
|
||||||
async function goNext() {
|
async function goNext() {
|
||||||
if (wizardStep.value === "options" && !preview.value) {
|
if (wizardStep.value === "options" && !preview.value) {
|
||||||
await loadPreview();
|
await loadPreview();
|
||||||
@@ -361,8 +390,8 @@ watch([sourceFormat, delimiter, hasHeader, trimValues, emptyStringAsNull, select
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Dialog v-model:open="open">
|
<Dialog v-model:open="open">
|
||||||
<DialogScrollContent class="sm:max-w-[980px] pt-12" :trap-focus="false" @interact-outside.prevent>
|
<DialogScrollContent class="sm:max-w-[980px]" :trap-focus="false" @interact-outside.prevent>
|
||||||
<DialogHeader>
|
<DialogHeader class="pr-8">
|
||||||
<DialogTitle class="flex items-center gap-2 text-base">
|
<DialogTitle class="flex items-center gap-2 text-base">
|
||||||
<FileUp class="h-4 w-4" />
|
<FileUp class="h-4 w-4" />
|
||||||
{{ t("tableImport.title") }}
|
{{ t("tableImport.title") }}
|
||||||
@@ -370,26 +399,43 @@ watch([sourceFormat, delimiter, hasHeader, trimValues, emptyStringAsNull, select
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div class="space-y-4 py-2">
|
<div class="space-y-4 py-2">
|
||||||
<div class="grid grid-cols-[1fr_auto] gap-2">
|
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-2">
|
||||||
<input ref="fileInput" type="file" accept=".csv,.tsv,.txt,.json,.xlsx,.xlsm,.xls" class="hidden" @change="handleFileInputChange" />
|
<input ref="fileInput" type="file" accept=".csv,.tsv,.txt,.json,.xlsx,.xlsm,.xls" class="hidden" @change="handleFileInputChange" />
|
||||||
<div class="min-w-0 rounded-md border bg-muted/20 px-3 py-2">
|
<div class="flex h-10 min-w-0 items-center gap-2 rounded-md border bg-muted/20 px-3">
|
||||||
<div class="truncate text-xs text-muted-foreground">{{ t("tableImport.target") }}</div>
|
<span class="shrink-0 text-xs text-muted-foreground">{{ t("tableImport.target") }}</span>
|
||||||
<div class="truncate text-sm font-medium">
|
<span class="min-w-0 truncate text-sm font-medium">
|
||||||
{{ targetLabel || t("editor.noDatabase") }}
|
{{ targetLabel || t("editor.noDatabase") }}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="outline" size="sm" :disabled="running || loadingPreview" @click="selectFile">
|
<Button variant="outline" class="h-10 px-3" :disabled="running || loadingPreview" @click="selectFile">
|
||||||
<Loader2 v-if="loadingPreview" class="mr-1.5 h-3.5 w-3.5 animate-spin" />
|
<Loader2 v-if="loadingPreview" class="mr-1.5 h-3.5 w-3.5 animate-spin" />
|
||||||
<Upload v-else class="mr-1.5 h-3.5 w-3.5" />
|
<Upload v-else class="mr-1.5 h-3.5 w-3.5" />
|
||||||
{{ selectedSource ? t("tableImport.changeFile") : t("tableImport.selectFile") }}
|
{{ selectedSource ? t("tableImport.changeFile") : t("tableImport.selectFile") }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-5 gap-1 rounded-md border bg-muted/20 p-1">
|
<nav class="rounded-md border bg-muted/20 px-3 py-2" :aria-label="t('tableImport.progress')">
|
||||||
<button v-for="step in wizardSteps" :key="step.value" type="button" class="h-8 rounded px-2 text-xs font-medium" :class="wizardStep === step.value ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground'" :disabled="!canOpenStep(step.value)" @click="wizardStep = step.value">
|
<ol class="grid grid-cols-5">
|
||||||
{{ t(step.labelKey) }}
|
<li v-for="(step, index) in wizardSteps" :key="step.value" class="relative flex min-w-0 justify-center">
|
||||||
</button>
|
<div v-if="index > 0" class="pointer-events-none absolute left-0 right-1/2 top-3.5 h-px" :class="wizardStepConnectorClass(index, true)" />
|
||||||
</div>
|
<div v-if="index < wizardSteps.length - 1" class="pointer-events-none absolute left-1/2 right-0 top-3.5 h-px" :class="wizardStepConnectorClass(index, false)" />
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="relative z-10 flex min-w-0 flex-col items-center gap-1 rounded-md px-2 py-1 text-xs font-medium transition-colors"
|
||||||
|
:class="[wizardStepTextClass(step.value), canOpenStep(step.value) ? 'cursor-pointer' : 'cursor-default']"
|
||||||
|
:disabled="!canOpenStep(step.value)"
|
||||||
|
:aria-current="isWizardStepActive(step.value) ? 'step' : undefined"
|
||||||
|
@click="wizardStep = step.value"
|
||||||
|
>
|
||||||
|
<span class="flex h-6 w-6 shrink-0 items-center justify-center rounded-full border text-[11px] font-semibold" :class="wizardStepCircleClass(step.value)">
|
||||||
|
<Check v-if="isWizardStepComplete(step.value)" class="h-3.5 w-3.5" />
|
||||||
|
<span v-else>{{ index + 1 }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="max-w-full truncate">{{ t(step.labelKey) }}</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div v-if="wizardStep === 'source'" class="space-y-4">
|
<div v-if="wizardStep === 'source'" class="space-y-4">
|
||||||
<div class="rounded-md border border-dashed p-6 text-center">
|
<div class="rounded-md border border-dashed p-6 text-center">
|
||||||
|
|||||||
@@ -423,6 +423,8 @@ const showFixedTabScrollbar = computed(() => hasFixedTabOverflow.value);
|
|||||||
const showRegularTabOverflowControls = computed(() => regularTabs.value.length > 0 && hasTabOverflow.value);
|
const showRegularTabOverflowControls = computed(() => regularTabs.value.length > 0 && hasTabOverflow.value);
|
||||||
const regularTabOverflowOpen = ref(false);
|
const regularTabOverflowOpen = ref(false);
|
||||||
const fixedTabOverflowOpen = ref(false);
|
const fixedTabOverflowOpen = ref(false);
|
||||||
|
const tabBarClass = computed(() => [isClassicLayout.value ? "bg-muted" : "border-b bg-background", hasFixedTabs.value ? "flex-col" : "", isClassicLayout.value && hasFixedTabs.value ? "border-b" : ""]);
|
||||||
|
const regularTabRowClass = computed(() => [isClassicLayout.value ? "h-9 items-stretch" : "h-10 items-center px-2", isClassicLayout.value && !hasFixedTabs.value ? "border-b" : ""]);
|
||||||
|
|
||||||
function tabMenuIcon(tab: QueryTab) {
|
function tabMenuIcon(tab: QueryTab) {
|
||||||
if (tab.mode === "data" || tab.mode === "mongo" || tab.mode === "redis") return Table2;
|
if (tab.mode === "data" || tab.mode === "mongo" || tab.mode === "redis") return Table2;
|
||||||
@@ -524,8 +526,8 @@ function onOverflowItemKeydown(event: KeyboardEvent, tabId: string, kind: "regul
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="queryStore.tabs.length > 0 || driverStoreOpen || settingsPageOpen" class="app-tab-bar relative flex w-full min-w-0 shrink-0 overflow-hidden border-b" :class="[isClassicLayout ? 'bg-muted' : 'bg-background', hasFixedTabs ? 'flex-col' : '']">
|
<div v-if="queryStore.tabs.length > 0 || driverStoreOpen || settingsPageOpen" class="app-tab-bar relative flex w-full min-w-0 shrink-0 overflow-hidden" :class="tabBarClass">
|
||||||
<div class="flex w-full min-w-0 shrink-0 overflow-hidden" :class="isClassicLayout ? 'h-9 items-stretch' : 'h-10 items-center px-2'">
|
<div class="flex w-full min-w-0 shrink-0 overflow-hidden" :class="regularTabRowClass">
|
||||||
<div class="app-tab-strip relative h-full min-w-0 flex-1 overflow-hidden">
|
<div class="app-tab-strip relative h-full min-w-0 flex-1 overflow-hidden">
|
||||||
<div v-if="showRegularTabScrollbar" class="app-tab-scrollbar" :class="{ 'app-tab-scrollbar--dragging': isScrollbarDragging }" @pointerdown="startScrollbarDrag">
|
<div v-if="showRegularTabScrollbar" class="app-tab-scrollbar" :class="{ 'app-tab-scrollbar--dragging': isScrollbarDragging }" @pointerdown="startScrollbarDrag">
|
||||||
<div class="app-tab-scrollbar__thumb" :style="tabScrollbarThumbStyle" />
|
<div class="app-tab-scrollbar__thumb" :style="tabScrollbarThumbStyle" />
|
||||||
|
|||||||
Reference in new issue
Block a user