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:
Till JS 2026-03-31 12:35:17 +02:00
parent f58d58ff99
commit 504e7756a7
115 changed files with 781 additions and 3084 deletions

View file

@ -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>

View file

@ -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>

View file

@ -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}

View file

@ -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}

View file

@ -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}

View file

@ -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}

View file

@ -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>

View file

@ -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))]">