atmosphere explorer

refactor lexicon schema component

handle.invalid d0eaf19c 91857add

verified
+182 -231
+3 -3
package.json
··· 11 11 "serve": "vite preview" 12 12 }, 13 13 "devDependencies": { 14 - "@iconify-json/lucide": "^1.2.87", 14 + "@iconify-json/lucide": "^1.2.88", 15 15 "@iconify/tailwind4": "^1.2.1", 16 16 "@tailwindcss/vite": "^4.1.18", 17 17 "prettier": "^3.8.1", ··· 24 24 }, 25 25 "dependencies": { 26 26 "@atcute/atproto": "^3.1.10", 27 - "@atcute/bluesky": "^3.2.16", 27 + "@atcute/bluesky": "^3.2.17", 28 28 "@atcute/car": "^5.1.0", 29 29 "@atcute/cbor": "^2.3.0", 30 30 "@atcute/cid": "^2.4.0", ··· 39 39 "@atcute/multibase": "^1.1.7", 40 40 "@atcute/oauth-browser-client": "^3.0.0", 41 41 "@atcute/repo": "^0.1.1", 42 - "@atcute/tangled": "^1.0.15", 42 + "@atcute/tangled": "^1.0.16", 43 43 "@atcute/tid": "^1.1.1", 44 44 "@codemirror/commands": "^6.10.1", 45 45 "@codemirror/lang-json": "^6.0.2",
+52 -52
pnpm-lock.yaml
··· 12 12 specifier: ^3.1.10 13 13 version: 3.1.10 14 14 '@atcute/bluesky': 15 - specifier: ^3.2.16 16 - version: 3.2.16 15 + specifier: ^3.2.17 16 + version: 3.2.17 17 17 '@atcute/car': 18 18 specifier: ^5.1.0 19 19 version: 5.1.0 ··· 57 57 specifier: ^0.1.1 58 58 version: 0.1.1 59 59 '@atcute/tangled': 60 - specifier: ^1.0.15 61 - version: 1.0.15 60 + specifier: ^1.0.16 61 + version: 1.0.16 62 62 '@atcute/tid': 63 63 specifier: ^1.1.1 64 64 version: 1.1.1 ··· 109 109 version: 1.9.11 110 110 devDependencies: 111 111 '@iconify-json/lucide': 112 - specifier: ^1.2.87 113 - version: 1.2.87 112 + specifier: ^1.2.88 113 + version: 1.2.88 114 114 '@iconify/tailwind4': 115 115 specifier: ^1.2.1 116 116 version: 1.2.1(tailwindcss@4.1.18) 117 117 '@tailwindcss/vite': 118 118 specifier: ^4.1.18 119 - version: 4.1.18(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 119 + version: 4.1.18(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 120 120 prettier: 121 121 specifier: ^3.8.1 122 122 version: 3.8.1 ··· 134 134 version: 5.9.3 135 135 vite: 136 136 specifier: ^7.3.1 137 - version: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 137 + version: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 138 138 vite-plugin-solid: 139 139 specifier: ^2.11.10 140 - version: 2.11.10(solid-js@1.9.11)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 140 + version: 2.11.10(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 141 141 142 142 packages: 143 143 ··· 147 147 '@atcute/atproto@3.1.10': 148 148 resolution: {integrity: sha512-+GKZpOc0PJcdWMQEkTfg/rSNDAAHxmAUGBl60g2az15etqJn5WaUPNGFE2sB7hKpwi5Ue2h/L0OacINcE/JDDQ==} 149 149 150 - '@atcute/bluesky@3.2.16': 151 - resolution: {integrity: sha512-phFAJNE+SCkIbCcgzjFxntS2KpGvzkLw0JA9qKIXlueF4wNreEt/D5HjnB5eRR9pV1/kcD94II9f7ZAwarf0lQ==} 150 + '@atcute/bluesky@3.2.17': 151 + resolution: {integrity: sha512-Li+RsPkcRNC6AnNlqOGnlmAcjSwBdXIKFubJL1nwACDngKNXG4ooGL5cvzeekdDEfHmtFhS/tyZNaUx9QXYEUw==} 152 152 153 153 '@atcute/car@3.1.3': 154 154 resolution: {integrity: sha512-WJ13bAEt7TjDMVi09ubjLtvhdljbWInGm9Kfy7Y6NhrmiyC/aZYaA/zHX/bHI6xv1c/h3SQduWqxOr4ae49eqA==} ··· 212 212 '@atcute/repo@0.1.1': 213 213 resolution: {integrity: sha512-P5aWjt3bvcquUkUmGPslF0naAfLGRHse5Qdz9/RJYrFuoH0iiEMyRnW6M+3ksOe20GPsMnbq71WbzzFkRFPBtg==} 214 214 215 - '@atcute/tangled@1.0.15': 216 - resolution: {integrity: sha512-cEQ0r+iTr4sVfiE6amlqT/h9X+tCGyfhSU+zIGUl6YzAAUMHvNhi9q98BFrdB3nBeOqfHVk/vwLnzQxxqiHZsQ==} 215 + '@atcute/tangled@1.0.16': 216 + resolution: {integrity: sha512-8we9seXrD79MhvA0BSBgKOvZz/Cx6sJJ4wc4QcHZF4Ats/+4+xuNOwzuFNL+1sNib/GqXxa8dhmmpoY6T1PRZQ==} 217 217 218 218 '@atcute/tid@1.1.1': 219 219 resolution: {integrity: sha512-djJ8UGhLkTU5V51yCnBEruMg35qETjWzWy5sJG/2gEOl2Gd7rQWHSaf+yrO6vMS5EFA38U2xOWE3EDUPzvc2ZQ==} ··· 661 661 '@codemirror/view': ^6.0.0 662 662 '@lezer/highlight': ^1.0.0 663 663 664 - '@iconify-json/lucide@1.2.87': 665 - resolution: {integrity: sha512-wxYIAp0f8Uw0rJa6BMWMaRbiHk3yV4XczA38GKXFlqyZtTdmHM1QOF4NZw5xpMlRDzbh2MnB7wjteLeFnn/ciQ==} 664 + '@iconify-json/lucide@1.2.88': 665 + resolution: {integrity: sha512-QBJq+VSj3yHXoMgf+1I4guUhXA+tpxzAt46LJdTSFN6UKy254GstTh+P/a6GD4Bvyi1fCAfi5hS/yCmu0w3mNw==} 666 666 667 667 '@iconify/tailwind4@1.2.1': 668 668 resolution: {integrity: sha512-Hd7k8y7uzT3hk8ltw0jGku0r0wA8sc3d2iMvVTYv/9tMxBb+frZtWZGD9hDMU3EYuE+lMn58wi2lS8R2ZbwFcQ==} ··· 712 712 '@jsr/mary__zip@0.1.1': 713 713 resolution: {integrity: sha512-RIt6xSshG6x1X4qUVGXukgS8ysot+wLQc/WAkNogbiDwm3tzFyDxZdEs8TVDQyT1L7lApPPgbEgdcex7NcfGrw==, tarball: https://npm.jsr.io/~/11/@jsr/mary__zip/0.1.1.tgz} 714 714 715 - '@lezer/common@1.5.0': 716 - resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==} 715 + '@lezer/common@1.5.1': 716 + resolution: {integrity: sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw==} 717 717 718 718 '@lezer/highlight@1.2.3': 719 719 resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} ··· 979 979 '@types/estree@1.0.8': 980 980 resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 981 981 982 - '@types/node@25.1.0': 983 - resolution: {integrity: sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==} 982 + '@types/node@25.2.0': 983 + resolution: {integrity: sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==} 984 984 985 985 acorn@8.15.0: 986 986 resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} ··· 1016 1016 bun-types@1.3.8: 1017 1017 resolution: {integrity: sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q==} 1018 1018 1019 - caniuse-lite@1.0.30001766: 1020 - resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==} 1019 + caniuse-lite@1.0.30001767: 1020 + resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==} 1021 1021 1022 1022 codemirror@6.0.2: 1023 1023 resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} ··· 1083 1083 domutils@3.2.2: 1084 1084 resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} 1085 1085 1086 - electron-to-chromium@1.5.283: 1087 - resolution: {integrity: sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==} 1086 + electron-to-chromium@1.5.286: 1087 + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} 1088 1088 1089 - enhanced-resolve@5.18.4: 1090 - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} 1089 + enhanced-resolve@5.19.0: 1090 + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} 1091 1091 engines: {node: '>=10.13.0'} 1092 1092 1093 1093 entities@4.5.0: ··· 1561 1561 dependencies: 1562 1562 '@atcute/lexicons': 1.2.7 1563 1563 1564 - '@atcute/bluesky@3.2.16': 1564 + '@atcute/bluesky@3.2.17': 1565 1565 dependencies: 1566 1566 '@atcute/atproto': 3.1.10 1567 1567 '@atcute/lexicons': 1.2.7 ··· 1703 1703 '@atcute/mst': 0.1.2 1704 1704 '@atcute/uint8array': 1.1.0 1705 1705 1706 - '@atcute/tangled@1.0.15': 1706 + '@atcute/tangled@1.0.16': 1707 1707 dependencies: 1708 1708 '@atcute/atproto': 3.1.10 1709 1709 '@atcute/lexicons': 1.2.7 ··· 1847 1847 '@codemirror/language': 6.12.1 1848 1848 '@codemirror/state': 6.5.4 1849 1849 '@codemirror/view': 6.39.12 1850 - '@lezer/common': 1.5.0 1850 + '@lezer/common': 1.5.1 1851 1851 1852 1852 '@codemirror/commands@6.10.1': 1853 1853 dependencies: 1854 1854 '@codemirror/language': 6.12.1 1855 1855 '@codemirror/state': 6.5.4 1856 1856 '@codemirror/view': 6.39.12 1857 - '@lezer/common': 1.5.0 1857 + '@lezer/common': 1.5.1 1858 1858 1859 1859 '@codemirror/lang-json@6.0.2': 1860 1860 dependencies: ··· 1865 1865 dependencies: 1866 1866 '@codemirror/state': 6.5.4 1867 1867 '@codemirror/view': 6.39.12 1868 - '@lezer/common': 1.5.0 1868 + '@lezer/common': 1.5.1 1869 1869 '@lezer/highlight': 1.2.3 1870 1870 '@lezer/lr': 1.4.8 1871 1871 style-mod: 4.1.3 ··· 2061 2061 '@codemirror/view': 6.39.12 2062 2062 '@lezer/highlight': 1.2.3 2063 2063 2064 - '@iconify-json/lucide@1.2.87': 2064 + '@iconify-json/lucide@1.2.88': 2065 2065 dependencies: 2066 2066 '@iconify/types': 2.0.0 2067 2067 ··· 2126 2126 '@jsr/mary__ds-queue': 0.1.3 2127 2127 '@jsr/mary__mutex': 0.1.0 2128 2128 2129 - '@lezer/common@1.5.0': {} 2129 + '@lezer/common@1.5.1': {} 2130 2130 2131 2131 '@lezer/highlight@1.2.3': 2132 2132 dependencies: 2133 - '@lezer/common': 1.5.0 2133 + '@lezer/common': 1.5.1 2134 2134 2135 2135 '@lezer/json@1.0.3': 2136 2136 dependencies: 2137 - '@lezer/common': 1.5.0 2137 + '@lezer/common': 1.5.1 2138 2138 '@lezer/highlight': 1.2.3 2139 2139 '@lezer/lr': 1.4.8 2140 2140 2141 2141 '@lezer/lr@1.4.8': 2142 2142 dependencies: 2143 - '@lezer/common': 1.5.0 2143 + '@lezer/common': 1.5.1 2144 2144 2145 2145 '@marijn/find-cluster-break@1.0.2': {} 2146 2146 ··· 2240 2240 '@tailwindcss/node@4.1.18': 2241 2241 dependencies: 2242 2242 '@jridgewell/remapping': 2.3.5 2243 - enhanced-resolve: 5.18.4 2243 + enhanced-resolve: 5.19.0 2244 2244 jiti: 2.6.1 2245 2245 lightningcss: 1.30.2 2246 2246 magic-string: 0.30.21 ··· 2298 2298 '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 2299 2299 '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 2300 2300 2301 - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2))': 2301 + '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2))': 2302 2302 dependencies: 2303 2303 '@tailwindcss/node': 4.1.18 2304 2304 '@tailwindcss/oxide': 4.1.18 2305 2305 tailwindcss: 4.1.18 2306 - vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2306 + vite: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2307 2307 2308 2308 '@types/babel__core@7.20.5': 2309 2309 dependencies: ··· 2332 2332 2333 2333 '@types/estree@1.0.8': {} 2334 2334 2335 - '@types/node@25.1.0': 2335 + '@types/node@25.2.0': 2336 2336 dependencies: 2337 2337 undici-types: 7.16.0 2338 2338 ··· 2361 2361 browserslist@4.28.1: 2362 2362 dependencies: 2363 2363 baseline-browser-mapping: 2.9.19 2364 - caniuse-lite: 1.0.30001766 2365 - electron-to-chromium: 1.5.283 2364 + caniuse-lite: 1.0.30001767 2365 + electron-to-chromium: 1.5.286 2366 2366 node-releases: 2.0.27 2367 2367 update-browserslist-db: 1.2.3(browserslist@4.28.1) 2368 2368 2369 2369 bun-types@1.3.8: 2370 2370 dependencies: 2371 - '@types/node': 25.1.0 2371 + '@types/node': 25.2.0 2372 2372 2373 - caniuse-lite@1.0.30001766: {} 2373 + caniuse-lite@1.0.30001767: {} 2374 2374 2375 2375 codemirror@6.0.2: 2376 2376 dependencies: ··· 2440 2440 domelementtype: 2.3.0 2441 2441 domhandler: 5.0.3 2442 2442 2443 - electron-to-chromium@1.5.283: {} 2443 + electron-to-chromium@1.5.286: {} 2444 2444 2445 - enhanced-resolve@5.18.4: 2445 + enhanced-resolve@5.19.0: 2446 2446 dependencies: 2447 2447 graceful-fs: 4.2.11 2448 2448 tapable: 2.3.0 ··· 2788 2788 escalade: 3.2.0 2789 2789 picocolors: 1.1.1 2790 2790 2791 - vite-plugin-solid@2.11.10(solid-js@1.9.11)(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2791 + vite-plugin-solid@2.11.10(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2792 2792 dependencies: 2793 2793 '@babel/core': 7.29.0 2794 2794 '@types/babel__core': 7.20.5 ··· 2796 2796 merge-anything: 5.1.7 2797 2797 solid-js: 1.9.11 2798 2798 solid-refresh: 0.6.3(solid-js@1.9.11) 2799 - vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2800 - vitefu: 1.1.1(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 2799 + vite: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2800 + vitefu: 1.1.1(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 2801 2801 transitivePeerDependencies: 2802 2802 - supports-color 2803 2803 2804 - vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2): 2804 + vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2): 2805 2805 dependencies: 2806 2806 esbuild: 0.27.2 2807 2807 fdir: 6.5.0(picomatch@4.0.3) ··· 2810 2810 rollup: 4.57.1 2811 2811 tinyglobby: 0.2.15 2812 2812 optionalDependencies: 2813 - '@types/node': 25.1.0 2813 + '@types/node': 25.2.0 2814 2814 fsevents: 2.3.3 2815 2815 jiti: 2.6.1 2816 2816 lightningcss: 1.30.2 2817 2817 tsx: 4.19.2 2818 2818 2819 - vitefu@1.1.1(vite@7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2819 + vitefu@1.1.1(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2820 2820 optionalDependencies: 2821 - vite: 7.3.1(@types/node@25.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2821 + vite: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2822 2822 2823 2823 w3c-keyname@2.2.8: {} 2824 2824
+127 -176
src/components/lexicon-schema.tsx
··· 3 3 import { createEffect, For, Show } from "solid-js"; 4 4 import { resolveLexiconAuthority } from "../utils/api.js"; 5 5 6 + // Style constants 7 + const CONTAINER_CLASS = 8 + "divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"; 9 + 10 + const CARD_CLASS = 11 + "flex flex-col gap-2 rounded-lg border border-neutral-200 bg-neutral-50/50 p-3 dark:border-neutral-700 dark:bg-neutral-800/30"; 12 + 13 + const RESOURCE_COLORS = { 14 + repo: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300", 15 + rpc: "bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300", 16 + default: "bg-neutral-200 text-neutral-800 dark:bg-neutral-700 dark:text-neutral-300", 17 + } as const; 18 + 19 + const DEF_TYPE_COLORS = { 20 + record: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300", 21 + query: "bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300", 22 + procedure: "bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-300", 23 + subscription: "bg-pink-100 text-pink-800 dark:bg-pink-900/30 dark:text-pink-300", 24 + object: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300", 25 + token: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300", 26 + "permission-set": "bg-cyan-100 text-cyan-800 dark:bg-cyan-900/30 dark:text-cyan-300", 27 + default: "bg-neutral-200 text-neutral-800 dark:bg-neutral-700 dark:text-neutral-300", 28 + } as const; 29 + 30 + // Utility functions 31 + const hasConstraints = (property: LexiconProperty | LexiconDef) => 32 + property.minLength !== undefined || 33 + property.maxLength !== undefined || 34 + property.maxGraphemes !== undefined || 35 + property.minGraphemes !== undefined || 36 + property.minimum !== undefined || 37 + property.maximum !== undefined || 38 + property.maxSize !== undefined || 39 + property.accept || 40 + property.enum || 41 + property.const || 42 + property.default !== undefined || 43 + property.knownValues || 44 + property.closed; 45 + 6 46 interface LexiconSchema { 7 47 lexicon: number; 8 48 id: string; ··· 44 84 closed?: boolean; 45 85 enum?: string[]; 46 86 const?: string; 47 - default?: any; 87 + default?: string | number | boolean; 48 88 minimum?: number; 49 89 maximum?: number; 50 90 accept?: string[]; ··· 86 126 maximum?: number; 87 127 enum?: string[]; 88 128 const?: string | boolean | number; 89 - default?: any; 129 + default?: string | number | boolean; 90 130 knownValues?: string[]; 91 131 accept?: string[]; 92 132 maxSize?: number; ··· 226 266 required?: boolean; 227 267 hideNameType?: boolean; 228 268 }) => { 229 - const hasConstraints = (property: LexiconProperty) => 230 - property.minLength !== undefined || 231 - property.maxLength !== undefined || 232 - property.maxGraphemes !== undefined || 233 - property.minGraphemes !== undefined || 234 - property.minimum !== undefined || 235 - property.maximum !== undefined || 236 - property.maxSize !== undefined || 237 - property.accept || 238 - property.enum || 239 - property.const || 240 - property.default !== undefined || 241 - property.knownValues || 242 - property.closed; 243 - 244 269 return ( 245 270 <div class="flex flex-col gap-2 py-3"> 246 271 <Show when={!props.hideNameType}> ··· 322 347 ); 323 348 }; 324 349 325 - const resourceColor = (resource: string) => { 326 - switch (resource) { 327 - case "repo": 328 - return "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300"; 329 - case "rpc": 330 - return "bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300"; 331 - default: 332 - return "bg-neutral-200 text-neutral-800 dark:bg-neutral-700 dark:text-neutral-300"; 333 - } 350 + const resourceColor = (resource: string) => 351 + RESOURCE_COLORS[resource as keyof typeof RESOURCE_COLORS] || RESOURCE_COLORS.default; 352 + 353 + const SchemaSection = (props: { title: string; encoding: string; schema?: LexiconObject }) => { 354 + return ( 355 + <div class="flex flex-col gap-2"> 356 + <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 357 + {props.title} 358 + </h4> 359 + <div class={CARD_CLASS}> 360 + <div class="text-sm"> 361 + <span class="font-semibold">Encoding: </span> 362 + <span class="font-mono">{props.encoding}</span> 363 + </div> 364 + <Show when={props.schema?.ref}> 365 + <div class="flex items-center gap-2"> 366 + <span class="text-sm font-semibold">Schema:</span> 367 + <TypeBadge type="ref" refType={props.schema!.ref} /> 368 + </div> 369 + </Show> 370 + <Show when={props.schema?.refs}> 371 + <div class="flex flex-col gap-2"> 372 + <div class="flex items-center gap-2"> 373 + <span class="text-sm font-semibold">Schema (union):</span> 374 + </div> 375 + <UnionBadges refs={props.schema!.refs!} /> 376 + </div> 377 + </Show> 378 + <Show when={props.schema?.properties && Object.keys(props.schema.properties).length > 0}> 379 + <div class={CONTAINER_CLASS}> 380 + <For each={Object.entries(props.schema!.properties!)}> 381 + {([name, property]) => ( 382 + <PropertyRow 383 + name={name} 384 + property={property} 385 + required={(props.schema?.required || []).includes(name)} 386 + /> 387 + )} 388 + </For> 389 + </div> 390 + </Show> 391 + </div> 392 + </div> 393 + ); 334 394 }; 335 395 336 396 const PermissionRow = (props: { permission: LexiconPermission; index: number }) => { ··· 407 467 }; 408 468 409 469 const DefSection = (props: { name: string; def: LexiconDef }) => { 410 - const defTypeColor = () => { 411 - switch (props.def.type) { 412 - case "record": 413 - return "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300"; 414 - case "query": 415 - return "bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-300"; 416 - case "procedure": 417 - return "bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-300"; 418 - case "subscription": 419 - return "bg-pink-100 text-pink-800 dark:bg-pink-900/30 dark:text-pink-300"; 420 - case "object": 421 - return "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300"; 422 - case "token": 423 - return "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300"; 424 - case "permission-set": 425 - return "bg-cyan-100 text-cyan-800 dark:bg-cyan-900/30 dark:text-cyan-300"; 426 - default: 427 - return "bg-neutral-200 text-neutral-800 dark:bg-neutral-700 dark:text-neutral-300"; 428 - } 429 - }; 470 + const defTypeColor = () => 471 + DEF_TYPE_COLORS[props.def.type as keyof typeof DEF_TYPE_COLORS] || DEF_TYPE_COLORS.default; 430 472 431 - const hasDefContent = () => 432 - props.def.refs || 433 - props.def.minLength !== undefined || 434 - props.def.maxLength !== undefined || 435 - props.def.maxGraphemes !== undefined || 436 - props.def.minGraphemes !== undefined || 437 - props.def.minimum !== undefined || 438 - props.def.maximum !== undefined || 439 - props.def.maxSize !== undefined || 440 - props.def.accept || 441 - props.def.enum || 442 - props.def.const || 443 - props.def.default !== undefined || 444 - props.def.closed || 445 - props.def.items || 446 - props.def.knownValues; 473 + const hasDefContent = () => props.def.refs || props.def.items || hasConstraints(props.def); 447 474 448 475 return ( 449 476 <div class="flex flex-col gap-3" id={`def-${props.name}`}> ··· 471 498 472 499 {/* Permission-set: Title and Detail */} 473 500 <Show when={props.def.type === "permission-set" && (props.def.title || props.def.detail)}> 474 - <div class="flex flex-col gap-2 rounded-lg border border-neutral-200 bg-neutral-50/50 p-3 dark:border-neutral-700 dark:bg-neutral-800/30"> 501 + <div class={CARD_CLASS}> 475 502 <Show when={props.def.title}> 476 503 <div class="flex flex-col gap-1"> 477 504 <span class="text-xs font-semibold text-neutral-500 uppercase dark:text-neutral-400"> ··· 530 557 </Show> 531 558 532 559 {/* Permission-set: Permissions list */} 533 - <Show when={props.def.permissions && props.def.permissions.length > 0}> 534 - {(() => { 535 - const supportedPermissions = () => 536 - props.def.permissions!.filter((p) => p.resource === "repo" || p.resource === "rpc"); 537 - return ( 538 - <Show when={supportedPermissions().length > 0}> 539 - <div class="flex flex-col gap-2"> 540 - <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 541 - Permissions 542 - </h4> 543 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 544 - <For each={supportedPermissions()}> 545 - {(permission, index) => ( 546 - <PermissionRow permission={permission} index={index()} /> 547 - )} 548 - </For> 549 - </div> 550 - </div> 551 - </Show> 552 - ); 553 - })()} 560 + <Show 561 + when={ 562 + props.def.permissions && 563 + props.def.permissions.filter((p) => p.resource === "repo" || p.resource === "rpc") 564 + .length > 0 565 + } 566 + > 567 + <div class="flex flex-col gap-2"> 568 + <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 569 + Permissions 570 + </h4> 571 + <div class={CONTAINER_CLASS}> 572 + <For 573 + each={props.def.permissions!.filter( 574 + (p) => p.resource === "repo" || p.resource === "rpc", 575 + )} 576 + > 577 + {(permission, index) => <PermissionRow permission={permission} index={index()} />} 578 + </For> 579 + </div> 580 + </div> 554 581 </Show> 555 582 556 583 {/* Properties (for record/object types) */} ··· 561 588 <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 562 589 Properties 563 590 </h4> 564 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 591 + <div class={CONTAINER_CLASS}> 565 592 <For each={Object.entries(props.def.properties || props.def.record?.properties || {})}> 566 593 {([name, property]) => ( 567 594 <PropertyRow ··· 586 613 <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 587 614 Parameters 588 615 </h4> 589 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 616 + <div class={CONTAINER_CLASS}> 590 617 <For each={Object.entries(props.def.parameters!.properties!)}> 591 618 {([name, property]) => ( 592 619 <PropertyRow ··· 602 629 603 630 {/* Input */} 604 631 <Show when={props.def.input}> 605 - <div class="flex flex-col gap-2"> 606 - <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 607 - Input 608 - </h4> 609 - <div class="flex flex-col gap-2 rounded-lg border border-neutral-200 bg-neutral-50/50 p-3 dark:border-neutral-700 dark:bg-neutral-800/30"> 610 - <div class="text-sm"> 611 - <span class="font-semibold">Encoding: </span> 612 - <span class="font-mono">{props.def.input!.encoding}</span> 613 - </div> 614 - <Show when={props.def.input!.schema?.ref}> 615 - <div class="flex items-center gap-2"> 616 - <span class="text-sm font-semibold">Schema:</span> 617 - <TypeBadge type="ref" refType={props.def.input!.schema!.ref} /> 618 - </div> 619 - </Show> 620 - <Show when={props.def.input!.schema?.refs}> 621 - <div class="flex flex-col gap-2"> 622 - <div class="flex items-center gap-2"> 623 - <span class="text-sm font-semibold">Schema (union):</span> 624 - </div> 625 - <UnionBadges refs={props.def.input!.schema!.refs!} /> 626 - </div> 627 - </Show> 628 - <Show 629 - when={ 630 - props.def.input!.schema?.properties && 631 - Object.keys(props.def.input!.schema.properties).length > 0 632 - } 633 - > 634 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 635 - <For each={Object.entries(props.def.input!.schema!.properties!)}> 636 - {([name, property]) => ( 637 - <PropertyRow 638 - name={name} 639 - property={property} 640 - required={(props.def.input!.schema?.required || []).includes(name)} 641 - /> 642 - )} 643 - </For> 644 - </div> 645 - </Show> 646 - </div> 647 - </div> 632 + <SchemaSection 633 + title="Input" 634 + encoding={props.def.input!.encoding} 635 + schema={props.def.input!.schema} 636 + /> 648 637 </Show> 649 638 650 639 {/* Output */} 651 640 <Show when={props.def.output}> 652 - <div class="flex flex-col gap-2"> 653 - <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 654 - Output 655 - </h4> 656 - <div class="flex flex-col gap-2 rounded-lg border border-neutral-200 bg-neutral-50/50 p-3 dark:border-neutral-700 dark:bg-neutral-800/30"> 657 - <div class="text-sm"> 658 - <span class="font-semibold">Encoding: </span> 659 - <span class="font-mono">{props.def.output!.encoding}</span> 660 - </div> 661 - <Show when={props.def.output!.schema?.ref}> 662 - <div class="flex items-center gap-2"> 663 - <span class="text-sm font-semibold">Schema:</span> 664 - <TypeBadge type="ref" refType={props.def.output!.schema!.ref} /> 665 - </div> 666 - </Show> 667 - <Show when={props.def.output!.schema?.refs}> 668 - <div class="flex flex-col gap-2"> 669 - <div class="flex items-center gap-2"> 670 - <span class="text-sm font-semibold">Schema (union):</span> 671 - </div> 672 - <UnionBadges refs={props.def.output!.schema!.refs!} /> 673 - </div> 674 - </Show> 675 - <Show 676 - when={ 677 - props.def.output!.schema?.properties && 678 - Object.keys(props.def.output!.schema.properties).length > 0 679 - } 680 - > 681 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 682 - <For each={Object.entries(props.def.output!.schema!.properties!)}> 683 - {([name, property]) => ( 684 - <PropertyRow 685 - name={name} 686 - property={property} 687 - required={(props.def.output!.schema?.required || []).includes(name)} 688 - /> 689 - )} 690 - </For> 691 - </div> 692 - </Show> 693 - </div> 694 - </div> 641 + <SchemaSection 642 + title="Output" 643 + encoding={props.def.output!.encoding} 644 + schema={props.def.output!.schema} 645 + /> 695 646 </Show> 696 647 697 648 {/* Errors */} ··· 700 651 <h4 class="text-sm font-semibold text-neutral-600 uppercase dark:text-neutral-400"> 701 652 Errors 702 653 </h4> 703 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 654 + <div class={CONTAINER_CLASS}> 704 655 <For each={props.def.errors}> 705 656 {(error) => ( 706 657 <div class="flex flex-col gap-1 py-2"> ··· 730 681 ) && hasDefContent() 731 682 } 732 683 > 733 - <div class="divide-y divide-neutral-200 rounded-lg border border-neutral-200 bg-neutral-50/50 px-3 dark:divide-neutral-700 dark:border-neutral-700 dark:bg-neutral-800/30"> 684 + <div class={CONTAINER_CLASS}> 734 685 <PropertyRow name={props.name} property={props.def} hideNameType /> 735 686 </div> 736 687 </Show> ··· 756 707 return ( 757 708 <div class="w-full max-w-4xl px-2"> 758 709 {/* Header */} 759 - <div class="flex flex-col gap-2 border-b border-neutral-300 pb-4 dark:border-neutral-700"> 710 + <div class="flex flex-col gap-2 border-b border-neutral-300 pb-3 dark:border-neutral-700"> 760 711 <h2 class="text-lg font-semibold">{props.schema.id}</h2> 761 712 <div class="flex gap-4 text-sm text-neutral-600 dark:text-neutral-400"> 762 713 <span> ··· 770 721 </div> 771 722 772 723 {/* Definitions */} 773 - <div class="flex flex-col gap-6 pt-4"> 724 + <div class="flex flex-col gap-6 pt-3"> 774 725 <For each={Object.entries(props.schema.defs)}> 775 726 {([name, def]) => <DefSection name={name} def={def} />} 776 727 </For>