diff --git a/bun.lock b/bun.lock index 067d6926..49753da4 100644 --- a/bun.lock +++ b/bun.lock @@ -24,7 +24,8 @@ "@solidjs/router": "0.15.3", "@thisbeyond/solid-dnd": "0.7.5", "diff": "8.0.2", - "luxon": "3.7.1", + "fuzzysort": "catalog:", + "luxon": "catalog:", "marked": "16.2.0", "marked-shiki": "1.2.1", "remeda": "catalog:", @@ -218,11 +219,11 @@ "diff": "8.0.2", "js-base64": "3.7.7", "lang-map": "0.4.0", - "luxon": "3.6.1", + "luxon": "catalog:", "marked": "15.0.12", "marked-shiki": "1.2.1", "rehype-autolink-headings": "7.1.0", - "remeda": "2.26.0", + "remeda": "catalog:", "sharp": "0.32.5", "shiki": "3.4.2", "solid-js": "catalog:", @@ -249,7 +250,9 @@ "@types/bun": "1.2.21", "@types/node": "22.13.9", "ai": "5.0.8", + "fuzzysort": "3.1.0", "hono": "4.7.10", + "luxon": "3.6.1", "remeda": "2.26.0", "solid-js": "1.9.9", "typescript": "5.8.2", @@ -1660,6 +1663,8 @@ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "fuzzysort": ["fuzzysort@3.1.0", "", {}, "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ=="], + "gel": ["gel@2.1.1", "", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-Newg9X7mRYskoBjSw70l1YnJ/ZGbq64VPyR821H5WVkTGpHG2O0mQILxCeUhxdYERLFY9B4tUyKLyf3uMTjtKw=="], "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], @@ -1988,7 +1993,7 @@ "lru.min": ["lru.min@1.1.2", "", {}, "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg=="], - "luxon": ["luxon@3.7.1", "", {}, "sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg=="], + "luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="], "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], @@ -3034,8 +3039,6 @@ "@opencode/web/@types/luxon": ["@types/luxon@3.6.2", "", {}, "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw=="], - "@opencode/web/luxon": ["luxon@3.6.1", "", {}, "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ=="], - "@opencode/web/marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], "@opencode/web/shiki": ["shiki@3.4.2", "", { "dependencies": { "@shikijs/core": "3.4.2", "@shikijs/engine-javascript": "3.4.2", "@shikijs/engine-oniguruma": "3.4.2", "@shikijs/langs": "3.4.2", "@shikijs/themes": "3.4.2", "@shikijs/types": "3.4.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ=="], diff --git a/package.json b/package.json index d775a3fa..99baee94 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "@tsconfig/node22": "22.0.2", "ai": "5.0.8", "hono": "4.7.10", + "fuzzysort": "3.1.0", + "luxon": "3.6.1", "typescript": "5.8.2", "zod": "4.1.8", "remeda": "2.26.0", diff --git a/packages/app/package.json b/packages/app/package.json index 142cb3a5..bcd26254 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -29,7 +29,8 @@ "@solidjs/router": "0.15.3", "@thisbeyond/solid-dnd": "0.7.5", "diff": "8.0.2", - "luxon": "3.7.1", + "fuzzysort": "catalog:", + "luxon": "catalog:", "marked": "16.2.0", "marked-shiki": "1.2.1", "remeda": "catalog:", diff --git a/packages/app/src/assets/theme.css b/packages/app/src/assets/theme.css index 48d91fc9..9012c589 100644 --- a/packages/app/src/assets/theme.css +++ b/packages/app/src/assets/theme.css @@ -159,109 +159,109 @@ } [data-theme="ayu"][data-dark="false"] { - --theme-primary: #59c2ff; - --theme-secondary: #d2a6ff; - --theme-accent: #e6b450; - --theme-error: #d95757; - --theme-warning: #e6b673; - --theme-success: #7fd962; - --theme-info: #39bae6; - --theme-text: #bfbdb6; - --theme-text-muted: #565b66; - --theme-background: #0b0e14; - --theme-background-panel: #0f131a; - --theme-background-element: #0d1017; - --theme-border: #6c7380; - --theme-border-active: #6c7380; - --theme-border-subtle: #11151c; - --theme-diff-added: #7fd962; - --theme-diff-removed: #f26d78; - --theme-diff-context: #acb6bf; - --theme-diff-hunk-header: #acb6bf; - --theme-diff-highlight-added: #aad94c; - --theme-diff-highlight-removed: #f07178; + --theme-primary: #59C2FF; + --theme-secondary: #D2A6FF; + --theme-accent: #E6B450; + --theme-error: #D95757; + --theme-warning: #E6B673; + --theme-success: #7FD962; + --theme-info: #39BAE6; + --theme-text: #BFBDB6; + --theme-text-muted: #565B66; + --theme-background: #0B0E14; + --theme-background-panel: #0F131A; + --theme-background-element: #0D1017; + --theme-border: #6C7380; + --theme-border-active: #6C7380; + --theme-border-subtle: #11151C; + --theme-diff-added: #7FD962; + --theme-diff-removed: #F26D78; + --theme-diff-context: #ACB6BF; + --theme-diff-hunk-header: #ACB6BF; + --theme-diff-highlight-added: #AAD94C; + --theme-diff-highlight-removed: #F07178; --theme-diff-added-bg: #20303b; --theme-diff-removed-bg: #37222c; - --theme-diff-context-bg: #0f131a; - --theme-diff-line-number: #6c7380; + --theme-diff-context-bg: #0F131A; + --theme-diff-line-number: #6C7380; --theme-diff-added-line-number-bg: #1b2b34; --theme-diff-removed-line-number-bg: #2d1f26; - --theme-markdown-text: #bfbdb6; - --theme-markdown-heading: #d2a6ff; - --theme-markdown-link: #59c2ff; - --theme-markdown-link-text: #39bae6; - --theme-markdown-code: #aad94c; - --theme-markdown-block-quote: #e6b673; - --theme-markdown-emph: #e6b673; - --theme-markdown-strong: #ffb454; - --theme-markdown-horizontal-rule: #565b66; - --theme-markdown-list-item: #59c2ff; - --theme-markdown-list-enumeration: #39bae6; - --theme-markdown-image: #59c2ff; - --theme-markdown-image-text: #39bae6; - --theme-markdown-code-block: #bfbdb6; - --theme-syntax-comment: #acb6bf; - --theme-syntax-keyword: #ff8f40; - --theme-syntax-function: #ffb454; - --theme-syntax-variable: #59c2ff; - --theme-syntax-string: #aad94c; - --theme-syntax-number: #d2a6ff; - --theme-syntax-type: #e6b673; - --theme-syntax-operator: #f29668; - --theme-syntax-punctuation: #bfbdb6; + --theme-markdown-text: #BFBDB6; + --theme-markdown-heading: #D2A6FF; + --theme-markdown-link: #59C2FF; + --theme-markdown-link-text: #39BAE6; + --theme-markdown-code: #AAD94C; + --theme-markdown-block-quote: #E6B673; + --theme-markdown-emph: #E6B673; + --theme-markdown-strong: #FFB454; + --theme-markdown-horizontal-rule: #565B66; + --theme-markdown-list-item: #59C2FF; + --theme-markdown-list-enumeration: #39BAE6; + --theme-markdown-image: #59C2FF; + --theme-markdown-image-text: #39BAE6; + --theme-markdown-code-block: #BFBDB6; + --theme-syntax-comment: #ACB6BF; + --theme-syntax-keyword: #FF8F40; + --theme-syntax-function: #FFB454; + --theme-syntax-variable: #59C2FF; + --theme-syntax-string: #AAD94C; + --theme-syntax-number: #D2A6FF; + --theme-syntax-type: #E6B673; + --theme-syntax-operator: #F29668; + --theme-syntax-punctuation: #BFBDB6; } [data-theme="ayu"][data-dark="true"] { - --theme-primary: #59c2ff; - --theme-secondary: #d2a6ff; - --theme-accent: #e6b450; - --theme-error: #d95757; - --theme-warning: #e6b673; - --theme-success: #7fd962; - --theme-info: #39bae6; - --theme-text: #bfbdb6; - --theme-text-muted: #565b66; - --theme-background: #0b0e14; - --theme-background-panel: #0f131a; - --theme-background-element: #0d1017; - --theme-border: #6c7380; - --theme-border-active: #6c7380; - --theme-border-subtle: #11151c; - --theme-diff-added: #7fd962; - --theme-diff-removed: #f26d78; - --theme-diff-context: #acb6bf; - --theme-diff-hunk-header: #acb6bf; - --theme-diff-highlight-added: #aad94c; - --theme-diff-highlight-removed: #f07178; + --theme-primary: #59C2FF; + --theme-secondary: #D2A6FF; + --theme-accent: #E6B450; + --theme-error: #D95757; + --theme-warning: #E6B673; + --theme-success: #7FD962; + --theme-info: #39BAE6; + --theme-text: #BFBDB6; + --theme-text-muted: #565B66; + --theme-background: #0B0E14; + --theme-background-panel: #0F131A; + --theme-background-element: #0D1017; + --theme-border: #6C7380; + --theme-border-active: #6C7380; + --theme-border-subtle: #11151C; + --theme-diff-added: #7FD962; + --theme-diff-removed: #F26D78; + --theme-diff-context: #ACB6BF; + --theme-diff-hunk-header: #ACB6BF; + --theme-diff-highlight-added: #AAD94C; + --theme-diff-highlight-removed: #F07178; --theme-diff-added-bg: #20303b; --theme-diff-removed-bg: #37222c; - --theme-diff-context-bg: #0f131a; - --theme-diff-line-number: #6c7380; + --theme-diff-context-bg: #0F131A; + --theme-diff-line-number: #6C7380; --theme-diff-added-line-number-bg: #1b2b34; --theme-diff-removed-line-number-bg: #2d1f26; - --theme-markdown-text: #bfbdb6; - --theme-markdown-heading: #d2a6ff; - --theme-markdown-link: #59c2ff; - --theme-markdown-link-text: #39bae6; - --theme-markdown-code: #aad94c; - --theme-markdown-block-quote: #e6b673; - --theme-markdown-emph: #e6b673; - --theme-markdown-strong: #ffb454; - --theme-markdown-horizontal-rule: #565b66; - --theme-markdown-list-item: #59c2ff; - --theme-markdown-list-enumeration: #39bae6; - --theme-markdown-image: #59c2ff; - --theme-markdown-image-text: #39bae6; - --theme-markdown-code-block: #bfbdb6; - --theme-syntax-comment: #acb6bf; - --theme-syntax-keyword: #ff8f40; - --theme-syntax-function: #ffb454; - --theme-syntax-variable: #59c2ff; - --theme-syntax-string: #aad94c; - --theme-syntax-number: #d2a6ff; - --theme-syntax-type: #e6b673; - --theme-syntax-operator: #f29668; - --theme-syntax-punctuation: #bfbdb6; + --theme-markdown-text: #BFBDB6; + --theme-markdown-heading: #D2A6FF; + --theme-markdown-link: #59C2FF; + --theme-markdown-link-text: #39BAE6; + --theme-markdown-code: #AAD94C; + --theme-markdown-block-quote: #E6B673; + --theme-markdown-emph: #E6B673; + --theme-markdown-strong: #FFB454; + --theme-markdown-horizontal-rule: #565B66; + --theme-markdown-list-item: #59C2FF; + --theme-markdown-list-enumeration: #39BAE6; + --theme-markdown-image: #59C2FF; + --theme-markdown-image-text: #39BAE6; + --theme-markdown-code-block: #BFBDB6; + --theme-syntax-comment: #ACB6BF; + --theme-syntax-keyword: #FF8F40; + --theme-syntax-function: #FFB454; + --theme-syntax-variable: #59C2FF; + --theme-syntax-string: #AAD94C; + --theme-syntax-number: #D2A6FF; + --theme-syntax-type: #E6B673; + --theme-syntax-operator: #F29668; + --theme-syntax-punctuation: #BFBDB6; } [data-theme="catppuccin"][data-dark="false"] { @@ -901,109 +901,109 @@ } [data-theme="kanagawa"][data-dark="false"] { - --theme-primary: #2d4f67; - --theme-secondary: #957fb8; - --theme-accent: #d27e99; - --theme-error: #e82424; - --theme-warning: #d7a657; - --theme-success: #98bb6c; - --theme-info: #76946a; - --theme-text: #54433a; - --theme-text-muted: #9e9389; - --theme-background: #f2e9de; - --theme-background-panel: #eae4d7; - --theme-background-element: #e3dcd2; - --theme-border: #d4cbbf; - --theme-border-active: #c38d9d; - --theme-border-subtle: #dcd4c9; - --theme-diff-added: #98bb6c; - --theme-diff-removed: #e82424; - --theme-diff-context: #9e9389; - --theme-diff-hunk-header: #2d4f67; - --theme-diff-highlight-added: #89af5b; - --theme-diff-highlight-removed: #d61f1f; - --theme-diff-added-bg: #eaf3e4; - --theme-diff-removed-bg: #fbe6e6; - --theme-diff-context-bg: #eae4d7; - --theme-diff-line-number: #c7beb4; - --theme-diff-added-line-number-bg: #dde8d6; - --theme-diff-removed-line-number-bg: #f2dada; - --theme-markdown-text: #54433a; - --theme-markdown-heading: #957fb8; - --theme-markdown-link: #2d4f67; - --theme-markdown-link-text: #76946a; - --theme-markdown-code: #98bb6c; - --theme-markdown-block-quote: #9e9389; - --theme-markdown-emph: #c38d9d; - --theme-markdown-strong: #d7a657; - --theme-markdown-horizontal-rule: #9e9389; - --theme-markdown-list-item: #2d4f67; - --theme-markdown-list-enumeration: #76946a; - --theme-markdown-image: #2d4f67; - --theme-markdown-image-text: #76946a; - --theme-markdown-code-block: #54433a; - --theme-syntax-comment: #9e9389; - --theme-syntax-keyword: #957fb8; - --theme-syntax-function: #2d4f67; - --theme-syntax-variable: #54433a; - --theme-syntax-string: #98bb6c; - --theme-syntax-number: #d7a657; - --theme-syntax-type: #c38d9d; - --theme-syntax-operator: #d27e99; - --theme-syntax-punctuation: #54433a; + --theme-primary: #2D4F67; + --theme-secondary: #957FB8; + --theme-accent: #D27E99; + --theme-error: #E82424; + --theme-warning: #D7A657; + --theme-success: #98BB6C; + --theme-info: #76946A; + --theme-text: #54433A; + --theme-text-muted: #9E9389; + --theme-background: #F2E9DE; + --theme-background-panel: #EAE4D7; + --theme-background-element: #E3DCD2; + --theme-border: #D4CBBF; + --theme-border-active: #C38D9D; + --theme-border-subtle: #DCD4C9; + --theme-diff-added: #98BB6C; + --theme-diff-removed: #E82424; + --theme-diff-context: #9E9389; + --theme-diff-hunk-header: #2D4F67; + --theme-diff-highlight-added: #89AF5B; + --theme-diff-highlight-removed: #D61F1F; + --theme-diff-added-bg: #EAF3E4; + --theme-diff-removed-bg: #FBE6E6; + --theme-diff-context-bg: #EAE4D7; + --theme-diff-line-number: #C7BEB4; + --theme-diff-added-line-number-bg: #DDE8D6; + --theme-diff-removed-line-number-bg: #F2DADA; + --theme-markdown-text: #54433A; + --theme-markdown-heading: #957FB8; + --theme-markdown-link: #2D4F67; + --theme-markdown-link-text: #76946A; + --theme-markdown-code: #98BB6C; + --theme-markdown-block-quote: #9E9389; + --theme-markdown-emph: #C38D9D; + --theme-markdown-strong: #D7A657; + --theme-markdown-horizontal-rule: #9E9389; + --theme-markdown-list-item: #2D4F67; + --theme-markdown-list-enumeration: #76946A; + --theme-markdown-image: #2D4F67; + --theme-markdown-image-text: #76946A; + --theme-markdown-code-block: #54433A; + --theme-syntax-comment: #9E9389; + --theme-syntax-keyword: #957FB8; + --theme-syntax-function: #2D4F67; + --theme-syntax-variable: #54433A; + --theme-syntax-string: #98BB6C; + --theme-syntax-number: #D7A657; + --theme-syntax-type: #C38D9D; + --theme-syntax-operator: #D27E99; + --theme-syntax-punctuation: #54433A; } [data-theme="kanagawa"][data-dark="true"] { - --theme-primary: #7e9cd8; - --theme-secondary: #957fb8; - --theme-accent: #d27e99; - --theme-error: #e82424; - --theme-warning: #d7a657; - --theme-success: #98bb6c; - --theme-info: #76946a; - --theme-text: #dcd7ba; + --theme-primary: #7E9CD8; + --theme-secondary: #957FB8; + --theme-accent: #D27E99; + --theme-error: #E82424; + --theme-warning: #D7A657; + --theme-success: #98BB6C; + --theme-info: #76946A; + --theme-text: #DCD7BA; --theme-text-muted: #727169; - --theme-background: #1f1f28; - --theme-background-panel: #2a2a37; + --theme-background: #1F1F28; + --theme-background-panel: #2A2A37; --theme-background-element: #363646; - --theme-border: #54546d; - --theme-border-active: #c38d9d; + --theme-border: #54546D; + --theme-border-active: #C38D9D; --theme-border-subtle: #363646; - --theme-diff-added: #98bb6c; - --theme-diff-removed: #e82424; + --theme-diff-added: #98BB6C; + --theme-diff-removed: #E82424; --theme-diff-context: #727169; - --theme-diff-hunk-header: #2d4f67; - --theme-diff-highlight-added: #a9d977; - --theme-diff-highlight-removed: #f24a4a; - --theme-diff-added-bg: #252e25; + --theme-diff-hunk-header: #2D4F67; + --theme-diff-highlight-added: #A9D977; + --theme-diff-highlight-removed: #F24A4A; + --theme-diff-added-bg: #252E25; --theme-diff-removed-bg: #362020; - --theme-diff-context-bg: #2a2a37; - --theme-diff-line-number: #54546d; + --theme-diff-context-bg: #2A2A37; + --theme-diff-line-number: #54546D; --theme-diff-added-line-number-bg: #202820; - --theme-diff-removed-line-number-bg: #2d1c1c; - --theme-markdown-text: #dcd7ba; - --theme-markdown-heading: #957fb8; - --theme-markdown-link: #7e9cd8; - --theme-markdown-link-text: #76946a; - --theme-markdown-code: #98bb6c; + --theme-diff-removed-line-number-bg: #2D1C1C; + --theme-markdown-text: #DCD7BA; + --theme-markdown-heading: #957FB8; + --theme-markdown-link: #7E9CD8; + --theme-markdown-link-text: #76946A; + --theme-markdown-code: #98BB6C; --theme-markdown-block-quote: #727169; - --theme-markdown-emph: #c38d9d; - --theme-markdown-strong: #d7a657; + --theme-markdown-emph: #C38D9D; + --theme-markdown-strong: #D7A657; --theme-markdown-horizontal-rule: #727169; - --theme-markdown-list-item: #7e9cd8; - --theme-markdown-list-enumeration: #76946a; - --theme-markdown-image: #7e9cd8; - --theme-markdown-image-text: #76946a; - --theme-markdown-code-block: #dcd7ba; + --theme-markdown-list-item: #7E9CD8; + --theme-markdown-list-enumeration: #76946A; + --theme-markdown-image: #7E9CD8; + --theme-markdown-image-text: #76946A; + --theme-markdown-code-block: #DCD7BA; --theme-syntax-comment: #727169; - --theme-syntax-keyword: #957fb8; - --theme-syntax-function: #7e9cd8; - --theme-syntax-variable: #dcd7ba; - --theme-syntax-string: #98bb6c; - --theme-syntax-number: #d7a657; - --theme-syntax-type: #c38d9d; - --theme-syntax-operator: #d27e99; - --theme-syntax-punctuation: #dcd7ba; + --theme-syntax-keyword: #957FB8; + --theme-syntax-function: #7E9CD8; + --theme-syntax-variable: #DCD7BA; + --theme-syntax-string: #98BB6C; + --theme-syntax-number: #D7A657; + --theme-syntax-type: #C38D9D; + --theme-syntax-operator: #D27E99; + --theme-syntax-punctuation: #DCD7BA; } [data-theme="material"][data-dark="false"] { @@ -1325,109 +1325,109 @@ } [data-theme="nord"][data-dark="false"] { - --theme-primary: #5e81ac; - --theme-secondary: #81a1c1; - --theme-accent: #8fbcbb; - --theme-error: #bf616a; - --theme-warning: #d08770; - --theme-success: #a3be8c; - --theme-info: #5e81ac; - --theme-text: #2e3440; - --theme-text-muted: #3b4252; - --theme-background: #eceff4; - --theme-background-panel: #e5e9f0; - --theme-background-element: #d8dee9; - --theme-border: #4c566a; - --theme-border-active: #434c5e; - --theme-border-subtle: #4c566a; - --theme-diff-added: #a3be8c; - --theme-diff-removed: #bf616a; - --theme-diff-context: #4c566a; - --theme-diff-hunk-header: #4c566a; - --theme-diff-highlight-added: #a3be8c; - --theme-diff-highlight-removed: #bf616a; - --theme-diff-added-bg: #e5e9f0; - --theme-diff-removed-bg: #e5e9f0; - --theme-diff-context-bg: #e5e9f0; - --theme-diff-line-number: #d8dee9; - --theme-diff-added-line-number-bg: #e5e9f0; - --theme-diff-removed-line-number-bg: #e5e9f0; - --theme-markdown-text: #2e3440; - --theme-markdown-heading: #5e81ac; - --theme-markdown-link: #81a1c1; - --theme-markdown-link-text: #8fbcbb; - --theme-markdown-code: #a3be8c; - --theme-markdown-block-quote: #4c566a; - --theme-markdown-emph: #d08770; - --theme-markdown-strong: #ebcb8b; - --theme-markdown-horizontal-rule: #4c566a; - --theme-markdown-list-item: #5e81ac; - --theme-markdown-list-enumeration: #8fbcbb; - --theme-markdown-image: #81a1c1; - --theme-markdown-image-text: #8fbcbb; - --theme-markdown-code-block: #2e3440; - --theme-syntax-comment: #4c566a; - --theme-syntax-keyword: #81a1c1; - --theme-syntax-function: #88c0d0; - --theme-syntax-variable: #8fbcbb; - --theme-syntax-string: #a3be8c; - --theme-syntax-number: #b48ead; - --theme-syntax-type: #8fbcbb; - --theme-syntax-operator: #81a1c1; - --theme-syntax-punctuation: #2e3440; + --theme-primary: #5E81AC; + --theme-secondary: #81A1C1; + --theme-accent: #8FBCBB; + --theme-error: #BF616A; + --theme-warning: #D08770; + --theme-success: #A3BE8C; + --theme-info: #5E81AC; + --theme-text: #2E3440; + --theme-text-muted: #3B4252; + --theme-background: #ECEFF4; + --theme-background-panel: #E5E9F0; + --theme-background-element: #D8DEE9; + --theme-border: #4C566A; + --theme-border-active: #434C5E; + --theme-border-subtle: #4C566A; + --theme-diff-added: #A3BE8C; + --theme-diff-removed: #BF616A; + --theme-diff-context: #4C566A; + --theme-diff-hunk-header: #4C566A; + --theme-diff-highlight-added: #A3BE8C; + --theme-diff-highlight-removed: #BF616A; + --theme-diff-added-bg: #E5E9F0; + --theme-diff-removed-bg: #E5E9F0; + --theme-diff-context-bg: #E5E9F0; + --theme-diff-line-number: #D8DEE9; + --theme-diff-added-line-number-bg: #E5E9F0; + --theme-diff-removed-line-number-bg: #E5E9F0; + --theme-markdown-text: #2E3440; + --theme-markdown-heading: #5E81AC; + --theme-markdown-link: #81A1C1; + --theme-markdown-link-text: #8FBCBB; + --theme-markdown-code: #A3BE8C; + --theme-markdown-block-quote: #4C566A; + --theme-markdown-emph: #D08770; + --theme-markdown-strong: #EBCB8B; + --theme-markdown-horizontal-rule: #4C566A; + --theme-markdown-list-item: #5E81AC; + --theme-markdown-list-enumeration: #8FBCBB; + --theme-markdown-image: #81A1C1; + --theme-markdown-image-text: #8FBCBB; + --theme-markdown-code-block: #2E3440; + --theme-syntax-comment: #4C566A; + --theme-syntax-keyword: #81A1C1; + --theme-syntax-function: #88C0D0; + --theme-syntax-variable: #8FBCBB; + --theme-syntax-string: #A3BE8C; + --theme-syntax-number: #B48EAD; + --theme-syntax-type: #8FBCBB; + --theme-syntax-operator: #81A1C1; + --theme-syntax-punctuation: #2E3440; } [data-theme="nord"][data-dark="true"] { - --theme-primary: #88c0d0; - --theme-secondary: #81a1c1; - --theme-accent: #8fbcbb; - --theme-error: #bf616a; - --theme-warning: #d08770; - --theme-success: #a3be8c; - --theme-info: #88c0d0; - --theme-text: #eceff4; - --theme-text-muted: #8b95a7; - --theme-background: #2e3440; - --theme-background-panel: #3b4252; - --theme-background-element: #434c5e; - --theme-border: #434c5e; - --theme-border-active: #4c566a; - --theme-border-subtle: #434c5e; - --theme-diff-added: #a3be8c; - --theme-diff-removed: #bf616a; - --theme-diff-context: #8b95a7; - --theme-diff-hunk-header: #8b95a7; - --theme-diff-highlight-added: #a3be8c; - --theme-diff-highlight-removed: #bf616a; - --theme-diff-added-bg: #3b4252; - --theme-diff-removed-bg: #3b4252; - --theme-diff-context-bg: #3b4252; - --theme-diff-line-number: #434c5e; - --theme-diff-added-line-number-bg: #3b4252; - --theme-diff-removed-line-number-bg: #3b4252; - --theme-markdown-text: #d8dee9; - --theme-markdown-heading: #88c0d0; - --theme-markdown-link: #81a1c1; - --theme-markdown-link-text: #8fbcbb; - --theme-markdown-code: #a3be8c; - --theme-markdown-block-quote: #8b95a7; - --theme-markdown-emph: #d08770; - --theme-markdown-strong: #ebcb8b; - --theme-markdown-horizontal-rule: #8b95a7; - --theme-markdown-list-item: #88c0d0; - --theme-markdown-list-enumeration: #8fbcbb; - --theme-markdown-image: #81a1c1; - --theme-markdown-image-text: #8fbcbb; - --theme-markdown-code-block: #d8dee9; - --theme-syntax-comment: #8b95a7; - --theme-syntax-keyword: #81a1c1; - --theme-syntax-function: #88c0d0; - --theme-syntax-variable: #8fbcbb; - --theme-syntax-string: #a3be8c; - --theme-syntax-number: #b48ead; - --theme-syntax-type: #8fbcbb; - --theme-syntax-operator: #81a1c1; - --theme-syntax-punctuation: #d8dee9; + --theme-primary: #88C0D0; + --theme-secondary: #81A1C1; + --theme-accent: #8FBCBB; + --theme-error: #BF616A; + --theme-warning: #D08770; + --theme-success: #A3BE8C; + --theme-info: #88C0D0; + --theme-text: #ECEFF4; + --theme-text-muted: #8B95A7; + --theme-background: #2E3440; + --theme-background-panel: #3B4252; + --theme-background-element: #434C5E; + --theme-border: #434C5E; + --theme-border-active: #4C566A; + --theme-border-subtle: #434C5E; + --theme-diff-added: #A3BE8C; + --theme-diff-removed: #BF616A; + --theme-diff-context: #8B95A7; + --theme-diff-hunk-header: #8B95A7; + --theme-diff-highlight-added: #A3BE8C; + --theme-diff-highlight-removed: #BF616A; + --theme-diff-added-bg: #3B4252; + --theme-diff-removed-bg: #3B4252; + --theme-diff-context-bg: #3B4252; + --theme-diff-line-number: #434C5E; + --theme-diff-added-line-number-bg: #3B4252; + --theme-diff-removed-line-number-bg: #3B4252; + --theme-markdown-text: #D8DEE9; + --theme-markdown-heading: #88C0D0; + --theme-markdown-link: #81A1C1; + --theme-markdown-link-text: #8FBCBB; + --theme-markdown-code: #A3BE8C; + --theme-markdown-block-quote: #8B95A7; + --theme-markdown-emph: #D08770; + --theme-markdown-strong: #EBCB8B; + --theme-markdown-horizontal-rule: #8B95A7; + --theme-markdown-list-item: #88C0D0; + --theme-markdown-list-enumeration: #8FBCBB; + --theme-markdown-image: #81A1C1; + --theme-markdown-image-text: #8FBCBB; + --theme-markdown-code-block: #D8DEE9; + --theme-syntax-comment: #8B95A7; + --theme-syntax-keyword: #81A1C1; + --theme-syntax-function: #88C0D0; + --theme-syntax-variable: #8FBCBB; + --theme-syntax-string: #A3BE8C; + --theme-syntax-number: #B48EAD; + --theme-syntax-type: #8FBCBB; + --theme-syntax-operator: #81A1C1; + --theme-syntax-punctuation: #D8DEE9; } [data-theme="one-dark"][data-dark="false"] { @@ -2173,109 +2173,109 @@ } [data-theme="vesper"][data-dark="false"] { - --theme-primary: #ffc799; - --theme-secondary: #99ffe4; - --theme-accent: #ffc799; - --theme-error: #ff8080; - --theme-warning: #ffc799; - --theme-success: #99ffe4; - --theme-info: #ffc799; + --theme-primary: #FFC799; + --theme-secondary: #99FFE4; + --theme-accent: #FFC799; + --theme-error: #FF8080; + --theme-warning: #FFC799; + --theme-success: #99FFE4; + --theme-info: #FFC799; --theme-text: #101010; - --theme-text-muted: #a0a0a0; - --theme-background: #fff; - --theme-background-panel: #f0f0f0; - --theme-background-element: #e0e0e0; - --theme-border: #d0d0d0; - --theme-border-active: #ffc799; - --theme-border-subtle: #e8e8e8; - --theme-diff-added: #99ffe4; - --theme-diff-removed: #ff8080; - --theme-diff-context: #a0a0a0; - --theme-diff-hunk-header: #a0a0a0; - --theme-diff-highlight-added: #99ffe4; - --theme-diff-highlight-removed: #ff8080; + --theme-text-muted: #A0A0A0; + --theme-background: #FFF; + --theme-background-panel: #F0F0F0; + --theme-background-element: #E0E0E0; + --theme-border: #D0D0D0; + --theme-border-active: #FFC799; + --theme-border-subtle: #E8E8E8; + --theme-diff-added: #99FFE4; + --theme-diff-removed: #FF8080; + --theme-diff-context: #A0A0A0; + --theme-diff-hunk-header: #A0A0A0; + --theme-diff-highlight-added: #99FFE4; + --theme-diff-highlight-removed: #FF8080; --theme-diff-added-bg: #e8f5e8; --theme-diff-removed-bg: #f5e8e8; - --theme-diff-context-bg: #f8f8f8; + --theme-diff-context-bg: #F8F8F8; --theme-diff-line-number: #808080; --theme-diff-added-line-number-bg: #e8f5e8; --theme-diff-removed-line-number-bg: #f5e8e8; --theme-markdown-text: #101010; - --theme-markdown-heading: #ffc799; - --theme-markdown-link: #ffc799; - --theme-markdown-link-text: #a0a0a0; - --theme-markdown-code: #a0a0a0; + --theme-markdown-heading: #FFC799; + --theme-markdown-link: #FFC799; + --theme-markdown-link-text: #A0A0A0; + --theme-markdown-code: #A0A0A0; --theme-markdown-block-quote: #101010; --theme-markdown-emph: #101010; --theme-markdown-strong: #101010; - --theme-markdown-horizontal-rule: #65737e; + --theme-markdown-horizontal-rule: #65737E; --theme-markdown-list-item: #101010; --theme-markdown-list-enumeration: #101010; - --theme-markdown-image: #ffc799; - --theme-markdown-image-text: #a0a0a0; + --theme-markdown-image: #FFC799; + --theme-markdown-image-text: #A0A0A0; --theme-markdown-code-block: #101010; --theme-syntax-comment: #8b8b8b94; - --theme-syntax-keyword: #a0a0a0; - --theme-syntax-function: #ffc799; + --theme-syntax-keyword: #A0A0A0; + --theme-syntax-function: #FFC799; --theme-syntax-variable: #101010; - --theme-syntax-string: #99ffe4; - --theme-syntax-number: #ffc799; - --theme-syntax-type: #ffc799; - --theme-syntax-operator: #a0a0a0; + --theme-syntax-string: #99FFE4; + --theme-syntax-number: #FFC799; + --theme-syntax-type: #FFC799; + --theme-syntax-operator: #A0A0A0; --theme-syntax-punctuation: #101010; } [data-theme="vesper"][data-dark="true"] { - --theme-primary: #ffc799; - --theme-secondary: #99ffe4; - --theme-accent: #ffc799; - --theme-error: #ff8080; - --theme-warning: #ffc799; - --theme-success: #99ffe4; - --theme-info: #ffc799; - --theme-text: #fff; - --theme-text-muted: #a0a0a0; + --theme-primary: #FFC799; + --theme-secondary: #99FFE4; + --theme-accent: #FFC799; + --theme-error: #FF8080; + --theme-warning: #FFC799; + --theme-success: #99FFE4; + --theme-info: #FFC799; + --theme-text: #FFF; + --theme-text-muted: #A0A0A0; --theme-background: #101010; --theme-background-panel: #101010; --theme-background-element: #101010; --theme-border: #282828; - --theme-border-active: #ffc799; - --theme-border-subtle: #1c1c1c; - --theme-diff-added: #99ffe4; - --theme-diff-removed: #ff8080; - --theme-diff-context: #a0a0a0; - --theme-diff-hunk-header: #a0a0a0; - --theme-diff-highlight-added: #99ffe4; - --theme-diff-highlight-removed: #ff8080; + --theme-border-active: #FFC799; + --theme-border-subtle: #1C1C1C; + --theme-diff-added: #99FFE4; + --theme-diff-removed: #FF8080; + --theme-diff-context: #A0A0A0; + --theme-diff-hunk-header: #A0A0A0; + --theme-diff-highlight-added: #99FFE4; + --theme-diff-highlight-removed: #FF8080; --theme-diff-added-bg: #0d2818; --theme-diff-removed-bg: #281a1a; --theme-diff-context-bg: #101010; --theme-diff-line-number: #505050; --theme-diff-added-line-number-bg: #0d2818; --theme-diff-removed-line-number-bg: #281a1a; - --theme-markdown-text: #fff; - --theme-markdown-heading: #ffc799; - --theme-markdown-link: #ffc799; - --theme-markdown-link-text: #a0a0a0; - --theme-markdown-code: #a0a0a0; - --theme-markdown-block-quote: #fff; - --theme-markdown-emph: #fff; - --theme-markdown-strong: #fff; - --theme-markdown-horizontal-rule: #65737e; - --theme-markdown-list-item: #fff; - --theme-markdown-list-enumeration: #fff; - --theme-markdown-image: #ffc799; - --theme-markdown-image-text: #a0a0a0; - --theme-markdown-code-block: #fff; + --theme-markdown-text: #FFF; + --theme-markdown-heading: #FFC799; + --theme-markdown-link: #FFC799; + --theme-markdown-link-text: #A0A0A0; + --theme-markdown-code: #A0A0A0; + --theme-markdown-block-quote: #FFF; + --theme-markdown-emph: #FFF; + --theme-markdown-strong: #FFF; + --theme-markdown-horizontal-rule: #65737E; + --theme-markdown-list-item: #FFF; + --theme-markdown-list-enumeration: #FFF; + --theme-markdown-image: #FFC799; + --theme-markdown-image-text: #A0A0A0; + --theme-markdown-code-block: #FFF; --theme-syntax-comment: #8b8b8b94; - --theme-syntax-keyword: #a0a0a0; - --theme-syntax-function: #ffc799; - --theme-syntax-variable: #fff; - --theme-syntax-string: #99ffe4; - --theme-syntax-number: #ffc799; - --theme-syntax-type: #ffc799; - --theme-syntax-operator: #a0a0a0; - --theme-syntax-punctuation: #fff; + --theme-syntax-keyword: #A0A0A0; + --theme-syntax-function: #FFC799; + --theme-syntax-variable: #FFF; + --theme-syntax-string: #99FFE4; + --theme-syntax-number: #FFC799; + --theme-syntax-type: #FFC799; + --theme-syntax-operator: #A0A0A0; + --theme-syntax-punctuation: #FFF; } [data-theme="zenburn"][data-dark="false"] { @@ -2383,3 +2383,4 @@ --theme-syntax-operator: #f0dfaf; --theme-syntax-punctuation: #dcdccc; } + diff --git a/packages/app/src/components/select.tsx b/packages/app/src/components/select.tsx new file mode 100644 index 00000000..6849f90f --- /dev/null +++ b/packages/app/src/components/select.tsx @@ -0,0 +1,184 @@ +import { Select as KobalteSelect } from "@kobalte/core/select" +import { createEffect, createMemo } from "solid-js" +import type { ComponentProps } from "solid-js" +import { Icon } from "@/ui/icon" +import fuzzysort from "fuzzysort" +import { pipe, groupBy, entries, map } from "remeda" +import { createStore } from "solid-js/store" + +export interface SelectProps { + variant?: "default" | "outline" + size?: "sm" | "md" | "lg" + placeholder?: string + options: T[] + current?: T + value?: (x: T) => string + label?: (x: T) => string + groupBy?: (x: T) => string + filterKeys: string[] + onFilter?: (query: string) => void + onSelect?: (value: T | undefined) => void + class?: ComponentProps<"div">["class"] + classList?: ComponentProps<"div">["classList"] +} + +export function Select(props: SelectProps) { + let inputRef: HTMLInputElement | undefined = undefined + let listboxRef: HTMLUListElement | undefined = undefined + let contentRef: HTMLDivElement | undefined = undefined + const [store, setStore] = createStore({ + filter: "", + }) + const grouped = createMemo(() => { + const needle = store.filter.toLowerCase() + const result = pipe( + props.options, + (x) => (!needle ? x : fuzzysort.go(needle, x, { keys: props.filterKeys }).map((x) => x.obj)), + groupBy((x) => (props.groupBy ? props.groupBy(x) : "")), + // mapValues((x) => x.sort((a, b) => a.title.localeCompare(b.title))), + entries(), + map(([k, v]) => ({ category: k, options: v })), + ) + return result + }) + // const flat = createMemo(() => { + // return pipe( + // grouped(), + // flatMap(({ options }) => options), + // ) + // }) + + createEffect(() => { + store.filter + listboxRef?.scrollTo(0, 0) + // setStore("selected", 0) + // scroll.scrollTo(0) + }) + + return ( + + allowDuplicateSelectionEvents={false} + disallowEmptySelection={true} + closeOnSelection={false} + value={props.current} + options={grouped()} + optionValue={(x) => (props.value ? props.value(x) : (x as string))} + optionTextValue={(x) => (props.label ? props.label(x) : (x as string))} + optionGroupChildren="options" + placeholder={props.placeholder} + sectionComponent={(props) => ( + + {props.section.rawValue.category} + + )} + itemComponent={(itemProps) => ( + + + {props.label ? props.label(itemProps.item.rawValue) : (itemProps.item.rawValue as string)} + + + + + + )} + onChange={(v) => { + if (props.onSelect) props.onSelect(v ?? undefined) + if (v !== null) { + // close the select + } + }} + onOpenChange={(v) => v || setStore("filter", "")} + > + + > + {(state) => { + const selected = state.selectedOption() ?? props.current + if (!selected) return props.placeholder || "" + if (props.label) return props.label(selected) + return selected as string + }} + + + + + + + (contentRef = el)} + onKeyDown={(e) => { + if (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Escape") { + return + } + inputRef?.focus() + }} + classList={{ + "min-w-32 overflow-hidden rounded-md border border-border-subtle/40": true, + "bg-background-panel p-1 shadow-md z-50": true, + "data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:zoom-out-95": true, + "data-[expanded]:animate-in data-[expanded]:fade-in-0 data-[expanded]:zoom-in-95": true, + }} + > +
+ (inputRef = el)} + id="select-filter" + type="text" + placeholder="Filter models" + value={store.filter} + onInput={(e) => setStore("filter", e.currentTarget.value)} + onKeyDown={(e) => { + if (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Escape") { + e.preventDefault() + e.stopPropagation() + listboxRef?.focus() + } + }} + classList={{ + "w-full": true, + "px-2 pb-2 text-text font-light placeholder-text-muted/70 text-xs focus:outline-none": true, + }} + /> +
+ (listboxRef = el)} + classList={{ + "overflow-y-auto max-h-48 no-scrollbar": true, + }} + /> +
+
+ + ) +} diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx index 161166ba..eff15264 100644 --- a/packages/app/src/context/local.tsx +++ b/packages/app/src/context/local.tsx @@ -24,22 +24,26 @@ function init() { const sdk = useSDK() const sync = useSync() - const agents = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent")) + const list = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent")) const agent = (() => { const [store, setStore] = createStore<{ current: string }>({ - current: agents()[0].name, + current: list()[0].name, }) return { + list, current() { - return agents().find((x) => x.name === store.current)! + return list().find((x) => x.name === store.current)! + }, + set(name: string | undefined) { + setStore("current", name ?? list()[0].name) }, move(direction: 1 | -1) { - let next = agents().findIndex((x) => x.name === store.current) + direction - if (next < 0) next = agents().length - 1 - if (next >= agents().length) next = 0 - const value = agents()[next] + let next = list().findIndex((x) => x.name === store.current) + direction + if (next < 0) next = list().length - 1 + if (next >= list().length) next = 0 + const value = list()[next] setStore("current", value.name) if (value.model) model.set({ @@ -89,7 +93,12 @@ function init() { return store.model[agent.current().name] ?? (a.model ? a.model : fallback()) }) + const list = createMemo(() => + sync.data.provider.flatMap((x) => Object.values(x.models).map((m) => ({ providerID: x.id, modelID: m.id }))), + ) + return { + list, current, recent() { return store.recent @@ -103,10 +112,10 @@ function init() { model: model.name ?? value.modelID, } }), - set(model: { providerID: string; modelID: string }, options?: { recent?: boolean }) { + set(model: { providerID: string; modelID: string } | undefined, options?: { recent?: boolean }) { batch(() => { - setStore("model", agent.current().name, model) - if (options?.recent) { + setStore("model", agent.current().name, model ?? fallback()) + if (options?.recent && model) { const uniq = uniqueBy([model, ...store.recent], (x) => x.providerID + x.modelID) if (uniq.length > 5) uniq.pop() setStore("recent", uniq) diff --git a/packages/app/src/pages/index.tsx b/packages/app/src/pages/index.tsx index 11ea3163..e8d4664a 100644 --- a/packages/app/src/pages/index.tsx +++ b/packages/app/src/pages/index.tsx @@ -1,5 +1,6 @@ import { FileIcon, Icon, IconButton, Logo, Tooltip } from "@/ui" import { Tabs } from "@/ui/tabs" +import { Select } from "@/components/select" import FileTree from "@/components/file-tree" import { createSignal, For, Match, onCleanup, onMount, Show, Switch } from "solid-js" import { useLocal, useSDK } from "@/context" @@ -51,6 +52,10 @@ export default function Page() { return } + if (document.activeElement?.id === "select-filter") { + return + } + if (local.file.active()) { if (e.getModifierState(MOD)) { if (e.key.toLowerCase() === "a") { @@ -228,10 +233,10 @@ export default function Page() {
- + Files - + Changes @@ -256,7 +261,7 @@ export default function Page() { /> -
No changes yet
+
No changes yet
@@ -493,11 +498,28 @@ export default function Page() { placeholder="It all starts with a prompt..." class="w-full p-1 pb-4 text-text font-light placeholder-text-muted/70 text-sm focus:outline-none" /> -
- - {local.agent.current()?.name ?? "unknown"} /{" "} - {local.model.parsed().provider} / {local.model.parsed().model} - +
+
+ x.modelID} + value={(x) => `${x.providerID}.${x.modelID}`} + filterKeys={["providerID", "modelID"]} + groupBy={(x) => x.providerID} + size="sm" + class="uppercase" + /> + {local.model.parsed().provider} +
diff --git a/packages/web/package.json b/packages/web/package.json index dff76b3a..fa693e7f 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -23,11 +23,11 @@ "diff": "8.0.2", "js-base64": "3.7.7", "lang-map": "0.4.0", - "luxon": "3.6.1", + "luxon": "catalog:", "marked": "15.0.12", "marked-shiki": "1.2.1", "rehype-autolink-headings": "7.1.0", - "remeda": "2.26.0", + "remeda": "catalog:", "sharp": "0.32.5", "shiki": "3.4.2", "solid-js": "catalog:",