mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:21:10 +02:00
refactor(apps): automated SVG-to-Phosphor migration across all apps
Script-based migration of inline SVG icons to Phosphor components. Covers todo, manacore, mukke, chat, zitare, times, citycorners, inventar, uload, playground, presi, picture, moodlit, storage, news, wisekeep, clock, matrix, manadeck, skilltree, and photos. ~190 SVGs replaced across 115 files. Remaining SVGs are spinners, brand logos, or decorative/chart SVGs that don't map to Phosphor. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f58d58ff99
commit
504e7756a7
115 changed files with 781 additions and 3084 deletions
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { Check, X } from '@manacore/shared-icons';
|
||||
import type { Template, AIModel } from '@chat/types';
|
||||
import { chatService } from '$lib/services/chat';
|
||||
import { onMount } from 'svelte';
|
||||
|
|
@ -183,14 +184,7 @@
|
|||
aria-label="Farbe {color}"
|
||||
>
|
||||
{#if selectedColor === color}
|
||||
<svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={16} weight="bold" class="text-white" />
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
|
|
@ -238,23 +232,9 @@
|
|||
{documentMode ? 'bg-primary' : 'bg-muted-foreground'}"
|
||||
>
|
||||
{#if documentMode}
|
||||
<svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={16} class="text-white" />
|
||||
{:else}
|
||||
<svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} class="text-white" />
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -105,14 +105,7 @@
|
|||
border={false}
|
||||
>
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash />
|
||||
{/snippet}
|
||||
</SettingsDangerButton>
|
||||
</SettingsDangerZone>
|
||||
|
|
@ -121,14 +114,7 @@
|
|||
<!-- About Section -->
|
||||
<SettingsSection title="Über die App">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info />
|
||||
{/snippet}
|
||||
|
||||
<SettingsCard>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import { chatService } from '$lib/services/chat';
|
||||
import { PageHeader } from '@manacore/shared-ui';
|
||||
import type { Space, Conversation, AIModel } from '@chat/types';
|
||||
import { ChatCircle } from '@manacore/shared-icons';
|
||||
|
||||
const spaceId = $derived($page.params.id ?? '');
|
||||
|
||||
|
|
@ -128,19 +129,7 @@
|
|||
|
||||
{#if conversations.length === 0}
|
||||
<div class="text-center py-12 bg-surface rounded-xl border border-border">
|
||||
<svg
|
||||
class="w-12 h-12 text-muted-foreground mx-auto mb-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1.5"
|
||||
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
||||
/>
|
||||
</svg>
|
||||
<ChatCircle size={48} class="text-muted-foreground mx-auto mb-3" />
|
||||
<p class="text-muted-foreground">Noch keine Konversationen in diesem Space.</p>
|
||||
</div>
|
||||
{:else}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import { CaretLeft, Plus, MapPin, MapTrifold, UsersThree, Heart } from '@manacore/shared-icons';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { page } from '$app/stores';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
|
|
@ -71,9 +72,7 @@
|
|||
<div>
|
||||
<div class="mb-1 flex items-center gap-2">
|
||||
<a href="/" class="text-foreground-secondary hover:text-primary transition-colors">
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-foreground">{city?.name}</h1>
|
||||
</div>
|
||||
|
|
@ -93,9 +92,7 @@
|
|||
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-white shadow-md transition-all hover:bg-primary/90 hover:shadow-lg"
|
||||
title={$_('add.title')}
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
<Plus size={20} weight="bold" />
|
||||
</a>
|
||||
</header>
|
||||
|
||||
|
|
@ -106,24 +103,7 @@
|
|||
<!-- Location count -->
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex h-9 w-9 items-center justify-center rounded-lg bg-primary/10 text-primary">
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 10.5a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MapPin size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg font-semibold text-foreground">{stats.locationCount}</p>
|
||||
|
|
@ -139,19 +119,7 @@
|
|||
<div
|
||||
class="flex h-9 w-9 items-center justify-center rounded-lg bg-green-500/10 text-green-600 dark:text-green-400"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M9 6.75V15m6-6v8.25m.503 3.498l4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 00-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MapTrifold size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg font-semibold text-foreground">{stats.hasCoordinates}</p>
|
||||
|
|
@ -168,19 +136,7 @@
|
|||
<div
|
||||
class="flex h-9 w-9 items-center justify-center rounded-lg bg-amber-500/10 text-amber-600 dark:text-amber-400"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"
|
||||
/>
|
||||
</svg>
|
||||
<UsersThree size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg font-semibold text-foreground">{stats.contributorCount}</p>
|
||||
|
|
@ -276,25 +232,9 @@
|
|||
title={favoriteIds.has(location.id) ? $_('favorites.remove') : $_('favorites.add')}
|
||||
>
|
||||
{#if favoriteIds.has(location.id)}
|
||||
<svg class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M11.645 20.91l-.007-.003-.022-.012a15.247 15.247 0 01-.383-.218 25.18 25.18 0 01-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0112 5.052 5.5 5.5 0 0116.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 01-4.244 3.17 15.247 15.247 0 01-.383.219l-.022.012-.007.004-.003.001a.752.752 0 01-.704 0l-.003-.001z"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={20} weight="fill" class="text-red-500" />
|
||||
{:else}
|
||||
<svg
|
||||
class="h-5 w-5 text-white"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={20} class="text-white" />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { getContext } from 'svelte';
|
||||
import { CaretLeft } from '@manacore/shared-icons';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { page } from '$app/stores';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
|
|
@ -191,9 +192,7 @@
|
|||
href="/cities/{citySlug}"
|
||||
class="text-foreground-secondary hover:text-primary transition-colors"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-foreground">{$_('add.title')}</h1>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,20 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { browser } from '$app/environment';
|
||||
import {
|
||||
CaretLeft,
|
||||
Check,
|
||||
ShareNetwork,
|
||||
Heart,
|
||||
Plus,
|
||||
MapPin,
|
||||
PencilSimple,
|
||||
Trash,
|
||||
MapTrifold,
|
||||
NavigationArrow,
|
||||
ArrowSquareOut,
|
||||
Star,
|
||||
} from '@manacore/shared-icons';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { favoritesStore } from '$lib/stores/favorites.svelte';
|
||||
|
|
@ -299,9 +313,7 @@
|
|||
href="/cities/{citySlug}"
|
||||
class="flex h-10 w-10 items-center justify-center rounded-full bg-black/30 text-white backdrop-blur-sm transition-colors hover:bg-black/50"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
<CaretLeft size={20} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -313,29 +325,9 @@
|
|||
title={$_('detail.share')}
|
||||
>
|
||||
{#if shareSuccess}
|
||||
<svg
|
||||
class="h-5 w-5 text-green-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
||||
</svg>
|
||||
<Check size={20} class="text-green-400" />
|
||||
{:else}
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M7.217 10.907a2.25 2.25 0 100 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186l9.566-5.314m-9.566 7.5l9.566 5.314m0 0a2.25 2.25 0 103.935 2.186 2.25 2.25 0 00-3.935-2.186zm0-12.814a2.25 2.25 0 103.933-2.185 2.25 2.25 0 00-3.933 2.185z"
|
||||
/>
|
||||
</svg>
|
||||
<ShareNetwork size={20} />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
@ -346,25 +338,9 @@
|
|||
title={favoriteIds.has(location.id) ? $_('favorites.remove') : $_('favorites.add')}
|
||||
>
|
||||
{#if favoriteIds.has(location.id)}
|
||||
<svg class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M11.645 20.91l-.007-.003-.022-.012a15.247 15.247 0 01-.383-.218 25.18 25.18 0 01-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0112 5.052 5.5 5.5 0 0116.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 01-4.244 3.17 15.247 15.247 0 01-.383.219l-.022.012-.007.004-.003.001a.752.752 0 01-.704 0l-.003-.001z"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={20} weight="fill" class="text-red-500" />
|
||||
{:else}
|
||||
<svg
|
||||
class="h-5 w-5 text-white"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={20} class="text-white" />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -421,15 +397,7 @@
|
|||
class="flex h-16 w-20 flex-shrink-0 items-center justify-center rounded-lg border-2 border-dashed border-border text-foreground-secondary transition-colors hover:border-primary hover:text-primary"
|
||||
title={$_('gallery.addPhoto')}
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
@ -476,24 +444,7 @@
|
|||
<h1 class="text-3xl font-bold text-foreground">{location.name}</h1>
|
||||
{#if location.address}
|
||||
<p class="mt-2 flex items-center gap-1.5 text-foreground-secondary">
|
||||
<svg
|
||||
class="h-4 w-4 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 10.5a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MapPin size={16} class="flex-shrink-0" />
|
||||
{location.address}
|
||||
</p>
|
||||
{/if}
|
||||
|
|
@ -562,17 +513,13 @@
|
|||
<div class="flex items-center gap-1.5">
|
||||
<div class="flex items-center gap-0.5">
|
||||
{#each Array(5) as _, i}
|
||||
<svg
|
||||
class="h-4 w-4 {i < Math.round(location.reviewStats.averageRating)
|
||||
<Star
|
||||
size={16}
|
||||
weight="fill"
|
||||
class={i < Math.round(location.reviewStats.averageRating)
|
||||
? 'text-amber-400'
|
||||
: 'text-gray-300 dark:text-gray-600'}"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"
|
||||
/>
|
||||
</svg>
|
||||
: 'text-gray-300 dark:text-gray-600'}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<span class="text-sm font-medium text-foreground">
|
||||
|
|
@ -608,17 +555,13 @@
|
|||
onclick={() => (reviewRating = star)}
|
||||
class="transition-transform hover:scale-110"
|
||||
>
|
||||
<svg
|
||||
class="h-8 w-8 {star <= reviewRating
|
||||
<Star
|
||||
size={32}
|
||||
weight="fill"
|
||||
class={star <= reviewRating
|
||||
? 'text-amber-400'
|
||||
: 'text-gray-300 dark:text-gray-600'}"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"
|
||||
/>
|
||||
</svg>
|
||||
: 'text-gray-300 dark:text-gray-600'}
|
||||
/>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
@ -645,17 +588,13 @@
|
|||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-1">
|
||||
{#each Array(5) as _, i}
|
||||
<svg
|
||||
class="h-4 w-4 {i < review.rating
|
||||
<Star
|
||||
size={16}
|
||||
weight="fill"
|
||||
class={i < review.rating
|
||||
? 'text-amber-400'
|
||||
: 'text-gray-300 dark:text-gray-600'}"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"
|
||||
/>
|
||||
</svg>
|
||||
: 'text-gray-300 dark:text-gray-600'}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
|
|
@ -690,38 +629,14 @@
|
|||
href="/cities/{citySlug}/locations/{location.id}/edit"
|
||||
class="flex items-center gap-2 rounded-lg border border-border bg-background-card px-4 py-2.5 text-sm font-medium text-foreground-secondary transition-colors hover:bg-background-card-hover hover:text-foreground"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
|
||||
/>
|
||||
</svg>
|
||||
<PencilSimple size={16} />
|
||||
{$_('detail.edit')}
|
||||
</a>
|
||||
<button
|
||||
onclick={() => (showDeleteConfirm = true)}
|
||||
class="flex items-center gap-2 rounded-lg border border-red-200 bg-red-50 px-4 py-2.5 text-sm font-medium text-red-600 transition-colors hover:bg-red-100 dark:border-red-800 dark:bg-red-950/30 dark:text-red-400 dark:hover:bg-red-950/50"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={16} />
|
||||
{$_('detail.delete')}
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -760,19 +675,7 @@
|
|||
href="/cities/{citySlug}/map"
|
||||
class="flex flex-1 items-center justify-center gap-2 bg-background-card px-4 py-2.5 text-sm text-foreground-secondary transition-colors hover:text-primary"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M9 6.75V15m6-6v8.25m.503 3.498l4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 00-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MapTrifold size={16} />
|
||||
{$_('detail.showOnMap')}
|
||||
</a>
|
||||
<a
|
||||
|
|
@ -781,19 +684,7 @@
|
|||
rel="noopener noreferrer"
|
||||
class="flex flex-1 items-center justify-center gap-2 bg-background-card px-4 py-2.5 text-sm text-foreground-secondary transition-colors hover:text-primary"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5"
|
||||
/>
|
||||
</svg>
|
||||
<NavigationArrow size={16} />
|
||||
{$_('detail.directions')}
|
||||
</a>
|
||||
<a
|
||||
|
|
@ -802,19 +693,7 @@
|
|||
rel="noopener noreferrer"
|
||||
class="flex flex-1 items-center justify-center gap-2 bg-background-card px-4 py-2.5 text-sm text-foreground-secondary transition-colors hover:text-primary"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25"
|
||||
/>
|
||||
</svg>
|
||||
<ArrowSquareOut size={16} />
|
||||
{$_('detail.openInMaps')}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { onMount, getContext } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { CaretLeft } from '@manacore/shared-icons';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { locationCollection, type LocalCity } from '$lib/data/local-store';
|
||||
|
|
@ -92,9 +93,7 @@
|
|||
href="/cities/{citySlug}/locations/{$page.params.id}"
|
||||
class="text-foreground-secondary hover:text-primary transition-colors"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-foreground">{$_('edit.title')}</h1>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount, getContext } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { CaretLeft, GlobeSimple } from '@manacore/shared-icons';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { page } from '$app/stores';
|
||||
import { useAllLocations, filterByCity } from '$lib/data/queries';
|
||||
|
|
@ -207,15 +208,7 @@
|
|||
href="/cities/{citySlug}"
|
||||
class="text-foreground-secondary hover:text-primary transition-colors"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
</a>
|
||||
<h1 class="text-2xl font-bold text-foreground">{$_('map.title')}</h1>
|
||||
</div>
|
||||
|
|
@ -232,13 +225,7 @@
|
|||
class="h-5 w-5 border-2 border-primary border-t-transparent rounded-full animate-spin"
|
||||
></div>
|
||||
{:else}
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418"
|
||||
/>
|
||||
</svg>
|
||||
<GlobeSimple size={20} />
|
||||
{/if}
|
||||
</button>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -224,11 +224,7 @@
|
|||
onclick={(e) => handleRemove(e, location.id)}
|
||||
title={$_('favorites.remove')}
|
||||
>
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M11.645 20.91l-.007-.003-.022-.012a15.247 15.247 0 01-.383-.218 25.18 25.18 0 01-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0112 5.052 5.5 5.5 0 0116.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 01-4.244 3.17 15.247 15.247 0 01-.383.219l-.022.012-.007.004-.003.001a.752.752 0 01-.704 0l-.003-.001z"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={20} weight="fill" />
|
||||
</button>
|
||||
</a>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { _ } from 'svelte-i18n';
|
||||
import { PageHeader } from '@manacore/shared-ui';
|
||||
import {
|
||||
import { Clock } from '@manacore/shared-icons';
|
||||
stopwatchesStore,
|
||||
formatTime,
|
||||
formatLapTime,
|
||||
|
|
@ -72,20 +73,7 @@
|
|||
<!-- Empty State -->
|
||||
<div class="flex flex-col items-center justify-center py-16 text-center">
|
||||
<div class="w-24 h-24 mb-6 rounded-full bg-muted flex items-center justify-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-12 w-12 text-muted-foreground"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1.5"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Clock size={20} class="text-muted-foreground" />
|
||||
</div>
|
||||
<h2 class="text-xl font-medium text-foreground mb-2">{$_('stopwatch.noStopwatches')}</h2>
|
||||
<p class="text-muted-foreground mb-6 max-w-sm">{$_('stopwatch.noStopwatchesDescription')}</p>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { FieldDefinition, FieldType } from '@inventar/shared';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { Plus, Trash } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
fields: FieldDefinition[];
|
||||
|
|
@ -199,14 +200,7 @@
|
|||
class="mt-1 text-[hsl(var(--muted-foreground))] hover:text-red-500"
|
||||
title={$_('field.removeField')}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -217,9 +211,7 @@
|
|||
onclick={addField}
|
||||
class="flex w-full items-center justify-center gap-2 rounded-lg border-2 border-dashed border-[hsl(var(--border))] py-3 text-sm text-[hsl(var(--muted-foreground))] transition-colors hover:border-[hsl(var(--primary))] hover:text-[hsl(var(--primary))]"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
{$_('collection.addField')}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
getTotalItemCount,
|
||||
} from '$lib/data/queries';
|
||||
import type { Collection, Item } from '@inventar/shared';
|
||||
import { Plus, Trash } from '@manacore/shared-icons';
|
||||
|
||||
const collectionsCtx: { readonly value: Collection[] } = getContext('collections');
|
||||
const itemsCtx: { readonly value: Item[] } = getContext('items');
|
||||
|
|
@ -53,9 +54,7 @@
|
|||
href="/collections/new"
|
||||
class="flex items-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-sm font-medium text-[hsl(var(--primary-foreground))] transition-colors hover:opacity-90"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
{$_('collection.create')}
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -104,14 +103,7 @@
|
|||
onclick={(e) => handleDelete(e, collection.id)}
|
||||
class="rounded p-1 text-[hsl(var(--muted-foreground))] opacity-0 transition-opacity hover:text-red-500 group-hover:opacity-100"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { CaretLeft } from '@manacore/shared-icons';
|
||||
import { collectionsStore } from '$lib/stores/collections.svelte';
|
||||
import { DEFAULT_TEMPLATES } from '@inventar/shared';
|
||||
import type { CollectionSchema, Template } from '@inventar/shared';
|
||||
|
|
@ -49,9 +50,7 @@
|
|||
onclick={() => (step === 'details' && selectedTemplate ? (step = 'template') : goto('/'))}
|
||||
class="text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<CaretLeft size={20} />
|
||||
</button>
|
||||
<h1 class="text-2xl font-bold text-[hsl(var(--foreground))]">{$_('collection.create')}</h1>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import type { Collection, Item, ItemStatus } from '@inventar/shared';
|
||||
import StatusBadge from '$lib/components/StatusBadge.svelte';
|
||||
import ViewModeToggle from '$lib/components/ViewModeToggle.svelte';
|
||||
import { MagnifyingGlass } from '@manacore/shared-icons';
|
||||
|
||||
const collectionsCtx: { readonly value: Collection[] } = getContext('collections');
|
||||
const itemsCtx: { readonly value: Item[] } = getContext('items');
|
||||
|
|
@ -53,19 +54,10 @@
|
|||
<!-- Search & Filters -->
|
||||
<div class="space-y-3">
|
||||
<div class="relative">
|
||||
<svg
|
||||
class="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[hsl(var(--muted-foreground))]"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass
|
||||
size={20}
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 text-[hsl(var(--muted-foreground))]"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={searchQuery}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { CaretLeft } from '@manacore/shared-icons';
|
||||
import { getContext } from 'svelte';
|
||||
import { itemsStore } from '$lib/stores/items.svelte';
|
||||
import {
|
||||
|
|
@ -101,14 +102,7 @@
|
|||
onclick={() => goto(collection ? `/collections/${collection.id}` : '/items')}
|
||||
class="text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 19l-7-7 7-7"
|
||||
/>
|
||||
</svg>
|
||||
<CaretLeft size={20} />
|
||||
</button>
|
||||
{#if !editing}
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { locationsStore } from '$lib/stores/locations.svelte';
|
||||
import { getLocationTree } from '$lib/data/queries';
|
||||
import type { Location } from '@inventar/shared';
|
||||
import { Plus } from '@manacore/shared-icons';
|
||||
|
||||
const locationsCtx: { readonly value: Location[] } = getContext('locations');
|
||||
|
||||
|
|
@ -65,9 +66,7 @@
|
|||
onclick={() => startCreate()}
|
||||
class="flex items-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-sm font-medium text-[hsl(var(--primary-foreground))]"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
{$_('location.create')}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { getFilteredItems, getCollectionById } from '$lib/data/queries';
|
||||
import type { Collection, Item } from '@inventar/shared';
|
||||
import StatusBadge from '$lib/components/StatusBadge.svelte';
|
||||
import { MagnifyingGlass } from '@manacore/shared-icons';
|
||||
|
||||
const collectionsCtx: { readonly value: Collection[] } = getContext('collections');
|
||||
const itemsCtx: { readonly value: Item[] } = getContext('items');
|
||||
|
|
@ -23,19 +24,10 @@
|
|||
<h1 class="text-2xl font-bold text-[hsl(var(--foreground))]">{$_('nav.search')}</h1>
|
||||
|
||||
<div class="relative">
|
||||
<svg
|
||||
class="absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 text-[hsl(var(--muted-foreground))]"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass
|
||||
size={20}
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 text-[hsl(var(--muted-foreground))]"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={query}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||
import { APP_VERSION } from '$lib/version';
|
||||
import {
|
||||
import { Envelope, SignOut, Tag, User } from '@manacore/shared-icons';
|
||||
SettingsPage,
|
||||
SettingsSection,
|
||||
SettingsCard,
|
||||
|
|
@ -26,14 +27,7 @@
|
|||
<SettingsPage title="Einstellungen" subtitle="Verwalte dein Konto und passe die App an.">
|
||||
<SettingsSection title="Konto">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
<User size={20} />
|
||||
{/snippet}
|
||||
<SettingsCard>
|
||||
<SettingsRow
|
||||
|
|
@ -42,14 +36,7 @@
|
|||
border={false}
|
||||
>
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<Envelope size={20} />
|
||||
{/snippet}
|
||||
</SettingsRow>
|
||||
</SettingsCard>
|
||||
|
|
@ -83,14 +70,7 @@
|
|||
<SettingsCard>
|
||||
<SettingsRow label="Version" border={false}>
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
|
||||
/>
|
||||
</svg>
|
||||
<Tag size={20} />
|
||||
{/snippet}
|
||||
<span class="text-[hsl(var(--muted-foreground))]">{APP_VERSION}</span>
|
||||
</SettingsRow>
|
||||
|
|
@ -106,14 +86,7 @@
|
|||
border={false}
|
||||
>
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="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"
|
||||
/>
|
||||
</svg>
|
||||
<SignOut size={20} />
|
||||
{/snippet}
|
||||
</SettingsDangerButton>
|
||||
</SettingsDangerZone>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { CaretRight } from '@manacore/shared-icons';
|
||||
|
||||
interface Link {
|
||||
name: string;
|
||||
url: string;
|
||||
|
|
@ -36,14 +38,10 @@
|
|||
<p class="font-medium text-sm truncate">{link.name}</p>
|
||||
<p class="text-xs text-muted-foreground truncate">{link.description}</p>
|
||||
</div>
|
||||
<svg
|
||||
class="h-4 w-4 text-muted-foreground group-hover:text-foreground transition-colors"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<CaretRight
|
||||
size={20}
|
||||
class="text-muted-foreground group-hover:text-foreground transition-colors"
|
||||
/>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { Card } from '@manacore/shared-ui';
|
||||
import { DotsSixVertical, Trash } from '@manacore/shared-icons';
|
||||
import type { WidgetConfig, WidgetSize } from '$lib/types/dashboard';
|
||||
import { getWidgetMeta } from '$lib/types/dashboard';
|
||||
import { dashboardStore } from '$lib/stores/dashboard.svelte';
|
||||
|
|
@ -54,14 +55,7 @@
|
|||
<div
|
||||
class="flex cursor-grab items-center justify-center gap-2 border-b border-border py-2 active:cursor-grabbing"
|
||||
>
|
||||
<svg class="h-5 w-5 text-muted-foreground" viewBox="0 0 24 24" fill="currentColor">
|
||||
<circle cx="9" cy="5" r="1.5" />
|
||||
<circle cx="15" cy="5" r="1.5" />
|
||||
<circle cx="9" cy="12" r="1.5" />
|
||||
<circle cx="15" cy="12" r="1.5" />
|
||||
<circle cx="9" cy="19" r="1.5" />
|
||||
<circle cx="15" cy="19" r="1.5" />
|
||||
</svg>
|
||||
<DotsSixVertical size={20} class="text-muted-foreground" />
|
||||
<span class="text-sm font-medium">{meta?.icon} {$_(widget.title)}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -88,17 +82,7 @@
|
|||
onclick={handleRemove}
|
||||
class="flex items-center gap-1 rounded-lg px-3 py-1.5 text-sm font-medium text-destructive hover:bg-destructive/10"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M3 6h18" />
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
||||
</svg>
|
||||
<Trash size={16} />
|
||||
{$_('dashboard.remove_widget')}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { ArrowsClockwise } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
/** Error message to display */
|
||||
|
|
@ -42,10 +43,7 @@
|
|||
</svg>
|
||||
{$_('common.loading')}
|
||||
{:else}
|
||||
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M1 4v6h6" />
|
||||
<path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10" />
|
||||
</svg>
|
||||
<ArrowsClockwise size={16} />
|
||||
{$_('dashboard.retry')}
|
||||
{/if}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { Button, Card } from '@manacore/shared-ui';
|
||||
import { ArrowSquareOut } from '@manacore/shared-icons';
|
||||
import SectionEditor from './SectionEditor.svelte';
|
||||
import RepeatableField from './RepeatableField.svelte';
|
||||
import { saveLandingConfig, publishLanding } from '$lib/api/services/landing';
|
||||
|
|
@ -500,14 +501,7 @@
|
|||
class="ml-auto text-sm text-primary-600 hover:underline flex items-center gap-1"
|
||||
>
|
||||
{config.publishedUrl}
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
||||
/>
|
||||
</svg>
|
||||
<ArrowSquareOut size={16} />
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts" generics="T">
|
||||
import { Button } from '@manacore/shared-ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { Plus, X } from '@manacore/shared-icons';
|
||||
|
||||
let {
|
||||
items = [],
|
||||
|
|
@ -26,14 +27,7 @@
|
|||
class="absolute top-2 right-2 p-1 text-gray-400 hover:text-red-500 transition-colors"
|
||||
title="Remove"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} />
|
||||
</button>
|
||||
{@render renderItem(item, index)}
|
||||
</div>
|
||||
|
|
@ -44,9 +38,7 @@
|
|||
onclick={onAdd}
|
||||
class="w-full flex items-center justify-center gap-2 py-2 px-4 border border-dashed border-gray-300 dark:border-gray-600 rounded-lg text-sm text-gray-500 hover:text-gray-700 dark:hover:text-gray-300 hover:border-gray-400 dark:hover:border-gray-500 transition-colors"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
{addLabel}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
import { CaretDown } from '@manacore/shared-icons';
|
||||
|
||||
let {
|
||||
title,
|
||||
|
|
@ -17,14 +18,10 @@
|
|||
class="w-full flex items-center justify-between px-4 py-3 bg-gray-50 dark:bg-gray-800/50 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
<span class="font-medium text-sm text-gray-900 dark:text-white">{title}</span>
|
||||
<svg
|
||||
class="h-5 w-5 text-gray-500 transition-transform {isExpanded ? 'rotate-180' : ''}"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
<CaretDown
|
||||
size={20}
|
||||
class="text-gray-500 transition-transform {isExpanded ? 'rotate-180' : ''}"
|
||||
/>
|
||||
</button>
|
||||
|
||||
{#if isExpanded}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { DeleteUserDataResponse } from '$lib/api/services/admin';
|
||||
import { Check, Warning, XCircle } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
|
|
@ -49,19 +50,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-green-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-600" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Daten geloscht</h3>
|
||||
</div>
|
||||
|
|
@ -116,19 +105,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-red-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<Warning size={20} class="text-red-600" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-red-600">Alle Daten loschen?</h3>
|
||||
</div>
|
||||
|
|
@ -149,43 +126,19 @@
|
|||
|
||||
<ul class="text-sm text-muted-foreground mb-6 space-y-2">
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500" />
|
||||
<span>Alle Projektdaten (Chats, Todos, Termine, Kontakte, etc.)</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500" />
|
||||
<span>Alle Sessions und Anmeldedaten</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500" />
|
||||
<span>Credits und Transaktionshistorie</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500" />
|
||||
<span>Dein Nutzerkonto</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { qrExportService, type QRExportResult } from '$lib/api/services/qr-export';
|
||||
import type { UserDataSummary } from '$lib/api/services/my-data';
|
||||
import { WallpaperModal } from '@manacore/wallpaper-generator/svelte';
|
||||
import { DownloadSimple, Image, Warning, QrCode } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
|
|
@ -119,14 +120,7 @@
|
|||
<!-- Header -->
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center">
|
||||
<svg class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z"
|
||||
/>
|
||||
</svg>
|
||||
<QrCode size={20} class="text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold">QR-Code Export</h3>
|
||||
|
|
@ -150,19 +144,7 @@
|
|||
<div
|
||||
class="rounded-lg border border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-900/20 p-4 text-center"
|
||||
>
|
||||
<svg
|
||||
class="h-8 w-8 text-red-500 mx-auto mb-2"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<Warning size={20} class="text-red-500 mx-auto mb-2" />
|
||||
<p class="text-red-600 dark:text-red-400 mb-4">{error}</p>
|
||||
<button
|
||||
onclick={loadExportData}
|
||||
|
|
@ -226,28 +208,14 @@
|
|||
onclick={downloadPNG}
|
||||
class="flex-1 flex items-center justify-center gap-2 px-4 py-2 border rounded-lg hover:bg-muted transition-colors"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||
/>
|
||||
</svg>
|
||||
<DownloadSimple size={20} />
|
||||
PNG
|
||||
</button>
|
||||
<button
|
||||
onclick={downloadSVG}
|
||||
class="flex-1 flex items-center justify-center gap-2 px-4 py-2 border rounded-lg hover:bg-muted transition-colors"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||
/>
|
||||
</svg>
|
||||
<DownloadSimple size={20} />
|
||||
SVG
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -257,14 +225,7 @@
|
|||
onclick={openWallpaperModal}
|
||||
class="w-full flex items-center justify-center gap-2 px-4 py-2 bg-primary/10 text-primary border border-primary/20 rounded-lg hover:bg-primary/20 transition-colors"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<Image size={20} />
|
||||
Als Wallpaper
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import AppsStep from './steps/AppsStep.svelte';
|
||||
import CreditsStep from './steps/CreditsStep.svelte';
|
||||
import CompleteStep from './steps/CompleteStep.svelte';
|
||||
import { Check } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
onComplete: () => void;
|
||||
|
|
@ -123,14 +124,7 @@
|
|||
: 'bg-muted text-muted-foreground'}"
|
||||
>
|
||||
{#if index < currentStep}
|
||||
<svg class="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} />
|
||||
{:else}
|
||||
{index + 1}
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { Info } from '@manacore/shared-icons';
|
||||
// Apps overview step - shows available Mana apps
|
||||
|
||||
const APPS = [
|
||||
|
|
@ -105,14 +106,7 @@
|
|||
<div class="mt-8 p-4 rounded-xl bg-primary/5 border border-primary/20">
|
||||
<div class="flex gap-3">
|
||||
<div class="h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center shrink-0">
|
||||
<svg class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info size={20} class="text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-medium">Ein Konto, alle Apps</h4>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { Check, Gear, House, SquaresFour, CurrencyCircleDollar } from '@manacore/shared-icons';
|
||||
|
||||
// Completion step with celebration
|
||||
</script>
|
||||
|
||||
|
|
@ -8,9 +10,7 @@
|
|||
<div
|
||||
class="inline-flex h-24 w-24 rounded-full bg-gradient-to-br from-green-400 to-emerald-500 items-center justify-center shadow-lg shadow-green-500/25 animate-bounce"
|
||||
>
|
||||
<svg class="h-12 w-12 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<Check size={20} class="text-white" />
|
||||
</div>
|
||||
|
||||
<!-- Confetti-like decorations -->
|
||||
|
|
@ -40,14 +40,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-colors"
|
||||
>
|
||||
<svg class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
|
||||
/>
|
||||
</svg>
|
||||
<House size={20} class="text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-semibold group-hover:text-primary transition-colors">Dashboard</div>
|
||||
|
|
@ -64,19 +57,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-lg bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center group-hover:bg-blue-200 dark:group-hover:bg-blue-900/50 transition-colors"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-blue-600 dark:text-blue-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
|
||||
/>
|
||||
</svg>
|
||||
<SquaresFour size={20} class="text-blue-600 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-semibold group-hover:text-blue-600 transition-colors">Alle Apps</div>
|
||||
|
|
@ -93,19 +74,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-lg bg-yellow-100 dark:bg-yellow-900/30 flex items-center justify-center group-hover:bg-yellow-200 dark:group-hover:bg-yellow-900/50 transition-colors"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-yellow-600 dark:text-yellow-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyCircleDollar size={20} class="text-yellow-600 dark:text-yellow-400" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-semibold group-hover:text-yellow-600 transition-colors">Credits</div>
|
||||
|
|
@ -122,25 +91,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-lg bg-gray-100 dark:bg-gray-800 flex items-center justify-center group-hover:bg-gray-200 dark:group-hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-gray-600 dark:text-gray-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Gear size={20} class="text-gray-600 dark:text-gray-400" />
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { Check, CurrencyCircleDollar, Gift, Lightbulb } from '@manacore/shared-icons';
|
||||
|
||||
// Credits explanation step
|
||||
</script>
|
||||
|
||||
|
|
@ -7,14 +9,7 @@
|
|||
<div
|
||||
class="inline-flex h-16 w-16 rounded-2xl bg-gradient-to-br from-yellow-400 to-orange-500 items-center justify-center mb-4 shadow-lg shadow-orange-500/25"
|
||||
>
|
||||
<svg class="h-8 w-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyCircleDollar size={32} class="text-white" />
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold mb-2">Das Credits-System</h2>
|
||||
<p class="text-muted-foreground">Einfach und transparent für alle AI-Features.</p>
|
||||
|
|
@ -32,51 +27,15 @@
|
|||
</h3>
|
||||
<ul class="space-y-2 text-sm text-muted-foreground">
|
||||
<li class="flex items-start gap-2">
|
||||
<svg
|
||||
class="h-4 w-4 text-green-500 mt-0.5 shrink-0"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-500 mt-0.5 shrink-0" />
|
||||
<span>Du hast ein Credit-Guthaben für alle Mana-Apps</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-2">
|
||||
<svg
|
||||
class="h-4 w-4 text-green-500 mt-0.5 shrink-0"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-500 mt-0.5 shrink-0" />
|
||||
<span>AI-Features wie Chat, Bildgenerierung etc. kosten Credits</span>
|
||||
</li>
|
||||
<li class="flex items-start gap-2">
|
||||
<svg
|
||||
class="h-4 w-4 text-green-500 mt-0.5 shrink-0"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-500 mt-0.5 shrink-0" />
|
||||
<span>Einfache Preisregel: <strong class="text-foreground">1 Mana = 1 Cent</strong></span>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -90,14 +49,7 @@
|
|||
<span
|
||||
class="h-6 w-6 rounded-full bg-green-500 flex items-center justify-center text-sm text-white"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7"
|
||||
/>
|
||||
</svg>
|
||||
<Gift size={16} />
|
||||
</span>
|
||||
Gratis-Credits
|
||||
</h3>
|
||||
|
|
@ -147,19 +99,7 @@
|
|||
class="p-4 rounded-xl bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800"
|
||||
>
|
||||
<div class="flex gap-3">
|
||||
<svg
|
||||
class="h-5 w-5 text-blue-500 shrink-0 mt-0.5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
|
||||
/>
|
||||
</svg>
|
||||
<Lightbulb size={20} class="text-blue-500 shrink-0 mt-0.5" />
|
||||
<p class="text-sm text-blue-800 dark:text-blue-200">
|
||||
<strong>Tipp:</strong> Mit einer Mana Quelle M erhältst du monatlich 1.000 Mana ab 9,99€/Monat.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { profileService } from '$lib/api/profile';
|
||||
import { Camera, Check } from '@manacore/shared-icons';
|
||||
|
||||
let { nameValue = $bindable('') }: { nameValue?: string } = $props();
|
||||
|
||||
|
|
@ -123,20 +124,7 @@
|
|||
<div
|
||||
class="absolute inset-0 rounded-full bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center"
|
||||
>
|
||||
<svg class="h-8 w-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Camera size={20} class="text-white" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
|
@ -176,14 +164,7 @@
|
|||
class="p-3 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg"
|
||||
>
|
||||
<p class="text-sm text-green-600 dark:text-green-400 flex items-center gap-2">
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} />
|
||||
Profil gespeichert!
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -205,14 +186,7 @@
|
|||
</svg>
|
||||
Speichern...
|
||||
{:else}
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} />
|
||||
Jetzt speichern
|
||||
{/if}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { Palette, SquaresFour, CurrencyCircleDollar } from '@manacore/shared-icons';
|
||||
|
||||
// Welcome step - introduces ManaCore
|
||||
</script>
|
||||
|
||||
|
|
@ -24,19 +26,7 @@
|
|||
<div
|
||||
class="h-8 w-8 rounded-md bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center flex-shrink-0"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4 text-blue-600 dark:text-blue-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
|
||||
/>
|
||||
</svg>
|
||||
<SquaresFour size={16} class="text-blue-600 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-medium text-sm">Alle Apps</h3>
|
||||
|
|
@ -48,19 +38,7 @@
|
|||
<div
|
||||
class="h-8 w-8 rounded-md bg-green-100 dark:bg-green-900/30 flex items-center justify-center flex-shrink-0"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4 text-green-600 dark:text-green-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyCircleDollar size={16} class="text-green-600 dark:text-green-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-medium text-sm">Credits-System</h3>
|
||||
|
|
@ -72,19 +50,7 @@
|
|||
<div
|
||||
class="h-8 w-8 rounded-md bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center flex-shrink-0"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4 text-purple-600 dark:text-purple-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"
|
||||
/>
|
||||
</svg>
|
||||
<Palette size={20} class="text-purple-600 dark:text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-medium text-sm">Personalisierung</h3>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { profileService } from '$lib/api/profile';
|
||||
import { Key, Eye, EyeSlash } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
|
|
@ -86,14 +87,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg class="h-5 w-5 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
|
||||
/>
|
||||
</svg>
|
||||
<Key size={20} class="text-blue-600" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Passwort ändern</h3>
|
||||
</div>
|
||||
|
|
@ -118,14 +112,9 @@
|
|||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{#if showCurrentPassword}
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
|
||||
</svg>
|
||||
<EyeSlash size={20} />
|
||||
{:else}
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
<Eye size={20} />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -150,14 +139,9 @@
|
|||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{#if showNewPassword}
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
|
||||
</svg>
|
||||
<EyeSlash size={20} />
|
||||
{:else}
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
<Eye size={20} />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -178,7 +162,9 @@
|
|||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
||||
<div
|
||||
class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg"
|
||||
>
|
||||
<p class="text-sm text-red-600 dark:text-red-400">{error}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { profileService } from '$lib/api/profile';
|
||||
import { Warning, XCircle } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
|
|
@ -78,14 +79,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg class="h-5 w-5 text-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<Warning size={20} class="text-red-600" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-red-600">Konto löschen</h3>
|
||||
</div>
|
||||
|
|
@ -104,43 +98,19 @@
|
|||
|
||||
<ul class="text-sm text-muted-foreground mb-6 space-y-2">
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500 flex-shrink-0" />
|
||||
<span>Alle Projektdaten (Chats, Todos, Termine, etc.)</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500 flex-shrink-0" />
|
||||
<span>Alle verbleibenden Credits</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500 flex-shrink-0" />
|
||||
<span>Dein aktives Abonnement (wird gekündigt)</span>
|
||||
</li>
|
||||
<li class="flex items-center gap-2">
|
||||
<svg class="h-4 w-4 text-red-500 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle size={16} weight="fill" class="text-red-500 flex-shrink-0" />
|
||||
<span>Dein Nutzerkonto</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -159,7 +129,9 @@
|
|||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
||||
<div
|
||||
class="mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg"
|
||||
>
|
||||
<p class="text-sm text-red-600 dark:text-red-400">{error}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -212,7 +184,9 @@
|
|||
</div>
|
||||
|
||||
{#if error}
|
||||
<div class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
|
||||
<div
|
||||
class="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg"
|
||||
>
|
||||
<p class="text-sm text-red-600 dark:text-red-400">{error}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { profileService, type UserProfile } from '$lib/api/profile';
|
||||
import { PencilSimple } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
|
|
@ -146,14 +147,7 @@
|
|||
<div class="p-6">
|
||||
<div class="flex items-center gap-3 mb-6">
|
||||
<div class="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center">
|
||||
<svg class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
||||
/>
|
||||
</svg>
|
||||
<PencilSimple size={20} class="text-primary" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Profil bearbeiten</h3>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { ShieldCheck } from '@manacore/shared-icons';
|
||||
|
||||
let { children }: { children: Snippet } = $props();
|
||||
|
||||
|
|
@ -50,19 +51,7 @@
|
|||
<p class="text-muted-foreground">System monitoring and management</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 px-3 py-1.5 rounded-full bg-red-100 dark:bg-red-900/30">
|
||||
<svg
|
||||
class="h-4 w-4 text-red-600 dark:text-red-400"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
||||
/>
|
||||
</svg>
|
||||
<ShieldCheck size={20} class="text-red-600 dark:text-red-400" />
|
||||
<span class="text-sm font-medium text-red-600 dark:text-red-400">Admin</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { ArrowSquareOut } from '@manacore/shared-icons';
|
||||
import QuickLinks from '$lib/components/admin/QuickLinks.svelte';
|
||||
|
||||
interface ServiceHealth {
|
||||
|
|
@ -124,14 +125,7 @@
|
|||
rel="noopener noreferrer"
|
||||
class="text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
|
||||
/>
|
||||
</svg>
|
||||
<ArrowSquareOut size={16} />
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { adminService, type UserListItem } from '$lib/api/services/admin';
|
||||
import { MagnifyingGlass } from '@manacore/shared-icons';
|
||||
|
||||
let users = $state<UserListItem[]>([]);
|
||||
let loading = $state(true);
|
||||
|
|
@ -84,19 +85,10 @@
|
|||
<!-- Search -->
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="relative flex-1 max-w-md">
|
||||
<svg
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass
|
||||
size={20}
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nach Email oder Name suchen..."
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { CaretLeft, Check, Warning, CheckCircle, WarningCircle } from '@manacore/shared-icons';
|
||||
import StatCard from '$lib/components/admin/StatCard.svelte';
|
||||
import ProjectDataCard from '$lib/components/admin/ProjectDataCard.svelte';
|
||||
import {
|
||||
|
|
@ -86,9 +87,7 @@
|
|||
class="p-2 rounded-lg hover:bg-muted transition-colors"
|
||||
aria-label="Zuruck zur Nutzerliste"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<CaretLeft size={20} />
|
||||
</button>
|
||||
<div class="flex-1">
|
||||
<h1 class="text-2xl font-bold">Nutzerdaten</h1>
|
||||
|
|
@ -150,24 +149,12 @@
|
|||
</span>
|
||||
{#if userData.user.emailVerified}
|
||||
<span class="text-xs text-green-600 flex items-center gap-1">
|
||||
<svg class="h-3 w-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<CheckCircle size={12} weight="fill" />
|
||||
Email verifiziert
|
||||
</span>
|
||||
{:else}
|
||||
<span class="text-xs text-yellow-600 flex items-center gap-1">
|
||||
<svg class="h-3 w-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<WarningCircle size={12} weight="fill" />
|
||||
Email nicht verifiziert
|
||||
</span>
|
||||
{/if}
|
||||
|
|
@ -267,19 +254,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-green-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-600" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Loschung abgeschlossen</h3>
|
||||
</div>
|
||||
|
|
@ -325,19 +300,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg
|
||||
class="h-5 w-5 text-red-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<Warning size={20} class="text-red-600" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-red-600">Daten unwiderruflich loschen?</h3>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import UserTable from '$lib/components/admin/UserTable.svelte';
|
||||
import { MagnifyingGlass } from '@manacore/shared-icons';
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
|
|
@ -99,19 +100,10 @@
|
|||
<!-- Search & Filters -->
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="relative flex-1 max-w-md">
|
||||
<svg
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass
|
||||
size={20}
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search users..."
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { Button, Input, Card, PageHeader, Badge } from '@manacore/shared-ui';
|
||||
import { Check, Copy, Info, Key, Plus, Prohibit } from '@manacore/shared-icons';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { apiKeysService, type ApiKey, type ApiKeyWithSecret } from '$lib/api/api-keys';
|
||||
|
||||
|
|
@ -133,14 +134,7 @@
|
|||
>
|
||||
{#snippet actions()}
|
||||
<Button onclick={() => (showCreateModal = true)}>
|
||||
<svg class="h-4 w-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={16} class="mr-2" />
|
||||
Create API Key
|
||||
</Button>
|
||||
{/snippet}
|
||||
|
|
@ -169,14 +163,7 @@
|
|||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
|
||||
/>
|
||||
</svg>
|
||||
<Key size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Active Keys</h2>
|
||||
|
|
@ -188,19 +175,7 @@
|
|||
|
||||
{#if activeKeys.length === 0}
|
||||
<div class="text-center py-8 text-muted-foreground">
|
||||
<svg
|
||||
class="h-12 w-12 mx-auto mb-4 opacity-50"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
|
||||
/>
|
||||
</svg>
|
||||
<Key size={48} class="mx-auto mb-4 opacity-50" />
|
||||
<p class="font-medium">No API keys yet</p>
|
||||
<p class="text-sm mt-1">Create your first API key to get started</p>
|
||||
</div>
|
||||
|
|
@ -214,7 +189,9 @@
|
|||
<Badge variant="secondary">{key.scopes.join(', ')}</Badge>
|
||||
<Badge variant="outline">{key.rateLimitRequests}/min</Badge>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-1 text-sm text-muted-foreground flex-wrap">
|
||||
<div
|
||||
class="flex items-center gap-4 mt-1 text-sm text-muted-foreground flex-wrap"
|
||||
>
|
||||
<code class="bg-muted px-2 py-0.5 rounded font-mono text-xs"
|
||||
>{key.keyPrefix}</code
|
||||
>
|
||||
|
|
@ -245,14 +222,7 @@
|
|||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/20 text-red-600 dark:text-red-400"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"
|
||||
/>
|
||||
</svg>
|
||||
<Prohibit size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Revoked Keys</h2>
|
||||
|
|
@ -293,14 +263,7 @@
|
|||
<div
|
||||
class="flex h-10 w-10 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">How to Use</h2>
|
||||
|
|
@ -350,14 +313,7 @@
|
|||
<div
|
||||
class="flex h-12 w-12 mx-auto mb-4 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/20 text-green-600 dark:text-green-400"
|
||||
>
|
||||
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} />
|
||||
</div>
|
||||
|
||||
<h3 class="text-lg font-semibold mb-2">API Key Created</h3>
|
||||
|
|
@ -376,28 +332,9 @@
|
|||
onclick={() => copyToClipboard(createdKey!.key)}
|
||||
>
|
||||
{#if copied}
|
||||
<svg
|
||||
class="h-5 w-5 text-green-600"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-600" />
|
||||
{:else}
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<Copy size={20} />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -444,7 +381,9 @@
|
|||
<span class="text-sm">Text-to-Speech (tts)</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-muted-foreground">Select which services this key can access</p>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
Select which services this key can access
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Rate Limit -->
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import TilingLayout from '$lib/components/dashboard/TilingLayout.svelte';
|
||||
import { collectLeaves } from '$lib/utils/tiling-tree';
|
||||
import TilePanel from '$lib/components/dashboard/TilePanel.svelte';
|
||||
import { Check, PencilSimple } from '@manacore/shared-icons';
|
||||
|
||||
let isMobile = $state(false);
|
||||
|
||||
|
|
@ -53,29 +54,12 @@
|
|||
>
|
||||
{#if tilingStore.isEditing}
|
||||
<span class="flex items-center gap-2">
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<Check size={20} />
|
||||
{$_('dashboard.done')}
|
||||
</span>
|
||||
{:else}
|
||||
<span class="flex items-center gap-2">
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
||||
</svg>
|
||||
<PencilSimple size={16} />
|
||||
{$_('dashboard.customize')}
|
||||
</span>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { Card, PageHeader } from '@manacore/shared-ui';
|
||||
import { ClipboardText, X } from '@manacore/shared-icons';
|
||||
import {
|
||||
giftsService,
|
||||
type GiftListItem,
|
||||
|
|
@ -365,14 +366,7 @@
|
|||
class="p-2 rounded hover:bg-surface-hover text-muted-foreground hover:text-foreground"
|
||||
title="Link kopieren"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
|
||||
></path>
|
||||
</svg>
|
||||
<ClipboardText size={16} />
|
||||
</button>
|
||||
{#if gift.status === 'active'}
|
||||
<button
|
||||
|
|
@ -398,19 +392,7 @@
|
|||
></path>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
></path>
|
||||
</svg>
|
||||
<X size={20} />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { Card, Button, PageHeader } from '@manacore/shared-ui';
|
||||
import type { PageData } from './$types';
|
||||
import { Plus } from '@manacore/shared-icons';
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
|
||||
|
|
@ -30,14 +31,7 @@
|
|||
>
|
||||
{#snippet actions()}
|
||||
<Button variant="primary">
|
||||
<svg class="mr-2 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={20} class="mr-2" />
|
||||
Create Organization
|
||||
</Button>
|
||||
{/snippet}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,17 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { Card, PageHeader } from '@manacore/shared-ui';
|
||||
import {
|
||||
QrCode,
|
||||
DownloadSimple,
|
||||
Info,
|
||||
ShieldCheck,
|
||||
CurrencyCircleDollar,
|
||||
Clock,
|
||||
Warning,
|
||||
CheckCircle,
|
||||
WarningCircle,
|
||||
} from '@manacore/shared-icons';
|
||||
import Breadcrumbs from '$lib/components/Breadcrumbs.svelte';
|
||||
import StatCard from '$lib/components/admin/StatCard.svelte';
|
||||
import ProjectDataCard from '$lib/components/admin/ProjectDataCard.svelte';
|
||||
|
|
@ -117,14 +128,7 @@
|
|||
class="flex items-center gap-2 px-4 py-2 border rounded-lg hover:bg-muted transition-colors"
|
||||
title="Als QR-Code exportieren"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h.01M5 8h2a1 1 0 001-1V5a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1zm12 0h2a1 1 0 001-1V5a1 1 0 00-1-1h-2a1 1 0 00-1 1v2a1 1 0 001 1zM5 20h2a1 1 0 001-1v-2a1 1 0 00-1-1H5a1 1 0 00-1 1v2a1 1 0 001 1z"
|
||||
/>
|
||||
</svg>
|
||||
<QrCode size={16} />
|
||||
<span>QR-Code</span>
|
||||
</button>
|
||||
<button
|
||||
|
|
@ -149,14 +153,7 @@
|
|||
></path>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||
/>
|
||||
</svg>
|
||||
<DownloadSimple size={16} />
|
||||
{/if}
|
||||
<span>{exporting ? 'Exportiere...' : 'Daten exportieren'}</span>
|
||||
</button>
|
||||
|
|
@ -169,19 +166,7 @@
|
|||
class="rounded-lg border bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 p-4"
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
<svg
|
||||
class="h-5 w-5 text-blue-500 mt-0.5 shrink-0"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info size={20} class="text-blue-500 mt-0.5 shrink-0" />
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-blue-800 dark:text-blue-200">
|
||||
Hier siehst du alle Daten, die wir uber dich speichern. Mehr Informationen findest du in
|
||||
|
|
@ -245,24 +230,12 @@
|
|||
</span>
|
||||
{#if userData.user.emailVerified}
|
||||
<span class="text-xs text-green-600 flex items-center gap-1">
|
||||
<svg class="h-3 w-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<CheckCircle size={12} weight="fill" />
|
||||
Email verifiziert
|
||||
</span>
|
||||
{:else}
|
||||
<span class="text-xs text-yellow-600 flex items-center gap-1">
|
||||
<svg class="h-3 w-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<WarningCircle size={12} weight="fill" />
|
||||
Email nicht verifiziert
|
||||
</span>
|
||||
{/if}
|
||||
|
|
@ -293,19 +266,7 @@
|
|||
<Card>
|
||||
<div class="p-6">
|
||||
<h3 class="text-lg font-semibold mb-4 flex items-center gap-2">
|
||||
<svg
|
||||
class="h-5 w-5 text-blue-500"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
||||
/>
|
||||
</svg>
|
||||
<ShieldCheck size={20} class="text-blue-500" />
|
||||
Authentifizierung
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
|
|
@ -337,19 +298,7 @@
|
|||
<Card>
|
||||
<div class="p-6">
|
||||
<h3 class="text-lg font-semibold mb-4 flex items-center gap-2">
|
||||
<svg
|
||||
class="h-5 w-5 text-yellow-500"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyCircleDollar size={20} class="text-yellow-500" />
|
||||
Credits
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
|
|
@ -388,14 +337,7 @@
|
|||
<Card>
|
||||
<div class="p-6">
|
||||
<h3 class="text-lg font-semibold mb-4 flex items-center gap-2">
|
||||
<svg class="h-5 w-5 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Clock size={20} class="text-gray-500" />
|
||||
Aufbewahrungsfristen
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground mb-4">So lange speichern wir deine Daten:</p>
|
||||
|
|
@ -431,14 +373,7 @@
|
|||
<div
|
||||
class="h-10 w-10 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center"
|
||||
>
|
||||
<svg class="h-5 w-5 text-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<Warning size={20} class="text-red-600" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-red-600">Gefahrenzone</h3>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { Card, PageHeader } from '@manacore/shared-ui';
|
||||
import { Check } from '@manacore/shared-icons';
|
||||
import {
|
||||
subscriptionsService,
|
||||
type SubscriptionPlan,
|
||||
|
|
@ -87,15 +88,30 @@
|
|||
function getStatusBadge(status: string): { text: string; class: string } {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return { text: 'Aktiv', class: 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400' };
|
||||
return {
|
||||
text: 'Aktiv',
|
||||
class: 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400',
|
||||
};
|
||||
case 'canceled':
|
||||
return { text: 'Gekündigt', class: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400' };
|
||||
return {
|
||||
text: 'Gekündigt',
|
||||
class: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400',
|
||||
};
|
||||
case 'past_due':
|
||||
return { text: 'Überfällig', class: 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400' };
|
||||
return {
|
||||
text: 'Überfällig',
|
||||
class: 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400',
|
||||
};
|
||||
case 'trialing':
|
||||
return { text: 'Testphase', class: 'bg-blue-100 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400' };
|
||||
return {
|
||||
text: 'Testphase',
|
||||
class: 'bg-blue-100 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400',
|
||||
};
|
||||
default:
|
||||
return { text: status, class: 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400' };
|
||||
return {
|
||||
text: status,
|
||||
class: 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +129,10 @@
|
|||
const { url } = await subscriptionsService.createCheckout(plan.id, billingInterval);
|
||||
window.location.href = url;
|
||||
} catch (e) {
|
||||
showToast(e instanceof Error ? e.message : 'Fehler beim Erstellen der Checkout-Session', 'error');
|
||||
showToast(
|
||||
e instanceof Error ? e.message : 'Fehler beim Erstellen der Checkout-Session',
|
||||
'error'
|
||||
);
|
||||
} finally {
|
||||
processingPlanId = null;
|
||||
}
|
||||
|
|
@ -132,7 +151,11 @@
|
|||
}
|
||||
|
||||
async function handleCancelSubscription() {
|
||||
if (!confirm('Möchtest du dein Abonnement wirklich kündigen? Du kannst es bis zum Ende der Laufzeit weiter nutzen.')) {
|
||||
if (
|
||||
!confirm(
|
||||
'Möchtest du dein Abonnement wirklich kündigen? Du kannst es bis zum Ende der Laufzeit weiter nutzen.'
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +202,9 @@
|
|||
|
||||
{#if loading}
|
||||
<div class="flex items-center justify-center py-12">
|
||||
<div class="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent"></div>
|
||||
<div
|
||||
class="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent"
|
||||
></div>
|
||||
</div>
|
||||
{:else if error}
|
||||
<Card>
|
||||
|
|
@ -220,8 +245,19 @@
|
|||
>
|
||||
{#if openingPortal}
|
||||
<svg class="animate-spin h-4 w-4" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
<circle
|
||||
class="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
stroke-width="4"
|
||||
></circle>
|
||||
<path
|
||||
class="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
{/if}
|
||||
Zahlungsmethode verwalten
|
||||
|
|
@ -272,13 +308,13 @@
|
|||
<div>
|
||||
<div class="flex items-center gap-3">
|
||||
<h2 class="text-xl font-bold">Free Plan</h2>
|
||||
<span class="px-2 py-0.5 text-xs font-medium rounded-full bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400">
|
||||
<span
|
||||
class="px-2 py-0.5 text-xs font-medium rounded-full bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400"
|
||||
>
|
||||
Aktuell
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground mt-1">
|
||||
150 Mana / Monat
|
||||
</p>
|
||||
<p class="text-sm text-muted-foreground mt-1">150 Mana / Monat</p>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Upgrade auf einen bezahlten Plan für mehr Mana und Features.
|
||||
|
|
@ -314,7 +350,8 @@
|
|||
<div class="inline-flex items-center gap-2 p-1 bg-muted rounded-lg">
|
||||
<button
|
||||
onclick={() => (billingInterval = 'month')}
|
||||
class="px-4 py-2 rounded-md text-sm font-medium transition-colors {billingInterval === 'month'
|
||||
class="px-4 py-2 rounded-md text-sm font-medium transition-colors {billingInterval ===
|
||||
'month'
|
||||
? 'bg-background shadow-sm'
|
||||
: 'hover:text-foreground'}"
|
||||
>
|
||||
|
|
@ -322,7 +359,8 @@
|
|||
</button>
|
||||
<button
|
||||
onclick={() => (billingInterval = 'year')}
|
||||
class="px-4 py-2 rounded-md text-sm font-medium transition-colors {billingInterval === 'year'
|
||||
class="px-4 py-2 rounded-md text-sm font-medium transition-colors {billingInterval ===
|
||||
'year'
|
||||
? 'bg-background shadow-sm'
|
||||
: 'hover:text-foreground'}"
|
||||
>
|
||||
|
|
@ -336,12 +374,18 @@
|
|||
<div class="grid gap-6 md:grid-cols-3">
|
||||
{#each plans as plan}
|
||||
{@const isCurrentPlan = currentSubscription?.plan?.id === plan.id}
|
||||
{@const price = billingInterval === 'year' ? plan.priceYearlyEuroCents : plan.priceMonthlyEuroCents}
|
||||
{@const savings = getSavingsPercent(plan.priceMonthlyEuroCents, plan.priceYearlyEuroCents)}
|
||||
{@const price =
|
||||
billingInterval === 'year' ? plan.priceYearlyEuroCents : plan.priceMonthlyEuroCents}
|
||||
{@const savings = getSavingsPercent(
|
||||
plan.priceMonthlyEuroCents,
|
||||
plan.priceYearlyEuroCents
|
||||
)}
|
||||
<Card>
|
||||
<div class="text-center p-2">
|
||||
{#if isCurrentPlan}
|
||||
<span class="inline-block px-3 py-1 text-xs font-medium rounded-full bg-primary/10 text-primary mb-4">
|
||||
<span
|
||||
class="inline-block px-3 py-1 text-xs font-medium rounded-full bg-primary/10 text-primary mb-4"
|
||||
>
|
||||
Dein Plan
|
||||
</span>
|
||||
{/if}
|
||||
|
|
@ -375,9 +419,7 @@
|
|||
<ul class="mt-6 space-y-3 text-left">
|
||||
{#each plan.features as feature}
|
||||
<li class="flex items-start gap-2 text-sm">
|
||||
<svg class="h-5 w-5 text-green-500 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<Check size={20} class="text-green-500 flex-shrink-0" />
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
{/each}
|
||||
|
|
@ -389,13 +431,24 @@
|
|||
disabled={isCurrentPlan || processingPlanId === plan.id || plan.isDefault}
|
||||
class="mt-6 w-full py-2 px-4 rounded-lg font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2
|
||||
{isCurrentPlan || plan.isDefault
|
||||
? 'bg-muted text-muted-foreground'
|
||||
: 'bg-primary text-primary-foreground hover:bg-primary/90'}"
|
||||
? 'bg-muted text-muted-foreground'
|
||||
: 'bg-primary text-primary-foreground hover:bg-primary/90'}"
|
||||
>
|
||||
{#if processingPlanId === plan.id}
|
||||
<svg class="animate-spin h-4 w-4" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
<circle
|
||||
class="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
stroke-width="4"
|
||||
></circle>
|
||||
<path
|
||||
class="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
Wird verarbeitet...
|
||||
{:else if isCurrentPlan}
|
||||
|
|
@ -445,11 +498,15 @@
|
|||
</td>
|
||||
<td class="py-3 pr-4">
|
||||
{#if invoice.status === 'paid'}
|
||||
<span class="px-2 py-0.5 text-xs font-medium rounded-full bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400">
|
||||
<span
|
||||
class="px-2 py-0.5 text-xs font-medium rounded-full bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400"
|
||||
>
|
||||
Bezahlt
|
||||
</span>
|
||||
{:else}
|
||||
<span class="px-2 py-0.5 text-xs font-medium rounded-full bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400">
|
||||
<span
|
||||
class="px-2 py-0.5 text-xs font-medium rounded-full bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400"
|
||||
>
|
||||
{invoice.status}
|
||||
</span>
|
||||
{/if}
|
||||
|
|
@ -480,7 +537,8 @@
|
|||
<!-- Toast Notification -->
|
||||
{#if toastMessage}
|
||||
<div
|
||||
class="fixed bottom-4 right-4 z-50 px-4 py-3 rounded-lg shadow-lg animate-fade-in {toastType === 'success'
|
||||
class="fixed bottom-4 right-4 z-50 px-4 py-3 rounded-lg shadow-lg animate-fade-in {toastType ===
|
||||
'success'
|
||||
? 'bg-green-600 text-white'
|
||||
: 'bg-red-600 text-white'}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { Check } from '@manacore/shared-icons';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
|
@ -14,14 +15,7 @@
|
|||
<div
|
||||
class="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/30"
|
||||
>
|
||||
<svg
|
||||
class="h-10 w-10 text-green-600 dark:text-green-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<Check size={20} class="text-green-600 dark:text-green-400" />
|
||||
</div>
|
||||
|
||||
<h1 class="mb-4 text-2xl font-bold text-gray-900 dark:text-white">E-Mail bestätigt!</h1>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
// Get error from URL query params
|
||||
const error = $derived($page.url.searchParams.get('error') || 'unknown_error');
|
||||
|
|
@ -30,19 +31,7 @@
|
|||
<div
|
||||
class="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30"
|
||||
>
|
||||
<svg
|
||||
class="h-10 w-10 text-red-600 dark:text-red-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} class="text-red-600 dark:text-red-400" />
|
||||
</div>
|
||||
|
||||
<h1 class="mb-4 text-2xl font-bold text-gray-900 dark:text-white">
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
SettingsRow,
|
||||
GlobalSettingsSection,
|
||||
} from '@manacore/shared-ui';
|
||||
import { Info } from '@manacore/shared-icons';
|
||||
|
||||
onMount(async () => {
|
||||
await userSettings.load();
|
||||
|
|
@ -26,14 +27,7 @@
|
|||
<!-- About Section -->
|
||||
<SettingsSection title="Über">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info />
|
||||
{/snippet}
|
||||
|
||||
<SettingsCard>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { matrixStore, type SimpleMessage, type SimpleRoom } from '$lib/matrix';
|
||||
import { X, MagnifyingGlass, PaperPlaneTilt, User, Users } from '@manacore/shared-icons';
|
||||
import { Check, MagnifyingGlass, PaperPlaneTilt, User, Users, X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
|
@ -125,19 +125,7 @@
|
|||
: 'border-black/20 dark:border-white/20'}"
|
||||
>
|
||||
{#if selectedRooms.has(room.id)}
|
||||
<svg
|
||||
class="w-3 h-3 text-white"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={14} class="text-white" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { page } from '$app/stores';
|
||||
import { matrixStore, type SimpleMessage } from '$lib/matrix';
|
||||
import { RoomHeader, Timeline, MessageInput, DropZoneOverlay } from '$lib/components/chat';
|
||||
import { CaretLeft } from '@manacore/shared-icons';
|
||||
import RoomSettingsPanel from '$lib/components/chat/RoomSettingsPanel.svelte';
|
||||
import SearchDialog from '$lib/components/chat/SearchDialog.svelte';
|
||||
import ForwardMessageDialog from '$lib/components/chat/ForwardMessageDialog.svelte';
|
||||
|
|
@ -249,14 +250,7 @@
|
|||
<div
|
||||
class="w-10 h-10 rounded-full bg-primary/20 backdrop-blur-sm flex items-center justify-center"
|
||||
>
|
||||
<svg class="w-5 h-5 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 19l-7-7 7-7"
|
||||
/>
|
||||
</svg>
|
||||
<CaretLeft size={20} class="text-primary" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { moodCollection } from '$lib/data/local-store';
|
||||
import type { LocalMood } from '$lib/data/local-store';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
const moods = useLiveQuery(() => moodCollection.getAll());
|
||||
|
||||
|
|
@ -156,14 +157,7 @@
|
|||
}}
|
||||
class="absolute right-2 top-2 rounded-full p-1 text-gray-500 opacity-0 hover:bg-gray-800 hover:text-red-400 group-hover:opacity-100"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/></svg
|
||||
>
|
||||
<X size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useLiveQuery } from '@manacore/local-store/svelte';
|
||||
import { sequenceCollection, moodCollection } from '$lib/data/local-store';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { Trash } from '@manacore/shared-icons';
|
||||
|
||||
const sequences = useLiveQuery(() => sequenceCollection.getAll());
|
||||
const moods = useLiveQuery(() => moodCollection.getAll());
|
||||
|
|
@ -100,14 +101,7 @@
|
|||
onclick={() => deleteSequence(seq.id, seq.name)}
|
||||
class="rounded p-1 text-gray-500 opacity-0 hover:text-red-400 group-hover:opacity-100"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/></svg
|
||||
>
|
||||
<Trash size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { MusicNote, Pause, Play } from '@manacore/shared-icons';
|
||||
|
||||
interface LibraryBeat {
|
||||
id: string;
|
||||
|
|
@ -134,14 +135,7 @@
|
|||
{:else if beats.length === 0}
|
||||
<div class="text-center py-12 text-foreground-secondary">
|
||||
<div class="w-16 h-16 mx-auto mb-4 opacity-50">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-full h-full">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={20} class="w-full h-full" />
|
||||
</div>
|
||||
<p>No beats available in the library yet.</p>
|
||||
<p class="text-sm mt-2">Upload your own beat instead.</p>
|
||||
|
|
@ -159,13 +153,9 @@
|
|||
aria-label={previewingBeat === beat.id ? 'Stop preview' : 'Play preview'}
|
||||
>
|
||||
{#if previewingBeat === beat.id}
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
||||
</svg>
|
||||
<Pause size={20} weight="fill" />
|
||||
{:else}
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { audioStore } from '$lib/stores/audio.svelte';
|
||||
import { detectBpmFromFile } from '$lib/utils/bpm-detector';
|
||||
import BeatLibrary from './BeatLibrary.svelte';
|
||||
import { MusicNote, Upload, Warning } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
projectId: string;
|
||||
|
|
@ -138,14 +139,7 @@
|
|||
: 'text-foreground-secondary hover:text-foreground'}"
|
||||
>
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<Upload size={16} />
|
||||
Upload
|
||||
</span>
|
||||
{#if activeTab === 'upload'}
|
||||
|
|
@ -160,14 +154,7 @@
|
|||
: 'text-foreground-secondary hover:text-foreground'}"
|
||||
>
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={16} />
|
||||
Library
|
||||
</span>
|
||||
{#if activeTab === 'library'}
|
||||
|
|
@ -198,19 +185,7 @@
|
|||
<div class="space-y-4">
|
||||
<div class="w-16 h-16 mx-auto">
|
||||
{#if isDetectingBpm}
|
||||
<svg
|
||||
class="w-full h-full text-primary animate-pulse"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={20} class="w-full h-full text-primary animate-pulse" />
|
||||
{:else}
|
||||
<div
|
||||
class="w-full h-full border-4 border-primary border-t-transparent rounded-full animate-spin"
|
||||
|
|
@ -230,14 +205,7 @@
|
|||
{:else}
|
||||
<label for="beat-upload" class="cursor-pointer block">
|
||||
<div class="w-16 h-16 mx-auto mb-4 text-foreground-secondary">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-full h-full">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
/>
|
||||
</svg>
|
||||
<Upload size={20} class="w-full h-full" />
|
||||
</div>
|
||||
<p class="text-lg font-medium mb-2">Upload a Beat</p>
|
||||
<p class="text-foreground-secondary text-sm">
|
||||
|
|
@ -271,19 +239,7 @@
|
|||
</div>
|
||||
{:else if transcriptionError}
|
||||
<div class="flex items-center gap-3 p-4 bg-red-500/10 rounded-lg border border-red-500/30">
|
||||
<svg
|
||||
class="w-5 h-5 text-red-500 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<Warning size={20} class="text-red-500" />
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium text-red-500">Transcription failed</p>
|
||||
<p class="text-xs text-foreground-secondary">{transcriptionError}</p>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@
|
|||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import VisualizerRenderer from '$lib/visualizer/VisualizerRenderer.svelte';
|
||||
import { visualizerStore } from '$lib/visualizer/registry.svelte';
|
||||
import {
|
||||
CaretDown,
|
||||
Pause,
|
||||
Play,
|
||||
Playlist,
|
||||
Repeat,
|
||||
SkipForward,
|
||||
SpeakerHigh,
|
||||
X,
|
||||
} from '@manacore/shared-icons';
|
||||
|
||||
let innerHeight = $state(typeof window !== 'undefined' ? window.innerHeight : 800);
|
||||
|
||||
|
|
@ -49,14 +59,7 @@
|
|||
class="p-2 rounded-lg bg-white/10 hover:bg-white/20 backdrop-blur-sm transition-colors text-white"
|
||||
aria-label="Close player"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
<CaretDown size={24} />
|
||||
</button>
|
||||
<div class="text-sm text-white/70">Now Playing</div>
|
||||
<!-- Visualizer switcher -->
|
||||
|
|
@ -128,11 +131,7 @@
|
|||
: 'text-white/40 hover:text-white/70'}"
|
||||
aria-label="Toggle shuffle"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} weight="fill" />
|
||||
</button>
|
||||
|
||||
<!-- Previous -->
|
||||
|
|
@ -141,9 +140,7 @@
|
|||
class="p-2 rounded-full hover:bg-white/10 transition-colors text-white"
|
||||
aria-label="Previous track"
|
||||
>
|
||||
<svg class="w-7 h-7" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 6h2v12H6zm3.5 6l8.5 6V6z" />
|
||||
</svg>
|
||||
<SkipForward size={20} weight="fill" />
|
||||
</button>
|
||||
|
||||
<!-- Play/Pause -->
|
||||
|
|
@ -153,13 +150,9 @@
|
|||
aria-label={playerStore.isPlaying ? 'Pause' : 'Play'}
|
||||
>
|
||||
{#if playerStore.isPlaying}
|
||||
<svg class="w-8 h-8" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
||||
</svg>
|
||||
<Pause size={32} weight="fill" />
|
||||
{:else}
|
||||
<svg class="w-8 h-8" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={32} weight="fill" />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
@ -169,9 +162,7 @@
|
|||
class="p-2 rounded-full hover:bg-white/10 transition-colors text-white"
|
||||
aria-label="Next track"
|
||||
>
|
||||
<svg class="w-7 h-7" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 18l8.5-6L6 6v12zm2-8.14L11.03 12 8 14.14V9.86zM16 6h2v12h-2z" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" />
|
||||
</button>
|
||||
|
||||
<!-- Repeat -->
|
||||
|
|
@ -182,9 +173,7 @@
|
|||
: 'text-white/40 hover:text-white/70'}"
|
||||
aria-label="Toggle repeat ({playerStore.repeatMode})"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4z" />
|
||||
</svg>
|
||||
<Repeat size={20} weight="fill" />
|
||||
{#if playerStore.repeatMode === 'one'}
|
||||
<span
|
||||
class="absolute -top-1 -right-1 text-[10px] font-bold bg-white text-black rounded-full w-4 h-4 flex items-center justify-center"
|
||||
|
|
@ -196,11 +185,7 @@
|
|||
|
||||
<!-- Volume + Queue row -->
|
||||
<div class="flex items-center justify-center gap-4">
|
||||
<svg class="w-4 h-4 text-white/50 shrink-0" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"
|
||||
/>
|
||||
</svg>
|
||||
<SpeakerHigh size={16} weight="fill" class="text-white/50 shrink-0" />
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
|
|
@ -217,11 +202,7 @@
|
|||
: 'text-white/40 hover:text-white/70'}"
|
||||
aria-label="Toggle queue"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M15 6H3v2h12V6zm0 4H3v2h12v-2zM3 16h8v-2H3v2zM17 6v8.18c-.31-.11-.65-.18-1-.18-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3V8h3V6h-5z"
|
||||
/>
|
||||
</svg>
|
||||
<Playlist size={20} weight="fill" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { audioStore } from '$lib/stores/audio.svelte';
|
||||
import { editorStore } from '$lib/stores/editor.svelte';
|
||||
import { MARKER_COLORS, type MarkerType } from '@mukke/shared';
|
||||
import { ArrowsClockwise, Trash } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
onMarkerClick?: (markerId: string) => void;
|
||||
|
|
@ -175,27 +176,13 @@
|
|||
? 'Stop Loop (L)'
|
||||
: 'Loop Region (L)'}
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||
/>
|
||||
</svg>
|
||||
<ArrowsClockwise size={16} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => handleDeleteMarker(selectedMarker.id)}
|
||||
class="p-1 text-red-500 hover:bg-red-500/10 rounded"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import FrequencyBars from '$lib/visualizer/FrequencyBars.svelte';
|
||||
import { MusicNote, Pause, Play, X } from '@manacore/shared-icons';
|
||||
|
||||
let progress = $derived(
|
||||
playerStore.duration > 0 ? (playerStore.currentTime / playerStore.duration) * 100 : 0
|
||||
|
|
@ -35,14 +36,7 @@
|
|||
class="ml-auto p-0.5 hover:text-red-400 shrink-0"
|
||||
aria-label="Dismiss error"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -64,11 +58,7 @@
|
|||
class="flex items-center gap-3 flex-1 min-w-0"
|
||||
>
|
||||
<div class="w-12 h-12 rounded bg-background flex items-center justify-center shrink-0">
|
||||
<svg class="w-6 h-6 text-foreground-secondary" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={24} weight="fill" class="text-foreground-secondary" />
|
||||
</div>
|
||||
|
||||
<!-- Song info -->
|
||||
|
|
@ -91,13 +81,9 @@
|
|||
aria-label={playerStore.isPlaying ? 'Pause' : 'Play'}
|
||||
>
|
||||
{#if playerStore.isPlaying}
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
||||
</svg>
|
||||
<Pause size={20} weight="fill" />
|
||||
{:else}
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
@ -107,9 +93,7 @@
|
|||
class="p-2 rounded-lg hover:bg-surface-hover transition-colors text-foreground-secondary"
|
||||
aria-label="Next track"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 18l8.5-6L6 6v12zm2-8.14L11.03 12 8 14.14V9.86zM16 6h2v12h-2z" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { audioStore } from '$lib/stores/audio.svelte';
|
||||
import { editorStore } from '$lib/stores/editor.svelte';
|
||||
import { formatTime } from '$lib/utils/time-format';
|
||||
import { Pause, Play, SkipBack, SkipForward } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
onPlay?: () => void;
|
||||
|
|
@ -49,13 +50,9 @@
|
|||
aria-label={audioStore.isPlaying ? 'Pause' : 'Play'}
|
||||
>
|
||||
{#if audioStore.isPlaying}
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
||||
</svg>
|
||||
<Pause size={20} weight="fill" />
|
||||
{:else}
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
@ -104,14 +101,7 @@
|
|||
class="p-2 rounded-lg hover:bg-surface-hover transition-colors"
|
||||
aria-label="Skip backward 5 seconds"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0019 16V8a1 1 0 00-1.6-.8l-5.334 4zM4.066 11.2a1 1 0 000 1.6l5.334 4A1 1 0 0011 16V8a1 1 0 00-1.6-.8l-5.334 4z"
|
||||
/>
|
||||
</svg>
|
||||
<SkipForward size={20} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
|
|
@ -120,13 +110,9 @@
|
|||
aria-label={audioStore.isPlaying ? 'Pause' : 'Play'}
|
||||
>
|
||||
{#if audioStore.isPlaying}
|
||||
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
||||
</svg>
|
||||
<Pause size={24} weight="fill" />
|
||||
{:else}
|
||||
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={24} weight="fill" />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
@ -135,14 +121,7 @@
|
|||
class="p-2 rounded-lg hover:bg-surface-hover transition-colors"
|
||||
aria-label="Skip forward 5 seconds"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11.933 12.8a1 1 0 000-1.6L6.6 7.2A1 1 0 005 8v8a1 1 0 001.6.8l5.333-4zM19.933 12.8a1 1 0 000-1.6l-5.333-4A1 1 0 0013 8v8a1 1 0 001.6.8l5.333-4z"
|
||||
/>
|
||||
</svg>
|
||||
<SkipBack size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
function formatTime(s: number | null): string {
|
||||
if (!s || !isFinite(s)) return '0:00';
|
||||
|
|
@ -27,14 +28,7 @@
|
|||
class="p-2 rounded-lg hover:bg-surface-hover transition-colors text-foreground-secondary"
|
||||
aria-label="Close queue"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -96,14 +90,7 @@
|
|||
class="p-1.5 rounded-lg hover:bg-surface-hover transition-colors text-foreground-secondary hover:text-foreground shrink-0"
|
||||
aria-label="Remove from queue"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { Song } from '@mukke/shared';
|
||||
import { libraryStore } from '$lib/stores/library.svelte';
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
song: Song;
|
||||
|
|
@ -123,14 +124,7 @@
|
|||
onclick={onclose}
|
||||
class="p-1 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { connectAnalyzer, getAudioContext, getSourceNode, resumeAudioContext } from './analyzer';
|
||||
import { CaretLeft, CaretRight } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
height?: number;
|
||||
|
|
@ -159,9 +160,7 @@
|
|||
class="p-1.5 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
|
||||
aria-label="Previous preset"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
|
||||
</svg>
|
||||
<CaretRight size={16} weight="fill" />
|
||||
</button>
|
||||
|
||||
<span class="text-xs text-white/80 bg-black/50 px-2 py-1 rounded truncate max-w-[60%]">
|
||||
|
|
@ -173,9 +172,7 @@
|
|||
class="p-1.5 rounded-full bg-black/50 text-white hover:bg-black/70 transition-colors"
|
||||
aria-label="Next preset"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z" />
|
||||
</svg>
|
||||
<CaretLeft size={16} weight="fill" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { libraryStore } from '$lib/stores/library.svelte';
|
||||
import { projectStore } from '$lib/stores/project.svelte';
|
||||
import { DownloadSimple, Note, Plus } from '@manacore/shared-icons';
|
||||
|
||||
let statsLoading = $state(true);
|
||||
let projectsLoading = $state(true);
|
||||
|
|
@ -80,28 +81,14 @@
|
|||
href="/upload"
|
||||
class="inline-flex items-center gap-2 px-4 py-2.5 bg-primary text-white rounded-lg hover:bg-primary-hover transition-colors font-medium"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
|
||||
/>
|
||||
</svg>
|
||||
<DownloadSimple size={20} />
|
||||
Upload Songs
|
||||
</a>
|
||||
<a
|
||||
href="/projects"
|
||||
class="inline-flex items-center gap-2 px-4 py-2.5 bg-surface border border-border text-foreground rounded-lg hover:bg-background transition-colors font-medium"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
Create Project
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -125,19 +112,7 @@
|
|||
</div>
|
||||
{:else if projectStore.projects.length === 0}
|
||||
<div class="text-center py-12 bg-surface rounded-lg">
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary mx-auto mb-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
||||
/>
|
||||
</svg>
|
||||
<Note size={48} class="text-foreground-secondary mx-auto mb-3" />
|
||||
<p class="text-foreground-secondary mb-2">No projects yet</p>
|
||||
<a href="/projects" class="text-sm text-primary hover:underline"
|
||||
>Create your first project</a
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
import BeatUploader from '$lib/components/BeatUploader.svelte';
|
||||
import { ThemeToggle } from '@manacore/shared-theme-ui';
|
||||
import { theme } from '$lib/stores/theme.svelte';
|
||||
import { ArrowLeft, DownloadSimple, MusicNote } from '@manacore/shared-icons';
|
||||
|
||||
let waveformEditor: WaveformEditor;
|
||||
let showExportMenu = $state(false);
|
||||
|
|
@ -268,14 +269,7 @@
|
|||
href="/"
|
||||
class="text-foreground-secondary hover:text-foreground transition-colors shrink-0"
|
||||
>
|
||||
<svg class="w-5 h-5 md:w-6 md:h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
||||
/>
|
||||
</svg>
|
||||
<ArrowLeft size={20} class="md: md:" />
|
||||
</a>
|
||||
<div class="min-w-0">
|
||||
<h1 class="font-semibold text-sm md:text-base truncate">
|
||||
|
|
@ -305,14 +299,7 @@
|
|||
class="w-4 h-4 border-2 border-foreground border-t-transparent rounded-full animate-spin"
|
||||
></div>
|
||||
{:else}
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||
/>
|
||||
</svg>
|
||||
<DownloadSimple size={16} />
|
||||
{/if}
|
||||
<span class="hidden sm:inline">Export</span>
|
||||
</button>
|
||||
|
|
@ -370,14 +357,7 @@
|
|||
<div
|
||||
class="flex items-center gap-2 text-xs md:text-sm text-foreground-secondary truncate"
|
||||
>
|
||||
<svg class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={16} class="shrink-0" />
|
||||
<span class="truncate">{projectStore.currentBeat.filename}</span>
|
||||
</div>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import type { Song } from '@mukke/shared';
|
||||
import { useAllSongs } from '$lib/data/queries';
|
||||
import type { LocalSong } from '$lib/data/local-store';
|
||||
import { Heart, MusicNote, Pause, PencilSimple, Play, User } from '@manacore/shared-icons';
|
||||
|
||||
// Live query — auto-updates on IndexedDB changes
|
||||
const allSongs = useAllSongs();
|
||||
|
|
@ -185,19 +186,7 @@
|
|||
{#if libraryStore.activeTab === 'songs'}
|
||||
{#if songs.length === 0}
|
||||
<div class="text-center py-16">
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary mx-auto mb-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={48} class="text-foreground-secondary mx-auto mb-3" />
|
||||
<p class="text-foreground-secondary mb-2">No songs in your library</p>
|
||||
<a href="/upload" class="text-sm text-primary hover:underline">Upload your first song</a>
|
||||
</div>
|
||||
|
|
@ -247,39 +236,26 @@
|
|||
}}
|
||||
/>
|
||||
{:else}
|
||||
<svg
|
||||
class="w-5 h-5 text-foreground-secondary transition-opacity {playerStore
|
||||
.currentSong?.id === song.id && playerStore.isPlaying
|
||||
<MusicNote
|
||||
size={20}
|
||||
class="text-foreground-secondary transition-opacity {playerStore.currentSong
|
||||
?.id === song.id && playerStore.isPlaying
|
||||
? 'opacity-0'
|
||||
: 'group-hover:opacity-0'}"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
/>
|
||||
{/if}
|
||||
<!-- Playing indicator or play icon on hover -->
|
||||
{#if playerStore.currentSong?.id === song.id && playerStore.isPlaying}
|
||||
<div
|
||||
class="absolute inset-0 flex items-center justify-center bg-black/40 rounded"
|
||||
>
|
||||
<svg class="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" />
|
||||
</svg>
|
||||
<Pause size={20} weight="fill" class="text-white" />
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="absolute inset-0 items-center justify-center bg-black/40 rounded hidden group-hover:flex"
|
||||
>
|
||||
<svg class="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" class="text-white" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
@ -298,28 +274,14 @@
|
|||
class="p-1 text-foreground-secondary hover:text-primary transition-colors"
|
||||
title="Edit metadata"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
|
||||
/>
|
||||
</svg>
|
||||
<PencilSimple size={16} />
|
||||
</button>
|
||||
<button
|
||||
onclick={(e) => openInEditor(song.id, e)}
|
||||
class="p-1 text-foreground-secondary hover:text-primary transition-colors"
|
||||
title="Open in Editor"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={16} />
|
||||
</button>
|
||||
<button
|
||||
onclick={(e) => handleToggleFavorite(song.id, e)}
|
||||
|
|
@ -328,19 +290,7 @@
|
|||
: 'text-foreground-secondary hover:text-red-500'}"
|
||||
title={song.favorite ? 'Remove from favorites' : 'Add to favorites'}
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4"
|
||||
fill={song.favorite ? 'currentColor' : 'none'}
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="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"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
@ -375,19 +325,7 @@
|
|||
}}
|
||||
/>
|
||||
{:else}
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={48} class="text-foreground-secondary" />
|
||||
{/if}
|
||||
</div>
|
||||
<h3 class="font-medium truncate group-hover:text-primary transition-colors">
|
||||
|
|
@ -420,14 +358,7 @@
|
|||
<div
|
||||
class="w-10 h-10 rounded-full bg-background flex items-center justify-center text-foreground-secondary"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
<User size={20} />
|
||||
</div>
|
||||
<span class="font-medium">{artist.artist}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import type { Song } from '@mukke/shared';
|
||||
import { CaretLeft, MusicNote } from '@manacore/shared-icons';
|
||||
|
||||
function getBackendUrl(): string {
|
||||
let baseUrl = 'http://localhost:3010';
|
||||
|
|
@ -89,9 +90,7 @@
|
|||
href="/library"
|
||||
class="inline-flex items-center gap-1 text-sm text-foreground-secondary hover:text-foreground mb-6 transition-colors"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
Back to Library
|
||||
</a>
|
||||
|
||||
|
|
@ -114,19 +113,7 @@
|
|||
{#if coverUrl}
|
||||
<img src={coverUrl} alt={albumName} class="w-full h-full object-cover" />
|
||||
{:else}
|
||||
<svg
|
||||
class="w-16 h-16 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={20} class="text-foreground-secondary" />
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import type { Song } from '@mukke/shared';
|
||||
import { CaretLeft, User } from '@manacore/shared-icons';
|
||||
|
||||
function getBackendUrl(): string {
|
||||
let baseUrl = 'http://localhost:3010';
|
||||
|
|
@ -77,9 +78,7 @@
|
|||
href="/library"
|
||||
class="inline-flex items-center gap-1 text-sm text-foreground-secondary hover:text-foreground mb-6 transition-colors"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
Back to Library
|
||||
</a>
|
||||
|
||||
|
|
@ -97,19 +96,7 @@
|
|||
<!-- Artist header -->
|
||||
<div class="flex items-end gap-6 mb-8">
|
||||
<div class="w-36 h-36 bg-surface rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<svg
|
||||
class="w-14 h-14 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
<User size={20} class="text-foreground-secondary" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold mb-1">{artistName}</h1>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import type { Song } from '@mukke/shared';
|
||||
import { CaretLeft } from '@manacore/shared-icons';
|
||||
|
||||
function getBackendUrl(): string {
|
||||
let baseUrl = 'http://localhost:3010';
|
||||
|
|
@ -77,9 +78,7 @@
|
|||
href="/library"
|
||||
class="inline-flex items-center gap-1 text-sm text-foreground-secondary hover:text-foreground mb-6 transition-colors"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
Back to Library
|
||||
</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { playlistStore } from '$lib/stores/playlist.svelte';
|
||||
import { MukkeEvents } from '@manacore/shared-utils/analytics';
|
||||
import { useAllPlaylists } from '$lib/data/queries';
|
||||
import { List, MusicNote, Plus, Trash } from '@manacore/shared-icons';
|
||||
|
||||
// Live query — auto-updates on IndexedDB changes
|
||||
const allPlaylists = useAllPlaylists();
|
||||
|
|
@ -51,28 +52,14 @@
|
|||
onclick={() => (showCreateModal = true)}
|
||||
class="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors text-sm font-medium"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={16} />
|
||||
Create Playlist
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if allPlaylists.value.length === 0}
|
||||
<div class="text-center py-16">
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary mx-auto mb-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 10h16M4 14h16M4 18h16"
|
||||
/>
|
||||
</svg>
|
||||
<List size={48} class="text-foreground-secondary mx-auto mb-3" />
|
||||
<p class="text-foreground-secondary mb-3">No playlists yet</p>
|
||||
<button onclick={() => (showCreateModal = true)} class="text-sm text-primary hover:underline">
|
||||
Create your first playlist
|
||||
|
|
@ -91,19 +78,7 @@
|
|||
{#if playlist.coverArtPath && false}
|
||||
<img src={false} alt={playlist.name} class="w-full h-full object-cover" />
|
||||
{:else}
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={48} class="text-foreground-secondary" />
|
||||
{/if}
|
||||
</div>
|
||||
<h3 class="font-medium truncate group-hover:text-primary transition-colors">
|
||||
|
|
@ -119,14 +94,7 @@
|
|||
class="absolute top-3 right-3 p-1.5 rounded-lg bg-background/80 text-foreground-secondary hover:text-red-500 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
title="Delete playlist"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={16} />
|
||||
</button>
|
||||
</a>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { MukkeEvents } from '@manacore/shared-utils/analytics';
|
||||
import type { Song } from '@mukke/shared';
|
||||
import { CaretLeft, FileText, MusicNote, Play, Plus, X } from '@manacore/shared-icons';
|
||||
|
||||
let isEditingName = $state(false);
|
||||
let editName = $state('');
|
||||
|
|
@ -86,9 +87,7 @@
|
|||
href="/playlists"
|
||||
class="inline-flex items-center gap-1 text-sm text-foreground-secondary hover:text-foreground transition-colors mb-4"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
<CaretLeft size={16} />
|
||||
Back to Playlists
|
||||
</a>
|
||||
|
||||
|
|
@ -147,9 +146,7 @@
|
|||
disabled={playlistStore.currentPlaylist.songs.length === 0}
|
||||
class="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors text-sm font-medium disabled:opacity-50"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
<Play size={16} weight="fill" />
|
||||
Play All
|
||||
</button>
|
||||
<button
|
||||
|
|
@ -157,28 +154,14 @@
|
|||
disabled={playlistStore.currentPlaylist.songs.length === 0}
|
||||
class="flex items-center gap-2 px-4 py-2 bg-surface border border-border rounded-lg hover:bg-background transition-colors text-sm font-medium disabled:opacity-50"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 4h7l5 5v11H4V4zm10 0h6v6m-6-6l6 6M4 20l6-6"
|
||||
/>
|
||||
</svg>
|
||||
<FileText size={16} />
|
||||
Shuffle
|
||||
</button>
|
||||
<a
|
||||
href="/library"
|
||||
class="flex items-center gap-2 px-4 py-2 bg-surface border border-border rounded-lg hover:bg-background transition-colors text-sm font-medium"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={16} />
|
||||
Add Songs
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -186,19 +169,7 @@
|
|||
<!-- Song list -->
|
||||
{#if playlistStore.currentPlaylist.songs.length === 0}
|
||||
<div class="text-center py-16">
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary mx-auto mb-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={48} class="text-foreground-secondary mx-auto mb-3" />
|
||||
<p class="text-foreground-secondary mb-2">No songs in this playlist</p>
|
||||
<a href="/library" class="text-sm text-primary hover:underline">
|
||||
Browse your library to add songs
|
||||
|
|
@ -238,19 +209,7 @@
|
|||
class="w-full h-full object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<svg
|
||||
class="w-5 h-5 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={20} class="text-foreground-secondary" />
|
||||
{/if}
|
||||
</div>
|
||||
<span class="truncate font-medium">{song.title}</span>
|
||||
|
|
@ -264,14 +223,7 @@
|
|||
class="p-1 text-foreground-secondary hover:text-red-500 transition-colors"
|
||||
title="Remove from playlist"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { projectStore } from '$lib/stores/project.svelte';
|
||||
import { MukkeEvents } from '@manacore/shared-utils/analytics';
|
||||
import { MusicNote, Plus, Trash } from '@manacore/shared-icons';
|
||||
|
||||
let showCreateModal = $state(false);
|
||||
let newProjectTitle = $state('');
|
||||
|
|
@ -58,9 +59,7 @@
|
|||
onclick={() => (showCreateModal = true)}
|
||||
class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-hover transition-colors flex items-center gap-2"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
New Project
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -74,19 +73,7 @@
|
|||
{:else if projectStore.projects.length === 0}
|
||||
<div class="text-center py-16">
|
||||
<div class="w-16 h-16 bg-surface rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<svg
|
||||
class="w-8 h-8 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3"
|
||||
/>
|
||||
</svg>
|
||||
<MusicNote size={32} class="text-foreground-secondary" />
|
||||
</div>
|
||||
<h3 class="text-lg font-medium mb-2">No projects yet</h3>
|
||||
<p class="text-foreground-secondary mb-4">Create your first project to get started</p>
|
||||
|
|
@ -112,14 +99,7 @@
|
|||
onclick={(e) => handleDeleteProject(project.id, e)}
|
||||
class="p-1 text-foreground-secondary hover:text-red-500 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{#if project.description}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { playerStore } from '$lib/stores/player.svelte';
|
||||
import { playlistStore } from '$lib/stores/playlist.svelte';
|
||||
import type { Song } from '@mukke/shared';
|
||||
import { Heart, MagnifyingGlass, Note, Plus } from '@manacore/shared-icons';
|
||||
|
||||
let query = $state('');
|
||||
let results = $state<Song[]>([]);
|
||||
|
|
@ -80,19 +81,10 @@
|
|||
|
||||
<!-- Search input -->
|
||||
<div class="relative mb-6">
|
||||
<svg
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass
|
||||
size={20}
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 text-foreground-secondary"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={query}
|
||||
|
|
@ -113,19 +105,7 @@
|
|||
{:else if !hasSearched}
|
||||
<!-- Empty state before searching -->
|
||||
<div class="text-center py-16">
|
||||
<svg
|
||||
class="w-12 h-12 text-foreground-secondary mx-auto mb-3"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass size={48} class="text-foreground-secondary mx-auto mb-3" />
|
||||
<p class="text-foreground-secondary">Search your music library</p>
|
||||
</div>
|
||||
{:else if results.length === 0}
|
||||
|
|
@ -176,19 +156,7 @@
|
|||
: 'text-foreground-secondary hover:text-red-500'}"
|
||||
title={song.favorite ? 'Remove from favorites' : 'Add to favorites'}
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4"
|
||||
fill={song.favorite ? 'currentColor' : 'none'}
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="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"
|
||||
/>
|
||||
</svg>
|
||||
<Heart size={16} />
|
||||
</button>
|
||||
<!-- Add to Playlist -->
|
||||
<div class="relative">
|
||||
|
|
@ -197,14 +165,7 @@
|
|||
class="p-1 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
title="Add to playlist"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={16} />
|
||||
</button>
|
||||
{#if activePlaylistDropdown === song.id}
|
||||
<div
|
||||
|
|
@ -232,14 +193,7 @@
|
|||
class="p-1 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
title="Open in editor"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
||||
/>
|
||||
</svg>
|
||||
<Note size={16} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { libraryStore } from '$lib/stores/library.svelte';
|
||||
import { MukkeEvents } from '@manacore/shared-utils/analytics';
|
||||
import { Check, DownloadSimple, Plus, X } from '@manacore/shared-icons';
|
||||
|
||||
interface UploadFile {
|
||||
file: File;
|
||||
|
|
@ -159,27 +160,13 @@
|
|||
ondrop={handleDrop}
|
||||
role="region"
|
||||
>
|
||||
<svg
|
||||
class="w-12 h-12 mx-auto mb-4 text-foreground-secondary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
|
||||
/>
|
||||
</svg>
|
||||
<DownloadSimple size={48} class="mx-auto mb-4 text-foreground-secondary" />
|
||||
<p class="text-foreground-secondary mb-2">Drag and drop audio files here</p>
|
||||
<p class="text-sm text-foreground-secondary mb-4">or</p>
|
||||
<label
|
||||
class="inline-flex items-center gap-2 px-4 py-2.5 bg-primary text-white rounded-lg hover:bg-primary-hover transition-colors font-medium cursor-pointer"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={20} />
|
||||
Browse Files
|
||||
<input type="file" accept="audio/*" multiple class="hidden" onchange={handleFileInput} />
|
||||
</label>
|
||||
|
|
@ -198,19 +185,7 @@
|
|||
class="w-5 h-5 border-2 border-primary border-t-transparent rounded-full animate-spin flex-shrink-0"
|
||||
></div>
|
||||
{:else if uf.status === 'uploaded'}
|
||||
<svg
|
||||
class="w-5 h-5 text-green-500 flex-shrink-0"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="text-green-500" />
|
||||
{:else if uf.status === 'error'}
|
||||
<svg
|
||||
class="w-5 h-5 text-red-500 flex-shrink-0"
|
||||
|
|
@ -234,14 +209,7 @@
|
|||
onclick={() => removeFile(uf.id)}
|
||||
class="p-1 text-foreground-secondary hover:text-foreground flex-shrink-0"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import type { LocalArticle } from '$lib/data/local-store';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { Archive, Trash } from '@manacore/shared-icons';
|
||||
|
||||
const NEWS_SERVER = import.meta.env.PUBLIC_NEWS_SERVER_URL || 'http://localhost:3071';
|
||||
|
||||
|
|
@ -154,28 +155,14 @@
|
|||
class="rounded-lg p-2 text-gray-500 opacity-0 transition-all hover:bg-gray-800 hover:text-gray-300 group-hover:opacity-100"
|
||||
title={article.isArchived ? 'Wiederherstellen' : 'Archivieren'}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"
|
||||
/>
|
||||
</svg>
|
||||
<Archive size={16} />
|
||||
</button>
|
||||
<button
|
||||
onclick={() => deleteArticle(article)}
|
||||
class="rounded-lg p-2 text-gray-500 opacity-0 transition-all hover:bg-gray-800 hover:text-red-400 group-hover:opacity-100"
|
||||
title="Löschen"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
SettingsRow,
|
||||
GlobalSettingsSection,
|
||||
} from '@manacore/shared-ui';
|
||||
import { Info } from '@manacore/shared-icons';
|
||||
|
||||
onMount(async () => {
|
||||
await userSettings.load();
|
||||
|
|
@ -26,14 +27,7 @@
|
|||
<!-- About Section -->
|
||||
<SettingsSection title="Über">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info />
|
||||
{/snippet}
|
||||
|
||||
<SettingsCard>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import type { ChatMessage, ComparisonMessage } from '$lib/types';
|
||||
import MessageBubble from './MessageBubble.svelte';
|
||||
import ComparisonMessageBubble from './ComparisonMessageBubble.svelte';
|
||||
import { ChatCircle } from '@manacore/shared-icons';
|
||||
|
||||
let scrollContainer: HTMLDivElement | undefined = $state();
|
||||
|
||||
|
|
@ -18,20 +19,7 @@
|
|||
{#if chatStore.messages.length === 0}
|
||||
<div class="flex h-full flex-col items-center justify-center">
|
||||
<div class="mb-4 rounded-full p-4" style="background-color: var(--color-surface);">
|
||||
<svg
|
||||
class="h-12 w-12"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
style="color: var(--color-text-muted);"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1.5"
|
||||
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
||||
/>
|
||||
</svg>
|
||||
<ChatCircle size={20} />
|
||||
</div>
|
||||
<h2 class="mb-2 text-lg font-medium">Start a conversation</h2>
|
||||
<p class="max-w-md text-center text-sm" style="color: var(--color-text-muted);">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type { Skill, SkillBranch } from '$lib/types';
|
||||
import { BRANCH_INFO } from '$lib/types';
|
||||
import { X, Plus, Sparkle } from '@manacore/shared-icons';
|
||||
import { X, Plus, Sparkle, Check } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
|
|
@ -184,14 +184,7 @@
|
|||
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'}"
|
||||
>
|
||||
{#if isAdded}
|
||||
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={16} />
|
||||
{:else}
|
||||
<Plus class="h-4 w-4" />
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
SettingsRow,
|
||||
GlobalSettingsSection,
|
||||
} from '@manacore/shared-ui';
|
||||
import { Palette, Database, Info } from '@manacore/shared-icons';
|
||||
|
||||
let stats = $state<StorageStats | null>(null);
|
||||
let maxStorage = 10 * 1024 * 1024 * 1024; // 10 GB
|
||||
|
|
@ -43,14 +44,7 @@
|
|||
<!-- Appearance Section -->
|
||||
<SettingsSection title="Darstellung">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"
|
||||
/>
|
||||
</svg>
|
||||
<Palette />
|
||||
{/snippet}
|
||||
|
||||
<SettingsCard>
|
||||
|
|
@ -96,14 +90,7 @@
|
|||
<!-- Storage Section -->
|
||||
<SettingsSection title="Speicher">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"
|
||||
/>
|
||||
</svg>
|
||||
<Database />
|
||||
{/snippet}
|
||||
|
||||
<SettingsCard>
|
||||
|
|
@ -133,14 +120,7 @@
|
|||
<!-- About Section -->
|
||||
<SettingsSection title="Über">
|
||||
{#snippet icon()}
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info />
|
||||
{/snippet}
|
||||
|
||||
<SettingsCard>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { getContext } from 'svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { timeEntryCollection } from '$lib/data/local-store';
|
||||
import { X, CurrencyDollar } from '@manacore/shared-icons';
|
||||
import type { Project, Client } from '@times/shared';
|
||||
import {
|
||||
parseMultiEntryInput,
|
||||
|
|
@ -180,14 +181,7 @@
|
|||
onclick={onClose}
|
||||
class="rounded-lg p-1 text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]"
|
||||
>
|
||||
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -309,14 +303,7 @@
|
|||
? 'bg-[hsl(var(--primary)/0.1)] text-[hsl(var(--primary))]'
|
||||
: 'text-[hsl(var(--muted-foreground))]'}"
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyDollar size={16} />
|
||||
{isBillable ? $_('entry.billable') : $_('entry.notBillable')}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { _ } from 'svelte-i18n';
|
||||
import { timeEntryCollection } from '$lib/data/local-store';
|
||||
import { formatDurationCompact } from '$lib/data/queries';
|
||||
import { CurrencyDollar } from '@manacore/shared-icons';
|
||||
import type { TimeEntry, Project, Client } from '@times/shared';
|
||||
import ConfirmDialog from './ConfirmDialog.svelte';
|
||||
|
||||
|
|
@ -184,14 +185,7 @@
|
|||
? 'bg-[hsl(var(--primary)/0.1)] text-[hsl(var(--primary))]'
|
||||
: 'text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]'}"
|
||||
>
|
||||
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyDollar size={14} />
|
||||
{editIsBillable ? $_('entry.billable') : $_('entry.notBillable')}
|
||||
</button>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import EntryItem from './EntryItem.svelte';
|
||||
import { groupEntriesByDate, getTotalDuration, formatDurationCompact } from '$lib/data/queries';
|
||||
import type { TimeEntry } from '@times/shared';
|
||||
import { Clock } from '@manacore/shared-icons';
|
||||
|
||||
let { entries }: { entries: TimeEntry[] } = $props();
|
||||
|
||||
|
|
@ -33,19 +34,7 @@
|
|||
<div
|
||||
class="rounded-xl border border-dashed border-[hsl(var(--border))] p-8 text-center text-[hsl(var(--muted-foreground))]"
|
||||
>
|
||||
<svg
|
||||
class="mx-auto mb-3 h-10 w-10 opacity-50"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="1.5"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Clock size={20} class="mx-auto mb-3 opacity-50" />
|
||||
<p>{$_('entry.noEntries')}</p>
|
||||
</div>
|
||||
{:else}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { _ } from 'svelte-i18n';
|
||||
import { timerStore } from '$lib/stores/timer.svelte';
|
||||
import { formatDuration } from '$lib/data/queries';
|
||||
import { CurrencyDollar, Pause, Play } from '@manacore/shared-icons';
|
||||
import type { Project, Client } from '@times/shared';
|
||||
|
||||
const allProjects = getContext<{ value: Project[] }>('projects');
|
||||
|
|
@ -148,14 +149,7 @@
|
|||
: 'border-[hsl(var(--border))] text-[hsl(var(--muted-foreground))]'}"
|
||||
title={isBillable ? $_('entry.billable') : $_('entry.notBillable')}
|
||||
>
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CurrencyDollar size={16} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -168,17 +162,12 @@
|
|||
>
|
||||
{#if timerStore.isRunning}
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<rect x="6" y="4" width="4" height="16" rx="1" />
|
||||
<rect x="14" y="4" width="4" height="16" rx="1" />
|
||||
</svg>
|
||||
<Pause size={20} weight="fill" />
|
||||
{$_('timer.stop')}
|
||||
</span>
|
||||
{:else}
|
||||
<span class="flex items-center justify-center gap-2">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<polygon points="5 3 19 12 5 21 5 3" />
|
||||
</svg>
|
||||
<Play size={20} weight="fill" />
|
||||
{$_('timer.start')}
|
||||
</span>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { _ } from 'svelte-i18n';
|
||||
import { timerStore } from '$lib/stores/timer.svelte';
|
||||
import { formatDuration } from '$lib/data/queries';
|
||||
import { Stop } from '@manacore/shared-icons';
|
||||
import type { Project } from '@times/shared';
|
||||
|
||||
const allProjects = getContext<{ value: Project[] }>('projects');
|
||||
|
|
@ -54,9 +55,7 @@
|
|||
class="flex h-5 w-5 items-center justify-center rounded bg-red-500 text-white transition-colors hover:bg-red-600"
|
||||
title={$_('timer.stop')}
|
||||
>
|
||||
<svg class="h-2.5 w-2.5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<rect x="6" y="6" width="12" height="12" rx="1" />
|
||||
</svg>
|
||||
<Stop size={10} weight="fill" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import type { Client, Project, TimeEntry } from '@times/shared';
|
||||
import { PROJECT_COLORS } from '@times/shared/constants';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import { CaretRight } from '@manacore/shared-icons';
|
||||
|
||||
const allClients = getContext<{ value: Client[] }>('clients');
|
||||
const allProjects = getContext<{ value: Project[] }>('projects');
|
||||
|
|
@ -317,14 +318,7 @@
|
|||
onclick={() => (showArchived = !showArchived)}
|
||||
class="flex items-center gap-2 text-sm text-[hsl(var(--muted-foreground))]"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4 transition-transform {showArchived ? 'rotate-90' : ''}"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<CaretRight size={20} class="transition-transform {showArchived ? 'rotate-90' : ''}" />
|
||||
{$_('project.archived')} ({archivedClients.length})
|
||||
</button>
|
||||
{#if showArchived}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import type { Project, Client, TimeEntry } from '@times/shared';
|
||||
import { PROJECT_COLORS } from '@times/shared/constants';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import { CaretRight } from '@manacore/shared-icons';
|
||||
|
||||
const allProjects = getContext<{ value: Project[] }>('projects');
|
||||
const allClients = getContext<{ value: Client[] }>('clients');
|
||||
|
|
@ -330,14 +331,7 @@
|
|||
onclick={() => (showArchived = !showArchived)}
|
||||
class="flex items-center gap-2 text-sm text-[hsl(var(--muted-foreground))]"
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4 transition-transform {showArchived ? 'rotate-90' : ''}"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<CaretRight size={20} class="transition-transform {showArchived ? 'rotate-90' : ''}" />
|
||||
{$_('project.archived')} ({archivedProjects.length})
|
||||
</button>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { Clock } from '@manacore/shared-icons';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
|
@ -11,19 +12,7 @@
|
|||
<div
|
||||
class="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-2xl bg-[hsl(var(--muted))]"
|
||||
>
|
||||
<svg
|
||||
class="h-10 w-10 text-[hsl(var(--muted-foreground))]"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Clock size={20} class="text-[hsl(var(--muted-foreground))]" />
|
||||
</div>
|
||||
<h1 class="mb-2 text-2xl font-bold text-[hsl(var(--foreground))]">Offline</h1>
|
||||
<p class="mb-6 text-[hsl(var(--muted-foreground))]">
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
import { PRIORITY_OPTIONS } from '@todo/shared';
|
||||
import { format, addDays } from 'date-fns';
|
||||
import { de } from 'date-fns/locale';
|
||||
import { CalendarBlank, Folder, Plus, Flag, ArrowRight } from '@manacore/shared-icons';
|
||||
|
||||
let inputValue = $state('');
|
||||
let isLoading = $state(false);
|
||||
|
|
@ -266,9 +267,7 @@
|
|||
<div class="quick-add-wrapper">
|
||||
<!-- Plus icon -->
|
||||
<div class="quick-add-icon">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={16} />
|
||||
</div>
|
||||
|
||||
<!-- Input -->
|
||||
|
|
@ -296,14 +295,7 @@
|
|||
}}
|
||||
title="Fälligkeitsdatum"
|
||||
>
|
||||
<svg class="option-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<CalendarBlank size={20} class="option-icon" />
|
||||
<span class="option-label">{dateLabel()}</span>
|
||||
</button>
|
||||
|
||||
|
|
@ -335,20 +327,7 @@
|
|||
}}
|
||||
title="Priorität"
|
||||
>
|
||||
<svg
|
||||
class="option-icon"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke={currentPriority.color}
|
||||
style="color: {currentPriority.color}"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 21v-4m0 0V5a2 2 0 012-2h6.5l1 1H21l-3 6 3 6h-8.5l-1-1H5a2 2 0 00-2 2zm9-13.5V9"
|
||||
/>
|
||||
</svg>
|
||||
<Flag size={16} color={currentPriority.color} />
|
||||
</button>
|
||||
|
||||
{#if showPriorityPicker}
|
||||
|
|
@ -380,20 +359,7 @@
|
|||
}}
|
||||
title="Projekt"
|
||||
>
|
||||
<svg
|
||||
class="option-icon"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke={selectedProject?.color || 'currentColor'}
|
||||
style={selectedProject ? `color: ${selectedProject.color}` : ''}
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
<Folder size={20} class="option-icon" />
|
||||
</button>
|
||||
|
||||
{#if showProjectPicker}
|
||||
|
|
@ -432,14 +398,7 @@
|
|||
class="animate-spin h-4 w-4 border-2 border-white border-r-transparent rounded-full"
|
||||
></div>
|
||||
{:else}
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 7l5 5m0 0l-5 5m5-5H6"
|
||||
/>
|
||||
</svg>
|
||||
<ArrowRight size={16} />
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import type { Subtask } from '@todo/shared';
|
||||
import { dndzone } from 'svelte-dnd-action';
|
||||
import { flip } from 'svelte/animate';
|
||||
import { Check, Plus, X, DotsSixVertical } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
subtasks: Subtask[];
|
||||
|
|
@ -113,14 +114,7 @@
|
|||
<div class="subtask-item" animate:flip={{ duration: 200 }}>
|
||||
<!-- Drag handle -->
|
||||
<div class="drag-handle" aria-label="Ziehen zum Sortieren">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 8h16M4 16h16"
|
||||
/>
|
||||
</svg>
|
||||
<DotsSixVertical size={16} />
|
||||
</div>
|
||||
|
||||
<!-- Checkbox -->
|
||||
|
|
@ -131,14 +125,7 @@
|
|||
onclick={() => toggleComplete(subtask.id)}
|
||||
>
|
||||
{#if subtask.isCompleted}
|
||||
<svg class="check-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="check-icon" />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
|
@ -169,14 +156,7 @@
|
|||
onclick={() => deleteSubtask(subtask.id)}
|
||||
title="Löschen"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
@ -186,9 +166,7 @@
|
|||
<!-- Add new subtask -->
|
||||
<div class="add-subtask">
|
||||
<div class="add-icon">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<Plus size={16} />
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
import { ContactSelector, focusTrap } from '@manacore/shared-ui';
|
||||
import { ManaLinkList, ManaLinkPicker } from '@manacore/shared-links/ui';
|
||||
import { searchCrossApp } from '$lib/data/cross-app-search';
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
task: Task;
|
||||
|
|
@ -188,14 +189,7 @@
|
|||
<div class="modal-header">
|
||||
<h2 class="modal-title">Aufgabe bearbeiten</h2>
|
||||
<button type="button" class="close-btn" onclick={onClose} title="Schließen">
|
||||
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,15 @@
|
|||
|
||||
const tagsCtx: { readonly value: Tag[] } = getContext('tags');
|
||||
import type { SortBy, SortOrder } from '$lib/stores/view.svelte';
|
||||
import { X, DotsThree } from '@manacore/shared-icons';
|
||||
import {
|
||||
CaretDown,
|
||||
Check,
|
||||
CheckCircle,
|
||||
Columns,
|
||||
DotsThree,
|
||||
MagnifyingGlass,
|
||||
X,
|
||||
} from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
// Layout
|
||||
|
|
@ -135,14 +143,7 @@
|
|||
<!-- Kanban View Button -->
|
||||
{#if showKanbanNav}
|
||||
<button class="glass-pill" onclick={() => goto('/kanban')} title="Kanban-Ansicht">
|
||||
<svg class="pill-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"
|
||||
/>
|
||||
</svg>
|
||||
<Columns size={18} />
|
||||
<span class="pill-label">Kanban</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -183,19 +184,7 @@
|
|||
onclick={onToggleCompleted}
|
||||
title={isCompletedVisible ? 'Erledigte ausblenden' : 'Erledigte anzeigen'}
|
||||
>
|
||||
<svg
|
||||
class="pill-icon"
|
||||
fill={isCompletedVisible ? 'currentColor' : 'none'}
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CheckCircle size={20} class="pill-icon" />
|
||||
<span class="pill-label">Erledigt</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -239,19 +228,10 @@
|
|||
{#if showSearch}
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="relative flex-1 max-w-xs">
|
||||
<svg
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
<MagnifyingGlass
|
||||
size={16}
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
|
|
@ -264,14 +244,7 @@
|
|||
class="absolute right-2 top-1/2 -translate-y-1/2 p-1 text-muted-foreground hover:text-foreground rounded-full hover:bg-muted transition-colors"
|
||||
onclick={() => onSearchChange('')}
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
@ -281,14 +254,7 @@
|
|||
class="ml-auto px-3 py-2 text-sm text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors flex items-center gap-2"
|
||||
onclick={onClearFilters}
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
Zurücksetzen
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -368,21 +334,12 @@
|
|||
{:else}
|
||||
<span class="text-muted-foreground">Auswählen</span>
|
||||
{/if}
|
||||
<svg
|
||||
class="w-4 h-4 text-muted-foreground transition-transform {showLabelsDropdown
|
||||
<CaretDown
|
||||
size={16}
|
||||
class="text-muted-foreground transition-transform {showLabelsDropdown
|
||||
? 'rotate-180'
|
||||
: ''}"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
/>
|
||||
</button>
|
||||
|
||||
{#if showLabelsDropdown}
|
||||
|
|
@ -410,19 +367,7 @@
|
|||
></div>
|
||||
<span class="flex-1 text-left truncate">{label.name}</span>
|
||||
{#if selectedLabelIds.includes(label.id)}
|
||||
<svg
|
||||
class="w-4 h-4 text-primary flex-shrink-0"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={16} class="text-primary" />
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
import { ContactAvatar, ContactSelector } from '@manacore/shared-ui';
|
||||
import SubtaskList from './SubtaskList.svelte';
|
||||
import {
|
||||
import { Check, CheckSquare, DotsSixVertical } from '@manacore/shared-icons';
|
||||
PrioritySelector,
|
||||
StorypointsSelector,
|
||||
DurationPicker,
|
||||
|
|
@ -381,14 +382,7 @@
|
|||
>
|
||||
<!-- Drag handle -->
|
||||
<div class="drag-handle">
|
||||
<svg class="drag-icon" viewBox="0 0 24 24" fill="currentColor">
|
||||
<circle cx="9" cy="6" r="1.5" />
|
||||
<circle cx="15" cy="6" r="1.5" />
|
||||
<circle cx="9" cy="12" r="1.5" />
|
||||
<circle cx="15" cy="12" r="1.5" />
|
||||
<circle cx="9" cy="18" r="1.5" />
|
||||
<circle cx="15" cy="18" r="1.5" />
|
||||
</svg>
|
||||
<DotsSixVertical size={16} class="drag-icon" />
|
||||
</div>
|
||||
|
||||
<!-- Checkbox with priority fill -->
|
||||
|
|
@ -400,20 +394,7 @@
|
|||
onclick={handleToggleClick}
|
||||
>
|
||||
{#if task.isCompleted || isAnimatingComplete}
|
||||
<svg
|
||||
class="check-icon"
|
||||
class:animate-check={isAnimatingComplete}
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="check-icon" />
|
||||
{:else if task.priority === 'urgent'}
|
||||
<span class="priority-bang">!</span>
|
||||
{/if}
|
||||
|
|
@ -441,14 +422,7 @@
|
|||
<div class="task-meta">
|
||||
{#if subtaskProgress()}
|
||||
<span class="meta-item">
|
||||
<svg class="meta-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<CheckSquare size={20} class="meta-icon" />
|
||||
{subtaskProgress()}
|
||||
</span>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import { viewStore, type SortBy } from '$lib/stores/view.svelte';
|
||||
import { todoSettings } from '$lib/stores/settings.svelte';
|
||||
import { PillToolbarButton, PillToolbarDivider, PillViewSwitcher } from '@manacore/shared-ui';
|
||||
import { CheckCircle, Columns, Funnel } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
/** Vertical layout (for sidebar mode) */
|
||||
|
|
@ -91,14 +92,7 @@
|
|||
}}
|
||||
title="Ansicht wechseln"
|
||||
>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"
|
||||
/>
|
||||
</svg>
|
||||
<Columns size={20} />
|
||||
</PillToolbarButton>
|
||||
|
||||
{#if !vertical}
|
||||
|
|
@ -114,14 +108,7 @@
|
|||
active={activeFilterCount > 0}
|
||||
title="Filter"
|
||||
>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
|
||||
/>
|
||||
</svg>
|
||||
<Funnel size={20} />
|
||||
{#if activeFilterCount > 0}
|
||||
<span class="filter-count">{activeFilterCount}</span>
|
||||
{/if}
|
||||
|
|
@ -191,14 +178,7 @@
|
|||
active={showCompleted}
|
||||
title={showCompleted ? 'Erledigte ausblenden' : 'Erledigte anzeigen'}
|
||||
>
|
||||
<svg fill={showCompleted ? 'currentColor' : 'none'} stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<CheckCircle size={20} />
|
||||
</PillToolbarButton>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,40 @@
|
|||
<script lang="ts">
|
||||
import { dndzone, SHADOW_PLACEHOLDER_ITEM_ID, type DndEvent } from 'svelte-dnd-action';
|
||||
import type { LocalBoardView, ViewColumn } from '$lib/data/local-store';
|
||||
import {
|
||||
X,
|
||||
Plus,
|
||||
Columns,
|
||||
GridFour,
|
||||
Flag,
|
||||
Folder,
|
||||
CalendarBlank,
|
||||
List,
|
||||
Star,
|
||||
Tag,
|
||||
Clock,
|
||||
Crosshair,
|
||||
Lightning,
|
||||
Heart,
|
||||
DotsSixVertical,
|
||||
} from '@manacore/shared-icons';
|
||||
import type { ComponentType } from 'svelte';
|
||||
|
||||
// Map icon names to Phosphor components
|
||||
const phosphorIconMap: Record<string, ComponentType> = {
|
||||
columns: Columns,
|
||||
'grid-four': GridFour,
|
||||
flag: Flag,
|
||||
folders: Folder,
|
||||
calendar: CalendarBlank,
|
||||
list: List,
|
||||
star: Star,
|
||||
tag: Tag,
|
||||
clock: Clock,
|
||||
target: Crosshair,
|
||||
lightning: Lightning,
|
||||
heart: Heart,
|
||||
};
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
|
@ -30,24 +64,6 @@
|
|||
{ value: 'heart', label: 'Herz' },
|
||||
] as const;
|
||||
|
||||
const iconPathMap: Record<string, string> = {
|
||||
columns: 'M9 4h6v16H9zM3 4h4v16H3zM17 4h4v16h-4z',
|
||||
'grid-four': 'M3 3h8v8H3zM13 3h8v8h-8zM3 13h8v8H3zM13 13h8v8h-8z',
|
||||
flag: 'M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1zM4 22v-7',
|
||||
folders: 'M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z',
|
||||
calendar:
|
||||
'M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z',
|
||||
list: 'M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01',
|
||||
star: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z',
|
||||
tag: 'M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82zM7 7h.01',
|
||||
clock: 'M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM12 6v6l4 2',
|
||||
target:
|
||||
'M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM12 18a6 6 0 100-12 6 6 0 000 12zM12 14a2 2 0 100-4 2 2 0 000 4z',
|
||||
lightning: 'M13 2L3 14h9l-1 10 10-12h-9l1-10z',
|
||||
heart:
|
||||
'M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z',
|
||||
};
|
||||
|
||||
// ─── GroupBy options ────────────────────────────────────
|
||||
const groupByOptions = [
|
||||
{ value: 'status', label: 'Status' },
|
||||
|
|
@ -324,15 +340,7 @@
|
|||
<div class="modal-header">
|
||||
<h2 class="modal-title">{isEditMode ? 'View bearbeiten' : 'Neue View'}</h2>
|
||||
<button type="button" class="close-btn" onclick={onClose} aria-label="Schließen">
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M18 6L6 18M6 6l12 12" />
|
||||
</svg>
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -363,18 +371,9 @@
|
|||
onclick={() => (icon = opt.value)}
|
||||
title={opt.label}
|
||||
>
|
||||
{#if iconPathMap[opt.value]}
|
||||
<svg
|
||||
class="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d={iconPathMap[opt.value]} />
|
||||
</svg>
|
||||
{#if phosphorIconMap[opt.value]}
|
||||
{@const IconComp = phosphorIconMap[opt.value]}
|
||||
<IconComp size={20} />
|
||||
{/if}
|
||||
<span class="icon-label">{opt.label}</span>
|
||||
</button>
|
||||
|
|
@ -402,15 +401,7 @@
|
|||
class:selected={layout === 'kanban'}
|
||||
onclick={() => (layout = 'kanban')}
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d={iconPathMap.columns} />
|
||||
</svg>
|
||||
<Columns size={16} />
|
||||
Kanban
|
||||
</button>
|
||||
<button
|
||||
|
|
@ -419,15 +410,7 @@
|
|||
class:selected={layout === 'grid'}
|
||||
onclick={() => (layout = 'grid')}
|
||||
>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d={iconPathMap['grid-four']} />
|
||||
</svg>
|
||||
<GridFour size={16} />
|
||||
Grid
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -439,15 +422,7 @@
|
|||
<label class="field-label">Spalten</label>
|
||||
{#if columnsEditable}
|
||||
<button type="button" class="add-col-btn" onclick={addColumn}>
|
||||
<svg
|
||||
class="h-3.5 w-3.5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
<Plus size={14} />
|
||||
Hinzufügen
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -482,16 +457,7 @@
|
|||
<!-- Drag handle -->
|
||||
{#if columnsEditable}
|
||||
<span class="drag-handle" aria-label="Spalte verschieben">
|
||||
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor">
|
||||
<circle cx="9" cy="5" r="1.5" />
|
||||
<circle cx="15" cy="5" r="1.5" />
|
||||
<circle cx="9" cy="10" r="1.5" />
|
||||
<circle cx="15" cy="10" r="1.5" />
|
||||
<circle cx="9" cy="15" r="1.5" />
|
||||
<circle cx="15" cy="15" r="1.5" />
|
||||
<circle cx="9" cy="20" r="1.5" />
|
||||
<circle cx="15" cy="20" r="1.5" />
|
||||
</svg>
|
||||
<DotsSixVertical size={16} weight="bold" />
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
|
|
@ -540,15 +506,7 @@
|
|||
onclick={() => removeColumn(col.id)}
|
||||
title="Spalte entfernen"
|
||||
>
|
||||
<svg
|
||||
class="h-3.5 w-3.5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M18 6L6 18M6 6l12 12" />
|
||||
</svg>
|
||||
<X size={14} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,40 @@
|
|||
<script lang="ts">
|
||||
import { dndzone, SHADOW_PLACEHOLDER_ITEM_ID, type DndEvent } from 'svelte-dnd-action';
|
||||
import type { LocalBoardView } from '$lib/data/local-store';
|
||||
import {
|
||||
DotsThreeVertical,
|
||||
Plus,
|
||||
PencilSimple,
|
||||
Columns,
|
||||
GridFour,
|
||||
Flag,
|
||||
Folder,
|
||||
CalendarBlank,
|
||||
List,
|
||||
Star,
|
||||
Tag,
|
||||
Clock,
|
||||
Crosshair,
|
||||
Lightning,
|
||||
Heart,
|
||||
} from '@manacore/shared-icons';
|
||||
import type { ComponentType } from 'svelte';
|
||||
|
||||
// Map icon names to Phosphor components
|
||||
const phosphorIconMap: Record<string, ComponentType> = {
|
||||
columns: Columns,
|
||||
'grid-four': GridFour,
|
||||
flag: Flag,
|
||||
folders: Folder,
|
||||
calendar: CalendarBlank,
|
||||
list: List,
|
||||
star: Star,
|
||||
tag: Tag,
|
||||
clock: Clock,
|
||||
target: Crosshair,
|
||||
lightning: Lightning,
|
||||
heart: Heart,
|
||||
};
|
||||
|
||||
interface Props {
|
||||
views: LocalBoardView[];
|
||||
|
|
@ -37,25 +71,6 @@
|
|||
let contextMenuViewId = $state<string | null>(null);
|
||||
let contextMenuPos = $state({ x: 0, y: 0 });
|
||||
|
||||
// Map icon names to simple SVG representations
|
||||
const iconMap: Record<string, string> = {
|
||||
columns: 'M9 4h6v16H9zM3 4h4v16H3zM17 4h4v16h-4z',
|
||||
'grid-four': 'M3 3h8v8H3zM13 3h8v8h-8zM3 13h8v8H3zM13 13h8v8h-8z',
|
||||
flag: 'M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1zM4 22v-7',
|
||||
folders: 'M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z',
|
||||
calendar:
|
||||
'M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z',
|
||||
list: 'M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01',
|
||||
star: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z',
|
||||
tag: 'M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82zM7 7h.01',
|
||||
clock: 'M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM12 6v6l4 2',
|
||||
target:
|
||||
'M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10zM12 18a6 6 0 100-12 6 6 0 000 12zM12 14a2 2 0 100-4 2 2 0 000 4z',
|
||||
lightning: 'M13 2L3 14h9l-1 10 10-12h-9l1-10z',
|
||||
heart:
|
||||
'M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z',
|
||||
};
|
||||
|
||||
function handleContextMenu(e: MouseEvent, view: LocalBoardView) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
|
@ -107,18 +122,9 @@
|
|||
onclick={() => onSelect(view.id)}
|
||||
oncontextmenu={(e) => handleContextMenu(e, view)}
|
||||
>
|
||||
{#if view.icon && iconMap[view.icon]}
|
||||
<svg
|
||||
class="h-4 w-4 mr-1.5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d={iconMap[view.icon]} />
|
||||
</svg>
|
||||
{#if view.icon && phosphorIconMap[view.icon]}
|
||||
{@const IconComponent = phosphorIconMap[view.icon]}
|
||||
<span class="mr-1.5"><IconComponent size={16} /></span>
|
||||
{:else if view.icon}
|
||||
<span class="mr-1.5 text-sm">{view.icon}</span>
|
||||
{/if}
|
||||
|
|
@ -131,11 +137,7 @@
|
|||
onclick={(e) => handleMoreClick(e, view)}
|
||||
aria-label="View-Optionen"
|
||||
>
|
||||
<svg class="h-3 w-3" viewBox="0 0 24 24" fill="currentColor">
|
||||
<circle cx="12" cy="5" r="2" />
|
||||
<circle cx="12" cy="12" r="2" />
|
||||
<circle cx="12" cy="19" r="2" />
|
||||
</svg>
|
||||
<DotsThreeVertical size={12} weight="bold" />
|
||||
</button>
|
||||
{/if}
|
||||
</button>
|
||||
|
|
@ -144,17 +146,7 @@
|
|||
|
||||
{#if onCreate}
|
||||
<button type="button" class="view-pill add-pill" onclick={onCreate}>
|
||||
<svg
|
||||
class="h-4 w-4"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
<Plus size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
@ -168,10 +160,7 @@
|
|||
role="menu"
|
||||
>
|
||||
<button type="button" class="context-item" role="menuitem" onclick={handleEditClick}>
|
||||
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" />
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" />
|
||||
</svg>
|
||||
<PencilSimple size={16} />
|
||||
Bearbeiten
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import type { DurationUnit, EffectiveDuration } from '@todo/shared';
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
value: EffectiveDuration | null;
|
||||
|
|
@ -96,14 +97,7 @@
|
|||
</button>
|
||||
{#if value !== null}
|
||||
<button type="button" class="duration-clear" onclick={clear} title="Zurücksetzen">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
value: number | null;
|
||||
onChange: (value: number | null) => void;
|
||||
|
|
@ -38,14 +40,7 @@
|
|||
{/each}
|
||||
{#if value !== null}
|
||||
<button type="button" class="fun-rating-clear" onclick={handleClear} title="Zurücksetzen">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
value: number | null;
|
||||
onChange: (value: number | null) => void;
|
||||
|
|
@ -31,14 +33,7 @@
|
|||
{/each}
|
||||
{#if value !== null}
|
||||
<button type="button" class="storypoint-clear" onclick={handleClear} title="Zurücksetzen">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import type { Tag } from '@manacore/shared-tags';
|
||||
import { CaretDown, Check } from '@manacore/shared-icons';
|
||||
|
||||
const tagsCtx: { readonly value: Tag[] } = getContext('tags');
|
||||
|
||||
|
|
@ -52,9 +53,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<svg class="dropdown-arrow" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
<CaretDown size={20} class="dropdown-arrow" />
|
||||
</button>
|
||||
|
||||
{#if showDropdown}
|
||||
|
|
@ -71,14 +70,7 @@
|
|||
<span class="tag-dot" style="background-color: {tag.color}"></span>
|
||||
<span class="tag-name">{tag.name}</span>
|
||||
{#if selectedIds.includes(tag.id)}
|
||||
<svg class="check-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="check-icon" />
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@
|
|||
import { de } from 'date-fns/locale';
|
||||
import { ConfirmationModal, ContactAvatar } from '@manacore/shared-ui';
|
||||
import TaskEditModal from '../TaskEditModal.svelte';
|
||||
import {
|
||||
ArrowsClockwise,
|
||||
CalendarBlank,
|
||||
Check,
|
||||
CheckSquare,
|
||||
Note,
|
||||
Trash,
|
||||
} from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
task: Task;
|
||||
|
|
@ -172,14 +180,7 @@
|
|||
{#if onToggleComplete}
|
||||
<button class="task-checkbox" class:checked={task.isCompleted} onclick={onToggleComplete}>
|
||||
{#if task.isCompleted}
|
||||
<svg class="check-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="3"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
</svg>
|
||||
<Check size={20} class="check-icon" />
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
|
@ -210,28 +211,14 @@
|
|||
<div class="task-meta">
|
||||
{#if dueDateText()}
|
||||
<span class="meta-item" class:overdue={isOverdue()}>
|
||||
<svg class="meta-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<CalendarBlank size={20} class="meta-icon" />
|
||||
{dueDateText()}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
{#if subtaskProgress()}
|
||||
<span class="meta-item">
|
||||
<svg class="meta-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
|
||||
/>
|
||||
</svg>
|
||||
<CheckSquare size={20} class="meta-icon" />
|
||||
{subtaskProgress()}
|
||||
</span>
|
||||
{/if}
|
||||
|
|
@ -286,46 +273,16 @@
|
|||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<button class="context-item" onclick={handleContextEdit}>
|
||||
<svg class="context-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
||||
/>
|
||||
</svg>
|
||||
<Note size={20} class="context-icon" />
|
||||
Bearbeiten
|
||||
</button>
|
||||
<button class="context-item" onclick={handleContextToggleComplete}>
|
||||
<svg class="context-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
{#if task.isCompleted}
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||
/>
|
||||
{:else}
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
{/if}
|
||||
</svg>
|
||||
<ArrowsClockwise size={20} class="context-icon" />
|
||||
{task.isCompleted ? 'Wiederherstellen' : 'Erledigen'}
|
||||
</button>
|
||||
<div class="context-divider"></div>
|
||||
<button class="context-item danger" onclick={handleContextDelete}>
|
||||
<svg class="context-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
<Trash size={20} class="context-icon" />
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { Plus, X } from '@manacore/shared-icons';
|
||||
|
||||
interface Props {
|
||||
onAdd: (title: string) => void;
|
||||
placeholder?: string;
|
||||
|
|
@ -54,14 +56,7 @@
|
|||
onmousedown={(e) => e.preventDefault()}
|
||||
onclick={handleSubmit}
|
||||
>
|
||||
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={14} />
|
||||
Hinzufügen
|
||||
</button>
|
||||
<button
|
||||
|
|
@ -72,14 +67,7 @@
|
|||
isAdding = false;
|
||||
}}
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
<X size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -91,14 +79,7 @@
|
|||
<div
|
||||
class="w-5 h-5 rounded-full border-2 border-dashed border-current group-hover:border-primary group-hover:text-primary flex items-center justify-center transition-colors"
|
||||
>
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
<Plus size={14} />
|
||||
</div>
|
||||
<span class="group-hover:text-foreground transition-colors">Aufgabe hinzufügen</span>
|
||||
</button>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue