feat: searchable multi-select with all 217 panproto languages for repo creation
Author: Aaron Steven White
Commit
78cf24bca91f3d7456d842e45306390f1279506aParent: 8769703583
Structural diff unavailable
These commits were pushed via plain git push, so no pre-parsed
schemas are available. Install git-remote-cospan and re-push via panproto:// to
see scope-level changes, breaking change detection, and semantic diffs.
brew install panproto/tap/git-remote-cospan3 files changed +314 -32
@@ -436,7 +436,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
436436 437437 [[package]] 438438 name = "cospan-appview" 439-version = "0.3.0" 439+version = "0.3.1" 440440 dependencies = [ 441441 "anyhow", 442442 "async-trait",
@@ -479,7 +479,7 @@ dependencies = [
479479 480480 [[package]] 481481 name = "cospan-codegen" 482-version = "0.3.0" 482+version = "0.3.1" 483483 dependencies = [ 484484 "anyhow", 485485 "panproto-core",
@@ -493,7 +493,7 @@ dependencies = [
493493 494494 [[package]] 495495 name = "cospan-node" 496-version = "0.3.0" 496+version = "0.3.1" 497497 dependencies = [ 498498 "anyhow", 499499 "async-trait",
@@ -0,0 +1,220 @@
1+// Generated from panproto grammars.toml 2+export const ALL_LANGUAGES = [ 3+ { value: 'actionscript', label: 'Actionscript' }, 4+ { value: 'ada', label: 'Ada' }, 5+ { value: 'agda', label: 'Agda' }, 6+ { value: 'al', label: 'Al' }, 7+ { value: 'apex', label: 'Apex' }, 8+ { value: 'arduino', label: 'Arduino' }, 9+ { value: 'asciidoc', label: 'Asciidoc' }, 10+ { value: 'asm', label: 'Asm' }, 11+ { value: 'astro', label: 'Astro' }, 12+ { value: 'awk', label: 'Awk' }, 13+ { value: 'bash', label: 'Bash' }, 14+ { value: 'bass', label: 'Bass' }, 15+ { value: 'batch', label: 'Batch' }, 16+ { value: 'beancount', label: 'Beancount' }, 17+ { value: 'bibtex', label: 'Bibtex' }, 18+ { value: 'bicep', label: 'Bicep' }, 19+ { value: 'bitbake', label: 'Bitbake' }, 20+ { value: 'blade', label: 'Blade' }, 21+ { value: 'brightscript', label: 'Brightscript' }, 22+ { value: 'bsl', label: 'Bsl' }, 23+ { value: 'c', label: 'C' }, 24+ { value: 'caddy', label: 'Caddy' }, 25+ { value: 'cairo', label: 'Cairo' }, 26+ { value: 'capnp', label: 'Capnp' }, 27+ { value: 'cedar', label: 'Cedar' }, 28+ { value: 'cedarschema', label: 'Cedarschema' }, 29+ { value: 'chatito', label: 'Chatito' }, 30+ { value: 'circom', label: 'Circom' }, 31+ { value: 'clarity', label: 'Clarity' }, 32+ { value: 'clojure', label: 'Clojure' }, 33+ { value: 'cmake', label: 'Cmake' }, 34+ { value: 'cobol', label: 'Cobol' }, 35+ { value: 'commonlisp', label: 'Commonlisp' }, 36+ { value: 'cooklang', label: 'Cooklang' }, 37+ { value: 'corn', label: 'Corn' }, 38+ { value: 'cpon', label: 'Cpon' }, 39+ { value: 'cpp', label: 'Cpp' }, 40+ { value: 'crystal', label: 'Crystal' }, 41+ { value: 'csharp', label: 'Csharp' }, 42+ { value: 'css', label: 'Css' }, 43+ { value: 'csv', label: 'Csv' }, 44+ { value: 'cuda', label: 'Cuda' }, 45+ { value: 'cue', label: 'Cue' }, 46+ { value: 'cylc', label: 'Cylc' }, 47+ { value: 'd', label: 'D' }, 48+ { value: 'dart', label: 'Dart' }, 49+ { value: 'desktop', label: 'Desktop' }, 50+ { value: 'devicetree', label: 'Devicetree' }, 51+ { value: 'diff', label: 'Diff' }, 52+ { value: 'djot', label: 'Djot' }, 53+ { value: 'dockerfile', label: 'Dockerfile' }, 54+ { value: 'dot', label: 'Dot' }, 55+ { value: 'dtd', label: 'Dtd' }, 56+ { value: 'ebnf', label: 'Ebnf' }, 57+ { value: 'eds', label: 'Eds' }, 58+ { value: 'eex', label: 'Eex' }, 59+ { value: 'elisp', label: 'Elisp' }, 60+ { value: 'elixir', label: 'Elixir' }, 61+ { value: 'elm', label: 'Elm' }, 62+ { value: 'elsa', label: 'Elsa' }, 63+ { value: 'embedded_template', label: 'Embedded Template' }, 64+ { value: 'enforce', label: 'Enforce' }, 65+ { value: 'erlang', label: 'Erlang' }, 66+ { value: 'facility', label: 'Facility' }, 67+ { value: 'faust', label: 'Faust' }, 68+ { value: 'fennel', label: 'Fennel' }, 69+ { value: 'fidl', label: 'Fidl' }, 70+ { value: 'firrtl', label: 'Firrtl' }, 71+ { value: 'fish', label: 'Fish' }, 72+ { value: 'forth', label: 'Forth' }, 73+ { value: 'fortran', label: 'Fortran' }, 74+ { value: 'fsharp', label: 'Fsharp' }, 75+ { value: 'fsharp_signature', label: 'Fsharp Signature' }, 76+ { value: 'func', label: 'Func' }, 77+ { value: 'gdscript', label: 'Gdscript' }, 78+ { value: 'gitattributes', label: 'Gitattributes' }, 79+ { value: 'gitignore', label: 'Gitignore' }, 80+ { value: 'gleam', label: 'Gleam' }, 81+ { value: 'glsl', label: 'Glsl' }, 82+ { value: 'gn', label: 'Gn' }, 83+ { value: 'go', label: 'Go' }, 84+ { value: 'godot_resource', label: 'Godot Resource' }, 85+ { value: 'gomod', label: 'Gomod' }, 86+ { value: 'graphql', label: 'Graphql' }, 87+ { value: 'groovy', label: 'Groovy' }, 88+ { value: 'hack', label: 'Hack' }, 89+ { value: 'hare', label: 'Hare' }, 90+ { value: 'haskell', label: 'Haskell' }, 91+ { value: 'haxe', label: 'Haxe' }, 92+ { value: 'hcl', label: 'Hcl' }, 93+ { value: 'heex', label: 'Heex' }, 94+ { value: 'hlsl', label: 'Hlsl' }, 95+ { value: 'html', label: 'Html' }, 96+ { value: 'http', label: 'Http' }, 97+ { value: 'hurl', label: 'Hurl' }, 98+ { value: 'idris', label: 'Idris' }, 99+ { value: 'ini', label: 'Ini' }, 100+ { value: 'ispc', label: 'Ispc' }, 101+ { value: 'janet', label: 'Janet' }, 102+ { value: 'java', label: 'Java' }, 103+ { value: 'javascript', label: 'Javascript' }, 104+ { value: 'jinja2', label: 'Jinja2' }, 105+ { value: 'jq', label: 'Jq' }, 106+ { value: 'json', label: 'Json' }, 107+ { value: 'jsonnet', label: 'Jsonnet' }, 108+ { value: 'julia', label: 'Julia' }, 109+ { value: 'just', label: 'Just' }, 110+ { value: 'kdl', label: 'Kdl' }, 111+ { value: 'kotlin', label: 'Kotlin' }, 112+ { value: 'latex', label: 'Latex' }, 113+ { value: 'lean', label: 'Lean' }, 114+ { value: 'ledger', label: 'Ledger' }, 115+ { value: 'less', label: 'Less' }, 116+ { value: 'linkerscript', label: 'Linkerscript' }, 117+ { value: 'liquid', label: 'Liquid' }, 118+ { value: 'llvm', label: 'Llvm' }, 119+ { value: 'lua', label: 'Lua' }, 120+ { value: 'luau', label: 'Luau' }, 121+ { value: 'magik', label: 'Magik' }, 122+ { value: 'make', label: 'Make' }, 123+ { value: 'markdown', label: 'Markdown' }, 124+ { value: 'matlab', label: 'Matlab' }, 125+ { value: 'mermaid', label: 'Mermaid' }, 126+ { value: 'meson', label: 'Meson' }, 127+ { value: 'mojo', label: 'Mojo' }, 128+ { value: 'move', label: 'Move' }, 129+ { value: 'netlinx', label: 'Netlinx' }, 130+ { value: 'nginx', label: 'Nginx' }, 131+ { value: 'nickel', label: 'Nickel' }, 132+ { value: 'nim', label: 'Nim' }, 133+ { value: 'ninja', label: 'Ninja' }, 134+ { value: 'nix', label: 'Nix' }, 135+ { value: 'norg', label: 'Norg' }, 136+ { value: 'nqc', label: 'Nqc' }, 137+ { value: 'nushell', label: 'Nushell' }, 138+ { value: 'objc', label: 'Objc' }, 139+ { value: 'ocaml', label: 'Ocaml' }, 140+ { value: 'ocaml_interface', label: 'Ocaml Interface' }, 141+ { value: 'odin', label: 'Odin' }, 142+ { value: 'org', label: 'Org' }, 143+ { value: 'pascal', label: 'Pascal' }, 144+ { value: 'pem', label: 'Pem' }, 145+ { value: 'perl', label: 'Perl' }, 146+ { value: 'pgn', label: 'Pgn' }, 147+ { value: 'php', label: 'Php' }, 148+ { value: 'pkl', label: 'Pkl' }, 149+ { value: 'po', label: 'Po' }, 150+ { value: 'pony', label: 'Pony' }, 151+ { value: 'postscript', label: 'Postscript' }, 152+ { value: 'powershell', label: 'Powershell' }, 153+ { value: 'prisma', label: 'Prisma' }, 154+ { value: 'prolog', label: 'Prolog' }, 155+ { value: 'promql', label: 'Promql' }, 156+ { value: 'properties', label: 'Properties' }, 157+ { value: 'protobuf', label: 'Protobuf' }, 158+ { value: 'psv', label: 'Psv' }, 159+ { value: 'pug', label: 'Pug' }, 160+ { value: 'puppet', label: 'Puppet' }, 161+ { value: 'purescript', label: 'Purescript' }, 162+ { value: 'python', label: 'Python' }, 163+ { value: 'ql', label: 'Ql' }, 164+ { value: 'qml', label: 'Qml' }, 165+ { value: 'r', label: 'R' }, 166+ { value: 'racket', label: 'Racket' }, 167+ { value: 're2c', label: 'Re2C' }, 168+ { value: 'rego', label: 'Rego' }, 169+ { value: 'rescript', label: 'Rescript' }, 170+ { value: 'robot', label: 'Robot' }, 171+ { value: 'ron', label: 'Ron' }, 172+ { value: 'rst', label: 'Rst' }, 173+ { value: 'ruby', label: 'Ruby' }, 174+ { value: 'rust', label: 'Rust' }, 175+ { value: 'scala', label: 'Scala' }, 176+ { value: 'scheme', label: 'Scheme' }, 177+ { value: 'scss', label: 'Scss' }, 178+ { value: 'smali', label: 'Smali' }, 179+ { value: 'smithy', label: 'Smithy' }, 180+ { value: 'solidity', label: 'Solidity' }, 181+ { value: 'sparql', label: 'Sparql' }, 182+ { value: 'sql', label: 'Sql' }, 183+ { value: 'squirrel', label: 'Squirrel' }, 184+ { value: 'starlark', label: 'Starlark' }, 185+ { value: 'svelte', label: 'Svelte' }, 186+ { value: 'swift', label: 'Swift' }, 187+ { value: 'tablegen', label: 'Tablegen' }, 188+ { value: 'tcl', label: 'Tcl' }, 189+ { value: 'teal', label: 'Teal' }, 190+ { value: 'templ', label: 'Templ' }, 191+ { value: 'terraform', label: 'Terraform' }, 192+ { value: 'textproto', label: 'Textproto' }, 193+ { value: 'thrift', label: 'Thrift' }, 194+ { value: 'tlaplus', label: 'Tlaplus' }, 195+ { value: 'todotxt', label: 'Todotxt' }, 196+ { value: 'toml', label: 'Toml' }, 197+ { value: 'tsv', label: 'Tsv' }, 198+ { value: 'tsx', label: 'Tsx' }, 199+ { value: 'turtle', label: 'Turtle' }, 200+ { value: 'twig', label: 'Twig' }, 201+ { value: 'typescript', label: 'Typescript' }, 202+ { value: 'typst', label: 'Typst' }, 203+ { value: 'uxntal', label: 'Uxntal' }, 204+ { value: 'v', label: 'V' }, 205+ { value: 'vb', label: 'Vb' }, 206+ { value: 'verilog', label: 'Verilog' }, 207+ { value: 'vhdl', label: 'Vhdl' }, 208+ { value: 'vim', label: 'Vim' }, 209+ { value: 'vue', label: 'Vue' }, 210+ { value: 'wast', label: 'Wast' }, 211+ { value: 'wat', label: 'Wat' }, 212+ { value: 'wgsl', label: 'Wgsl' }, 213+ { value: 'wit', label: 'Wit' }, 214+ { value: 'wolfram', label: 'Wolfram' }, 215+ { value: 'xml', label: 'Xml' }, 216+ { value: 'yaml', label: 'Yaml' }, 217+ { value: 'yuck', label: 'Yuck' }, 218+ { value: 'zig', label: 'Zig' }, 219+ { value: 'zsh', label: 'Zsh' }, 220+];
@@ -1,31 +1,43 @@
11 <script lang="ts"> 22 import { getAuth } from '$lib/stores/auth.svelte'; 33 import { goto } from '$app/navigation'; 4+ import { ALL_LANGUAGES } from '$lib/data/languages'; 45 56 let auth = $derived(getAuth()); 67 78 let name = $state(''); 89 let description = $state(''); 9- let protocol = $state('typescript'); 10+ let selectedProtocols = $state<string[]>(['typescript']); 11+ let protocolSearch = $state(''); 12+ let showProtocolDropdown = $state(false); 1013 let visibility = $state('public'); 1114 let creating = $state(false); 1215 let error = $state(''); 1316 14- const protocols = [ 15- { value: 'typescript', label: 'TypeScript' }, 16- { value: 'python', label: 'Python' }, 17- { value: 'rust', label: 'Rust' }, 18- { value: 'java', label: 'Java' }, 19- { value: 'go', label: 'Go' }, 20- { value: 'swift', label: 'Swift' }, 21- { value: 'kotlin', label: 'Kotlin' }, 22- { value: 'csharp', label: 'C#' }, 23- { value: 'protobuf', label: 'Protocol Buffers' }, 24- { value: 'graphql', label: 'GraphQL' }, 25- { value: 'json_schema', label: 'JSON Schema' }, 26- { value: 'sql', label: 'SQL' }, 27- { value: 'atproto', label: 'ATProto Lexicon' }, 28- ]; 17+ let filteredProtocols = $derived( 18+ protocolSearch.trim() 19+ ? ALL_LANGUAGES.filter((p) => 20+ p.label.toLowerCase().includes(protocolSearch.toLowerCase()) || 21+ p.value.toLowerCase().includes(protocolSearch.toLowerCase()) 22+ ) 23+ : ALL_LANGUAGES 24+ ); 25+ 26+ function toggleProtocol(value: string) { 27+ if (selectedProtocols.includes(value)) { 28+ selectedProtocols = selectedProtocols.filter((p) => p !== value); 29+ } else { 30+ selectedProtocols = [...selectedProtocols, value]; 31+ } 32+ } 33+ 34+ function removeProtocol(value: string) { 35+ selectedProtocols = selectedProtocols.filter((p) => p !== value); 36+ } 37+ 38+ function protocolLabel(value: string): string { 39+ return ALL_LANGUAGES.find((p) => p.value === value)?.label ?? value; 40+ } 2941 3042 async function handleCreate(event: Event) { 3143 event.preventDefault();
@@ -42,7 +54,7 @@
4254 did: auth.did, 4355 name: name.trim(), 4456 description: description.trim() || undefined, 45- protocol, 57+ protocol: selectedProtocols.join(','), 4658 visibility, 4759 }), 4860 });
@@ -105,19 +117,69 @@
105117 </div> 106118 107119 <div> 108- <label for="protocol" class="mb-1 block text-xs font-medium text-text-secondary"> 109- Protocol 120+ <label class="mb-1 block text-xs font-medium text-text-secondary"> 121+ Languages ({selectedProtocols.length} selected) 110122 </label> 111- <select 112- id="protocol" 113- bind:value={protocol} 114- class="w-full rounded-md border border-border bg-surface-0 px-3 py-2 text-sm text-text-primary focus:border-accent focus:outline-none" 115- > 116- {#each protocols as p} 117- <option value={p.value}>{p.label}</option> 118- {/each} 119- </select> 120- <p class="mt-1 text-xs text-text-secondary">The schema protocol this repository tracks. Determines structural diff and merge behavior.</p> 123+ 124+ <!-- Selected tags --> 125+ {#if selectedProtocols.length > 0} 126+ <div class="mb-2 flex flex-wrap gap-1.5"> 127+ {#each selectedProtocols as p} 128+ <button 129+ type="button" 130+ onclick={() => removeProtocol(p)} 131+ class="inline-flex items-center gap-1 rounded-full bg-accent/15 px-2.5 py-0.5 text-xs font-medium text-accent transition-colors hover:bg-accent/25" 132+ > 133+ {protocolLabel(p)} 134+ <svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> 135+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> 136+ </svg> 137+ </button> 138+ {/each} 139+ </div> 140+ {/if} 141+ 142+ <!-- Search input --> 143+ <div class="relative"> 144+ <input 145+ type="text" 146+ bind:value={protocolSearch} 147+ onfocus={() => showProtocolDropdown = true} 148+ onblur={() => setTimeout(() => showProtocolDropdown = false, 200)} 149+ placeholder="Search 217 languages..." 150+ autocomplete="off" 151+ class="w-full rounded-md border border-border bg-surface-0 px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:border-accent focus:outline-none" 152+ /> 153+ 154+ {#if showProtocolDropdown} 155+ <ul class="absolute left-0 top-full z-50 mt-1 max-h-48 w-full overflow-y-auto rounded-lg border border-border bg-surface-1 shadow-lg"> 156+ {#each filteredProtocols as p} 157+ <li> 158+ <button 159+ type="button" 160+ onmousedown={() => toggleProtocol(p.value)} 161+ class="flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors hover:bg-surface-2 162+ {selectedProtocols.includes(p.value) ? 'text-accent' : 'text-text-secondary'}" 163+ > 164+ {#if selectedProtocols.includes(p.value)} 165+ <svg class="h-3 w-3 shrink-0 text-accent" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="3"> 166+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /> 167+ </svg> 168+ {:else} 169+ <span class="h-3 w-3 shrink-0"></span> 170+ {/if} 171+ {p.label} 172+ </button> 173+ </li> 174+ {/each} 175+ {#if filteredProtocols.length === 0} 176+ <li class="px-3 py-2 text-xs text-text-secondary">No matches</li> 177+ {/if} 178+ </ul> 179+ {/if} 180+ </div> 181+ 182+ <p class="mt-1 text-xs text-text-secondary">Languages this repository uses. Determines structural diff and merge behavior.</p> 121183 </div> 122184 123185 <div>