fix(ci): build shared packages before tests and fix formatting

- Add build:packages step to all test.yml jobs (fixes @manacore/shared-nestjs-auth not found)
- Handle missing coverage artifacts gracefully in test-coverage.yml
- Update .prettierignore to exclude apps-archived/ and problematic files
- Format all source files to pass CI checks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Wuesteon 2025-12-01 23:15:00 +01:00
parent 5282f5545b
commit 0ebfde0851
163 changed files with 15247 additions and 14677 deletions

View file

@ -13,7 +13,15 @@
header?: Snippet;
}
let { items, direction = 'down', label, icon, isOpen = false, onToggle, header }: Props = $props();
let {
items,
direction = 'down',
label,
icon,
isOpen = false,
onToggle,
header,
}: Props = $props();
let internalOpen = $state(false);
let triggerButton: HTMLButtonElement;
@ -90,13 +98,13 @@
sparkle:
'M12 2L13.09 8.26L18 6L15.74 10.91L22 12L15.74 13.09L18 18L13.09 15.74L12 22L10.91 15.74L6 18L8.26 13.09L2 12L8.26 10.91L6 6L10.91 8.26L12 2Z',
leaf: 'M6.5 21.5C3.5 18.5 3.5 12.5 6.5 8.5C9.5 4.5 15 3 20 3C20 8 18.5 13.5 14.5 16.5C10.5 19.5 4.5 19.5 4.5 19.5M6.5 21.5L4.5 19.5M6.5 21.5C6.5 21.5 12 18 14.5 16.5',
hexagon:
'M12 2L21.5 7.5V16.5L12 22L2.5 16.5V7.5L12 2Z',
hexagon: 'M12 2L21.5 7.5V16.5L12 22L2.5 16.5V7.5L12 2Z',
waves:
'M2 12C2 12 5 8 9 8C13 8 15 12 15 12C15 12 17 16 21 16M2 17C2 17 5 13 9 13C13 13 15 17 15 17C15 17 17 21 21 21M2 7C2 7 5 3 9 3C13 3 15 7 15 7C15 7 17 11 21 11',
// User menu icons
user: 'M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z',
settings: 'M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93s.844.083 1.16-.175l.713-.57a1.125 1.125 0 011.578.112l.773.773a1.125 1.125 0 01.112 1.578l-.57.713c-.258.316-.29.756-.175 1.16s.506.71.93.78l.894.15c.542.09.94.56.94 1.109v1.094c0 .55-.398 1.02-.94 1.11l-.894.149c-.424.07-.764.384-.93.78s-.083.844.175 1.16l.57.713a1.125 1.125 0 01-.112 1.578l-.773.773a1.125 1.125 0 01-1.578.112l-.713-.57c-.316-.258-.756-.29-1.16-.175s-.71.506-.78.93l-.15.894c-.09.542-.56.94-1.109.94h-1.094c-.55 0-1.02-.398-1.11-.94l-.149-.894c-.07-.424-.384-.764-.78-.93s-.844-.083-1.16.175l-.713.57a1.125 1.125 0 01-1.578-.112l-.773-.773a1.125 1.125 0 01-.112-1.578l.57-.713c.258-.316.29-.756.175-1.16s-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.764-.384.93-.78s.083-.844-.175-1.16l-.57-.713a1.125 1.125 0 01.112-1.578l.773-.773a1.125 1.125 0 011.578-.112l.713.57c.316.258.756.29 1.16.175s.71-.506.78-.93l.15-.894zM15 12a3 3 0 11-6 0 3 3 0 016 0z',
settings:
'M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93s.844.083 1.16-.175l.713-.57a1.125 1.125 0 011.578.112l.773.773a1.125 1.125 0 01.112 1.578l-.57.713c-.258.316-.29.756-.175 1.16s.506.71.93.78l.894.15c.542.09.94.56.94 1.109v1.094c0 .55-.398 1.02-.94 1.11l-.894.149c-.424.07-.764.384-.93.78s-.083.844.175 1.16l.57.713a1.125 1.125 0 01-.112 1.578l-.773.773a1.125 1.125 0 01-1.578.112l-.713-.57c-.316-.258-.756-.29-1.16-.175s-.71.506-.78.93l-.15.894c-.09.542-.56.94-1.109.94h-1.094c-.55 0-1.02-.398-1.11-.94l-.149-.894c-.07-.424-.384-.764-.78-.93s-.844-.083-1.16.175l-.713.57a1.125 1.125 0 01-1.578-.112l-.773-.773a1.125 1.125 0 01-.112-1.578l.57-.713c.258-.316.29-.756.175-1.16s-.506-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.764-.384.93-.78s.083-.844-.175-1.16l-.57-.713a1.125 1.125 0 01.112-1.578l.773-.773a1.125 1.125 0 011.578-.112l.713.57c.316.258.756.29 1.16.175s.71-.506.78-.93l.15-.894zM15 12a3 3 0 11-6 0 3 3 0 016 0z',
logout:
'M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1',
// App icons
@ -156,7 +164,10 @@
{#each items.filter((i) => !i.disabled) as item, i (item.id)}
{#if item.divider}
<div class="dropdown-divider" style="animation-delay: {(header ? i + 1 : i) * 15}ms"></div>
<div
class="dropdown-divider"
style="animation-delay: {(header ? i + 1 : i) * 15}ms"
></div>
{:else}
<button
onclick={() => handleItemClick(item)}
@ -194,7 +205,13 @@
/>
</svg>
{:else if item.submenu && item.submenu.length > 0}
<svg class="chevron-submenu" class:rotated={openSubmenuId === item.id} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg
class="chevron-submenu"
class:rotated={openSubmenuId === item.id}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"

View file

@ -1,6 +1,12 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import type { PillNavItem, PillDropdownItem, PillNavElement, PillTabGroupConfig, PillAppItem } from './types';
import type {
PillNavItem,
PillDropdownItem,
PillNavElement,
PillTabGroupConfig,
PillAppItem,
} from './types';
import PillDropdown from './PillDropdown.svelte';
import PillTabGroup from './PillTabGroup.svelte';
@ -256,7 +262,8 @@
creditCard:
'M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z',
search: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z',
heart: 'M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z',
heart:
'M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z',
list: 'M4 6h16M4 10h16M4 14h16M4 18h16',
compass:
'M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM16.24 7.76L14.12 14.12L7.76 16.24L9.88 9.88L16.24 7.76Z',
@ -379,7 +386,7 @@
{/if}
{/each}
<!-- Theme Variant Selector -->
<!-- Theme Variant Selector -->
{#if showThemeVariants && themeVariantItems.length > 0}
<PillDropdown
items={themeVariantItems}
@ -397,7 +404,12 @@
title="Light mode"
>
<svg class="mode-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d={getIconPath('sun')} />
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d={getIconPath('sun')}
/>
</svg>
</button>
<button
@ -408,7 +420,12 @@
title="Dark mode"
>
<svg class="mode-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d={getIconPath('moon')} />
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d={getIconPath('moon')}
/>
</svg>
</button>
<button
@ -420,7 +437,12 @@
>
<svg class="mode-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<rect x="2" y="3" width="20" height="14" rx="2" stroke-width="2" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 21h8M12 17v4" />
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 21h8M12 17v4"
/>
</svg>
</button>
</div>
@ -1086,7 +1108,9 @@
border-radius: 9999px !important;
background: rgba(245, 245, 245, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.1) !important;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
color: #374151 !important;
}

View file

@ -113,7 +113,9 @@
>
<div
class="status-indicator"
style="background-color: {getStatusColor(app.status)}; box-shadow: 0 0 8px {getStatusColor(app.status)};"
style="background-color: {getStatusColor(
app.status
)}; box-shadow: 0 0 8px {getStatusColor(app.status)};"
></div>
<div class="app-icon-wrapper">
@ -142,26 +144,29 @@
aria-modal="true"
tabindex="-1"
>
<button
onclick={closeModal}
class="modal-close-btn"
aria-label="Close modal"
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<button onclick={closeModal} class="modal-close-btn" aria-label="Close modal">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 6L6 18M6 6l12 12" />
</svg>
</button>
<div
bind:this={modalScrollContainer}
class="modal-scroll-container scrollbar-hide"
>
<div bind:this={modalScrollContainer} class="modal-scroll-container scrollbar-hide">
<div class="modal-cards-wrapper">
{#each apps as app, index}
<div
class="modal-card"
class:active={selectedApp === index}
style="transform: perspective(1000px) rotateX({cardRotations[index]?.rotateX || 0}deg) rotateY({cardRotations[index]?.rotateY || 0}deg);"
style="transform: perspective(1000px) rotateX({cardRotations[index]?.rotateX ||
0}deg) rotateY({cardRotations[index]?.rotateY || 0}deg);"
onclick={(e) => {
e.stopPropagation();
selectedApp = index;
@ -274,7 +279,9 @@
border: 1px solid rgba(255, 255, 255, 0.1);
background-color: rgba(255, 255, 255, 0.06);
backdrop-filter: blur(10px);
transition: transform 0.2s ease, background-color 0.2s ease;
transition:
transform 0.2s ease,
background-color 0.2s ease;
/* Staggered entrance animation */
animation: fadeInUp 0.4s ease-out both;
animation-delay: calc(0.3s + var(--index) * 0.08s);
@ -363,7 +370,8 @@
}
@keyframes pulse {
0%, 100% {
0%,
100% {
opacity: 1;
}
50% {
@ -418,7 +426,9 @@
background-color: rgba(255, 255, 255, 0.1);
color: #fff;
cursor: pointer;
transition: background-color 0.2s, transform 0.2s;
transition:
background-color 0.2s,
transform 0.2s;
}
.modal-close-btn:hover {
@ -455,7 +465,9 @@
background-color: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(20px);
transform-style: preserve-3d;
transition: transform 0.1s ease-out, background-color 0.2s ease;
transition:
transform 0.1s ease-out,
background-color 0.2s ease;
animation: modalCardIn 0.3s ease-out both;
}
@ -593,7 +605,9 @@
font-weight: 600;
border: 2px solid;
cursor: pointer;
transition: opacity 0.2s, transform 0.2s;
transition:
opacity 0.2s,
transform 0.2s;
color: #fff;
}
@ -609,8 +623,12 @@
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes modalCardIn {

View file

@ -135,7 +135,14 @@
>
{#if loading}
<svg class="h-4 w-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
/>
<path
class="opacity-75"
fill="currentColor"

View file

@ -71,7 +71,9 @@
>
{#if showHeader}
<!-- Header -->
<div class="flex items-center justify-between p-6 border-b border-black/10 dark:border-white/10">
<div
class="flex items-center justify-between p-6 border-b border-black/10 dark:border-white/10"
>
<div class="flex items-center gap-3 flex-1">
{#if icon}
{@render icon()}

View file

@ -1,5 +1,11 @@
<script lang="ts">
import { MANA_APPS, APP_URLS, APP_STATUS_LABELS, type ManaApp, type AppIconId } from '@manacore/shared-branding';
import {
MANA_APPS,
APP_URLS,
APP_STATUS_LABELS,
type ManaApp,
type AppIconId,
} from '@manacore/shared-branding';
interface Props {
/** Current app ID to highlight */
@ -12,12 +18,7 @@
onAppClick?: (app: ManaApp) => void;
}
let {
currentAppId,
title = 'Alle Apps',
locale = 'de',
onAppClick,
}: Props = $props();
let { currentAppId, title = 'Alle Apps', locale = 'de', onAppClick }: Props = $props();
// Filter active apps (non-archived)
const apps = $derived(MANA_APPS.filter((app) => !app.archived));
@ -155,13 +156,7 @@
<!-- Modal -->
{#if selectedAppIndex !== null}
<div
class="modal-overlay"
onclick={closeModal}
role="dialog"
aria-modal="true"
tabindex="-1"
>
<div class="modal-overlay" onclick={closeModal} role="dialog" aria-modal="true" tabindex="-1">
<button onclick={closeModal} class="modal-close-btn" aria-label="Close modal">
<svg
width="24"
@ -202,7 +197,10 @@
tabindex="0"
>
<div class="modal-card-status">
<div class="modal-status-dot" style="background-color: {getStatusColor(app.status)};"></div>
<div
class="modal-status-dot"
style="background-color: {getStatusColor(app.status)};"
></div>
<span class="modal-status-label">{statusLabels[app.status]}</span>
</div>
@ -224,7 +222,9 @@
<div class="modal-app-action">
{#if app.comingSoon}
<span class="modal-coming-soon">{locale === 'de' ? 'Demnächst' : 'Coming Soon'}</span>
<span class="modal-coming-soon"
>{locale === 'de' ? 'Demnächst' : 'Coming Soon'}</span
>
{:else}
<button
class="modal-open-btn"
@ -303,7 +303,10 @@
border: 1px solid rgba(0, 0, 0, 0.08);
background-color: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
transition:
transform 0.2s ease,
box-shadow 0.2s ease,
border-color 0.2s ease;
text-align: center;
}
@ -427,7 +430,9 @@
background-color: rgba(255, 255, 255, 0.1);
color: #fff;
cursor: pointer;
transition: background-color 0.2s, transform 0.2s;
transition:
background-color 0.2s,
transform 0.2s;
}
.modal-close-btn:hover {
@ -473,7 +478,9 @@
background-color: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(20px);
transform-style: preserve-3d;
transition: transform 0.1s ease-out, background-color 0.2s ease;
transition:
transform 0.1s ease-out,
background-color 0.2s ease;
animation: modalCardIn 0.3s ease-out both;
}
@ -575,7 +582,9 @@
font-weight: 600;
border: 2px solid;
cursor: pointer;
transition: opacity 0.2s, transform 0.2s;
transition:
opacity 0.2s,
transform 0.2s;
color: #fff;
}

View file

@ -33,7 +33,9 @@
</script>
<div
class="settings-danger-button {border ? 'settings-danger-button--border' : ''} {disabled ? 'settings-danger-button--disabled' : ''} {className}"
class="settings-danger-button {border ? 'settings-danger-button--border' : ''} {disabled
? 'settings-danger-button--disabled'
: ''} {className}"
>
<div class="settings-danger-button__content">
{#if icon}
@ -49,12 +51,7 @@
</div>
</div>
<button
type="button"
{onclick}
class="settings-danger-button__button"
{disabled}
>
<button type="button" {onclick} class="settings-danger-button__button" {disabled}>
{buttonText || label}
</button>
</div>

View file

@ -10,11 +10,7 @@
children: Snippet;
}
let {
title = 'Danger Zone',
class: className = '',
children,
}: Props = $props();
let { title = 'Danger Zone', class: className = '', children }: Props = $props();
</script>
<section class="settings-danger-zone {className}">

View file

@ -14,13 +14,7 @@
children: Snippet;
}
let {
title,
subtitle,
maxWidth = 'md',
class: className = '',
children,
}: Props = $props();
let { title, subtitle, maxWidth = 'md', class: className = '', children }: Props = $props();
const maxWidthClasses = {
sm: 'max-w-lg',

View file

@ -40,7 +40,9 @@
{#if href}
<a
{href}
class="settings-row {border ? 'settings-row--border' : ''} settings-row--clickable {disabled ? 'settings-row--disabled' : ''} {className}"
class="settings-row {border ? 'settings-row--border' : ''} settings-row--clickable {disabled
? 'settings-row--disabled'
: ''} {className}"
>
<div class="settings-row__content">
{#if icon}
@ -69,7 +71,9 @@
<button
type="button"
{onclick}
class="settings-row {border ? 'settings-row--border' : ''} settings-row--clickable {disabled ? 'settings-row--disabled' : ''} {className}"
class="settings-row {border ? 'settings-row--border' : ''} settings-row--clickable {disabled
? 'settings-row--disabled'
: ''} {className}"
{disabled}
>
<div class="settings-row__content">
@ -97,7 +101,9 @@
</button>
{:else}
<div
class="settings-row {border ? 'settings-row--border' : ''} {disabled ? 'settings-row--disabled' : ''} {className}"
class="settings-row {border ? 'settings-row--border' : ''} {disabled
? 'settings-row--disabled'
: ''} {className}"
>
<div class="settings-row__content">
{#if icon}

View file

@ -12,12 +12,7 @@
children: Snippet;
}
let {
title,
icon,
class: className = '',
children,
}: Props = $props();
let { title, icon, class: className = '', children }: Props = $props();
</script>
<section class="settings-section {className}">

View file

@ -39,7 +39,9 @@
</script>
<div
class="settings-toggle {border ? 'settings-toggle--border' : ''} {disabled ? 'settings-toggle--disabled' : ''} {className}"
class="settings-toggle {border ? 'settings-toggle--border' : ''} {disabled
? 'settings-toggle--disabled'
: ''} {className}"
>
<div class="settings-toggle__content">
{#if icon}