Player names open profiles across the launcher and admin panel

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DjMbLQujBHunCCu5GpsHaT
This commit is contained in:
Claude committed 2026-10-01 00:49:13 +00:00
1 parent f428bd210f
commit c37cde5cc8
13 files changed
+82 -24

No files matched your search

+2 -1
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import PlayerLink from './PlayerLink.svelte';
import { onMount } from 'svelte';
import {
Landmark, ArrowDownToLine, ArrowUpFromLine, Wallet, Lock, Server, History, Coins, LoaderCircle, RefreshCw, TrendingUp
@@ -213,7 +214,7 @@
</span>
<Avatar uuid={tx.actor_uuid} name={m?.name ?? '?'} size={1.7} />
<div class="who">
<strong>{m?.name ?? 'Former member'}</strong>
<strong>{#if m}<PlayerLink uuid={tx.actor_uuid} name={m.name} />{:else}Former member{/if}</strong>
<span class="tiny muted" title={tx.note}>{verbs[tx.kind] ?? tx.kind}{tx.note ? ` · ${tx.note}` : ''} · {ago(tx.created_at)}</span>
</div>
<span class="amt" class:out={isOut(tx.kind)}>{isOut(tx.kind) ? '−' : '+'}{money(tx.amount)}</span>
@@ -2,6 +2,7 @@
import { onMount } from 'svelte';
import { X, Send, UserPlus, Sparkles, MapPin, LoaderCircle, Shield, Clock, Swords, Star } from '@lucide/svelte';
import Avatar from './Avatar.svelte';
import PlayerLink from './PlayerLink.svelte';
import { activeAccount, toast } from '../lib/store.svelte';
import { invoke } from '../lib/tauri';
import type { Guild, GuildMember, UserProfileView } from '../lib/types';
@@ -84,7 +85,7 @@
<div class="head">
<div class="ring"><Avatar {uuid} name={name} size={4} /></div>
<div class="who">
<h3>{name}</h3>
<h3><PlayerLink {uuid} {name} /></h3>
{#if profile.level_info?.title}<span class="title"><Sparkles size={12} /> {profile.level_info.title}</span>{/if}
<span class="presence"><i class:on={online}></i>{online ? 'Online now' : 'Offline'}</span>
</div>
+21
View File
@@ -0,0 +1,21 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import { app } from '../lib/store.svelte';
// A player's name that opens their profile. Safe to place inside other clickable rows.
let { uuid, name = '', class: cls = '', children }: { uuid?: string | null; name?: string; class?: string; children?: Snippet } = $props();
const open = (e: Event) => { e.stopPropagation(); if (uuid) app.viewProfileUuid = uuid; };
</script>
{#if uuid}
<button type="button" class="plink {cls}" title="View {name || 'player'}'s profile" onclick={open}
onkeydown={(e) => e.stopPropagation()}>{#if children}{@render children()}{:else}{name}{/if}</button>
{:else}
<span class={cls}>{#if children}{@render children()}{:else}{name}{/if}</span>
{/if}
<style>
.plink { all: unset; cursor: pointer; font: inherit; color: inherit; border-radius: 4px; transition: color 0.12s ease; }
.plink:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.plink:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
</style>
+4 -3
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import PlayerLink from '../components/PlayerLink.svelte';
import { onMount } from 'svelte';
import {
Shield, Map, Users, MessageSquare, Plus, Crown, UserCheck, Trash2,
@@ -83,7 +84,7 @@
}
}
type Invite = { id: number; guild_id: string; guild_name: string; guild_tag: string; icon_url: string; inviter: string };
type Invite = { id: number; guild_id: string; guild_name: string; guild_tag: string; icon_url: string; inviter: string; inviter_uuid?: string };
let invites = $state<Invite[]>([]);
async function loadInvites() {
try { invites = await invoke<Invite[]>('my_guild_invites'); } catch { invites = []; }
@@ -259,7 +260,7 @@
{#each invites as inv (inv.id)}
<div class="invite">
<span class="dot"><Shield size={15} /></span>
<span class="text"><strong>[{inv.guild_tag}] {inv.guild_name}</strong><span class="muted tiny">Invited by {inv.inviter}</span></span>
<span class="text"><strong>[{inv.guild_tag}] {inv.guild_name}</strong><span class="muted tiny">Invited by <PlayerLink uuid={inv.inviter_uuid} name={inv.inviter} /></span></span>
<button class="sm ghost" onclick={() => answerInvite(inv, false)}>Decline</button>
<button class="sm primary" onclick={() => answerInvite(inv, true)} disabled={!!myGuild} title={myGuild ? 'Leave your guild first' : ''}>Accept</button>
</div>
@@ -450,7 +451,7 @@
<div class="author-meta">
<Avatar uuid={p.author_uuid} name={p.author_name} size={1.8} />
<div class="author-info">
<span class="author-name">{p.author_name}</span>
<span class="author-name"><PlayerLink uuid={p.author_uuid} name={p.author_name} /></span>
<span class="post-date tiny muted">{new Date(p.created_at).toLocaleString()}</span>
</div>
</div>
+7 -6
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import PlayerLink from '../components/PlayerLink.svelte';
import { onMount } from 'svelte';
import {
Users, UserPlus, MessageSquare, Gamepad2, Send, Check, X, Trash2,
@@ -301,7 +302,7 @@
<div class="card-left" role="button" tabindex="0" onclick={() => (app.viewProfileUuid = req.uuid)} onkeydown={(e) => e.key === 'Enter' && (app.viewProfileUuid = req.uuid)}>
<Avatar uuid={req.uuid} name={req.username} size={2.5} />
<div class="name-block">
<span class="user-title">{req.username}</span>
<span class="user-title"><PlayerLink uuid={req.uuid} name={req.username} /></span>
<span class="tiny muted">Wants to be friends</span>
</div>
</div>
@@ -326,7 +327,7 @@
<div class="card-left">
<Avatar uuid={req.uuid} name={req.username} size={2.5} />
<div class="name-block">
<span class="user-title">{req.username}</span>
<span class="user-title"><PlayerLink uuid={req.uuid} name={req.username} /></span>
<span class="tiny muted">Request pending...</span>
</div>
</div>
@@ -366,7 +367,7 @@
<span class="status-dot" class:online={friend.online}></span>
</div>
<div class="name-block">
<span class="user-title">{friend.username}</span>
<span class="user-title"><PlayerLink uuid={friend.uuid} name={friend.username} /></span>
{#if friend.online && friend.playing_on}
<span class="tiny playing-on">Playing on {friend.playing_on}</span>
{:else if friend.online}
@@ -508,7 +509,7 @@
<span class="status-dot" class:online={friend.online}></span>
</div>
<div class="conv-meta">
<span class="conv-name">{friend.username}</span>
<span class="conv-name"><PlayerLink uuid={friend.uuid} name={friend.username} /></span>
{#if friend.playing_on}
<span class="tiny muted">{friend.playing_on}</span>
{/if}
@@ -531,7 +532,7 @@
>
<Avatar uuid={activeChatFriend.uuid} name={activeChatFriend.username} size={2.2} />
<div>
<strong>{activeChatFriend.username}</strong>
<strong><PlayerLink uuid={activeChatFriend.uuid} name={activeChatFriend.username} /></strong>
<span class="tiny muted block">{activeChatFriend.online ? 'Active now' : 'Offline'}</span>
</div>
</div>
@@ -599,7 +600,7 @@
<div class="invite-top">
<Avatar uuid={inv.sender_uuid} name={inv.sender_name} size={2.5} />
<div class="invite-meta">
<span class="inviter-name"><strong>{inv.sender_name}</strong> invited you to play</span>
<span class="inviter-name"><strong><PlayerLink uuid={inv.sender_uuid} name={inv.sender_name} /></strong> invited you to play</span>
<span class="server-title">{inv.server_name}</span>
<span class="tiny muted server-addr">{inv.instance_name}</span>
</div>
+3 -2
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import PlayerLink from '../components/PlayerLink.svelte';
import {
Trophy, Swords, Skull, Pickaxe, Clock, Box, MessageSquare, LogIn,
RefreshCw, LoaderCircle, Users, Server, Flame, Sparkles, ChevronDown, Check,
@@ -472,7 +473,7 @@
#{row.rank}
</span>
<Avatar uuid={row.uuid} name={row.username} size={2.2} />
<strong class="baltop-name">{row.username}</strong>
<strong class="baltop-name"><PlayerLink uuid={row.uuid} name={row.username} /></strong>
{#if isMe}<span class="badge you">You</span>{/if}
</div>
<span class="baltop-val highlight">
@@ -610,7 +611,7 @@
</span>
<div class="col-player row align-center gap-sm">
<Avatar name={row.name} uuid={row.uuid} size={1.8} />
<strong class="row-player-name">{row.name}</strong>
<strong class="row-player-name"><PlayerLink uuid={row.uuid} name={row.name} /></strong>
{#if isMe}<span class="badge you">You</span>{/if}
</div>
<strong class="col-main highlight">{statValue(row, sortField)}</strong>