import type { ReactElement } from 'react';
import { ArrowUpRight, Star, StarHalf, StarOff } from 'lucide-react';
import Link from '@/components/objects/Link';
import type {
DevicePageShellProps,
DeviceStatGroup,
StatsGridProps,
StatItemProps,
SectionsGridProps,
SectionCardProps,
SectionRowProps,
RatingProps,
StarState,
} from '@/lib/types';
import { isExternalHref, externalLinkProps } from '@/lib/utils/styles';
import { iconSizes } from '@/lib/devices/config';
import DeviceHero from './DeviceHero';
export default function DevicePageShell({ device }: DevicePageShellProps): ReactElement {
return (
{device.stats.length ? : null}
{device.sections.length ? : null}
);
}
function StatsGrid({ stats }: StatsGridProps): ReactElement {
return (
At a glance
{stats.map((group) => (
))}
);
}
function StatCard({ group }: { group: DeviceStatGroup }): ReactElement {
const Icon = group.icon;
return (
{Icon ? (
) : null}
{group.title}
{group.items.map((item) => (
))}
);
}
function StatItem({ item, groupIcon }: StatItemProps): ReactElement {
const isExternal = isExternalHref(item.href);
const linkProps = isExternal ? externalLinkProps : {};
const baseClasses =
'relative overflow-hidden rounded-2xl border border-gray-800 bg-gray-900/70 px-4 py-5 text-gray-100 transition';
const GroupIcon = groupIcon;
const content = (
<>
{GroupIcon ? (
) : null}
{item.href && isExternal ? (
) : null}
{item.label ? (
{item.label}
) : null}
{item.value}
>
);
if (item.href) {
return (
{content}
);
}
return {content}
;
}
function SectionsGrid({ sections }: SectionsGridProps): ReactElement {
return (
Deep dive
{sections.map((section) => (
))}
);
}
function SectionCard({ section }: SectionCardProps): ReactElement {
const Icon = section.icon;
const shouldSpanWide =
!!section.paragraphs?.length && (!section.rows || section.paragraphs.length > 1);
return (
{section.rows?.length ? (
{section.rows.map((row) => (
))}
) : null}
{section.listItems?.length ? (
{section.listItems.map((item) => {
const isExternal = isExternalHref(item.href);
const linkProps = isExternal ? externalLinkProps : {};
return (
-
{item.href ? (
{item.label}
{isExternal ? (
) : null}
) : (
{item.label}
)}
{item.description ? (
{item.description}
) : null}
);
})}
) : null}
{section.paragraphs?.length ? (
{section.paragraphs.map((paragraph) => (
{paragraph}
))}
) : null}
);
}
function SectionRow({ row }: SectionRowProps): ReactElement {
const { icon: RowIcon } = row;
const isExternal = isExternalHref(row.href);
const linkProps = isExternal ? externalLinkProps : {};
const baseClasses =
'relative overflow-hidden rounded-2xl border border-gray-800 bg-gray-900/70 px-4 py-5 text-gray-100 transition';
const content = (
<>
{RowIcon ? (
) : null}
{row.href && isExternal ? (
) : null}
{row.label}
{row.value}
{row.note ?
{row.note}
: null}
>
);
if (row.href) {
return (
{content}
);
}
return {content}
;
}
function Rating({ rating }: RatingProps): ReactElement {
const stars = buildStars(rating.value, rating.scale ?? 5);
return (
{stars.map((state, idx) => {
const key = `${rating.label ?? rating.value}-${idx}`;
if (state === 'full') {
return ;
}
if (state === 'half') {
return ;
}
return ;
})}
{rating.value.toFixed(1)}
{rating.label ? {rating.label} : null}
);
}
function buildStars(value: number, scale: number): StarState[] {
const stars: StarState[] = [];
const normalized = Math.max(0, Math.min(value, scale));
for (let i = 1; i <= scale; i += 1) {
if (normalized >= i) {
stars.push('full');
} else if (normalized > i - 1 && normalized < i) {
stars.push('half');
} else {
stars.push('empty');
}
}
return stars;
}