refactor(personFormat): replace getInitials(Person) with getInitials(name: string)
Unify the initials-extraction logic: the new string-based getInitials() splits on whitespace, takes the first char of the first and last word uppercased — matching the pattern that was already inlined in CommentThread. Update PersonChip, DocumentMetadataDrawer, and CommentThread to use the shared function. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import type { Comment } from '$lib/types';
|
||||
import MentionEditor from '$lib/components/MentionEditor.svelte';
|
||||
import { renderBody, extractContent } from '$lib/utils/mention';
|
||||
import { relativeTime } from '$lib/utils/time';
|
||||
import { getInitials } from '$lib/utils/personFormat';
|
||||
import type { MentionDTO } from '$lib/types';
|
||||
|
||||
type Props = {
|
||||
@@ -76,14 +77,6 @@ function isOwn(c: { authorId: string | null }): boolean {
|
||||
return currentUserId !== null && c.authorId === currentUserId;
|
||||
}
|
||||
|
||||
function getInitials(name: string): string {
|
||||
return name
|
||||
.split(/\s+/)
|
||||
.slice(0, 2)
|
||||
.map((w) => w.charAt(0).toUpperCase())
|
||||
.join('');
|
||||
}
|
||||
|
||||
function extractQuote(content: string): { quote: string | null; body: string } {
|
||||
const match = content.match(/^>\s*"(.+?)"\s*\n\n?([\s\S]*)$/);
|
||||
if (match) return { quote: match[1], body: match[2] };
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
import { formatDate } from '$lib/utils/date';
|
||||
import { formatDocumentStatus } from '$lib/utils/documentStatusLabel';
|
||||
import { getInitials as calcInitials, personAvatarColor } from '$lib/utils/personFormat';
|
||||
import { getInitials, personAvatarColor } from '$lib/utils/personFormat';
|
||||
|
||||
type Person = { id: string; firstName?: string | null; lastName: string; displayName: string };
|
||||
type Tag = { id: string; name: string };
|
||||
@@ -32,10 +32,6 @@ let showAllReceivers = $state(false);
|
||||
|
||||
const displayedReceivers = $derived(showAllReceivers ? receivers : visibleReceivers);
|
||||
|
||||
function getInitials(person: Person): string {
|
||||
return calcInitials(person);
|
||||
}
|
||||
|
||||
function getFullName(person: Person): string {
|
||||
return person.displayName;
|
||||
}
|
||||
@@ -51,7 +47,7 @@ function getFullName(person: Person): string {
|
||||
style="background-color: {personAvatarColor(person.id)}"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{getInitials(person)}
|
||||
{getInitials(person.displayName)}
|
||||
</span>
|
||||
<span class="font-serif text-sm text-ink">{getFullName(person)}</span>
|
||||
</a>
|
||||
|
||||
@@ -12,7 +12,7 @@ let { person, abbreviated }: Props = $props();
|
||||
|
||||
const name = $derived(abbreviated ? abbreviateName(person) : person.displayName);
|
||||
const avatarColor = $derived(personAvatarColor(person.id));
|
||||
const initials = $derived(getInitials(person));
|
||||
const initials = $derived(getInitials(person.displayName));
|
||||
</script>
|
||||
|
||||
<a
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
getInitials,
|
||||
abbreviateName,
|
||||
formatXsMeta,
|
||||
personAvatarColor,
|
||||
@@ -8,6 +9,30 @@ import {
|
||||
statusLabel
|
||||
} from './personFormat';
|
||||
|
||||
// ─── getInitials ─────────────────────────────────────────────────────────────
|
||||
|
||||
describe('getInitials', () => {
|
||||
it('returns first chars of first and last word uppercased', () => {
|
||||
expect(getInitials('Marcel Raddatz')).toBe('MR');
|
||||
});
|
||||
|
||||
it('returns single char for a single-word name', () => {
|
||||
expect(getInitials('Raddatz')).toBe('R');
|
||||
});
|
||||
|
||||
it('returns empty string for an empty name', () => {
|
||||
expect(getInitials('')).toBe('');
|
||||
});
|
||||
|
||||
it('splits on whitespace only — hyphenated first word counts as one', () => {
|
||||
expect(getInitials('Anna-Maria Raddatz')).toBe('AR');
|
||||
});
|
||||
|
||||
it('ignores extra whitespace between words', () => {
|
||||
expect(getInitials(' Karl Raddatz ')).toBe('KR');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── abbreviateName ──────────────────────────────────────────────────────────
|
||||
|
||||
describe('abbreviateName', () => {
|
||||
|
||||
@@ -18,9 +18,11 @@ function djb2(str: string): number {
|
||||
return Math.abs(hash);
|
||||
}
|
||||
|
||||
export function getInitials(person: Person): string {
|
||||
if (person.firstName) return `${person.firstName[0]}${person.lastName[0]}`.toUpperCase();
|
||||
return person.lastName.substring(0, 2).toUpperCase();
|
||||
export function getInitials(name: string): string {
|
||||
const words = name.trim().split(/\s+/).filter(Boolean);
|
||||
if (words.length === 0) return '';
|
||||
if (words.length === 1) return words[0].charAt(0).toUpperCase();
|
||||
return (words[0].charAt(0) + words[words.length - 1].charAt(0)).toUpperCase();
|
||||
}
|
||||
|
||||
export function abbreviateName(person: Person): string {
|
||||
|
||||
Reference in New Issue
Block a user