diff --git a/apps/desktop/src/components/editor/SqlPreviewPanel.vue b/apps/desktop/src/components/editor/SqlPreviewPanel.vue
index 9772de79db..1efc0a8701 100644
--- a/apps/desktop/src/components/editor/SqlPreviewPanel.vue
+++ b/apps/desktop/src/components/editor/SqlPreviewPanel.vue
@@ -1,5 +1,5 @@
diff --git a/apps/desktop/src/lib/__tests__/sql/sqlHighlighter.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlHighlighter.spec.ts
index b9c44808d5..90d3411341 100644
--- a/apps/desktop/src/lib/__tests__/sql/sqlHighlighter.spec.ts
+++ b/apps/desktop/src/lib/__tests__/sql/sqlHighlighter.spec.ts
@@ -8,6 +8,49 @@ describe("escapeHtml", () => {
});
describe("createSafeSqlHighlighter", () => {
+ it("keeps the default GitHub themes", () => {
+ const codeToHtml = vi.fn(() => "SELECT 1");
+ const highlighter = createSafeSqlHighlighter({ codeToHtml }, { appearance: () => "light" });
+
+ expect(highlighter("SELECT 1")).toBe("SELECT 1");
+ expect(highlighter("SELECT 2", "dark")).toBe("SELECT 1");
+ expect(codeToHtml).toHaveBeenNthCalledWith(1, "SELECT 1", {
+ lang: "sql",
+ structure: "inline",
+ theme: "github-light",
+ });
+ expect(codeToHtml).toHaveBeenNthCalledWith(2, "SELECT 2", {
+ lang: "sql",
+ structure: "inline",
+ theme: "github-dark",
+ });
+ });
+
+ it("uses the existing SQL preview themes", () => {
+ const codeToHtml = vi.fn(() => "SELECT 1");
+ const highlighter = createSafeSqlHighlighter(
+ { codeToHtml },
+ {
+ appearance: () => "light",
+ themePreset: "preview",
+ },
+ );
+
+ highlighter("SELECT 1");
+ highlighter("SELECT 2", "dark");
+
+ expect(codeToHtml).toHaveBeenNthCalledWith(1, "SELECT 1", {
+ lang: "sql",
+ structure: "inline",
+ theme: "min-light",
+ });
+ expect(codeToHtml).toHaveBeenNthCalledWith(2, "SELECT 2", {
+ lang: "sql",
+ structure: "inline",
+ theme: "dark-plus",
+ });
+ });
+
it("falls back to escaped SQL when Shiki highlighting fails", () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const highlighter = createSafeSqlHighlighter(
diff --git a/apps/desktop/src/lib/sql/sqlHighlighter.ts b/apps/desktop/src/lib/sql/sqlHighlighter.ts
index edd8a4a6bd..1c50fd6f15 100644
--- a/apps/desktop/src/lib/sql/sqlHighlighter.ts
+++ b/apps/desktop/src/lib/sql/sqlHighlighter.ts
@@ -4,11 +4,20 @@ export type SqlHighlighter = (content: string, appearance?: AppThemeAppearance)
interface ShikiSqlHighlighterOptions {
appearance: () => AppThemeAppearance;
+ themePreset?: ShikiSqlThemePreset;
}
+type ShikiSqlThemePreset = "default" | "preview";
+
const SHIKI_THEMES = {
- dark: "github-dark",
- light: "github-light",
+ default: {
+ dark: "github-dark",
+ light: "github-light",
+ },
+ preview: {
+ dark: "dark-plus",
+ light: "min-light",
+ },
} as const;
type ShikiHighlighter = Awaited>;
@@ -29,10 +38,11 @@ export async function createShikiSqlHighlighter(options: ShikiSqlHighlighterOpti
export function createSafeSqlHighlighter(highlighter: ShikiCodeHighlighter, options: ShikiSqlHighlighterOptions): SqlHighlighter {
return (content, appearance = options.appearance()) => {
try {
+ const themes = SHIKI_THEMES[options.themePreset ?? "default"];
return highlighter.codeToHtml(content, {
lang: "sql",
structure: "inline",
- theme: SHIKI_THEMES[appearance],
+ theme: themes[appearance],
});
} catch (error) {
console.warn("[DBX][sqlHighlighter] Failed to highlight SQL:", error);
@@ -64,11 +74,19 @@ function getShikiSqlHighlighter(): Promise {
}
async function loadShikiSqlHighlighter(): Promise {
- const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, githubDark, githubLight, sql] = await Promise.all([import("shiki/core"), import("shiki/engine/javascript"), import("shiki/themes/github-dark.mjs"), import("shiki/themes/github-light.mjs"), import("shiki/langs/sql.mjs")]);
+ const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, githubDark, githubLight, darkPlus, minLight, sql] = await Promise.all([
+ import("shiki/core"),
+ import("shiki/engine/javascript"),
+ import("shiki/themes/github-dark.mjs"),
+ import("shiki/themes/github-light.mjs"),
+ import("shiki/themes/dark-plus.mjs"),
+ import("shiki/themes/min-light.mjs"),
+ import("shiki/langs/sql.mjs"),
+ ]);
return createHighlighterCore({
engine: createJavaScriptRegexEngine(),
langs: [sql.default],
- themes: [githubDark.default, githubLight.default],
+ themes: [githubDark.default, githubLight.default, darkPlus.default, minLight.default],
});
}
diff --git a/packages/app-tests/sqlPreviewWrap.test.ts b/packages/app-tests/sqlPreviewWrap.test.ts
index 530f54d8c1..187f873a29 100644
--- a/packages/app-tests/sqlPreviewWrap.test.ts
+++ b/packages/app-tests/sqlPreviewWrap.test.ts
@@ -2,10 +2,12 @@ import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const sqlPreviewSource = readFileSync("apps/desktop/src/components/editor/SqlPreviewPanel.vue", "utf8");
+const sqlHighlighterSource = readFileSync("apps/desktop/src/lib/sql/sqlHighlighter.ts", "utf8");
describe("SQL preview wrapping", () => {
it("renders highlighted SQL inline inside a wrapping preformatted block", () => {
- expect(sqlPreviewSource).toContain('structure: "inline"');
+ expect(sqlPreviewSource).toContain('themePreset: "preview"');
+ expect(sqlHighlighterSource).toContain('structure: "inline"');
expect(sqlPreviewSource).toContain('