[Mappe·Shared] Avatar + avatarFor(name) — one deterministic name-hash avatar (§5) #855
Open
opened 2026-06-16 10:53:27 +02:00 by marcel
·
0 comments
No Branch/Tag Specified
main
feat/issue-856-page-header
feat/issue-859-meta-line
feat/issue-858-card
feat/issue-860-empty-state
feat/issue-861-status-dot
feat/issue-855-avatar
feat/issue-857-segmented-control
feat/issue-850-inline-event-clustering
devops/issue-848-fork-exit-timeout
feat/issue-827-zeitstrahl-grouping
feat/issue-837-relationship-edit-dates
feat/issue-818-renovate-nightly-audit
feat/issue-803-geschichten-document-filter-chip
worktree-feat+issue-738-nl-search-backend
feat/issue-286-notification-bell-form-actions
feat/issue-580-sentry-backend
fix/issue-593-management-port-zero
worktree-feat+issue-557-upload-artifact-v3-pin
worktree-chore+issue-556-drop-client-branches-coverage-gate
fix/issue-514-prerender-crawl-bakes-redirects
fix/issue-472-prerender-entries
feat/issue-395-readme
feat/issue-345-bulk-mark-reviewed
feat/issue-344-bell-tooltip
feat/issue-341-annotieren-contrast
feat/issue-225-bulk-metadata-edit
feat/issue-317-bulk-upload
feat/issue-271-dashboard-redesign
docs/issue-240-mission-control-spec
refactor/issues-193-200
feat/issue-162-korrespondenz-redesign
feature/68-new-document-file-first
feat/81-discussion-discoverability
feat/62-document-bottom-panel
feature/56-backfill-file-hashes
feat/38-document-edit-history
fix/svelte5-test-delegation-and-login-auth
No results found.
Labels
Clear labels
P0-critical
P1-high
P2-medium
P3-later
audit
bug
cleanup
collaboration
conversation
descoped
devops
documentation
epic
feature
file-upload
legibility
needs-discussion
needs-review
notification
person
phase-1: security
phase-2: container-images
phase-3: prod-compose
phase-4: spring-prod-profile
phase-5: backups
phase-6: deployment-docs
phase-7: monitoring
redesign-mappe
refactor
security
spec-required
test
ui
user
Blocks a core user journey, causes data loss, or is a security/accessibility barrier. Work on this before P1+.
Significant friction on a main user journey; workaround exists but is non-obvious. Next up after P0.
Noticeable improvement; doesn't block anything; schedule opportunistically.
Cosmetic or parking-lot work; fine to stay open indefinitely.
Read-only audit / assessment work; produces a report rather than changing code
Something isn't working
Removal of dead code, vague comments, naming violations, and scratch artifacts
We want to extend the family archive to have more collaboration tools
We will do that later
README, ARCHITECTURE, GLOSSARY, CONTRIBUTING, per-domain docs
Marker for epic-level issues that group multiple child issues
Codebase Legibility Refactor — preparing the codebase for human evaluation and bus-factor reduction
Has an open decision or design question that must be resolved before implementation can start.
Spec is drafted and awaiting the multi-persona /review-issue gate.
Security hygiene — must be done first
Production-ready multi-stage Docker images
Production compose overlay + Caddy reverse proxy
Spring Boot production configuration profile
Database and object storage backup strategy
.env.example, DEPLOYMENT.md, runbook
Prometheus, Loki, Grafana, Alertmanager
Mappe visual redesign — consistency alignment across the app (shared components + pages). See the design_handoff bundle.
Code restructuring without behaviour change
Feature whose contract is its issue body (EARS REQ-NNN); the spec must pass review before implementation.
UI/UX and accessibility issues
Milestone
No items
No Milestone
Mappe Visual Redesign
Projects
Clear projects
No project
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: marcel/familienarchiv#855
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Shared component · Story 3. Part of #853. The most consequential token violation.
Context
Two conflicting avatar systems exist:
personFormat.ts → personAvatarColor(id)uses a 5-color palette hashed by person-id (djb2);ReaderPersonChipsduplicates it with a divergent 5-color palette;PersonCardandCoCorrespondentsListjust paint a flatbg-primary.DESIGN_RULES §5mandates one util: a 10-color palette hashed by name, white Montserrat initials, so the same person is the same color on every screen.Scope
$lib/shared/avatar.ts—avatarFor(name): hashh = (h*31 + name.charCodeAt(i)) >>> 0, name-keyed, over the 10-color §1 palette; initials = first + last initial. Both the hash util and the palette constant live in$lib/shared/—Avatar.svelte(shared primitive) must not import from$lib/person/or any domain; a shared→domain import violateseslint.config.js boundaries/dependencies(constitution §1.4).$lib/shared/primitives/Avatar.svelte— propsname,size∈ {26,28,40,48}; plus astackedvariant (-ml-1.5+ring-2 ring-surface). Thenameprop is a plainstring— never pass a Person/AppUser entity; the primitive must not know about either domain.PersonChip,PersonCard,CoCorrespondentsList,ReaderPersonChips(delete its local copy), and foldContributorStackonto the stacked variant (fixring-white → ring-surface; size 22 → 26).personAvatarColor/AVATAR_PALETTEinpersonFormat.tsand migrate any existing tests inpersonFormat.spec.tstoavatar.spec.ts.avatarForinitials line must not be ported verbatim from the §5 prototype — guard against empty/single-token names (parts[0][0]throws on""): an empty name yields safe fallback (empty initials,palette[0]); a single-token name yields one initial.ContributorStackoverflow/placeholder states: theAvatarprimitive must support an overflow chip (+N) and an empty/dashed-border placeholder slot soContributorStack's current states survive in the stacked variant.ReaderPersonChipscarriesdark:shadow-none dark:ring-1 dark:ring-white/10— preserve an equivalent dark-mode edge inAvatar.svelteso the dashboard reader chips retain definition against--c-surface #011526. Verify the 10 palette colors pass contrast against the dark canvas.Acceptance
$lib/shared/avatar.ts; one named export; no hex values duplicated elsewhere$lib/shared/—npm run lintpasses with no boundary violationring-surfacepersonAvatarColor/AVATAR_PALETTEdeleted frompersonFormat.tspalette[0]); single-token name → one initial+Nchip and empty/placeholder slot states covered (forContributorStack)#c17a00~2.9:1 and sand#9a8040~3.3:1 currently fail AA for normal text at those sizes); those swatches must use a darkened variant or the AA floor must be met — measure and documentaria-hidden="true"; standalone avatar →role="img"+aria-label={name}(attribute binding, never string concatenation){...}escaping;{@html}is never used anywhere in the componentAvatar.sveltepreserves a ring/shadow edge in dark mode; all 10 palette colors verified against--c-surface #011526(run axe in dark mode)ReaderPersonChipsgrid (grid-cols-2 sm:grid-cols-4) with 48px avatar + nameavatar.spec.ts— determinism (same name → same bg),palette.length === 10, first+last initials, empty/single-token guard;Avatar.svelte.spec.ts— renders initials, applies size class,stackedadds-ml-1.5 ring-2 ring-surfaceOut of scope
Depends on: token close-out (§1 palette token must be merged before this starts). Blocks: every page with avatars. Refs:
DESIGN_RULES §5, the prototypes'av()helper,_AUTHORING_KIT.md §1, constitution §1.4.marcel referenced this issue2026-06-16 13:43:16 +02:00
marcel referenced this issue2026-06-16 13:43:30 +02:00
marcel referenced this issue2026-06-16 13:43:38 +02:00
marcel referenced this issue2026-06-16 13:43:58 +02:00
marcel referenced this issue2026-06-16 13:44:42 +02:00
marcel referenced this issue2026-06-16 13:44:52 +02:00
marcel referenced this issue2026-06-16 13:49:00 +02:00
marcel referenced this issue2026-06-16 13:49:13 +02:00
marcel referenced this issue2026-06-16 13:49:43 +02:00
marcel referenced this issue2026-06-16 14:00:04 +02:00
marcel referenced this issue2026-06-16 14:00:06 +02:00
marcel referenced this issue2026-06-16 14:00:06 +02:00
marcel referenced this issue2026-06-16 14:00:26 +02:00
marcel referenced this issue2026-06-16 14:00:44 +02:00
marcel referenced this issue2026-06-16 14:01:12 +02:00
marcel referenced this issue2026-06-16 14:01:13 +02:00
marcel referenced this issue2026-06-16 14:01:19 +02:00
marcel referenced this issue2026-06-16 14:01:37 +02:00
marcel referenced this issue2026-06-16 14:01:52 +02:00
marcel referenced this issue2026-06-16 14:02:21 +02:00
marcel referenced this issue2026-06-16 14:02:38 +02:00
marcel referenced this issue2026-06-16 14:04:53 +02:00
marcel referenced this issue2026-06-16 14:04:55 +02:00
marcel referenced this issue2026-06-16 14:04:56 +02:00
marcel referenced this issue2026-06-16 14:05:21 +02:00
marcel referenced this issue2026-06-16 14:05:21 +02:00
marcel referenced this issue2026-06-16 14:05:25 +02:00
marcel referenced this issue2026-06-16 14:05:47 +02:00
marcel referenced this issue2026-06-16 14:05:50 +02:00
marcel referenced this issue2026-06-16 14:06:07 +02:00
marcel referenced this issue2026-06-16 14:06:08 +02:00
marcel referenced this issue2026-06-16 14:06:08 +02:00
marcel referenced this issue2026-06-16 14:06:33 +02:00
marcel referenced this issue2026-06-16 14:06:42 +02:00
marcel referenced this issue2026-06-16 14:06:49 +02:00
marcel referenced this issue2026-06-16 14:06:54 +02:00
marcel referenced this issue2026-06-16 14:07:09 +02:00
marcel referenced this issue2026-06-16 14:07:16 +02:00
marcel referenced this issue2026-06-16 14:07:20 +02:00