Defer heavy getServerSideProps on home, operator, addresses, and wallet to cut TTFB; centralize locale-safe formatters with client-only relative times; add compact ops UX, bridge/operator relay pagination, and Playwright route/scroll smoke in deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
import Link from 'next/link'
|
|
import { Card } from '@/libs/frontend-ui-primitives'
|
|
import type { ExplorerFeatureAction } from '@/data/explorerOperations'
|
|
|
|
export function OperationsActionLink({ action }: { action: ExplorerFeatureAction }) {
|
|
const className = 'inline-flex items-center text-sm font-semibold text-primary-600 hover:underline'
|
|
const label = `${action.label} ->`
|
|
|
|
if (action.external) {
|
|
return (
|
|
<a href={action.href} className={className} target="_blank" rel="noopener noreferrer">
|
|
{label}
|
|
</a>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<Link href={action.href} className={className}>
|
|
{label}
|
|
</Link>
|
|
)
|
|
}
|
|
|
|
function ActionCard({ action }: { action: ExplorerFeatureAction }) {
|
|
return (
|
|
<Card className="border border-gray-200 dark:border-gray-700">
|
|
<div className="flex h-full flex-col">
|
|
<div className="text-base font-semibold text-gray-900 dark:text-white">{action.title}</div>
|
|
<p className="mt-2 flex-1 text-sm leading-6 text-gray-600 dark:text-gray-400">{action.description}</p>
|
|
<div className="mt-4">
|
|
<OperationsActionLink action={action} />
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
export default function OperationsActionGrid({
|
|
actions,
|
|
title = 'Quick actions',
|
|
className = '',
|
|
}: {
|
|
actions: ExplorerFeatureAction[]
|
|
title?: string
|
|
className?: string
|
|
}) {
|
|
if (actions.length === 0) return null
|
|
|
|
return (
|
|
<div className={className}>
|
|
<details className="group mb-6 rounded-2xl border border-gray-200 bg-gray-50/80 dark:border-gray-800 dark:bg-gray-900/40 md:hidden">
|
|
<summary className="cursor-pointer list-none px-4 py-3 text-sm font-semibold text-gray-900 dark:text-white [&::-webkit-details-marker]:hidden">
|
|
<span className="flex items-center justify-between gap-3">
|
|
{title}
|
|
<span className="text-xs font-normal uppercase tracking-wide text-gray-500">
|
|
{actions.length} links · <span className="group-open:hidden">Show</span>
|
|
<span className="hidden group-open:inline">Hide</span>
|
|
</span>
|
|
</span>
|
|
</summary>
|
|
<div className="space-y-3 border-t border-gray-200 px-3 py-3 dark:border-gray-800">
|
|
{actions.map((action) => (
|
|
<ActionCard key={`${action.title}-${action.href}`} action={action} />
|
|
))}
|
|
</div>
|
|
</details>
|
|
|
|
<div className="hidden gap-4 md:grid lg:grid-cols-2">
|
|
{actions.map((action) => (
|
|
<ActionCard key={`${action.title}-${action.href}`} action={action} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|