feat(sidebar): add right-aligned comment display
This commit is contained in:
parent
857a3acb90
commit
9f42f478bf
|
|
@ -4105,6 +4105,7 @@ onUnmounted(cleanupPreviewEditor);
|
|||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="comment-aligned">{{ t("settings.sidebarObjectInfoModeCommentAligned") }}</SelectItem>
|
||||
<SelectItem value="comment-right">{{ t("settings.sidebarObjectInfoModeCommentRight") }}</SelectItem>
|
||||
<SelectItem value="comment-inline">{{ t("settings.sidebarObjectInfoModeCommentInline") }}</SelectItem>
|
||||
<SelectItem value="size">{{ t("settings.sidebarObjectInfoModeSize") }}</SelectItem>
|
||||
<SelectItem value="hidden">{{ t("settings.sidebarObjectInfoModeHidden") }}</SelectItem>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ import { Badge } from "@/components/ui/badge";
|
|||
import { Input } from "@/components/ui/input";
|
||||
import LightTooltip from "@/components/ui/LightTooltip.vue";
|
||||
import type { ColumnInfo, ConnectionConfig, DatabaseType, TreeNode, TreeNodeType } from "@/types/database";
|
||||
import { canTreeNodeShowExpander, sidebarTreeNodeComment, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { canTreeNodeShowExpander, sidebarTreeNodeComment, trailingCommentAvailableWidth, trailingCommentGapPx, treeItemPaddingLeft, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { clearActiveTableReferencePayload, createTableReferencePayload, createTableReferenceDropEvent, setActiveTableReferencePayload, type QueryEditorTableReferencePayload } from "@/lib/editor/queryEditorTableDrop";
|
||||
import { formatSidebarObjectStorage } from "@/lib/sidebar/sidebarDatabaseStorage";
|
||||
import { dataTabOpenModeFromTreeClick } from "@/lib/sidebar/dataTabOpenPolicy";
|
||||
|
|
@ -69,12 +69,22 @@ const labelRef = ref<HTMLElement>();
|
|||
|
||||
const rowRef = ref<HTMLElement>();
|
||||
|
||||
const trailingCommentLayoutRef = ref<HTMLElement>();
|
||||
|
||||
const trailingCommentLeadingRef = ref<HTMLElement>();
|
||||
|
||||
const trailingCommentMaxWidth = ref(0);
|
||||
|
||||
const labelOverflowing = ref(false);
|
||||
|
||||
let labelResizeObserver: ResizeObserver | null = null;
|
||||
|
||||
let trailingCommentResizeObserver: ResizeObserver | null = null;
|
||||
|
||||
let labelMeasureFrame = 0;
|
||||
|
||||
let trailingCommentMeasureFrame = 0;
|
||||
|
||||
function cancelLabelOverflowMeasure() {
|
||||
if (!labelMeasureFrame) return;
|
||||
window.cancelAnimationFrame(labelMeasureFrame);
|
||||
|
|
@ -541,10 +551,61 @@ const isNodeDefaultDatabase = computed(
|
|||
);
|
||||
|
||||
const trailingComment = computed(() => {
|
||||
if (settingsStore.editorSettings.sidebarObjectInfoMode !== "comment-inline" && settingsStore.editorSettings.sidebarObjectInfoMode !== "comment-aligned") return null;
|
||||
if (!settingsStore.editorSettings.sidebarObjectInfoMode.startsWith("comment-")) return null;
|
||||
return sidebarTreeNodeComment(activeNode.value);
|
||||
});
|
||||
|
||||
function isRightAlignedComment(): boolean {
|
||||
return settingsStore.editorSettings.sidebarObjectInfoMode === "comment-right" && !!trailingComment.value;
|
||||
}
|
||||
|
||||
function cancelTrailingCommentMeasure() {
|
||||
if (!trailingCommentMeasureFrame) return;
|
||||
window.cancelAnimationFrame(trailingCommentMeasureFrame);
|
||||
trailingCommentMeasureFrame = 0;
|
||||
}
|
||||
|
||||
function measureTrailingCommentLayout() {
|
||||
const container = trailingCommentLayoutRef.value;
|
||||
const leading = trailingCommentLeadingRef.value;
|
||||
if (!isRightAlignedComment() || !container || !leading) {
|
||||
trailingCommentMaxWidth.value = 0;
|
||||
return;
|
||||
}
|
||||
trailingCommentMaxWidth.value = trailingCommentAvailableWidth(container.clientWidth, leading.scrollWidth);
|
||||
}
|
||||
|
||||
function scheduleTrailingCommentMeasure() {
|
||||
if (typeof window === "undefined") {
|
||||
measureTrailingCommentLayout();
|
||||
return;
|
||||
}
|
||||
cancelTrailingCommentMeasure();
|
||||
trailingCommentMeasureFrame = window.requestAnimationFrame(() => {
|
||||
trailingCommentMeasureFrame = 0;
|
||||
measureTrailingCommentLayout();
|
||||
});
|
||||
}
|
||||
|
||||
function refreshTrailingCommentMeasurement() {
|
||||
trailingCommentResizeObserver?.disconnect();
|
||||
trailingCommentResizeObserver = null;
|
||||
|
||||
const container = trailingCommentLayoutRef.value;
|
||||
const leading = trailingCommentLeadingRef.value;
|
||||
if (!isRightAlignedComment() || !container || !leading) {
|
||||
trailingCommentMaxWidth.value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
scheduleTrailingCommentMeasure();
|
||||
if (typeof ResizeObserver !== "undefined") {
|
||||
trailingCommentResizeObserver = new ResizeObserver(scheduleTrailingCommentMeasure);
|
||||
trailingCommentResizeObserver.observe(container);
|
||||
trailingCommentResizeObserver.observe(leading);
|
||||
}
|
||||
}
|
||||
|
||||
function formattedObjectStorage(): string {
|
||||
if (settingsStore.editorSettings.sidebarObjectInfoMode !== "size" || (activeNode.value.type !== "database" && activeNode.value.type !== "table" && activeNode.value.type !== "materialized_view")) return "";
|
||||
return formatSidebarObjectStorage(activeNode.value.sizeBytes);
|
||||
|
|
@ -562,6 +623,8 @@ const rowWidthClass = computed(() => (usesFullWidthLabel.value ? "w-max min-w-fu
|
|||
|
||||
const labelWidthClass = computed(() => treeLabelWidthClass({ fullWidth: usesFullWidthLabel.value, hasTrailingComment: hasTrailingMetadata() }));
|
||||
|
||||
watch(() => [isRightAlignedComment(), visibleLabel(activeNode.value), trailingComment.value, trailingCommentLayoutRef.value, trailingCommentLeadingRef.value], refreshTrailingCommentMeasurement, { flush: "post", immediate: true });
|
||||
|
||||
const paddingLeft = computed(() => treeItemPaddingLeft(props.depth));
|
||||
|
||||
const tableSearchParentId = computed(() => activeNode.value.tableSearchParentId || "");
|
||||
|
|
@ -868,6 +931,8 @@ watch(
|
|||
onBeforeUnmount(() => {
|
||||
stopPasteHandlerRegistration();
|
||||
handleMouseLeave();
|
||||
trailingCommentResizeObserver?.disconnect();
|
||||
cancelTrailingCommentMeasure();
|
||||
finishTableReferenceDrag();
|
||||
});
|
||||
|
||||
|
|
@ -1003,8 +1068,12 @@ function onKeydown(event: KeyboardEvent) {
|
|||
<DatabaseIcon v-if="node.type === 'connection'" :db-type="connectionIconType(node.connectionId)" class="h-3.5 w-3.5 shrink-0" />
|
||||
<Loader2 v-else-if="node.type === 'load-more' && node.isLoading" class="w-3.5 h-3.5 shrink-0 animate-spin text-primary" />
|
||||
<component v-else :is="getIconInfo(node)?.icon || Database" class="w-3.5 h-3.5 shrink-0" :class="databaseOpenVisual.iconClass" />
|
||||
<div :class="hasTrailingMetadata() ? 'flex flex-1 min-w-0 items-center' : 'contents'">
|
||||
<div :class="trailingComment ? 'flex max-w-full min-w-0 shrink-0 items-center gap-2' : formattedObjectStorage() ? 'flex min-w-0 flex-1 items-center gap-2' : 'contents'" :style="alignedCommentLabelWidth ? { width: `${alignedCommentLabelWidth}px` } : undefined">
|
||||
<div ref="trailingCommentLayoutRef" :class="hasTrailingMetadata() ? 'flex flex-1 min-w-0 items-center' : 'contents'">
|
||||
<div
|
||||
ref="trailingCommentLeadingRef"
|
||||
:class="trailingComment ? 'flex max-w-full min-w-0 shrink-0 items-center gap-2' : formattedObjectStorage() ? 'flex min-w-0 flex-1 items-center gap-2' : 'contents'"
|
||||
:style="alignedCommentLabelWidth ? { width: `${alignedCommentLabelWidth}px` } : undefined"
|
||||
>
|
||||
<input
|
||||
v-if="isRenamingGroup"
|
||||
ref="renameInputRef"
|
||||
|
|
@ -1029,7 +1098,15 @@ function onKeydown(event: KeyboardEvent) {
|
|||
{{ t("editor.defaultDatabase") }}
|
||||
</Badge>
|
||||
</div>
|
||||
<span v-if="trailingComment" class="sidebar-object-comment ml-2 min-w-0 flex-1 truncate text-left" :class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }">{{ trailingComment }}</span>
|
||||
<span v-if="trailingComment && !isRightAlignedComment()" class="sidebar-object-comment ml-2 min-w-0 flex-1 truncate text-left" :class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }">{{ trailingComment }}</span>
|
||||
<span v-if="isRightAlignedComment() && trailingCommentMaxWidth > 0" class="min-w-0 flex-1" aria-hidden="true" />
|
||||
<span
|
||||
v-if="isRightAlignedComment() && trailingCommentMaxWidth > 0"
|
||||
class="sidebar-object-comment sidebar-object-comment--right min-w-0 shrink-0 truncate text-left"
|
||||
:class="{ 'sidebar-object-comment--windows': useWindowsSidebarCommentFont }"
|
||||
:style="{ marginLeft: `${trailingCommentGapPx}px`, maxWidth: `${trailingCommentMaxWidth}px` }"
|
||||
>{{ trailingComment }}</span
|
||||
>
|
||||
</div>
|
||||
<span v-if="node.type === 'connection' && node.connectionId && connectionStore.connectedIds.has(node.connectionId)" class="w-1.5 h-1.5 rounded-full bg-green-500 shrink-0" />
|
||||
<span v-if="databaseOpenVisual.showsIndicator" class="w-1.5 h-1.5 rounded-full bg-green-500 shrink-0" />
|
||||
|
|
@ -1081,16 +1158,22 @@ function onKeydown(event: KeyboardEvent) {
|
|||
<style>
|
||||
.sidebar-object-comment {
|
||||
color: var(--muted-foreground);
|
||||
font-size: 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1rem;
|
||||
opacity: 0.6;
|
||||
/* Sidebar rows repaint on hover; avoid heavier font shaping and fallback here. */
|
||||
text-rendering: auto;
|
||||
}
|
||||
|
||||
.sidebar-object-comment--right {
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
flex-shrink: 999;
|
||||
}
|
||||
|
||||
.sidebar-object-comment--windows {
|
||||
font-family: "Microsoft YaHei UI", "Microsoft YaHei", "Segoe UI", system-ui, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3856,6 +3856,7 @@ export default {
|
|||
"Choose comments, object sizes, or no supplementary text after names. Comments and sizes are mutually exclusive. Database totals currently support PostgreSQL; table sizes support MySQL, PostgreSQL, GaussDB, Kingbase, GBase 8a, SQL Server, Oracle, Dameng, and ClickHouse.",
|
||||
sidebarObjectInfoModeCommentInline: "Comments (after name)",
|
||||
sidebarObjectInfoModeCommentAligned: "Comments (align siblings)",
|
||||
sidebarObjectInfoModeCommentRight: "Comments (align right)",
|
||||
sidebarObjectInfoModeSize: "Object size",
|
||||
sidebarObjectInfoModeHidden: "None",
|
||||
sidebarAllowHorizontalScroll: "Allow sidebar horizontal scroll",
|
||||
|
|
|
|||
|
|
@ -3634,6 +3634,7 @@ export default withEnglishFallback({
|
|||
"Elige comentarios, tamaños de objetos o ningún texto tras los nombres. Los comentarios y tamaños son excluyentes. El tamaño total de bases admite PostgreSQL; los tamaños de tablas admiten MySQL, PostgreSQL, GaussDB, Kingbase, GBase 8a, SQL Server, Oracle, Dameng y ClickHouse.",
|
||||
sidebarObjectInfoModeCommentInline: "Comentarios (junto al nombre)",
|
||||
sidebarObjectInfoModeCommentAligned: "Comentarios (alinear nivel)",
|
||||
sidebarObjectInfoModeCommentRight: "Comentarios (alinear a la derecha)",
|
||||
sidebarObjectInfoModeSize: "Tamaño del objeto",
|
||||
sidebarObjectInfoModeHidden: "Ninguna",
|
||||
sidebarAllowHorizontalScroll: "Permitir desplazamiento horizontal lateral",
|
||||
|
|
|
|||
|
|
@ -3632,6 +3632,7 @@ export default withEnglishFallback({
|
|||
"Scegli commenti, dimensioni degli oggetti o nessun testo dopo i nomi. Commenti e dimensioni sono alternativi. La dimensione totale dei database supporta PostgreSQL; le dimensioni delle tabelle supportano MySQL, PostgreSQL, GaussDB, Kingbase, GBase 8a, SQL Server, Oracle, Dameng e ClickHouse.",
|
||||
sidebarObjectInfoModeCommentInline: "Commenti (accanto al nome)",
|
||||
sidebarObjectInfoModeCommentAligned: "Commenti (allinea livello)",
|
||||
sidebarObjectInfoModeCommentRight: "Commenti (allinea a destra)",
|
||||
sidebarObjectInfoModeSize: "Dimensione oggetto",
|
||||
sidebarObjectInfoModeHidden: "Nessuna",
|
||||
sidebarAllowHorizontalScroll: "Consenti scorrimento orizzontale barra laterale",
|
||||
|
|
|
|||
|
|
@ -3623,6 +3623,7 @@ export default withEnglishFallback({
|
|||
"名前の後にコメント、オブジェクトサイズ、または何も表示しないかを選択します。コメントとサイズは同時に表示されません。データベース全体のサイズは PostgreSQL、テーブルサイズは MySQL、PostgreSQL、GaussDB、Kingbase、GBase 8a、SQL Server、Oracle、Dameng、ClickHouse に対応しています。",
|
||||
sidebarObjectInfoModeCommentInline: "コメント(名前の直後)",
|
||||
sidebarObjectInfoModeCommentAligned: "コメント(同階層で整列)",
|
||||
sidebarObjectInfoModeCommentRight: "コメント(右揃え)",
|
||||
sidebarObjectInfoModeSize: "オブジェクトサイズ",
|
||||
sidebarObjectInfoModeHidden: "表示しない",
|
||||
sidebarAllowHorizontalScroll: "サイドバーの横スクロールを許可",
|
||||
|
|
|
|||
|
|
@ -3634,6 +3634,7 @@ export default withEnglishFallback({
|
|||
"Escolha comentários, tamanhos de objetos ou nenhum texto após os nomes. Comentários e tamanhos são mutuamente exclusivos. O tamanho total dos bancos aceita PostgreSQL; os tamanhos das tabelas aceitam MySQL, PostgreSQL, GaussDB, Kingbase, GBase 8a, SQL Server, Oracle, Dameng e ClickHouse.",
|
||||
sidebarObjectInfoModeCommentInline: "Comentários (junto ao nome)",
|
||||
sidebarObjectInfoModeCommentAligned: "Comentários (alinhar nível)",
|
||||
sidebarObjectInfoModeCommentRight: "Comentários (alinhar à direita)",
|
||||
sidebarObjectInfoModeSize: "Tamanho do objeto",
|
||||
sidebarObjectInfoModeHidden: "Nenhuma",
|
||||
sidebarAllowHorizontalScroll: "Permitir rolagem horizontal da barra lateral",
|
||||
|
|
|
|||
|
|
@ -3845,6 +3845,7 @@ export default withEnglishFallback({
|
|||
sidebarObjectInfoModeDescription: "选择在名称后显示注释、对象大小或不显示。注释与大小互斥;数据库总大小目前支持 PostgreSQL,表大小支持 MySQL、PostgreSQL、GaussDB、Kingbase、GBase 8a、SQL Server、Oracle、达梦和 ClickHouse。",
|
||||
sidebarObjectInfoModeCommentInline: "注释(紧跟名称)",
|
||||
sidebarObjectInfoModeCommentAligned: "注释(同级对齐)",
|
||||
sidebarObjectInfoModeCommentRight: "注释(右侧对齐)",
|
||||
sidebarObjectInfoModeSize: "对象大小",
|
||||
sidebarObjectInfoModeHidden: "不显示",
|
||||
sidebarAllowHorizontalScroll: "允许侧边栏横向滚动",
|
||||
|
|
|
|||
|
|
@ -3445,6 +3445,7 @@ export default withEnglishFallback({
|
|||
sidebarObjectInfoModeDescription: "選擇在名稱後顯示註解、物件大小或不顯示。註解與大小互斥;資料庫總大小目前支援 PostgreSQL,資料表大小支援 MySQL、PostgreSQL、GaussDB、Kingbase、GBase 8a、SQL Server、Oracle、達夢和 ClickHouse。",
|
||||
sidebarObjectInfoModeCommentInline: "註解(緊接名稱)",
|
||||
sidebarObjectInfoModeCommentAligned: "註解(同層對齊)",
|
||||
sidebarObjectInfoModeCommentRight: "註解(靠右對齊)",
|
||||
sidebarObjectInfoModeSize: "物件大小",
|
||||
sidebarObjectInfoModeHidden: "不顯示",
|
||||
sidebarAllowHorizontalScroll: "允許側邊欄水平捲動",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { alignedSidebarCommentLabelWidths, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
import { alignedSidebarCommentLabelWidths, trailingCommentAvailableWidth, treeLabelWidthClass, usesFullWidthTreeLabel } from "@/lib/sidebar/sidebarTreeItemLayout";
|
||||
|
||||
describe("sidebar tree item layout", () => {
|
||||
it("keeps a table row constrained when it displays a comment", () => {
|
||||
|
|
@ -24,4 +24,11 @@ describe("sidebar tree item layout", () => {
|
|||
expect(widths.has("long")).toBe(false);
|
||||
expect(widths.get("view")).toBe(72);
|
||||
});
|
||||
|
||||
it("limits right-aligned comments to the space after the complete name and gap", () => {
|
||||
expect(trailingCommentAvailableWidth(260, 100)).toBe(152);
|
||||
expect(trailingCommentAvailableWidth(108, 100)).toBe(0);
|
||||
expect(trailingCommentAvailableWidth(100, 100)).toBe(0);
|
||||
expect(trailingCommentAvailableWidth(99, 100)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@ export function treeItemPaddingLeft(depth: number): string {
|
|||
return `${depth * 16 + 8}px`;
|
||||
}
|
||||
|
||||
export const trailingCommentGapPx = 8;
|
||||
|
||||
export function trailingCommentAvailableWidth(containerWidth: number, leadingWidth: number): number {
|
||||
return Math.max(0, Math.floor(containerWidth - leadingWidth - trailingCommentGapPx));
|
||||
}
|
||||
|
||||
export interface SidebarCommentAlignmentItem {
|
||||
id: string;
|
||||
depth: number;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ describe("normalizeEditorSettings", () => {
|
|||
expect(normalizeEditorSettings({}).sidebarObjectInfoMode).toBe("comment-aligned");
|
||||
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-aligned" }).sidebarObjectInfoMode).toBe("comment-aligned");
|
||||
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-inline" }).sidebarObjectInfoMode).toBe("comment-inline");
|
||||
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "comment-right" }).sidebarObjectInfoMode).toBe("comment-right");
|
||||
expect(normalizeEditorSettings({ sidebarObjectInfoMode: "size" }).sidebarObjectInfoMode).toBe("size");
|
||||
expect(normalizeEditorSettings({ sidebarTableCommentLayout: "aligned" } as any).sidebarObjectInfoMode).toBe("comment-aligned");
|
||||
expect(normalizeEditorSettings({ sidebarTableCommentLayout: "hidden" } as any).sidebarObjectInfoMode).toBe("hidden");
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ export interface CustomTheme {
|
|||
|
||||
export const DEFAULT_CUSTOM_THEMES: CustomTheme[] = [{ id: "default", name: "Custom", colors: { ...DEFAULT_CUSTOM_THEME_COLORS }, ddlColors: { ...DEFAULT_CUSTOM_THEME_DDL_COLORS } }];
|
||||
|
||||
export type SidebarObjectInfoMode = "comment-inline" | "comment-aligned" | "size" | "hidden";
|
||||
export type SidebarObjectInfoMode = "comment-inline" | "comment-aligned" | "comment-right" | "size" | "hidden";
|
||||
|
||||
export interface EditorSettings {
|
||||
fontFamily: string;
|
||||
|
|
@ -714,7 +714,7 @@ function normalizeConnectionListSortMode(value: unknown): ConnectionListSortMode
|
|||
}
|
||||
|
||||
function normalizeSidebarObjectInfoMode(value: unknown, legacyCommentLayout?: unknown, legacyHideTableComments?: unknown, legacyShowDatabaseSizes?: unknown): SidebarObjectInfoMode {
|
||||
if (value === "comment-inline" || value === "comment-aligned" || value === "size" || value === "hidden") return value;
|
||||
if (value === "comment-inline" || value === "comment-aligned" || value === "comment-right" || value === "size" || value === "hidden") return value;
|
||||
if (legacyCommentLayout === "hidden" || legacyHideTableComments === true) return "hidden";
|
||||
if (legacyShowDatabaseSizes === true) return "size";
|
||||
if (legacyCommentLayout === "aligned") return "comment-aligned";
|
||||
|
|
|
|||
Loading…
Reference in New Issue