diff --git a/e2e/i18n.spec.ts b/e2e/i18n.spec.ts index 73b9ce29..ec558fd5 100644 --- a/e2e/i18n.spec.ts +++ b/e2e/i18n.spec.ts @@ -6,6 +6,7 @@ import { waitForHydration } from './support/helpers'; /** Load the saved auth storage state, optionally stripping the locale cookie. */ function loadAuthState(projectName: string, { withoutLocale = false } = {}) { const authFile = path.join(import.meta.dirname, `.auth/user-setup-${projectName}.json`); + // eslint-disable-next-line security/detect-non-literal-fs-filename const state = JSON.parse(fs.readFileSync(authFile, 'utf-8')); if (withoutLocale) { state.cookies = state.cookies.filter((c: { name: string }) => c.name !== 'PARAGLIDE_LOCALE'); diff --git a/e2e/support/global-setup.ts b/e2e/support/global-setup.ts index 3754ac1b..d9d992f0 100644 --- a/e2e/support/global-setup.ts +++ b/e2e/support/global-setup.ts @@ -1,3 +1,4 @@ +/* eslint-disable security/detect-non-literal-fs-filename */ import fs from 'node:fs'; import path from 'path'; diff --git a/eslint.config.js b/eslint.config.js index 1e6f8cb6..1893c1d0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,6 +1,7 @@ import prettier from 'eslint-config-prettier'; import js from '@eslint/js'; import { includeIgnoreFile } from '@eslint/compat'; +import { defineConfig } from 'eslint/config'; import svelte from 'eslint-plugin-svelte'; import betterTailwindcss from 'eslint-plugin-better-tailwindcss'; import security from 'eslint-plugin-security'; @@ -10,7 +11,7 @@ import ts from 'typescript-eslint'; const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); -export default ts.config( +export default defineConfig( includeIgnoreFile(gitignorePath), { ignores: ['src/lib/editor/generated/**'] }, js.configs.recommended, @@ -27,7 +28,9 @@ export default ts.config( 'no-undef': 'off', // It will currently also error on external links or links with query parameters // https://github.com/sveltejs/eslint-plugin-svelte/issues/1353 - 'svelte/no-navigation-without-resolve': 'warn' + 'svelte/no-navigation-without-resolve': 'warn', + // Too common occurance in this project, disabling for now + 'security/detect-object-injection': 'off' } }, { @@ -49,7 +52,15 @@ export default ts.config( } }, rules: { - 'better-tailwindcss/no-unknown-classes': ['warn', { detectComponentClasses: true }] + 'better-tailwindcss/no-unknown-classes': [ + 'warn', + { + detectComponentClasses: true, + // DaisyUIs nestes selectors are not detected by this rule. + // Ignore them to catch outdated classes from DaisyUI v4 Agents seem to love. + ignore: ['dropdown-content', 'tab-active', 'swap-on', 'swap-off', 'menu-disabled'] + } + ] } } ); diff --git a/messages/de.json b/messages/de.json index 8b0bc0b1..e4002e8e 100644 --- a/messages/de.json +++ b/messages/de.json @@ -30,9 +30,11 @@ "header_user_menu": "Benutzermenü", "theme_switch_light": "Zum hellen Modus wechseln", "theme_switch_dark": "Zum dunklen Modus wechseln", + "theme_toggle": "Design umschalten", "page_title_dashboard": "Dashboard", "page_title_default": "Stackable", "page_title_suffix": "Stackable", + "meta_description": "Stackable Unified Data Platform UI – verwalten Sie Ihre Dateninfrastruktur über eine zentrale Oberfläche.", "page_title_trino": "Trino", "setup_steps_label": "Einrichtungsschritte", "language_label": "Sprache", diff --git a/messages/en.json b/messages/en.json index a6ded56d..92c4e3a5 100644 --- a/messages/en.json +++ b/messages/en.json @@ -30,9 +30,11 @@ "header_user_menu": "User menu", "theme_switch_light": "Switch to light mode", "theme_switch_dark": "Switch to dark mode", + "theme_toggle": "Toggle theme", "page_title_dashboard": "Dashboard", "page_title_default": "Stackable", "page_title_suffix": "Stackable", + "meta_description": "Stackable Unified Data Platform UI — manage your data infrastructure from a single interface.", "page_title_trino": "Trino", "setup_steps_label": "Setup steps", "language_label": "Language", diff --git a/src/app.css b/src/app.css index 30b34902..07487488 100644 --- a/src/app.css +++ b/src/app.css @@ -1,6 +1,16 @@ @import 'tailwindcss'; @plugin 'daisyui'; +/* + * DaisyUI's shipped dark-theme --color-primary (oklch(58% 0.233 277.117)) only reaches + * ~3.3:1 contrast against base-100/base-200, failing WCAG AA (4.5:1) for text-primary used + * as body text (e.g. active nav labels). This keeps the same hue while satisfying contrast. + */ +[data-theme='dark'] { + --color-primary: oklch(70% 0.17 277.117); + --color-primary-content: oklch(24% 0.12 277.117); +} + /* Subtle highlight for the currently executing statement in the Monaco editor */ .highlighted-statement { background-color: oklch(from var(--color-primary) l c h / 0.08); @@ -28,27 +38,29 @@ progress.progress::-moz-progress-bar { * Visible scrollbars for preview panels. Uses DaisyUI semantic color variables * so the thumb adapts to both light and dark themes automatically. */ -.preview-scroll { - scrollbar-width: thin; - /* Use currentColor so Firefox resolves the thumb colour immediately at paint - time rather than deferring CSS custom-property resolution. */ - scrollbar-color: color-mix(in oklch, currentColor 28%, transparent) transparent; -} +@layer components { + .preview-scroll { + scrollbar-width: thin; + /* Use currentColor so Firefox resolves the thumb colour immediately at paint + time rather than deferring CSS custom-property resolution. */ + scrollbar-color: color-mix(in oklch, currentColor 28%, transparent) transparent; + } -.preview-scroll::-webkit-scrollbar { - width: 8px; - height: 8px; -} + .preview-scroll::-webkit-scrollbar { + width: 8px; + height: 8px; + } -.preview-scroll::-webkit-scrollbar-track { - background: transparent; -} + .preview-scroll::-webkit-scrollbar-track { + background: transparent; + } -.preview-scroll::-webkit-scrollbar-thumb { - background-color: color-mix(in oklch, currentColor 28%, transparent); - border-radius: 4px; -} + .preview-scroll::-webkit-scrollbar-thumb { + background-color: color-mix(in oklch, currentColor 28%, transparent); + border-radius: 4px; + } -.preview-scroll::-webkit-scrollbar-thumb:hover { - background-color: color-mix(in oklch, currentColor 50%, transparent); + .preview-scroll::-webkit-scrollbar-thumb:hover { + background-color: color-mix(in oklch, currentColor 50%, transparent); + } } diff --git a/src/lib/components/TabBar.svelte b/src/lib/components/TabBar.svelte index 53586b2c..d7f9e351 100644 --- a/src/lib/components/TabBar.svelte +++ b/src/lib/components/TabBar.svelte @@ -124,72 +124,74 @@ } -
- {#each items as item, index (item.id)} - {@const isActive = item.id === activeId} - {@const isDragOver = - dragOverIndex === index && dragFromIndex !== null && dragFromIndex !== index} -
- - - {#if showClose && item.closable !== false} - {/if} -
- {/each} + + {#if showClose && item.closable !== false} + + {/if} +
+ {/each} + {#if onAdd && showAdd} diff --git a/src/lib/components/layout/header/UserMenu.svelte b/src/lib/components/layout/header/UserMenu.svelte index 0641b735..0fa6322c 100644 --- a/src/lib/components/layout/header/UserMenu.svelte +++ b/src/lib/components/layout/header/UserMenu.svelte @@ -1,4 +1,5 @@ + + + + {@render children()}