Add profile pictures and improve modal animations
- Add ProfilePicture component with fallback to user initials - Integrate profile pictures in dashboard recent activity dialog layout - Add profile pictures to payments list and split details - Fix modal animation overshoot by using fixed positioning and smooth slide-in - Add fade-in animation for modal content with proper sequencing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { onMount, createEventDispatcher } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import ProfilePicture from './ProfilePicture.svelte';
|
||||
|
||||
export let paymentId;
|
||||
|
||||
@@ -150,10 +151,13 @@
|
||||
{#each payment.splits as split}
|
||||
<div class="split-item" class:current-user={split.username === session?.user?.nickname}>
|
||||
<div class="split-user">
|
||||
<span class="username">{split.username}</span>
|
||||
{#if split.username === session?.user?.nickname}
|
||||
<span class="you-badge">You</span>
|
||||
{/if}
|
||||
<ProfilePicture username={split.username} size={24} />
|
||||
<div class="user-info">
|
||||
<span class="username">{split.username}</span>
|
||||
{#if split.username === session?.user?.nickname}
|
||||
<span class="you-badge">You</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="split-amount" class:positive={split.amount < 0} class:negative={split.amount > 0}>
|
||||
{#if split.amount > 0}
|
||||
@@ -362,6 +366,12 @@
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.split-user .user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
|
66
src/lib/components/ProfilePicture.svelte
Normal file
66
src/lib/components/ProfilePicture.svelte
Normal file
@@ -0,0 +1,66 @@
|
||||
<script>
|
||||
export let username;
|
||||
export let size = 40; // Default size in pixels
|
||||
export let alt = '';
|
||||
|
||||
let imageError = false;
|
||||
|
||||
$: profileUrl = `https://bocken.org/static/user/full/${username}.webp`;
|
||||
$: altText = alt || `${username}'s profile picture`;
|
||||
|
||||
function handleError() {
|
||||
imageError = true;
|
||||
}
|
||||
|
||||
function getInitials(name) {
|
||||
if (!name) return '?';
|
||||
return name.split(' ')
|
||||
.map(word => word.charAt(0))
|
||||
.join('')
|
||||
.toUpperCase()
|
||||
.substring(0, 2);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="profile-picture" style="width: {size}px; height: {size}px;">
|
||||
{#if !imageError}
|
||||
<img
|
||||
src={profileUrl}
|
||||
alt={altText}
|
||||
on:error={handleError}
|
||||
loading="lazy"
|
||||
/>
|
||||
{:else}
|
||||
<div class="fallback">
|
||||
{getInitials(username)}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.profile-picture {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fallback {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 0.75em;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user