Add company overview skeleton and cache
This commit is contained in:
141
components/analysis/company-analysis-skeleton.tsx
Normal file
141
components/analysis/company-analysis-skeleton.tsx
Normal file
@@ -0,0 +1,141 @@
|
||||
import { Panel } from '@/components/ui/panel';
|
||||
|
||||
function SkeletonLine(props: { className: string }) {
|
||||
return (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className={`rounded-full bg-[color:var(--panel-soft)] motion-safe:animate-pulse ${props.className}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function SkeletonCard(props: {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<Panel title={props.title} subtitle={props.subtitle} className={props.className}>
|
||||
{props.children}
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
export function CompanyAnalysisSkeleton() {
|
||||
return (
|
||||
<div className="space-y-6" data-testid="analysis-overview-skeleton" aria-live="polite" aria-busy="true">
|
||||
<span className="sr-only">Loading company overview</span>
|
||||
|
||||
<section className="grid gap-6 xl:grid-cols-[minmax(320px,1fr)_minmax(0,2fr)]">
|
||||
<Panel className="h-full pt-2">
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-3">
|
||||
<SkeletonLine className="h-8 w-3/4" />
|
||||
<SkeletonLine className="h-3 w-1/2" />
|
||||
</div>
|
||||
<div className="border-t border-[color:var(--line-weak)] py-4">
|
||||
<div className="space-y-3">
|
||||
<SkeletonLine className="h-3 w-28" />
|
||||
<SkeletonLine className="h-4 w-full" />
|
||||
<SkeletonLine className="h-4 w-[92%]" />
|
||||
<SkeletonLine className="h-4 w-[84%]" />
|
||||
<SkeletonLine className="h-4 w-[66%]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Panel>
|
||||
|
||||
<SkeletonCard title="Price chart" className="pt-2">
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
{Array.from({ length: 3 }, (_, index) => (
|
||||
<div key={index} className="border-b border-[color:var(--line-weak)] px-4 py-4 sm:border-b-0 sm:border-r last:border-r-0">
|
||||
<SkeletonLine className="h-3 w-24" />
|
||||
<SkeletonLine className="mt-3 h-7 w-28" />
|
||||
<SkeletonLine className="mt-3 h-3 w-20" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="rounded-xl border border-[color:var(--line-weak)] bg-[color:var(--panel-soft)] p-4">
|
||||
<SkeletonLine className="h-[288px] w-full rounded-xl" />
|
||||
</div>
|
||||
</div>
|
||||
</SkeletonCard>
|
||||
</section>
|
||||
|
||||
<section className="grid gap-6 xl:grid-cols-2">
|
||||
<SkeletonCard title="Company profile facts" className="pt-2">
|
||||
<div className="space-y-3">
|
||||
{Array.from({ length: 4 }, (_, index) => (
|
||||
<div key={index} className="grid grid-cols-[18%_32%_18%_32%] gap-3 border-t border-[color:var(--line-weak)] py-2">
|
||||
<SkeletonLine className="h-3 w-16" />
|
||||
<SkeletonLine className="h-4 w-20" />
|
||||
<SkeletonLine className="h-3 w-16" />
|
||||
<SkeletonLine className="h-4 w-24" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</SkeletonCard>
|
||||
|
||||
<SkeletonCard title="Valuation" className="pt-2">
|
||||
<div className="space-y-3">
|
||||
{Array.from({ length: 4 }, (_, index) => (
|
||||
<div key={index} className="grid grid-cols-[18%_32%_18%_32%] gap-3 border-t border-[color:var(--line-weak)] py-2">
|
||||
<SkeletonLine className="h-3 w-20" />
|
||||
<SkeletonLine className="h-4 w-24" />
|
||||
<SkeletonLine className="h-3 w-20" />
|
||||
<SkeletonLine className="h-4 w-20" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</SkeletonCard>
|
||||
</section>
|
||||
|
||||
<SkeletonCard title="Bull vs Bear" subtitle="The highest-level reasons investors may lean in or lean out right now." className="pt-2">
|
||||
<div className="grid gap-4 lg:grid-cols-2">
|
||||
{Array.from({ length: 2 }, (_, index) => (
|
||||
<section key={index} className="border-t border-[color:var(--line-weak)] pt-5">
|
||||
<SkeletonLine className="h-6 w-28" />
|
||||
<div className="mt-4 space-y-3">
|
||||
{Array.from({ length: 3 }, (_, bulletIndex) => (
|
||||
<div key={bulletIndex} className="border-t border-[color:var(--line-weak)] pt-3">
|
||||
<SkeletonLine className="h-4 w-full" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
</SkeletonCard>
|
||||
|
||||
<section className="grid gap-6 xl:grid-cols-[minmax(280px,0.72fr)_minmax(0,1.28fr)]">
|
||||
<SkeletonCard title="Past 7 Days" className="pt-2">
|
||||
<div className="space-y-3">
|
||||
<SkeletonLine className="h-4 w-full" />
|
||||
<SkeletonLine className="h-4 w-[88%]" />
|
||||
<div className="space-y-2 pt-2">
|
||||
{Array.from({ length: 3 }, (_, index) => (
|
||||
<SkeletonLine key={index} className="h-4 w-full" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</SkeletonCard>
|
||||
|
||||
<SkeletonCard title="Recent Developments" subtitle="SEC-first event cards sourced from filings and attached analysis." className="pt-2">
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
{Array.from({ length: 4 }, (_, index) => (
|
||||
<article key={index} className="border-t border-[color:var(--line-weak)] pt-4">
|
||||
<SkeletonLine className="h-3 w-28" />
|
||||
<SkeletonLine className="mt-3 h-5 w-3/4" />
|
||||
<SkeletonLine className="mt-3 h-4 w-full" />
|
||||
<SkeletonLine className="mt-2 h-4 w-[90%]" />
|
||||
<SkeletonLine className="mt-4 h-3 w-24" />
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</SkeletonCard>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user