A focused Docker Compose management web application.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: project search bar

Brooke e0293e06 efcc7452

+63 -4
+1
packages/panel/package.json
··· 30 30 "parse-sse": "^0.1.0", 31 31 "prettier": "^3.4.2", 32 32 "prettier-plugin-svelte": "^3.3.3", 33 + "runed": "^0.37.1", 33 34 "sass": "^1.89.0", 34 35 "svelte": "^5.0.0", 35 36 "svelte-check": "^4.0.0",
+4
packages/panel/src/lib/style.scss
··· 115 115 &:focus-visible { 116 116 outline: 2px solid var(--lavender); 117 117 } 118 + 119 + &::placeholder { 120 + color: var(--subtext0); 121 + } 118 122 } 119 123 120 124 @media (min-width: 426px) {
+28 -4
packages/panel/src/routes/(authenticated)/projects/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import StatusIcon, { type LuminaryStatus } from "$lib/component/StatusIcon.svelte"; 3 + import { faMagnifyingGlass, faMinus, faPlus } from "@fortawesome/free-solid-svg-icons"; 3 4 import { Accordion } from "melt/builders"; 4 5 import { getList } from "$lib/api"; 6 + import { Debounced } from "runed"; 5 7 import Fa from "svelte-fa"; 6 - import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons"; 7 8 8 9 const ORDER = ["healthy", "running", "exited", "paused", "down", "paused"] as LuminaryStatus[]; 9 10 10 11 const accordion = new Accordion({ multiple: true, value: ORDER }); 11 12 13 + let search = $state(""); 14 + const debounced = new Debounced(() => search, 250); 15 + 12 16 let groups = $derived( 13 - Object.entries(Object.groupBy(Object.values(getList()), (project) => project.status)).toSorted( 14 - ([a], [b]) => ORDER.indexOf(a as LuminaryStatus) - ORDER.indexOf(b as LuminaryStatus), 15 - ), 17 + Object.entries( 18 + Object.groupBy( 19 + Object.values(getList()).filter((p) => p.name.includes(debounced.current)), 20 + (project) => project.status, 21 + ), 22 + ).toSorted(([a], [b]) => ORDER.indexOf(a as LuminaryStatus) - ORDER.indexOf(b as LuminaryStatus)), 16 23 ); 17 24 </script> 18 25 19 26 <div class="flexc gap-10 full" {...accordion.root}> 27 + <div class="flexr center gap-10"> 28 + <Fa icon={faMagnifyingGlass} size="lg" /> 29 + <input class="full" type="text" placeholder="Search projects..." bind:value={search} /> 30 + </div> 31 + 20 32 {#each groups as [status, projects]} 21 33 {@const item = accordion.getItem({ id: status })} 22 34 <button class="a divider" {...item.trigger} aria-label="toggle {status} projects"> ··· 41 53 </div> 42 54 {/if} 43 55 {/each} 56 + 57 + {#if debounced.current} 58 + <button 59 + class="a" 60 + onclick={() => { 61 + search = ""; 62 + debounced.setImmediately(""); 63 + }} 64 + > 65 + Clear search filter 66 + </button> 67 + {/if} 44 68 </div> 45 69 46 70 <style lang="scss">
+30
pnpm-lock.yaml
··· 61 61 prettier-plugin-svelte: 62 62 specifier: ^3.3.3 63 63 version: 3.5.1(prettier@3.8.1)(svelte@5.53.7) 64 + runed: 65 + specifier: ^0.37.1 66 + version: 0.37.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.7)(vite@6.4.1(@types/node@25.3.5)(sass@1.97.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@6.4.1(@types/node@25.3.5)(sass@1.97.3)))(svelte@5.53.7) 64 67 sass: 65 68 specifier: ^1.89.0 66 69 version: 1.97.3 ··· 797 800 lodash.merge@4.6.2: 798 801 resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 799 802 803 + lz-string@1.5.0: 804 + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} 805 + hasBin: true 806 + 800 807 magic-string@0.30.21: 801 808 resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 802 809 ··· 900 907 peerDependencies: 901 908 svelte: ^5.7.0 902 909 910 + runed@0.37.1: 911 + resolution: {integrity: sha512-MeFY73xBW8IueWBm012nNFIGy19WUGPLtknavyUPMpnyt350M47PhGSGrGoSLbidwn+Zlt/O0cp8/OZE3LASWA==} 912 + peerDependencies: 913 + '@sveltejs/kit': ^2.21.0 914 + svelte: ^5.7.0 915 + zod: ^4.1.0 916 + peerDependenciesMeta: 917 + '@sveltejs/kit': 918 + optional: true 919 + zod: 920 + optional: true 921 + 903 922 sade@1.8.1: 904 923 resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 905 924 engines: {node: '>=6'} ··· 1579 1598 1580 1599 lodash.merge@4.6.2: {} 1581 1600 1601 + lz-string@1.5.0: {} 1602 + 1582 1603 magic-string@0.30.21: 1583 1604 dependencies: 1584 1605 '@jridgewell/sourcemap-codec': 1.5.5 ··· 1697 1718 dependencies: 1698 1719 esm-env: 1.2.2 1699 1720 svelte: 5.53.7 1721 + 1722 + runed@0.37.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.7)(vite@6.4.1(@types/node@25.3.5)(sass@1.97.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@6.4.1(@types/node@25.3.5)(sass@1.97.3)))(svelte@5.53.7): 1723 + dependencies: 1724 + dequal: 2.0.3 1725 + esm-env: 1.2.2 1726 + lz-string: 1.5.0 1727 + svelte: 5.53.7 1728 + optionalDependencies: 1729 + '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.53.7)(vite@6.4.1(@types/node@25.3.5)(sass@1.97.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@6.4.1(@types/node@25.3.5)(sass@1.97.3)) 1700 1730 1701 1731 sade@1.8.1: 1702 1732 dependencies: