feat(web): show initial letter only on first sound of each group

Instead of displaying the letter (A, B, C...) on every sound card,
only show it on the first card that starts with that letter. Makes
the grid much cleaner and easier to scan.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bot 2026-03-01 15:28:53 +01:00
parent da0ae2b9a6
commit 5f0b06550e

View file

@ -282,6 +282,16 @@ export default function App() {
return m;
}, [visibleFolders]);
const firstOfInitial = useMemo(() => {
const seen = new Set<string>();
const result = new Set<number>();
displaySounds.forEach((s, idx) => {
const ch = s.name.charAt(0).toUpperCase();
if (!seen.has(ch)) { seen.add(ch); result.add(idx); }
});
return result;
}, [displaySounds]);
const channelsByGuild = useMemo(() => {
const groups: Record<string, VoiceChannelInfo[]> = {};
channels.forEach(c => {
@ -503,12 +513,13 @@ export default function App() {
const isPlaying = lastPlayed === s.name;
const isNew = s.isRecent || s.badges?.includes('new');
const initial = s.name.charAt(0).toUpperCase();
const showInitial = firstOfInitial.has(idx);
const folderColor = s.folder ? (folderColorMap[s.folder] || 'var(--accent)') : 'var(--accent)';
return (
<div
key={key}
className={`sound-card ${isPlaying ? 'playing' : ''}`}
className={`sound-card ${isPlaying ? 'playing' : ''} ${showInitial ? 'has-initial' : ''}`}
style={{ animationDelay: `${Math.min(idx * 20, 400)}ms` }}
onClick={e => {
const card = e.currentTarget;
@ -541,7 +552,7 @@ export default function App() {
>
<span className="material-icons fav-icon">{isFav ? 'star' : 'star_border'}</span>
</span>
<span className="sound-emoji" style={{ color: folderColor }}>{initial}</span>
{showInitial && <span className="sound-emoji" style={{ color: folderColor }}>{initial}</span>}
<span className="sound-name">{s.name}</span>
{s.folder && <span className="sound-duration">{s.folder}</span>}
<div className="playing-indicator">