Skip to content

Commit d7d2e8b

Browse files
committed
Show recent folder document activity
1 parent c554589 commit d7d2e8b

2 files changed

Lines changed: 110 additions & 8 deletions

File tree

App.tsx

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,14 @@ const MainApp: React.FC = () => {
307307
return Number.isNaN(date.getTime()) ? null : date;
308308
};
309309

310+
const formatNodeTitle = (node: DocumentOrFolder) => {
311+
const trimmed = node.title.trim();
312+
if (trimmed) {
313+
return trimmed;
314+
}
315+
return node.type === 'folder' ? 'Untitled Folder' : 'Untitled Document';
316+
};
317+
310318
const computeFromTree = (folderNode: DocumentNode): FolderOverviewMetrics => {
311319
const recordLatest = (() => {
312320
let latest: Date | null = null;
@@ -325,25 +333,45 @@ const MainApp: React.FC = () => {
325333

326334
recordLatest.update(folderNode.updatedAt);
327335

328-
const directDocumentCount = folderNode.children.filter(child => child.type === 'document').length;
329-
const directFolderCount = folderNode.children.filter(child => child.type === 'folder').length;
336+
const folderChildren = folderNode.children ?? [];
337+
const directDocumentCount = folderChildren.filter(child => child.type === 'document').length;
338+
const directFolderCount = folderChildren.filter(child => child.type === 'folder').length;
330339

331340
let totalDocumentCount = 0;
332341
let totalFolderCount = 0;
333-
const stack = [...folderNode.children];
342+
const stack: { node: DocumentNode; parentPath: string[] }[] = folderChildren.map(child => ({
343+
node: child,
344+
parentPath: [],
345+
}));
346+
const recentDocuments: FolderOverviewMetrics['recentDocuments'] = [];
334347

335348
while (stack.length > 0) {
336-
const current = stack.pop()!;
349+
const { node: current, parentPath } = stack.pop()!;
337350
recordLatest.update(current.updatedAt);
338351
if (current.type === 'document') {
339352
totalDocumentCount += 1;
353+
recentDocuments.push({
354+
id: current.id,
355+
title: current.title,
356+
updatedAt: current.updatedAt,
357+
parentPath,
358+
});
340359
} else if (current.type === 'folder') {
341360
totalFolderCount += 1;
342-
stack.push(...current.children);
361+
const nextPath = [...parentPath, formatNodeTitle(current)];
362+
const childNodes = current.children ?? [];
363+
stack.push(...childNodes.map(child => ({ node: child, parentPath: nextPath })));
343364
}
344365
}
345366

346367
const latestDate = recordLatest.getValue();
368+
const sortedRecent = recentDocuments
369+
.sort((a, b) => {
370+
const aDate = parseDate(a.updatedAt)?.getTime() ?? 0;
371+
const bDate = parseDate(b.updatedAt)?.getTime() ?? 0;
372+
return bDate - aDate;
373+
})
374+
.slice(0, 5);
347375

348376
return {
349377
directDocumentCount,
@@ -352,6 +380,7 @@ const MainApp: React.FC = () => {
352380
totalFolderCount,
353381
totalItemCount: totalDocumentCount + totalFolderCount,
354382
lastUpdated: latestDate ? latestDate.toISOString() : null,
383+
recentDocuments: sortedRecent,
355384
};
356385
};
357386

@@ -393,21 +422,39 @@ const MainApp: React.FC = () => {
393422

394423
let totalDocumentCount = 0;
395424
let totalFolderCount = 0;
396-
const stack = [...directChildren];
425+
const stack: { node: DocumentOrFolder; parentPath: string[] }[] = directChildren.map(child => ({
426+
node: child,
427+
parentPath: [],
428+
}));
429+
const recentDocuments: FolderOverviewMetrics['recentDocuments'] = [];
397430

398431
while (stack.length > 0) {
399-
const current = stack.pop()!;
432+
const { node: current, parentPath } = stack.pop()!;
400433
recordLatest.update(current.updatedAt);
401434
if (current.type === 'document') {
402435
totalDocumentCount += 1;
436+
recentDocuments.push({
437+
id: current.id,
438+
title: current.title,
439+
updatedAt: current.updatedAt,
440+
parentPath,
441+
});
403442
} else {
404443
totalFolderCount += 1;
405444
const childItems = childMap.get(current.id) ?? [];
406-
stack.push(...childItems);
445+
const nextPath = [...parentPath, formatNodeTitle(current)];
446+
stack.push(...childItems.map(item => ({ node: item, parentPath: nextPath })));
407447
}
408448
}
409449

410450
const latestDate = recordLatest.getValue();
451+
const sortedRecent = recentDocuments
452+
.sort((a, b) => {
453+
const aDate = parseDate(a.updatedAt)?.getTime() ?? 0;
454+
const bDate = parseDate(b.updatedAt)?.getTime() ?? 0;
455+
return bDate - aDate;
456+
})
457+
.slice(0, 5);
411458

412459
return {
413460
directDocumentCount,
@@ -416,6 +463,7 @@ const MainApp: React.FC = () => {
416463
totalFolderCount,
417464
totalItemCount: totalDocumentCount + totalFolderCount,
418465
lastUpdated: latestDate ? latestDate.toISOString() : null,
466+
recentDocuments: sortedRecent,
419467
};
420468
};
421469

@@ -1308,6 +1356,7 @@ const MainApp: React.FC = () => {
13081356
totalFolderCount: 0,
13091357
totalItemCount: 0,
13101358
lastUpdated: activeNode.updatedAt,
1359+
recentDocuments: [],
13111360
};
13121361
return (
13131362
<FolderOverview

components/FolderOverview.tsx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ export interface FolderOverviewMetrics {
1010
totalFolderCount: number;
1111
totalItemCount: number;
1212
lastUpdated: string | null;
13+
recentDocuments: RecentDocumentSummary[];
14+
}
15+
16+
export interface RecentDocumentSummary {
17+
id: string;
18+
title: string;
19+
updatedAt: string | null;
20+
parentPath: string[];
1321
}
1422

1523
interface FolderOverviewProps {
@@ -59,6 +67,7 @@ const FolderOverview: React.FC<FolderOverviewProps> = ({
5967
totalFolderCount,
6068
totalItemCount,
6169
lastUpdated,
70+
recentDocuments,
6271
} = metrics;
6372

6473
const hasChildren = totalItemCount > 0;
@@ -183,6 +192,50 @@ const FolderOverview: React.FC<FolderOverviewProps> = ({
183192
</div>
184193
</div>
185194

195+
<div className="mt-10 rounded-lg border border-border-color bg-background/70 p-6">
196+
<h2 className="text-sm font-semibold uppercase tracking-wide text-text-secondary">
197+
Recently updated in this folder
198+
</h2>
199+
{recentDocuments.length > 0 ? (
200+
<ul className="mt-4 space-y-3">
201+
{recentDocuments.map((doc) => {
202+
const formattedTitle = doc.title.trim() || 'Untitled document';
203+
const formattedDate = formatDateTime(doc.updatedAt);
204+
const hasPath = doc.parentPath.length > 0;
205+
const isUnknownDate = formattedDate === 'Unknown';
206+
return (
207+
<li
208+
key={doc.id}
209+
className="flex flex-col gap-2 rounded-md border border-border-color/80 bg-background px-4 py-3 sm:flex-row sm:items-center sm:justify-between"
210+
>
211+
<div className="flex items-start gap-3">
212+
<div className="mt-1 flex h-8 w-8 items-center justify-center rounded-full bg-primary/10 text-primary">
213+
<FileIcon className="h-4 w-4" />
214+
</div>
215+
<div>
216+
<p className="font-medium text-text-main">{formattedTitle}</p>
217+
{hasPath && (
218+
<p className="text-xs uppercase tracking-wide text-text-tertiary">
219+
{doc.parentPath.join(' / ')}
220+
</p>
221+
)}
222+
</div>
223+
</div>
224+
<div className="text-sm text-text-secondary sm:text-right">
225+
Updated {isUnknownDate ? 'recently' : formattedDate}
226+
</div>
227+
</li>
228+
);
229+
})}
230+
</ul>
231+
) : (
232+
<div className="mt-4 flex items-center gap-2 rounded-md border border-dashed border-border-color/70 bg-background/60 px-4 py-3 text-sm text-text-secondary">
233+
<InfoIcon className="h-4 w-4" />
234+
<span>No recent document activity yet. Updates will appear here as you work.</span>
235+
</div>
236+
)}
237+
</div>
238+
186239
{!hasChildren && (
187240
<div className="mt-8 flex items-center gap-3 rounded-lg border border-dashed border-border-color/80 bg-background/60 p-6 text-sm text-text-secondary">
188241
<InfoIcon className="h-5 w-5 text-text-secondary" />

0 commit comments

Comments
 (0)