feat(editor): enhance SQL completion icons and styles
This commit is contained in:
parent
d8650df323
commit
e62ad97bcd
|
|
@ -138,7 +138,7 @@ const keyColumns = computed(() =>
|
|||
.filter(Boolean),
|
||||
);
|
||||
const rowLimitNumber = computed(() => Number(rowLimit.value) || 1000);
|
||||
const comparedResults = computed(() => batchResults.value.filter((item) => item.status !== "error"));
|
||||
|
||||
const sameTableCount = computed(() => batchResults.value.filter((item) => item.status === "same").length);
|
||||
const differentTableCount = computed(() => batchResults.value.filter((item) => item.status === "different").length);
|
||||
const failedTableCount = computed(() => batchResults.value.filter((item) => item.status === "error").length);
|
||||
|
|
|
|||
|
|
@ -598,7 +598,11 @@ async function provideSqlCompletions(
|
|||
|
||||
// If qualifier didn't match any table names, try it as a schema name
|
||||
let qualifierIsSchema = false;
|
||||
if (completionContext.qualifier && completionContext.suggestTables && tables.length === 0) {
|
||||
if (
|
||||
completionContext.qualifier &&
|
||||
tables.length === 0 &&
|
||||
(completionContext.suggestTables || completionContext.exclusiveColumnSuggestions)
|
||||
) {
|
||||
const schemaTables = await connectionStore.listCompletionTables(
|
||||
props.connectionId,
|
||||
props.database,
|
||||
|
|
@ -676,7 +680,13 @@ async function provideSqlCompletions(
|
|||
}
|
||||
|
||||
const effectiveContext = qualifierIsSchema
|
||||
? { ...completionContext, qualifier: undefined, suggestTables: true, suggestColumns: false }
|
||||
? {
|
||||
...completionContext,
|
||||
qualifier: undefined,
|
||||
suggestTables: true,
|
||||
suggestColumns: false,
|
||||
exclusiveColumnSuggestions: false,
|
||||
}
|
||||
: completionContext;
|
||||
|
||||
const items = buildSqlCompletionItemsFromContext(effectiveContext, {
|
||||
|
|
@ -692,7 +702,7 @@ async function provideSqlCompletions(
|
|||
item.type === "snippet" && item.apply
|
||||
? codeMirrorSnippetCompletion(item.apply, {
|
||||
label: item.label,
|
||||
type: "snippet",
|
||||
type: item.type,
|
||||
detail: item.detail,
|
||||
boost: item.boost,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,10 +3,53 @@ import type { EditorTheme } from "@/stores/settingsStore";
|
|||
import type { AppThemeAppearance } from "@/lib/appTheme";
|
||||
|
||||
type CodeMirrorStyleSpec = Parameters<typeof import("@codemirror/view").EditorView.theme>[0];
|
||||
type LucideIconNode = Array<[string, Record<string, string>]>;
|
||||
|
||||
export const EDITOR_FONT_SIZE_CSS_VAR = "--dbx-editor-font-size";
|
||||
export const EDITOR_FONT_FAMILY_CSS_VAR = "--dbx-editor-font-family";
|
||||
|
||||
const TABLE_ICON: LucideIconNode = [
|
||||
["path", { d: "M12 3v18" }],
|
||||
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
|
||||
["path", { d: "M3 9h18" }],
|
||||
["path", { d: "M3 15h18" }],
|
||||
];
|
||||
|
||||
const COLUMNS_ICON: LucideIconNode = [
|
||||
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }],
|
||||
["path", { d: "M12 3v18" }],
|
||||
];
|
||||
|
||||
const KEYWORD_ICON: LucideIconNode = [
|
||||
["path", { d: "m16 18 6-6-6-6" }],
|
||||
["path", { d: "m8 6-6 6 6 6" }],
|
||||
];
|
||||
|
||||
const SNIPPET_ICON: LucideIconNode = [
|
||||
["path", { d: "m15 10 5 5-5 5" }],
|
||||
["path", { d: "M4 4v7a4 4 0 0 0 4 4h12" }],
|
||||
];
|
||||
|
||||
function encodeSvgIcon(iconNode: LucideIconNode): string {
|
||||
const body = iconNode
|
||||
.map(
|
||||
([tag, attrs]) =>
|
||||
`<${tag} ${Object.entries(attrs)
|
||||
.map(([key, value]) => `${key}="${value}"`)
|
||||
.join(" ")} />`,
|
||||
)
|
||||
.join("");
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${body}</svg>`;
|
||||
return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
|
||||
}
|
||||
|
||||
function lucideCompletionIconMask(iconNode: LucideIconNode) {
|
||||
const mask = encodeSvgIcon(iconNode);
|
||||
return {
|
||||
"--dbx-completion-icon-mask": mask,
|
||||
};
|
||||
}
|
||||
|
||||
/** Load a CodeMirror theme extension by theme name. */
|
||||
export function resolveEditorTheme(theme: EditorTheme, appAppearance: AppThemeAppearance): Exclude<EditorTheme, "app"> {
|
||||
if (theme === "app") return appAppearance === "dark" ? "one-dark" : "vscode-light";
|
||||
|
|
@ -128,11 +171,52 @@ export function buildSqlCompletionThemeRules(): CodeMirrorStyleSpec {
|
|||
outline: "1px solid color-mix(in oklch, var(--primary) 22%, transparent)",
|
||||
},
|
||||
".cm-completionIcon": {
|
||||
display: "none !important",
|
||||
height: "0",
|
||||
margin: "0",
|
||||
paddingRight: "0 !important",
|
||||
width: "0",
|
||||
alignItems: "center",
|
||||
display: "inline-flex",
|
||||
flex: "0 0 15px",
|
||||
height: "15px",
|
||||
justifyContent: "center",
|
||||
marginRight: "0.65em",
|
||||
opacity: "1",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
width: "15px",
|
||||
},
|
||||
".cm-completionIcon:before": {
|
||||
backgroundColor: "currentColor",
|
||||
content: "''",
|
||||
display: "block",
|
||||
height: "14px",
|
||||
position: "absolute",
|
||||
WebkitMaskImage: "var(--dbx-completion-icon-mask)",
|
||||
WebkitMaskPosition: "center",
|
||||
WebkitMaskRepeat: "no-repeat",
|
||||
WebkitMaskSize: "14px 14px",
|
||||
maskImage: "var(--dbx-completion-icon-mask)",
|
||||
maskPosition: "center",
|
||||
maskRepeat: "no-repeat",
|
||||
maskSize: "14px 14px",
|
||||
width: "14px",
|
||||
},
|
||||
".cm-completionIcon:after": {
|
||||
content: "'none'",
|
||||
display: "none",
|
||||
},
|
||||
".cm-completionIcon-table": {
|
||||
color: "color-mix(in oklch, var(--primary) 92%, var(--popover-foreground))",
|
||||
...lucideCompletionIconMask(TABLE_ICON),
|
||||
},
|
||||
".cm-completionIcon-column": {
|
||||
color: "color-mix(in oklch, var(--blue-500, #3b82f6) 92%, var(--popover-foreground))",
|
||||
...lucideCompletionIconMask(COLUMNS_ICON),
|
||||
},
|
||||
".cm-completionIcon-keyword": {
|
||||
color: "color-mix(in oklch, var(--orange-500, #f97316) 92%, var(--popover-foreground))",
|
||||
...lucideCompletionIconMask(KEYWORD_ICON),
|
||||
},
|
||||
".cm-completionIcon-snippet": {
|
||||
color: "color-mix(in oklch, var(--emerald-500, #10b981) 92%, var(--popover-foreground))",
|
||||
...lucideCompletionIconMask(SNIPPET_ICON),
|
||||
},
|
||||
".cm-completionLabel": {
|
||||
color: "inherit",
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ html.disable-transitions *::after {
|
|||
}
|
||||
|
||||
/* Splitpanes */
|
||||
.splitpanes--horizontal .splitpanes__pane {
|
||||
transition: none !important;
|
||||
}
|
||||
.splitpanes--vertical > .splitpanes__splitter {
|
||||
width: 3px !important;
|
||||
border-left: 1px solid var(--border);
|
||||
|
|
|
|||
|
|
@ -24,12 +24,26 @@ test("sql completion theme styles the autocomplete popup", () => {
|
|||
padding: "4px 0",
|
||||
});
|
||||
assert.deepEqual(rules[".cm-completionIcon"], {
|
||||
display: "none !important",
|
||||
height: "0",
|
||||
margin: "0",
|
||||
paddingRight: "0 !important",
|
||||
width: "0",
|
||||
alignItems: "center",
|
||||
display: "inline-flex",
|
||||
flex: "0 0 15px",
|
||||
height: "15px",
|
||||
justifyContent: "center",
|
||||
marginRight: "0.65em",
|
||||
opacity: "1",
|
||||
overflow: "hidden",
|
||||
position: "relative",
|
||||
width: "15px",
|
||||
});
|
||||
assert.equal(rules[".cm-completionIcon:before"]?.backgroundColor, "currentColor");
|
||||
assert.equal(rules[".cm-completionIcon:before"]?.content, "''");
|
||||
assert.equal(rules[".cm-completionIcon:before"]?.WebkitMaskSize, "14px 14px");
|
||||
assert.equal(rules[".cm-completionIcon:after"]?.display, "none");
|
||||
assert.equal(rules[".cm-completionIcon-table"]?.color, "color-mix(in oklch, var(--primary) 92%, var(--popover-foreground))");
|
||||
assert.equal(rules[".cm-completionIcon-column"]?.color, "color-mix(in oklch, var(--blue-500, #3b82f6) 92%, var(--popover-foreground))");
|
||||
assert.equal(rules[".cm-completionIcon-keyword"]?.color, "color-mix(in oklch, var(--orange-500, #f97316) 92%, var(--popover-foreground))");
|
||||
assert.equal(rules[".cm-completionIcon-keyword"]?.["--dbx-completion-icon-mask"]?.includes("m16%2018%206-6-6-6"), true);
|
||||
assert.equal(rules[".cm-completionIcon-snippet"]?.color, "color-mix(in oklch, var(--emerald-500, #10b981) 92%, var(--popover-foreground))");
|
||||
assert.deepEqual(rules[".cm-completionLabel"], {
|
||||
color: "inherit",
|
||||
fontFamily: `var(${EDITOR_FONT_FAMILY_CSS_VAR}, var(--font-mono, monospace))`,
|
||||
|
|
|
|||
Loading…
Reference in New Issue