Private
Public Access
1
0

Phase 6: Activity log and notifications

Add activity logging to all write API routes, notification system with
real-time delivery via Socket.IO, @mention parsing in comments, activity
feed sidebar on board page, per-card activity in card modal, and
notification bell with unread badge in the navbar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-26 00:26:15 -05:00
parent e61c549ddb
commit e5f2c64e14
32 changed files with 930 additions and 23 deletions
+32
View File
@@ -6,6 +6,7 @@
import { getDueUrgency, getUrgencyClasses, formatDueDate } from '$lib/utils/due-date.js';
import { joinBoard, leaveBoard, onBoardEvent, offBoardEvent, getSocketId } from '$lib/stores/socket.js';
import CardModal from '$lib/components/CardModal.svelte';
import ActivityFeed from '$lib/components/ActivityFeed.svelte';
let { data } = $props();
@@ -25,6 +26,7 @@
let editingColumnId = $state<string | null>(null);
let editingColumnTitle = $state('');
let viewingUsers = $state<any[]>([]);
let showActivity = $state(false);
const flipDurationMs = 200;
@@ -349,8 +351,22 @@
</div>
</div>
{/if}
<button
onclick={() => (showActivity = !showActivity)}
class="ml-auto rounded px-2 py-1 text-sm text-gray-500 hover:bg-gray-200 hover:text-gray-700 transition flex items-center gap-1"
class:bg-gray-200={showActivity}
title="Toggle activity feed"
>
<svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
</svg>
Activity
</button>
</div>
<!-- Main area: columns + optional activity sidebar -->
<div class="flex-1 flex overflow-hidden">
<!-- Columns container -->
<div class="flex-1 overflow-x-auto p-4">
<div
@@ -594,4 +610,20 @@
{/if}
</div>
</div>
<!-- Activity sidebar -->
{#if showActivity}
<div class="w-80 flex-shrink-0 border-l border-gray-200 bg-white overflow-y-auto p-4">
<div class="flex items-center justify-between mb-4">
<h2 class="text-sm font-semibold text-gray-700">Activity</h2>
<button onclick={() => (showActivity = false)} class="text-gray-400 hover:text-gray-600 transition p-1">
<svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
<ActivityFeed boardId={data.board.id} />
</div>
{/if}
</div>
</div>