diff --git a/frontend/src/routes/dashboard/team/+page.svelte b/frontend/src/routes/dashboard/team/+page.svelte index b6acb04..7bbf159 100644 --- a/frontend/src/routes/dashboard/team/+page.svelte +++ b/frontend/src/routes/dashboard/team/+page.svelte @@ -2,6 +2,8 @@ import Sidebar from '$lib/components/Sidebar.svelte'; import { onMount } from 'svelte'; import { goto } from '$app/navigation'; + import { fly } from 'svelte/transition'; + import { cubicOut } from 'svelte/easing'; import { auth } from '$lib/auth.svelte'; import { toast } from '$lib/toast.svelte'; import { @@ -73,6 +75,10 @@ let removing = $state(false); let removeError = $state(null); + // Delight: new member row flash, name saved flash + let recentlyAddedId = $state(null); + let nameSavedFlash = $state(false); + // Danger zone let showDangerConfirm = $state(false); let dangerLoading = $state(false); @@ -124,6 +130,8 @@ if (result.ok) { team = { ...team, name: trimmed }; editingName = false; + nameSavedFlash = true; + setTimeout(() => (nameSavedFlash = false), 900); toast.success('Team name updated'); } else { nameError = result.error; @@ -177,6 +185,8 @@ const result = await addMember(team.id, addEmail.trim().toLowerCase()); if (result.ok) { members = [...members, result.data]; + recentlyAddedId = result.data.user_id; + setTimeout(() => (recentlyAddedId = null), 1200); showAddMember = false; addEmail = ''; searchResults = []; @@ -251,6 +261,11 @@ } } + function avatarColor(email: string): string { + const palette = ['#5e8c58', '#5a9fd4', '#d4a73c', '#a07ab0', '#cf8172']; + return palette[email.charCodeAt(0) % palette.length]; + } + function formatDate(iso: string): string { return new Date(iso).toLocaleDateString('en-US', { month: 'short', @@ -471,7 +486,7 @@ title={canManage ? 'Click to edit' : undefined} > {team.name} @@ -498,108 +513,115 @@ - -
-
-
- Slug + +
+ +
+
+
+ Slug +
+ {team.slug}
- {team.slug} copyToClipboard(team!.slug, 'slug')} + title="Copy slug" + class="flex shrink-0 items-center gap-1.5 rounded-[var(--radius-button)] border px-3 py-1.5 text-meta font-semibold transition-all duration-150 + {copiedSlug + ? 'border-[var(--color-accent)]/40 bg-[var(--color-accent-glow-mid)] text-[var(--color-accent-mid)]' + : 'border-[var(--color-border-mid)] text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]'}" > + {#if copiedSlug} + + + + Copied + {:else} + + + + + Copy + {/if} +
- -
- -
-
-
- Team ID + +
+
+
+ Team ID +
+ {team.id}
- {team.id} copyToClipboard(team!.id, 'id')} + title="Copy team ID" + class="flex shrink-0 items-center gap-1.5 rounded-[var(--radius-button)] border px-3 py-1.5 text-meta font-semibold transition-all duration-150 + {copiedId + ? 'border-[var(--color-accent)]/40 bg-[var(--color-accent-glow-mid)] text-[var(--color-accent-mid)]' + : 'border-[var(--color-border-mid)] text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]'}" > + {#if copiedId} + + + + Copied + {:else} + + + + + Copy + {/if} +
-
@@ -676,17 +698,20 @@ {#each members as member, i (member.user_id)}
- {member.email} - {#if member.user_id === auth.userId} - you - {/if} +
+ {member.email} + {#if member.user_id === auth.userId} + you + {/if} +
@@ -989,7 +1014,8 @@ class="flex w-full items-center gap-2.5 px-3 py-2 text-ui transition-colors duration-150 hover:bg-[var(--color-bg-3)]" >
{result.email[0]}
@@ -1228,3 +1254,27 @@
{/if} + +