feat(sidebar): add indentation and font size settings
This commit is contained in:
1 parent
98df975614
commit
745483cd6c
16 files changed
+164
-13
No files matched your search
@@ -47,6 +47,10 @@ import {
|
||||
type CustomTheme,
|
||||
type ClickTableNavigationTarget,
|
||||
type SqlCompletionTriggerMode,
|
||||
SIDEBAR_INDENT_MIN,
|
||||
SIDEBAR_INDENT_MAX,
|
||||
SIDEBAR_FONT_SIZE_MIN,
|
||||
SIDEBAR_FONT_SIZE_MAX,
|
||||
} from "@/stores/settingsStore";
|
||||
import { createRunStatementButtonDom, loadEditorTheme, editorFontTheme } from "@/lib/editor/editorThemes";
|
||||
import { orderAiConfigsForDisplay } from "@/lib/ai/aiConfigOrdering";
|
||||
@@ -406,6 +410,8 @@ const editUpdateNotificationsEnabled = ref(settingsStore.editorSettings.updateNo
|
||||
const editSidebarHiddenTablePrefixes = ref(settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n"));
|
||||
const editSidebarObjectInfoMode = ref<SidebarObjectInfoMode>(settingsStore.editorSettings.sidebarObjectInfoMode);
|
||||
const editSidebarAllowHorizontalScroll = ref(settingsStore.editorSettings.sidebarAllowHorizontalScroll);
|
||||
const editSidebarIndent = ref(settingsStore.editorSettings.sidebarIndent);
|
||||
const editSidebarFontSize = ref(settingsStore.editorSettings.sidebarFontSize);
|
||||
const editExportBatchSize = ref(settingsStore.editorSettings.exportBatchSize);
|
||||
const editGlobalDateTimeDisplayFormat = ref(settingsStore.editorSettings.globalDateTimeDisplayFormat);
|
||||
const editGlobalDateTimeExportFormat = ref(settingsStore.editorSettings.globalDateTimeExportFormat);
|
||||
@@ -526,6 +532,8 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
|
||||
updateNotificationsEnabled: editUpdateNotificationsEnabled.value,
|
||||
sidebarObjectInfoMode: editSidebarObjectInfoMode.value,
|
||||
sidebarAllowHorizontalScroll: editSidebarAllowHorizontalScroll.value,
|
||||
sidebarIndent: editSidebarIndent.value,
|
||||
sidebarFontSize: editSidebarFontSize.value,
|
||||
sidebarHiddenTablePrefixes: normalizeSidebarHiddenTablePrefixes(editSidebarHiddenTablePrefixes.value),
|
||||
exportBatchSize: editExportBatchSize.value,
|
||||
globalDateTimeDisplayFormat: editGlobalDateTimeDisplayFormat.value,
|
||||
@@ -808,6 +816,8 @@ function syncEditorSettingsDraftFromStore() {
|
||||
editSidebarHiddenTablePrefixes.value = settingsStore.editorSettings.sidebarHiddenTablePrefixes.join("\n");
|
||||
editSidebarObjectInfoMode.value = settingsStore.editorSettings.sidebarObjectInfoMode;
|
||||
editSidebarAllowHorizontalScroll.value = settingsStore.editorSettings.sidebarAllowHorizontalScroll;
|
||||
editSidebarIndent.value = settingsStore.editorSettings.sidebarIndent;
|
||||
editSidebarFontSize.value = settingsStore.editorSettings.sidebarFontSize;
|
||||
editExportBatchSize.value = settingsStore.editorSettings.exportBatchSize;
|
||||
editGlobalDateTimeDisplayFormat.value = settingsStore.editorSettings.globalDateTimeDisplayFormat;
|
||||
editGlobalDateTimeExportFormat.value = settingsStore.editorSettings.globalDateTimeExportFormat;
|
||||
@@ -1023,6 +1033,8 @@ function resetDefaultsForTab(tab: SettingsCategory) {
|
||||
editUpdateNotificationsEnabled.value = DEFAULT_EDITOR_SETTINGS.updateNotificationsEnabled;
|
||||
editSidebarObjectInfoMode.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectInfoMode;
|
||||
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
|
||||
editSidebarIndent.value = DEFAULT_EDITOR_SETTINGS.sidebarIndent;
|
||||
editSidebarFontSize.value = DEFAULT_EDITOR_SETTINGS.sidebarFontSize;
|
||||
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
|
||||
editToolbarItems.value = { ...DEFAULT_EDITOR_SETTINGS.toolbarItems };
|
||||
} else if (tab === "data") {
|
||||
@@ -1132,6 +1144,8 @@ function resetAllDefaults() {
|
||||
editUpdateNotificationsEnabled.value = DEFAULT_EDITOR_SETTINGS.updateNotificationsEnabled;
|
||||
editSidebarObjectInfoMode.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectInfoMode;
|
||||
editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll;
|
||||
editSidebarIndent.value = DEFAULT_EDITOR_SETTINGS.sidebarIndent;
|
||||
editSidebarFontSize.value = DEFAULT_EDITOR_SETTINGS.sidebarFontSize;
|
||||
editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n");
|
||||
editExportBatchSize.value = DEFAULT_EDITOR_SETTINGS.exportBatchSize;
|
||||
editGlobalDateTimeDisplayFormat.value = DEFAULT_EDITOR_SETTINGS.globalDateTimeDisplayFormat;
|
||||
@@ -4751,6 +4765,52 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<Switch id="sidebar-allow-horizontal-scroll" v-model="editSidebarAllowHorizontalScroll" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="space-y-1">
|
||||
<Label for="sidebar-indent">{{ t("settings.sidebarIndent") }}</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t("settings.sidebarIndentDescription") }}
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
id="sidebar-indent"
|
||||
type="number"
|
||||
class="w-24 text-right"
|
||||
:min="SIDEBAR_INDENT_MIN"
|
||||
:max="SIDEBAR_INDENT_MAX"
|
||||
:step="2"
|
||||
:model-value="editSidebarIndent"
|
||||
@update:model-value="
|
||||
(value: string | number) => {
|
||||
const n = typeof value === 'string' ? parseInt(value) : value;
|
||||
if (!isNaN(n)) editSidebarIndent = n;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<div class="space-y-1">
|
||||
<Label for="sidebar-font-size">{{ t("settings.sidebarFontSize") }}</Label>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t("settings.sidebarFontSizeDescription") }}
|
||||
</p>
|
||||
</div>
|
||||
<Input
|
||||
id="sidebar-font-size"
|
||||
type="number"
|
||||
class="w-24 text-right"
|
||||
:min="SIDEBAR_FONT_SIZE_MIN"
|
||||
:max="SIDEBAR_FONT_SIZE_MAX"
|
||||
:step="1"
|
||||
:model-value="editSidebarFontSize"
|
||||
@update:model-value="
|
||||
(value: string | number) => {
|
||||
const n = typeof value === 'string' ? parseInt(value) : value;
|
||||
if (!isNaN(n)) editSidebarFontSize = n;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="sidebar-hidden-table-prefixes">{{ t("settings.sidebarHiddenTablePrefixes") }}</Label>
|
||||
<textarea
|
||||
|
||||
@@ -82,6 +82,7 @@ const showConnectedConnectionsOnly = ref(false);
|
||||
const isDisconnectingAllActiveConnections = ref(false);
|
||||
const searchInputRef = ref<HTMLInputElement>();
|
||||
const rootRef = ref<HTMLElement>();
|
||||
const sidebarRootStyle = computed<Record<string, string>>(() => ({ fontSize: `${settingsStore.editorSettings.sidebarFontSize}px` }));
|
||||
const pointerInsideTree = ref(false);
|
||||
const treeScrollerRef = ref<InstanceType<typeof RecycleScroller> | null>(null);
|
||||
const plainTreeScrollerRef = ref<HTMLElement | null>(null);
|
||||
@@ -691,7 +692,7 @@ function measureSidebarTreeContentWidth() {
|
||||
if (!context) return;
|
||||
const style = window.getComputedStyle(rootRef.value);
|
||||
context.font = style.font || `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;
|
||||
sidebarTreeContentWidth.value = sidebarTreeNaturalContentWidth(sidebarTreeNaturalWidthItems.value, (text) => context.measureText(text).width);
|
||||
sidebarTreeContentWidth.value = sidebarTreeNaturalContentWidth(sidebarTreeNaturalWidthItems.value, (text) => context.measureText(text).width, settingsStore.editorSettings.sidebarIndent);
|
||||
void nextTick(scheduleSidebarScrollMetricsUpdate);
|
||||
}
|
||||
|
||||
@@ -705,7 +706,15 @@ function scheduleSidebarTreeContentWidthMeasure() {
|
||||
}
|
||||
|
||||
watch(
|
||||
[flatNodes, () => settingsStore.editorSettings.sidebarObjectInfoMode, () => settingsStore.editorSettings.sidebarShowConnectionNotes, () => settingsStore.editorSettings.sidebarHiddenTablePrefixes, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale],
|
||||
[
|
||||
flatNodes,
|
||||
() => settingsStore.editorSettings.sidebarObjectInfoMode,
|
||||
() => settingsStore.editorSettings.sidebarShowConnectionNotes,
|
||||
() => settingsStore.editorSettings.sidebarHiddenTablePrefixes,
|
||||
() => settingsStore.editorSettings.uiFontFamily,
|
||||
() => settingsStore.editorSettings.uiScale,
|
||||
() => settingsStore.editorSettings.sidebarFontSize,
|
||||
],
|
||||
scheduleSidebarCommentLabelMeasure,
|
||||
{
|
||||
flush: "post",
|
||||
@@ -713,7 +722,7 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
watch([sidebarTreeNaturalWidthItems, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale], scheduleSidebarTreeContentWidthMeasure, {
|
||||
watch([sidebarTreeNaturalWidthItems, () => settingsStore.editorSettings.uiFontFamily, () => settingsStore.editorSettings.uiScale, () => settingsStore.editorSettings.sidebarIndent, () => settingsStore.editorSettings.sidebarFontSize], scheduleSidebarTreeContentWidthMeasure, {
|
||||
flush: "post",
|
||||
immediate: true,
|
||||
});
|
||||
@@ -1988,7 +1997,7 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="rootRef" class="h-full min-h-0 flex flex-col text-sm select-none" @pointerenter="pointerInsideTree = true" @pointerleave="pointerInsideTree = false">
|
||||
<div ref="rootRef" class="h-full min-h-0 flex flex-col select-none" :style="sidebarRootStyle" @pointerenter="pointerInsideTree = true" @pointerleave="pointerInsideTree = false">
|
||||
<SidebarTreeRuntimeHost
|
||||
:ref="bindSidebarTreeRuntimeHost"
|
||||
:node="sidebarTreeRuntimeInitialNode"
|
||||
|
||||
@@ -742,7 +742,7 @@ const labelWidthClass = computed(() => {
|
||||
|
||||
watch(() => [isRightAlignedComment(), visibleLabel(activeNode.value), trailingComment.value, trailingCommentLayoutRef.value, trailingCommentLeadingRef.value], refreshTrailingCommentMeasurement, { flush: "post", immediate: true });
|
||||
|
||||
const paddingLeft = computed(() => treeItemPaddingLeft(props.depth));
|
||||
const paddingLeft = computed(() => treeItemPaddingLeft(props.depth, settingsStore.editorSettings.sidebarIndent));
|
||||
|
||||
const tableSearchParentId = computed(() => activeNode.value.tableSearchParentId || "");
|
||||
|
||||
@@ -1424,8 +1424,9 @@ function onKeydown(event: KeyboardEvent) {
|
||||
<style>
|
||||
.sidebar-object-comment {
|
||||
color: var(--muted-foreground);
|
||||
font-size: 12px;
|
||||
line-height: 1rem;
|
||||
/* Relative to the sidebar tree root font size so comments follow the sidebarFontSize setting. */
|
||||
font-size: 0.85em;
|
||||
line-height: 1.25;
|
||||
opacity: 0.6;
|
||||
/* Sidebar rows repaint on hover; avoid heavier font shaping and fallback here. */
|
||||
text-rendering: auto;
|
||||
@@ -1439,7 +1440,7 @@ function onKeydown(event: KeyboardEvent) {
|
||||
|
||||
.sidebar-object-comment--windows {
|
||||
font-family: "Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI", system-ui, sans-serif;
|
||||
font-size: 14px;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -5838,6 +5838,10 @@ export default {
|
||||
sidebarObjectInfoModeHidden: "None",
|
||||
sidebarAllowHorizontalScroll: "Allow sidebar horizontal scroll",
|
||||
sidebarAllowHorizontalScrollDescription: "Show long table, view, and collection names in full by allowing horizontal sidebar scrolling.",
|
||||
sidebarIndent: "Sidebar indentation",
|
||||
sidebarIndentDescription: "Horizontal offset added per tree depth level, in pixels.",
|
||||
sidebarFontSize: "Sidebar font size",
|
||||
sidebarFontSizeDescription: "Font size for the sidebar object tree, in pixels. Independent of the editor font size.",
|
||||
snippetsDescription: "Customize SQL snippet templates triggered in the editor.",
|
||||
snippetsAdd: "Add Snippet",
|
||||
snippetsLabel: "Label",
|
||||
|
||||
@@ -5988,6 +5988,10 @@ export default withEnglishFallback({
|
||||
syncSnippetMigrateLegacyCleanupRequired: "Se creó el fragmento cifrado, pero no se pudo eliminar el fragmento heredado {id}. Elimínelo manualmente y rote las credenciales que podrían haberse expuesto.",
|
||||
syncSnippetRetryLegacyCleanup: "Reintentar limpieza heredada",
|
||||
syncSnippetLegacyCleanupSuccess: "Se eliminó el fragmento heredado de texto sin formato {id}.",
|
||||
sidebarIndent: "Sangría de la barra lateral",
|
||||
sidebarIndentDescription: "Desplazamiento en píxeles de la sangría para cada nivel del árbol.",
|
||||
sidebarFontSize: "Tamaño de fuente de la barra lateral",
|
||||
sidebarFontSizeDescription: "Tamaño de fuente (en píxeles) del árbol de objetos de la barra lateral, independiente del tamaño de fuente del editor.",
|
||||
},
|
||||
driverStore: {
|
||||
jreDirRemoveFailed: "No se pudo eliminar el directorio JRE antiguo: {path} (error original: {error})",
|
||||
|
||||
@@ -5988,6 +5988,10 @@ export default withEnglishFallback({
|
||||
syncSnippetMigrateLegacyCleanupRequired: "Lo snippet crittografato è stato creato, ma non è stato possibile eliminare lo snippet legacy {id}. Eliminalo manualmente e ruota le credenziali che potrebbero essere state esposte.",
|
||||
syncSnippetRetryLegacyCleanup: "Riprova pulizia legacy",
|
||||
syncSnippetLegacyCleanupSuccess: "Lo snippet legacy in testo semplice {id} è stato eliminato.",
|
||||
sidebarIndent: "Indentazione della barra laterale",
|
||||
sidebarIndentDescription: "Offset in pixel per l'indentazione di ogni livello dell'albero.",
|
||||
sidebarFontSize: "Dimensione del carattere della barra laterale",
|
||||
sidebarFontSizeDescription: "Dimensione del carattere (in pixel) per l'albero degli oggetti della barra laterale, indipendente dalla dimensione del carattere dell'editor.",
|
||||
},
|
||||
driverStore: {
|
||||
jreDirRemoveFailed: "Impossibile rimuovere la vecchia directory JRE: {path} (errore originale: {error})",
|
||||
|
||||
@@ -6041,6 +6041,10 @@ export default withEnglishFallback({
|
||||
completionTriggerModeManual: "手動のみ",
|
||||
completionTriggerModeRequirePrefix: "識別子入力後",
|
||||
completionTriggerModePositional: "スマート位置",
|
||||
sidebarIndent: "サイドバーのインデント",
|
||||
sidebarIndentDescription: "各ツリー階層のインデントのピクセルオフセット。",
|
||||
sidebarFontSize: "サイドバーのフォントサイズ",
|
||||
sidebarFontSizeDescription: "サイドバーのオブジェクトツリーのフォントサイズ(ピクセル)。エディターのフォントサイズとは独立しています。",
|
||||
},
|
||||
driverStore: {
|
||||
jreDirRemoveFailed: "古い JRE ディレクトリを削除できませんでした: {path}(元のエラー: {error})",
|
||||
|
||||
@@ -5990,6 +5990,10 @@ export default withEnglishFallback({
|
||||
syncSnippetMigrateLegacyCleanupRequired: "O snippet criptografado foi criado, mas não foi possível excluir o snippet legado {id}. Exclua-o manualmente e altere as credenciais que possam ter sido expostas.",
|
||||
syncSnippetRetryLegacyCleanup: "Tentar limpeza legada novamente",
|
||||
syncSnippetLegacyCleanupSuccess: "O snippet legado em texto simples {id} foi removido.",
|
||||
sidebarIndent: "Indentação da barra lateral",
|
||||
sidebarIndentDescription: "O deslocamento em pixels da indentação para cada nível da árvore.",
|
||||
sidebarFontSize: "Tamanho da fonte da barra lateral",
|
||||
sidebarFontSizeDescription: "Tamanho da fonte (em pixels) da árvore de objetos da barra lateral, independente do tamanho da fonte do editor.",
|
||||
},
|
||||
driverStore: {
|
||||
jreDirRemoveFailed: "Não foi possível remover o diretório JRE antigo: {path} (erro original: {error})",
|
||||
|
||||
@@ -5824,6 +5824,10 @@ export default withEnglishFallback({
|
||||
sidebarObjectInfoModeHidden: "不显示",
|
||||
sidebarAllowHorizontalScroll: "允许侧边栏横向滚动",
|
||||
sidebarAllowHorizontalScrollDescription: "完整显示较长的表、视图和集合名称;默认关闭以保留省略号截断。",
|
||||
sidebarIndent: "侧边栏缩进",
|
||||
sidebarIndentDescription: "每个树层级缩进的像素偏移量。",
|
||||
sidebarFontSize: "侧边栏字体大小",
|
||||
sidebarFontSizeDescription: "侧边栏对象树的字体大小(像素),独立于编辑器字体大小。",
|
||||
snippetsDescription: "自定义编辑器中触发的 SQL 代码片段模板。",
|
||||
snippetsAdd: "添加片段",
|
||||
snippetsLabel: "显示名",
|
||||
|
||||
@@ -5328,6 +5328,10 @@ export default withEnglishFallback({
|
||||
syncSnippetMigrateLegacyCleanupRequired: "已建立加密程式碼片段,但無法刪除舊程式碼片段 {id}。請手動刪除它,並輪換可能已暴露的憑據。",
|
||||
syncSnippetRetryLegacyCleanup: "重試清理舊版程式碼片段",
|
||||
syncSnippetLegacyCleanupSuccess: "已刪除舊版純文字程式碼片段 {id}。",
|
||||
sidebarIndent: "側邊欄縮排",
|
||||
sidebarIndentDescription: "每個樹層級縮排的像素位移量。",
|
||||
sidebarFontSize: "側邊欄字型大小",
|
||||
sidebarFontSizeDescription: "側邊欄物件樹的字型大小(像素),獨立於編輯器字型大小。",
|
||||
},
|
||||
driverStore: {
|
||||
jreDirRemoveFailed: "無法刪除舊的 JRE 目錄:{path}(原始錯誤:{error})",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { alignedCommentLeadingWidth, alignedSidebarCommentLabelWidths, canTreeNodeShowExpander, sidebarTreeNaturalContentWidth, sidebarTreeNodeComment, trailingCommentAvailableWidth, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { alignedCommentLeadingWidth, alignedSidebarCommentLabelWidths, canTreeNodeShowExpander, sidebarTreeNaturalContentWidth, sidebarTreeNodeComment, trailingCommentAvailableWidth, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import type { TreeNode } from "@/types/database";
|
||||
|
||||
describe("sidebar tree item layout", () => {
|
||||
@@ -91,4 +91,16 @@ describe("sidebar tree item layout", () => {
|
||||
it("returns zero when no tree row uses natural width", () => {
|
||||
expect(sidebarTreeNaturalContentWidth([{ depth: 2, label: "commented", usesNaturalWidth: false }], (text) => text.length * 7)).toBe(0);
|
||||
});
|
||||
|
||||
it("applies a configurable per-depth indent to rows and natural-width measurement", () => {
|
||||
// Default keeps the historical 16px per level.
|
||||
expect(treeItemPaddingLeft(2)).toBe("40px");
|
||||
expect(treeItemPaddingLeft(2, 24)).toBe("56px");
|
||||
expect(treeItemPaddingLeft(0, 24)).toBe("8px");
|
||||
|
||||
const items = [{ depth: 4, label: "nested", usesNaturalWidth: true, trailingWidth: 20 }];
|
||||
const measure = (text: string) => text.length * 7;
|
||||
expect(sidebarTreeNaturalContentWidth(items, measure, 16)).toBe(4 * 16 + 8 + 54 + "nested".length * 7 + 20);
|
||||
expect(sidebarTreeNaturalContentWidth(items, measure, 32)).toBe(4 * 32 + 8 + 54 + "nested".length * 7 + 20);
|
||||
});
|
||||
});
|
||||
@@ -63,6 +63,8 @@ export const EDITOR_SETTINGS_DRAFT_KEYS = [
|
||||
"updateNotificationsEnabled",
|
||||
"sidebarObjectInfoMode",
|
||||
"sidebarAllowHorizontalScroll",
|
||||
"sidebarIndent",
|
||||
"sidebarFontSize",
|
||||
"sidebarHiddenTablePrefixes",
|
||||
"exportBatchSize",
|
||||
"exportRowLimitEnabled",
|
||||
|
||||
@@ -167,6 +167,8 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] =
|
||||
{ id: "navigation-open-database-on-single-click", category: "navigation", titleKey: "settings.sidebarOpenDatabaseOnSingleClick", descriptionKey: "settings.sidebarOpenDatabaseOnSingleClickDescription", targetId: "navigation" },
|
||||
{ id: "navigation-tabs-restore", category: "navigation", titleKey: "settings.openTabsRestoreMode", descriptionKey: "settings.openTabsRestoreModeDescription", targetId: "navigation" },
|
||||
{ id: "navigation-sidebar-scroll", category: "navigation", titleKey: "settings.sidebarAllowHorizontalScroll", descriptionKey: "settings.sidebarAllowHorizontalScrollDescription", targetId: "navigation" },
|
||||
{ id: "navigation-sidebar-indent", category: "navigation", titleKey: "settings.sidebarIndent", descriptionKey: "settings.sidebarIndentDescription", targetId: "navigation" },
|
||||
{ id: "navigation-sidebar-font-size", category: "navigation", titleKey: "settings.sidebarFontSize", descriptionKey: "settings.sidebarFontSizeDescription", targetId: "navigation" },
|
||||
{ id: "navigation-hidden-tables", category: "navigation", titleKey: "settings.sidebarHiddenTablePrefixes", descriptionKey: "settings.sidebarHiddenTablePrefixesDescription", targetId: "navigation" },
|
||||
{ id: "navigation-table-page-size", category: "navigation", titleKey: "settings.sidebarTablePageSize", descriptionKey: "settings.sidebarTablePageSizeDescription", targetId: "navigation" },
|
||||
{ id: "navigation-disconnect-tabs", category: "navigation", titleKey: "settings.disconnectTabHandlingMode", descriptionKey: "settings.disconnectTabHandlingModeDescription", targetId: "navigation" },
|
||||
|
||||
@@ -63,8 +63,10 @@ const pinnableTypes: Set<TreeNodeType> = new Set([
|
||||
|
||||
const commentTypes: Set<TreeNodeType> = new Set(["connection", "schema", "table", "view", "materialized_view", "column", "mongo-collection", "vector-collection", "elasticsearch-index"]);
|
||||
|
||||
export function treeItemPaddingLeft(depth: number): string {
|
||||
return `${depth * 16 + 8}px`;
|
||||
export const SIDEBAR_INDENT_DEFAULT_PX = 16;
|
||||
|
||||
export function treeItemPaddingLeft(depth: number, indentPx = SIDEBAR_INDENT_DEFAULT_PX): string {
|
||||
return `${depth * indentPx + 8}px`;
|
||||
}
|
||||
|
||||
export const trailingCommentGapPx = 8;
|
||||
@@ -97,11 +99,11 @@ export interface SidebarTreeNaturalWidthItem {
|
||||
// Right padding, expander/icon widths and the two flex gaps before the label.
|
||||
const sidebarTreeRowChromeWidth = 54;
|
||||
|
||||
export function sidebarTreeNaturalContentWidth(items: readonly SidebarTreeNaturalWidthItem[], measureText: (text: string) => number): number {
|
||||
export function sidebarTreeNaturalContentWidth(items: readonly SidebarTreeNaturalWidthItem[], measureText: (text: string) => number, indentPx = SIDEBAR_INDENT_DEFAULT_PX): number {
|
||||
let width = 0;
|
||||
for (const item of items) {
|
||||
if (!item.usesNaturalWidth) continue;
|
||||
const paddingLeft = item.depth * 16 + 8;
|
||||
const paddingLeft = item.depth * indentPx + 8;
|
||||
width = Math.max(width, Math.ceil(paddingLeft + sidebarTreeRowChromeWidth + measureText(item.label) + (item.trailingWidth ?? 0)));
|
||||
}
|
||||
return width;
|
||||
|
||||
@@ -43,6 +43,17 @@ describe("normalizeEditorSettings", () => {
|
||||
expect(normalizeEditorSettings({ regexMaxMatchCount: Number.POSITIVE_INFINITY }).regexMaxMatchCount).toBe(1000);
|
||||
expect(normalizeEditorSettings({ regexMaxMatchCount: Number.NaN }).regexMaxMatchCount).toBe(1000);
|
||||
});
|
||||
it("defaults and bounds the sidebar indent and font size", () => {
|
||||
expect(normalizeEditorSettings({}).sidebarIndent).toBe(16);
|
||||
expect(normalizeEditorSettings({}).sidebarFontSize).toBe(14);
|
||||
expect(normalizeEditorSettings({ sidebarIndent: 24, sidebarFontSize: 18 }).sidebarIndent).toBe(24);
|
||||
expect(normalizeEditorSettings({ sidebarIndent: 24, sidebarFontSize: 18 }).sidebarFontSize).toBe(18);
|
||||
expect(normalizeEditorSettings({ sidebarIndent: 999, sidebarFontSize: 1 } as any).sidebarIndent).toBe(32);
|
||||
expect(normalizeEditorSettings({ sidebarIndent: 999, sidebarFontSize: 1 } as any).sidebarFontSize).toBe(9);
|
||||
expect(normalizeEditorSettings({ sidebarIndent: 1.4, sidebarFontSize: 13.6 } as any).sidebarIndent).toBe(4);
|
||||
expect(normalizeEditorSettings({ sidebarIndent: 1.4, sidebarFontSize: 13.6 } as any).sidebarFontSize).toBe(14);
|
||||
});
|
||||
|
||||
it("uses inline comments by default and preserves legacy comment visibility", () => {
|
||||
expect(normalizeEditorSettings({}).sidebarObjectInfoMode).toBe("comment-inline");
|
||||
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-aligned" }).sidebarObjectInfoMode).toBe("comment-aligned");
|
||||
|
||||
@@ -418,6 +418,12 @@ export type ResultRunDisplayMode = (typeof RESULT_RUN_DISPLAY_MODES)[number];
|
||||
export const TABLE_FONT_SIZE_MIN = 8;
|
||||
export const TABLE_FONT_SIZE_MAX = 16;
|
||||
export const TABLE_FONT_SIZE_DEFAULT = 13;
|
||||
export const SIDEBAR_FONT_SIZE_MIN = 9;
|
||||
export const SIDEBAR_FONT_SIZE_MAX = 24;
|
||||
export const SIDEBAR_FONT_SIZE_DEFAULT = 14;
|
||||
export const SIDEBAR_INDENT_MIN = 4;
|
||||
export const SIDEBAR_INDENT_MAX = 32;
|
||||
export const SIDEBAR_INDENT_DEFAULT = 16;
|
||||
const DISCONNECT_TAB_HANDLING_MODES = ["close-tabs", "keep-tabs-clear-results", "keep-tabs-keep-results"] as const;
|
||||
export type DisconnectTabHandlingMode = (typeof DISCONNECT_TAB_HANDLING_MODES)[number];
|
||||
|
||||
@@ -587,6 +593,8 @@ export interface EditorSettings {
|
||||
sidebarObjectInfoMode: SidebarObjectInfoMode;
|
||||
sidebarShowConnectionNotes: boolean;
|
||||
sidebarAllowHorizontalScroll: boolean;
|
||||
sidebarIndent: number;
|
||||
sidebarFontSize: number;
|
||||
columnFormatters: Record<string, ColumnFormatterConfig>;
|
||||
customColumnFormatters: Record<string, CustomColumnFormatterConfig>;
|
||||
globalDateTimeDisplayFormat: string;
|
||||
@@ -786,6 +794,8 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
|
||||
sidebarObjectInfoMode: "comment-inline",
|
||||
sidebarShowConnectionNotes: false,
|
||||
sidebarAllowHorizontalScroll: false,
|
||||
sidebarIndent: SIDEBAR_INDENT_DEFAULT,
|
||||
sidebarFontSize: SIDEBAR_FONT_SIZE_DEFAULT,
|
||||
columnFormatters: {},
|
||||
customColumnFormatters: {},
|
||||
globalDateTimeDisplayFormat: "",
|
||||
@@ -872,6 +882,16 @@ function normalizeTableFontSize(value: unknown): number {
|
||||
return Math.min(TABLE_FONT_SIZE_MAX, Math.max(TABLE_FONT_SIZE_MIN, Math.round(value)));
|
||||
}
|
||||
|
||||
function normalizeSidebarFontSize(value: unknown): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) return SIDEBAR_FONT_SIZE_DEFAULT;
|
||||
return Math.min(SIDEBAR_FONT_SIZE_MAX, Math.max(SIDEBAR_FONT_SIZE_MIN, Math.round(value)));
|
||||
}
|
||||
|
||||
function normalizeSidebarIndent(value: unknown): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) return SIDEBAR_INDENT_DEFAULT;
|
||||
return Math.min(SIDEBAR_INDENT_MAX, Math.max(SIDEBAR_INDENT_MIN, Math.round(value)));
|
||||
}
|
||||
|
||||
function normalizeUpdateDownloadSource(value: unknown): UpdateDownloadSource {
|
||||
// Preserve the intent of users who previously selected the mainland-China mirror.
|
||||
if (value === "atomgit") return "cnb";
|
||||
@@ -1168,6 +1188,8 @@ export function normalizeEditorSettings(settings: Partial<EditorSettings>, exist
|
||||
),
|
||||
sidebarShowConnectionNotes: settings.sidebarShowConnectionNotes === true,
|
||||
sidebarAllowHorizontalScroll: settings.sidebarAllowHorizontalScroll ?? DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll,
|
||||
sidebarIndent: normalizeSidebarIndent(settings.sidebarIndent),
|
||||
sidebarFontSize: normalizeSidebarFontSize(settings.sidebarFontSize),
|
||||
columnFormatters: normalizeColumnFormatters(settings.columnFormatters),
|
||||
customColumnFormatters: normalizeCustomColumnFormatters(settings.customColumnFormatters),
|
||||
globalDateTimeDisplayFormat: normalizeGlobalDateTimePattern(settings.globalDateTimeDisplayFormat),
|
||||
@@ -1712,6 +1734,8 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
if (partial.sidebarObjectInfoMode !== undefined) editorSettings.value.sidebarObjectInfoMode = normalizeSidebarObjectInfoMode(partial.sidebarObjectInfoMode);
|
||||
if (partial.sidebarShowConnectionNotes !== undefined) editorSettings.value.sidebarShowConnectionNotes = partial.sidebarShowConnectionNotes === true;
|
||||
if (partial.sidebarAllowHorizontalScroll !== undefined) editorSettings.value.sidebarAllowHorizontalScroll = partial.sidebarAllowHorizontalScroll;
|
||||
if (partial.sidebarIndent !== undefined) editorSettings.value.sidebarIndent = normalizeSidebarIndent(partial.sidebarIndent);
|
||||
if (partial.sidebarFontSize !== undefined) editorSettings.value.sidebarFontSize = normalizeSidebarFontSize(partial.sidebarFontSize);
|
||||
if (partial.columnFormatters !== undefined) editorSettings.value.columnFormatters = partial.columnFormatters;
|
||||
if (partial.customColumnFormatters !== undefined) editorSettings.value.customColumnFormatters = partial.customColumnFormatters;
|
||||
if (partial.globalDateTimeDisplayFormat !== undefined) editorSettings.value.globalDateTimeDisplayFormat = normalizeGlobalDateTimePattern(partial.globalDateTimeDisplayFormat);
|
||||
|
||||
Reference in new issue
Block a user