From d77e9e8c0d388f97086610cb288f5fa252acf436 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 14:28:54 +0800 Subject: [PATCH 01/17] feat(windows): align default theme with IntelliJ New UI palette Map lithe-dark/lithe-light colors to the IntelliJ New UI dark/light theme values (Gray/Blue ramp), invert the surface/background layering so panels sit above the editor area, switch list selection and hover toward the IDEA blue ramp, and reduce the global radius from 10px to 8px. Values sourced from intellij-community expUI theme JSONs. --- .../src/extensions/themes/builtin/lithe.json | 48 +++++++++---------- windows/tauri/src/styles/theme.css | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/windows/tauri/src/extensions/themes/builtin/lithe.json b/windows/tauri/src/extensions/themes/builtin/lithe.json index 5ef661fee..3e42a2d69 100644 --- a/windows/tauri/src/extensions/themes/builtin/lithe.json +++ b/windows/tauri/src/extensions/themes/builtin/lithe.json @@ -14,18 +14,18 @@ "foreground": "#1f2328", "muted-foreground": "#4f5965", "subtle-foreground": "#68717d", - "border": "#dde1e6", - "accent": "#f0f2f5", - "selected": "#e8ebef", - "selection": "rgba(8, 119, 193, 0.2)", - "primary": "#0877c1", + "border": "#dfe1e5", + "accent": "#edf3ff", + "selected": "#d4e2ff", + "selection": "rgba(53, 116, 240, 0.2)", + "primary": "#3574f0", "cursor": "#1f2328", - "cursor-vim-normal": "rgba(8, 119, 193, 0.62)", - "cursor-vim-insert": "#0877c1", + "cursor-vim-normal": "rgba(53, 116, 240, 0.62)", + "cursor-vim-insert": "#3574f0", "destructive": "#cf3f4f", "success": "#27864f", "warning": "#a86400", - "info": "#0877c1", + "info": "#3574f0", "git-modified": "#a86400", "git-modified-staged": "#bd7411", "git-added": "#27864f", @@ -76,23 +76,23 @@ "description": "Layered neutral surfaces with readable text and Lithe blue accents", "appearance": "dark", "colors": { - "background": "#151619", - "surface": "#0f1012", - "foreground": "#f2f3f5", - "muted-foreground": "#c4c9d1", + "background": "#1e1f22", + "surface": "#2b2d30", + "foreground": "#dfe1e5", + "muted-foreground": "#b4b8bf", "subtle-foreground": "#8b929e", - "border": "#2b2f36", - "accent": "#202328", - "selected": "#282c33", - "selection": "rgba(40, 149, 211, 0.3)", - "primary": "#2895d3", - "cursor": "#f2f3f5", - "cursor-vim-normal": "rgba(40, 149, 211, 0.68)", - "cursor-vim-insert": "#2895d3", - "destructive": "#f16d75", - "success": "#4cc38a", - "warning": "#d9a441", - "info": "#58a6e7", + "border": "#43454a", + "accent": "#393b40", + "selected": "#2e436e", + "selection": "rgba(53, 116, 240, 0.3)", + "primary": "#3574f0", + "cursor": "#dfe1e5", + "cursor-vim-normal": "rgba(53, 116, 240, 0.68)", + "cursor-vim-insert": "#3574f0", + "destructive": "#db5c5c", + "success": "#57965c", + "warning": "#d6ae58", + "info": "#548af7", "git-modified": "#d9a441", "git-modified-staged": "#e5b75e", "git-added": "#4cc38a", diff --git a/windows/tauri/src/styles/theme.css b/windows/tauri/src/styles/theme.css index 98027e4c2..c6d38d8ef 100644 --- a/windows/tauri/src/styles/theme.css +++ b/windows/tauri/src/styles/theme.css @@ -131,7 +131,7 @@ --lithe-chrome-gap-loose: 6px; --lithe-chrome-padding-inline: 8px; --lithe-chrome-radius: 6px; - --radius: 10px; + --radius: 8px; --app-duration-fast: 150ms; --app-duration-normal: 200ms; --app-ease-smooth: cubic-bezier(0.22, 1, 0.36, 1); From d98de777c148b5baa66e8c126e0d1a31f56ab6f9 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:07:18 +0800 Subject: [PATCH 02/17] chore(windows): vendor IntelliJ platform icons for the icon funnel Copy 91 Apache-2.0 SVGs (52 mapped icons, light/dark pairs, embedded copyright comments preserved) from the intellij-community platform icon set. The mapping list and deterministic generator with --check validation live under scripts/; asset URLs are emitted to src/ui/icons/idea-assets.generated.ts. --- windows/tauri/scripts/generate-idea-icons.ts | 171 ++++++++++++++++++ windows/tauri/scripts/idea-icon-mappings.json | 62 +++++++ .../src/ui/icons/idea-assets.generated.ts | 167 +++++++++++++++++ .../ui/icons/idea/expui/actions/addFile.svg | 5 + .../icons/idea/expui/actions/addFile_dark.svg | 5 + .../ui/icons/idea/expui/actions/newFolder.svg | 6 + .../idea/expui/actions/newFolder_dark.svg | 6 + .../src/ui/icons/idea/expui/general/add.svg | 4 + .../ui/icons/idea/expui/general/add_dark.svg | 4 + .../icons/idea/expui/general/chevronDown.svg | 4 + .../idea/expui/general/chevronDown_dark.svg | 4 + .../icons/idea/expui/general/chevronLeft.svg | 4 + .../idea/expui/general/chevronLeft_dark.svg | 4 + .../icons/idea/expui/general/chevronRight.svg | 4 + .../idea/expui/general/chevronRight_dark.svg | 4 + .../ui/icons/idea/expui/general/chevronUp.svg | 4 + .../idea/expui/general/chevronUp_dark.svg | 4 + .../src/ui/icons/idea/expui/general/close.svg | 4 + .../icons/idea/expui/general/close_dark.svg | 4 + .../src/ui/icons/idea/expui/general/copy.svg | 8 + .../ui/icons/idea/expui/general/copy_dark.svg | 8 + .../ui/icons/idea/expui/general/delete.svg | 4 + .../icons/idea/expui/general/delete_dark.svg | 4 + .../ui/icons/idea/expui/general/download.svg | 7 + .../idea/expui/general/download_dark.svg | 7 + .../src/ui/icons/idea/expui/general/edit.svg | 4 + .../ui/icons/idea/expui/general/edit_dark.svg | 4 + .../icons/idea/expui/general/errorDialog.svg | 6 + .../idea/expui/general/errorDialog_dark.svg | 13 ++ .../ui/icons/idea/expui/general/filter.svg | 4 + .../icons/idea/expui/general/filter_dark.svg | 4 + .../idea/expui/general/greenCheckmark.svg | 3 + .../expui/general/greenCheckmark_dark.svg | 3 + .../ui/icons/idea/expui/general/history.svg | 5 + .../icons/idea/expui/general/history_dark.svg | 5 + .../idea/expui/general/informationDialog.svg | 6 + .../expui/general/informationDialog_dark.svg | 13 ++ .../ui/icons/idea/expui/general/keyboard.svg | 14 ++ .../idea/expui/general/keyboard_dark.svg | 14 ++ .../ui/icons/idea/expui/general/locked.svg | 4 + .../icons/idea/expui/general/locked_dark.svg | 4 + .../idea/expui/general/moreHorizontal.svg | 6 + .../expui/general/moreHorizontal_dark.svg | 6 + .../src/ui/icons/idea/expui/general/pin.svg | 5 + .../ui/icons/idea/expui/general/pin_dark.svg | 5 + .../idea/expui/general/questionDialog.svg | 6 + .../expui/general/questionDialog_dark.svg | 13 ++ .../src/ui/icons/idea/expui/general/redo.svg | 4 + .../ui/icons/idea/expui/general/redo_dark.svg | 4 + .../ui/icons/idea/expui/general/refresh.svg | 7 + .../icons/idea/expui/general/refresh_dark.svg | 7 + .../ui/icons/idea/expui/general/remove.svg | 4 + .../icons/idea/expui/general/remove_dark.svg | 4 + .../src/ui/icons/idea/expui/general/save.svg | 4 + .../ui/icons/idea/expui/general/save_dark.svg | 4 + .../ui/icons/idea/expui/general/search.svg | 5 + .../icons/idea/expui/general/search_dark.svg | 5 + .../ui/icons/idea/expui/general/settings.svg | 4 + .../idea/expui/general/settings_dark.svg | 4 + .../idea/expui/general/successDialog.svg | 5 + .../idea/expui/general/successDialog_dark.svg | 12 ++ .../src/ui/icons/idea/expui/general/undo.svg | 4 + .../ui/icons/idea/expui/general/undo_dark.svg | 4 + .../ui/icons/idea/expui/general/unlocked.svg | 4 + .../idea/expui/general/unlocked_dark.svg | 4 + .../ui/icons/idea/expui/general/upload.svg | 7 + .../icons/idea/expui/general/upload_dark.svg | 7 + .../src/ui/icons/idea/expui/general/user.svg | 7 + .../ui/icons/idea/expui/general/user_dark.svg | 7 + .../idea/expui/general/warningDialog.svg | 6 + .../idea/expui/general/warningDialog_dark.svg | 13 ++ .../ui/icons/idea/expui/ide/externalLink.svg | 4 + .../idea/expui/ide/externalLink_dark.svg | 4 + .../src/ui/icons/idea/expui/nodes/folder.svg | 4 + .../ui/icons/idea/expui/nodes/folder_dark.svg | 4 + .../src/ui/icons/idea/expui/run/debug.svg | 6 + .../ui/icons/idea/expui/run/debug_dark.svg | 6 + .../src/ui/icons/idea/expui/run/pause.svg | 5 + .../ui/icons/idea/expui/run/pause_dark.svg | 5 + .../tauri/src/ui/icons/idea/expui/run/run.svg | 4 + .../src/ui/icons/idea/expui/run/run_dark.svg | 4 + .../src/ui/icons/idea/expui/run/stop.svg | 4 + .../src/ui/icons/idea/expui/run/stop_dark.svg | 4 + .../idea/expui/toolwindows/notifications.svg | 5 + .../expui/toolwindows/notifications_dark.svg | 5 + .../src/ui/icons/idea/expui/vcs/commit.svg | 4 + .../ui/icons/idea/expui/vcs/commit_dark.svg | 4 + .../src/ui/icons/idea/expui/vcs/diff.svg | 5 + .../src/ui/icons/idea/expui/vcs/diff_dark.svg | 5 + .../src/ui/icons/idea/expui/vcs/merge.svg | 6 + .../ui/icons/idea/expui/vcs/merge_dark.svg | 6 + .../src/ui/icons/idea/fileTypes/text.svg | 8 + .../tauri/src/ui/icons/idea/vcs/branch.svg | 8 + .../src/ui/icons/idea/vcs/branch_dark.svg | 8 + 94 files changed, 909 insertions(+) create mode 100644 windows/tauri/scripts/generate-idea-icons.ts create mode 100644 windows/tauri/scripts/idea-icon-mappings.json create mode 100644 windows/tauri/src/ui/icons/idea-assets.generated.ts create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/addFile.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/addFile_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/newFolder.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/newFolder_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/add.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/add_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronDown.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronDown_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronLeft.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronLeft_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronRight.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronRight_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronUp.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/chevronUp_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/close.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/close_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/copy.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/copy_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/delete.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/delete_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/download.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/download_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/edit.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/edit_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/errorDialog.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/errorDialog_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/filter.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/filter_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/history.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/history_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/informationDialog.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/informationDialog_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/keyboard.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/keyboard_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/locked.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/locked_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/pin.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/pin_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/questionDialog.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/questionDialog_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/redo.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/redo_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/refresh.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/refresh_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/remove.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/remove_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/save.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/save_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/search.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/search_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/settings.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/settings_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/successDialog.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/successDialog_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/undo.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/undo_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/unlocked.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/unlocked_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/upload.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/upload_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/user.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/user_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/warningDialog.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/warningDialog_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/ide/externalLink.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/ide/externalLink_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/folder.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/folder_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/debug.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/debug_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/pause.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/pause_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/run.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/run_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/stop.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/run/stop_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/vcs/commit.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/vcs/commit_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/vcs/diff.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/vcs/diff_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/vcs/merge.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/vcs/merge_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/fileTypes/text.svg create mode 100644 windows/tauri/src/ui/icons/idea/vcs/branch.svg create mode 100644 windows/tauri/src/ui/icons/idea/vcs/branch_dark.svg diff --git a/windows/tauri/scripts/generate-idea-icons.ts b/windows/tauri/scripts/generate-idea-icons.ts new file mode 100644 index 000000000..b04ed0434 --- /dev/null +++ b/windows/tauri/scripts/generate-idea-icons.ts @@ -0,0 +1,171 @@ +/** + * Copies IntelliJ platform icon SVGs into the Lithe icon funnel and emits the + * generated asset map consumed by `src/ui/icons.tsx`. + * + * Usage (run from windows/tauri): + * bun scripts/generate-idea-icons.ts --source /platform/icons/src [--check] + * + * The mapping file (scripts/idea-icon-mappings.json) is the single source of + * truth for which Lithe icon exports use IntelliJ assets; every other export + * keeps its lucide fallback. Source paths are repo-relative and resolved + * against --source, so no machine-specific path is persisted. Each copied SVG + * keeps its embedded Apache-2.0 copyright comment untouched. + */ +import { createHash } from "node:crypto"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; + +interface MappingEntry { + icon: string; + source: string | null; + note?: string; +} + +interface MappingFile { + icons: MappingEntry[]; +} + +const REPO_ROOT = resolve(import.meta.dir, ".."); +const MAPPING_PATH = join(import.meta.dir, "idea-icon-mappings.json"); +const ICONS_TSX_PATH = join(REPO_ROOT, "src/ui/icons.tsx"); +const ASSETS_DIR = join(REPO_ROOT, "src/ui/icons/idea"); +const GENERATED_TS_PATH = join(REPO_ROOT, "src/ui/icons/idea-assets.generated.ts"); + +function parseArgs(): { source: string | null; check: boolean } { + const argv = process.argv.slice(2); + let source: string | null = null; + let check = false; + for (let i = 0; i < argv.length; i += 1) { + if (argv[i] === "--source" && argv[i + 1]) { + source = resolve(argv[i + 1]); + i += 1; + } else if (argv[i] === "--check") { + check = true; + } + } + return { source, check }; +} + +function toIdentifier(icon: string): string { + return icon.replace(/Icon$/, "").replace(/^./, (c) => c.toLowerCase()); +} + +function sha(buffer: Buffer): string { + return createHash("sha256").update(buffer).digest("hex"); +} + +const { source: sourceRoot, check } = parseArgs(); +if (!sourceRoot) { + console.error("Missing --source /platform/icons/src"); + process.exit(1); +} + +const mapping = JSON.parse(readFileSync(MAPPING_PATH, "utf8")) as MappingFile; +const iconsTsx = readFileSync(ICONS_TSX_PATH, "utf8"); + +interface PlannedIcon { + icon: string; + source: string; + light: string; + dark: string | null; +} + +const planned: PlannedIcon[] = []; +const missingSources: string[] = []; +const unknownExports: string[] = []; +const duplicateIcons: string[] = []; + +for (const entry of mapping.icons) { + if (planned.some((p) => p.icon === entry.icon)) { + duplicateIcons.push(entry.icon); + continue; + } + if (!new RegExp(`export const ${entry.icon} =`).test(iconsTsx)) { + unknownExports.push(entry.icon); + continue; + } + if (!entry.source) { + continue; + } + const lightAbs = join(sourceRoot, entry.source); + if (!existsSync(lightAbs)) { + missingSources.push(entry.source); + continue; + } + const darkRel = entry.source.replace(/\.svg$/, "_dark.svg"); + const darkAbs = join(sourceRoot, darkRel); + planned.push({ + icon: entry.icon, + source: entry.source, + light: entry.source, + dark: existsSync(darkAbs) ? darkRel : null, + }); +} + +planned.sort((a, b) => a.icon.localeCompare(b.icon)); + +const failures = [ + ...missingSources.map((s) => `source SVG not found: ${s}`), + ...unknownExports.map((i) => `not exported from src/ui/icons.tsx: ${i}`), + ...duplicateIcons.map((i) => `duplicate mapping entry: ${i}`), +]; +if (failures.length > 0) { + console.error(failures.join("\n")); + process.exit(1); +} + +let generated = `// AUTO-GENERATED by scripts/generate-idea-icons.ts — do not edit by hand.\n`; +generated += `// Mapping source: scripts/idea-icon-mappings.json (paths relative to the\n`; +generated += `// intellij-community platform/icons/src checkout passed via --source).\n`; +generated += `// Keys are icon export display names resolved by createIconComponent.\n\n`; + +for (const p of planned) { + generated += `import ${toIdentifier(p.icon)}Light from "./idea/${p.light}?url";\n`; + if (p.dark) { + generated += `import ${toIdentifier(p.icon)}Dark from "./idea/${p.dark}?url";\n`; + } +} +generated += `\nexport interface IdeaIconAsset {\n light: string;\n dark: string;\n}\n\n`; +generated += `export const ideaIconAssets: Record = {\n`; +for (const p of planned) { + const darkId = p.dark ? `${toIdentifier(p.icon)}Dark` : `${toIdentifier(p.icon)}Light`; + generated += ` ${p.icon}: { light: ${toIdentifier(p.icon)}Light, dark: ${darkId} },\n`; +} +generated += `};\n`; + +if (check) { + const problems: string[] = []; + if (readFileSync(GENERATED_TS_PATH, "utf8") !== generated) { + problems.push("src/ui/icons/idea-assets.generated.ts is out of date; rerun the generator"); + } + for (const p of planned) { + const pairs = p.dark ? [p.light, p.dark] : [p.light]; + for (const rel of pairs) { + const copied = join(ASSETS_DIR, rel); + if (!existsSync(copied)) { + problems.push(`missing copied asset: src/ui/icons/idea/${rel}`); + } else if (sha(readFileSync(copied)) !== sha(readFileSync(join(sourceRoot, rel)))) { + problems.push(`copied asset differs from source: src/ui/icons/idea/${rel}`); + } + } + } + if (problems.length > 0) { + console.error(problems.join("\n")); + process.exit(1); + } + console.log(`idea-icons check passed (${planned.length} mapped icons)`); + process.exit(0); +} + +for (const p of planned) { + const pairs = p.dark ? [p.light, p.dark] : [p.light]; + for (const rel of pairs) { + const dest = join(ASSETS_DIR, rel); + mkdirSync(dirname(dest), { recursive: true }); + writeFileSync(dest, readFileSync(join(sourceRoot, rel))); + } +} +writeFileSync(GENERATED_TS_PATH, generated); +console.log( + `Copied ${planned.reduce((n, p) => n + (p.dark ? 2 : 1), 0)} SVGs and emitted idea-assets.generated.ts (${planned.length} icons mapped)`, +); diff --git a/windows/tauri/scripts/idea-icon-mappings.json b/windows/tauri/scripts/idea-icon-mappings.json new file mode 100644 index 000000000..44d9d94ad --- /dev/null +++ b/windows/tauri/scripts/idea-icon-mappings.json @@ -0,0 +1,62 @@ +{ + "description": "Lithe icon export name -> IntelliJ platform icon asset (relative to intellij-community platform/icons/src). Managed by scripts/generate-idea-icons.ts. Icons absent from this list keep their lucide fallback. colorPolicy defaults to 'fixed' (IDEA colors as-is); 'fallback' entries document why an IDEA asset was not used.", + "icons": [ + { "icon": "PlusIcon", "source": "expui/general/add.svg" }, + { "icon": "XIcon", "source": "expui/general/close.svg" }, + { "icon": "CheckIcon", "source": "expui/general/greenCheckmark.svg" }, + { "icon": "CheckCircleIcon", "source": "expui/general/successDialog.svg" }, + { "icon": "TrashIcon", "source": "expui/general/delete.svg" }, + { "icon": "CaretDownIcon", "source": "expui/general/chevronDown.svg" }, + { "icon": "ChevronDownIcon", "source": "expui/general/chevronDown.svg" }, + { "icon": "CaretUpIcon", "source": "expui/general/chevronUp.svg" }, + { "icon": "ChevronUpIcon", "source": "expui/general/chevronUp.svg" }, + { "icon": "CaretLeftIcon", "source": "expui/general/chevronLeft.svg" }, + { "icon": "ChevronLeftIcon", "source": "expui/general/chevronLeft.svg" }, + { "icon": "CaretRightIcon", "source": "expui/general/chevronRight.svg" }, + { "icon": "ChevronRightIcon", "source": "expui/general/chevronRight.svg" }, + { "icon": "MagnifyingGlassIcon", "source": "expui/general/search.svg" }, + { "icon": "GearIcon", "source": "expui/general/settings.svg" }, + { "icon": "RefreshIcon", "source": "expui/general/refresh.svg" }, + { "icon": "CopyIcon", "source": "expui/general/copy.svg" }, + { "icon": "DownloadIcon", "source": "expui/general/download.svg" }, + { "icon": "UploadIcon", "source": "expui/general/upload.svg" }, + { "icon": "FloppyDiskIcon", "source": "expui/general/save.svg" }, + { "icon": "ArrowCounterClockwiseIcon", "source": "expui/general/undo.svg" }, + { "icon": "ArrowClockwiseIcon", "source": "expui/general/redo.svg" }, + { "icon": "WarningIcon", "source": "expui/general/warningDialog.svg" }, + { "icon": "WarningCircleIcon", "source": "expui/general/warningDialog.svg" }, + { "icon": "InfoIcon", "source": "expui/general/informationDialog.svg" }, + { "icon": "QuestionIcon", "source": "expui/general/questionDialog.svg" }, + { "icon": "XCircleIcon", "source": "expui/general/errorDialog.svg" }, + { "icon": "MinusIcon", "source": "expui/general/remove.svg" }, + { "icon": "DotsThreeIcon", "source": "expui/general/moreHorizontal.svg" }, + { "icon": "KeyboardIcon", "source": "expui/general/keyboard.svg" }, + { "icon": "ClockCounterClockwiseIcon", "source": "expui/general/history.svg" }, + { "icon": "FunnelIcon", "source": "expui/general/filter.svg" }, + { "icon": "PencilIcon", "source": "expui/general/edit.svg" }, + { "icon": "LockIcon", "source": "expui/general/locked.svg" }, + { "icon": "LockOpenIcon", "source": "expui/general/unlocked.svg" }, + { "icon": "UserIcon", "source": "expui/general/user.svg" }, + { "icon": "PushPinIcon", "source": "expui/general/pin.svg" }, + { "icon": "GitBranchIcon", "source": "vcs/branch.svg" }, + { "icon": "GitCommitIcon", "source": "expui/vcs/commit.svg" }, + { "icon": "GitMergeIcon", "source": "expui/vcs/merge.svg" }, + { "icon": "GitDiffIcon", "source": "expui/vcs/diff.svg" }, + { "icon": "PlayIcon", "source": "expui/run/run.svg" }, + { "icon": "StopIcon", "source": "expui/run/stop.svg" }, + { "icon": "PauseIcon", "source": "expui/run/pause.svg" }, + { "icon": "BugIcon", "source": "expui/run/debug.svg" }, + { "icon": "FolderIcon", "source": "expui/nodes/folder.svg" }, + { "icon": "FolderPlusIcon", "source": "expui/actions/newFolder.svg" }, + { "icon": "FilePlusIcon", "source": "expui/actions/addFile.svg" }, + { "icon": "FileIcon", "source": "fileTypes/text.svg" }, + { "icon": "FileTextIcon", "source": "fileTypes/text.svg" }, + { "icon": "OpenExternalIcon", "source": "expui/ide/externalLink.svg" }, + { "icon": "BellIcon", "source": "expui/toolwindows/notifications.svg" }, + { + "icon": "TerminalIcon", + "source": null, + "note": "IDEA terminal tool window icon ships in the terminal plugin, not platform/icons; keep lucide fallback" + } + ] +} diff --git a/windows/tauri/src/ui/icons/idea-assets.generated.ts b/windows/tauri/src/ui/icons/idea-assets.generated.ts new file mode 100644 index 000000000..9f0fea1e8 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea-assets.generated.ts @@ -0,0 +1,167 @@ +// AUTO-GENERATED by scripts/generate-idea-icons.ts — do not edit by hand. +// Mapping source: scripts/idea-icon-mappings.json (paths relative to the +// intellij-community platform/icons/src checkout passed via --source). +// Keys are icon export display names resolved by createIconComponent. + +import arrowClockwiseLight from "./idea/expui/general/redo.svg?url"; +import arrowClockwiseDark from "./idea/expui/general/redo_dark.svg?url"; +import arrowCounterClockwiseLight from "./idea/expui/general/undo.svg?url"; +import arrowCounterClockwiseDark from "./idea/expui/general/undo_dark.svg?url"; +import bellLight from "./idea/expui/toolwindows/notifications.svg?url"; +import bellDark from "./idea/expui/toolwindows/notifications_dark.svg?url"; +import bugLight from "./idea/expui/run/debug.svg?url"; +import bugDark from "./idea/expui/run/debug_dark.svg?url"; +import caretDownLight from "./idea/expui/general/chevronDown.svg?url"; +import caretDownDark from "./idea/expui/general/chevronDown_dark.svg?url"; +import caretLeftLight from "./idea/expui/general/chevronLeft.svg?url"; +import caretLeftDark from "./idea/expui/general/chevronLeft_dark.svg?url"; +import caretRightLight from "./idea/expui/general/chevronRight.svg?url"; +import caretRightDark from "./idea/expui/general/chevronRight_dark.svg?url"; +import caretUpLight from "./idea/expui/general/chevronUp.svg?url"; +import caretUpDark from "./idea/expui/general/chevronUp_dark.svg?url"; +import checkCircleLight from "./idea/expui/general/successDialog.svg?url"; +import checkCircleDark from "./idea/expui/general/successDialog_dark.svg?url"; +import checkLight from "./idea/expui/general/greenCheckmark.svg?url"; +import checkDark from "./idea/expui/general/greenCheckmark_dark.svg?url"; +import chevronDownLight from "./idea/expui/general/chevronDown.svg?url"; +import chevronDownDark from "./idea/expui/general/chevronDown_dark.svg?url"; +import chevronLeftLight from "./idea/expui/general/chevronLeft.svg?url"; +import chevronLeftDark from "./idea/expui/general/chevronLeft_dark.svg?url"; +import chevronRightLight from "./idea/expui/general/chevronRight.svg?url"; +import chevronRightDark from "./idea/expui/general/chevronRight_dark.svg?url"; +import chevronUpLight from "./idea/expui/general/chevronUp.svg?url"; +import chevronUpDark from "./idea/expui/general/chevronUp_dark.svg?url"; +import clockCounterClockwiseLight from "./idea/expui/general/history.svg?url"; +import clockCounterClockwiseDark from "./idea/expui/general/history_dark.svg?url"; +import copyLight from "./idea/expui/general/copy.svg?url"; +import copyDark from "./idea/expui/general/copy_dark.svg?url"; +import dotsThreeLight from "./idea/expui/general/moreHorizontal.svg?url"; +import dotsThreeDark from "./idea/expui/general/moreHorizontal_dark.svg?url"; +import downloadLight from "./idea/expui/general/download.svg?url"; +import downloadDark from "./idea/expui/general/download_dark.svg?url"; +import fileLight from "./idea/fileTypes/text.svg?url"; +import filePlusLight from "./idea/expui/actions/addFile.svg?url"; +import filePlusDark from "./idea/expui/actions/addFile_dark.svg?url"; +import fileTextLight from "./idea/fileTypes/text.svg?url"; +import floppyDiskLight from "./idea/expui/general/save.svg?url"; +import floppyDiskDark from "./idea/expui/general/save_dark.svg?url"; +import folderLight from "./idea/expui/nodes/folder.svg?url"; +import folderDark from "./idea/expui/nodes/folder_dark.svg?url"; +import folderPlusLight from "./idea/expui/actions/newFolder.svg?url"; +import folderPlusDark from "./idea/expui/actions/newFolder_dark.svg?url"; +import funnelLight from "./idea/expui/general/filter.svg?url"; +import funnelDark from "./idea/expui/general/filter_dark.svg?url"; +import gearLight from "./idea/expui/general/settings.svg?url"; +import gearDark from "./idea/expui/general/settings_dark.svg?url"; +import gitBranchLight from "./idea/vcs/branch.svg?url"; +import gitBranchDark from "./idea/vcs/branch_dark.svg?url"; +import gitCommitLight from "./idea/expui/vcs/commit.svg?url"; +import gitCommitDark from "./idea/expui/vcs/commit_dark.svg?url"; +import gitDiffLight from "./idea/expui/vcs/diff.svg?url"; +import gitDiffDark from "./idea/expui/vcs/diff_dark.svg?url"; +import gitMergeLight from "./idea/expui/vcs/merge.svg?url"; +import gitMergeDark from "./idea/expui/vcs/merge_dark.svg?url"; +import infoLight from "./idea/expui/general/informationDialog.svg?url"; +import infoDark from "./idea/expui/general/informationDialog_dark.svg?url"; +import keyboardLight from "./idea/expui/general/keyboard.svg?url"; +import keyboardDark from "./idea/expui/general/keyboard_dark.svg?url"; +import lockLight from "./idea/expui/general/locked.svg?url"; +import lockDark from "./idea/expui/general/locked_dark.svg?url"; +import lockOpenLight from "./idea/expui/general/unlocked.svg?url"; +import lockOpenDark from "./idea/expui/general/unlocked_dark.svg?url"; +import magnifyingGlassLight from "./idea/expui/general/search.svg?url"; +import magnifyingGlassDark from "./idea/expui/general/search_dark.svg?url"; +import minusLight from "./idea/expui/general/remove.svg?url"; +import minusDark from "./idea/expui/general/remove_dark.svg?url"; +import openExternalLight from "./idea/expui/ide/externalLink.svg?url"; +import openExternalDark from "./idea/expui/ide/externalLink_dark.svg?url"; +import pauseLight from "./idea/expui/run/pause.svg?url"; +import pauseDark from "./idea/expui/run/pause_dark.svg?url"; +import pencilLight from "./idea/expui/general/edit.svg?url"; +import pencilDark from "./idea/expui/general/edit_dark.svg?url"; +import playLight from "./idea/expui/run/run.svg?url"; +import playDark from "./idea/expui/run/run_dark.svg?url"; +import plusLight from "./idea/expui/general/add.svg?url"; +import plusDark from "./idea/expui/general/add_dark.svg?url"; +import pushPinLight from "./idea/expui/general/pin.svg?url"; +import pushPinDark from "./idea/expui/general/pin_dark.svg?url"; +import questionLight from "./idea/expui/general/questionDialog.svg?url"; +import questionDark from "./idea/expui/general/questionDialog_dark.svg?url"; +import refreshLight from "./idea/expui/general/refresh.svg?url"; +import refreshDark from "./idea/expui/general/refresh_dark.svg?url"; +import stopLight from "./idea/expui/run/stop.svg?url"; +import stopDark from "./idea/expui/run/stop_dark.svg?url"; +import trashLight from "./idea/expui/general/delete.svg?url"; +import trashDark from "./idea/expui/general/delete_dark.svg?url"; +import uploadLight from "./idea/expui/general/upload.svg?url"; +import uploadDark from "./idea/expui/general/upload_dark.svg?url"; +import userLight from "./idea/expui/general/user.svg?url"; +import userDark from "./idea/expui/general/user_dark.svg?url"; +import warningCircleLight from "./idea/expui/general/warningDialog.svg?url"; +import warningCircleDark from "./idea/expui/general/warningDialog_dark.svg?url"; +import warningLight from "./idea/expui/general/warningDialog.svg?url"; +import warningDark from "./idea/expui/general/warningDialog_dark.svg?url"; +import xCircleLight from "./idea/expui/general/errorDialog.svg?url"; +import xCircleDark from "./idea/expui/general/errorDialog_dark.svg?url"; +import xLight from "./idea/expui/general/close.svg?url"; +import xDark from "./idea/expui/general/close_dark.svg?url"; + +export interface IdeaIconAsset { + light: string; + dark: string; +} + +export const ideaIconAssets: Record = { + ArrowClockwiseIcon: { light: arrowClockwiseLight, dark: arrowClockwiseDark }, + ArrowCounterClockwiseIcon: { light: arrowCounterClockwiseLight, dark: arrowCounterClockwiseDark }, + BellIcon: { light: bellLight, dark: bellDark }, + BugIcon: { light: bugLight, dark: bugDark }, + CaretDownIcon: { light: caretDownLight, dark: caretDownDark }, + CaretLeftIcon: { light: caretLeftLight, dark: caretLeftDark }, + CaretRightIcon: { light: caretRightLight, dark: caretRightDark }, + CaretUpIcon: { light: caretUpLight, dark: caretUpDark }, + CheckCircleIcon: { light: checkCircleLight, dark: checkCircleDark }, + CheckIcon: { light: checkLight, dark: checkDark }, + ChevronDownIcon: { light: chevronDownLight, dark: chevronDownDark }, + ChevronLeftIcon: { light: chevronLeftLight, dark: chevronLeftDark }, + ChevronRightIcon: { light: chevronRightLight, dark: chevronRightDark }, + ChevronUpIcon: { light: chevronUpLight, dark: chevronUpDark }, + ClockCounterClockwiseIcon: { light: clockCounterClockwiseLight, dark: clockCounterClockwiseDark }, + CopyIcon: { light: copyLight, dark: copyDark }, + DotsThreeIcon: { light: dotsThreeLight, dark: dotsThreeDark }, + DownloadIcon: { light: downloadLight, dark: downloadDark }, + FileIcon: { light: fileLight, dark: fileLight }, + FilePlusIcon: { light: filePlusLight, dark: filePlusDark }, + FileTextIcon: { light: fileTextLight, dark: fileTextLight }, + FloppyDiskIcon: { light: floppyDiskLight, dark: floppyDiskDark }, + FolderIcon: { light: folderLight, dark: folderDark }, + FolderPlusIcon: { light: folderPlusLight, dark: folderPlusDark }, + FunnelIcon: { light: funnelLight, dark: funnelDark }, + GearIcon: { light: gearLight, dark: gearDark }, + GitBranchIcon: { light: gitBranchLight, dark: gitBranchDark }, + GitCommitIcon: { light: gitCommitLight, dark: gitCommitDark }, + GitDiffIcon: { light: gitDiffLight, dark: gitDiffDark }, + GitMergeIcon: { light: gitMergeLight, dark: gitMergeDark }, + InfoIcon: { light: infoLight, dark: infoDark }, + KeyboardIcon: { light: keyboardLight, dark: keyboardDark }, + LockIcon: { light: lockLight, dark: lockDark }, + LockOpenIcon: { light: lockOpenLight, dark: lockOpenDark }, + MagnifyingGlassIcon: { light: magnifyingGlassLight, dark: magnifyingGlassDark }, + MinusIcon: { light: minusLight, dark: minusDark }, + OpenExternalIcon: { light: openExternalLight, dark: openExternalDark }, + PauseIcon: { light: pauseLight, dark: pauseDark }, + PencilIcon: { light: pencilLight, dark: pencilDark }, + PlayIcon: { light: playLight, dark: playDark }, + PlusIcon: { light: plusLight, dark: plusDark }, + PushPinIcon: { light: pushPinLight, dark: pushPinDark }, + QuestionIcon: { light: questionLight, dark: questionDark }, + RefreshIcon: { light: refreshLight, dark: refreshDark }, + StopIcon: { light: stopLight, dark: stopDark }, + TrashIcon: { light: trashLight, dark: trashDark }, + UploadIcon: { light: uploadLight, dark: uploadDark }, + UserIcon: { light: userLight, dark: userDark }, + WarningCircleIcon: { light: warningCircleLight, dark: warningCircleDark }, + WarningIcon: { light: warningLight, dark: warningDark }, + XCircleIcon: { light: xCircleLight, dark: xCircleDark }, + XIcon: { light: xLight, dark: xDark }, +}; diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/addFile.svg b/windows/tauri/src/ui/icons/idea/expui/actions/addFile.svg new file mode 100644 index 000000000..c47513163 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/addFile.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/addFile_dark.svg b/windows/tauri/src/ui/icons/idea/expui/actions/addFile_dark.svg new file mode 100644 index 000000000..843fd69c4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/addFile_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/newFolder.svg b/windows/tauri/src/ui/icons/idea/expui/actions/newFolder.svg new file mode 100644 index 000000000..4b43b5855 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/newFolder.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/newFolder_dark.svg b/windows/tauri/src/ui/icons/idea/expui/actions/newFolder_dark.svg new file mode 100644 index 000000000..c33a67ba4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/newFolder_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/add.svg b/windows/tauri/src/ui/icons/idea/expui/general/add.svg new file mode 100644 index 000000000..57eaaf561 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/add.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/add_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/add_dark.svg new file mode 100644 index 000000000..397e9321b --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/add_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronDown.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronDown.svg new file mode 100644 index 000000000..3bed7d65a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronDown.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronDown_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronDown_dark.svg new file mode 100644 index 000000000..375ab4dd8 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronDown_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronLeft.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronLeft.svg new file mode 100644 index 000000000..c6c4fa041 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronLeft.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronLeft_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronLeft_dark.svg new file mode 100644 index 000000000..d4284d234 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronLeft_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronRight.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronRight.svg new file mode 100644 index 000000000..5120ed891 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronRight.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronRight_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronRight_dark.svg new file mode 100644 index 000000000..838142106 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronRight_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronUp.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronUp.svg new file mode 100644 index 000000000..e40a745d7 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronUp.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/chevronUp_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/chevronUp_dark.svg new file mode 100644 index 000000000..5ecca2a0c --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/chevronUp_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/close.svg b/windows/tauri/src/ui/icons/idea/expui/general/close.svg new file mode 100644 index 000000000..f26883a45 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/close_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/close_dark.svg new file mode 100644 index 000000000..88693089a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/close_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/copy.svg b/windows/tauri/src/ui/icons/idea/expui/general/copy.svg new file mode 100644 index 000000000..df3e7429a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/copy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/copy_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/copy_dark.svg new file mode 100644 index 000000000..a7072426d --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/copy_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/delete.svg b/windows/tauri/src/ui/icons/idea/expui/general/delete.svg new file mode 100644 index 000000000..a858096ac --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/delete.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/delete_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/delete_dark.svg new file mode 100644 index 000000000..03ff9f241 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/delete_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/download.svg b/windows/tauri/src/ui/icons/idea/expui/general/download.svg new file mode 100644 index 000000000..014f5cee5 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/download.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/download_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/download_dark.svg new file mode 100644 index 000000000..06841c5f7 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/download_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/edit.svg b/windows/tauri/src/ui/icons/idea/expui/general/edit.svg new file mode 100644 index 000000000..bd3c0a391 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/edit_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/edit_dark.svg new file mode 100644 index 000000000..e75126d05 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/edit_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/errorDialog.svg b/windows/tauri/src/ui/icons/idea/expui/general/errorDialog.svg new file mode 100644 index 000000000..5226d6bca --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/errorDialog.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/errorDialog_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/errorDialog_dark.svg new file mode 100644 index 000000000..6162ef026 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/errorDialog_dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/filter.svg b/windows/tauri/src/ui/icons/idea/expui/general/filter.svg new file mode 100644 index 000000000..c51534701 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/filter.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/filter_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/filter_dark.svg new file mode 100644 index 000000000..bde0136ae --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/filter_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark.svg b/windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark.svg new file mode 100644 index 000000000..f9c7c89f4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark_dark.svg new file mode 100644 index 000000000..ce333a7c4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/greenCheckmark_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/history.svg b/windows/tauri/src/ui/icons/idea/expui/general/history.svg new file mode 100644 index 000000000..50a772e9b --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/history.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/history_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/history_dark.svg new file mode 100644 index 000000000..c83b74b16 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/history_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/informationDialog.svg b/windows/tauri/src/ui/icons/idea/expui/general/informationDialog.svg new file mode 100644 index 000000000..479082c59 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/informationDialog.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/informationDialog_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/informationDialog_dark.svg new file mode 100644 index 000000000..0dae67f8c --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/informationDialog_dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/keyboard.svg b/windows/tauri/src/ui/icons/idea/expui/general/keyboard.svg new file mode 100644 index 000000000..bf1a38210 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/keyboard.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/keyboard_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/keyboard_dark.svg new file mode 100644 index 000000000..447bc05ec --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/keyboard_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/locked.svg b/windows/tauri/src/ui/icons/idea/expui/general/locked.svg new file mode 100644 index 000000000..666daddf5 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/locked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/locked_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/locked_dark.svg new file mode 100644 index 000000000..9658ca553 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/locked_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal.svg b/windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal.svg new file mode 100644 index 000000000..2d99b38c8 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal_dark.svg new file mode 100644 index 000000000..7b4ce2802 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/moreHorizontal_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/pin.svg b/windows/tauri/src/ui/icons/idea/expui/general/pin.svg new file mode 100644 index 000000000..9199fc045 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/pin.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/pin_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/pin_dark.svg new file mode 100644 index 000000000..f287b61b7 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/pin_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/questionDialog.svg b/windows/tauri/src/ui/icons/idea/expui/general/questionDialog.svg new file mode 100644 index 000000000..0b560f6f2 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/questionDialog.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/questionDialog_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/questionDialog_dark.svg new file mode 100644 index 000000000..ceeb8e074 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/questionDialog_dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/redo.svg b/windows/tauri/src/ui/icons/idea/expui/general/redo.svg new file mode 100644 index 000000000..862b8f574 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/redo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/redo_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/redo_dark.svg new file mode 100644 index 000000000..a39093042 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/redo_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/refresh.svg b/windows/tauri/src/ui/icons/idea/expui/general/refresh.svg new file mode 100644 index 000000000..7a4c73dfd --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/refresh.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/refresh_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/refresh_dark.svg new file mode 100644 index 000000000..3362992af --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/refresh_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/remove.svg b/windows/tauri/src/ui/icons/idea/expui/general/remove.svg new file mode 100644 index 000000000..05801bb86 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/remove.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/remove_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/remove_dark.svg new file mode 100644 index 000000000..f37204d1e --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/remove_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/save.svg b/windows/tauri/src/ui/icons/idea/expui/general/save.svg new file mode 100644 index 000000000..28089cdb1 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/save.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/save_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/save_dark.svg new file mode 100644 index 000000000..2372e3e9b --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/save_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/search.svg b/windows/tauri/src/ui/icons/idea/expui/general/search.svg new file mode 100644 index 000000000..021b0c394 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/search.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/search_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/search_dark.svg new file mode 100644 index 000000000..d5a82d9c1 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/search_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/settings.svg b/windows/tauri/src/ui/icons/idea/expui/general/settings.svg new file mode 100644 index 000000000..c30de8209 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/settings.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/settings_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/settings_dark.svg new file mode 100644 index 000000000..62f328167 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/settings_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/successDialog.svg b/windows/tauri/src/ui/icons/idea/expui/general/successDialog.svg new file mode 100644 index 000000000..70f19c47e --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/successDialog.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/successDialog_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/successDialog_dark.svg new file mode 100644 index 000000000..2bbe52d09 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/successDialog_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/undo.svg b/windows/tauri/src/ui/icons/idea/expui/general/undo.svg new file mode 100644 index 000000000..7a98c7583 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/undo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/undo_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/undo_dark.svg new file mode 100644 index 000000000..2fa3c0d42 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/undo_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/unlocked.svg b/windows/tauri/src/ui/icons/idea/expui/general/unlocked.svg new file mode 100644 index 000000000..305bcde68 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/unlocked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/unlocked_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/unlocked_dark.svg new file mode 100644 index 000000000..a53f82243 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/unlocked_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/upload.svg b/windows/tauri/src/ui/icons/idea/expui/general/upload.svg new file mode 100644 index 000000000..b26837f5f --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/upload.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/upload_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/upload_dark.svg new file mode 100644 index 000000000..2241155ef --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/upload_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/user.svg b/windows/tauri/src/ui/icons/idea/expui/general/user.svg new file mode 100644 index 000000000..b0d3ad131 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/user.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/user_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/user_dark.svg new file mode 100644 index 000000000..71816fd61 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/user_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/warningDialog.svg b/windows/tauri/src/ui/icons/idea/expui/general/warningDialog.svg new file mode 100644 index 000000000..4d4740b82 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/warningDialog.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/warningDialog_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/warningDialog_dark.svg new file mode 100644 index 000000000..69b5c4e3a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/warningDialog_dark.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/ide/externalLink.svg b/windows/tauri/src/ui/icons/idea/expui/ide/externalLink.svg new file mode 100644 index 000000000..b2b1f496b --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/ide/externalLink.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/windows/tauri/src/ui/icons/idea/expui/ide/externalLink_dark.svg b/windows/tauri/src/ui/icons/idea/expui/ide/externalLink_dark.svg new file mode 100644 index 000000000..b30959431 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/ide/externalLink_dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/folder.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/folder.svg new file mode 100644 index 000000000..7ece6b711 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/folder.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/folder_dark.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/folder_dark.svg new file mode 100644 index 000000000..0af492bad --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/folder_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/debug.svg b/windows/tauri/src/ui/icons/idea/expui/run/debug.svg new file mode 100644 index 000000000..c1279337a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/debug.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/debug_dark.svg b/windows/tauri/src/ui/icons/idea/expui/run/debug_dark.svg new file mode 100644 index 000000000..757d0b50d --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/debug_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/pause.svg b/windows/tauri/src/ui/icons/idea/expui/run/pause.svg new file mode 100644 index 000000000..4d12f24f2 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/pause.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/pause_dark.svg b/windows/tauri/src/ui/icons/idea/expui/run/pause_dark.svg new file mode 100644 index 000000000..1907d98f0 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/pause_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/run.svg b/windows/tauri/src/ui/icons/idea/expui/run/run.svg new file mode 100644 index 000000000..dd11f50d3 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/run.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/run_dark.svg b/windows/tauri/src/ui/icons/idea/expui/run/run_dark.svg new file mode 100644 index 000000000..0c199c7de --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/run_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/stop.svg b/windows/tauri/src/ui/icons/idea/expui/run/stop.svg new file mode 100644 index 000000000..845ab7622 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/stop.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/run/stop_dark.svg b/windows/tauri/src/ui/icons/idea/expui/run/stop_dark.svg new file mode 100644 index 000000000..d9ee43c30 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/run/stop_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications.svg new file mode 100644 index 000000000..956e3cbef --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications_dark.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications_dark.svg new file mode 100644 index 000000000..a456c6b5a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/notifications_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/vcs/commit.svg b/windows/tauri/src/ui/icons/idea/expui/vcs/commit.svg new file mode 100644 index 000000000..3098d179b --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/vcs/commit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/vcs/commit_dark.svg b/windows/tauri/src/ui/icons/idea/expui/vcs/commit_dark.svg new file mode 100644 index 000000000..7caf397cb --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/vcs/commit_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/vcs/diff.svg b/windows/tauri/src/ui/icons/idea/expui/vcs/diff.svg new file mode 100644 index 000000000..79e21abd7 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/vcs/diff.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/vcs/diff_dark.svg b/windows/tauri/src/ui/icons/idea/expui/vcs/diff_dark.svg new file mode 100644 index 000000000..1d85078eb --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/vcs/diff_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/vcs/merge.svg b/windows/tauri/src/ui/icons/idea/expui/vcs/merge.svg new file mode 100644 index 000000000..e097c49eb --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/vcs/merge.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/vcs/merge_dark.svg b/windows/tauri/src/ui/icons/idea/expui/vcs/merge_dark.svg new file mode 100644 index 000000000..9e903a8a9 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/vcs/merge_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/fileTypes/text.svg b/windows/tauri/src/ui/icons/idea/fileTypes/text.svg new file mode 100644 index 000000000..6289b2fda --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/fileTypes/text.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/vcs/branch.svg b/windows/tauri/src/ui/icons/idea/vcs/branch.svg new file mode 100644 index 000000000..aef4fdf29 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/vcs/branch.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/vcs/branch_dark.svg b/windows/tauri/src/ui/icons/idea/vcs/branch_dark.svg new file mode 100644 index 000000000..2870a3a12 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/vcs/branch_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + From d5cac7f8723ea8db201384cb1099795f9e45d365 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:07:19 +0800 Subject: [PATCH 03/17] feat(windows): render IntelliJ icons through the app icon funnel createIconComponent resolves mapped display names to dual light/dark asset instances; CSS toggles the active variant via data-theme-type so theme switches need no rerender. Unmapped exports keep the lucide fallback, IconProps stay unchanged, and weight/strokeWidth are no-ops for fixed-color assets. --- windows/tauri/src/ui/icons.css | 32 ++++++++++++++++++++++++ windows/tauri/src/ui/icons.test.tsx | 38 +++++++++++++++++++++++------ windows/tauri/src/ui/icons.tsx | 32 ++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 windows/tauri/src/ui/icons.css diff --git a/windows/tauri/src/ui/icons.css b/windows/tauri/src/ui/icons.css new file mode 100644 index 000000000..82d54b788 --- /dev/null +++ b/windows/tauri/src/ui/icons.css @@ -0,0 +1,32 @@ +/* + * IntelliJ icon assets are rendered as dual light/dark instances. The + * active variant follows the runtime `data-theme-type` attribute set by the + * theme registry, so switching themes needs no React re-render. + */ +.lithe-idea-icon { + display: inline-flex; + align-items: center; + justify-content: center; + flex: none; + line-height: 0; + vertical-align: middle; +} + +.lithe-idea-icon img { + width: 100%; + height: 100%; + pointer-events: none; + user-select: none; +} + +.lithe-idea-icon .lithe-idea-icon-dark { + display: none; +} + +:root[data-theme-type="dark"] .lithe-idea-icon .lithe-idea-icon-light { + display: none; +} + +:root[data-theme-type="dark"] .lithe-idea-icon .lithe-idea-icon-dark { + display: block; +} diff --git a/windows/tauri/src/ui/icons.test.tsx b/windows/tauri/src/ui/icons.test.tsx index cef0d2092..9347c416a 100644 --- a/windows/tauri/src/ui/icons.test.tsx +++ b/windows/tauri/src/ui/icons.test.tsx @@ -3,7 +3,7 @@ import { createElement, type ElementType } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import * as AppIcons from "./icons"; -const intentionalHelpIcons = new Set(["Icon", "QuestionIcon"]); +const intentionalHelpIcons = new Set(["Icon"]); const iconEntries = Object.entries(AppIcons).filter( ([exportName]) => exportName === "Icon" || exportName.endsWith("Icon"), @@ -34,16 +34,10 @@ describe("application icon mappings", () => { } }); - test("maps representative controls to the expected Lucide icons", () => { + test("maps unmapped controls to the expected Lucide icons", () => { const cases: Array<[ElementType, string]> = [ [AppIcons.FilesIcon, "lucide-files"], - [AppIcons.MagnifyingGlassIcon, "lucide-search"], - [AppIcons.GearIcon, "lucide-settings"], [AppIcons.WindowExpandIcon, "lucide-maximize2"], - [AppIcons.XIcon, "lucide-x"], - [AppIcons.WarningIcon, "lucide-triangle-alert"], - [AppIcons.WarningCircleIcon, "lucide-circle-alert"], - [AppIcons.OpenExternalIcon, "lucide-external-link"], [AppIcons.ArrowSquareOutIcon, "lucide-external-link"], [AppIcons.SquareIcon, "lucide-square"], ]; @@ -52,4 +46,32 @@ describe("application icon mappings", () => { expect(renderIcon(IconComponent)).toContain(expectedClass); } }); + + test("renders mapped IntelliJ icons as dual-variant image assets", () => { + const mapped: Array = [ + "MagnifyingGlassIcon", + "GearIcon", + "XIcon", + "WarningIcon", + "WarningCircleIcon", + "OpenExternalIcon", + "GitBranchIcon", + "PlayIcon", + "QuestionIcon", + ]; + for (const exportName of mapped) { + const markup = renderIcon(AppIcons[exportName] as ElementType); + expect(markup).toContain("lithe-idea-icon"); + expect(markup.match(/ { + const markup = renderToStaticMarkup( + createElement(AppIcons.TrashIcon as ElementType, { title: "delete action" }), + ); + expect(markup).toContain('alt="delete action"'); + }); }); diff --git a/windows/tauri/src/ui/icons.tsx b/windows/tauri/src/ui/icons.tsx index 42a5a30e6..6fb56dddc 100644 --- a/windows/tauri/src/ui/icons.tsx +++ b/windows/tauri/src/ui/icons.tsx @@ -10,6 +10,8 @@ import { type SVGProps, } from "react"; import { CircleHelp, icons as lucideIcons } from "lucide-react"; +import { ideaIconAssets } from "./icons/idea-assets.generated"; +import "./icons.css"; const legacyIconCompatibility: Record> = { AiLoading: lucideIcons.LoaderCircle, @@ -163,6 +165,36 @@ function createIconComponent(IconComponent: ComponentType, displayName: str } as CSSProperties) : style; + // IntelliJ assets are fixed-color SVGs with light/dark variants; render + // both and let CSS pick the active one, so theme switches need no rerender. + // weight/strokeWidth have no effect on these (colorPolicy: fixed). + const asset = ideaIconAssets[displayName]; + if (asset) { + const { className, id, onClick } = iconProps; + return createElement( + "span", + { + ref: ref as any, + className: ["lithe-idea-icon", className].filter(Boolean).join(" "), + id, + onClick, + style: { width: size, height: size, ...nextStyle }, + }, + createElement("img", { + src: asset.light, + alt: title ?? alt ?? "", + className: "lithe-idea-icon-light", + draggable: false, + }), + createElement("img", { + src: asset.dark, + alt: "", + className: "lithe-idea-icon-dark", + draggable: false, + }), + ); + } + return createElement(IconComponent, { ...iconProps, ref, From 4015181be29bc7cb0d38dd9ed84e7bbf94257d5c Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:12:55 +0800 Subject: [PATCH 04/17] chore(windows): map long-tail icons and record complete fallback inventory Map 43 additional statically used icons to IntelliJ platform assets (188 SVGs total now vendored) and register every remaining used icon explicitly as a lucide fallback with a note, so the mapping file covers the full 194-icon usage inventory. --- windows/tauri/scripts/idea-icon-mappings.json | 922 +++++++++++++++++- .../src/ui/icons/idea-assets.generated.ts | 129 +++ .../ui/icons/idea/expui/actions/lightning.svg | 4 + .../idea/expui/actions/lightning_dark.svg | 4 + .../idea/expui/actions/realIntentionBulb.svg | 9 + .../expui/actions/realIntentionBulb_dark.svg | 9 + .../icons/idea/expui/bookmarks/bookmark.svg | 4 + .../idea/expui/bookmarks/bookmark_dark.svg | 4 + .../ui/icons/idea/expui/fileTypes/archive.svg | 8 + .../idea/expui/fileTypes/archive_dark.svg | 8 + .../ui/icons/idea/expui/fileTypes/image.svg | 6 + .../icons/idea/expui/fileTypes/image_dark.svg | 6 + .../src/ui/icons/idea/expui/general/cut.svg | 4 + .../ui/icons/idea/expui/general/cut_dark.svg | 4 + .../src/ui/icons/idea/expui/general/down.svg | 4 + .../ui/icons/idea/expui/general/down_dark.svg | 4 + .../src/ui/icons/idea/expui/general/exit.svg | 5 + .../ui/icons/idea/expui/general/exit_dark.svg | 12 + .../idea/expui/general/externalTools.svg | 2 + .../idea/expui/general/externalTools_dark.svg | 2 + .../ui/icons/idea/expui/general/groups.svg | 7 + .../icons/idea/expui/general/groups_dark.svg | 7 + .../ui/icons/idea/expui/general/hashtag.svg | 6 + .../icons/idea/expui/general/hashtag_dark.svg | 6 + .../src/ui/icons/idea/expui/general/hide.svg | 4 + .../ui/icons/idea/expui/general/hide_dark.svg | 4 + .../ui/icons/idea/expui/general/language.svg | 7 + .../idea/expui/general/language_dark.svg | 7 + .../ui/icons/idea/expui/general/layout.svg | 4 + .../icons/idea/expui/general/layout_dark.svg | 4 + .../src/ui/icons/idea/expui/general/left.svg | 4 + .../ui/icons/idea/expui/general/left_dark.svg | 4 + .../ui/icons/idea/expui/general/listFiles.svg | 7 + .../idea/expui/general/listFiles_dark.svg | 7 + .../src/ui/icons/idea/expui/general/right.svg | 4 + .../icons/idea/expui/general/right_dark.svg | 4 + .../src/ui/icons/idea/expui/general/show.svg | 5 + .../ui/icons/idea/expui/general/show_dark.svg | 5 + .../idea/expui/general/splitHorizontally.svg | 4 + .../expui/general/splitHorizontally_dark.svg | 4 + .../idea/expui/general/splitVertically.svg | 4 + .../expui/general/splitVertically_dark.svg | 4 + .../src/ui/icons/idea/expui/general/tree.svg | 6 + .../ui/icons/idea/expui/general/tree_dark.svg | 6 + .../src/ui/icons/idea/expui/general/up.svg | 4 + .../ui/icons/idea/expui/general/up_dark.svg | 4 + .../src/ui/icons/idea/expui/image/zoomIn.svg | 6 + .../ui/icons/idea/expui/image/zoomIn_dark.svg | 6 + .../src/ui/icons/idea/expui/image/zoomOut.svg | 5 + .../icons/idea/expui/image/zoomOut_dark.svg | 5 + .../src/ui/icons/idea/expui/javaee/home.svg | 7 + .../ui/icons/idea/expui/javaee/home_dark.svg | 7 + .../ui/icons/idea/expui/nodes/dataTables.svg | 7 + .../idea/expui/nodes/dataTables_dark.svg | 14 + .../src/ui/icons/idea/expui/nodes/desktop.svg | 5 + .../icons/idea/expui/nodes/desktop_dark.svg | 5 + .../ui/icons/idea/expui/nodes/function.svg | 5 + .../icons/idea/expui/nodes/function_dark.svg | 5 + .../idea/expui/toolwindows/documentation.svg | 8 + .../expui/toolwindows/documentation_dark.svg | 8 + .../icons/idea/expui/toolwindows/messages.svg | 7 + .../idea/expui/toolwindows/messages_dark.svg | 14 + .../icons/idea/expui/toolwindows/palette.svg | 8 + .../idea/expui/toolwindows/palette_dark.svg | 8 + .../expui/toolwindows/toolWindowDataView.svg | 10 + .../toolwindows/toolWindowDataView_dark.svg | 10 + .../ui/icons/idea/expui/toolwindows/web.svg | 4 + .../icons/idea/expui/toolwindows/web_dark.svg | 4 + 68 files changed, 1388 insertions(+), 52 deletions(-) create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/lightning.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/lightning_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/fileTypes/archive.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/fileTypes/archive_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/fileTypes/image.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/fileTypes/image_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/cut.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/cut_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/down.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/down_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/exit.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/exit_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/externalTools.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/externalTools_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/groups.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/groups_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/hashtag.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/hashtag_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/hide.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/hide_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/language.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/language_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/layout.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/layout_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/left.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/left_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/listFiles.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/listFiles_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/right.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/right_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/show.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/show_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/splitVertically.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/splitVertically_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/tree.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/tree_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/up.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/general/up_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/image/zoomIn.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/image/zoomIn_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/image/zoomOut.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/image/zoomOut_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/javaee/home.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/javaee/home_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/dataTables.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/dataTables_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/desktop.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/desktop_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/function.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/nodes/function_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/messages.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/messages_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/palette.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/palette_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView_dark.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/web.svg create mode 100644 windows/tauri/src/ui/icons/idea/expui/toolwindows/web_dark.svg diff --git a/windows/tauri/scripts/idea-icon-mappings.json b/windows/tauri/scripts/idea-icon-mappings.json index 44d9d94ad..33263c57d 100644 --- a/windows/tauri/scripts/idea-icon-mappings.json +++ b/windows/tauri/scripts/idea-icon-mappings.json @@ -1,62 +1,880 @@ { "description": "Lithe icon export name -> IntelliJ platform icon asset (relative to intellij-community platform/icons/src). Managed by scripts/generate-idea-icons.ts. Icons absent from this list keep their lucide fallback. colorPolicy defaults to 'fixed' (IDEA colors as-is); 'fallback' entries document why an IDEA asset was not used.", "icons": [ - { "icon": "PlusIcon", "source": "expui/general/add.svg" }, - { "icon": "XIcon", "source": "expui/general/close.svg" }, - { "icon": "CheckIcon", "source": "expui/general/greenCheckmark.svg" }, - { "icon": "CheckCircleIcon", "source": "expui/general/successDialog.svg" }, - { "icon": "TrashIcon", "source": "expui/general/delete.svg" }, - { "icon": "CaretDownIcon", "source": "expui/general/chevronDown.svg" }, - { "icon": "ChevronDownIcon", "source": "expui/general/chevronDown.svg" }, - { "icon": "CaretUpIcon", "source": "expui/general/chevronUp.svg" }, - { "icon": "ChevronUpIcon", "source": "expui/general/chevronUp.svg" }, - { "icon": "CaretLeftIcon", "source": "expui/general/chevronLeft.svg" }, - { "icon": "ChevronLeftIcon", "source": "expui/general/chevronLeft.svg" }, - { "icon": "CaretRightIcon", "source": "expui/general/chevronRight.svg" }, - { "icon": "ChevronRightIcon", "source": "expui/general/chevronRight.svg" }, - { "icon": "MagnifyingGlassIcon", "source": "expui/general/search.svg" }, - { "icon": "GearIcon", "source": "expui/general/settings.svg" }, - { "icon": "RefreshIcon", "source": "expui/general/refresh.svg" }, - { "icon": "CopyIcon", "source": "expui/general/copy.svg" }, - { "icon": "DownloadIcon", "source": "expui/general/download.svg" }, - { "icon": "UploadIcon", "source": "expui/general/upload.svg" }, - { "icon": "FloppyDiskIcon", "source": "expui/general/save.svg" }, - { "icon": "ArrowCounterClockwiseIcon", "source": "expui/general/undo.svg" }, - { "icon": "ArrowClockwiseIcon", "source": "expui/general/redo.svg" }, - { "icon": "WarningIcon", "source": "expui/general/warningDialog.svg" }, - { "icon": "WarningCircleIcon", "source": "expui/general/warningDialog.svg" }, - { "icon": "InfoIcon", "source": "expui/general/informationDialog.svg" }, - { "icon": "QuestionIcon", "source": "expui/general/questionDialog.svg" }, - { "icon": "XCircleIcon", "source": "expui/general/errorDialog.svg" }, - { "icon": "MinusIcon", "source": "expui/general/remove.svg" }, - { "icon": "DotsThreeIcon", "source": "expui/general/moreHorizontal.svg" }, - { "icon": "KeyboardIcon", "source": "expui/general/keyboard.svg" }, - { "icon": "ClockCounterClockwiseIcon", "source": "expui/general/history.svg" }, - { "icon": "FunnelIcon", "source": "expui/general/filter.svg" }, - { "icon": "PencilIcon", "source": "expui/general/edit.svg" }, - { "icon": "LockIcon", "source": "expui/general/locked.svg" }, - { "icon": "LockOpenIcon", "source": "expui/general/unlocked.svg" }, - { "icon": "UserIcon", "source": "expui/general/user.svg" }, - { "icon": "PushPinIcon", "source": "expui/general/pin.svg" }, - { "icon": "GitBranchIcon", "source": "vcs/branch.svg" }, - { "icon": "GitCommitIcon", "source": "expui/vcs/commit.svg" }, - { "icon": "GitMergeIcon", "source": "expui/vcs/merge.svg" }, - { "icon": "GitDiffIcon", "source": "expui/vcs/diff.svg" }, - { "icon": "PlayIcon", "source": "expui/run/run.svg" }, - { "icon": "StopIcon", "source": "expui/run/stop.svg" }, - { "icon": "PauseIcon", "source": "expui/run/pause.svg" }, - { "icon": "BugIcon", "source": "expui/run/debug.svg" }, - { "icon": "FolderIcon", "source": "expui/nodes/folder.svg" }, - { "icon": "FolderPlusIcon", "source": "expui/actions/newFolder.svg" }, - { "icon": "FilePlusIcon", "source": "expui/actions/addFile.svg" }, - { "icon": "FileIcon", "source": "fileTypes/text.svg" }, - { "icon": "FileTextIcon", "source": "fileTypes/text.svg" }, - { "icon": "OpenExternalIcon", "source": "expui/ide/externalLink.svg" }, - { "icon": "BellIcon", "source": "expui/toolwindows/notifications.svg" }, + { + "icon": "AiLoadingIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArchiveIcon", + "source": "expui/fileTypes/archive.svg" + }, + { + "icon": "ArrowBendDownLeftIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArrowClockwiseIcon", + "source": "expui/general/redo.svg" + }, + { + "icon": "ArrowCounterClockwiseIcon", + "source": "expui/general/undo.svg" + }, + { + "icon": "ArrowDownIcon", + "source": "expui/general/down.svg" + }, + { + "icon": "ArrowFatLineDownIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArrowLeftIcon", + "source": "expui/general/left.svg" + }, + { + "icon": "ArrowRightIcon", + "source": "expui/general/right.svg" + }, + { + "icon": "ArrowSquareOutIcon", + "source": "expui/ide/externalLink.svg" + }, + { + "icon": "ArrowUpIcon", + "source": "expui/general/up.svg" + }, + { + "icon": "ArrowsClockwiseIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArrowsInIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArrowsInLineVerticalIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArrowsLeftRightIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ArrowsOutIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "BellIcon", + "source": "expui/toolwindows/notifications.svg" + }, + { + "icon": "BookOpenIcon", + "source": "expui/toolwindows/documentation.svg" + }, + { + "icon": "BookmarkIcon", + "source": "expui/bookmarks/bookmark.svg" + }, + { + "icon": "BracketsCurlyIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "BrainIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "BroomIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "BugBeetleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "BugIcon", + "source": "expui/run/debug.svg" + }, + { + "icon": "CalendarIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CaretDoubleLeftIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CaretDoubleRightIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CaretDoubleUpIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CaretDownIcon", + "source": "expui/general/chevronDown.svg" + }, + { + "icon": "CaretLeftIcon", + "source": "expui/general/chevronLeft.svg" + }, + { + "icon": "CaretRightIcon", + "source": "expui/general/chevronRight.svg" + }, + { + "icon": "CaretUpIcon", + "source": "expui/general/chevronUp.svg" + }, + { + "icon": "ChatCircleTextIcon", + "source": "expui/toolwindows/messages.svg" + }, + { + "icon": "CheckCircleIcon", + "source": "expui/general/successDialog.svg" + }, + { + "icon": "CheckIcon", + "source": "expui/general/greenCheckmark.svg" + }, + { + "icon": "ChevronDownIcon", + "source": "expui/general/chevronDown.svg" + }, + { + "icon": "ChevronLeftIcon", + "source": "expui/general/chevronLeft.svg" + }, + { + "icon": "ChevronRightIcon", + "source": "expui/general/chevronRight.svg" + }, + { + "icon": "ChevronUpIcon", + "source": "expui/general/chevronUp.svg" + }, + { + "icon": "CircleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CirclesThreeIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ClipboardIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ClipboardTextIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ClockCounterClockwiseIcon", + "source": "expui/general/history.svg" + }, + { + "icon": "ClockIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CloudArrowDownIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CloudCheckIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CloudIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CloudSlashIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CloudWarningIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CodeBlockIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CodeIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ColumnsIcon", + "source": "expui/general/splitVertically.svg" + }, + { + "icon": "CommandIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CopyIcon", + "source": "expui/general/copy.svg" + }, + { + "icon": "CopySimpleIcon", + "source": "expui/general/copy.svg" + }, + { + "icon": "CornersInIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CornersOutIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CreditCardIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CubeIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "CursorClickIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "DatabaseIcon", + "source": "expui/toolwindows/toolWindowDataView.svg" + }, + { + "icon": "DotOutlineIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "DotsThreeIcon", + "source": "expui/general/moreHorizontal.svg" + }, + { + "icon": "DownloadIcon", + "source": "expui/general/download.svg" + }, + { + "icon": "DownloadSimpleIcon", + "source": "expui/general/download.svg" + }, + { + "icon": "EyeIcon", + "source": "expui/general/show.svg" + }, + { + "icon": "EyeSlashIcon", + "source": "expui/general/hide.svg" + }, + { + "icon": "FadersHorizontalIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "FileCodeIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "FileIcon", + "source": "fileTypes/text.svg" + }, + { + "icon": "FilePlusIcon", + "source": "expui/actions/addFile.svg" + }, + { + "icon": "FileTextIcon", + "source": "fileTypes/text.svg" + }, + { + "icon": "FilesIcon", + "source": "expui/general/listFiles.svg" + }, + { + "icon": "FlipHorizontalIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "FlipVerticalIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "FloppyDiskIcon", + "source": "expui/general/save.svg" + }, + { + "icon": "FolderIcon", + "source": "expui/nodes/folder.svg" + }, + { + "icon": "FolderOpenIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "FolderPlusIcon", + "source": "expui/actions/newFolder.svg" + }, + { + "icon": "FolderSimpleStarIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "FunctionIcon", + "source": "expui/nodes/function.svg" + }, + { + "icon": "FunnelIcon", + "source": "expui/general/filter.svg" + }, + { + "icon": "GearIcon", + "source": "expui/general/settings.svg" + }, + { + "icon": "GearSixIcon", + "source": "expui/general/settings.svg" + }, + { + "icon": "GitBranchIcon", + "source": "vcs/branch.svg" + }, + { + "icon": "GitCommitIcon", + "source": "expui/vcs/commit.svg" + }, + { + "icon": "GitDiffIcon", + "source": "expui/vcs/diff.svg" + }, + { + "icon": "GitGraphIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "GitMergeIcon", + "source": "expui/vcs/merge.svg" + }, + { + "icon": "GitPullRequestIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "GithubLogoIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "GlobeHemisphereWestIcon", + "source": "expui/toolwindows/web.svg" + }, + { + "icon": "GlobeIcon", + "source": "expui/toolwindows/web.svg" + }, + { + "icon": "HardDrivesIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "HashIcon", + "source": "expui/general/hashtag.svg" + }, + { + "icon": "HouseIcon", + "source": "expui/javaee/home.svg" + }, + { + "icon": "ImageIcon", + "source": "expui/fileTypes/image.svg" + }, + { + "icon": "InfoIcon", + "source": "expui/general/informationDialog.svg" + }, + { + "icon": "KeyIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "KeyboardIcon", + "source": "expui/general/keyboard.svg" + }, + { + "icon": "LaptopIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "LightbulbIcon", + "source": "expui/actions/realIntentionBulb.svg" + }, + { + "icon": "LightningIcon", + "source": "expui/actions/lightning.svg" + }, + { + "icon": "LightningSlashIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "LinkIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "LinkSimpleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ListBulletsIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ListChecksIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ListIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "LockIcon", + "source": "expui/general/locked.svg" + }, + { + "icon": "LockKeyIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "LockOpenIcon", + "source": "expui/general/unlocked.svg" + }, + { + "icon": "MagicWandIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "MagnifyingGlassIcon", + "source": "expui/general/search.svg" + }, + { + "icon": "MagnifyingGlassMinusIcon", + "source": "expui/image/zoomOut.svg" + }, + { + "icon": "MagnifyingGlassPlusIcon", + "source": "expui/image/zoomIn.svg" + }, + { + "icon": "MegaphoneIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "MicrophoneIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "MinusCircleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "MinusIcon", + "source": "expui/general/remove.svg" + }, + { + "icon": "MoneyIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "MonitorIcon", + "source": "expui/nodes/desktop.svg" + }, + { + "icon": "MoonIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "NavigationArrowIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "NetworkIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "NodesIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "OpenExternalIcon", + "source": "expui/ide/externalLink.svg" + }, + { + "icon": "PackageIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PaintBrushIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PaletteIcon", + "source": "expui/toolwindows/palette.svg" + }, + { + "icon": "PaperPlaneTiltIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PauseIcon", + "source": "expui/run/pause.svg" + }, + { + "icon": "PenIcon", + "source": "expui/general/edit.svg" + }, + { + "icon": "PencilIcon", + "source": "expui/general/edit.svg" + }, + { + "icon": "PencilLineIcon", + "source": "expui/general/edit.svg" + }, + { + "icon": "PencilSimpleIcon", + "source": "expui/general/edit.svg" + }, + { + "icon": "PencilSimpleLineIcon", + "source": "expui/general/edit.svg" + }, + { + "icon": "PlayCircleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PlayIcon", + "source": "expui/run/run.svg" + }, + { + "icon": "PlugsConnectedIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PlusCircleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PlusIcon", + "source": "expui/general/add.svg" + }, + { + "icon": "PulseIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PushPinIcon", + "source": "expui/general/pin.svg" + }, + { + "icon": "PushPinSlashIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "PuzzlePieceIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "QuestionIcon", + "source": "expui/general/questionDialog.svg" + }, + { + "icon": "RadioButtonIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "RefreshIcon", + "source": "expui/general/refresh.svg" + }, + { + "icon": "RobotIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "RocketLaunchIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "RowsIcon", + "source": "expui/general/splitHorizontally.svg" + }, + { + "icon": "RowsPlusTopIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ScissorsIcon", + "source": "expui/general/cut.svg" + }, + { + "icon": "ShieldCheckIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ShieldIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "ShieldWarningIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "SidebarSimpleIcon", + "source": "expui/general/layout.svg" + }, + { + "icon": "SignInIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "SignOutIcon", + "source": "expui/general/exit.svg" + }, + { + "icon": "SlidersHorizontalIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "SlidersIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "SparkleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "SquareIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "SquaresFourIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "StackIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "StopIcon", + "source": "expui/run/stop.svg" + }, + { + "icon": "SunIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TableIcon", + "source": "expui/nodes/dataTables.svg" + }, + { + "icon": "TagIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, { "icon": "TerminalIcon", "source": null, "note": "IDEA terminal tool window icon ships in the terminal plugin, not platform/icons; keep lucide fallback" + }, + { + "icon": "TerminalWindowIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextAaIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextAlignCenterIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextAlignJustifyIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextAlignLeftIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextIndentIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextOutdentIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TextTIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "TranslateIcon", + "source": "expui/general/language.svg" + }, + { + "icon": "TrashIcon", + "source": "expui/general/delete.svg" + }, + { + "icon": "TreeStructureIcon", + "source": "expui/general/tree.svg" + }, + { + "icon": "UploadIcon", + "source": "expui/general/upload.svg" + }, + { + "icon": "UploadSimpleIcon", + "source": "expui/general/upload.svg" + }, + { + "icon": "UserCircleIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "UserIcon", + "source": "expui/general/user.svg" + }, + { + "icon": "UsersThreeIcon", + "source": "expui/general/groups.svg" + }, + { + "icon": "WarningCircleIcon", + "source": "expui/general/warningDialog.svg" + }, + { + "icon": "WarningIcon", + "source": "expui/general/warningDialog.svg" + }, + { + "icon": "WindowExpandIcon", + "source": null, + "note": "no confident IntelliJ platform asset; lucide fallback" + }, + { + "icon": "WrenchIcon", + "source": "expui/general/externalTools.svg" + }, + { + "icon": "XCircleIcon", + "source": "expui/general/errorDialog.svg" + }, + { + "icon": "XIcon", + "source": "expui/general/close.svg" } ] } diff --git a/windows/tauri/src/ui/icons/idea-assets.generated.ts b/windows/tauri/src/ui/icons/idea-assets.generated.ts index 9f0fea1e8..73c80c177 100644 --- a/windows/tauri/src/ui/icons/idea-assets.generated.ts +++ b/windows/tauri/src/ui/icons/idea-assets.generated.ts @@ -3,12 +3,28 @@ // intellij-community platform/icons/src checkout passed via --source). // Keys are icon export display names resolved by createIconComponent. +import archiveLight from "./idea/expui/fileTypes/archive.svg?url"; +import archiveDark from "./idea/expui/fileTypes/archive_dark.svg?url"; import arrowClockwiseLight from "./idea/expui/general/redo.svg?url"; import arrowClockwiseDark from "./idea/expui/general/redo_dark.svg?url"; import arrowCounterClockwiseLight from "./idea/expui/general/undo.svg?url"; import arrowCounterClockwiseDark from "./idea/expui/general/undo_dark.svg?url"; +import arrowDownLight from "./idea/expui/general/down.svg?url"; +import arrowDownDark from "./idea/expui/general/down_dark.svg?url"; +import arrowLeftLight from "./idea/expui/general/left.svg?url"; +import arrowLeftDark from "./idea/expui/general/left_dark.svg?url"; +import arrowRightLight from "./idea/expui/general/right.svg?url"; +import arrowRightDark from "./idea/expui/general/right_dark.svg?url"; +import arrowSquareOutLight from "./idea/expui/ide/externalLink.svg?url"; +import arrowSquareOutDark from "./idea/expui/ide/externalLink_dark.svg?url"; +import arrowUpLight from "./idea/expui/general/up.svg?url"; +import arrowUpDark from "./idea/expui/general/up_dark.svg?url"; import bellLight from "./idea/expui/toolwindows/notifications.svg?url"; import bellDark from "./idea/expui/toolwindows/notifications_dark.svg?url"; +import bookmarkLight from "./idea/expui/bookmarks/bookmark.svg?url"; +import bookmarkDark from "./idea/expui/bookmarks/bookmark_dark.svg?url"; +import bookOpenLight from "./idea/expui/toolwindows/documentation.svg?url"; +import bookOpenDark from "./idea/expui/toolwindows/documentation_dark.svg?url"; import bugLight from "./idea/expui/run/debug.svg?url"; import bugDark from "./idea/expui/run/debug_dark.svg?url"; import caretDownLight from "./idea/expui/general/chevronDown.svg?url"; @@ -19,6 +35,8 @@ import caretRightLight from "./idea/expui/general/chevronRight.svg?url"; import caretRightDark from "./idea/expui/general/chevronRight_dark.svg?url"; import caretUpLight from "./idea/expui/general/chevronUp.svg?url"; import caretUpDark from "./idea/expui/general/chevronUp_dark.svg?url"; +import chatCircleTextLight from "./idea/expui/toolwindows/messages.svg?url"; +import chatCircleTextDark from "./idea/expui/toolwindows/messages_dark.svg?url"; import checkCircleLight from "./idea/expui/general/successDialog.svg?url"; import checkCircleDark from "./idea/expui/general/successDialog_dark.svg?url"; import checkLight from "./idea/expui/general/greenCheckmark.svg?url"; @@ -33,15 +51,29 @@ import chevronUpLight from "./idea/expui/general/chevronUp.svg?url"; import chevronUpDark from "./idea/expui/general/chevronUp_dark.svg?url"; import clockCounterClockwiseLight from "./idea/expui/general/history.svg?url"; import clockCounterClockwiseDark from "./idea/expui/general/history_dark.svg?url"; +import columnsLight from "./idea/expui/general/splitVertically.svg?url"; +import columnsDark from "./idea/expui/general/splitVertically_dark.svg?url"; import copyLight from "./idea/expui/general/copy.svg?url"; import copyDark from "./idea/expui/general/copy_dark.svg?url"; +import copySimpleLight from "./idea/expui/general/copy.svg?url"; +import copySimpleDark from "./idea/expui/general/copy_dark.svg?url"; +import databaseLight from "./idea/expui/toolwindows/toolWindowDataView.svg?url"; +import databaseDark from "./idea/expui/toolwindows/toolWindowDataView_dark.svg?url"; import dotsThreeLight from "./idea/expui/general/moreHorizontal.svg?url"; import dotsThreeDark from "./idea/expui/general/moreHorizontal_dark.svg?url"; import downloadLight from "./idea/expui/general/download.svg?url"; import downloadDark from "./idea/expui/general/download_dark.svg?url"; +import downloadSimpleLight from "./idea/expui/general/download.svg?url"; +import downloadSimpleDark from "./idea/expui/general/download_dark.svg?url"; +import eyeLight from "./idea/expui/general/show.svg?url"; +import eyeDark from "./idea/expui/general/show_dark.svg?url"; +import eyeSlashLight from "./idea/expui/general/hide.svg?url"; +import eyeSlashDark from "./idea/expui/general/hide_dark.svg?url"; import fileLight from "./idea/fileTypes/text.svg?url"; import filePlusLight from "./idea/expui/actions/addFile.svg?url"; import filePlusDark from "./idea/expui/actions/addFile_dark.svg?url"; +import filesLight from "./idea/expui/general/listFiles.svg?url"; +import filesDark from "./idea/expui/general/listFiles_dark.svg?url"; import fileTextLight from "./idea/fileTypes/text.svg?url"; import floppyDiskLight from "./idea/expui/general/save.svg?url"; import floppyDiskDark from "./idea/expui/general/save_dark.svg?url"; @@ -49,10 +81,14 @@ import folderLight from "./idea/expui/nodes/folder.svg?url"; import folderDark from "./idea/expui/nodes/folder_dark.svg?url"; import folderPlusLight from "./idea/expui/actions/newFolder.svg?url"; import folderPlusDark from "./idea/expui/actions/newFolder_dark.svg?url"; +import functionLight from "./idea/expui/nodes/function.svg?url"; +import functionDark from "./idea/expui/nodes/function_dark.svg?url"; import funnelLight from "./idea/expui/general/filter.svg?url"; import funnelDark from "./idea/expui/general/filter_dark.svg?url"; import gearLight from "./idea/expui/general/settings.svg?url"; import gearDark from "./idea/expui/general/settings_dark.svg?url"; +import gearSixLight from "./idea/expui/general/settings.svg?url"; +import gearSixDark from "./idea/expui/general/settings_dark.svg?url"; import gitBranchLight from "./idea/vcs/branch.svg?url"; import gitBranchDark from "./idea/vcs/branch_dark.svg?url"; import gitCommitLight from "./idea/expui/vcs/commit.svg?url"; @@ -61,24 +97,54 @@ import gitDiffLight from "./idea/expui/vcs/diff.svg?url"; import gitDiffDark from "./idea/expui/vcs/diff_dark.svg?url"; import gitMergeLight from "./idea/expui/vcs/merge.svg?url"; import gitMergeDark from "./idea/expui/vcs/merge_dark.svg?url"; +import globeHemisphereWestLight from "./idea/expui/toolwindows/web.svg?url"; +import globeHemisphereWestDark from "./idea/expui/toolwindows/web_dark.svg?url"; +import globeLight from "./idea/expui/toolwindows/web.svg?url"; +import globeDark from "./idea/expui/toolwindows/web_dark.svg?url"; +import hashLight from "./idea/expui/general/hashtag.svg?url"; +import hashDark from "./idea/expui/general/hashtag_dark.svg?url"; +import houseLight from "./idea/expui/javaee/home.svg?url"; +import houseDark from "./idea/expui/javaee/home_dark.svg?url"; +import imageLight from "./idea/expui/fileTypes/image.svg?url"; +import imageDark from "./idea/expui/fileTypes/image_dark.svg?url"; import infoLight from "./idea/expui/general/informationDialog.svg?url"; import infoDark from "./idea/expui/general/informationDialog_dark.svg?url"; import keyboardLight from "./idea/expui/general/keyboard.svg?url"; import keyboardDark from "./idea/expui/general/keyboard_dark.svg?url"; +import lightbulbLight from "./idea/expui/actions/realIntentionBulb.svg?url"; +import lightbulbDark from "./idea/expui/actions/realIntentionBulb_dark.svg?url"; +import lightningLight from "./idea/expui/actions/lightning.svg?url"; +import lightningDark from "./idea/expui/actions/lightning_dark.svg?url"; import lockLight from "./idea/expui/general/locked.svg?url"; import lockDark from "./idea/expui/general/locked_dark.svg?url"; import lockOpenLight from "./idea/expui/general/unlocked.svg?url"; import lockOpenDark from "./idea/expui/general/unlocked_dark.svg?url"; import magnifyingGlassLight from "./idea/expui/general/search.svg?url"; import magnifyingGlassDark from "./idea/expui/general/search_dark.svg?url"; +import magnifyingGlassMinusLight from "./idea/expui/image/zoomOut.svg?url"; +import magnifyingGlassMinusDark from "./idea/expui/image/zoomOut_dark.svg?url"; +import magnifyingGlassPlusLight from "./idea/expui/image/zoomIn.svg?url"; +import magnifyingGlassPlusDark from "./idea/expui/image/zoomIn_dark.svg?url"; import minusLight from "./idea/expui/general/remove.svg?url"; import minusDark from "./idea/expui/general/remove_dark.svg?url"; +import monitorLight from "./idea/expui/nodes/desktop.svg?url"; +import monitorDark from "./idea/expui/nodes/desktop_dark.svg?url"; import openExternalLight from "./idea/expui/ide/externalLink.svg?url"; import openExternalDark from "./idea/expui/ide/externalLink_dark.svg?url"; +import paletteLight from "./idea/expui/toolwindows/palette.svg?url"; +import paletteDark from "./idea/expui/toolwindows/palette_dark.svg?url"; import pauseLight from "./idea/expui/run/pause.svg?url"; import pauseDark from "./idea/expui/run/pause_dark.svg?url"; import pencilLight from "./idea/expui/general/edit.svg?url"; import pencilDark from "./idea/expui/general/edit_dark.svg?url"; +import pencilLineLight from "./idea/expui/general/edit.svg?url"; +import pencilLineDark from "./idea/expui/general/edit_dark.svg?url"; +import pencilSimpleLight from "./idea/expui/general/edit.svg?url"; +import pencilSimpleDark from "./idea/expui/general/edit_dark.svg?url"; +import pencilSimpleLineLight from "./idea/expui/general/edit.svg?url"; +import pencilSimpleLineDark from "./idea/expui/general/edit_dark.svg?url"; +import penLight from "./idea/expui/general/edit.svg?url"; +import penDark from "./idea/expui/general/edit_dark.svg?url"; import playLight from "./idea/expui/run/run.svg?url"; import playDark from "./idea/expui/run/run_dark.svg?url"; import plusLight from "./idea/expui/general/add.svg?url"; @@ -89,18 +155,38 @@ import questionLight from "./idea/expui/general/questionDialog.svg?url"; import questionDark from "./idea/expui/general/questionDialog_dark.svg?url"; import refreshLight from "./idea/expui/general/refresh.svg?url"; import refreshDark from "./idea/expui/general/refresh_dark.svg?url"; +import rowsLight from "./idea/expui/general/splitHorizontally.svg?url"; +import rowsDark from "./idea/expui/general/splitHorizontally_dark.svg?url"; +import scissorsLight from "./idea/expui/general/cut.svg?url"; +import scissorsDark from "./idea/expui/general/cut_dark.svg?url"; +import sidebarSimpleLight from "./idea/expui/general/layout.svg?url"; +import sidebarSimpleDark from "./idea/expui/general/layout_dark.svg?url"; +import signOutLight from "./idea/expui/general/exit.svg?url"; +import signOutDark from "./idea/expui/general/exit_dark.svg?url"; import stopLight from "./idea/expui/run/stop.svg?url"; import stopDark from "./idea/expui/run/stop_dark.svg?url"; +import tableLight from "./idea/expui/nodes/dataTables.svg?url"; +import tableDark from "./idea/expui/nodes/dataTables_dark.svg?url"; +import translateLight from "./idea/expui/general/language.svg?url"; +import translateDark from "./idea/expui/general/language_dark.svg?url"; import trashLight from "./idea/expui/general/delete.svg?url"; import trashDark from "./idea/expui/general/delete_dark.svg?url"; +import treeStructureLight from "./idea/expui/general/tree.svg?url"; +import treeStructureDark from "./idea/expui/general/tree_dark.svg?url"; import uploadLight from "./idea/expui/general/upload.svg?url"; import uploadDark from "./idea/expui/general/upload_dark.svg?url"; +import uploadSimpleLight from "./idea/expui/general/upload.svg?url"; +import uploadSimpleDark from "./idea/expui/general/upload_dark.svg?url"; import userLight from "./idea/expui/general/user.svg?url"; import userDark from "./idea/expui/general/user_dark.svg?url"; +import usersThreeLight from "./idea/expui/general/groups.svg?url"; +import usersThreeDark from "./idea/expui/general/groups_dark.svg?url"; import warningCircleLight from "./idea/expui/general/warningDialog.svg?url"; import warningCircleDark from "./idea/expui/general/warningDialog_dark.svg?url"; import warningLight from "./idea/expui/general/warningDialog.svg?url"; import warningDark from "./idea/expui/general/warningDialog_dark.svg?url"; +import wrenchLight from "./idea/expui/general/externalTools.svg?url"; +import wrenchDark from "./idea/expui/general/externalTools_dark.svg?url"; import xCircleLight from "./idea/expui/general/errorDialog.svg?url"; import xCircleDark from "./idea/expui/general/errorDialog_dark.svg?url"; import xLight from "./idea/expui/general/close.svg?url"; @@ -112,14 +198,23 @@ export interface IdeaIconAsset { } export const ideaIconAssets: Record = { + ArchiveIcon: { light: archiveLight, dark: archiveDark }, ArrowClockwiseIcon: { light: arrowClockwiseLight, dark: arrowClockwiseDark }, ArrowCounterClockwiseIcon: { light: arrowCounterClockwiseLight, dark: arrowCounterClockwiseDark }, + ArrowDownIcon: { light: arrowDownLight, dark: arrowDownDark }, + ArrowLeftIcon: { light: arrowLeftLight, dark: arrowLeftDark }, + ArrowRightIcon: { light: arrowRightLight, dark: arrowRightDark }, + ArrowSquareOutIcon: { light: arrowSquareOutLight, dark: arrowSquareOutDark }, + ArrowUpIcon: { light: arrowUpLight, dark: arrowUpDark }, BellIcon: { light: bellLight, dark: bellDark }, + BookmarkIcon: { light: bookmarkLight, dark: bookmarkDark }, + BookOpenIcon: { light: bookOpenLight, dark: bookOpenDark }, BugIcon: { light: bugLight, dark: bugDark }, CaretDownIcon: { light: caretDownLight, dark: caretDownDark }, CaretLeftIcon: { light: caretLeftLight, dark: caretLeftDark }, CaretRightIcon: { light: caretRightLight, dark: caretRightDark }, CaretUpIcon: { light: caretUpLight, dark: caretUpDark }, + ChatCircleTextIcon: { light: chatCircleTextLight, dark: chatCircleTextDark }, CheckCircleIcon: { light: checkCircleLight, dark: checkCircleDark }, CheckIcon: { light: checkLight, dark: checkDark }, ChevronDownIcon: { light: chevronDownLight, dark: chevronDownDark }, @@ -127,41 +222,75 @@ export const ideaIconAssets: Record = { ChevronRightIcon: { light: chevronRightLight, dark: chevronRightDark }, ChevronUpIcon: { light: chevronUpLight, dark: chevronUpDark }, ClockCounterClockwiseIcon: { light: clockCounterClockwiseLight, dark: clockCounterClockwiseDark }, + ColumnsIcon: { light: columnsLight, dark: columnsDark }, CopyIcon: { light: copyLight, dark: copyDark }, + CopySimpleIcon: { light: copySimpleLight, dark: copySimpleDark }, + DatabaseIcon: { light: databaseLight, dark: databaseDark }, DotsThreeIcon: { light: dotsThreeLight, dark: dotsThreeDark }, DownloadIcon: { light: downloadLight, dark: downloadDark }, + DownloadSimpleIcon: { light: downloadSimpleLight, dark: downloadSimpleDark }, + EyeIcon: { light: eyeLight, dark: eyeDark }, + EyeSlashIcon: { light: eyeSlashLight, dark: eyeSlashDark }, FileIcon: { light: fileLight, dark: fileLight }, FilePlusIcon: { light: filePlusLight, dark: filePlusDark }, + FilesIcon: { light: filesLight, dark: filesDark }, FileTextIcon: { light: fileTextLight, dark: fileTextLight }, FloppyDiskIcon: { light: floppyDiskLight, dark: floppyDiskDark }, FolderIcon: { light: folderLight, dark: folderDark }, FolderPlusIcon: { light: folderPlusLight, dark: folderPlusDark }, + FunctionIcon: { light: functionLight, dark: functionDark }, FunnelIcon: { light: funnelLight, dark: funnelDark }, GearIcon: { light: gearLight, dark: gearDark }, + GearSixIcon: { light: gearSixLight, dark: gearSixDark }, GitBranchIcon: { light: gitBranchLight, dark: gitBranchDark }, GitCommitIcon: { light: gitCommitLight, dark: gitCommitDark }, GitDiffIcon: { light: gitDiffLight, dark: gitDiffDark }, GitMergeIcon: { light: gitMergeLight, dark: gitMergeDark }, + GlobeHemisphereWestIcon: { light: globeHemisphereWestLight, dark: globeHemisphereWestDark }, + GlobeIcon: { light: globeLight, dark: globeDark }, + HashIcon: { light: hashLight, dark: hashDark }, + HouseIcon: { light: houseLight, dark: houseDark }, + ImageIcon: { light: imageLight, dark: imageDark }, InfoIcon: { light: infoLight, dark: infoDark }, KeyboardIcon: { light: keyboardLight, dark: keyboardDark }, + LightbulbIcon: { light: lightbulbLight, dark: lightbulbDark }, + LightningIcon: { light: lightningLight, dark: lightningDark }, LockIcon: { light: lockLight, dark: lockDark }, LockOpenIcon: { light: lockOpenLight, dark: lockOpenDark }, MagnifyingGlassIcon: { light: magnifyingGlassLight, dark: magnifyingGlassDark }, + MagnifyingGlassMinusIcon: { light: magnifyingGlassMinusLight, dark: magnifyingGlassMinusDark }, + MagnifyingGlassPlusIcon: { light: magnifyingGlassPlusLight, dark: magnifyingGlassPlusDark }, MinusIcon: { light: minusLight, dark: minusDark }, + MonitorIcon: { light: monitorLight, dark: monitorDark }, OpenExternalIcon: { light: openExternalLight, dark: openExternalDark }, + PaletteIcon: { light: paletteLight, dark: paletteDark }, PauseIcon: { light: pauseLight, dark: pauseDark }, PencilIcon: { light: pencilLight, dark: pencilDark }, + PencilLineIcon: { light: pencilLineLight, dark: pencilLineDark }, + PencilSimpleIcon: { light: pencilSimpleLight, dark: pencilSimpleDark }, + PencilSimpleLineIcon: { light: pencilSimpleLineLight, dark: pencilSimpleLineDark }, + PenIcon: { light: penLight, dark: penDark }, PlayIcon: { light: playLight, dark: playDark }, PlusIcon: { light: plusLight, dark: plusDark }, PushPinIcon: { light: pushPinLight, dark: pushPinDark }, QuestionIcon: { light: questionLight, dark: questionDark }, RefreshIcon: { light: refreshLight, dark: refreshDark }, + RowsIcon: { light: rowsLight, dark: rowsDark }, + ScissorsIcon: { light: scissorsLight, dark: scissorsDark }, + SidebarSimpleIcon: { light: sidebarSimpleLight, dark: sidebarSimpleDark }, + SignOutIcon: { light: signOutLight, dark: signOutDark }, StopIcon: { light: stopLight, dark: stopDark }, + TableIcon: { light: tableLight, dark: tableDark }, + TranslateIcon: { light: translateLight, dark: translateDark }, TrashIcon: { light: trashLight, dark: trashDark }, + TreeStructureIcon: { light: treeStructureLight, dark: treeStructureDark }, UploadIcon: { light: uploadLight, dark: uploadDark }, + UploadSimpleIcon: { light: uploadSimpleLight, dark: uploadSimpleDark }, UserIcon: { light: userLight, dark: userDark }, + UsersThreeIcon: { light: usersThreeLight, dark: usersThreeDark }, WarningCircleIcon: { light: warningCircleLight, dark: warningCircleDark }, WarningIcon: { light: warningLight, dark: warningDark }, + WrenchIcon: { light: wrenchLight, dark: wrenchDark }, XCircleIcon: { light: xCircleLight, dark: xCircleDark }, XIcon: { light: xLight, dark: xDark }, }; diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/lightning.svg b/windows/tauri/src/ui/icons/idea/expui/actions/lightning.svg new file mode 100644 index 000000000..4ac384edd --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/lightning.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/lightning_dark.svg b/windows/tauri/src/ui/icons/idea/expui/actions/lightning_dark.svg new file mode 100644 index 000000000..251f75413 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/lightning_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb.svg b/windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb.svg new file mode 100644 index 000000000..2b1ff1313 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb_dark.svg b/windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb_dark.svg new file mode 100644 index 000000000..04446b57b --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/actions/realIntentionBulb_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark.svg b/windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark.svg new file mode 100644 index 000000000..37ddd8909 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark_dark.svg b/windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark_dark.svg new file mode 100644 index 000000000..829d176c5 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/bookmarks/bookmark_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/fileTypes/archive.svg b/windows/tauri/src/ui/icons/idea/expui/fileTypes/archive.svg new file mode 100644 index 000000000..87bbbeece --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/fileTypes/archive.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/fileTypes/archive_dark.svg b/windows/tauri/src/ui/icons/idea/expui/fileTypes/archive_dark.svg new file mode 100644 index 000000000..ab3cae2cc --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/fileTypes/archive_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/fileTypes/image.svg b/windows/tauri/src/ui/icons/idea/expui/fileTypes/image.svg new file mode 100644 index 000000000..9a09720fa --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/fileTypes/image.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/fileTypes/image_dark.svg b/windows/tauri/src/ui/icons/idea/expui/fileTypes/image_dark.svg new file mode 100644 index 000000000..4f189a0e3 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/fileTypes/image_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/cut.svg b/windows/tauri/src/ui/icons/idea/expui/general/cut.svg new file mode 100644 index 000000000..f4688fd6a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/cut.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/cut_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/cut_dark.svg new file mode 100644 index 000000000..374de24c3 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/cut_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/down.svg b/windows/tauri/src/ui/icons/idea/expui/general/down.svg new file mode 100644 index 000000000..8e456442a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/down.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/down_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/down_dark.svg new file mode 100644 index 000000000..4647fc570 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/down_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/exit.svg b/windows/tauri/src/ui/icons/idea/expui/general/exit.svg new file mode 100644 index 000000000..8ff96d714 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/exit.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/exit_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/exit_dark.svg new file mode 100644 index 000000000..e4cdd4abf --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/exit_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/externalTools.svg b/windows/tauri/src/ui/icons/idea/expui/general/externalTools.svg new file mode 100644 index 000000000..222cce249 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/externalTools.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/windows/tauri/src/ui/icons/idea/expui/general/externalTools_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/externalTools_dark.svg new file mode 100644 index 000000000..26950fb68 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/externalTools_dark.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/windows/tauri/src/ui/icons/idea/expui/general/groups.svg b/windows/tauri/src/ui/icons/idea/expui/general/groups.svg new file mode 100644 index 000000000..d4ab80fbb --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/groups.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/groups_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/groups_dark.svg new file mode 100644 index 000000000..2769c3ce0 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/groups_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/hashtag.svg b/windows/tauri/src/ui/icons/idea/expui/general/hashtag.svg new file mode 100644 index 000000000..75331f397 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/hashtag.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/hashtag_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/hashtag_dark.svg new file mode 100644 index 000000000..d7ed0fb18 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/hashtag_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/hide.svg b/windows/tauri/src/ui/icons/idea/expui/general/hide.svg new file mode 100644 index 000000000..d3339b0ea --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/hide.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/hide_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/hide_dark.svg new file mode 100644 index 000000000..1d8f73c96 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/hide_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/language.svg b/windows/tauri/src/ui/icons/idea/expui/general/language.svg new file mode 100644 index 000000000..6519face4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/language.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/language_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/language_dark.svg new file mode 100644 index 000000000..bfe830915 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/language_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/layout.svg b/windows/tauri/src/ui/icons/idea/expui/general/layout.svg new file mode 100644 index 000000000..d308e821a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/layout.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/layout_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/layout_dark.svg new file mode 100644 index 000000000..ae84e4cb5 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/layout_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/left.svg b/windows/tauri/src/ui/icons/idea/expui/general/left.svg new file mode 100644 index 000000000..2e692c113 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/left.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/left_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/left_dark.svg new file mode 100644 index 000000000..c582ee9d3 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/left_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/listFiles.svg b/windows/tauri/src/ui/icons/idea/expui/general/listFiles.svg new file mode 100644 index 000000000..38ee91a91 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/listFiles.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/listFiles_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/listFiles_dark.svg new file mode 100644 index 000000000..798a2b352 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/listFiles_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/right.svg b/windows/tauri/src/ui/icons/idea/expui/general/right.svg new file mode 100644 index 000000000..5e410fbaa --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/right.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/right_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/right_dark.svg new file mode 100644 index 000000000..2f6780a64 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/right_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/show.svg b/windows/tauri/src/ui/icons/idea/expui/general/show.svg new file mode 100644 index 000000000..5b8294841 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/show.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/show_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/show_dark.svg new file mode 100644 index 000000000..f1943369a --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/show_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally.svg b/windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally.svg new file mode 100644 index 000000000..bde0f3954 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally_dark.svg new file mode 100644 index 000000000..a77be9798 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/splitHorizontally_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/splitVertically.svg b/windows/tauri/src/ui/icons/idea/expui/general/splitVertically.svg new file mode 100644 index 000000000..36076234c --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/splitVertically.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/splitVertically_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/splitVertically_dark.svg new file mode 100644 index 000000000..3d34338da --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/splitVertically_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/tree.svg b/windows/tauri/src/ui/icons/idea/expui/general/tree.svg new file mode 100644 index 000000000..4d949713e --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/tree.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/tree_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/tree_dark.svg new file mode 100644 index 000000000..0ff8904a5 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/tree_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/up.svg b/windows/tauri/src/ui/icons/idea/expui/general/up.svg new file mode 100644 index 000000000..a884232c9 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/up.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/general/up_dark.svg b/windows/tauri/src/ui/icons/idea/expui/general/up_dark.svg new file mode 100644 index 000000000..db56b61bf --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/general/up_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/image/zoomIn.svg b/windows/tauri/src/ui/icons/idea/expui/image/zoomIn.svg new file mode 100644 index 000000000..dc4380e34 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/image/zoomIn.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/image/zoomIn_dark.svg b/windows/tauri/src/ui/icons/idea/expui/image/zoomIn_dark.svg new file mode 100644 index 000000000..39cb0f660 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/image/zoomIn_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/image/zoomOut.svg b/windows/tauri/src/ui/icons/idea/expui/image/zoomOut.svg new file mode 100644 index 000000000..90d8d4152 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/image/zoomOut.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/image/zoomOut_dark.svg b/windows/tauri/src/ui/icons/idea/expui/image/zoomOut_dark.svg new file mode 100644 index 000000000..41c92b418 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/image/zoomOut_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/javaee/home.svg b/windows/tauri/src/ui/icons/idea/expui/javaee/home.svg new file mode 100644 index 000000000..ba500aee4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/javaee/home.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/javaee/home_dark.svg b/windows/tauri/src/ui/icons/idea/expui/javaee/home_dark.svg new file mode 100644 index 000000000..2dd4533ea --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/javaee/home_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/dataTables.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/dataTables.svg new file mode 100644 index 000000000..e96143a5c --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/dataTables.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/dataTables_dark.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/dataTables_dark.svg new file mode 100644 index 000000000..a32f62be8 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/dataTables_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/desktop.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/desktop.svg new file mode 100644 index 000000000..101405375 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/desktop.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/desktop_dark.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/desktop_dark.svg new file mode 100644 index 000000000..9eebcbe48 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/desktop_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/function.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/function.svg new file mode 100644 index 000000000..622ee6927 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/function.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/nodes/function_dark.svg b/windows/tauri/src/ui/icons/idea/expui/nodes/function_dark.svg new file mode 100644 index 000000000..0f92bb482 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/nodes/function_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation.svg new file mode 100644 index 000000000..377d61495 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation_dark.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation_dark.svg new file mode 100644 index 000000000..643ae4e68 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/documentation_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/messages.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/messages.svg new file mode 100644 index 000000000..0b6e8a743 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/messages.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/messages_dark.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/messages_dark.svg new file mode 100644 index 000000000..0d98f22c9 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/messages_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/palette.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/palette.svg new file mode 100644 index 000000000..d08c85050 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/palette.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/palette_dark.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/palette_dark.svg new file mode 100644 index 000000000..ae27d2386 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/palette_dark.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView.svg new file mode 100644 index 000000000..e6ad3e27d --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView_dark.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView_dark.svg new file mode 100644 index 000000000..c00e77da4 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/toolWindowDataView_dark.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/web.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/web.svg new file mode 100644 index 000000000..897fab392 --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/web.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/ui/icons/idea/expui/toolwindows/web_dark.svg b/windows/tauri/src/ui/icons/idea/expui/toolwindows/web_dark.svg new file mode 100644 index 000000000..0ca6194ab --- /dev/null +++ b/windows/tauri/src/ui/icons/idea/expui/toolwindows/web_dark.svg @@ -0,0 +1,4 @@ + + + + From 2509390c87e94bed5353f410e16ec978c5f7461b Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:12:55 +0800 Subject: [PATCH 05/17] test(windows): keep lucide assertions on icons still using lucide --- windows/tauri/src/ui/icons.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/tauri/src/ui/icons.test.tsx b/windows/tauri/src/ui/icons.test.tsx index 9347c416a..4cab2dfaf 100644 --- a/windows/tauri/src/ui/icons.test.tsx +++ b/windows/tauri/src/ui/icons.test.tsx @@ -36,10 +36,10 @@ describe("application icon mappings", () => { test("maps unmapped controls to the expected Lucide icons", () => { const cases: Array<[ElementType, string]> = [ - [AppIcons.FilesIcon, "lucide-files"], [AppIcons.WindowExpandIcon, "lucide-maximize2"], - [AppIcons.ArrowSquareOutIcon, "lucide-external-link"], [AppIcons.SquareIcon, "lucide-square"], + [AppIcons.SunIcon, "lucide-sun"], + [AppIcons.TerminalIcon, "lucide-terminal"], ]; for (const [IconComponent, expectedClass] of cases) { From 996f00765c988bc57a262506486c2e175b920acf Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:16:16 +0800 Subject: [PATCH 06/17] fix(windows): render IntelliJ icon assets with an svg root Asset icons previously rendered as a span+img pair, which button and chrome CSS sizing selectors ([&_svg]:size-*) did not match, shrinking sidebar and toolbar icons to the 13px font default. Render the dual light/dark variants as children of a real svg root instead, so asset icons keep the exact lucide sizing contract. --- windows/tauri/src/ui/icons.css | 20 ++++--------- windows/tauri/src/ui/icons.test.tsx | 9 +++--- windows/tauri/src/ui/icons.tsx | 44 ++++++++++++++++++----------- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/windows/tauri/src/ui/icons.css b/windows/tauri/src/ui/icons.css index 82d54b788..29760f062 100644 --- a/windows/tauri/src/ui/icons.css +++ b/windows/tauri/src/ui/icons.css @@ -1,22 +1,12 @@ /* - * IntelliJ icon assets are rendered as dual light/dark instances. The - * active variant follows the runtime `data-theme-type` attribute set by the - * theme registry, so switching themes needs no React re-render. + * IntelliJ icon assets render as dual light/dark children inside a + * real root. The active variant follows the runtime `data-theme-type` + * attribute set by the theme registry, so switching themes needs no React + * re-render. The svg root keeps the lucide sizing contract (width/height + * attributes, overridable by CSS selectors like [&_svg]:size-*). */ .lithe-idea-icon { - display: inline-flex; - align-items: center; - justify-content: center; flex: none; - line-height: 0; - vertical-align: middle; -} - -.lithe-idea-icon img { - width: 100%; - height: 100%; - pointer-events: none; - user-select: none; } .lithe-idea-icon .lithe-idea-icon-dark { diff --git a/windows/tauri/src/ui/icons.test.tsx b/windows/tauri/src/ui/icons.test.tsx index 4cab2dfaf..53609020f 100644 --- a/windows/tauri/src/ui/icons.test.tsx +++ b/windows/tauri/src/ui/icons.test.tsx @@ -61,17 +61,18 @@ describe("application icon mappings", () => { ]; for (const exportName of mapped) { const markup = renderIcon(AppIcons[exportName] as ElementType); - expect(markup).toContain("lithe-idea-icon"); - expect(markup.match(/ { + test("forwards title to the asset aria label", () => { const markup = renderToStaticMarkup( createElement(AppIcons.TrashIcon as ElementType, { title: "delete action" }), ); - expect(markup).toContain('alt="delete action"'); + expect(markup).toContain('aria-label="delete action"'); }); }); diff --git a/windows/tauri/src/ui/icons.tsx b/windows/tauri/src/ui/icons.tsx index 6fb56dddc..cebcd012f 100644 --- a/windows/tauri/src/ui/icons.tsx +++ b/windows/tauri/src/ui/icons.tsx @@ -166,31 +166,43 @@ function createIconComponent(IconComponent: ComponentType, displayName: str : style; // IntelliJ assets are fixed-color SVGs with light/dark variants; render - // both and let CSS pick the active one, so theme switches need no rerender. - // weight/strokeWidth have no effect on these (colorPolicy: fixed). + // both as children of a real root and let CSS pick the + // active one, so theme switches need no rerender. The svg root keeps the + // same sizing contract as lucide icons (width/height attrs overridable by + // CSS like [&_svg]:size-*), and weight/strokeWidth are no-ops (fixed art). const asset = ideaIconAssets[displayName]; if (asset) { - const { className, id, onClick } = iconProps; + const { className, ...svgProps } = iconProps; return createElement( - "span", + "svg", { - ref: ref as any, + ...svgProps, + ref, className: ["lithe-idea-icon", className].filter(Boolean).join(" "), - id, - onClick, - style: { width: size, height: size, ...nextStyle }, + viewBox: "0 0 16 16", + width: size, + height: size, + fill: "none", + style: nextStyle, + role: title ?? alt ? "img" : undefined, + "aria-label": title ?? alt, + "aria-hidden": title ?? alt ? undefined : true, }, - createElement("img", { - src: asset.light, - alt: title ?? alt ?? "", + createElement("image", { + href: asset.light, className: "lithe-idea-icon-light", - draggable: false, + x: 0, + y: 0, + width: 16, + height: 16, }), - createElement("img", { - src: asset.dark, - alt: "", + createElement("image", { + href: asset.dark, className: "lithe-idea-icon-dark", - draggable: false, + x: 0, + y: 0, + width: 16, + height: 16, }), ); } From 36a6ceab4cd4aa6ef6c2fe5e9046f435b8b673e3 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:19:59 +0800 Subject: [PATCH 07/17] feat(windows): style editor tabs with IntelliJ underline selection Selected editor and terminal tabs now carry a 4px accent underline on the top edge over the editor background instead of a block highlight, unselected labels render at reduced alpha, and the tab strip shares the editor background with a 1px rule below it, matching the IntelliJ New UI editor tab treatment. --- windows/tauri/src/styles/theme.css | 4 +++- windows/tauri/src/ui/tab-bar.tsx | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/windows/tauri/src/styles/theme.css b/windows/tauri/src/styles/theme.css index c6d38d8ef..0c3f9a6d1 100644 --- a/windows/tauri/src/styles/theme.css +++ b/windows/tauri/src/styles/theme.css @@ -150,7 +150,9 @@ --secondary-foreground: var(--foreground); --success: var(--primary); --warning: var(--muted-foreground); - --tab-bar-bg: color-mix(in srgb, var(--surface) 72%, var(--background)); + /* IntelliJ editor tab strip: same base as the editor area, separated by a + 1px rule below the strip instead of a tinted band. */ + --tab-bar-bg: var(--background); --tab-active-bg: var(--background); --tab-hover-bg: color-mix(in srgb, var(--accent) 72%, transparent); --shadow-card: diff --git a/windows/tauri/src/ui/tab-bar.tsx b/windows/tauri/src/ui/tab-bar.tsx index 440694f3f..0f7be433c 100644 --- a/windows/tauri/src/ui/tab-bar.tsx +++ b/windows/tauri/src/ui/tab-bar.tsx @@ -201,14 +201,18 @@ const tabVariants = cva( className: "text-subtle-foreground/90 hover:bg-accent hover:text-foreground", }, { + // IntelliJ editor tabs: selected tab is marked by a 4px accent + // underline on the top edge over the editor background, not a block + // highlight; unselected labels render at reduced alpha. variant: "connected", active: true, - className: "z-10 bg-accent/90 text-foreground shadow-none", + className: + "z-10 bg-transparent text-foreground shadow-none hover:bg-transparent before:absolute before:inset-x-1.5 before:top-0 before:h-[4px] before:rounded-full before:bg-primary before:content-['']", }, { variant: "connected", active: false, - className: "text-subtle-foreground/85 hover:bg-tab-hover/60 hover:text-foreground", + className: "text-foreground/75 hover:bg-accent/50 hover:text-foreground", }, ], }, @@ -242,7 +246,7 @@ const tabBarSurfaceVariants = cva("relative flex overflow-hidden", { variants: { orientation: { horizontal: - "h-(--lithe-tab-bar-height) min-h-(--lithe-tab-bar-height) shrink-0 items-center gap-(--lithe-chrome-gap) bg-tab-bar px-(--lithe-chrome-padding-inline)", + "h-(--lithe-tab-bar-height) min-h-(--lithe-tab-bar-height) shrink-0 items-center gap-(--lithe-chrome-gap) border-b border-border bg-tab-bar px-(--lithe-chrome-padding-inline)", vertical: "h-full min-h-0 flex-col bg-tab-bar py-(--lithe-chrome-gap)", }, }, From a03e0d7e6d0e02f9ee540e25c5b3865ae20eedde Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:23:44 +0800 Subject: [PATCH 08/17] feat(windows): use IntelliJ blue selection for sidebar rows and rail Selected activity rail buttons and sidebar list rows now use the blue selection fill token instead of a neutral gray block, and pane headers tighten from 44px to 36px, matching IntelliJ tool window chrome. --- windows/tauri/src/styles/theme.css | 2 +- windows/tauri/src/ui/sidebar.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/windows/tauri/src/styles/theme.css b/windows/tauri/src/styles/theme.css index 0c3f9a6d1..066994578 100644 --- a/windows/tauri/src/styles/theme.css +++ b/windows/tauri/src/styles/theme.css @@ -117,7 +117,7 @@ --ui-text-base: var(--app-ui-font-size); --lithe-title-bar-height: 2.5rem; --lithe-footer-height: 1.5rem; - --lithe-pane-header-height: 2.75rem; + --lithe-pane-header-height: 2.25rem; --lithe-tab-bar-height: var(--lithe-pane-header-height); --lithe-tab-height: 1.75rem; --lithe-tab-max-width: 12.5rem; diff --git a/windows/tauri/src/ui/sidebar.tsx b/windows/tauri/src/ui/sidebar.tsx index ecaccf472..23e948d34 100644 --- a/windows/tauri/src/ui/sidebar.tsx +++ b/windows/tauri/src/ui/sidebar.tsx @@ -240,7 +240,9 @@ export function SidebarListItem({ "font-sans ui-text-chrome flex min-h-(--lithe-tab-height) w-full min-w-0 items-center gap-(--lithe-chrome-gap-loose) rounded-(--lithe-chrome-radius) px-2 py-1 text-left text-subtle-foreground transition-[background-color,color]", "hover:bg-accent/70 hover:text-foreground focus-visible:bg-accent/70 focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20", "disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-transparent disabled:hover:text-subtle-foreground", - active && "bg-accent/80 text-foreground", + // IntelliJ marks selected rail buttons and list rows with the same + // blue selection fill rather than a neutral gray block. + active && "bg-selected text-foreground", iconOnly && "justify-center gap-0 px-0", className, )} From 8f3210001ec04b8f5d8210d0052144f664ed150b Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:24:42 +0800 Subject: [PATCH 09/17] feat(windows): tighten file tree rows to IntelliJ chrome density Tree rows render at the 13px chrome size like the IntelliJ project view, with the chrome radius on selection highlights. --- windows/tauri/src/features/sidebar/components/sidebar-tree.tsx | 2 +- windows/tauri/src/features/sidebar/styles/sidebar-tree.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/tauri/src/features/sidebar/components/sidebar-tree.tsx b/windows/tauri/src/features/sidebar/components/sidebar-tree.tsx index 10803134b..09d5f11ef 100644 --- a/windows/tauri/src/features/sidebar/components/sidebar-tree.tsx +++ b/windows/tauri/src/features/sidebar/components/sidebar-tree.tsx @@ -237,7 +237,7 @@ export const SidebarTreeRow = forwardRef data-depth={depth} tabIndex={tabIndex} className={cn( - "file-tree-row font-sans ui-text-sm flex w-full min-w-0 flex-1 select-none items-center whitespace-nowrap rounded-lg border border-transparent bg-transparent text-left text-foreground outline-none transition-colors duration-(--app-duration-fast) ease-(--app-ease-smooth) hover:bg-accent focus-visible:border-primary/40 gap-1.5 px-1.5 py-1 leading-row", + "file-tree-row font-sans ui-text-chrome flex w-full min-w-0 flex-1 select-none items-center whitespace-nowrap rounded-(--lithe-chrome-radius) border border-transparent bg-transparent text-left text-foreground outline-none transition-colors duration-(--app-duration-fast) ease-(--app-ease-smooth) hover:bg-accent focus-visible:border-primary/40 gap-1.5 px-1.5 py-1 leading-row", active && "bg-selected", action && "pr-0", className, diff --git a/windows/tauri/src/features/sidebar/styles/sidebar-tree.css b/windows/tauri/src/features/sidebar/styles/sidebar-tree.css index 5427cc093..53d601617 100644 --- a/windows/tauri/src/features/sidebar/styles/sidebar-tree.css +++ b/windows/tauri/src/features/sidebar/styles/sidebar-tree.css @@ -11,7 +11,7 @@ position: absolute; inset: 0; z-index: 0; - border-radius: var(--radius-lg); + border-radius: var(--lithe-chrome-radius); background-color: transparent; content: ""; pointer-events: none; From d2ae13a0dbc6acda76c96a6b4563d4ef48ded0a1 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:26:56 +0800 Subject: [PATCH 10/17] feat(windows): tighten popup chrome to IntelliJ menu density Menu and context items render at the 13px chrome size with tighter row padding, and tooltips drop to the 12px caption size. --- windows/tauri/src/ui/context-menu.tsx | 10 +++++----- windows/tauri/src/ui/dropdown-menu.tsx | 8 ++++---- windows/tauri/src/ui/tooltip.tsx | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/windows/tauri/src/ui/context-menu.tsx b/windows/tauri/src/ui/context-menu.tsx index d8eaea80c..e599037b2 100644 --- a/windows/tauri/src/ui/context-menu.tsx +++ b/windows/tauri/src/ui/context-menu.tsx @@ -42,7 +42,7 @@ function ContextMenuContent({ Date: Wed, 19 Aug 2026 15:32:58 +0800 Subject: [PATCH 11/17] chore(windows): vendor IntelliJ file type icons as idea-icons theme Copy 77 Apache-2.0 SVGs (40 definitions, light/dark pairs) from the intellij-community platform file type set into a new bundled idea-icons theme directory, with a mapping file and deterministic generator that emits the extension.json manifest and validates via --check. --- .../tauri/scripts/generate-idea-file-icons.ts | 190 +++++++++++++++++ .../scripts/idea-file-icon-mappings.json | 92 +++++++++ .../bundled/icon-themes/idea/extension.json | 194 ++++++++++++++++++ .../idea/icons/expui/fileTypes/Csharp.svg | 3 + .../icons/expui/fileTypes/Csharp_dark.svg | 3 + .../idea/icons/expui/fileTypes/archive.svg | 8 + .../icons/expui/fileTypes/archive_dark.svg | 8 + .../idea/icons/expui/fileTypes/c.svg | 4 + .../idea/icons/expui/fileTypes/c_dark.svg | 4 + .../idea/icons/expui/fileTypes/cpp.svg | 7 + .../idea/icons/expui/fileTypes/cpp_dark.svg | 7 + .../idea/icons/expui/fileTypes/css.svg | 5 + .../idea/icons/expui/fileTypes/css_dark.svg | 5 + .../idea/icons/expui/fileTypes/csv.svg | 7 + .../idea/icons/expui/fileTypes/csv_dark.svg | 7 + .../idea/icons/expui/fileTypes/docker.svg | 5 + .../icons/expui/fileTypes/docker_dark.svg | 5 + .../icons/expui/fileTypes/editorConfig.svg | 4 + .../expui/fileTypes/editorConfig_dark.svg | 4 + .../idea/icons/expui/fileTypes/font.svg | 5 + .../idea/icons/expui/fileTypes/font_dark.svg | 5 + .../idea/icons/expui/fileTypes/gitignore.svg | 4 + .../idea/icons/expui/fileTypes/gradle.svg | 5 + .../icons/expui/fileTypes/gradle_dark.svg | 5 + .../idea/icons/expui/fileTypes/graphql.svg | 4 + .../icons/expui/fileTypes/graphql_dark.svg | 4 + .../idea/icons/expui/fileTypes/groovy.svg | 5 + .../icons/expui/fileTypes/groovy_dark.svg | 5 + .../idea/icons/expui/fileTypes/h.svg | 6 + .../idea/icons/expui/fileTypes/h_dark.svg | 6 + .../idea/icons/expui/fileTypes/html.svg | 5 + .../idea/icons/expui/fileTypes/html_dark.svg | 5 + .../idea/icons/expui/fileTypes/http.svg | 6 + .../idea/icons/expui/fileTypes/image.svg | 6 + .../idea/icons/expui/fileTypes/image_dark.svg | 6 + .../idea/icons/expui/fileTypes/java.svg | 6 + .../idea/icons/expui/fileTypes/javaScript.svg | 6 + .../icons/expui/fileTypes/javaScript_dark.svg | 6 + .../idea/icons/expui/fileTypes/java_dark.svg | 6 + .../idea/icons/expui/fileTypes/json.svg | 5 + .../idea/icons/expui/fileTypes/json_dark.svg | 5 + .../idea/icons/expui/fileTypes/jsp.svg | 9 + .../idea/icons/expui/fileTypes/jsp_dark.svg | 9 + .../idea/icons/expui/fileTypes/markdown.svg | 5 + .../icons/expui/fileTypes/markdown_dark.svg | 5 + .../idea/icons/expui/fileTypes/patch.svg | 5 + .../idea/icons/expui/fileTypes/patch_dark.svg | 5 + .../idea/icons/expui/fileTypes/perl.svg | 4 + .../idea/icons/expui/fileTypes/perl_dark.svg | 4 + .../idea/icons/expui/fileTypes/properties.svg | 4 + .../icons/expui/fileTypes/properties_dark.svg | 4 + .../idea/icons/expui/fileTypes/rst.svg | 8 + .../idea/icons/expui/fileTypes/rst_dark.svg | 8 + .../idea/icons/expui/fileTypes/shell.svg | 6 + .../idea/icons/expui/fileTypes/shell_dark.svg | 6 + .../idea/icons/expui/fileTypes/sql.svg | 10 + .../idea/icons/expui/fileTypes/sql_dark.svg | 10 + .../idea/icons/expui/fileTypes/swiftLang.svg | 3 + .../icons/expui/fileTypes/swiftLang_dark.svg | 3 + .../idea/icons/expui/fileTypes/terraform.svg | 6 + .../icons/expui/fileTypes/terraform_dark.svg | 6 + .../idea/icons/expui/fileTypes/text.svg | 7 + .../idea/icons/expui/fileTypes/text_dark.svg | 7 + .../idea/icons/expui/fileTypes/toml.svg | 5 + .../idea/icons/expui/fileTypes/toml_dark.svg | 5 + .../idea/icons/expui/fileTypes/typeScript.svg | 6 + .../icons/expui/fileTypes/typeScript_dark.svg | 6 + .../idea/icons/expui/fileTypes/vue.svg | 6 + .../idea/icons/expui/fileTypes/wsdl.svg | 8 + .../idea/icons/expui/fileTypes/wsdl_dark.svg | 8 + .../idea/icons/expui/fileTypes/xhtml.svg | 5 + .../idea/icons/expui/fileTypes/xhtml_dark.svg | 5 + .../idea/icons/expui/fileTypes/xml.svg | 4 + .../idea/icons/expui/fileTypes/xml_dark.svg | 4 + .../idea/icons/expui/fileTypes/xsd.svg | 9 + .../idea/icons/expui/fileTypes/xsd_dark.svg | 9 + .../idea/icons/expui/fileTypes/yaml.svg | 7 + .../idea/icons/expui/fileTypes/yaml_dark.svg | 7 + .../idea/icons/expui/nodes/folder.svg | 4 + .../idea/icons/expui/nodes/folder_dark.svg | 4 + 80 files changed, 914 insertions(+) create mode 100644 windows/tauri/scripts/generate-idea-file-icons.ts create mode 100644 windows/tauri/scripts/idea-file-icon-mappings.json create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/extension.json create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gitignore.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/http.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/vue.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder_dark.svg diff --git a/windows/tauri/scripts/generate-idea-file-icons.ts b/windows/tauri/scripts/generate-idea-file-icons.ts new file mode 100644 index 000000000..a71c73c34 --- /dev/null +++ b/windows/tauri/scripts/generate-idea-file-icons.ts @@ -0,0 +1,190 @@ +/** + * Builds the bundled `idea-icons` file icon theme from IntelliJ platform + * assets: copies SVGs into + * src/extensions/bundled/icon-themes/idea/icons and emits the theme's + * extension.json manifest. + * + * Usage (run from windows/tauri): + * bun scripts/generate-idea-file-icons.ts --source /platform/icons/src [--check] + * + * Dark appearance uses the `_dark.svg` sibling when present; the light + * appearance always uses the base file. Copied SVGs keep their embedded + * Apache-2.0 copyright comments untouched. + */ +import { createHash } from "node:crypto"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; + +interface FileThemeMapping { + fileExtensions: Record; + filenames: Record; + folders: Record; + defaultFile: string; + defaultFolder: string; +} + +const REPO_ROOT = resolve(import.meta.dir, ".."); +const MAPPING_PATH = join(import.meta.dir, "idea-file-icon-mappings.json"); +const THEME_DIR = join(REPO_ROOT, "src/extensions/bundled/icon-themes/idea"); +const MANIFEST_PATH = join(THEME_DIR, "extension.json"); + +function parseArgs(): { source: string | null; check: boolean } { + const argv = process.argv.slice(2); + let source: string | null = null; + let check = false; + for (let i = 0; i < argv.length; i += 1) { + if (argv[i] === "--source" && argv[i + 1]) { + source = resolve(argv[i + 1]); + i += 1; + } else if (argv[i] === "--check") { + check = true; + } + } + return { source, check }; +} + +function sha(buffer: Buffer): string { + return createHash("sha256").update(buffer).digest("hex"); +} + +function definitionName(source: string): string { + const file = source.split("/").pop() ?? source; + return `idea-${file.replace(/\.svg$/, "")}`; +} + +function themeAssetPath(source: string, dark: boolean): string { + const rel = dark ? source.replace(/\.svg$/, "_dark.svg") : source; + return `./icons/${rel}`; +} + +const { source: sourceRoot, check } = parseArgs(); +if (!sourceRoot) { + console.error("Missing --source /platform/icons/src"); + process.exit(1); +} + +const mapping = JSON.parse(readFileSync(MAPPING_PATH, "utf8")) as FileThemeMapping; + +const entries = new Map(); // definition name -> source svg +const mapKeys = new Map(); // ".ts" / "Dockerfile" / "src" -> definition name + +function registerEntries(record: Record): string[] { + const keys: string[] = []; + for (const [key, source] of Object.entries(record)) { + const name = definitionName(source); + entries.set(name, source); + mapKeys.set(key, name); + keys.push(key); + } + return keys; +} + +const extensionKeys = registerEntries(mapping.fileExtensions); +const filenameKeys = registerEntries(mapping.filenames); +const folderKeys = registerEntries(mapping.folders); +entries.set(definitionName(mapping.defaultFile), mapping.defaultFile); +entries.set(definitionName(mapping.defaultFolder), mapping.defaultFolder); + +const missing: string[] = []; +const darkVariants = new Map(); // definition name -> has dark pair +for (const [name, source] of entries) { + if (!existsSync(join(sourceRoot, source))) { + missing.push(source); + continue; + } + const hasDark = existsSync(join(sourceRoot, source.replace(/\.svg$/, "_dark.svg"))); + darkVariants.set(name, hasDark); +} +if (missing.length > 0) { + console.error(missing.map((s) => `source SVG not found: ${s}`).join("\n")); + process.exit(1); +} + +const iconDefinitions: Record = {}; +const lightIconDefinitions: Record = {}; +const fileExtensions: Record = {}; +const filenames: Record = {}; +const folders: Record = {}; +const expandedFolders: Record = {}; + +for (const [name, source] of entries) { + const hasDark = darkVariants.get(name) === true; + iconDefinitions[name] = themeAssetPath(source, hasDark); + lightIconDefinitions[name] = themeAssetPath(source, false); +} +for (const key of extensionKeys) fileExtensions[key] = mapKeys.get(key)!; +for (const key of filenameKeys) filenames[key] = mapKeys.get(key)!; +for (const key of folderKeys) { + folders[key] = mapKeys.get(key)!; + expandedFolders[key] = mapKeys.get(key)!; +} + +const manifest = { + $schema: "https://lithe.dev/schemas/extension.json", + id: "lithe.icon-theme.idea-icons", + name: "idea-icons", + displayName: "IDEA Icons", + publisher: "Lithe", + categories: ["Icon Theme"], + version: "0.1.0", + description: + "File icons from the IntelliJ platform icon set (intellij-community, Apache-2.0, embedded per-file copyright notices preserved).", + icons: [ + { + id: "idea-icons", + name: "IDEA Icons", + description: + "File icons from the IntelliJ platform icon set (intellij-community, Apache-2.0).", + defaultFile: definitionName(mapping.defaultFile), + defaultFolder: definitionName(mapping.defaultFolder), + defaultFolderOpen: definitionName(mapping.defaultFolder), + iconDefinitions, + lightIconDefinitions, + fileExtensions, + filenames, + folders, + expandedFolders, + }, + ], +}; + +const filesToCopy: Array<[string, boolean]> = []; +for (const [name, source] of entries) { + filesToCopy.push([source, false]); + if (darkVariants.get(name) === true) { + filesToCopy.push([source.replace(/\.svg$/, "_dark.svg"), true]); + } +} + +if (check) { + const problems: string[] = []; + const current = readFileSync(MANIFEST_PATH, "utf8"); + const expected = JSON.stringify(manifest, null, 2) + "\n"; + if (current !== expected) { + problems.push("extension.json is out of date; rerun the generator"); + } + for (const [rel] of filesToCopy) { + const copied = join(THEME_DIR, "icons", rel); + if (!existsSync(copied)) { + problems.push(`missing copied asset: idea/icons/${rel}`); + } else if (sha(readFileSync(copied)) !== sha(readFileSync(join(sourceRoot, rel)))) { + problems.push(`copied asset differs from source: idea/icons/${rel}`); + } + } + if (problems.length > 0) { + console.error(problems.join("\n")); + process.exit(1); + } + console.log(`idea-icons theme check passed (${entries.size} definitions)`); + process.exit(0); +} + +for (const [rel] of filesToCopy) { + const dest = join(THEME_DIR, "icons", rel); + mkdirSync(dirname(dest), { recursive: true }); + writeFileSync(dest, readFileSync(join(sourceRoot, rel))); +} +writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + "\n"); +console.log( + `Copied ${filesToCopy.length} SVGs and emitted idea-icons extension.json (${entries.size} definitions)`, +); diff --git a/windows/tauri/scripts/idea-file-icon-mappings.json b/windows/tauri/scripts/idea-file-icon-mappings.json new file mode 100644 index 000000000..c4cd472b2 --- /dev/null +++ b/windows/tauri/scripts/idea-file-icon-mappings.json @@ -0,0 +1,92 @@ +{ + "description": "Lithe idea-icons file theme mapping: file extension / filename -> IntelliJ platform icon SVG (relative to intellij-community platform/icons/src). Managed by scripts/generate-idea-file-icons.ts. Assets without a dark pair render the base file in both appearances.", + "fileExtensions": { + ".ts": "expui/fileTypes/typeScript.svg", + ".mts": "expui/fileTypes/typeScript.svg", + ".cts": "expui/fileTypes/typeScript.svg", + ".tsx": "expui/fileTypes/typeScript.svg", + ".js": "expui/fileTypes/javaScript.svg", + ".mjs": "expui/fileTypes/javaScript.svg", + ".cjs": "expui/fileTypes/javaScript.svg", + ".jsx": "expui/fileTypes/javaScript.svg", + ".json": "expui/fileTypes/json.svg", + ".jsonc": "expui/fileTypes/json.svg", + ".json5": "expui/fileTypes/json.svg", + ".md": "expui/fileTypes/markdown.svg", + ".mdx": "expui/fileTypes/markdown.svg", + ".java": "expui/fileTypes/java.svg", + ".xml": "expui/fileTypes/xml.svg", + ".xsd": "expui/fileTypes/xsd.svg", + ".wsdl": "expui/fileTypes/wsdl.svg", + ".xhtml": "expui/fileTypes/xhtml.svg", + ".yml": "expui/fileTypes/yaml.svg", + ".yaml": "expui/fileTypes/yaml.svg", + ".html": "expui/fileTypes/html.svg", + ".htm": "expui/fileTypes/html.svg", + ".css": "expui/fileTypes/css.svg", + ".scss": "expui/fileTypes/css.svg", + ".less": "expui/fileTypes/css.svg", + ".sass": "expui/fileTypes/css.svg", + ".sql": "expui/fileTypes/sql.svg", + ".sh": "expui/fileTypes/shell.svg", + ".bash": "expui/fileTypes/shell.svg", + ".zsh": "expui/fileTypes/shell.svg", + ".properties": "expui/fileTypes/properties.svg", + ".toml": "expui/fileTypes/toml.svg", + ".csv": "expui/fileTypes/csv.svg", + ".http": "expui/fileTypes/http.svg", + ".png": "expui/fileTypes/image.svg", + ".jpg": "expui/fileTypes/image.svg", + ".jpeg": "expui/fileTypes/image.svg", + ".gif": "expui/fileTypes/image.svg", + ".svg": "expui/fileTypes/image.svg", + ".webp": "expui/fileTypes/image.svg", + ".ico": "expui/fileTypes/image.svg", + ".bmp": "expui/fileTypes/image.svg", + ".zip": "expui/fileTypes/archive.svg", + ".tar": "expui/fileTypes/archive.svg", + ".gz": "expui/fileTypes/archive.svg", + ".tgz": "expui/fileTypes/archive.svg", + ".7z": "expui/fileTypes/archive.svg", + ".rar": "expui/fileTypes/archive.svg", + ".ttf": "expui/fileTypes/font.svg", + ".otf": "expui/fileTypes/font.svg", + ".woff": "expui/fileTypes/font.svg", + ".woff2": "expui/fileTypes/font.svg", + ".vue": "expui/fileTypes/vue.svg", + ".graphql": "expui/fileTypes/graphql.svg", + ".gql": "expui/fileTypes/graphql.svg", + ".tf": "expui/fileTypes/terraform.svg", + ".hcl": "expui/fileTypes/terraform.svg", + ".swift": "expui/fileTypes/swiftLang.svg", + ".c": "expui/fileTypes/c.svg", + ".h": "expui/fileTypes/h.svg", + ".cpp": "expui/fileTypes/cpp.svg", + ".cc": "expui/fileTypes/cpp.svg", + ".cxx": "expui/fileTypes/cpp.svg", + ".hpp": "expui/fileTypes/h.svg", + ".cs": "expui/fileTypes/Csharp.svg", + ".jsp": "expui/fileTypes/jsp.svg", + ".gradle": "expui/fileTypes/gradle.svg", + ".kts": "expui/fileTypes/gradle.svg", + ".groovy": "expui/fileTypes/groovy.svg", + ".pl": "expui/fileTypes/perl.svg", + ".rst": "expui/fileTypes/rst.svg", + ".patch": "expui/fileTypes/patch.svg", + ".diff": "expui/fileTypes/patch.svg", + ".txt": "expui/fileTypes/text.svg", + ".log": "expui/fileTypes/text.svg", + ".lock": "expui/fileTypes/text.svg" + }, + "filenames": { + "dockerfile": "expui/fileTypes/docker.svg", + ".gitignore": "expui/fileTypes/gitignore.svg", + ".editorconfig": "expui/fileTypes/editorConfig.svg", + ".env": "expui/fileTypes/properties.svg", + "license": "expui/fileTypes/text.svg", + "notice": "expui/fileTypes/text.svg" + }, + "folders": {}, + "defaultFile": "expui/fileTypes/text.svg", + "defaultFolder": "expui/nodes/folder.svg" +} diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/extension.json b/windows/tauri/src/extensions/bundled/icon-themes/idea/extension.json new file mode 100644 index 000000000..517ec8dac --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/extension.json @@ -0,0 +1,194 @@ +{ + "$schema": "https://lithe.dev/schemas/extension.json", + "id": "lithe.icon-theme.idea-icons", + "name": "idea-icons", + "displayName": "IDEA Icons", + "publisher": "Lithe", + "categories": [ + "Icon Theme" + ], + "version": "0.1.0", + "description": "File icons from the IntelliJ platform icon set (intellij-community, Apache-2.0, embedded per-file copyright notices preserved).", + "icons": [ + { + "id": "idea-icons", + "name": "IDEA Icons", + "description": "File icons from the IntelliJ platform icon set (intellij-community, Apache-2.0).", + "defaultFile": "idea-text", + "defaultFolder": "idea-folder", + "defaultFolderOpen": "idea-folder", + "iconDefinitions": { + "idea-typeScript": "./icons/expui/fileTypes/typeScript_dark.svg", + "idea-javaScript": "./icons/expui/fileTypes/javaScript_dark.svg", + "idea-json": "./icons/expui/fileTypes/json_dark.svg", + "idea-markdown": "./icons/expui/fileTypes/markdown_dark.svg", + "idea-java": "./icons/expui/fileTypes/java_dark.svg", + "idea-xml": "./icons/expui/fileTypes/xml_dark.svg", + "idea-xsd": "./icons/expui/fileTypes/xsd_dark.svg", + "idea-wsdl": "./icons/expui/fileTypes/wsdl_dark.svg", + "idea-xhtml": "./icons/expui/fileTypes/xhtml_dark.svg", + "idea-yaml": "./icons/expui/fileTypes/yaml_dark.svg", + "idea-html": "./icons/expui/fileTypes/html_dark.svg", + "idea-css": "./icons/expui/fileTypes/css_dark.svg", + "idea-sql": "./icons/expui/fileTypes/sql_dark.svg", + "idea-shell": "./icons/expui/fileTypes/shell_dark.svg", + "idea-properties": "./icons/expui/fileTypes/properties_dark.svg", + "idea-toml": "./icons/expui/fileTypes/toml_dark.svg", + "idea-csv": "./icons/expui/fileTypes/csv_dark.svg", + "idea-http": "./icons/expui/fileTypes/http.svg", + "idea-image": "./icons/expui/fileTypes/image_dark.svg", + "idea-archive": "./icons/expui/fileTypes/archive_dark.svg", + "idea-font": "./icons/expui/fileTypes/font_dark.svg", + "idea-vue": "./icons/expui/fileTypes/vue.svg", + "idea-graphql": "./icons/expui/fileTypes/graphql_dark.svg", + "idea-terraform": "./icons/expui/fileTypes/terraform_dark.svg", + "idea-swiftLang": "./icons/expui/fileTypes/swiftLang_dark.svg", + "idea-c": "./icons/expui/fileTypes/c_dark.svg", + "idea-h": "./icons/expui/fileTypes/h_dark.svg", + "idea-cpp": "./icons/expui/fileTypes/cpp_dark.svg", + "idea-Csharp": "./icons/expui/fileTypes/Csharp_dark.svg", + "idea-jsp": "./icons/expui/fileTypes/jsp_dark.svg", + "idea-gradle": "./icons/expui/fileTypes/gradle_dark.svg", + "idea-groovy": "./icons/expui/fileTypes/groovy_dark.svg", + "idea-perl": "./icons/expui/fileTypes/perl_dark.svg", + "idea-rst": "./icons/expui/fileTypes/rst_dark.svg", + "idea-patch": "./icons/expui/fileTypes/patch_dark.svg", + "idea-text": "./icons/expui/fileTypes/text_dark.svg", + "idea-docker": "./icons/expui/fileTypes/docker_dark.svg", + "idea-gitignore": "./icons/expui/fileTypes/gitignore.svg", + "idea-editorConfig": "./icons/expui/fileTypes/editorConfig_dark.svg", + "idea-folder": "./icons/expui/nodes/folder_dark.svg" + }, + "lightIconDefinitions": { + "idea-typeScript": "./icons/expui/fileTypes/typeScript.svg", + "idea-javaScript": "./icons/expui/fileTypes/javaScript.svg", + "idea-json": "./icons/expui/fileTypes/json.svg", + "idea-markdown": "./icons/expui/fileTypes/markdown.svg", + "idea-java": "./icons/expui/fileTypes/java.svg", + "idea-xml": "./icons/expui/fileTypes/xml.svg", + "idea-xsd": "./icons/expui/fileTypes/xsd.svg", + "idea-wsdl": "./icons/expui/fileTypes/wsdl.svg", + "idea-xhtml": "./icons/expui/fileTypes/xhtml.svg", + "idea-yaml": "./icons/expui/fileTypes/yaml.svg", + "idea-html": "./icons/expui/fileTypes/html.svg", + "idea-css": "./icons/expui/fileTypes/css.svg", + "idea-sql": "./icons/expui/fileTypes/sql.svg", + "idea-shell": "./icons/expui/fileTypes/shell.svg", + "idea-properties": "./icons/expui/fileTypes/properties.svg", + "idea-toml": "./icons/expui/fileTypes/toml.svg", + "idea-csv": "./icons/expui/fileTypes/csv.svg", + "idea-http": "./icons/expui/fileTypes/http.svg", + "idea-image": "./icons/expui/fileTypes/image.svg", + "idea-archive": "./icons/expui/fileTypes/archive.svg", + "idea-font": "./icons/expui/fileTypes/font.svg", + "idea-vue": "./icons/expui/fileTypes/vue.svg", + "idea-graphql": "./icons/expui/fileTypes/graphql.svg", + "idea-terraform": "./icons/expui/fileTypes/terraform.svg", + "idea-swiftLang": "./icons/expui/fileTypes/swiftLang.svg", + "idea-c": "./icons/expui/fileTypes/c.svg", + "idea-h": "./icons/expui/fileTypes/h.svg", + "idea-cpp": "./icons/expui/fileTypes/cpp.svg", + "idea-Csharp": "./icons/expui/fileTypes/Csharp.svg", + "idea-jsp": "./icons/expui/fileTypes/jsp.svg", + "idea-gradle": "./icons/expui/fileTypes/gradle.svg", + "idea-groovy": "./icons/expui/fileTypes/groovy.svg", + "idea-perl": "./icons/expui/fileTypes/perl.svg", + "idea-rst": "./icons/expui/fileTypes/rst.svg", + "idea-patch": "./icons/expui/fileTypes/patch.svg", + "idea-text": "./icons/expui/fileTypes/text.svg", + "idea-docker": "./icons/expui/fileTypes/docker.svg", + "idea-gitignore": "./icons/expui/fileTypes/gitignore.svg", + "idea-editorConfig": "./icons/expui/fileTypes/editorConfig.svg", + "idea-folder": "./icons/expui/nodes/folder.svg" + }, + "fileExtensions": { + ".ts": "idea-typeScript", + ".mts": "idea-typeScript", + ".cts": "idea-typeScript", + ".tsx": "idea-typeScript", + ".js": "idea-javaScript", + ".mjs": "idea-javaScript", + ".cjs": "idea-javaScript", + ".jsx": "idea-javaScript", + ".json": "idea-json", + ".jsonc": "idea-json", + ".json5": "idea-json", + ".md": "idea-markdown", + ".mdx": "idea-markdown", + ".java": "idea-java", + ".xml": "idea-xml", + ".xsd": "idea-xsd", + ".wsdl": "idea-wsdl", + ".xhtml": "idea-xhtml", + ".yml": "idea-yaml", + ".yaml": "idea-yaml", + ".html": "idea-html", + ".htm": "idea-html", + ".css": "idea-css", + ".scss": "idea-css", + ".less": "idea-css", + ".sass": "idea-css", + ".sql": "idea-sql", + ".sh": "idea-shell", + ".bash": "idea-shell", + ".zsh": "idea-shell", + ".properties": "idea-properties", + ".toml": "idea-toml", + ".csv": "idea-csv", + ".http": "idea-http", + ".png": "idea-image", + ".jpg": "idea-image", + ".jpeg": "idea-image", + ".gif": "idea-image", + ".svg": "idea-image", + ".webp": "idea-image", + ".ico": "idea-image", + ".bmp": "idea-image", + ".zip": "idea-archive", + ".tar": "idea-archive", + ".gz": "idea-archive", + ".tgz": "idea-archive", + ".7z": "idea-archive", + ".rar": "idea-archive", + ".ttf": "idea-font", + ".otf": "idea-font", + ".woff": "idea-font", + ".woff2": "idea-font", + ".vue": "idea-vue", + ".graphql": "idea-graphql", + ".gql": "idea-graphql", + ".tf": "idea-terraform", + ".hcl": "idea-terraform", + ".swift": "idea-swiftLang", + ".c": "idea-c", + ".h": "idea-h", + ".cpp": "idea-cpp", + ".cc": "idea-cpp", + ".cxx": "idea-cpp", + ".hpp": "idea-h", + ".cs": "idea-Csharp", + ".jsp": "idea-jsp", + ".gradle": "idea-gradle", + ".kts": "idea-gradle", + ".groovy": "idea-groovy", + ".pl": "idea-perl", + ".rst": "idea-rst", + ".patch": "idea-patch", + ".diff": "idea-patch", + ".txt": "idea-text", + ".log": "idea-text", + ".lock": "idea-text" + }, + "filenames": { + "dockerfile": "idea-docker", + ".gitignore": "idea-gitignore", + ".editorconfig": "idea-editorConfig", + ".env": "idea-properties", + "license": "idea-text", + "notice": "idea-text" + }, + "folders": {}, + "expandedFolders": {} + } + ] +} diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp.svg new file mode 100644 index 000000000..cc74ead1e --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp.svg @@ -0,0 +1,3 @@ + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp_dark.svg new file mode 100644 index 000000000..c0b2a9df3 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/Csharp_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive.svg new file mode 100644 index 000000000..87bbbeece --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive_dark.svg new file mode 100644 index 000000000..ab3cae2cc --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/archive_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c.svg new file mode 100644 index 000000000..b7a663f5a --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c_dark.svg new file mode 100644 index 000000000..af5455250 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/c_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp.svg new file mode 100644 index 000000000..e8c8c1949 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp_dark.svg new file mode 100644 index 000000000..3c4442388 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/cpp_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css.svg new file mode 100644 index 000000000..929203773 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css_dark.svg new file mode 100644 index 000000000..f541ee8c7 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/css_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv.svg new file mode 100644 index 000000000..cc5fa2eaa --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv_dark.svg new file mode 100644 index 000000000..d038177a9 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/csv_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker.svg new file mode 100644 index 000000000..a4f9cab91 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker_dark.svg new file mode 100644 index 000000000..5369a264a --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/docker_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig.svg new file mode 100644 index 000000000..547bba721 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig_dark.svg new file mode 100644 index 000000000..528d02ebe --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/editorConfig_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font.svg new file mode 100644 index 000000000..9e187b36f --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font_dark.svg new file mode 100644 index 000000000..94fbd32d9 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/font_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gitignore.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gitignore.svg new file mode 100644 index 000000000..86228c617 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gitignore.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle.svg new file mode 100644 index 000000000..29f3e59ee --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle_dark.svg new file mode 100644 index 000000000..37c055abf --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/gradle_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql.svg new file mode 100644 index 000000000..d4dd36ac3 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql_dark.svg new file mode 100644 index 000000000..a0095957d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/graphql_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy.svg new file mode 100644 index 000000000..671aff55e --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy_dark.svg new file mode 100644 index 000000000..0dfe6a462 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/groovy_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h.svg new file mode 100644 index 000000000..1905b901a --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h_dark.svg new file mode 100644 index 000000000..935071870 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/h_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html.svg new file mode 100644 index 000000000..c446cf39e --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html_dark.svg new file mode 100644 index 000000000..9e10d57f1 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/html_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/http.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/http.svg new file mode 100644 index 000000000..906237407 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/http.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image.svg new file mode 100644 index 000000000..9a09720fa --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image_dark.svg new file mode 100644 index 000000000..4f189a0e3 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/image_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java.svg new file mode 100644 index 000000000..00e1a4c96 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript.svg new file mode 100644 index 000000000..d7eb6cc8d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript_dark.svg new file mode 100644 index 000000000..188617076 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/javaScript_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java_dark.svg new file mode 100644 index 000000000..155295f59 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/java_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json.svg new file mode 100644 index 000000000..d8f707dd5 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json_dark.svg new file mode 100644 index 000000000..29371ab71 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/json_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp.svg new file mode 100644 index 000000000..564a2190c --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp_dark.svg new file mode 100644 index 000000000..1c04aa9cf --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/jsp_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown.svg new file mode 100644 index 000000000..c603fd236 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown_dark.svg new file mode 100644 index 000000000..2d86cd368 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/markdown_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch.svg new file mode 100644 index 000000000..b3a1d040b --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch_dark.svg new file mode 100644 index 000000000..e6d13133e --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/patch_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl.svg new file mode 100644 index 000000000..565044076 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl_dark.svg new file mode 100644 index 000000000..870ac8faa --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/perl_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties.svg new file mode 100644 index 000000000..547bba721 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties_dark.svg new file mode 100644 index 000000000..528d02ebe --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/properties_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst.svg new file mode 100644 index 000000000..09c5b340e --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst_dark.svg new file mode 100644 index 000000000..ae54b4de1 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/rst_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell.svg new file mode 100644 index 000000000..0676afdd7 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell_dark.svg new file mode 100644 index 000000000..7022d0c76 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/shell_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql.svg new file mode 100644 index 000000000..a57c04270 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql_dark.svg new file mode 100644 index 000000000..57d62ee80 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/sql_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang.svg new file mode 100644 index 000000000..4b6e68b65 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang.svg @@ -0,0 +1,3 @@ + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang_dark.svg new file mode 100644 index 000000000..5d386f489 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/swiftLang_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform.svg new file mode 100644 index 000000000..ac3ca7839 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform_dark.svg new file mode 100644 index 000000000..4c4d9bfee --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/terraform_dark.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text.svg new file mode 100644 index 000000000..110139cf6 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text_dark.svg new file mode 100644 index 000000000..86468276b --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/text_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml.svg new file mode 100644 index 000000000..10789f0e9 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml_dark.svg new file mode 100644 index 000000000..b9e6aea69 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/toml_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript.svg new file mode 100644 index 000000000..b4d487f0d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript_dark.svg new file mode 100644 index 000000000..5c74ff7f7 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/typeScript_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/vue.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/vue.svg new file mode 100644 index 000000000..8625428aa --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/vue.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl.svg new file mode 100644 index 000000000..a92e9c5c0 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl_dark.svg new file mode 100644 index 000000000..3732545ba --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/wsdl_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml.svg new file mode 100644 index 000000000..94b886f9b --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml_dark.svg new file mode 100644 index 000000000..432f62e24 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xhtml_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml.svg new file mode 100644 index 000000000..154c1eded --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml_dark.svg new file mode 100644 index 000000000..8a2eb779d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xml_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd.svg new file mode 100644 index 000000000..0c87edc93 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd_dark.svg new file mode 100644 index 000000000..c012bd1e6 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/xsd_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml.svg new file mode 100644 index 000000000..9d4031ee2 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml_dark.svg new file mode 100644 index 000000000..b173b95d9 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/yaml_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder.svg new file mode 100644 index 000000000..7ece6b711 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder_dark.svg new file mode 100644 index 000000000..0af492bad --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/folder_dark.svg @@ -0,0 +1,4 @@ + + + + From 94c8435e7299b70fe9575e9dbd8aaa76b0a88f69 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 15:32:59 +0800 Subject: [PATCH 12/17] feat(windows): register the idea-icons bundled file theme Register the new theme in the bundled extension manifests and icon asset glob so it appears alongside lithe-icons in appearance settings. --- .../src/extensions/bundled/bundled-extension-manifests.ts | 5 +++++ .../src/extensions/icon-themes/bundled-icon-theme-assets.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts b/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts index 435e28e14..b03fbc76b 100644 --- a/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts +++ b/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts @@ -1,4 +1,5 @@ import litheIconTheme from "./icon-themes/lithe/extension.json"; +import ideaIconTheme from "./icon-themes/idea/extension.json"; import materialIconTheme from "./icon-themes/material/extension.json"; import pierreIconTheme from "./icon-themes/pierre/extension.json"; import symbolsIconTheme from "./icon-themes/symbols/extension.json"; @@ -14,6 +15,10 @@ export const bundledExtensionManifests: BundledExtensionManifestEntry[] = [ manifest: litheIconTheme as ExtensionManifest, relativePath: "icon-themes/lithe", }, + { + manifest: ideaIconTheme as ExtensionManifest, + relativePath: "icon-themes/idea", + }, { manifest: symbolsIconTheme as ExtensionManifest, relativePath: "icon-themes/symbols", diff --git a/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts b/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts index 735a07b6f..5fb2d195a 100644 --- a/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts +++ b/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts @@ -1,5 +1,5 @@ const BUNDLED_ICON_THEME_ASSETS = import.meta.glob( - "../bundled/icon-themes/{lithe,material,pierre,symbols}/**/*.svg", + "../bundled/icon-themes/{idea,lithe,material,pierre,symbols}/**/*.svg", { eager: true, import: "default", @@ -9,6 +9,7 @@ const BUNDLED_ICON_THEME_ASSETS = import.meta.glob( const BUNDLED_ICON_THEME_DIRECTORIES: Record = { "lithe.icon-theme.lithe-icons": "lithe", + "lithe.icon-theme.idea-icons": "idea", "lithe.icon-theme.material": "material", "lithe.icon-theme.pierre": "pierre", "lithe.icon-theme.symbols": "symbols", From 520f3c774755ba7c8aeaed7f0464473e2a4767d3 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Wed, 19 Aug 2026 21:05:29 +0800 Subject: [PATCH 13/17] feat(windows): make IDEA icons the default file theme --- .../bundled-extension-manifests.test.ts | 11 +++++++++++ .../bundled/bundled-extension-manifests.ts | 5 ----- .../icon-themes/bundled-icon-theme-assets.ts | 3 +-- .../settings/config/default-settings.ts | 2 +- .../lib/settings-normalization.test.ts | 19 +++++++++++++++++++ .../settings/lib/settings-normalization.ts | 3 ++- 6 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 windows/tauri/src/extensions/bundled-extension-manifests.test.ts diff --git a/windows/tauri/src/extensions/bundled-extension-manifests.test.ts b/windows/tauri/src/extensions/bundled-extension-manifests.test.ts new file mode 100644 index 000000000..97754510e --- /dev/null +++ b/windows/tauri/src/extensions/bundled-extension-manifests.test.ts @@ -0,0 +1,11 @@ +import { describe, expect, test } from "bun:test"; +import { bundledExtensionManifests } from "./bundled/bundled-extension-manifests"; + +describe("bundled file icon themes", () => { + test("ships IDEA Icons without the retired Lithe icon theme", () => { + const extensionIds = bundledExtensionManifests.map(({ manifest }) => manifest.id); + + expect(extensionIds).toContain("lithe.icon-theme.idea-icons"); + expect(extensionIds).not.toContain("lithe.icon-theme.lithe-icons"); + }); +}); diff --git a/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts b/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts index b03fbc76b..d98c48118 100644 --- a/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts +++ b/windows/tauri/src/extensions/bundled/bundled-extension-manifests.ts @@ -1,4 +1,3 @@ -import litheIconTheme from "./icon-themes/lithe/extension.json"; import ideaIconTheme from "./icon-themes/idea/extension.json"; import materialIconTheme from "./icon-themes/material/extension.json"; import pierreIconTheme from "./icon-themes/pierre/extension.json"; @@ -11,10 +10,6 @@ export interface BundledExtensionManifestEntry { } export const bundledExtensionManifests: BundledExtensionManifestEntry[] = [ - { - manifest: litheIconTheme as ExtensionManifest, - relativePath: "icon-themes/lithe", - }, { manifest: ideaIconTheme as ExtensionManifest, relativePath: "icon-themes/idea", diff --git a/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts b/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts index 5fb2d195a..b8f83c4df 100644 --- a/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts +++ b/windows/tauri/src/extensions/icon-themes/bundled-icon-theme-assets.ts @@ -1,5 +1,5 @@ const BUNDLED_ICON_THEME_ASSETS = import.meta.glob( - "../bundled/icon-themes/{idea,lithe,material,pierre,symbols}/**/*.svg", + "../bundled/icon-themes/{idea,material,pierre,symbols}/**/*.svg", { eager: true, import: "default", @@ -8,7 +8,6 @@ const BUNDLED_ICON_THEME_ASSETS = import.meta.glob( ) as Record; const BUNDLED_ICON_THEME_DIRECTORIES: Record = { - "lithe.icon-theme.lithe-icons": "lithe", "lithe.icon-theme.idea-icons": "idea", "lithe.icon-theme.material": "material", "lithe.icon-theme.pierre": "pierre", diff --git a/windows/tauri/src/features/settings/config/default-settings.ts b/windows/tauri/src/features/settings/config/default-settings.ts index 356f7ba4a..0e5845d53 100644 --- a/windows/tauri/src/features/settings/config/default-settings.ts +++ b/windows/tauri/src/features/settings/config/default-settings.ts @@ -72,7 +72,7 @@ export const defaultSettings: Settings = { windowChromeDensity: "focused", // Theme theme: "lithe-dark", - iconTheme: "lithe-icons", + iconTheme: "idea-icons", syncSystemTheme: false, autoThemeLight: "lithe-light", autoThemeDark: "lithe-dark", diff --git a/windows/tauri/src/features/settings/lib/settings-normalization.test.ts b/windows/tauri/src/features/settings/lib/settings-normalization.test.ts index 9bf0590dc..ecf330bf5 100644 --- a/windows/tauri/src/features/settings/lib/settings-normalization.test.ts +++ b/windows/tauri/src/features/settings/lib/settings-normalization.test.ts @@ -23,3 +23,22 @@ describe("JDTLS JDK setting normalization", () => { expect(normalizeSettings(settings).jdtlsJavaHomePath).toBe(""); }); }); + +describe("IDEA file icon theme normalization", () => { + test("uses IDEA Icons for new settings", () => { + expect(getDefaultSettingsSnapshot().iconTheme).toBe("idea-icons"); + }); + + test("migrates current and legacy Lithe icon theme ids", () => { + for (const iconTheme of [ + "lithe-icons", + "lithe-icons-dimmed", + "lithe-icons-light", + "lithe-file-icons", + "lithe-file-icons-dark", + "lithe-file-icons-light", + ]) { + expect(normalizeSettingValue("iconTheme", iconTheme)).toBe("idea-icons"); + } + }); +}); diff --git a/windows/tauri/src/features/settings/lib/settings-normalization.ts b/windows/tauri/src/features/settings/lib/settings-normalization.ts index 767c0b74e..41964801c 100644 --- a/windows/tauri/src/features/settings/lib/settings-normalization.ts +++ b/windows/tauri/src/features/settings/lib/settings-normalization.ts @@ -207,13 +207,14 @@ function normalizeStringList(value: unknown): string[] { function normalizeIconTheme(value: string): string { if ( + value === "lithe-icons" || value === "lithe-icons-dimmed" || value === "lithe-icons-light" || value === "lithe-file-icons" || value === "lithe-file-icons-dark" || value === "lithe-file-icons-light" ) { - return "lithe-icons"; + return "idea-icons"; } if (value === "colorful-material" || value === "seti") { From 328285db3e71c48c6f146949f09e35fa9339a708 Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Thu, 20 Aug 2026 19:19:48 +0800 Subject: [PATCH 14/17] feat(windows): add semantic IDEA project icons --- scripts/build-windows.ps1 | 60 +++- .../tauri/scripts/generate-idea-file-icons.ts | 118 ++++--- .../scripts/idea-file-icon-mappings.json | 21 +- .../bundled-extension-manifests.test.ts | 70 +++++ .../bundled/icon-themes/idea/extension.json | 47 ++- .../idea/icons/expui/fileTypes/maven.svg | 4 + .../idea/icons/expui/fileTypes/maven_dark.svg | 4 + .../idea/icons/expui/nodes/annotation.svg | 5 + .../icons/expui/nodes/annotation_dark.svg | 5 + .../idea/icons/expui/nodes/class.svg | 5 + .../idea/icons/expui/nodes/class_dark.svg | 5 + .../idea/icons/expui/nodes/enum.svg | 5 + .../idea/icons/expui/nodes/enum_dark.svg | 5 + .../idea/icons/expui/nodes/exception.svg | 5 + .../idea/icons/expui/nodes/exception_dark.svg | 5 + .../idea/icons/expui/nodes/interface.svg | 5 + .../idea/icons/expui/nodes/interface_dark.svg | 5 + .../idea/icons/expui/nodes/package.svg | 5 + .../idea/icons/expui/nodes/package_dark.svg | 5 + .../idea/icons/expui/nodes/record.svg | 5 + .../idea/icons/expui/nodes/record_dark.svg | 5 + .../idea/icons/expui/nodes/resourcesRoot.svg | 8 + .../icons/expui/nodes/resourcesRoot_dark.svg | 8 + .../idea/icons/expui/nodes/sourceRoot.svg | 4 + .../icons/expui/nodes/sourceRoot_dark.svg | 4 + .../icons/expui/nodes/testResourcesRoot.svg | 8 + .../expui/nodes/testResourcesRoot_dark.svg | 8 + .../idea/icons/expui/nodes/testRoot.svg | 4 + .../idea/icons/expui/nodes/testRoot_dark.svg | 4 + .../components/themed-file-icon.tsx | 8 +- .../icon-themes/file-icon-semantics.test.ts | 15 + .../icon-themes/file-icon-semantics.ts | 37 +++ .../hooks/use-java-file-icon-kind.test.ts | 21 ++ .../hooks/use-java-file-icon-kind.ts | 287 ++++++++++++++++++ .../icon-themes/java-file-kind.test.ts | 81 +++++ .../extensions/icon-themes/java-file-kind.ts | 185 +++++++++++ .../components/file-explorer-surface.test.ts | 46 +++ .../components/file-explorer-tree-item.tsx | 28 +- .../components/file-explorer-tree.tsx | 21 +- .../hooks/use-file-explorer-visible-rows.ts | 33 +- .../file-explorer/lib/file-tree-row.test.ts | 14 + .../file-explorer/lib/file-tree-row.ts | 14 +- .../lib/maven-file-tree-semantics.test.ts | 77 +++++ .../lib/maven-file-tree-semantics.ts | 192 ++++++++++++ .../lib/visible-file-tree-rows.test.ts | 115 +++++++ .../lib/visible-file-tree-rows.ts | 20 +- .../styles/file-explorer-tree-guides.test.ts | 16 + .../styles/file-explorer-tree.css | 88 +++++- .../tabs/components/tab-bar-item.test.ts | 11 + .../features/tabs/components/tab-bar-item.tsx | 8 + .../src/features/tabs/components/tab-bar.tsx | 2 + 51 files changed, 1680 insertions(+), 81 deletions(-) create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/maven.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/maven_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot_dark.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot.svg create mode 100644 windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot_dark.svg create mode 100644 windows/tauri/src/extensions/icon-themes/file-icon-semantics.test.ts create mode 100644 windows/tauri/src/extensions/icon-themes/file-icon-semantics.ts create mode 100644 windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.test.ts create mode 100644 windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.ts create mode 100644 windows/tauri/src/extensions/icon-themes/java-file-kind.test.ts create mode 100644 windows/tauri/src/extensions/icon-themes/java-file-kind.ts create mode 100644 windows/tauri/src/features/file-explorer/components/file-explorer-surface.test.ts create mode 100644 windows/tauri/src/features/file-explorer/lib/file-tree-row.test.ts create mode 100644 windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.test.ts create mode 100644 windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.ts create mode 100644 windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.test.ts create mode 100644 windows/tauri/src/features/file-explorer/styles/file-explorer-tree-guides.test.ts create mode 100644 windows/tauri/src/features/tabs/components/tab-bar-item.test.ts diff --git a/scripts/build-windows.ps1 b/scripts/build-windows.ps1 index b427cddd3..72ab82883 100644 --- a/scripts/build-windows.ps1 +++ b/scripts/build-windows.ps1 @@ -8,8 +8,17 @@ param( $ErrorActionPreference = "Stop" $root = Split-Path -Parent $PSScriptRoot $windowsApp = Join-Path $root "windows/tauri" +$bundledExtensionsSource = [System.IO.Path]::GetFullPath((Join-Path $windowsApp "src/extensions/bundled")) +$preparedJdtlsRoot = $null +if (-not (Test-Path -LiteralPath $bundledExtensionsSource -PathType Container)) { + throw "Bundled extensions source directory is missing: $bundledExtensionsSource" +} if ($Configuration -eq "Release") { - & (Join-Path $root "scripts/prepare-jdtls.ps1") | Out-Null + $prepareOutput = @(& (Join-Path $root "scripts/prepare-jdtls.ps1")) + if ($prepareOutput.Count -eq 0) { + throw "JDTLS preparation did not return an output directory." + } + $preparedJdtlsRoot = [System.IO.Path]::GetFullPath([string]$prepareOutput[-1]) } Set-Location $windowsApp @@ -40,4 +49,53 @@ if ($Configuration -eq "Debug") { & bunx @tauriArgs if ($LASTEXITCODE -ne 0) { throw "Windows Tauri build failed" } +$profileName = if ($Configuration -eq "Debug") { "debug" } else { "release" } +$cargoTargetRoot = [System.IO.Path]::GetFullPath((Join-Path $windowsApp "src-tauri/target")) +$profileRoot = [System.IO.Path]::GetFullPath( + (Join-Path (Join-Path $cargoTargetRoot $RustTarget) $profileName) +) +$trimCharacters = [char[]]@([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) +$targetPrefix = $cargoTargetRoot.TrimEnd($trimCharacters) + [System.IO.Path]::DirectorySeparatorChar +if (-not $profileRoot.StartsWith($targetPrefix, [System.StringComparison]::OrdinalIgnoreCase)) { + throw "Windows Cargo target profile must stay inside $cargoTargetRoot" +} +if (-not (Test-Path -LiteralPath (Join-Path $profileRoot "lithe-windows.exe") -PathType Leaf)) { + throw "Windows Tauri executable is missing from target profile: $profileRoot" +} + +function Copy-ResourceDirectory { + param([string]$Source, [string]$RelativeDestination) + + if (-not (Test-Path -LiteralPath $Source -PathType Container)) { + throw "Bundled resource source directory is missing: $Source" + } + $destination = [System.IO.Path]::GetFullPath((Join-Path $profileRoot $RelativeDestination)) + $profilePrefix = $profileRoot.TrimEnd($trimCharacters) + [System.IO.Path]::DirectorySeparatorChar + if (-not $destination.StartsWith($profilePrefix, [System.StringComparison]::OrdinalIgnoreCase)) { + throw "Bundled resource destination must stay inside target profile: $destination" + } + if (Test-Path -LiteralPath $destination) { + Remove-Item -Recurse -Force -LiteralPath $destination + } + New-Item -ItemType Directory -Force -Path (Split-Path -Parent $destination) | Out-Null + Copy-Item -Recurse -Force -LiteralPath $Source -Destination $destination + $destination +} + +$bundledExtensionsDestination = Copy-ResourceDirectory $bundledExtensionsSource "extensions/bundled" +foreach ($relativePath in @("icon-themes", "themes", "icon-themes/idea/extension.json")) { + if (-not (Test-Path -LiteralPath (Join-Path $bundledExtensionsDestination $relativePath))) { + throw "Bundled extensions staging is incomplete: $relativePath" + } +} + +if ($Configuration -eq "Release") { + $jdtlsDestination = Copy-ResourceDirectory $preparedJdtlsRoot "LanguageServers/jdtls" + foreach ($relativePath in @("bin/jdtls.bat", "config_win", "plugins")) { + if (-not (Test-Path -LiteralPath (Join-Path $jdtlsDestination $relativePath))) { + throw "Bundled JDTLS staging is incomplete: $relativePath" + } + } +} + Write-Output "Windows Tauri build completed." diff --git a/windows/tauri/scripts/generate-idea-file-icons.ts b/windows/tauri/scripts/generate-idea-file-icons.ts index a71c73c34..1789c83cd 100644 --- a/windows/tauri/scripts/generate-idea-file-icons.ts +++ b/windows/tauri/scripts/generate-idea-file-icons.ts @@ -15,12 +15,30 @@ import { createHash } from "node:crypto"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; +interface IconMappingSpec { + source: string; + asset: string; + definition?: string; + darkSource?: string; + darkAsset?: string; +} + +type IconMapping = string | IconMappingSpec; + interface FileThemeMapping { - fileExtensions: Record; - filenames: Record; - folders: Record; - defaultFile: string; - defaultFolder: string; + fileExtensions: Record; + filenames: Record; + folders: Record; + defaultFile: IconMapping; + defaultFolder: IconMapping; +} + +interface ResolvedIconMapping { + source: string; + asset: string; + definition: string; + darkSource: string; + darkAsset: string; } const REPO_ROOT = resolve(import.meta.dir, ".."); @@ -47,14 +65,32 @@ function sha(buffer: Buffer): string { return createHash("sha256").update(buffer).digest("hex"); } -function definitionName(source: string): string { - const file = source.split("/").pop() ?? source; +function definitionName(asset: string): string { + const file = asset.split("/").pop() ?? asset; return `idea-${file.replace(/\.svg$/, "")}`; } -function themeAssetPath(source: string, dark: boolean): string { - const rel = dark ? source.replace(/\.svg$/, "_dark.svg") : source; - return `./icons/${rel}`; +function resolveIconMapping(mapping: IconMapping): ResolvedIconMapping { + const spec = typeof mapping === "string" ? { source: mapping, asset: mapping } : mapping; + if (spec.asset.startsWith("/") || spec.asset.split("/").includes("..")) { + throw new Error(`Icon asset path must stay inside the bundled theme: ${spec.asset}`); + } + + return { + source: spec.source, + asset: spec.asset, + definition: spec.definition ?? definitionName(spec.asset), + darkSource: spec.darkSource ?? spec.source.replace(/\.svg$/, "_dark.svg"), + darkAsset: spec.darkAsset ?? spec.asset.replace(/\.svg$/, "_dark.svg"), + }; +} + +function sourcePath(source: string): string { + return resolve(sourceRoot!, source); +} + +function themeAssetPath(mapping: ResolvedIconMapping, dark: boolean): string { + return `./icons/${dark ? mapping.darkAsset : mapping.asset}`; } const { source: sourceRoot, check } = parseArgs(); @@ -65,15 +101,15 @@ if (!sourceRoot) { const mapping = JSON.parse(readFileSync(MAPPING_PATH, "utf8")) as FileThemeMapping; -const entries = new Map(); // definition name -> source svg +const entries = new Map(); // definition name -> source/asset pair const mapKeys = new Map(); // ".ts" / "Dockerfile" / "src" -> definition name -function registerEntries(record: Record): string[] { +function registerEntries(record: Record): string[] { const keys: string[] = []; - for (const [key, source] of Object.entries(record)) { - const name = definitionName(source); - entries.set(name, source); - mapKeys.set(key, name); + for (const [key, rawMapping] of Object.entries(record)) { + const resolvedMapping = resolveIconMapping(rawMapping); + entries.set(resolvedMapping.definition, resolvedMapping); + mapKeys.set(key, resolvedMapping.definition); keys.push(key); } return keys; @@ -82,17 +118,19 @@ function registerEntries(record: Record): string[] { const extensionKeys = registerEntries(mapping.fileExtensions); const filenameKeys = registerEntries(mapping.filenames); const folderKeys = registerEntries(mapping.folders); -entries.set(definitionName(mapping.defaultFile), mapping.defaultFile); -entries.set(definitionName(mapping.defaultFolder), mapping.defaultFolder); +const defaultFile = resolveIconMapping(mapping.defaultFile); +const defaultFolder = resolveIconMapping(mapping.defaultFolder); +entries.set(defaultFile.definition, defaultFile); +entries.set(defaultFolder.definition, defaultFolder); const missing: string[] = []; const darkVariants = new Map(); // definition name -> has dark pair -for (const [name, source] of entries) { - if (!existsSync(join(sourceRoot, source))) { - missing.push(source); +for (const [name, iconMapping] of entries) { + if (!existsSync(sourcePath(iconMapping.source))) { + missing.push(iconMapping.source); continue; } - const hasDark = existsSync(join(sourceRoot, source.replace(/\.svg$/, "_dark.svg"))); + const hasDark = existsSync(sourcePath(iconMapping.darkSource)); darkVariants.set(name, hasDark); } if (missing.length > 0) { @@ -107,10 +145,10 @@ const filenames: Record = {}; const folders: Record = {}; const expandedFolders: Record = {}; -for (const [name, source] of entries) { +for (const [name, iconMapping] of entries) { const hasDark = darkVariants.get(name) === true; - iconDefinitions[name] = themeAssetPath(source, hasDark); - lightIconDefinitions[name] = themeAssetPath(source, false); + iconDefinitions[name] = themeAssetPath(iconMapping, hasDark); + lightIconDefinitions[name] = themeAssetPath(iconMapping, false); } for (const key of extensionKeys) fileExtensions[key] = mapKeys.get(key)!; for (const key of filenameKeys) filenames[key] = mapKeys.get(key)!; @@ -135,9 +173,9 @@ const manifest = { name: "IDEA Icons", description: "File icons from the IntelliJ platform icon set (intellij-community, Apache-2.0).", - defaultFile: definitionName(mapping.defaultFile), - defaultFolder: definitionName(mapping.defaultFolder), - defaultFolderOpen: definitionName(mapping.defaultFolder), + defaultFile: defaultFile.definition, + defaultFolder: defaultFolder.definition, + defaultFolderOpen: defaultFolder.definition, iconDefinitions, lightIconDefinitions, fileExtensions, @@ -148,11 +186,11 @@ const manifest = { ], }; -const filesToCopy: Array<[string, boolean]> = []; -for (const [name, source] of entries) { - filesToCopy.push([source, false]); +const filesToCopy: Array<{ source: string; asset: string }> = []; +for (const [name, iconMapping] of entries) { + filesToCopy.push({ source: iconMapping.source, asset: iconMapping.asset }); if (darkVariants.get(name) === true) { - filesToCopy.push([source.replace(/\.svg$/, "_dark.svg"), true]); + filesToCopy.push({ source: iconMapping.darkSource, asset: iconMapping.darkAsset }); } } @@ -163,12 +201,12 @@ if (check) { if (current !== expected) { problems.push("extension.json is out of date; rerun the generator"); } - for (const [rel] of filesToCopy) { - const copied = join(THEME_DIR, "icons", rel); + for (const file of filesToCopy) { + const copied = join(THEME_DIR, "icons", file.asset); if (!existsSync(copied)) { - problems.push(`missing copied asset: idea/icons/${rel}`); - } else if (sha(readFileSync(copied)) !== sha(readFileSync(join(sourceRoot, rel)))) { - problems.push(`copied asset differs from source: idea/icons/${rel}`); + problems.push(`missing copied asset: idea/icons/${file.asset}`); + } else if (sha(readFileSync(copied)) !== sha(readFileSync(sourcePath(file.source)))) { + problems.push(`copied asset differs from source: idea/icons/${file.asset}`); } } if (problems.length > 0) { @@ -179,10 +217,10 @@ if (check) { process.exit(0); } -for (const [rel] of filesToCopy) { - const dest = join(THEME_DIR, "icons", rel); +for (const file of filesToCopy) { + const dest = join(THEME_DIR, "icons", file.asset); mkdirSync(dirname(dest), { recursive: true }); - writeFileSync(dest, readFileSync(join(sourceRoot, rel))); + writeFileSync(dest, readFileSync(sourcePath(file.source))); } writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + "\n"); console.log( diff --git a/windows/tauri/scripts/idea-file-icon-mappings.json b/windows/tauri/scripts/idea-file-icon-mappings.json index c4cd472b2..2bc50aed9 100644 --- a/windows/tauri/scripts/idea-file-icon-mappings.json +++ b/windows/tauri/scripts/idea-file-icon-mappings.json @@ -79,6 +79,19 @@ ".lock": "expui/fileTypes/text.svg" }, "filenames": { + "\u0000lithe:java.class": "expui/nodes/class.svg", + "\u0000lithe:java.interface": "expui/nodes/interface.svg", + "\u0000lithe:java.enum": "expui/nodes/enum.svg", + "\u0000lithe:java.annotation": "expui/nodes/annotation.svg", + "\u0000lithe:java.record": "expui/nodes/record.svg", + "\u0000lithe:java.exception": "expui/nodes/exception.svg", + "pom.xml": { + "source": "../../../plugins/maven/src/main/resources/images/expui/build/mavenProject.svg", + "darkSource": "../../../plugins/maven/src/main/resources/images/expui/build/mavenProject_dark.svg", + "asset": "expui/fileTypes/maven.svg", + "darkAsset": "expui/fileTypes/maven_dark.svg", + "definition": "idea-maven" + }, "dockerfile": "expui/fileTypes/docker.svg", ".gitignore": "expui/fileTypes/gitignore.svg", ".editorconfig": "expui/fileTypes/editorConfig.svg", @@ -86,7 +99,13 @@ "license": "expui/fileTypes/text.svg", "notice": "expui/fileTypes/text.svg" }, - "folders": {}, + "folders": { + "\u0000lithe:folder.source-root": "expui/nodes/sourceRoot.svg", + "\u0000lithe:folder.test-root": "expui/nodes/testRoot.svg", + "\u0000lithe:folder.resources-root": "expui/nodes/resourcesRoot.svg", + "\u0000lithe:folder.test-resources-root": "expui/nodes/testResourcesRoot.svg", + "\u0000lithe:folder.package": "expui/nodes/package.svg" + }, "defaultFile": "expui/fileTypes/text.svg", "defaultFolder": "expui/nodes/folder.svg" } diff --git a/windows/tauri/src/extensions/bundled-extension-manifests.test.ts b/windows/tauri/src/extensions/bundled-extension-manifests.test.ts index 97754510e..716df833a 100644 --- a/windows/tauri/src/extensions/bundled-extension-manifests.test.ts +++ b/windows/tauri/src/extensions/bundled-extension-manifests.test.ts @@ -1,6 +1,34 @@ import { describe, expect, test } from "bun:test"; import { bundledExtensionManifests } from "./bundled/bundled-extension-manifests"; +function getIdeaIconTheme() { + const manifest = bundledExtensionManifests.find( + ({ manifest }) => manifest.id === "lithe.icon-theme.idea-icons", + )?.manifest; + const iconTheme = manifest?.icons?.find(({ id }) => id === "idea-icons"); + + if (!iconTheme) { + throw new Error("Bundled IDEA icon theme is missing"); + } + + return iconTheme; +} + +const IDEA_TREE_ICON_IDS = [ + "idea-maven", + "idea-class", + "idea-interface", + "idea-enum", + "idea-annotation", + "idea-record", + "idea-exception", + "idea-sourceRoot", + "idea-testRoot", + "idea-resourcesRoot", + "idea-testResourcesRoot", + "idea-package", +]; + describe("bundled file icon themes", () => { test("ships IDEA Icons without the retired Lithe icon theme", () => { const extensionIds = bundledExtensionManifests.map(({ manifest }) => manifest.id); @@ -8,4 +36,46 @@ describe("bundled file icon themes", () => { expect(extensionIds).toContain("lithe.icon-theme.idea-icons"); expect(extensionIds).not.toContain("lithe.icon-theme.lithe-icons"); }); + + test("maps the common IDEA project tree entries to ExpUI icons", () => { + const iconTheme = getIdeaIconTheme(); + + expect(iconTheme.fileExtensions?.[".java"]).toBe("idea-java"); + expect(iconTheme.filenames?.["pom.xml"]).toBe("idea-maven"); + expect(iconTheme.filenames?.[".gitignore"]).toBe("idea-gitignore"); + expect(iconTheme.filenames?.["\0lithe:java.class"]).toBe("idea-class"); + expect(iconTheme.filenames?.["\0lithe:java.exception"]).toBe("idea-exception"); + expect(iconTheme.folders?.["\0lithe:folder.source-root"]).toBe("idea-sourceRoot"); + expect(iconTheme.folders?.["\0lithe:folder.package"]).toBe("idea-package"); + expect(iconTheme.expandedFolders).toEqual(iconTheme.folders); + }); + + test("declares dark and light assets for every added IDEA tree icon", () => { + const iconTheme = getIdeaIconTheme(); + + for (const iconId of IDEA_TREE_ICON_IDS) { + expect(iconTheme.iconDefinitions[iconId]).toMatch(/_dark\.svg$/); + expect(iconTheme.lightIconDefinitions?.[iconId]).toMatch(/(? { + const iconTheme = getIdeaIconTheme(); + + for (const iconId of IDEA_TREE_ICON_IDS) { + const assetPaths = [ + iconTheme.iconDefinitions[iconId], + iconTheme.lightIconDefinitions?.[iconId], + ]; + + for (const assetPath of assetPaths) { + expect(assetPath).toBeDefined(); + const contents = await Bun.file( + new URL(`./bundled/icon-themes/idea/${assetPath!.replace(/^\.\//, "")}`, import.meta.url), + ).text(); + expect(contents.startsWith(" + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/maven_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/maven_dark.svg new file mode 100644 index 000000000..8f8f35e5c --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/fileTypes/maven_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation.svg new file mode 100644 index 000000000..842956af7 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation_dark.svg new file mode 100644 index 000000000..66abc9160 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/annotation_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class.svg new file mode 100644 index 000000000..77996e71b --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class_dark.svg new file mode 100644 index 000000000..a8027940d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/class_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum.svg new file mode 100644 index 000000000..13deae631 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum_dark.svg new file mode 100644 index 000000000..44d6e5cf8 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/enum_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception.svg new file mode 100644 index 000000000..ab5bae754 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception_dark.svg new file mode 100644 index 000000000..710a292ec --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/exception_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface.svg new file mode 100644 index 000000000..b7436907d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface_dark.svg new file mode 100644 index 000000000..53905c525 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/interface_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package.svg new file mode 100644 index 000000000..4fd24f914 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package_dark.svg new file mode 100644 index 000000000..f86ed61ba --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/package_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record.svg new file mode 100644 index 000000000..bafa1940d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record_dark.svg new file mode 100644 index 000000000..c965cf713 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/record_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot.svg new file mode 100644 index 000000000..a58f3256d --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot_dark.svg new file mode 100644 index 000000000..0a042e94e --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/resourcesRoot_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot.svg new file mode 100644 index 000000000..4a4b44608 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot_dark.svg new file mode 100644 index 000000000..7d3159c25 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/sourceRoot_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot.svg new file mode 100644 index 000000000..1098ebb34 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot_dark.svg new file mode 100644 index 000000000..221b77061 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testResourcesRoot_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot.svg new file mode 100644 index 000000000..4bfdae1a5 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot_dark.svg b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot_dark.svg new file mode 100644 index 000000000..21261bb49 --- /dev/null +++ b/windows/tauri/src/extensions/bundled/icon-themes/idea/icons/expui/nodes/testRoot_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/windows/tauri/src/extensions/icon-themes/components/themed-file-icon.tsx b/windows/tauri/src/extensions/icon-themes/components/themed-file-icon.tsx index f5898e1f2..1a077d91b 100644 --- a/windows/tauri/src/extensions/icon-themes/components/themed-file-icon.tsx +++ b/windows/tauri/src/extensions/icon-themes/components/themed-file-icon.tsx @@ -5,6 +5,7 @@ import { getDefaultSetting, useSettingsStore } from "@/features/settings/stores/ import { useTranslation } from "@/i18n/locale-provider"; import { cn } from "@/utils/cn"; import { iconThemeRegistry } from "../icon-theme-registry"; +import { getSemanticFileIconLookupName, type FileIconSemanticKind } from "../file-icon-semantics"; const THEMED_FILE_ICON_CACHE_KEY = import.meta.env.DEV ? Date.now().toString(36) : ""; @@ -18,6 +19,7 @@ interface ThemedFileIconProps { isDir: boolean; isExpanded?: boolean; isSymlink?: boolean; + semanticKind?: FileIconSemanticKind | null; className?: string; } @@ -26,6 +28,7 @@ export function ThemedFileIcon({ isDir, isExpanded = false, isSymlink = false, + semanticKind, className = "text-subtle-foreground", }: ThemedFileIconProps) { const { t } = useTranslation(); @@ -43,10 +46,11 @@ export function ThemedFileIcon({ const iconTheme = iconThemeRegistry.getTheme(iconThemeId) ?? iconThemeRegistry.getTheme(getDefaultSetting("iconTheme")); + const lookupFileName = getSemanticFileIconLookupName(iconThemeId, fileName, semanticKind); const iconResult = useMemo( - () => iconTheme?.getFileIcon(fileName, isDir, isExpanded, isSymlink) ?? null, - [fileName, iconTheme, isDir, isExpanded, isSymlink, colorThemeId], + () => iconTheme?.getFileIcon(lookupFileName, isDir, isExpanded, isSymlink) ?? null, + [lookupFileName, iconTheme, isDir, isExpanded, isSymlink, colorThemeId], ); const sanitizedSvg = useMemo( () => diff --git a/windows/tauri/src/extensions/icon-themes/file-icon-semantics.test.ts b/windows/tauri/src/extensions/icon-themes/file-icon-semantics.test.ts new file mode 100644 index 000000000..4b2dd034f --- /dev/null +++ b/windows/tauri/src/extensions/icon-themes/file-icon-semantics.test.ts @@ -0,0 +1,15 @@ +import { expect, test } from "bun:test"; +import { getSemanticFileIconLookupName } from "./file-icon-semantics"; + +test("IDEA Icons use reserved semantic lookups without affecting other themes", () => { + expect(getSemanticFileIconLookupName("idea-icons", "Example.java", "java.class")).toBe( + "\0lithe:java.class", + ); + expect(getSemanticFileIconLookupName("idea-icons", "java", "folder.source-root")).toBe( + "\0lithe:folder.source-root", + ); + expect(getSemanticFileIconLookupName("material-icons", "Example.java", "java.class")).toBe( + "Example.java", + ); + expect(getSemanticFileIconLookupName("idea-icons", "Example.java", null)).toBe("Example.java"); +}); diff --git a/windows/tauri/src/extensions/icon-themes/file-icon-semantics.ts b/windows/tauri/src/extensions/icon-themes/file-icon-semantics.ts new file mode 100644 index 000000000..f9ff556a8 --- /dev/null +++ b/windows/tauri/src/extensions/icon-themes/file-icon-semantics.ts @@ -0,0 +1,37 @@ +export type FileIconSemanticKind = + | "java.class" + | "java.interface" + | "java.enum" + | "java.annotation" + | "java.record" + | "java.exception" + | "folder.source-root" + | "folder.test-root" + | "folder.resources-root" + | "folder.test-resources-root" + | "folder.package"; + +export const IDEA_ICON_THEME_ID = "idea-icons"; + +const IDEA_SEMANTIC_LOOKUP_NAMES: Record = { + "java.class": "\0lithe:java.class", + "java.interface": "\0lithe:java.interface", + "java.enum": "\0lithe:java.enum", + "java.annotation": "\0lithe:java.annotation", + "java.record": "\0lithe:java.record", + "java.exception": "\0lithe:java.exception", + "folder.source-root": "\0lithe:folder.source-root", + "folder.test-root": "\0lithe:folder.test-root", + "folder.resources-root": "\0lithe:folder.resources-root", + "folder.test-resources-root": "\0lithe:folder.test-resources-root", + "folder.package": "\0lithe:folder.package", +}; + +export function getSemanticFileIconLookupName( + iconThemeId: string, + fileName: string, + semanticKind?: FileIconSemanticKind | null, +): string { + if (iconThemeId !== IDEA_ICON_THEME_ID || !semanticKind) return fileName; + return IDEA_SEMANTIC_LOOKUP_NAMES[semanticKind]; +} diff --git a/windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.test.ts b/windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.test.ts new file mode 100644 index 000000000..b2d013b4c --- /dev/null +++ b/windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.test.ts @@ -0,0 +1,21 @@ +import { expect, test } from "bun:test"; + +test("Java icon cache keeps external-change invalidation for every icon surface", async () => { + const source = await Bun.file(new URL("./use-java-file-icon-kind.ts", import.meta.url)).text(); + const tabBarSource = await Bun.file( + new URL("../../../features/tabs/components/tab-bar.tsx", import.meta.url), + ).text(); + const rowSubscription = source.slice( + source.indexOf("function subscribeToPath"), + source.indexOf("export function useJavaFileIconCacheLifecycle"), + ); + const treeLifecycle = source.slice( + source.indexOf("export function useJavaFileIconCacheLifecycle"), + ); + + expect(rowSubscription).not.toContain('addEventListener("file-external-change"'); + expect(treeLifecycle).toContain('addEventListener("file-external-change"'); + expect(treeLifecycle).toContain('removeEventListener("file-external-change"'); + expect(treeLifecycle).toContain("workspaceRuntimeRegistry.subscribe(handleWorkspaceChange)"); + expect(tabBarSource).toContain("useJavaFileIconCacheLifecycle();"); +}); diff --git a/windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.ts b/windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.ts new file mode 100644 index 000000000..7c6bb98b3 --- /dev/null +++ b/windows/tauri/src/extensions/icon-themes/hooks/use-java-file-icon-kind.ts @@ -0,0 +1,287 @@ +import { useCallback, useEffect, useMemo, useSyncExternalStore } from "react"; +import { IDEA_ICON_THEME_ID } from "@/extensions/icon-themes/file-icon-semantics"; +import { + detectJavaFileIconSemanticKind, + type JavaFileIconSemanticKind, +} from "@/extensions/icon-themes/java-file-kind"; +import { useBufferStore } from "@/features/editor/stores/buffer.store"; +import { getSourceEditorBufferByPath } from "@/features/editor/utils/buffer-index"; +import { readFile } from "@/features/file-system/controllers/platform"; +import { useSettingsStore } from "@/features/settings/stores/settings.store"; +import { workspaceRuntimeRegistry } from "@/features/workspace/runtime/workspace-runtime-registry"; +import { frontendTrace } from "@/utils/frontend-trace"; + +interface FileExternalChangeDetail { + path?: string; +} + +interface PendingJavaFileRead { + fileName: string; + generation: number; + path: string; + taskKey: string; + epoch: number; +} + +const MAX_CONCURRENT_JAVA_ICON_READS = 4; +const MAX_JAVA_ICON_SOURCE_CHARS = 256 * 1024; +const MAX_JAVA_ICON_CACHE_ENTRIES = 512; +const JAVA_ICON_READ_TIMEOUT_MS = 5_000; +const JAVA_ICON_RETRY_DELAY_MS = 1_000; +const javaFileKindCache = new Map(); +const javaFileReadEpochs = new Map(); +const javaFileReadFailureCounts = new Map(); +const javaFileRetryAfter = new Map(); +const queuedJavaFileTasks = new Set(); +const pendingJavaFileReads: PendingJavaFileRead[] = []; +const pathSubscribers = new Map void>>(); +let activeJavaFileReads = 0; +let workspaceGeneration = 0; +let firstReadFailureLogged = false; +let cacheLifecycleRefCount = 0; +let lifecycleWorkspaceUnsubscribe: (() => void) | null = null; + +function notifyPath(path: string) { + for (const callback of pathSubscribers.get(path) ?? []) callback(); +} + +function notifyAllPaths() { + for (const path of pathSubscribers.keys()) notifyPath(path); +} + +function rememberJavaFileKind(path: string, kind: JavaFileIconSemanticKind | null) { + javaFileKindCache.delete(path); + javaFileKindCache.set(path, kind); + + while (javaFileKindCache.size > MAX_JAVA_ICON_CACHE_ENTRIES) { + const oldestPath = javaFileKindCache.keys().next().value; + if (typeof oldestPath !== "string") break; + javaFileKindCache.delete(oldestPath); + } +} + +function invalidateJavaFilePath(path: string) { + javaFileKindCache.delete(path); + javaFileReadFailureCounts.delete(path); + javaFileRetryAfter.delete(path); + javaFileReadEpochs.set(path, (javaFileReadEpochs.get(path) ?? 0) + 1); + notifyPath(path); +} + +function handleExternalFileChange(event: Event) { + const path = (event as CustomEvent).detail?.path; + if (!path || !path.toLowerCase().endsWith(".java")) return; + invalidateJavaFilePath(path); +} + +function handleWorkspaceChange() { + workspaceGeneration += 1; + javaFileKindCache.clear(); + javaFileReadEpochs.clear(); + javaFileReadFailureCounts.clear(); + javaFileRetryAfter.clear(); + pendingJavaFileReads.length = 0; + queuedJavaFileTasks.clear(); + notifyAllPaths(); +} + +function subscribeToPath(path: string, callback: () => void) { + const subscribers = pathSubscribers.get(path) ?? new Set<() => void>(); + subscribers.add(callback); + pathSubscribers.set(path, subscribers); + + return () => { + const currentSubscribers = pathSubscribers.get(path); + currentSubscribers?.delete(callback); + if (currentSubscribers?.size === 0) pathSubscribers.delete(path); + }; +} + +export function useJavaFileIconCacheLifecycle() { + useEffect(() => { + cacheLifecycleRefCount += 1; + if (cacheLifecycleRefCount === 1) { + window.addEventListener("file-external-change", handleExternalFileChange); + lifecycleWorkspaceUnsubscribe = workspaceRuntimeRegistry.subscribe(handleWorkspaceChange); + } + + return () => { + cacheLifecycleRefCount = Math.max(0, cacheLifecycleRefCount - 1); + if (cacheLifecycleRefCount === 0) { + window.removeEventListener("file-external-change", handleExternalFileChange); + lifecycleWorkspaceUnsubscribe?.(); + lifecycleWorkspaceUnsubscribe = null; + handleWorkspaceChange(); + } + }; + }, []); +} + +function isEligibleLocalJavaIconPath(path: string): boolean { + if (!/^[A-Za-z]:[\\/]/.test(path) || path.startsWith("\\\\")) return false; + const segments = path.replace(/\\/g, "/").toLowerCase().split("/"); + return !segments.some((segment) => + ["target", "build", "out", "generated", "generated-sources"].includes(segment), + ); +} + +async function readJavaSourceWithinLimit(path: string): Promise { + const source = await readFile(path); + return source.length > MAX_JAVA_ICON_SOURCE_CHARS ? null : source; +} + +function withTimeout(promise: Promise, timeoutMs: number): Promise { + return new Promise((resolve, reject) => { + const timeoutId = window.setTimeout( + () => reject(new Error("Java icon source read timed out")), + timeoutMs, + ); + promise.then( + (value) => { + window.clearTimeout(timeoutId); + resolve(value); + }, + (error) => { + window.clearTimeout(timeoutId); + reject(error); + }, + ); + }); +} + +function scheduleRetry(path: string, fileName: string, generation: number) { + const retryAt = Date.now() + JAVA_ICON_RETRY_DELAY_MS; + javaFileRetryAfter.set(path, retryAt); + window.setTimeout(() => { + if (generation !== workspaceGeneration || javaFileRetryAfter.get(path) !== retryAt) return; + javaFileRetryAfter.delete(path); + queueJavaFileRead(path, fileName); + }, JAVA_ICON_RETRY_DELAY_MS); +} + +function recordReadFailure(pendingRead: PendingJavaFileRead, error: unknown) { + if (pendingRead.generation !== workspaceGeneration) return; + + const failureCount = (javaFileReadFailureCounts.get(pendingRead.path) ?? 0) + 1; + javaFileReadFailureCounts.set(pendingRead.path, failureCount); + if (failureCount >= 2) { + rememberJavaFileKind(pendingRead.path, null); + } else { + scheduleRetry(pendingRead.path, pendingRead.fileName, pendingRead.generation); + } + + if (!firstReadFailureLogged) { + firstReadFailureLogged = true; + frontendTrace("warn", "file-icons", "javaIconSemanticRead:error", { + path: pendingRead.path, + error: error instanceof Error ? error.message : String(error), + }); + } +} + +function runPendingJavaFileReads() { + while (activeJavaFileReads < MAX_CONCURRENT_JAVA_ICON_READS && pendingJavaFileReads.length > 0) { + const pendingRead = pendingJavaFileReads.shift(); + if (!pendingRead) return; + + if (pendingRead.generation !== workspaceGeneration) { + queuedJavaFileTasks.delete(pendingRead.taskKey); + continue; + } + + activeJavaFileReads += 1; + void withTimeout(readJavaSourceWithinLimit(pendingRead.path), JAVA_ICON_READ_TIMEOUT_MS) + .then((source) => { + if (pendingRead.generation !== workspaceGeneration) return; + if ((javaFileReadEpochs.get(pendingRead.path) ?? 0) !== pendingRead.epoch) return; + const kind = + source === null ? null : detectJavaFileIconSemanticKind(pendingRead.fileName, source); + rememberJavaFileKind(pendingRead.path, kind); + javaFileReadFailureCounts.delete(pendingRead.path); + javaFileRetryAfter.delete(pendingRead.path); + }) + .catch((error) => recordReadFailure(pendingRead, error)) + .finally(() => { + activeJavaFileReads -= 1; + queuedJavaFileTasks.delete(pendingRead.taskKey); + notifyPath(pendingRead.path); + + const currentEpoch = javaFileReadEpochs.get(pendingRead.path) ?? 0; + if ( + pendingRead.generation === workspaceGeneration && + currentEpoch !== pendingRead.epoch && + !javaFileKindCache.has(pendingRead.path) + ) { + queueJavaFileRead(pendingRead.path, pendingRead.fileName); + } + runPendingJavaFileReads(); + }); + } +} + +function queueJavaFileRead(path: string, fileName: string) { + const epoch = javaFileReadEpochs.get(path) ?? 0; + const taskKey = `${workspaceGeneration}\0${path}`; + if ( + !isEligibleLocalJavaIconPath(path) || + javaFileKindCache.has(path) || + queuedJavaFileTasks.has(taskKey) || + (javaFileRetryAfter.get(path) ?? 0) > Date.now() + ) { + return; + } + + queuedJavaFileTasks.add(taskKey); + pendingJavaFileReads.push({ + path, + fileName, + epoch, + generation: workspaceGeneration, + taskKey, + }); + runPendingJavaFileReads(); +} + +export function useJavaFileIconKind( + path: string, + fileName: string, + isDirectory: boolean, + enabled: boolean, +): JavaFileIconSemanticKind | null { + const iconThemeId = useSettingsStore((state) => state.settings.iconTheme); + const isJavaFile = !isDirectory && fileName.toLowerCase().endsWith(".java"); + const semanticIconsEnabled = + enabled && + iconThemeId === IDEA_ICON_THEME_ID && + isJavaFile && + isEligibleLocalJavaIconPath(path); + const sourceBufferContent = useBufferStore((state) => { + if (!semanticIconsEnabled) return null; + return getSourceEditorBufferByPath(state.buffers, path)?.content ?? null; + }); + const subscribe = useCallback( + (callback: () => void) => + semanticIconsEnabled ? subscribeToPath(path, callback) : () => undefined, + [path, semanticIconsEnabled], + ); + const diskKind = useSyncExternalStore( + subscribe, + () => (semanticIconsEnabled ? javaFileKindCache.get(path) : undefined), + () => undefined, + ); + const bufferKind = useMemo( + () => + sourceBufferContent === null || sourceBufferContent.length > MAX_JAVA_ICON_SOURCE_CHARS + ? null + : detectJavaFileIconSemanticKind(fileName, sourceBufferContent), + [fileName, sourceBufferContent], + ); + + useEffect(() => { + if (!semanticIconsEnabled || sourceBufferContent !== null) return; + queueJavaFileRead(path, fileName); + }, [diskKind, fileName, path, semanticIconsEnabled, sourceBufferContent]); + + if (!semanticIconsEnabled) return null; + return sourceBufferContent === null ? (diskKind ?? null) : bufferKind; +} diff --git a/windows/tauri/src/extensions/icon-themes/java-file-kind.test.ts b/windows/tauri/src/extensions/icon-themes/java-file-kind.test.ts new file mode 100644 index 000000000..9ad04739d --- /dev/null +++ b/windows/tauri/src/extensions/icon-themes/java-file-kind.test.ts @@ -0,0 +1,81 @@ +import { describe, expect, test } from "bun:test"; +import { detectJavaFileIconSemanticKind, type JavaFileIconSemanticKind } from "./java-file-kind"; + +describe("Java file icon semantics", () => { + const cases: Array<{ + fileName: string; + source: string; + expected: JavaFileIconSemanticKind; + }> = [ + { fileName: "Example.java", source: "public class Example {}", expected: "java.class" }, + { + fileName: "Example.java", + source: "public interface Example {}", + expected: "java.interface", + }, + { + fileName: "Example.java", + source: "public enum Example { VALUE }", + expected: "java.enum", + }, + { + fileName: "Example.java", + source: "public @interface Example {}", + expected: "java.annotation", + }, + { + fileName: "Example.java", + source: "public record Example(String value) {}", + expected: "java.record", + }, + { + fileName: "Example.java", + source: "public class Example extends java.lang.RuntimeException {}", + expected: "java.exception", + }, + ]; + + test.each(cases)("detects $fileName as $expected", ({ fileName, source, expected }) => { + expect(detectJavaFileIconSemanticKind(fileName, source)).toBe(expected); + }); + + test("ignores declarations inside comments, strings, text blocks, and nested types", () => { + const source = ` + // class Example {} + class Container { + String text = "interface Example {}"; + String block = """enum Example { VALUE }"""; + class Example {} + } + `; + + expect(detectJavaFileIconSemanticKind("Example.java", source)).toBeNull(); + }); + + test("uses the matching top-level declaration instead of the first declaration", () => { + const source = "class Helper {}\npublic interface Example {}"; + expect(detectJavaFileIconSemanticKind("Example.java", source)).toBe("java.interface"); + }); + + test("does not infer exception semantics from a filename or custom base class", () => { + expect( + detectJavaFileIconSemanticKind( + "ExampleException.java", + "class ExampleException extends DomainFailure {}", + ), + ).toBe("java.class"); + expect(detectJavaFileIconSemanticKind("Other.java", "class Example {}")).toBeNull(); + }); + + test("does not confuse a generic bound with the direct superclass", () => { + expect( + detectJavaFileIconSemanticKind("Example.java", "class Example {}"), + ).toBe("java.class"); + expect( + detectJavaFileIconSemanticKind( + "Example.java", + "class Example> extends RuntimeException {}", + ), + ).toBe("java.exception"); + }); +}); diff --git a/windows/tauri/src/extensions/icon-themes/java-file-kind.ts b/windows/tauri/src/extensions/icon-themes/java-file-kind.ts new file mode 100644 index 000000000..010aa2540 --- /dev/null +++ b/windows/tauri/src/extensions/icon-themes/java-file-kind.ts @@ -0,0 +1,185 @@ +import type { FileIconSemanticKind } from "./file-icon-semantics"; + +export type JavaFileIconSemanticKind = Extract< + FileIconSemanticKind, + | "java.class" + | "java.interface" + | "java.enum" + | "java.annotation" + | "java.record" + | "java.exception" +>; + +function maskJavaCommentsAndLiterals(source: string): string { + let output = ""; + let index = 0; + let state: "code" | "line-comment" | "block-comment" | "string" | "char" | "text-block" = "code"; + + const appendMasked = (value: string) => { + output += value.replace(/[^\r\n]/g, " "); + }; + + while (index < source.length) { + const nextTwo = source.slice(index, index + 2); + const nextThree = source.slice(index, index + 3); + const character = source[index] ?? ""; + + if (state === "code") { + if (nextTwo === "//") { + appendMasked(nextTwo); + index += 2; + state = "line-comment"; + continue; + } + if (nextTwo === "/*") { + appendMasked(nextTwo); + index += 2; + state = "block-comment"; + continue; + } + if (nextThree === '"""') { + appendMasked(nextThree); + index += 3; + state = "text-block"; + continue; + } + if (character === '"') { + appendMasked(character); + index += 1; + state = "string"; + continue; + } + if (character === "'") { + appendMasked(character); + index += 1; + state = "char"; + continue; + } + + output += character; + index += 1; + continue; + } + + if (state === "line-comment") { + appendMasked(character); + index += 1; + if (character === "\n") state = "code"; + continue; + } + + if (state === "block-comment") { + if (nextTwo === "*/") { + appendMasked(nextTwo); + index += 2; + state = "code"; + } else { + appendMasked(character); + index += 1; + } + continue; + } + + if (state === "text-block") { + if (nextThree === '"""') { + appendMasked(nextThree); + index += 3; + state = "code"; + } else { + appendMasked(character); + index += 1; + } + continue; + } + + if (character === "\\") { + appendMasked(source.slice(index, index + 2)); + index += Math.min(2, source.length - index); + continue; + } + + appendMasked(character); + index += 1; + if ((state === "string" && character === '"') || (state === "char" && character === "'")) { + state = "code"; + } + } + + return output; +} + +function getJavaBaseName(fileName: string): string | null { + const leafName = fileName.split(/[\\/]/).pop() ?? fileName; + if (!leafName.toLowerCase().endsWith(".java")) return null; + return leafName.slice(0, -".java".length); +} + +function stripLeadingTypeParameters(declarationTail: string): string { + let index = 0; + while (/\s/.test(declarationTail[index] ?? "")) index += 1; + if (declarationTail[index] !== "<") return declarationTail.slice(index); + + let depth = 0; + for (; index < declarationTail.length; index += 1) { + const character = declarationTail[index]; + if (character === "<") depth += 1; + if (character === ">") { + depth -= 1; + if (depth === 0) return declarationTail.slice(index + 1); + } + } + return ""; +} + +export function detectJavaFileIconSemanticKind( + fileName: string, + source: string, +): JavaFileIconSemanticKind | null { + const baseName = getJavaBaseName(fileName); + if (!baseName) return null; + + const maskedSource = maskJavaCommentsAndLiterals(source); + const declarationPattern = + /@interface\s+([A-Za-z_$][\w$]*)|\b(class|interface|enum|record)\s+([A-Za-z_$][\w$]*)/g; + let braceDepth = 0; + let scanIndex = 0; + + for (const match of maskedSource.matchAll(declarationPattern)) { + const matchIndex = match.index ?? 0; + while (scanIndex < matchIndex) { + const character = maskedSource[scanIndex]; + if (character === "{") braceDepth += 1; + if (character === "}") braceDepth = Math.max(0, braceDepth - 1); + scanIndex += 1; + } + + if (braceDepth !== 0) continue; + + const annotationName = match[1]; + const declarationKind = match[2]; + const declarationName = annotationName ?? match[3]; + if (declarationName !== baseName) continue; + + if (annotationName) return "java.annotation"; + if (declarationKind === "interface") return "java.interface"; + if (declarationKind === "enum") return "java.enum"; + if (declarationKind === "record") return "java.record"; + + const declarationEnd = maskedSource.indexOf("{", matchIndex); + const declarationTail = maskedSource.slice( + matchIndex + match[0].length, + declarationEnd === -1 ? maskedSource.length : declarationEnd, + ); + if ( + /\bextends\s+(?:java\.lang\.)?(?:RuntimeException|Exception|Throwable|Error)\b/.test( + stripLeadingTypeParameters(declarationTail), + ) + ) { + return "java.exception"; + } + + return "java.class"; + } + + return null; +} diff --git a/windows/tauri/src/features/file-explorer/components/file-explorer-surface.test.ts b/windows/tauri/src/features/file-explorer/components/file-explorer-surface.test.ts new file mode 100644 index 000000000..26c4ff795 --- /dev/null +++ b/windows/tauri/src/features/file-explorer/components/file-explorer-surface.test.ts @@ -0,0 +1,46 @@ +import { expect, test } from "bun:test"; + +function sourceSection(source: string, start: string, end: string) { + return source.slice(source.indexOf(start), source.indexOf(end)); +} + +test("file explorer chrome uses the editor background token", async () => { + const sidebarSource = await Bun.file( + new URL("../../../ui/sidebar.tsx", import.meta.url), + ).text(); + const fileExplorerSource = await Bun.file( + new URL("./file-explorer-pane.tsx", import.meta.url), + ).text(); + const fileExplorerStyles = await Bun.file( + new URL("../styles/file-explorer-tree.css", import.meta.url), + ).text(); + + const panel = sourceSection( + sidebarSource, + "export function SidebarPanel", + "export function SidebarTitleBar", + ); + const toolbar = sourceSection( + sidebarSource, + "export function SidebarToolbar", + "export const SidebarFooter", + ); + const header = sourceSection( + sidebarSource, + "export function SidebarHeader", + "export function SidebarComposerBody", + ); + + for (const chrome of [panel, toolbar, header]) { + expect(chrome).toContain("bg-background"); + expect(chrome).not.toContain("bg-surface"); + } + const fileExplorerHeaderStyles = sourceSection( + fileExplorerStyles, + ".file-explorer-header {", + ".file-explorer-header-title", + ); + expect(fileExplorerHeaderStyles).toContain("background-color: var(--background)"); + expect(fileExplorerHeaderStyles).not.toContain("background-color: var(--surface)"); + expect(fileExplorerSource).toContain(''); +}); diff --git a/windows/tauri/src/features/file-explorer/components/file-explorer-tree-item.tsx b/windows/tauri/src/features/file-explorer/components/file-explorer-tree-item.tsx index 1405b0ba5..3ca81415f 100644 --- a/windows/tauri/src/features/file-explorer/components/file-explorer-tree-item.tsx +++ b/windows/tauri/src/features/file-explorer/components/file-explorer-tree-item.tsx @@ -1,6 +1,9 @@ import type React from "react"; import { memo } from "react"; +import type { FileIconSemanticKind } from "@/extensions/icon-themes/file-icon-semantics"; import type { FileTreeGitStatusDecoration } from "@/features/file-explorer/lib/file-tree-git-status"; +import { FILE_TREE_BASE_INDENT } from "@/features/file-explorer/lib/file-tree-row"; +import { useJavaFileIconKind } from "@/extensions/icon-themes/hooks/use-java-file-icon-kind"; import type { FileEntry } from "@/features/file-system/types/app.types"; import { InlineRenameInput } from "@/ui/input"; import { SidebarTreeDisclosure, SidebarTreeRow } from "@/features/sidebar/components/sidebar-tree"; @@ -8,8 +11,6 @@ import { cn } from "@/utils/cn"; import { ThemedFileIcon } from "@/extensions/icon-themes/components/themed-file-icon"; import { useTranslation } from "@/i18n/locale-provider"; -const FILE_TREE_BASE_INDENT = 10; - export interface FileTreeGuideTarget { path: string; name: string; @@ -49,6 +50,8 @@ interface FileExplorerTreeItemProps { showIndentGuides: boolean; isExpanded: boolean; isActive: boolean; + isRoot: boolean; + semanticKind?: FileIconSemanticKind; isCut: boolean; isDragOver: boolean; isDragging: boolean; @@ -94,6 +97,8 @@ function FileExplorerTreeItemComponent({ showIndentGuides, isExpanded, isActive, + isRoot, + semanticKind, isCut, isDragOver, isDragging, @@ -106,6 +111,8 @@ function FileExplorerTreeItemComponent({ rowId, }: FileExplorerTreeItemProps) { const { t } = useTranslation(); + const javaSemanticKind = useJavaFileIconKind(file.path, file.name, file.isDir, showIcon); + const resolvedSemanticKind = semanticKind ?? javaSemanticKind; const paddingLeft = FILE_TREE_BASE_INDENT + depth * indentSize; const gitStatusDecoration = getGitStatusDecoration(file); const guideLevels = Array.from({ length: depth }, (_, level) => level); @@ -143,7 +150,7 @@ function FileExplorerTreeItemComponent({
{renderTreeGuides()}
) : null} ) : null } label={ - + {renderHighlightedLabel(displayName ?? file.name, searchQuery)} } @@ -254,6 +268,8 @@ export const FileExplorerTreeItem = memo( prev.showIndentGuides === next.showIndentGuides && prev.isExpanded === next.isExpanded && prev.isActive === next.isActive && + prev.isRoot === next.isRoot && + prev.semanticKind === next.semanticKind && prev.isCut === next.isCut && prev.isDragOver === next.isDragOver && prev.isDragging === next.isDragging && diff --git a/windows/tauri/src/features/file-explorer/components/file-explorer-tree.tsx b/windows/tauri/src/features/file-explorer/components/file-explorer-tree.tsx index b622aae36..4a5c61ddc 100644 --- a/windows/tauri/src/features/file-explorer/components/file-explorer-tree.tsx +++ b/windows/tauri/src/features/file-explorer/components/file-explorer-tree.tsx @@ -79,6 +79,7 @@ import { getVisibleFileTreeRowKey, useFileExplorerVisibleRows, } from "../hooks/use-file-explorer-visible-rows"; +import { useJavaFileIconCacheLifecycle } from "@/extensions/icon-themes/hooks/use-java-file-icon-kind"; import { FileExplorerViewport, type FileExplorerViewportHandle } from "./file-explorer-viewport"; import { FileExplorerTreeItem } from "./file-explorer-tree-item"; import type { FileTreeGuideTarget } from "./file-explorer-tree-item"; @@ -164,6 +165,7 @@ function FileExplorerTreeComponent({ onUploadFile, onFileMove, }: FileExplorerTreeProps) { + useJavaFileIconCacheLifecycle(); const [deleteCandidate, setDeleteCandidate] = useState<{ path: string; isDir: boolean; @@ -483,6 +485,7 @@ function FileExplorerTreeComponent({ }, [currentResolvedTreeSearch, isTreeSearchActive]); const { rowHeight, visibleRows, visibleRowIndexByPath } = useFileExplorerVisibleRows({ files: displayedFiles, + semanticFiles: files, expandedPathsOverride: displayedExpandedPaths, rootFolderPath, }); @@ -1101,10 +1104,11 @@ function FileExplorerTreeComponent({ return (
{ setHasTreeFocus(true); setFocusedPath((current) => current || activePath || visibleRows[0]?.file.path); @@ -1275,10 +1279,13 @@ function FileExplorerTreeComponent({ onMouseLeave={handleContainerMouseLeave} > event.stopPropagation()} onMouseDown={(event) => event.stopPropagation()} > +

+ {t("workbench.project")} +

{ diff --git a/windows/tauri/src/features/file-explorer/hooks/use-file-explorer-visible-rows.ts b/windows/tauri/src/features/file-explorer/hooks/use-file-explorer-visible-rows.ts index 93b4ff33f..9cf13b3e4 100644 --- a/windows/tauri/src/features/file-explorer/hooks/use-file-explorer-visible-rows.ts +++ b/windows/tauri/src/features/file-explorer/hooks/use-file-explorer-visible-rows.ts @@ -1,6 +1,8 @@ import { useMemo } from "react"; import { useShallow } from "zustand/react/shallow"; +import { IDEA_ICON_THEME_ID } from "@/extensions/icon-themes/file-icon-semantics"; import { getFileTreeRowHeight } from "@/features/file-explorer/lib/file-tree-row"; +import { buildMavenDirectorySemantics } from "@/features/file-explorer/lib/maven-file-tree-semantics"; import { buildVisibleFileTreeRows, type VisibleFileTreeRow, @@ -11,6 +13,7 @@ import { useSettingsStore } from "@/features/settings/stores/settings.store"; interface UseFileExplorerVisibleRowsOptions { files: FileEntry[]; + semanticFiles?: FileEntry[]; expandedPathsOverride?: ReadonlySet; rootFolderPath?: string; } @@ -21,28 +24,42 @@ export function getVisibleFileTreeRowKey(rows: readonly VisibleFileTreeRow[], in export function useFileExplorerVisibleRows({ files, + semanticFiles, expandedPathsOverride, rootFolderPath, }: UseFileExplorerVisibleRowsOptions) { const expandedPaths = useFileTreeStore((state) => state.expandedPaths); - const { compactFolders, hideRootFolder, sortOrder, uiFontSize } = useSettingsStore( - useShallow((state) => ({ - compactFolders: state.settings.compactFoldersInFileTree, - hideRootFolder: state.settings.hideRootFolderInFileTree, - sortOrder: state.settings.fileTreeSortOrder, - uiFontSize: state.settings.uiFontSize, - })), - ); + const { compactFolders, hideRootFolder, iconTheme, showFileIcons, sortOrder, uiFontSize } = + useSettingsStore( + useShallow((state) => ({ + compactFolders: state.settings.compactFoldersInFileTree, + hideRootFolder: state.settings.hideRootFolderInFileTree, + iconTheme: state.settings.iconTheme, + showFileIcons: state.settings.showFileIconsInFileTree, + sortOrder: state.settings.fileTreeSortOrder, + uiFontSize: state.settings.uiFontSize, + })), + ); const rowHeight = getFileTreeRowHeight(uiFontSize); + const semanticPresentationEnabled = showFileIcons && iconTheme === IDEA_ICON_THEME_ID; + const directorySemantics = useMemo( + () => + semanticPresentationEnabled + ? buildMavenDirectorySemantics(semanticFiles ?? files) + : new Map(), + [files, semanticFiles, semanticPresentationEnabled], + ); const visibleRows = useMemo(() => { return buildVisibleFileTreeRows(files, expandedPathsOverride ?? expandedPaths, { compactFolders, + directorySemantics, hiddenRootPath: hideRootFolder ? rootFolderPath : undefined, sortOrder, }); }, [ compactFolders, + directorySemantics, expandedPaths, expandedPathsOverride, files, diff --git a/windows/tauri/src/features/file-explorer/lib/file-tree-row.test.ts b/windows/tauri/src/features/file-explorer/lib/file-tree-row.test.ts new file mode 100644 index 000000000..4109e92ba --- /dev/null +++ b/windows/tauri/src/features/file-explorer/lib/file-tree-row.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, test } from "bun:test"; +import { FILE_TREE_MIN_ROW_HEIGHT, getFileTreeRowHeight } from "./file-tree-row"; + +describe("file tree row geometry", () => { + test("keeps the default UI font on the compact IDEA-style baseline", () => { + expect(getFileTreeRowHeight(13)).toBe(FILE_TREE_MIN_ROW_HEIGHT); + }); + + test("allows larger accessibility font settings to grow the row", () => { + expect(getFileTreeRowHeight(15)).toBe(26.25); + expect(getFileTreeRowHeight(18)).toBe(30.3); + expect(getFileTreeRowHeight(18.5)).toBe(30.98); + }); +}); diff --git a/windows/tauri/src/features/file-explorer/lib/file-tree-row.ts b/windows/tauri/src/features/file-explorer/lib/file-tree-row.ts index eb658fff1..a21243d3b 100644 --- a/windows/tauri/src/features/file-explorer/lib/file-tree-row.ts +++ b/windows/tauri/src/features/file-explorer/lib/file-tree-row.ts @@ -1,12 +1,14 @@ +export const FILE_TREE_BASE_INDENT = 10; +export const FILE_TREE_MIN_ROW_HEIGHT = 24; + const FILE_TREE_ROW_LINE_HEIGHT = 1.35; -const FILE_TREE_ROW_VERTICAL_PADDING = 8; -const FILE_TREE_ROW_BORDER_WIDTH = 2; +const FILE_TREE_ROW_VERTICAL_CHROME = 6; export function getFileTreeRowHeight(uiFontSize: number): number { - const height = - uiFontSize * FILE_TREE_ROW_LINE_HEIGHT + - FILE_TREE_ROW_VERTICAL_PADDING + - FILE_TREE_ROW_BORDER_WIDTH; + const height = Math.max( + FILE_TREE_MIN_ROW_HEIGHT, + uiFontSize * FILE_TREE_ROW_LINE_HEIGHT + FILE_TREE_ROW_VERTICAL_CHROME, + ); return Number(height.toFixed(2)); } diff --git a/windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.test.ts b/windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.test.ts new file mode 100644 index 000000000..4ec1fecdf --- /dev/null +++ b/windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.test.ts @@ -0,0 +1,77 @@ +import { describe, expect, test } from "bun:test"; +import type { FileEntry } from "@/features/file-system/types/app.types"; +import { buildMavenDirectorySemantics } from "./maven-file-tree-semantics"; + +function directory(name: string, path: string, children: FileEntry[] = []): FileEntry { + return { name, path, isDir: true, children }; +} + +function file(name: string, path: string): FileEntry { + return { name, path, isDir: false }; +} + +function createMavenTree(root = "D:\\project"): FileEntry[] { + return [ + directory("project", root, [ + directory("src", `${root}\\src`, [ + directory("main", `${root}\\src\\main`, [ + directory("java", `${root}\\src\\main\\java`, [ + directory("com", `${root}\\src\\main\\java\\com`, [ + directory("example", `${root}\\src\\main\\java\\com\\example`), + ]), + ]), + directory("resources", `${root}\\src\\main\\resources`), + ]), + directory("test", `${root}\\src\\test`, [ + directory("java", `${root}\\src\\test\\java`), + directory("resources", `${root}\\src\\test\\resources`), + ]), + ]), + file("pom.xml", `${root}\\pom.xml`), + ]), + ]; +} + +describe("Maven directory icon semantics", () => { + test("recognizes standard roots and Java packages in a loaded Maven module", () => { + const semantics = buildMavenDirectorySemantics(createMavenTree()); + + expect(semantics.get("D:\\project\\src\\main\\java")).toBe("folder.source-root"); + expect(semantics.get("D:\\project\\src\\main\\java\\com\\example")).toBe("folder.package"); + expect(semantics.get("D:\\project\\src\\test\\java")).toBe("folder.test-root"); + expect(semantics.get("D:\\project\\src\\main\\resources")).toBe("folder.resources-root"); + expect(semantics.get("D:\\project\\src\\test\\resources")).toBe("folder.test-resources-root"); + }); + + test("does not label standard-looking paths without a loaded pom.xml", () => { + const [root] = createMavenTree(); + root!.children = root!.children?.filter((entry) => entry.name !== "pom.xml"); + + expect(buildMavenDirectorySemantics([root!]).size).toBe(0); + }); + + test("does not label invalid Java package directory names", () => { + const tree = createMavenTree(); + const javaRoot = tree[0]?.children?.[0]?.children?.[0]?.children?.[0]; + javaRoot?.children?.push( + directory("not-a-package", "D:\\project\\src\\main\\java\\not-a-package"), + ); + + expect( + buildMavenDirectorySemantics(tree).get("D:\\project\\src\\main\\java\\not-a-package"), + ).toBeUndefined(); + }); + + test("rejects Java keywords while allowing Unicode identifiers", () => { + const tree = createMavenTree(); + const javaRoot = tree[0]?.children?.[0]?.children?.[0]?.children?.[0]; + javaRoot?.children?.push( + directory("class", "D:\\project\\src\\main\\java\\class"), + directory("示例", "D:\\project\\src\\main\\java\\示例"), + ); + const semantics = buildMavenDirectorySemantics(tree); + + expect(semantics.get("D:\\project\\src\\main\\java\\class")).toBeUndefined(); + expect(semantics.get("D:\\project\\src\\main\\java\\示例")).toBe("folder.package"); + }); +}); diff --git a/windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.ts b/windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.ts new file mode 100644 index 000000000..af8deddc2 --- /dev/null +++ b/windows/tauri/src/features/file-explorer/lib/maven-file-tree-semantics.ts @@ -0,0 +1,192 @@ +import type { FileIconSemanticKind } from "@/extensions/icon-themes/file-icon-semantics"; +import type { FileEntry } from "@/features/file-system/types/app.types"; +import { + getDirName, + getRelativePath, + joinPath, + normalizePath, + pathStartsWithRoot, + stripTrailingPathSeparators, +} from "@/utils/path-helpers"; + +type DirectorySemanticKind = Extract< + FileIconSemanticKind, + | "folder.source-root" + | "folder.test-root" + | "folder.resources-root" + | "folder.test-resources-root" + | "folder.package" +>; + +interface StandardMavenRoot { + path: string; + kind: Exclude; + containsPackages: boolean; +} + +const JAVA_RESERVED_PACKAGE_SEGMENTS = new Set([ + "abstract", + "assert", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "exports", + "extends", + "false", + "final", + "finally", + "float", + "for", + "goto", + "if", + "implements", + "import", + "instanceof", + "int", + "interface", + "long", + "module", + "native", + "new", + "null", + "open", + "opens", + "package", + "permits", + "private", + "protected", + "provides", + "public", + "record", + "requires", + "return", + "sealed", + "short", + "static", + "strictfp", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "to", + "transient", + "transitive", + "true", + "try", + "uses", + "var", + "void", + "volatile", + "while", + "with", + "yield", + "_", +]); + +function comparablePath(path: string): string { + const normalized = normalizePath(stripTrailingPathSeparators(path)); + return /^[A-Za-z]:\//.test(normalized) ? normalized.toLowerCase() : normalized; +} + +function pathsEqual(left: string, right: string): boolean { + return comparablePath(left) === comparablePath(right); +} + +function isJavaPackagePath(relativePath: string): boolean { + const segments = normalizePath(relativePath).split("/").filter(Boolean); + return ( + segments.length > 0 && + segments.every( + (segment) => + !JAVA_RESERVED_PACKAGE_SEGMENTS.has(segment) && + /^[\p{ID_Start}_$][\p{ID_Continue}$\u200C\u200D]*$/u.test(segment), + ) + ); +} + +function collectEntries(entries: readonly FileEntry[], output: FileEntry[]) { + for (const entry of entries) { + output.push(entry); + if (entry.children) collectEntries(entry.children, output); + } +} + +export function buildMavenDirectorySemantics( + files: readonly FileEntry[], +): ReadonlyMap { + const entries: FileEntry[] = []; + collectEntries(files, entries); + + const moduleRoots = Array.from( + new Set( + entries + .filter( + (entry) => + !entry.isDir && + entry.name.toLowerCase() === "pom.xml" && + !entry.path.startsWith("remote://"), + ) + .map((entry) => getDirName(entry.path)), + ), + ).sort((left, right) => comparablePath(right).length - comparablePath(left).length); + + const standardRoots: StandardMavenRoot[] = moduleRoots.flatMap((moduleRoot) => [ + { + path: joinPath(moduleRoot, "src", "main", "java"), + kind: "folder.source-root", + containsPackages: true, + }, + { + path: joinPath(moduleRoot, "src", "test", "java"), + kind: "folder.test-root", + containsPackages: true, + }, + { + path: joinPath(moduleRoot, "src", "main", "resources"), + kind: "folder.resources-root", + containsPackages: false, + }, + { + path: joinPath(moduleRoot, "src", "test", "resources"), + kind: "folder.test-resources-root", + containsPackages: false, + }, + ]); + + const semantics = new Map(); + for (const entry of entries) { + if (!entry.isDir) continue; + + for (const standardRoot of standardRoots) { + if (pathsEqual(entry.path, standardRoot.path)) { + semantics.set(entry.path, standardRoot.kind); + break; + } + + if (!standardRoot.containsPackages || !pathStartsWithRoot(entry.path, standardRoot.path)) { + continue; + } + + const relativePath = getRelativePath(entry.path, standardRoot.path); + if (isJavaPackagePath(relativePath)) { + semantics.set(entry.path, "folder.package"); + break; + } + } + } + + return semantics; +} diff --git a/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.test.ts b/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.test.ts new file mode 100644 index 000000000..da48023ca --- /dev/null +++ b/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.test.ts @@ -0,0 +1,115 @@ +import { expect, test } from "bun:test"; +import type { FileEntry } from "@/features/file-system/types/app.types"; +import { buildVisibleFileTreeRows } from "./visible-file-tree-rows"; + +function directory(name: string, path: string, children: FileEntry[] = []): FileEntry { + return { name, path, isDir: true, children }; +} + +test("compact folders preserve Maven source roots and compact packages with dots", () => { + const root = "D:\\project"; + const javaRoot = `${root}\\src\\main\\java`; + const packageRoot = `${javaRoot}\\com`; + const packageLeaf = `${packageRoot}\\example`; + const files = [ + directory("project", root, [ + directory("src", `${root}\\src`, [ + directory("main", `${root}\\src\\main`, [ + directory("java", javaRoot, [ + directory("com", packageRoot, [directory("example", packageLeaf)]), + ]), + directory("resources", `${root}\\src\\main\\resources`), + ]), + directory("test", `${root}\\src\\test`), + ]), + { name: "pom.xml", path: `${root}\\pom.xml`, isDir: false }, + ]), + ]; + const expandedPaths = new Set([ + root, + `${root}\\src`, + `${root}\\src\\main`, + javaRoot, + packageRoot, + packageLeaf, + ]); + + const rows = buildVisibleFileTreeRows(files, expandedPaths, { compactFolders: true }); + const sourceRootRow = rows.find((row) => row.file.path === javaRoot); + const packageRow = rows.find((row) => row.file.path === packageLeaf); + + expect(sourceRootRow?.displayName).toBeUndefined(); + expect(sourceRootRow?.semanticKind).toBe("folder.source-root"); + expect(packageRow?.displayName).toBe("com.example"); + expect(packageRow?.semanticKind).toBe("folder.package"); +}); + +test("compact package rows stop before an invalid package directory", () => { + const root = "D:\\project"; + const javaRoot = `${root}\\src\\main\\java`; + const packageRoot = `${javaRoot}\\com`; + const invalidChild = `${packageRoot}\\not-a-package`; + const files = [ + directory("project", root, [ + directory("src", `${root}\\src`, [ + directory("main", `${root}\\src\\main`, [ + directory("java", javaRoot, [ + directory("com", packageRoot, [directory("not-a-package", invalidChild)]), + ]), + ]), + ]), + { name: "pom.xml", path: `${root}\\pom.xml`, isDir: false }, + ]), + ]; + const expandedPaths = new Set([ + root, + `${root}\\src`, + `${root}\\src\\main`, + javaRoot, + packageRoot, + ]); + + const rows = buildVisibleFileTreeRows(files, expandedPaths, { compactFolders: true }); + + expect(rows.find((row) => row.file.path === packageRoot)?.semanticKind).toBe("folder.package"); + expect(rows.find((row) => row.file.path === packageRoot)?.displayName).toBeUndefined(); + expect(rows.find((row) => row.file.path === invalidChild)?.depth).toBeGreaterThan( + rows.find((row) => row.file.path === packageRoot)?.depth ?? -1, + ); +}); + +test("empty directory semantics preserve the original compact-folder projection", () => { + const root = "D:\\project"; + const javaRoot = `${root}\\src\\main\\java`; + const packageLeaf = `${javaRoot}\\com\\example`; + const files = [ + directory("project", root, [ + directory("src", `${root}\\src`, [ + directory("main", `${root}\\src\\main`, [ + directory("java", javaRoot, [ + directory("com", `${javaRoot}\\com`, [directory("example", packageLeaf)]), + ]), + ]), + ]), + { name: "pom.xml", path: `${root}\\pom.xml`, isDir: false }, + ]), + ]; + const expandedPaths = new Set([ + root, + `${root}\\src`, + `${root}\\src\\main`, + javaRoot, + `${javaRoot}\\com`, + packageLeaf, + ]); + + const rows = buildVisibleFileTreeRows(files, expandedPaths, { + compactFolders: true, + directorySemantics: new Map(), + }); + + expect(rows.find((row) => row.file.path === packageLeaf)?.displayName).toBe( + "src/main/java/com/example", + ); + expect(rows.find((row) => row.file.path === packageLeaf)?.semanticKind).toBeUndefined(); +}); diff --git a/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.ts b/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.ts index 18ec60148..11c697741 100644 --- a/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.ts +++ b/windows/tauri/src/features/file-explorer/lib/visible-file-tree-rows.ts @@ -1,5 +1,7 @@ import type { FileEntry } from "@/features/file-system/types/app.types"; +import type { FileIconSemanticKind } from "@/extensions/icon-themes/file-icon-semantics"; import { getCompactFolderChild } from "@/features/file-system/controllers/file-tree-utils"; +import { buildMavenDirectorySemantics } from "@/features/file-explorer/lib/maven-file-tree-semantics"; import type { FileTreeSortOrder } from "@/features/settings/types/settings.types"; import { getBaseName, getRelativePath, joinPath, pathStartsWithRoot } from "@/utils/path-helpers"; @@ -8,11 +10,13 @@ export interface VisibleFileTreeRow { depth: number; isExpanded: boolean; displayName?: string; + semanticKind?: FileIconSemanticKind; guideAncestors?: Array; } export interface BuildVisibleFileTreeRowsOptions { compactFolders?: boolean; + directorySemantics?: ReadonlyMap; hiddenRootPath?: string; sortOrder?: FileTreeSortOrder; } @@ -136,6 +140,7 @@ export function buildVisibleFileTreeRows( options: BuildVisibleFileTreeRowsOptions = {}, ): VisibleFileTreeRow[] { const rows: VisibleFileTreeRow[] = []; + const directorySemantics = options.directorySemantics ?? buildMavenDirectorySemantics(files); const compactFolders = options.compactFolders === true; const hiddenRootPath = options.hiddenRootPath; const sortOrder = options.sortOrder ?? "folders-first"; @@ -162,8 +167,16 @@ export function buildVisibleFileTreeRows( if (compactFolders) { while (expandedPaths.has(rowFile.path)) { + const currentSemanticKind = directorySemantics.get(rowFile.path); + if (currentSemanticKind && currentSemanticKind !== "folder.package") break; + const child = getCompactFolderChild(rowFile); if (!child) break; + const childSemanticKind = directorySemantics.get(child.path); + if (currentSemanticKind === "folder.package" && childSemanticKind !== "folder.package") { + break; + } + if (childSemanticKind && childSemanticKind !== "folder.package") break; rowFile = child; displayNameParts.push(child.name); @@ -171,11 +184,16 @@ export function buildVisibleFileTreeRows( } const isExpanded = rowFile.isDir && expandedPaths.has(rowFile.path); + const semanticKind = directorySemantics.get(rowFile.path); const row: VisibleFileTreeRow = { file: rowFile, depth, isExpanded, - displayName: displayNameParts.length > 1 ? displayNameParts.join("/") : undefined, + displayName: + displayNameParts.length > 1 + ? displayNameParts.join(semanticKind === "folder.package" ? "." : "/") + : undefined, + semanticKind, guideAncestors, }; rows.push(row); diff --git a/windows/tauri/src/features/file-explorer/styles/file-explorer-tree-guides.test.ts b/windows/tauri/src/features/file-explorer/styles/file-explorer-tree-guides.test.ts new file mode 100644 index 000000000..1d4f60285 --- /dev/null +++ b/windows/tauri/src/features/file-explorer/styles/file-explorer-tree-guides.test.ts @@ -0,0 +1,16 @@ +import { expect, test } from "bun:test"; + +test("file tree indent guides reveal without changing their interaction geometry", async () => { + const styles = await Bun.file(new URL("./file-explorer-tree.css", import.meta.url)).text(); + + expect(styles).toContain( + ".file-tree-container:has(.file-tree-guide:hover) [data-sidebar-tree-row] .file-tree-guide", + ); + expect(styles).toContain( + ".file-tree-container:has(:focus-visible) [data-sidebar-tree-row] .file-tree-guide", + ); + expect(styles).toContain("transition: opacity var(--app-duration-fast) var(--app-ease-smooth)"); + expect(styles).toMatch( + /\.file-tree-container \[data-sidebar-tree-row\] \.file-tree-guide \{[^}]*width: 7px;[^}]*opacity: 0;[^}]*pointer-events: auto;/s, + ); +}); diff --git a/windows/tauri/src/features/file-explorer/styles/file-explorer-tree.css b/windows/tauri/src/features/file-explorer/styles/file-explorer-tree.css index faab5a6bf..a2632d02c 100644 --- a/windows/tauri/src/features/file-explorer/styles/file-explorer-tree.css +++ b/windows/tauri/src/features/file-explorer/styles/file-explorer-tree.css @@ -1,4 +1,12 @@ .file-tree-container { + --file-tree-disclosure-size: 16px; + --file-tree-guide-icon-offset: 8px; + --file-tree-hover-bg: var(--accent); + --file-tree-icon-size: 16px; + --file-tree-row-inline-inset: 6px; + --file-tree-row-radius: 4px; + --file-tree-selected-idle-bg: var(--border); + --tree-guide-color: color-mix(in srgb, var(--subtle-foreground) 20%, transparent); position: relative; overflow-x: hidden; overflow-y: auto; @@ -20,10 +28,12 @@ .file-tree-container .file-tree-virtual-row { position: absolute; + box-sizing: border-box; right: 0; left: 0; width: 100%; min-width: 0; + padding-inline: var(--file-tree-row-inline-inset); } .file-tree-container .file-tree-item { @@ -35,7 +45,7 @@ .file-tree-container .file-tree-item button { box-sizing: border-box !important; border: 1px solid transparent !important; - border-radius: var(--radius-lg) !important; + border-radius: var(--file-tree-row-radius) !important; max-width: 100% !important; width: 100% !important; min-width: 0 !important; @@ -43,32 +53,46 @@ overflow: clip; display: flex !important; justify-content: flex-start !important; + column-gap: var(--lithe-chrome-gap) !important; + padding-block: 2px !important; } .file-tree-container .file-tree-item button:hover { - background-color: var(--file-tree-hover-bg) !important; + background-color: transparent !important; } .file-tree-container .file-tree-item button.bg-selected, .file-tree-container .file-tree-item button.bg-selected:hover { - border-color: color-mix(in srgb, var(--border) 78%, transparent) !important; + border-color: transparent !important; + background-color: var(--file-tree-selected-idle-bg) !important; +} + +.file-explorer-shell[data-tree-focused="true"] .file-tree-item button.bg-selected, +.file-explorer-shell[data-tree-focused="true"] .file-tree-item button.bg-selected:hover { background-color: var(--selected) !important; } .file-tree-container .file-tree-item button:focus-visible { - border-color: color-mix(in srgb, var(--primary) 42%, var(--border)) !important; + border-color: transparent !important; + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 52%, var(--border)); } .file-tree-container .file-tree-item { position: relative; - --file-tree-hover-bg: color-mix(in srgb, var(--accent) 68%, transparent); - --file-tree-guide-icon-offset: 7px; - --tree-guide-color: color-mix(in srgb, var(--subtle-foreground) 18%, transparent); +} + +.file-tree-container [data-sidebar-tree-row]::before { + border-radius: var(--file-tree-row-radius); +} + +.file-tree-container [data-sidebar-tree-row]:hover::before { + background-color: var(--file-tree-hover-bg); } .file-tree-container .file-tree-row { position: relative; z-index: 2; + font-size: var(--ui-text-sm); box-sizing: border-box; height: 100%; max-width: 100%; @@ -83,10 +107,49 @@ text-overflow: ellipsis; } +.file-tree-container .file-tree-row [data-sidebar-tree-disclosure] { + width: var(--file-tree-disclosure-size); + height: var(--file-tree-disclosure-size); + margin-right: 0; +} + +.file-tree-container .file-tree-row [data-sidebar-tree-disclosure] svg { + width: 12px; + height: 12px; +} + +.file-tree-container .file-tree-node-icon { + width: var(--file-tree-icon-size) !important; + height: var(--file-tree-icon-size) !important; + line-height: var(--file-tree-icon-size); + text-align: center; +} + +.file-tree-container .file-tree-row[data-root="true"] .file-tree-node-label { + font-weight: 600; +} + .file-tree-container .file-tree-row input { min-width: 0; } +.file-tree-container .file-tree-edit-row input { + font-size: var(--ui-text-sm); +} + +.file-explorer-header { + border-bottom: 1px solid color-mix(in srgb, var(--border) 72%, transparent); + background-color: var(--background); + backdrop-filter: none; +} + +.file-explorer-header-title { + color: var(--foreground); + font-size: var(--ui-text-chrome); + font-weight: 600; + line-height: var(--lithe-chrome-line-height); +} + .file-explorer-base-text, .file-explorer-base-text * { font-size: var(--ui-text-sm); @@ -106,12 +169,19 @@ inset: 0; } -.file-tree-container .file-tree-guide { +.file-tree-container [data-sidebar-tree-row] .file-tree-guide { position: absolute; width: 7px; - opacity: 0.9; + opacity: 0; pointer-events: auto; transform: translateX(-3px); + transition: opacity var(--app-duration-fast) var(--app-ease-smooth); +} + +.file-tree-container:has(.file-tree-guide:hover) [data-sidebar-tree-row] .file-tree-guide, +.file-tree-container:focus-visible [data-sidebar-tree-row] .file-tree-guide, +.file-tree-container:has(:focus-visible) [data-sidebar-tree-row] .file-tree-guide { + opacity: 0.9; } .file-tree-container .file-tree-guide::before { diff --git a/windows/tauri/src/features/tabs/components/tab-bar-item.test.ts b/windows/tauri/src/features/tabs/components/tab-bar-item.test.ts new file mode 100644 index 000000000..f435ca141 --- /dev/null +++ b/windows/tauri/src/features/tabs/components/tab-bar-item.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from "bun:test"; + +test("editor tabs pass Java declaration semantics to the active icon theme", async () => { + const source = await Bun.file(new URL("./tab-bar-item.tsx", import.meta.url)).text(); + + expect(source).toContain( + 'import { useJavaFileIconKind } from "@/extensions/icon-themes/hooks/use-java-file-icon-kind";', + ); + expect(source).toContain('buffer.type === "editor" && !buffer.isVirtual'); + expect(source).toContain("semanticKind={javaSemanticKind}"); +}); diff --git a/windows/tauri/src/features/tabs/components/tab-bar-item.tsx b/windows/tauri/src/features/tabs/components/tab-bar-item.tsx index 8cd5ed796..b1258fccd 100644 --- a/windows/tauri/src/features/tabs/components/tab-bar-item.tsx +++ b/windows/tauri/src/features/tabs/components/tab-bar-item.tsx @@ -16,6 +16,7 @@ import { import { memo, useCallback, useEffect, useState } from "react"; import type { RefCallback } from "react"; import { ThemedFileIcon } from "@/extensions/icon-themes/components/themed-file-icon"; +import { useJavaFileIconKind } from "@/extensions/icon-themes/hooks/use-java-file-icon-kind"; import { getSingletonToolBufferTitleKey } from "@/features/panes/constants/tool-buffers"; import type { PaneContent } from "@/features/panes/types/pane-content.types"; import { shouldShowTabCloseButton } from "@/features/settings/lib/ui-preferences"; @@ -75,6 +76,12 @@ const TabBarItem = memo(function TabBarItem({ const [faviconError, setFaviconError] = useState(false); const [avatarError, setAvatarError] = useState(false); const showTabIcons = useSettingsStore((state) => state.settings.showTabIcons); + const javaSemanticKind = useJavaFileIconKind( + buffer.path, + buffer.name, + false, + showTabIcons && buffer.type === "editor" && !buffer.isVirtual, + ); const tabCloseButtonVisibility = useSettingsStore( (state) => state.settings.tabCloseButtonVisibility, ); @@ -239,6 +246,7 @@ const TabBarItem = memo(function TabBarItem({ )} diff --git a/windows/tauri/src/features/tabs/components/tab-bar.tsx b/windows/tauri/src/features/tabs/components/tab-bar.tsx index 962a760b7..1bf929f1d 100644 --- a/windows/tauri/src/features/tabs/components/tab-bar.tsx +++ b/windows/tauri/src/features/tabs/components/tab-bar.tsx @@ -10,6 +10,7 @@ import { SidebarSimpleIcon as PanelLeftClose, } from "@/ui/icons"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useJavaFileIconCacheLifecycle } from "@/extensions/icon-themes/hooks/use-java-file-icon-kind"; import { useBufferStore } from "@/features/editor/stores/buffer.store"; import { useJumpListStore } from "@/features/editor/stores/jump-list.store"; import { useEditorStateStore } from "@/features/editor/stores/state.store"; @@ -61,6 +62,7 @@ const TabBar = ({ onTabClick: externalTabClick, disablePaneActions = false, }: TabBarProps) => { + useJavaFileIconCacheLifecycle(); const { t } = useTranslation(); // Get everything from stores const pendingClose = useBufferStore.use.pendingClose(); From c974488028a070d60efd5ae998ad1fd0dbda464e Mon Sep 17 00:00:00 2001 From: ybx <3046829330@qq.com> Date: Thu, 20 Aug 2026 19:20:27 +0800 Subject: [PATCH 15/17] style(windows): polish IDEA-inspired workbench chrome --- .../src/extensions/themes/builtin/lithe.json | 40 +++++----- .../editor/components/toolbar/breadcrumb.tsx | 4 +- .../features/editor/engines/monaco/theme.ts | 4 +- .../components/bottom-pane/bottom-pane.tsx | 2 +- .../layout/components/footer/footer.tsx | 5 +- .../layout/components/main-layout.tsx | 11 +-- .../components/plugin-activity-rail.test.ts | 34 +++++++++ .../components/plugin-activity-rail.tsx | 46 ++++++----- .../layout/components/resizable-pane.tsx | 10 +-- .../components/sidebar/main-sidebar.tsx | 6 -- .../sidebar/sidebar-pane-selector.tsx | 12 --- .../components/workbench-panel-frame.test.ts | 51 +++++++++++++ .../features/layout/config/item-order.test.ts | 5 ++ .../src/features/layout/config/item-order.ts | 1 - .../settings/config/default-settings.ts | 2 +- .../settings/config/typography-defaults.ts | 5 +- .../lib/settings-normalization.test.ts | 32 ++++++++ .../settings/lib/settings-normalization.ts | 12 +++ .../components/terminal-container.tsx | 35 +++++++-- .../utils/terminal-pane-visibility.test.ts | 76 +++++++++++++++++++ .../utils/terminal-pane-visibility.ts | 36 +++++++++ .../window/components/project-tab-bar.tsx | 20 +++-- .../window/components/title-bar/title-bar.tsx | 44 ++++++----- .../components/title-bar/window-controls.tsx | 19 +++-- .../window/components/window-menu-bar.test.ts | 12 +++ .../window/components/window-menu-bar.tsx | 4 +- .../utils/project-tab-bar-model.test.ts | 9 ++- .../window/utils/project-tab-bar-model.ts | 4 + windows/tauri/src/i18n/locale.test.ts | 2 +- windows/tauri/src/styles/theme.css | 10 +-- .../tauri/src/styles/window-transparency.css | 4 +- windows/tauri/src/ui/menubar.tsx | 2 +- windows/tauri/src/ui/sidebar.tsx | 9 +-- windows/tauri/src/ui/tab-bar.tsx | 7 +- 34 files changed, 429 insertions(+), 146 deletions(-) create mode 100644 windows/tauri/src/features/layout/components/plugin-activity-rail.test.ts create mode 100644 windows/tauri/src/features/layout/components/workbench-panel-frame.test.ts create mode 100644 windows/tauri/src/features/terminal/utils/terminal-pane-visibility.test.ts create mode 100644 windows/tauri/src/features/terminal/utils/terminal-pane-visibility.ts create mode 100644 windows/tauri/src/features/window/components/window-menu-bar.test.ts diff --git a/windows/tauri/src/extensions/themes/builtin/lithe.json b/windows/tauri/src/extensions/themes/builtin/lithe.json index 3e42a2d69..f340924ac 100644 --- a/windows/tauri/src/extensions/themes/builtin/lithe.json +++ b/windows/tauri/src/extensions/themes/builtin/lithe.json @@ -84,9 +84,9 @@ "border": "#43454a", "accent": "#393b40", "selected": "#2e436e", - "selection": "rgba(53, 116, 240, 0.3)", + "selection": "#214283", "primary": "#3574f0", - "cursor": "#dfe1e5", + "cursor": "#ced0d6", "cursor-vim-normal": "rgba(53, 116, 240, 0.68)", "cursor-vim-insert": "#3574f0", "destructive": "#db5c5c", @@ -117,24 +117,24 @@ "terminal-bright-white": "#ffffff" }, "syntax": { - "comment": "#7f8793", - "keyword": "#e879c6", - "string": "#8ccf9f", - "number": "#e2a96b", - "function": "#61c0bf", - "variable": "#c8a2f4", - "tag": "#61c0bf", - "attribute": "#e2a96b", - "punctuation": "#a2a9b4", - "constant": "#e2a96b", - "property": "#6cb6f1", - "type": "#8fb8ff", - "operator": "#e879c6", - "boolean": "#e879c6", - "null": "#c8a2f4", - "regex": "#8ccf9f", - "jsx": "#61c0bf", - "jsx-attribute": "#e2a96b" + "comment": "#7a7e85", + "keyword": "#cf8e6d", + "string": "#6aab73", + "number": "#2aacb8", + "function": "#56a8f5", + "variable": "#bcbec4", + "tag": "#d5b778", + "attribute": "#b3ae60", + "punctuation": "#bcbec4", + "constant": "#c77dbb", + "property": "#c77dbb", + "type": "#bcbec4", + "operator": "#bcbec4", + "boolean": "#cf8e6d", + "null": "#cf8e6d", + "regex": "#6aab73", + "jsx": "#d5b778", + "jsx-attribute": "#b3ae60" } } ] diff --git a/windows/tauri/src/features/editor/components/toolbar/breadcrumb.tsx b/windows/tauri/src/features/editor/components/toolbar/breadcrumb.tsx index 8e44f2cb7..43c8d7fec 100644 --- a/windows/tauri/src/features/editor/components/toolbar/breadcrumb.tsx +++ b/windows/tauri/src/features/editor/components/toolbar/breadcrumb.tsx @@ -202,8 +202,8 @@ export default function Breadcrumb({ return ( <> -
-
+
+
{showPath && showBreadcrumbPath ? ( <> {showFilePath ? ( diff --git a/windows/tauri/src/features/editor/engines/monaco/theme.ts b/windows/tauri/src/features/editor/engines/monaco/theme.ts index 0e5daf283..18250423c 100644 --- a/windows/tauri/src/features/editor/engines/monaco/theme.ts +++ b/windows/tauri/src/features/editor/engines/monaco/theme.ts @@ -76,8 +76,8 @@ function createMonacoThemeData( "editor.foreground": foreground, "editorCursor.foreground": cursor, "editor.selectionBackground": selection, - "editor.inactiveSelectionBackground": selected, - "editor.lineHighlightBackground": selected, + "editor.inactiveSelectionBackground": border, + "editor.lineHighlightBackground": secondaryBackground, "editorLineNumber.foreground": subtleForeground, "editorLineNumber.activeForeground": foreground, "editorIndentGuide.background1": border, diff --git a/windows/tauri/src/features/layout/components/bottom-pane/bottom-pane.tsx b/windows/tauri/src/features/layout/components/bottom-pane/bottom-pane.tsx index e1bf0b043..85cfcae17 100644 --- a/windows/tauri/src/features/layout/components/bottom-pane/bottom-pane.tsx +++ b/windows/tauri/src/features/layout/components/bottom-pane/bottom-pane.tsx @@ -245,7 +245,7 @@ const BottomPane = () => {
{ (state) => state.settings.footerTrailingItemsOrder, ); const filePathItem = useFooterFilePathItem(); - const branchItem = useFooterGitBranchItem(); const editorStatusItems = useFooterEditorStatusItems(); const footerLeadingItemsSource: Array | null> = [ filePathItem, - branchItem, ]; const footerLeadingItems = footerLeadingItemsSource.filter( (item): item is ChromeItem => item !== null, @@ -54,7 +51,7 @@ const Footer = () => { return ( diff --git a/windows/tauri/src/features/layout/components/main-layout.tsx b/windows/tauri/src/features/layout/components/main-layout.tsx index 4893c2b83..8d1a69a7c 100644 --- a/windows/tauri/src/features/layout/components/main-layout.tsx +++ b/windows/tauri/src/features/layout/components/main-layout.tsx @@ -19,7 +19,6 @@ import { useWorkspaceTabsStore } from "@/features/window/stores/workspace-tabs.s import { useUIState } from "@/features/window/stores/ui-state.store"; import { toast } from "sonner"; import { useTranslation } from "@/i18n/locale-provider"; -import { cn } from "@/utils/cn"; import { frontendTrace } from "@/utils/frontend-trace"; import { recordStartupMilestone } from "@/features/bootstrap/startup-performance"; import { getInternalTabDragData } from "@/features/tabs/utils/internal-tab-drag"; @@ -262,7 +261,7 @@ export function MainLayout() { )} - + {rootFolderPath ? ( <> @@ -282,13 +281,7 @@ export function MainLayout() {
-
+
{terminalWidthMode === "editor" && deferredSurfacesReady && ( diff --git a/windows/tauri/src/features/layout/components/plugin-activity-rail.test.ts b/windows/tauri/src/features/layout/components/plugin-activity-rail.test.ts new file mode 100644 index 000000000..f5718d6a5 --- /dev/null +++ b/windows/tauri/src/features/layout/components/plugin-activity-rail.test.ts @@ -0,0 +1,34 @@ +import { expect, test } from "bun:test"; + +test("right activity rail opens the real singleton Extensions buffer", async () => { + const railSource = await Bun.file( + new URL("./plugin-activity-rail.tsx", import.meta.url), + ).text(); + const layoutSource = await Bun.file(new URL("./main-layout.tsx", import.meta.url)).text(); + + expect(railSource).toContain( + "const openExtensionsBuffer = useBufferStore.use.actions().openExtensionsBuffer;", + ); + expect(railSource).toContain('buffer.type === "extensions"'); + expect(railSource).toContain('const extensionsLabel = t("extensions.title");'); + expect(railSource).toContain("aria-pressed={isExtensionsActive}"); + expect(railSource).toContain("onClick={openExtensionsBuffer}"); + expect(railSource).not.toContain("useState"); + expect(layoutSource).toContain(""); +}); + +test("right activity rail reserves only the current Extensions entry", async () => { + const railSource = await Bun.file( + new URL("./plugin-activity-rail.tsx", import.meta.url), + ).text(); + const transparencyStyles = await Bun.file( + new URL("../../../styles/window-transparency.css", import.meta.url), + ).text(); + + expect(railSource).toContain( + 'className="lithe-plugin-activity-rail flex w-9.5 shrink-0 flex-col items-center rounded-r-xl border-border border-r bg-surface pt-1"', + ); + expect(railSource).toContain(''); + expect(railSource.match(/ - + ); } diff --git a/windows/tauri/src/features/layout/components/resizable-pane.tsx b/windows/tauri/src/features/layout/components/resizable-pane.tsx index f3ac8259d..8b66df2bb 100644 --- a/windows/tauri/src/features/layout/components/resizable-pane.tsx +++ b/windows/tauri/src/features/layout/components/resizable-pane.tsx @@ -185,6 +185,8 @@ export function ResizablePane({ className={cn( "lithe-resizable-pane relative flex h-full min-w-0 shrink-0 overflow-visible bg-transparent", hidden && "pointer-events-none", + !hidden && position === "left" && "mr-(--lithe-workbench-gap)", + !hidden && position === "right" && "ml-(--lithe-workbench-gap)", className, )} aria-hidden={hidden} @@ -198,11 +200,9 @@ export function ResizablePane({ >
{children} diff --git a/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx b/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx index 3b08492fe..5f03963a4 100644 --- a/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx +++ b/windows/tauri/src/features/layout/components/sidebar/main-sidebar.tsx @@ -57,7 +57,6 @@ import { } from "@/ui/context-menu"; import { Spinner } from "@/ui/spinner"; import { - DatabaseIcon, EyeIcon, FilesIcon, FolderIcon, @@ -207,11 +206,6 @@ export const SidebarActivityRail = memo(({ expanded = false }: SidebarActivityRa }, ] : []), - { - id: "database", - label: t("workbench.database"), - icon: , - }, ...(coreFeatures.terminal ? [ { diff --git a/windows/tauri/src/features/layout/components/sidebar/sidebar-pane-selector.tsx b/windows/tauri/src/features/layout/components/sidebar/sidebar-pane-selector.tsx index 52123f568..58188a02d 100644 --- a/windows/tauri/src/features/layout/components/sidebar/sidebar-pane-selector.tsx +++ b/windows/tauri/src/features/layout/components/sidebar/sidebar-pane-selector.tsx @@ -14,7 +14,6 @@ import { useSettingsStore } from "@/features/settings/stores/settings.store"; import { SidebarListItem } from "@/ui/sidebar"; import { Tabs, TabsList, TabsTrigger } from "@/ui/tabs"; import { - DatabaseIcon, GearIcon, GitBranchIcon, GitGraphIcon, @@ -180,17 +179,6 @@ export const SidebarPaneSelector = ({ } satisfies SidebarPaneItem, ] : []), - { - id: "database", - label: showLabels ? t("workbench.database") : undefined, - icon: , - disabled: true, - ariaLabel: t("workbench.database"), - tooltip: { - content: BACKEND_UNAVAILABLE_TOOLTIP, - side: tooltipSide, - }, - }, ...(coreFeatures.terminal && onTerminalClick ? [ { diff --git a/windows/tauri/src/features/layout/components/workbench-panel-frame.test.ts b/windows/tauri/src/features/layout/components/workbench-panel-frame.test.ts new file mode 100644 index 000000000..6527743c2 --- /dev/null +++ b/windows/tauri/src/features/layout/components/workbench-panel-frame.test.ts @@ -0,0 +1,51 @@ +import { expect, test } from "bun:test"; + +test("workbench keeps the Project divider without outer horizontal or editor-to-rail seams", async () => { + const layoutSource = await Bun.file(new URL("./main-layout.tsx", import.meta.url)).text(); + const resizablePaneSource = await Bun.file( + new URL("./resizable-pane.tsx", import.meta.url), + ).text(); + const pluginRailSource = await Bun.file( + new URL("./plugin-activity-rail.tsx", import.meta.url), + ).text(); + const bottomPaneSource = await Bun.file( + new URL("./bottom-pane/bottom-pane.tsx", import.meta.url), + ).text(); + const footerSource = await Bun.file(new URL("./footer/footer.tsx", import.meta.url)).text(); + const titleBarSource = await Bun.file( + new URL("../../window/components/title-bar/title-bar.tsx", import.meta.url), + ).text(); + + expect(layoutSource).toContain( + 'className="lithe-glass-island relative min-h-0 flex-1 overflow-hidden rounded-xl border-border border-l bg-background"', + ); + expect(resizablePaneSource).toContain( + '!hidden && position === "left" && "mr-(--lithe-workbench-gap)"', + ); + expect(resizablePaneSource).toContain( + '!hidden && position === "right" && "ml-(--lithe-workbench-gap)"', + ); + expect(resizablePaneSource).toContain( + '!hidden && "rounded-xl border-border border-x"', + ); + expect(pluginRailSource).toContain( + 'className="lithe-plugin-activity-rail flex w-9.5 shrink-0 flex-col items-center rounded-r-xl border-border border-r bg-surface pt-1"', + ); + expect(pluginRailSource).not.toContain('ml-(--lithe-workbench-gap)'); + expect(pluginRailSource).not.toContain("border-l"); + expect(bottomPaneSource).toContain( + 'rounded-xl border-border/70 border-t border-l bg-background', + ); + expect(titleBarSource).toContain( + 'gap-(--lithe-chrome-gap) bg-surface px-(--lithe-chrome-padding-inline)', + ); + expect(titleBarSource).not.toContain( + 'gap-(--lithe-chrome-gap) border-border border-b bg-surface', + ); + expect(footerSource).toContain( + 'className="lithe-footer-bar relative z-20 justify-between gap-2 bg-surface"', + ); + expect(footerSource).not.toContain("border-t"); + expect(resizablePaneSource).toContain('const totalWidth = hidden ? "0px" : `${width}px`;'); + expect(resizablePaneSource).toContain('contentEl.style.width = `${currentWidth}px`;'); +}); diff --git a/windows/tauri/src/features/layout/config/item-order.test.ts b/windows/tauri/src/features/layout/config/item-order.test.ts index a6c33adc3..c53e4b458 100644 --- a/windows/tauri/src/features/layout/config/item-order.test.ts +++ b/windows/tauri/src/features/layout/config/item-order.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from "bun:test"; import { FOOTER_TRAILING_ITEM_IDS, + SIDEBAR_ACTIVITY_ITEM_IDS, SIDEBAR_BOTTOM_ACTIVITY_ITEM_IDS, normalizeItemOrder, } from "./item-order"; @@ -22,6 +23,10 @@ describe("footer item order", () => { }); describe("sidebar activity order", () => { + test("does not expose an unavailable Database placeholder", () => { + expect([...SIDEBAR_ACTIVITY_ITEM_IDS]).not.toContain("database"); + }); + test("places Run, Terminal, Diagnostics, Git Log, then Settings", () => { expect([...SIDEBAR_BOTTOM_ACTIVITY_ITEM_IDS]).toEqual([ "run", diff --git a/windows/tauri/src/features/layout/config/item-order.ts b/windows/tauri/src/features/layout/config/item-order.ts index 11f2ca4fd..6c05b4e89 100644 --- a/windows/tauri/src/features/layout/config/item-order.ts +++ b/windows/tauri/src/features/layout/config/item-order.ts @@ -3,7 +3,6 @@ export const SIDEBAR_ACTIVITY_ITEM_IDS = [ "files", "git", "search", - "database", "run", "terminal", "diagnostics", diff --git a/windows/tauri/src/features/settings/config/default-settings.ts b/windows/tauri/src/features/settings/config/default-settings.ts index 0e5845d53..40ff548d2 100644 --- a/windows/tauri/src/features/settings/config/default-settings.ts +++ b/windows/tauri/src/features/settings/config/default-settings.ts @@ -64,7 +64,7 @@ export const defaultSettings: Settings = { // UI uiFontFamily: DEFAULT_UI_FONT_FAMILY, uiFontSize: UI_FONT_SIZE_DEFAULT, - displayLanguage: "en-US", + displayLanguage: "zh-CN", reduceMotion: false, showStatusBar: true, showTabIcons: true, diff --git a/windows/tauri/src/features/settings/config/typography-defaults.ts b/windows/tauri/src/features/settings/config/typography-defaults.ts index 84ee4605f..61e4036de 100644 --- a/windows/tauri/src/features/settings/config/typography-defaults.ts +++ b/windows/tauri/src/features/settings/config/typography-defaults.ts @@ -1,4 +1,4 @@ -export const DEFAULT_UI_FONT_FAMILY = "Geist Sans"; +export const DEFAULT_UI_FONT_FAMILY = "Microsoft YaHei UI"; export const DEFAULT_MONO_FONT_FAMILY = "Geist Mono"; const DEFAULT_MONO_FONT_FALLBACK = @@ -11,8 +11,7 @@ const WINDOWS_SANS_FONT_FALLBACK = '"Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif'; export const DEFAULT_CODE_FONT_SIZE = 14; -const DEFAULT_UI_FONT_SIZE_OFFSET = 1; -export const DEFAULT_UI_FONT_SIZE = DEFAULT_CODE_FONT_SIZE + DEFAULT_UI_FONT_SIZE_OFFSET; +export const DEFAULT_UI_FONT_SIZE = 13; export function getTypographyFontFallbacks(isWindows: boolean) { return { diff --git a/windows/tauri/src/features/settings/lib/settings-normalization.test.ts b/windows/tauri/src/features/settings/lib/settings-normalization.test.ts index ecf330bf5..9c5f0a39b 100644 --- a/windows/tauri/src/features/settings/lib/settings-normalization.test.ts +++ b/windows/tauri/src/features/settings/lib/settings-normalization.test.ts @@ -42,3 +42,35 @@ describe("IDEA file icon theme normalization", () => { } }); }); + +describe("Windows New UI defaults", () => { + test("uses Chinese and the native CJK UI typography for new settings", () => { + const settings = getDefaultSettingsSnapshot(); + + expect(settings.displayLanguage).toBe("zh-CN"); + expect(settings.uiFontFamily).toBe("Microsoft YaHei UI"); + expect(settings.uiFontSize).toBe(13); + }); + + test("migrates the previous bundled UI typography as a pair", () => { + const settings = getDefaultSettingsSnapshot(); + settings.uiFontFamily = "Geist Sans"; + settings.uiFontSize = 15; + + const normalized = normalizeSettings(settings); + + expect(normalized.uiFontFamily).toBe("Microsoft YaHei UI"); + expect(normalized.uiFontSize).toBe(13); + }); + + test("preserves an explicitly customized typography pair", () => { + const settings = getDefaultSettingsSnapshot(); + settings.uiFontFamily = "Geist Sans"; + settings.uiFontSize = 14; + + const normalized = normalizeSettings(settings); + + expect(normalized.uiFontFamily).toBe("Geist Sans"); + expect(normalized.uiFontSize).toBe(14); + }); +}); diff --git a/windows/tauri/src/features/settings/lib/settings-normalization.ts b/windows/tauri/src/features/settings/lib/settings-normalization.ts index 41964801c..b396f119c 100644 --- a/windows/tauri/src/features/settings/lib/settings-normalization.ts +++ b/windows/tauri/src/features/settings/lib/settings-normalization.ts @@ -11,6 +11,7 @@ import { import { DEFAULT_MONO_FONT_FAMILY, DEFAULT_UI_FONT_FAMILY, + DEFAULT_UI_FONT_SIZE, } from "@/features/settings/config/typography-defaults"; import { normalizeConfiguredFontFamily } from "@/features/settings/lib/font-family-resolution"; import { @@ -95,6 +96,9 @@ const AI_MODEL_MIGRATIONS: Record> = { }, }; +const LEGACY_DEFAULT_UI_FONT_FAMILY = "Geist Sans"; +const LEGACY_DEFAULT_UI_FONT_SIZE = 15; + const AI_AUTOCOMPLETE_MODEL_MIGRATIONS: Record = { "google/gemini-2.5-flash-lite": "google/gemini-3.1-flash-lite", }; @@ -461,6 +465,14 @@ export function normalizeSettings(settings: Settings): Settings { normalizedSettings.gitSidebarTabOrder = ["changes", "history"]; } + if ( + normalizedSettings.uiFontFamily === LEGACY_DEFAULT_UI_FONT_FAMILY && + normalizedSettings.uiFontSize === LEGACY_DEFAULT_UI_FONT_SIZE + ) { + normalizedSettings.uiFontFamily = DEFAULT_UI_FONT_FAMILY; + normalizedSettings.uiFontSize = DEFAULT_UI_FONT_SIZE; + } + normalizedSettings.uiFontSize = normalizeUiFontSize(normalizedSettings.uiFontSize); normalizedSettings.fontFamily = normalizeConfiguredFontFamily( normalizedSettings.fontFamily, diff --git a/windows/tauri/src/features/terminal/components/terminal-container.tsx b/windows/tauri/src/features/terminal/components/terminal-container.tsx index fe079ef55..881af0456 100644 --- a/windows/tauri/src/features/terminal/components/terminal-container.tsx +++ b/windows/tauri/src/features/terminal/components/terminal-container.tsx @@ -8,6 +8,10 @@ import { useTerminalProfilesStore } from "@/features/terminal/stores/profiles.st import { useTerminalStore } from "@/features/terminal/stores/terminal.store"; import { useTerminalShellsStore } from "@/features/terminal/stores/shells.store"; import type { TerminalSplitDirection } from "@/features/terminal/types/terminal.types"; +import { + openNewTerminalFromGlobalEntry, + shouldAutoHideTerminalPane, +} from "@/features/terminal/utils/terminal-pane-visibility"; import { resolveTerminalLaunch, SYSTEM_DEFAULT_PROFILE_ID, @@ -85,7 +89,7 @@ const TerminalContainer = ({ [originalCloseTerminal], ); - const hasInitializedRef = useRef(false); + const previousTerminalCountRef = useRef(terminals.length); const wasVisibleRef = useRef(false); const workspaceDirectoryRef = useRef(currentDirectory); const terminalSessionRefs = useRef void; showSearch: () => void }>>( @@ -99,7 +103,7 @@ const TerminalContainer = ({ } workspaceDirectoryRef.current = currentDirectory; - hasInitializedRef.current = terminals.length > 0; + previousTerminalCountRef.current = terminals.length; wasVisibleRef.current = false; }, [currentDirectory, terminals.length]); const registerTerminalFocus = useUIState((state) => state.registerTerminalFocus); @@ -190,12 +194,23 @@ const TerminalContainer = ({ }; }, []); - // Auto-close bottom pane when all terminals are closed + // Collapse only on a visible terminal pane's transition from live tabs to none. + // An already-empty pane is allowed to remain visible long enough to create its first terminal. useEffect(() => { - if (terminals.length === 0 && hasInitializedRef.current) { + const previousTerminalCount = previousTerminalCountRef.current; + previousTerminalCountRef.current = terminals.length; + + if ( + shouldAutoHideTerminalPane({ + bottomPaneActiveTab, + isBottomPaneVisible, + previousTerminalCount, + terminalCount: terminals.length, + }) + ) { setIsBottomPaneVisible(false); } - }, [terminals.length, setIsBottomPaneVisible]); + }, [bottomPaneActiveTab, isBottomPaneVisible, terminals.length, setIsBottomPaneVisible]); const handleTabClick = useCallback( (terminalId: string) => { @@ -508,7 +523,11 @@ const TerminalContainer = ({ useEffect(() => { const handleNewTerminalEvent = () => { - handleNewTerminal(); + openNewTerminalFromGlobalEntry({ + createTerminal: handleNewTerminal, + setBottomPaneActiveTab, + setIsBottomPaneVisible, + }); }; const handleDetachTerminalToBuffer = (event: Event) => { @@ -521,7 +540,6 @@ const TerminalContainer = ({ const handleEnsureTerminalSession = () => { if (terminals.length === 0) { - hasInitializedRef.current = true; handleNewTerminal(); return; } @@ -558,6 +576,8 @@ const TerminalContainer = ({ focusActiveTerminal, handleNewTerminal, setActiveTerminal, + setBottomPaneActiveTab, + setIsBottomPaneVisible, handleSplitView, closeTerminal, ]); @@ -568,7 +588,6 @@ const TerminalContainer = ({ const justBecameVisible = isTerminalVisible && !wasVisibleRef.current; if (justBecameVisible && terminals.length === 0) { - hasInitializedRef.current = true; handleNewTerminal(); } diff --git a/windows/tauri/src/features/terminal/utils/terminal-pane-visibility.test.ts b/windows/tauri/src/features/terminal/utils/terminal-pane-visibility.test.ts new file mode 100644 index 000000000..ba269046a --- /dev/null +++ b/windows/tauri/src/features/terminal/utils/terminal-pane-visibility.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, test } from "bun:test"; +import { + openNewTerminalFromGlobalEntry, + shouldAutoHideTerminalPane, +} from "./terminal-pane-visibility"; + +describe("terminal pane auto-hide", () => { + test("hides the visible terminal pane after its last terminal closes", () => { + expect( + shouldAutoHideTerminalPane({ + bottomPaneActiveTab: "terminal", + isBottomPaneVisible: true, + previousTerminalCount: 1, + terminalCount: 0, + }), + ).toBe(true); + }); + + test("keeps an already-empty terminal pane open so a new terminal can be created", () => { + expect( + shouldAutoHideTerminalPane({ + bottomPaneActiveTab: "terminal", + isBottomPaneVisible: true, + previousTerminalCount: 0, + terminalCount: 0, + }), + ).toBe(false); + }); + + test("does not hide a terminal pane that is already hidden", () => { + expect( + shouldAutoHideTerminalPane({ + bottomPaneActiveTab: "terminal", + isBottomPaneVisible: false, + previousTerminalCount: 1, + terminalCount: 0, + }), + ).toBe(false); + }); + + test("does not hide another active bottom tool window when terminals close", () => { + for (const bottomPaneActiveTab of ["run", "gitLog", "debugger", "buffers"]) { + expect( + shouldAutoHideTerminalPane({ + bottomPaneActiveTab, + isBottomPaneVisible: true, + previousTerminalCount: 1, + terminalCount: 0, + }), + ).toBe(false); + } + }); + + test("keeps the terminal pane visible while another terminal remains", () => { + expect( + shouldAutoHideTerminalPane({ + bottomPaneActiveTab: "terminal", + isBottomPaneVisible: true, + previousTerminalCount: 2, + terminalCount: 1, + }), + ).toBe(false); + }); + + test("global new-terminal entry shows the terminal pane and creates exactly one terminal", () => { + const calls: string[] = []; + + openNewTerminalFromGlobalEntry({ + createTerminal: () => calls.push("create"), + setBottomPaneActiveTab: (tab) => calls.push(`tab:${tab}`), + setIsBottomPaneVisible: (visible) => calls.push(`visible:${visible}`), + }); + + expect(calls).toEqual(["tab:terminal", "visible:true", "create"]); + }); +}); diff --git a/windows/tauri/src/features/terminal/utils/terminal-pane-visibility.ts b/windows/tauri/src/features/terminal/utils/terminal-pane-visibility.ts new file mode 100644 index 000000000..bdf2336a6 --- /dev/null +++ b/windows/tauri/src/features/terminal/utils/terminal-pane-visibility.ts @@ -0,0 +1,36 @@ +interface TerminalPaneVisibilityState { + bottomPaneActiveTab: string; + isBottomPaneVisible: boolean; + previousTerminalCount: number; + terminalCount: number; +} + +interface NewTerminalEntryActions { + createTerminal: () => void; + setBottomPaneActiveTab: (tab: "terminal") => void; + setIsBottomPaneVisible: (visible: true) => void; +} + +export function shouldAutoHideTerminalPane({ + bottomPaneActiveTab, + isBottomPaneVisible, + previousTerminalCount, + terminalCount, +}: TerminalPaneVisibilityState): boolean { + return ( + isBottomPaneVisible && + bottomPaneActiveTab === "terminal" && + previousTerminalCount > 0 && + terminalCount === 0 + ); +} + +export function openNewTerminalFromGlobalEntry({ + createTerminal, + setBottomPaneActiveTab, + setIsBottomPaneVisible, +}: NewTerminalEntryActions): void { + setBottomPaneActiveTab("terminal"); + setIsBottomPaneVisible(true); + createTerminal(); +} diff --git a/windows/tauri/src/features/window/components/project-tab-bar.tsx b/windows/tauri/src/features/window/components/project-tab-bar.tsx index 19d7bb6f2..74e1cf859 100644 --- a/windows/tauri/src/features/window/components/project-tab-bar.tsx +++ b/windows/tauri/src/features/window/components/project-tab-bar.tsx @@ -5,9 +5,13 @@ import { useWorkspaceTabsStore } from "@/features/window/stores/workspace-tabs.s import { Button } from "@/ui/button"; import { FolderIcon, XIcon as X } from "@/ui/icons"; import { cn } from "@/utils/cn"; -import { getProjectTabBarItems } from "../utils/project-tab-bar-model"; +import { getProjectTabBarItems, shouldShowProjectTabBar } from "../utils/project-tab-bar-model"; -export function ProjectTabBar() { +interface ProjectTabBarProps { + hideWhenSingle?: boolean; +} + +export function ProjectTabBar({ hideWhenSingle = false }: ProjectTabBarProps) { const { t } = useTranslation(); const [closingProjectId, setClosingProjectId] = useState(null); const projectTabs = useWorkspaceTabsStore.use.projectTabs(); @@ -28,11 +32,11 @@ export function ProjectTabBar() { } }; - if (projects.length === 0) return null; + if (!shouldShowProjectTabBar(projects.length, hideWhenSingle)) return null; return (