mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 03:33:35 +00:00
fix(ui): unify sidebar tooltips
This commit is contained in:
@@ -4,8 +4,8 @@ import { useI18n } from "vue-i18n";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
import { Upload, Download, FolderPlus, RefreshCw, ChevronsLeft, ChevronsUp } from "@lucide/vue";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||
import LightDropdown from "@/components/ui/LightDropdown.vue";
|
||||
import LightTooltip from "@/components/ui/LightTooltip.vue";
|
||||
import ConnectionTree from "@/components/sidebar/ConnectionTree.vue";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
@@ -62,68 +62,50 @@ defineExpose({ focusSearch });
|
||||
<div class="flex items-center gap-px px-3 text-xs font-medium text-muted-foreground border-b bg-muted/20" :class="classicLayout ? 'h-9' : 'h-10'">
|
||||
<span class="flex self-stretch items-center truncate" data-tauri-drag-region>{{ t("sidebar.connections") }}</span>
|
||||
<span class="flex-1 self-stretch" data-tauri-drag-region />
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<span class="inline-flex">
|
||||
<LightDropdown
|
||||
model-value=""
|
||||
:items="importSourceItems"
|
||||
:aria-label="t('sidebar.import')"
|
||||
:trigger-icon="Download"
|
||||
trigger-class="inline-flex h-6 w-5 items-center justify-center rounded-md outline-none hover:bg-muted hover:text-foreground focus-visible:ring-0"
|
||||
trigger-icon-class="h-4 w-4"
|
||||
content-class="w-44"
|
||||
:show-trigger-label="false"
|
||||
:show-chevron="false"
|
||||
:highlight-selected="false"
|
||||
check-position="none"
|
||||
align="end"
|
||||
@update:model-value="(source) => emit('import', source as 'dbx' | 'navicat' | 'dbeaver' | 'datagrip')"
|
||||
/>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("sidebar.import") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="emit('export')">
|
||||
<Upload class="h-3 w-3" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("sidebar.export") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="collapseAllTreeNodes">
|
||||
<ChevronsUp class="h-3 w-3" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("sidebar.collapseAll") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="createNewGroup">
|
||||
<FolderPlus class="h-3 w-3" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("connectionGroup.createGroup") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="refreshTree">
|
||||
<RefreshCw class="h-3 w-3" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("contextMenu.refreshChildren") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="emit('collapse')">
|
||||
<ChevronsLeft class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("sidebar.collapse") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<LightTooltip :text="t('sidebar.import')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<span class="inline-flex">
|
||||
<LightDropdown
|
||||
model-value=""
|
||||
:items="importSourceItems"
|
||||
:aria-label="t('sidebar.import')"
|
||||
:trigger-icon="Download"
|
||||
trigger-class="inline-flex h-6 w-5 items-center justify-center rounded-md outline-none hover:bg-muted hover:text-foreground focus-visible:ring-0"
|
||||
trigger-icon-class="h-4 w-4"
|
||||
content-class="w-44"
|
||||
:show-trigger-label="false"
|
||||
:show-chevron="false"
|
||||
:highlight-selected="false"
|
||||
check-position="none"
|
||||
align="end"
|
||||
@update:model-value="(source) => emit('import', source as 'dbx' | 'navicat' | 'dbeaver' | 'datagrip')"
|
||||
/>
|
||||
</span>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('sidebar.export')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="emit('export')">
|
||||
<Upload class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('sidebar.collapseAll')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="collapseAllTreeNodes">
|
||||
<ChevronsUp class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('connectionGroup.createGroup')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="createNewGroup">
|
||||
<FolderPlus class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('contextMenu.refreshChildren')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="refreshTree">
|
||||
<RefreshCw class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('sidebar.collapse')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="emit('collapse')">
|
||||
<ChevronsLeft class="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
</div>
|
||||
<div class="flex-1 min-h-0">
|
||||
<ConnectionTree ref="connectionTreeRef" />
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, reactive, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Download, FileInput, FilePlus, FileText, FolderCog, FolderClosed, FolderOpen, FolderPlus, Library, LocateFixed, Pencil, Search, Trash2, Upload, X, ArrowDownWideNarrow } from "@lucide/vue";
|
||||
import { ArrowDownWideNarrow, Download, FileInput, FilePlus, FileText, FolderCog, FolderClosed, FolderOpen, FolderPlus, Library, LocateFixed, Pencil, Search, Trash2, Upload, X } from "@lucide/vue";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import CustomContextMenu, { type ContextMenuItem as CtxMenuItem } from "@/components/ui/CustomContextMenu.vue";
|
||||
import LightTooltip from "@/components/ui/LightTooltip.vue";
|
||||
import { useToast } from "@/composables/useToast";
|
||||
import { isTauriRuntime } from "@/lib/tauriRuntime";
|
||||
import * as api from "@/lib/api";
|
||||
@@ -738,8 +739,8 @@ const contextMenuItems = computed<CtxMenuItem[]>(() => {
|
||||
return [
|
||||
{ label: t("savedSql.newFolder"), action: openNewFolderInput, icon: FolderPlus },
|
||||
{ label: t("savedSql.newQuery"), action: () => openNewQueryInFolder(), icon: FilePlus },
|
||||
{ label: t("sqlLibrary.importDirectory"), action: () => importDirectoryIntoLibrary(), icon: Upload },
|
||||
{ label: t("sqlLibrary.exportLibrary"), action: () => exportFolderContents(), icon: Download },
|
||||
{ label: t("sqlLibrary.importDirectory"), action: () => importDirectoryIntoLibrary(), icon: Download },
|
||||
{ label: t("sqlLibrary.exportLibrary"), action: () => exportFolderContents(), icon: Upload },
|
||||
{ label: "", separator: true },
|
||||
{ label: t("sqlLibrary.openStorageDirectory"), action: openSqlStorageDirectory, icon: LocateFixed },
|
||||
{ label: t("sqlLibrary.chooseSyncDirectory"), action: chooseSyncDirectory, icon: FolderCog },
|
||||
@@ -769,8 +770,8 @@ const contextMenuItems = computed<CtxMenuItem[]>(() => {
|
||||
return [
|
||||
{ label: t("savedSql.newFolder"), action: () => openNewFolderInput(target.id), icon: FolderPlus },
|
||||
{ label: t("savedSql.newQuery"), action: () => openNewQueryInFolder(target), icon: FilePlus },
|
||||
{ label: t("sqlLibrary.importIntoFolder"), action: () => importDirectoryIntoLibrary(target), icon: Upload },
|
||||
{ label: t("sqlLibrary.exportFolder"), action: () => exportFolderContents(target), icon: Download },
|
||||
{ label: t("sqlLibrary.importIntoFolder"), action: () => importDirectoryIntoLibrary(target), icon: Download },
|
||||
{ label: t("sqlLibrary.exportFolder"), action: () => exportFolderContents(target), icon: Upload },
|
||||
{ label: "", separator: true },
|
||||
{ label: t("savedSql.renameFolder"), action: () => startRenameFolder(target), icon: Pencil },
|
||||
{ label: "", separator: true },
|
||||
@@ -1019,21 +1020,31 @@ function showDropInside(targetId: string) {
|
||||
<span class="text-[13px] font-medium">{{ t("sqlLibrary.title") }}</span>
|
||||
<span v-if="hasSelection" class="text-[12px] text-muted-foreground ml-1">({{ selectedCount }})</span>
|
||||
<span class="flex-1" />
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" :title="sortMode === 'folder' ? t('sqlLibrary.sortByDate') : t('sqlLibrary.sortByFolder')" @click="sortMode = sortMode === 'folder' ? 'date' : 'folder'">
|
||||
<ArrowDownWideNarrow :class="['h-3 w-3', sortMode === 'date' ? 'text-primary' : '']" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" :title="t('savedSql.newFolder')" @click="openNewFolderInput">
|
||||
<FolderPlus class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" :title="t('sqlLibrary.importDirectory')" @click="importDirectoryIntoLibrary()">
|
||||
<Upload class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" :title="t('sqlLibrary.exportLibrary')" @click="exportFolderContents()">
|
||||
<Download class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="emit('close')">
|
||||
<X class="h-3 w-3" />
|
||||
</Button>
|
||||
<LightTooltip :text="sortMode === 'folder' ? t('sqlLibrary.sortByDate') : t('sqlLibrary.sortByFolder')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="sortMode = sortMode === 'folder' ? 'date' : 'folder'">
|
||||
<ArrowDownWideNarrow :class="['h-3 w-3', sortMode === 'date' ? 'text-primary' : '']" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('savedSql.newFolder')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="openNewFolderInput">
|
||||
<FolderPlus class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('sqlLibrary.importDirectory')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="importDirectoryIntoLibrary()">
|
||||
<Download class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('sqlLibrary.exportLibrary')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="exportFolderContents()">
|
||||
<Upload class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
<LightTooltip :text="t('common.close')" side="bottom" :delay="0" :close-delay="0" nowrap>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="emit('close')">
|
||||
<X class="h-3 w-3" />
|
||||
</Button>
|
||||
</LightTooltip>
|
||||
</div>
|
||||
|
||||
<div class="border-b shrink-0 px-2 py-1">
|
||||
|
||||
@@ -10,6 +10,7 @@ const props = withDefaults(
|
||||
delay?: number;
|
||||
closeDelay?: number;
|
||||
openOnFocus?: boolean;
|
||||
nowrap?: boolean;
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
@@ -18,6 +19,7 @@ const props = withDefaults(
|
||||
delay: 300,
|
||||
closeDelay: 100,
|
||||
openOnFocus: true,
|
||||
nowrap: false,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -240,7 +242,7 @@ watch(
|
||||
v-if="show"
|
||||
ref="tooltipRef"
|
||||
class="fixed z-50 rounded-md bg-foreground text-xs text-background"
|
||||
:class="[slots.content ? '' : 'inline-flex w-fit max-w-xs items-center gap-1.5 px-3 py-1.5', tooltipTransformClass]"
|
||||
:class="[slots.content ? '' : ['inline-flex w-fit max-w-xs items-center gap-1.5 px-3 py-1.5', nowrap ? 'whitespace-nowrap' : ''], tooltipTransformClass]"
|
||||
:style="{ left: `${x}px`, top: `${y}px` }"
|
||||
role="tooltip"
|
||||
@mouseenter="clearCloseTimer"
|
||||
|
||||
Reference in New Issue
Block a user