From 2a162188714ff8bf4b124e9b99d9c0d369f107c6 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Thu, 11 Dec 2025 11:37:42 +1000 Subject: [PATCH] fix(tool-search): add published date, center copy button - Add formatTimeAgo utility function for relative time display - Show "Published X ago" at bottom of each tool card using npmPublishedAt - Center CodeBlock copy button vertically for better alignment - Update Tool interface to include npmPublishedAt from API --- apps/web/src/app/tool/tool-search/page.tsx | 32 +++++++++++++--------- packages/ui/src/CodeBlock/variants.ts | 6 ++-- packages/utils/src/format.ts | 24 ++++++++++++++++ 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/apps/web/src/app/tool/tool-search/page.tsx b/apps/web/src/app/tool/tool-search/page.tsx index a0ae2c6..aa024e5 100644 --- a/apps/web/src/app/tool/tool-search/page.tsx +++ b/apps/web/src/app/tool/tool-search/page.tsx @@ -10,6 +10,7 @@ import { Input } from '@tpmjs/ui/Input/Input'; import { ProgressBar } from '@tpmjs/ui/ProgressBar/ProgressBar'; import { Select } from '@tpmjs/ui/Select/Select'; import { Spinner } from '@tpmjs/ui/Spinner/Spinner'; +import { formatTimeAgo } from '@tpmjs/utils/format'; import Link from 'next/link'; import { useEffect, useState } from 'react'; import { AppHeader } from '~/components/AppHeader'; @@ -25,6 +26,7 @@ interface Tool { package: { npmPackageName: string; npmVersion: string; + npmPublishedAt: string; category: string; npmRepository: { url: string; type: string } | null; isOfficial: boolean; @@ -323,19 +325,23 @@ export default function ToolSearchPage(): React.ReactElement { )} - {/* Install command - onClick prevents propagation to parent Link */} -
e.stopPropagation()} - onKeyDown={(e) => e.stopPropagation()} - role="presentation" - > - + {/* Bottom section with install command and published date */} +
+
e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} + role="presentation" + > + +
+
+ Published {formatTimeAgo(tool.package.npmPublishedAt)} +
diff --git a/packages/ui/src/CodeBlock/variants.ts b/packages/ui/src/CodeBlock/variants.ts index f7a2808..5122e3f 100644 --- a/packages/ui/src/CodeBlock/variants.ts +++ b/packages/ui/src/CodeBlock/variants.ts @@ -59,12 +59,12 @@ export const codeBlockCodeVariants = createVariants({ */ export const codeBlockCopyButtonVariants = createVariants({ base: [ - // Position - 'absolute top-2 right-2', + // Position - vertically centered on right side + 'absolute right-2 top-1/2 -translate-y-1/2', // Display 'flex items-center justify-center', // Size - 'w-8 h-8', + 'w-7 h-7', // Background 'bg-surface-elevated hover:bg-accent', // Border diff --git a/packages/utils/src/format.ts b/packages/utils/src/format.ts index 5dbc40f..ae53d78 100644 --- a/packages/utils/src/format.ts +++ b/packages/utils/src/format.ts @@ -9,3 +9,27 @@ export function formatDate(date: Date): string { export function formatNumber(num: number): string { return new Intl.NumberFormat('en-US').format(num); } + +/** + * Format a date as a relative time string (e.g., "2 days ago", "3 months ago") + */ +export function formatTimeAgo(date: Date | string): string { + const now = new Date(); + const then = typeof date === 'string' ? new Date(date) : date; + const diffMs = now.getTime() - then.getTime(); + const diffSecs = Math.floor(diffMs / 1000); + const diffMins = Math.floor(diffSecs / 60); + const diffHours = Math.floor(diffMins / 60); + const diffDays = Math.floor(diffHours / 24); + const diffWeeks = Math.floor(diffDays / 7); + const diffMonths = Math.floor(diffDays / 30); + const diffYears = Math.floor(diffDays / 365); + + if (diffSecs < 60) return 'just now'; + if (diffMins < 60) return `${diffMins}m ago`; + if (diffHours < 24) return `${diffHours}h ago`; + if (diffDays < 7) return `${diffDays}d ago`; + if (diffWeeks < 4) return `${diffWeeks}w ago`; + if (diffMonths < 12) return `${diffMonths}mo ago`; + return `${diffYears}y ago`; +}