Redesign note card layout for shared notes

- Type bubble (colored dot) appears inline with body text, far right, only on shared notes
- Shared with capsules displayed in bottom right with consistent person-based colors
- Attachment icons in bottom left
- Body text truncated to single line to maintain consistent card heights
- Added color palette for person names (8 distinct colors) with hash-based consistency
- Removed metadata display from card footer
- Cleaner visual hierarchy with all key info visible at a glance
This commit is contained in:
2026-01-11 22:23:40 +00:00
parent 9d3e176773
commit 8d99d77e7a
+40 -8
View File
@@ -1835,6 +1835,35 @@
}
function renderNotesList(items) {
// Color palette for shared with person names (different from green)
const personColorPalette = [
{ bg: 'bg-blue-200', border: 'border-blue-400', text: 'text-blue-900' },
{ bg: 'bg-purple-200', border: 'border-purple-400', text: 'text-purple-900' },
{ bg: 'bg-indigo-200', border: 'border-indigo-400', text: 'text-indigo-900' },
{ bg: 'bg-cyan-200', border: 'border-cyan-400', text: 'text-cyan-900' },
{ bg: 'bg-teal-200', border: 'border-teal-400', text: 'text-teal-900' },
{ bg: 'bg-sky-200', border: 'border-sky-400', text: 'text-sky-900' },
{ bg: 'bg-lime-200', border: 'border-lime-400', text: 'text-lime-900' },
{ bg: 'bg-rose-200', border: 'border-rose-400', text: 'text-rose-900' },
];
// Map to store consistent colors for each person
const personColorMap = {};
function getPersonColor(name) {
if (!personColorMap[name]) {
// Generate consistent hash-based color index for this person
let hash = 0;
for (let i = 0; i < name.length; i++) {
hash = ((hash << 5) - hash) + name.charCodeAt(i);
hash = hash & hash; // Convert to 32-bit integer
}
const colorIndex = Math.abs(hash) % personColorPalette.length;
personColorMap[name] = personColorPalette[colorIndex];
}
return personColorMap[name];
}
const grid = document.getElementById('notesGrid');
const empty = document.getElementById('notesEmpty');
grid.innerHTML = '';
@@ -1899,7 +1928,8 @@
const sharedNames = Array.isArray(note.shared_with) ? note.shared_with : (typeof note.shared_with === 'string' ? note.shared_with.split(',').map(n => n.trim()) : []);
const capsules = sharedNames.map(name => {
const firstName = name.split(' ')[0];
return `<span class="inline-block px-2 py-0.5 rounded-full text-xs font-semibold bg-green-200 border border-green-400 text-green-900">${escapeHtml(firstName)}</span>`;
const colors = getPersonColor(name);
return `<span class="inline-block px-2 py-0.5 rounded-full text-xs font-semibold ${colors.bg} ${colors.border} border ${colors.text}">${escapeHtml(firstName)}</span>`;
}).join('');
sharedWithDisplay = `<div class="flex items-center flex-wrap gap-1 justify-end">${capsules}</div>`;
}
@@ -1908,16 +1938,18 @@
card.innerHTML = `
<div class="flex items-start justify-between gap-2">
<div class="font-semibold text-gray-900 truncate">${escapeHtml(title)}</div>
<div class="flex flex-col items-end gap-1 flex-shrink-0">
<div class="text-xs text-gray-500">${formatDateShort(note.created)}</div>
${note.shared ? `<div class="flex items-center gap-1.5">${typeBubble}${sharedWithDisplay}</div>` : ''}
<div class="text-xs text-gray-500 flex-shrink-0">${formatDateShort(note.created)}</div>
</div>
<div class="flex items-start gap-2 flex-1">
<div class="text-sm text-gray-700 line-clamp-1 flex-1">${escapeHtml(snippet || '(empty)')}</div>
${note.shared ? `<div class="flex items-center gap-1 flex-shrink-0">${typeBubble}</div>` : ''}
</div>
<div class="text-sm text-gray-700 line-clamp-3 flex-1">${escapeHtml(snippet || '(empty)')}</div>
<div class="flex items-center justify-between text-xs text-gray-600">
<span>${note.shared ? '' : escapeHtml(meta)}</span>
<div class="flex items-center justify-between text-xs text-gray-600 w-full">
<div class="flex items-center gap-1">
${note.shared ? '' : attachmentIcons}
${attachmentIcons}
</div>
<div class="flex items-center gap-1">
${note.shared ? sharedWithDisplay : ''}
</div>
</div>
`;