fix: resolve runtime errors and missing routes
- Fix $effect orphan error: move $effect calls from store constructors to initEffects() methods called from component context - Fix icon rendering: create DynamicIcon component to render Lucide icons from name strings instead of displaying raw text - Add /boards/new route for board creation - Fix seed emails (admin@launcher.local / user@launcher.local) to pass Zod email validation
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import DynamicIcon from '$lib/components/ui/DynamicIcon.svelte';
|
||||
|
||||
interface BoardSummary {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -24,7 +26,7 @@
|
||||
>
|
||||
<div class="flex items-start gap-3">
|
||||
{#if board.icon}
|
||||
<span class="text-xl">{board.icon}</span>
|
||||
<DynamicIcon name={board.icon} size={22} />
|
||||
{:else}
|
||||
<span class="flex h-8 w-8 items-center justify-center rounded-md bg-muted text-sm text-muted-foreground">
|
||||
B
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import DynamicIcon from '$lib/components/ui/DynamicIcon.svelte';
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
description: string | null;
|
||||
@@ -13,7 +15,7 @@
|
||||
<div class="mb-6 flex items-start justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
{#if icon}
|
||||
<span class="text-2xl">{icon}</span>
|
||||
<DynamicIcon name={icon} size={28} />
|
||||
{/if}
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-foreground">{name}</h1>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ui } from '$lib/stores/ui.svelte.js';
|
||||
import { page } from '$app/stores';
|
||||
import DynamicIcon from '$lib/components/ui/DynamicIcon.svelte';
|
||||
|
||||
interface BoardLink {
|
||||
id: string;
|
||||
@@ -150,7 +151,7 @@
|
||||
onclick={() => ui.closeMobileSidebar()}
|
||||
>
|
||||
{#if board.icon}
|
||||
<span class="shrink-0 text-base">{board.icon}</span>
|
||||
<span class="shrink-0"><DynamicIcon name={board.icon} size={18} /></span>
|
||||
{:else}
|
||||
<span
|
||||
class="flex h-5 w-5 shrink-0 items-center justify-center rounded bg-sidebar-accent text-[10px] font-medium text-sidebar-foreground"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import DynamicIcon from '$lib/components/ui/DynamicIcon.svelte';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
icon: string | null;
|
||||
@@ -29,7 +31,7 @@
|
||||
</svg>
|
||||
|
||||
{#if icon}
|
||||
<span class="text-base">{icon}</span>
|
||||
<DynamicIcon name={icon} size={18} />
|
||||
{/if}
|
||||
|
||||
<span class="font-medium text-foreground">{title}</span>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import * as icons from 'lucide-svelte';
|
||||
|
||||
interface Props {
|
||||
name: string | null;
|
||||
size?: number;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
let { name, size = 16, class: className = '' }: Props = $props();
|
||||
|
||||
// Convert kebab-case to PascalCase: "layout-dashboard" → "LayoutDashboard"
|
||||
function toPascalCase(str: string): string {
|
||||
return str
|
||||
.split('-')
|
||||
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
||||
.join('');
|
||||
}
|
||||
|
||||
const iconComponent = $derived(
|
||||
name ? (icons as Record<string, unknown>)[toPascalCase(name)] ?? null : null
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if iconComponent}
|
||||
<svelte:component this={iconComponent} {size} class={className} />
|
||||
{/if}
|
||||
Reference in New Issue
Block a user