A focused Docker Compose management web application.
0
fork

Configure Feed

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

feat: toaster

Brooke dd26f8c3 d21b3ee6

+255 -19
+6 -2
packages/panel/package.json
··· 13 13 "lint": "prettier --check ." 14 14 }, 15 15 "devDependencies": { 16 - "@fortawesome/free-brands-svg-icons": "^6.7.2", 17 - "@fortawesome/free-solid-svg-icons": "^6.7.2", 16 + "@catppuccin/palette": "^1.7.1", 17 + "@fontsource-variable/open-sans": "^5.2.7", 18 + "@fortawesome/fontawesome-common-types": "6.7.2", 19 + "@fortawesome/free-brands-svg-icons": "^6.7", 20 + "@fortawesome/free-regular-svg-icons": "^6.7", 21 + "@fortawesome/free-solid-svg-icons": "^6.7", 18 22 "@sveltejs/adapter-static": "^3.0.10", 19 23 "@sveltejs/kit": "^2.16.0", 20 24 "@sveltejs/vite-plugin-svelte": "^5.0.0",
+1 -1
packages/panel/src/app.html
··· 1 1 <!doctype html> 2 - <html lang="en"> 2 + <html lang="en" class="macchiato"> 3 3 <head> 4 4 <meta charset="utf-8" /> 5 5 <link rel="icon" href="%sveltekit.assets%/favicon.png" />
+47
packages/panel/src/lib/style.scss
··· 1 + @use "@catppuccin/palette/scss/catppuccin"; 2 + @use "sass:map"; 3 + 4 + @each $flavor, $color in catppuccin.$palette { 5 + :root.#{$flavor} { 6 + @each $shade, $value in $color { 7 + --#{$shade}: #{$value}; 8 + } 9 + } 10 + } 11 + 12 + :root { 13 + font-family: "Open Sans Variable", sans-serif; 14 + background-color: var(--base); 15 + color: var(--text); 16 + } 17 + 18 + ::selection { 19 + background-color: var(--overlay2); 20 + opacity: 0.2; 21 + } 22 + 23 + [popover] { 24 + font-family: inherit; 25 + color: inherit; 26 + } 27 + 28 + button.a, 29 + a { 30 + font-family: inherit; 31 + color: var(--blue); 32 + 33 + border-radius: 5px; 34 + background: none; 35 + border: none; 36 + 37 + cursor: pointer; 38 + display: inline-block; 39 + 40 + &:focus-visible { 41 + outline: 2px solid var(--rosewater); 42 + } 43 + 44 + &:hover { 45 + text-decoration: underline; 46 + } 47 + }
+12
packages/panel/src/routes/+layout.svelte
··· 1 + <script lang="ts"> 2 + import "@fontsource-variable/open-sans"; 3 + import "$lib/style.scss"; 4 + 5 + import Toaster from "./Toaster.svelte"; 6 + 7 + let { children } = $props(); 8 + </script> 9 + 10 + {@render children()} 11 + 12 + <Toaster />
+1 -1
packages/panel/src/routes/+page.svelte
··· 5 5 const client = createClient<paths>({ baseUrl: "./" }); 6 6 const login = client.POST("/api/auth/login", { 7 7 body: { 8 - username: "admin", 8 + username: "admi", 9 9 password: "password", 10 10 }, 11 11 });
+2
packages/panel/src/routes/+page.ts
··· 1 + export const prerender = true; 2 + export const ssr = false;
+149
packages/panel/src/routes/Toaster.svelte
··· 1 + <script lang="ts" module> 2 + import type { IconDefinition } from "@fortawesome/fontawesome-common-types"; 3 + 4 + type ToastData = { 5 + color: string; 6 + icon: IconDefinition; 7 + title: string; 8 + description: string; 9 + }; 10 + 11 + const toaster = new Toaster<ToastData>({ closeDelay: 15 * 1000 }); 12 + export const addToast = toaster.addToast; 13 + </script> 14 + 15 + <script lang="ts"> 16 + import { faXmark, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; 17 + import { faCircleXmark } from "@fortawesome/free-regular-svg-icons"; 18 + import { Progress } from "melt/builders"; 19 + import { Toaster } from "melt/builders"; 20 + import { fly } from "svelte/transition"; 21 + import { flip } from "svelte/animate"; 22 + import { Fa } from "svelte-fa"; 23 + </script> 24 + 25 + <button 26 + on:click={() => 27 + addToast({ 28 + data: { 29 + color: "peach", 30 + icon: faTriangleExclamation, 31 + title: "Something could go wrong", 32 + description: "More Information", 33 + }, 34 + })} 35 + > 36 + Add Warning 37 + </button> 38 + 39 + <button 40 + on:click={() => 41 + addToast({ 42 + data: { color: "red", icon: faCircleXmark, title: "Something went wrong", description: "More Information" }, 43 + })} 44 + > 45 + Add Error 46 + </button> 47 + 48 + <div {...toaster.root} class="root"> 49 + {#each toaster.toasts as toast (toast.id)} 50 + {@const progress = new Progress({ value: () => toast.percentage })} 51 + 52 + <div 53 + class="toast" 54 + {...toast.content} 55 + animate:flip={{ duration: 250 }} 56 + transition:fly={{ y: 20, duration: 250 }} 57 + > 58 + <div class="row"> 59 + <h3 {...toast.title}> 60 + <span style:color="var(--{toast.data.color})" style="padding-right: 1px;"> 61 + <Fa icon={toast.data.icon} translateY="0.1" /> 62 + </span> 63 + <span>{toast.data.title}</span> 64 + </h3> 65 + <button class="a" style:color="inherit" {...toast.close} aria-label="dismiss alert"> 66 + <Fa icon={faXmark} /> 67 + </button> 68 + </div> 69 + <div class="row"> 70 + <div {...toast.description}>{toast.data.description}</div> 71 + <div {...progress.root}> 72 + <div {...progress.progress} style:background="var(--{toast.data.color})"></div> 73 + </div> 74 + </div> 75 + </div> 76 + {/each} 77 + </div> 78 + 79 + <style lang="scss"> 80 + .root { 81 + position: fixed; 82 + inset: auto; 83 + bottom: 0px; 84 + right: 0px; 85 + 86 + margin: 0px; 87 + padding: 20px; 88 + 89 + background: none; 90 + border: none; 91 + 92 + display: flex; 93 + flex-direction: column; 94 + justify-content: flex-end; 95 + gap: 0.5rem; 96 + 97 + width: 400px; 98 + height: 100vh; 99 + overflow: hidden; 100 + pointer-events: none; 101 + } 102 + 103 + .toast { 104 + background-color: var(--surface0); 105 + box-shadow: 0 -2px 10px #00000080; 106 + 107 + pointer-events: all; 108 + overflow: hidden; 109 + 110 + border-radius: 10px; 111 + font-size: 14px; 112 + padding: 10px; 113 + 114 + display: flex; 115 + flex-direction: column; 116 + gap: 5px; 117 + } 118 + 119 + .row { 120 + display: flex; 121 + justify-content: space-between; 122 + align-items: center; 123 + } 124 + 125 + h3 { 126 + font-size: inherit; 127 + font-weight: bold; 128 + margin: 0; 129 + 130 + display: flex; 131 + align-items: center; 132 + gap: 5px; 133 + } 134 + 135 + [data-melt-progress-root] { 136 + background-color: var(--base); 137 + 138 + overflow: hidden; 139 + 140 + border-radius: 4px; 141 + height: 4px; 142 + width: 60px; 143 + } 144 + 145 + [data-melt-progress-progress] { 146 + transform: translateX(calc((100% - var(--progress)) * -1)); 147 + height: 100%; 148 + } 149 + </style>
+32 -14
pnpm-lock.yaml
··· 10 10 11 11 packages/panel: 12 12 devDependencies: 13 + '@catppuccin/palette': 14 + specifier: ^1.7.1 15 + version: 1.7.1 16 + '@fontsource-variable/open-sans': 17 + specifier: ^5.2.7 18 + version: 5.2.7 19 + '@fortawesome/fontawesome-common-types': 20 + specifier: 6.7.2 21 + version: 6.7.2 13 22 '@fortawesome/free-brands-svg-icons': 14 - specifier: ^6.7.2 23 + specifier: ^6.7 24 + version: 6.7.2 25 + '@fortawesome/free-regular-svg-icons': 26 + specifier: ^6.7 15 27 version: 6.7.2 16 28 '@fortawesome/free-solid-svg-icons': 17 - specifier: ^6.7.2 29 + specifier: ^6.7 18 30 version: 6.7.2 19 - '@sveltejs/adapter-auto': 20 - specifier: ^6.0.0 21 - version: 6.1.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))) 22 31 '@sveltejs/adapter-static': 23 32 specifier: ^3.0.10 24 33 version: 3.0.10(@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))) ··· 77 86 '@babel/helper-validator-identifier@7.28.5': 78 87 resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} 79 88 engines: {node: '>=6.9.0'} 89 + 90 + '@catppuccin/palette@1.7.1': 91 + resolution: {integrity: sha512-aRc1tbzrevOTV7nFTT9SRdF26w/MIwT4Jwt4fDMc9itRZUDXCuEDBLyz4TQMlqO9ZP8mf5Hu4Jr6D03NLFc6Gw==} 80 92 81 93 '@esbuild/aix-ppc64@0.25.12': 82 94 resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} ··· 243 255 '@floating-ui/utils@0.2.11': 244 256 resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} 245 257 258 + '@fontsource-variable/open-sans@5.2.7': 259 + resolution: {integrity: sha512-wzCLm2STuekK9Fz58DiuBnk4GgJpvvVtAU85a4b06ACNG/UsVjQcCvkUd6R/ETlHfsaykCUZamLRvSXg4KtWuA==} 260 + 246 261 '@fortawesome/fontawesome-common-types@6.7.2': 247 262 resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==} 248 263 engines: {node: '>=6'} 249 264 250 265 '@fortawesome/free-brands-svg-icons@6.7.2': 251 266 resolution: {integrity: sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==} 267 + engines: {node: '>=6'} 268 + 269 + '@fortawesome/free-regular-svg-icons@6.7.2': 270 + resolution: {integrity: sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==} 252 271 engines: {node: '>=6'} 253 272 254 273 '@fortawesome/free-solid-svg-icons@6.7.2': ··· 524 543 resolution: {integrity: sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==} 525 544 peerDependencies: 526 545 acorn: ^8.9.0 527 - 528 - '@sveltejs/adapter-auto@6.1.1': 529 - resolution: {integrity: sha512-cBNt4jgH4KuaNO5gRSB2CZKkGtz+OCZ8lPjRQGjhvVUD4akotnj2weUia6imLl2v07K3IgsQRyM36909miSwoQ==} 530 - peerDependencies: 531 - '@sveltejs/kit': ^2.0.0 532 546 533 547 '@sveltejs/adapter-static@3.0.10': 534 548 resolution: {integrity: sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==} ··· 1022 1036 1023 1037 '@babel/helper-validator-identifier@7.28.5': {} 1024 1038 1039 + '@catppuccin/palette@1.7.1': {} 1040 + 1025 1041 '@esbuild/aix-ppc64@0.25.12': 1026 1042 optional: true 1027 1043 ··· 1111 1127 1112 1128 '@floating-ui/utils@0.2.11': {} 1113 1129 1130 + '@fontsource-variable/open-sans@5.2.7': {} 1131 + 1114 1132 '@fortawesome/fontawesome-common-types@6.7.2': {} 1115 1133 1116 1134 '@fortawesome/free-brands-svg-icons@6.7.2': 1135 + dependencies: 1136 + '@fortawesome/fontawesome-common-types': 6.7.2 1137 + 1138 + '@fortawesome/free-regular-svg-icons@6.7.2': 1117 1139 dependencies: 1118 1140 '@fortawesome/fontawesome-common-types': 6.7.2 1119 1141 ··· 1312 1334 '@sveltejs/acorn-typescript@1.0.9(acorn@8.16.0)': 1313 1335 dependencies: 1314 1336 acorn: 8.16.0 1315 - 1316 - '@sveltejs/adapter-auto@6.1.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)))': 1317 - dependencies: 1318 - '@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)) 1319 1337 1320 1338 '@sveltejs/adapter-static@3.0.10(@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)))': 1321 1339 dependencies:
+5 -1
pnpm-workspace.yaml
··· 1 1 packages: 2 - - "packages/panel" 2 + - packages/panel 3 + 4 + onlyBuiltDependencies: 5 + - '@parcel/watcher' 6 + - esbuild