feat(grid): add table font shortcuts
This commit is contained in:
25 files changed
+198
-77
No files matched your search
@@ -21,7 +21,6 @@ import {
|
||||
useSettingsStore,
|
||||
AI_PROVIDER_PRESETS,
|
||||
EDITOR_THEMES,
|
||||
FONT_FAMILIES,
|
||||
DEFAULT_EDITOR_SETTINGS,
|
||||
DEFAULT_DESKTOP_SETTINGS,
|
||||
DEFAULT_SIDEBAR_TABLE_PAGE_SIZE,
|
||||
@@ -64,7 +63,6 @@ import {
|
||||
forgetWebdavSyncSecretsPassphrase,
|
||||
forgetWebdavSavedPassword,
|
||||
getAppSupportInfo,
|
||||
listSystemFonts,
|
||||
saveWebdavSyncSecretsPreference,
|
||||
saveWebdavSavedPassword,
|
||||
saveSnippetSavedToken,
|
||||
@@ -119,7 +117,8 @@ import { currentLocale, setLocale, type Locale } from "@/i18n";
|
||||
import { LOCALE_OPTIONS } from "@/lib/app/localeOptions";
|
||||
import { DEFAULT_WEB_DAV_AUTO_UPLOAD_INTERVAL_MINUTES, DEFAULT_WEB_DAV_REMOTE_PATH, normalizedWebDavAutoUploadInterval, writeWebDavAutoUploadFields } from "@/lib/webdav/webdavAutoUploadConfig";
|
||||
import { apiUrl } from "@/lib/common/webPath";
|
||||
import { DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY } from "@/lib/app/appFonts";
|
||||
import { DEFAULT_DATA_GRID_FONT_FAMILY, DEFAULT_UI_FONT_FAMILY, normalizeCustomFontFamilyInput, readableFontFamily, SYSTEM_UI_FONT_FAMILY } from "@/lib/app/appFonts";
|
||||
import { buildFontFamilyOptions, displayFontFamily, isPresetFontFamily, loadSystemFontNames } from "@/lib/app/fontFamilyOptions";
|
||||
import { buildAppSupportInfoRows, formatAppSupportInfoForClipboard, type AppSupportInfoLabels } from "@/lib/app/supportInfo";
|
||||
import { DateTimePatterns, normalizeSupportedDateTimePattern } from "@/lib/dataGrid/columnFormatter";
|
||||
import { MAX_RESULT_PAGE_SIZE, MIN_RESULT_PAGE_SIZE } from "@/lib/dataGrid/paginationPageSize";
|
||||
@@ -151,9 +150,6 @@ const appThemeModeOptions = computed(() => [
|
||||
{ value: "system" as AppThemeMode, label: t("toolbar.themeSystem"), icon: SunMoon },
|
||||
]);
|
||||
|
||||
let cachedSystemFonts: string[] | null = null;
|
||||
let pendingSystemFonts: Promise<string[]> | null = null;
|
||||
|
||||
const props = defineProps<{
|
||||
open?: boolean;
|
||||
variant?: "dialog" | "page";
|
||||
@@ -629,44 +625,20 @@ function confirmDeleteSnippet(snippet: SqlSnippet) {
|
||||
}
|
||||
}
|
||||
|
||||
const presetFontLabels = new Map(FONT_FAMILIES.map((font) => [font.value, font.label]));
|
||||
const presetFontValues = new Set(FONT_FAMILIES.map((font) => font.value));
|
||||
const uiFontPreviewValues = new Set([DEFAULT_UI_FONT_FAMILY, SYSTEM_UI_FONT_FAMILY]);
|
||||
|
||||
function cssFontFamilyForName(name: string): string {
|
||||
return `'${name.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}', monospace`;
|
||||
}
|
||||
|
||||
function readableFontFamily(value: string): string {
|
||||
const first = value.split(",")[0]?.trim() ?? value;
|
||||
return first.replace(/^['"]|['"]$/g, "").replace(/\\'/g, "'");
|
||||
}
|
||||
|
||||
function normalizeCustomFontFamilyInput(value: string): string {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return "";
|
||||
if (trimmed.includes(",") || trimmed.includes("'") || trimmed.includes('"')) return trimmed;
|
||||
return cssFontFamilyForName(trimmed);
|
||||
}
|
||||
|
||||
const systemFontOptions = computed(() => {
|
||||
const options = new Set(FONT_FAMILIES.map((font) => font.value));
|
||||
for (const font of systemFonts.value) options.add(cssFontFamilyForName(font));
|
||||
if (editFontFamily.value) options.add(editFontFamily.value);
|
||||
if (editTableFontFamily.value) options.add(editTableFontFamily.value);
|
||||
return [...options];
|
||||
return buildFontFamilyOptions(systemFonts.value, [editFontFamily.value]);
|
||||
});
|
||||
|
||||
const tableFontOptions = computed(() => buildFontFamilyOptions(systemFonts.value, [editTableFontFamily.value], [DEFAULT_DATA_GRID_FONT_FAMILY]));
|
||||
|
||||
const uiFontOptions = computed(() => {
|
||||
const options = new Set([SYSTEM_UI_FONT_FAMILY, DEFAULT_UI_FONT_FAMILY, ...systemFontOptions.value]);
|
||||
if (editUiFontFamily.value) options.add(editUiFontFamily.value);
|
||||
return [...options];
|
||||
});
|
||||
|
||||
function displayFontFamily(value: string): string {
|
||||
return presetFontLabels.get(value) ?? readableFontFamily(value);
|
||||
}
|
||||
|
||||
function displayUiFontFamily(value: string): string {
|
||||
if (value === SYSTEM_UI_FONT_FAMILY) return t("settings.uiFontSystemDefault");
|
||||
if (value === DEFAULT_UI_FONT_FAMILY) return t("settings.uiFontAppDefault");
|
||||
@@ -674,22 +646,14 @@ function displayUiFontFamily(value: string): string {
|
||||
}
|
||||
|
||||
function fontOptionStyle(value: string, selectedValue = editFontFamily.value) {
|
||||
return presetFontValues.has(value) || uiFontPreviewValues.has(value) || value === selectedValue ? { fontFamily: value } : undefined;
|
||||
return isPresetFontFamily(value) || uiFontPreviewValues.has(value) || value === selectedValue ? { fontFamily: value } : undefined;
|
||||
}
|
||||
|
||||
async function loadSystemFontOptions() {
|
||||
if (systemFontsLoaded.value || systemFontsLoading.value) return;
|
||||
systemFontsLoading.value = true;
|
||||
try {
|
||||
if (cachedSystemFonts) {
|
||||
systemFonts.value = cachedSystemFonts;
|
||||
} else {
|
||||
pendingSystemFonts ??= listSystemFonts().finally(() => {
|
||||
pendingSystemFonts = null;
|
||||
});
|
||||
cachedSystemFonts = await pendingSystemFonts;
|
||||
systemFonts.value = cachedSystemFonts;
|
||||
}
|
||||
systemFonts.value = await loadSystemFontNames();
|
||||
systemFontsLoaded.value = true;
|
||||
} catch {
|
||||
systemFonts.value = [];
|
||||
@@ -3571,7 +3535,7 @@ onUnmounted(cleanupPreviewEditor);
|
||||
</div>
|
||||
<SearchableSelect
|
||||
:model-value="editTableFontFamily"
|
||||
:options="systemFontOptions"
|
||||
:options="tableFontOptions"
|
||||
:placeholder="t('settings.selectFont')"
|
||||
:search-placeholder="t('settings.searchFont')"
|
||||
:empty-text="t('settings.noFontsFound')"
|
||||
@@ -3579,8 +3543,8 @@ onUnmounted(cleanupPreviewEditor);
|
||||
allow-custom
|
||||
:display-name="displayFontFamily"
|
||||
:normalize-custom="normalizeCustomFontFamilyInput"
|
||||
:trigger-class="appearanceFontSearchTriggerClass"
|
||||
:trigger-icon-class="appearanceFontSearchTriggerIconClass"
|
||||
trigger-variant="outline"
|
||||
trigger-class="h-9 w-full max-w-none justify-between"
|
||||
content-class="w-[var(--reka-popover-trigger-width)] min-w-[260px]"
|
||||
@update:model-value="onTableFontFamilyChange"
|
||||
@update:open="(open: boolean) => open && loadSystemFontOptions()"
|
||||
|
||||
@@ -3846,7 +3846,7 @@ const editorThemeAccessor = () => settingsStore.editorSettings.theme;
|
||||
const editorAppAppearance = () => (isDark.value ? "dark" : "light") as import("@/lib/app/appTheme").AppThemeAppearance;
|
||||
const editorAppPalette = () => themePalette.value;
|
||||
const editorFontSize = () => settingsStore.editorSettings.fontSize;
|
||||
const editorFontFamily = () => settingsStore.editorSettings.fontFamily;
|
||||
const detailEditorFontFamily = () => tableFontFamily.value;
|
||||
const SIDE_DETAIL_EDITOR_MIN_HEIGHT = 160;
|
||||
const SIDE_DETAIL_EDITOR_MAX_HEIGHT = 360;
|
||||
const SIDE_DETAIL_EDITOR_LINE_HEIGHT = 20;
|
||||
@@ -3874,7 +3874,7 @@ watch(valueEditorContainer, async (el) => {
|
||||
appAppearance: editorAppAppearance,
|
||||
appPalette: editorAppPalette,
|
||||
fontSize: editorFontSize,
|
||||
fontFamily: editorFontFamily,
|
||||
fontFamily: detailEditorFontFamily,
|
||||
});
|
||||
await valueDetailEditor.create(el, detailEditValue.value, activeCellDetail.value?.type);
|
||||
} else if (!el && valueDetailEditor) {
|
||||
@@ -4751,7 +4751,7 @@ function canvasCellContentOverflows(item: RowItem, actualColIdx: number, visible
|
||||
const displayText = formatCellCached(item.data[actualColIdx], actualColIdx);
|
||||
const editText = cellEditorTextForValue(item.data[actualColIdx], actualColIdx);
|
||||
if (editText.includes("\n") || editText.includes("\r") || editText.length > displayText.length) return true;
|
||||
const textWidth = measureCellTextWidth(displayText, `400 13px ${settingsStore.editorSettings.fontFamily}`);
|
||||
const textWidth = measureCellTextWidth(displayText, `400 ${tableFontSize.value}px ${tableFontFamily.value}`);
|
||||
return textWidth > Math.max(0, cellWidth - 24);
|
||||
}
|
||||
|
||||
@@ -7761,7 +7761,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
<div
|
||||
v-for="cell in item.values"
|
||||
:key="`${item.id}:${cell.recordIndex}`"
|
||||
class="relative flex shrink-0 items-center border-r border-border/70 px-2 py-0 font-mono truncate"
|
||||
class="relative flex shrink-0 items-center border-r border-border/70 px-2 py-0 truncate"
|
||||
:class="{
|
||||
'text-muted-foreground italic': cell.isNull,
|
||||
'cell-selected': transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
|
||||
@@ -9265,6 +9265,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
.data-grid-header-row,
|
||||
.data-grid-transpose-header,
|
||||
.data-grid-transpose-row {
|
||||
font-family: var(--dbx-data-grid-font-family);
|
||||
font-size: var(--dbx-table-font-size, 13px);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ const emit = defineEmits<{ apply: [] }>();
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
rows="5"
|
||||
class="min-h-24 w-full min-w-0 resize-y rounded-[6px] border border-input bg-transparent px-2.5 py-1.5 text-base outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 md:text-sm"
|
||||
class="dbx-data-grid-value-font min-h-24 w-full min-w-0 resize-y rounded-[6px] border border-input bg-transparent px-2.5 py-1.5 text-base outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 md:text-sm"
|
||||
:placeholder="t('grid.bulkEditValuePlaceholder')"
|
||||
@keydown.ctrl.enter.prevent="emit('apply')"
|
||||
@keydown.meta.enter.prevent="emit('apply')"
|
||||
|
||||
@@ -88,7 +88,7 @@ watch(jsonPreviewContainer, async (element) => {
|
||||
appAppearance: () => (isDark.value ? "dark" : "light"),
|
||||
appPalette: () => themePalette.value,
|
||||
fontSize: () => settingsStore.editorSettings.fontSize,
|
||||
fontFamily: () => settingsStore.editorSettings.fontFamily,
|
||||
fontFamily: () => settingsStore.editorSettings.tableFontFamily,
|
||||
});
|
||||
await jsonPreviewEditor.create(element, props.detail?.formattedJson ?? "", "json");
|
||||
} else if (!element && jsonPreviewEditor) {
|
||||
@@ -181,7 +181,7 @@ watch(
|
||||
<img :src="detail.imagePreviewUrl" :alt="detail.column" loading="lazy" decoding="async" referrerpolicy="no-referrer" class="max-h-72 w-full object-contain" />
|
||||
</a>
|
||||
<div v-if="jsonView && detail.formattedJson" ref="jsonPreviewContainer" data-cell-detail-editor-root class="h-[44vh] min-h-60 overflow-hidden rounded border bg-muted/20 p-3" />
|
||||
<pre v-else class="max-h-[44vh] overflow-auto rounded border bg-muted/20 p-3 font-mono text-xs whitespace-pre-wrap break-words" :class="{ 'italic text-muted-foreground': detail.value === null }">{{ detail.rawValuePreview }}</pre>
|
||||
<pre v-else class="dbx-data-grid-value-font max-h-[44vh] overflow-auto rounded border bg-muted/20 p-3 text-xs whitespace-pre-wrap break-words" :class="{ 'italic text-muted-foreground': detail.value === null }">{{ detail.rawValuePreview }}</pre>
|
||||
<div v-if="detail.isValuePreviewTruncated && !jsonView" class="text-[11px] text-muted-foreground">
|
||||
{{ t("grid.largeValuePreviewHint", { count: detail.rawValuePreview.length }) }}
|
||||
</div>
|
||||
|
||||
@@ -143,7 +143,7 @@ defineExpose({ openSearch });
|
||||
/></a>
|
||||
</div>
|
||||
<template v-if="editing"
|
||||
><div class="min-h-0 flex-1" :style="editorStyle">
|
||||
><div class="dbx-data-grid-value-font min-h-0 flex-1" :style="editorStyle">
|
||||
<TemporalCellEditor v-if="temporalEditorConfig" v-model="detailEditValue" :kind="temporalEditorConfig.kind" :fraction-precision="temporalEditorConfig.fractionPrecision" variant="inline" :commit-on-close="false" @cancel="emit('cancel')" @commit="emit('commit')" />
|
||||
<div v-else ref="detailsEditorContainer" data-cell-detail-editor-root class="min-h-0 h-full w-full rounded border overflow-hidden" />
|
||||
</div>
|
||||
@@ -162,7 +162,7 @@ defineExpose({ openSearch });
|
||||
/>
|
||||
<pre
|
||||
v-else
|
||||
class="overflow-auto rounded border bg-muted/20 p-2 font-mono text-xs whitespace-pre-wrap break-words cursor-pointer hover:border-primary/50"
|
||||
class="dbx-data-grid-value-font overflow-auto rounded border bg-muted/20 p-2 text-xs whitespace-pre-wrap break-words cursor-pointer hover:border-primary/50"
|
||||
:class="[{ 'cursor-text': detail.isEditable }, panelIsBottom && detail.imagePreviewUrl ? 'min-h-24 max-h-32 shrink-0' : '', valueFillsHeight && !detail.imagePreviewUrl ? 'min-h-0 flex-1' : '']"
|
||||
@dblclick="emit('startEdit')"
|
||||
>{{ detail.rawValuePreview }}</pre
|
||||
|
||||
@@ -65,11 +65,11 @@ const filteredColumnFields = computed(() => (props.columnDetail ? filterDataGrid
|
||||
<a v-if="field.imagePreviewUrl" :href="field.imagePreviewUrl" role="button" class="mb-2 block max-h-48 overflow-hidden rounded border bg-muted/20" @click.prevent="openImagePreview(field.imagePreviewUrl, field.column)"
|
||||
><img :src="field.imagePreviewUrl" :alt="field.column" loading="lazy" decoding="async" referrerpolicy="no-referrer" class="max-h-48 w-full object-contain"
|
||||
/></a>
|
||||
<pre class="max-h-44 overflow-auto rounded border bg-muted/20 p-2 font-mono text-xs whitespace-pre-wrap break-words" :class="{ 'italic text-muted-foreground': field.value === null }">{{ field.rawValuePreview }}</pre>
|
||||
<pre class="dbx-data-grid-value-font max-h-44 overflow-auto rounded border bg-muted/20 p-2 text-xs whitespace-pre-wrap break-words" :class="{ 'italic text-muted-foreground': field.value === null }">{{ field.rawValuePreview }}</pre>
|
||||
<div v-if="field.isValuePreviewTruncated" class="mt-1 text-[11px] text-muted-foreground">{{ t("grid.largeValuePreviewHint", { count: field.rawValuePreview.length }) }}</div>
|
||||
<div v-if="field.formattedJson" class="mt-2 space-y-1">
|
||||
<div class="text-muted-foreground">{{ t("grid.formattedJson") }}</div>
|
||||
<pre class="max-h-44 overflow-auto rounded border bg-muted/20 p-2 font-mono text-xs whitespace-pre-wrap break-words">{{ field.formattedJson }}</pre>
|
||||
<pre class="dbx-data-grid-value-font max-h-44 overflow-auto rounded border bg-muted/20 p-2 text-xs whitespace-pre-wrap break-words">{{ field.formattedJson }}</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-2 py-2">
|
||||
@@ -135,11 +135,11 @@ const filteredColumnFields = computed(() => (props.columnDetail ? filterDataGrid
|
||||
<a v-if="field.imagePreviewUrl" :href="field.imagePreviewUrl" role="button" class="mb-2 block max-h-40 overflow-hidden rounded border bg-muted/20" @click.prevent="openImagePreview(field.imagePreviewUrl, field.column)"
|
||||
><img :src="field.imagePreviewUrl" :alt="field.column" loading="lazy" decoding="async" referrerpolicy="no-referrer" class="max-h-40 w-full object-contain"
|
||||
/></a>
|
||||
<pre class="max-h-36 overflow-auto rounded border bg-muted/20 p-2 font-mono text-xs whitespace-pre-wrap break-words" :class="{ 'italic text-muted-foreground': field.value === null }">{{ field.rawValuePreview }}</pre>
|
||||
<pre class="dbx-data-grid-value-font max-h-36 overflow-auto rounded border bg-muted/20 p-2 text-xs whitespace-pre-wrap break-words" :class="{ 'italic text-muted-foreground': field.value === null }">{{ field.rawValuePreview }}</pre>
|
||||
<div v-if="field.isValuePreviewTruncated" class="mt-1 text-[11px] text-muted-foreground">{{ t("grid.largeValuePreviewHint", { count: field.rawValuePreview.length }) }}</div>
|
||||
<div v-if="field.formattedJson" class="mt-2 space-y-1">
|
||||
<div class="text-muted-foreground">{{ t("grid.formattedJson") }}</div>
|
||||
<pre class="max-h-36 overflow-auto rounded border bg-muted/20 p-2 font-mono text-xs whitespace-pre-wrap break-words">{{ field.formattedJson }}</pre>
|
||||
<pre class="dbx-data-grid-value-font max-h-36 overflow-auto rounded border bg-muted/20 p-2 text-xs whitespace-pre-wrap break-words">{{ field.formattedJson }}</pre>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-2 py-2">
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { SearchableSelect } from "@/components/ui/searchable-select";
|
||||
import { DEFAULT_DATA_GRID_FONT_FAMILY } from "@/lib/app/appFonts";
|
||||
import { buildFontFamilyOptions, displayFontFamily, loadSystemFontNames } from "@/lib/app/fontFamilyOptions";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
|
||||
const { t } = useI18n();
|
||||
const settingsStore = useSettingsStore();
|
||||
const systemFontNames = ref<string[]>([]);
|
||||
const tableFontFamily = computed(() => settingsStore.editorSettings.tableFontFamily);
|
||||
const tableFontOptions = computed(() => buildFontFamilyOptions(systemFontNames.value, [tableFontFamily.value], [DEFAULT_DATA_GRID_FONT_FAMILY]));
|
||||
|
||||
function setTableFontFamily(value: string) {
|
||||
settingsStore.updateEditorSettings({ tableFontFamily: value });
|
||||
}
|
||||
|
||||
async function loadSystemFontOptions() {
|
||||
try {
|
||||
systemFontNames.value = await loadSystemFontNames();
|
||||
} catch {
|
||||
systemFontNames.value = [];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs">
|
||||
<div class="min-w-0 flex items-center gap-2 font-medium">
|
||||
<span class="flex h-3.5 w-3.5 shrink-0 items-center justify-center text-[9px] font-semibold text-muted-foreground">Aa</span>
|
||||
<span>{{ t("grid.tableFontFamily") }}</span>
|
||||
</div>
|
||||
<SearchableSelect
|
||||
:model-value="tableFontFamily"
|
||||
:options="tableFontOptions"
|
||||
:placeholder="t('settings.selectFont')"
|
||||
:search-placeholder="t('settings.searchFont')"
|
||||
:empty-text="t('settings.noFontsFound')"
|
||||
:display-name="displayFontFamily"
|
||||
trigger-variant="outline"
|
||||
trigger-class="h-6 w-48 max-w-48 justify-between bg-muted/40 px-2 text-xs"
|
||||
content-class="w-64 max-w-[calc(100vw-2rem)]"
|
||||
@update:model-value="setTableFontFamily"
|
||||
@update:open="(open: boolean) => open && loadSystemFontOptions()"
|
||||
>
|
||||
<template #trigger-label="{ label }">
|
||||
<span class="truncate" :style="{ fontFamily: tableFontFamily }">{{ label }}</span>
|
||||
</template>
|
||||
<template #option-label="{ option, label }">
|
||||
<span class="truncate" :style="{ fontFamily: option }">{{ label }}</span>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
</div>
|
||||
</template>
|
||||
@@ -38,7 +38,7 @@ watch(previewContainer, async (element) => {
|
||||
appAppearance: () => (isDark.value ? "dark" : "light") as import("@/lib/app/appTheme").AppThemeAppearance,
|
||||
appPalette: () => themePalette.value,
|
||||
fontSize: () => settingsStore.editorSettings.fontSize,
|
||||
fontFamily: () => settingsStore.editorSettings.fontFamily,
|
||||
fontFamily: () => settingsStore.editorSettings.tableFontFamily,
|
||||
});
|
||||
await previewEditor.create(element, props.text, "json");
|
||||
} else if (!element && previewEditor) {
|
||||
@@ -65,7 +65,7 @@ watch(
|
||||
<div v-if="text" class="flex min-h-0 flex-1 flex-col overflow-hidden p-2">
|
||||
<div v-if="usesCodeEditor" ref="previewContainer" data-cell-detail-editor-root class="min-h-0 flex-1 overflow-hidden" />
|
||||
<template v-else>
|
||||
<pre class="min-h-0 flex-1 overflow-auto rounded border bg-muted/20 p-3 font-mono text-xs whitespace-pre-wrap break-words">{{ text }}</pre>
|
||||
<pre class="dbx-data-grid-value-font min-h-0 flex-1 overflow-auto rounded border bg-muted/20 p-3 text-xs whitespace-pre-wrap break-words">{{ text }}</pre>
|
||||
<div class="mt-1 text-[11px] text-muted-foreground">{{ t("grid.largeValuePreviewHint", { count: text.length }) }}</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,7 @@ import QueryLoadingState from "@/components/common/QueryLoadingState.vue";
|
||||
import QueryErrorActions from "@/components/common/QueryErrorActions.vue";
|
||||
import QueryResultToolbarActions from "@/components/layout/QueryResultToolbarActions.vue";
|
||||
import QueryResultViewSwitcher from "@/components/layout/QueryResultViewSwitcher.vue";
|
||||
import DataGridFontFamilyControl from "@/components/grid/DataGridFontFamilyControl.vue";
|
||||
import type { ColumnInfo } from "@/components/editor/ColumnInfoPanel.vue";
|
||||
let dataGridComponentPromise: Promise<typeof import("@/components/grid/DataGrid.vue")> | undefined;
|
||||
function loadDataGridComponent() {
|
||||
@@ -977,6 +978,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<DataGridFontFamilyControl />
|
||||
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs">
|
||||
<div class="min-w-0 flex items-center gap-2 font-medium">
|
||||
<span class="flex h-3.5 w-3.5 shrink-0 items-center justify-center text-[11px] font-semibold text-muted-foreground">A</span>
|
||||
@@ -1389,6 +1391,7 @@ defineExpose({ focusSearch, refreshData, refreshQueryEditorCompletionCache, hand
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<DataGridFontFamilyControl />
|
||||
<div class="flex items-center justify-between gap-3 px-3 py-1.5 text-xs">
|
||||
<div class="min-w-0 flex items-center gap-2 font-medium">
|
||||
<span class="flex h-3.5 w-3.5 shrink-0 items-center justify-center text-[11px] font-semibold text-muted-foreground">A</span>
|
||||
|
||||
Reference in new issue
Block a user