refactor: migrate all Svelte components from Svelte 4 to Svelte 5 runes
- Replace `export let` with `$props()` and `$bindable()` across all components
- Replace `$:` reactive statements with `$derived()` and `$effect()`
- Replace `createEventDispatcher` with callback props (e.g. `onchange`)
- Replace `on:event` directives with inline event handlers (`onclick`, `oninput`, etc.)
- Replace `<slot />` with `{@render children()}` in layout
- Use `untrack()` for SSR-safe $state initialization from reactive props
- Replace `blur` + `setTimeout` anti-pattern in TagInput with `clickOutside` action
- Fix `page` store usage in layout to use `$app/state` directly
- 0 errors, 0 warnings after svelte-check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,15 +2,17 @@
|
||||
import { enhance } from '$app/forms';
|
||||
import { slide } from 'svelte/transition';
|
||||
|
||||
export let data;
|
||||
export let form;
|
||||
let { data, form } = $props();
|
||||
|
||||
let activeTab = 'users';
|
||||
let editingTagId: string | null = null;
|
||||
let editingTagName = '';
|
||||
let editingUserId: string | null = null;
|
||||
let activeTab = $state('users');
|
||||
let editingTagId: string | null = $state(null);
|
||||
let editingTagName = $state('');
|
||||
let editingUserId: string | null = $state(null);
|
||||
let editingGroupId: string | null = $state(null);
|
||||
|
||||
function startEditTag(tag: any) {
|
||||
const availablePermissions = ['WRITE_ALL', 'ADMIN', 'ADMIN_USER', 'ADMIN_TAG', 'ADMIN_PERMISSION'];
|
||||
|
||||
function startEditTag(tag: { id: string; name: string }) {
|
||||
editingTagId = tag.id;
|
||||
editingTagName = tag.name;
|
||||
}
|
||||
@@ -20,7 +22,7 @@
|
||||
editingTagName = '';
|
||||
}
|
||||
|
||||
function startEditUser(id: string) {
|
||||
function startEditUser(id: string) {
|
||||
editingUserId = id;
|
||||
}
|
||||
|
||||
@@ -28,9 +30,6 @@
|
||||
editingUserId = null;
|
||||
}
|
||||
|
||||
let editingGroupId: string | null = null;
|
||||
const availablePermissions = ['WRITE_ALL', 'ADMIN', 'ADMIN_USER', 'ADMIN_TAG', 'ADMIN_PERMISSION'];
|
||||
|
||||
function startEditGroup(id: string) {
|
||||
editingGroupId = id;
|
||||
}
|
||||
@@ -51,21 +50,21 @@
|
||||
'users'
|
||||
? 'bg-brand-navy text-white'
|
||||
: 'text-gray-500 hover:text-brand-navy'}"
|
||||
on:click={() => (activeTab = 'users')}>Benutzer</button
|
||||
onclick={() => (activeTab = 'users')}>Benutzer</button
|
||||
>
|
||||
<button
|
||||
class="px-4 py-2 text-sm font-bold uppercase tracking-wide rounded-md transition {activeTab ===
|
||||
'groups'
|
||||
? 'bg-brand-navy text-white'
|
||||
: 'text-gray-500 hover:text-brand-navy'}"
|
||||
on:click={() => (activeTab = 'groups')}>Gruppen</button
|
||||
onclick={() => (activeTab = 'groups')}>Gruppen</button
|
||||
>
|
||||
<button
|
||||
class="px-4 py-2 text-sm font-bold uppercase tracking-wide rounded-md transition {activeTab ===
|
||||
'tags'
|
||||
? 'bg-brand-navy text-white'
|
||||
: 'text-gray-500 hover:text-brand-navy'}"
|
||||
on:click={() => (activeTab = 'tags')}>Schlagworte</button
|
||||
onclick={() => (activeTab = 'tags')}>Schlagworte</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,7 +105,6 @@
|
||||
<!-- === EDIT MODE === -->
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{user.username}
|
||||
<!-- Hidden ID Input for the form -->
|
||||
<input
|
||||
type="hidden"
|
||||
name="username"
|
||||
@@ -116,7 +114,6 @@
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 text-sm">
|
||||
<!-- Groups Select -->
|
||||
<select
|
||||
name="groupIds"
|
||||
multiple
|
||||
@@ -126,7 +123,7 @@
|
||||
{#each data.groups as group}
|
||||
<option
|
||||
value={group.id}
|
||||
selected={user.groups.some((g) => g.id === group.id)}
|
||||
selected={user.groups.some((g: { id: string }) => g.id === group.id)}
|
||||
>
|
||||
{group.name}
|
||||
</option>
|
||||
@@ -136,7 +133,6 @@
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right align-top">
|
||||
<!-- Password & Buttons -->
|
||||
<form
|
||||
id="edit-form-{user.id}"
|
||||
method="POST"
|
||||
@@ -164,7 +160,7 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={cancelEditUser}
|
||||
onclick={cancelEditUser}
|
||||
class="bg-gray-200 text-gray-600 px-2 py-1 rounded text-xs font-bold uppercase hover:bg-gray-300"
|
||||
>
|
||||
Abbrechen
|
||||
@@ -194,15 +190,13 @@
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<div class="flex items-center justify-end gap-4">
|
||||
<!-- Edit Button -->
|
||||
<button
|
||||
on:click={() => startEditUser(user.id)}
|
||||
onclick={() => startEditUser(user.id)}
|
||||
class="text-brand-mint hover:text-brand-navy text-sm font-bold uppercase tracking-wide"
|
||||
>
|
||||
Bearbeiten
|
||||
</button>
|
||||
|
||||
<!-- Delete Button -->
|
||||
<form
|
||||
method="POST"
|
||||
action="?/deleteUser"
|
||||
@@ -265,7 +259,6 @@
|
||||
class="rounded border-gray-300 text-sm w-full"
|
||||
/>
|
||||
|
||||
<!-- Multi-Select for Groups -->
|
||||
<div class="md:col-span-3">
|
||||
<select
|
||||
name="groupIds"
|
||||
@@ -290,7 +283,6 @@
|
||||
</div>
|
||||
</div>
|
||||
{:else if activeTab === 'tags'}
|
||||
<!-- TAGS SECTION (unchanged logic, just ensuring style consistency) -->
|
||||
<div class="bg-white shadow-sm border border-brand-sand rounded-lg overflow-hidden" in:slide>
|
||||
<div class="p-6 border-b border-gray-100 bg-yellow-50/50">
|
||||
<h2 class="text-lg font-bold text-gray-700">Schlagworte</h2>
|
||||
@@ -332,9 +324,9 @@
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={cancelEditTag}
|
||||
onclick={cancelEditTag}
|
||||
aria-label="Abbrechen"
|
||||
class="text-gray-400 hover:text-gray-600"
|
||||
class="text-gray-400 hover:text-gray-600"
|
||||
><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
@@ -353,7 +345,7 @@
|
||||
class="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<button
|
||||
on:click={() => startEditTag(tag)}
|
||||
onclick={() => startEditTag(tag)}
|
||||
aria-label="Schlagwort bearbeiten"
|
||||
class="p-1 text-gray-400 hover:text-brand-navy"
|
||||
>
|
||||
@@ -370,16 +362,13 @@
|
||||
method="POST"
|
||||
action="?/deleteTag"
|
||||
use:enhance={({ cancel }) => {
|
||||
// This runs BEFORE the request is sent
|
||||
if (
|
||||
!confirm(
|
||||
'Wirklich löschen? Das Schlagwort wird aus allen Dokumenten entfernt.'
|
||||
)
|
||||
) {
|
||||
cancel(); // Stop the request
|
||||
cancel();
|
||||
}
|
||||
|
||||
// This runs AFTER the server responds
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
};
|
||||
@@ -443,7 +432,6 @@
|
||||
>
|
||||
<input type="hidden" name="id" value={group.id} />
|
||||
|
||||
<!-- Name Input -->
|
||||
<div class="w-full sm:w-1/3">
|
||||
<input
|
||||
type="text"
|
||||
@@ -454,7 +442,6 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Permissions Checkboxes -->
|
||||
<div class="flex-1 flex flex-wrap gap-4 items-center h-full pt-2">
|
||||
{#each availablePermissions as perm}
|
||||
<label
|
||||
@@ -472,7 +459,6 @@
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex gap-2 self-start sm:self-center">
|
||||
<button type="submit" aria-label="Speichern" class="text-green-600 hover:text-green-800 p-1">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
@@ -486,9 +472,9 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
on:click={cancelEditGroup}
|
||||
onclick={cancelEditGroup}
|
||||
aria-label="Abbrechen"
|
||||
class="text-gray-400 hover:text-red-500 p-1"
|
||||
class="text-gray-400 hover:text-red-500 p-1"
|
||||
>
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||
><path
|
||||
@@ -524,7 +510,7 @@
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<div class="flex items-center justify-end gap-3">
|
||||
<button
|
||||
on:click={() => startEditGroup(group.id)}
|
||||
onclick={() => startEditGroup(group.id)}
|
||||
class="text-brand-mint hover:text-brand-navy text-sm font-bold uppercase tracking-wide"
|
||||
>
|
||||
Bearbeiten
|
||||
@@ -537,7 +523,6 @@
|
||||
if (!confirm('Gruppe wirklich löschen?')) {
|
||||
cancel();
|
||||
}
|
||||
|
||||
return async ({ update }) => {
|
||||
await update();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user