517 lines
No EOL
9.8 KiB
TypeScript
517 lines
No EOL
9.8 KiB
TypeScript
/**
|
|
* Device type definitions for portfolio showcase.
|
|
*
|
|
* Provides comprehensive type safety for device specifications, statistics,
|
|
* sections, and UI components. Supports both mobile devices and DAPs (Digital Audio Players).
|
|
*
|
|
* @module lib/types/device
|
|
* @category Types
|
|
*/
|
|
|
|
import React from 'react'
|
|
|
|
/**
|
|
* Icon component type for device-related icons.
|
|
*
|
|
* @public
|
|
*/
|
|
export type DeviceIcon = React.ComponentType<{
|
|
/** Optional className for styling */
|
|
className?: string
|
|
/** Optional size override */
|
|
size?: number
|
|
}>
|
|
|
|
/**
|
|
* Device type classification.
|
|
*
|
|
* @remarks
|
|
* - `mobile`: Smartphones and mobile devices
|
|
* - `dap`: Digital Audio Players (dedicated music players)
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const type: DeviceType = 'mobile'
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export type DeviceType = 'mobile' | 'dap'
|
|
|
|
/**
|
|
* Star rating display state.
|
|
*
|
|
* @remarks
|
|
* Used for rendering star ratings with half-star support.
|
|
*
|
|
* @public
|
|
*/
|
|
export type StarState = 'full' | 'half' | 'empty'
|
|
|
|
/**
|
|
* Type-safe external URL starting with http or https.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const url: ExternalHref = 'https://example.com'
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export type ExternalHref = `http${string}`
|
|
|
|
/**
|
|
* Badge display configuration for device highlights.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const badge: DeviceBadge = {
|
|
* label: 'Flagship',
|
|
* tone: 'highlight'
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceBadge {
|
|
/** Badge text */
|
|
label: string
|
|
|
|
/** Visual tone (default: neutral, highlight: accent, muted: subtle) */
|
|
tone?: 'default' | 'highlight' | 'muted'
|
|
}
|
|
|
|
/**
|
|
* Individual stat item within a stat group.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const stat: DeviceStatItem = {
|
|
* label: 'Display',
|
|
* value: '6.1" OLED',
|
|
* href: 'https://example.com/display-specs'
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceStatItem {
|
|
/** Optional label for the stat */
|
|
label?: string
|
|
|
|
/** Stat value to display */
|
|
value: string
|
|
|
|
/** Optional external link for more information */
|
|
href?: string
|
|
}
|
|
|
|
/**
|
|
* Group of related device statistics.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* import { CpuIcon } from 'lucide-react'
|
|
*
|
|
* const group: DeviceStatGroup = {
|
|
* title: 'Performance',
|
|
* icon: CpuIcon,
|
|
* accent: 'primary',
|
|
* items: [
|
|
* { label: 'Processor', value: 'Snapdragon 8 Gen 2' },
|
|
* { label: 'RAM', value: '8GB' },
|
|
* { label: 'Storage', value: '256GB' }
|
|
* ]
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceStatGroup {
|
|
/** Group title */
|
|
title: string
|
|
|
|
/** Optional icon for visual identification */
|
|
icon?: DeviceIcon
|
|
|
|
/** List of stat items in this group */
|
|
items: DeviceStatItem[]
|
|
|
|
/** Visual accent style */
|
|
accent?: 'primary' | 'surface'
|
|
}
|
|
|
|
/**
|
|
* Row item within a device section showing key-value pairs.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* import { BatteryIcon } from 'lucide-react'
|
|
*
|
|
* const row: DeviceSectionRow = {
|
|
* label: 'Battery',
|
|
* value: '5000 mAh',
|
|
* icon: BatteryIcon,
|
|
* note: 'Supports 65W fast charging'
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceSectionRow {
|
|
/** Row label */
|
|
label: string
|
|
|
|
/** Row value */
|
|
value: string
|
|
|
|
/** Optional icon */
|
|
icon?: DeviceIcon
|
|
|
|
/** Optional external link */
|
|
href?: string
|
|
|
|
/** Optional additional note */
|
|
note?: string
|
|
}
|
|
|
|
/**
|
|
* List item within a device section.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const item: DeviceSectionListItem = {
|
|
* label: 'USB-C 3.1',
|
|
* description: 'Fast data transfer and charging',
|
|
* href: 'https://example.com/usb-specs'
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceSectionListItem {
|
|
/** Item label */
|
|
label: string
|
|
|
|
/** Optional description */
|
|
description?: string
|
|
|
|
/** Optional external link */
|
|
href?: string
|
|
}
|
|
|
|
/**
|
|
* Rating configuration for device sections.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const rating: DeviceSectionRating = {
|
|
* value: 4.5,
|
|
* scale: 5,
|
|
* label: 'Overall Rating'
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceSectionRating {
|
|
/** Rating value (supports half-stars) */
|
|
value: number
|
|
|
|
/** Maximum rating scale (default: 5) */
|
|
scale?: number
|
|
|
|
/** Optional rating label */
|
|
label?: string
|
|
}
|
|
|
|
/**
|
|
* Device section containing grouped information.
|
|
*
|
|
* @remarks
|
|
* Sections can contain one of: rows (key-value pairs), listItems (bullet lists),
|
|
* paragraphs (text content), or rating (star rating). Each section has an icon
|
|
* for visual identification.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* import { CameraIcon } from 'lucide-react'
|
|
*
|
|
* const section: DeviceSection = {
|
|
* id: 'camera',
|
|
* title: 'Camera',
|
|
* icon: CameraIcon,
|
|
* rows: [
|
|
* { label: 'Main', value: '50MP f/1.8' },
|
|
* { label: 'Ultra-wide', value: '12MP f/2.2' },
|
|
* { label: 'Telephoto', value: '10MP f/2.4' }
|
|
* ],
|
|
* rating: { value: 4.5, scale: 5 }
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceSection {
|
|
/** Unique section identifier */
|
|
id: string
|
|
|
|
/** Section title */
|
|
title: string
|
|
|
|
/** Section icon */
|
|
icon: DeviceIcon
|
|
|
|
/** Optional key-value rows */
|
|
rows?: DeviceSectionRow[]
|
|
|
|
/** Optional list items */
|
|
listItems?: DeviceSectionListItem[]
|
|
|
|
/** Optional text paragraphs */
|
|
paragraphs?: string[]
|
|
|
|
/** Optional rating */
|
|
rating?: DeviceSectionRating
|
|
}
|
|
|
|
/**
|
|
* Complete device specification.
|
|
*
|
|
* Contains all data needed to render a device page including metadata, statistics,
|
|
* sections, and related devices.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* import { CpuIcon, BatteryIcon } from 'lucide-react'
|
|
*
|
|
* const device: DeviceSpec = {
|
|
* slug: 'pixel-8-pro',
|
|
* name: 'Google Pixel 8 Pro',
|
|
* codename: 'husky',
|
|
* type: 'mobile',
|
|
* manufacturer: 'Google',
|
|
* shortName: 'Pixel 8 Pro',
|
|
* status: 'Current',
|
|
* releaseYear: 2023,
|
|
* heroImage: {
|
|
* src: '/img/devices/pixel-8-pro.png',
|
|
* alt: 'Google Pixel 8 Pro',
|
|
* width: 800,
|
|
* height: 600
|
|
* },
|
|
* tagline: 'AI-powered flagship smartphone',
|
|
* summary: [
|
|
* 'Advanced Tensor G3 processor',
|
|
* 'Exceptional camera system',
|
|
* 'Premium build quality'
|
|
* ],
|
|
* badges: [
|
|
* { label: 'Flagship', tone: 'highlight' },
|
|
* { label: 'Current', tone: 'default' }
|
|
* ],
|
|
* stats: [
|
|
* {
|
|
* title: 'Performance',
|
|
* icon: CpuIcon,
|
|
* items: [
|
|
* { label: 'Processor', value: 'Google Tensor G3' },
|
|
* { label: 'RAM', value: '12GB' }
|
|
* ]
|
|
* }
|
|
* ],
|
|
* sections: [
|
|
* {
|
|
* id: 'battery',
|
|
* title: 'Battery',
|
|
* icon: BatteryIcon,
|
|
* rows: [{ label: 'Capacity', value: '5050 mAh' }]
|
|
* }
|
|
* ],
|
|
* related: ['pixel-7-pro', 'pixel-8'],
|
|
* updatedAt: '2024-01-15'
|
|
* }
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceSpec {
|
|
/** URL-friendly slug */
|
|
slug: string
|
|
|
|
/** Full device name */
|
|
name: string
|
|
|
|
/** Optional device codename */
|
|
codename?: string
|
|
|
|
/** Device type (mobile or dap) */
|
|
type: DeviceType
|
|
|
|
/** Manufacturer name */
|
|
manufacturer?: string
|
|
|
|
/** Short display name */
|
|
shortName?: string
|
|
|
|
/** Current status (e.g., 'Current', 'Retired') */
|
|
status?: string
|
|
|
|
/** Year of release */
|
|
releaseYear?: number
|
|
|
|
/** Hero image configuration */
|
|
heroImage: {
|
|
/** Image source path */
|
|
src: string
|
|
/** Alt text for accessibility */
|
|
alt: string
|
|
/** Optional width */
|
|
width?: number
|
|
/** Optional height */
|
|
height?: number
|
|
}
|
|
|
|
/** Marketing tagline */
|
|
tagline?: string
|
|
|
|
/** Summary bullet points */
|
|
summary?: string[]
|
|
|
|
/** Feature badges */
|
|
badges?: DeviceBadge[]
|
|
|
|
/** Stat groups */
|
|
stats: DeviceStatGroup[]
|
|
|
|
/** Content sections */
|
|
sections: DeviceSection[]
|
|
|
|
/** Related device slugs */
|
|
related?: string[]
|
|
|
|
/** Last update date (ISO format) */
|
|
updatedAt?: string
|
|
}
|
|
|
|
/**
|
|
* Collection of devices indexed by slug.
|
|
*
|
|
* @public
|
|
*/
|
|
export type DeviceCollection = Record<string, DeviceSpec>
|
|
|
|
/**
|
|
* Enriched device with computed metrics.
|
|
*
|
|
* Extends {@link DeviceSpec} with age calculations and display labels.
|
|
*
|
|
* @remarks
|
|
* This interface is generated by `DeviceService.enrichDevice()` method.
|
|
* All devices returned by DeviceService methods include these computed properties.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* import { DeviceService } from '@/lib/services'
|
|
*
|
|
* const enriched: DeviceWithMetrics = DeviceService.enrichDevice(device)
|
|
* console.log(enriched.ageInYears) // 1
|
|
* console.log(enriched.isCurrentYear) // false
|
|
* console.log(enriched.categoryLabel) // 'Mobile Devices'
|
|
* ```
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceWithMetrics extends DeviceSpec {
|
|
/** Device age in full years */
|
|
ageInYears: number
|
|
|
|
/** True if released in current year */
|
|
isCurrentYear: boolean
|
|
|
|
/** Display label for device category */
|
|
categoryLabel: string
|
|
}
|
|
|
|
/**
|
|
* Props for DevicePageShell component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DevicePageShellProps {
|
|
/** Device data to render */
|
|
device: DeviceSpec
|
|
}
|
|
|
|
/**
|
|
* Props for DeviceHero component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface DeviceHeroProps {
|
|
/** Device data for hero section */
|
|
device: DeviceSpec
|
|
}
|
|
|
|
/**
|
|
* Props for StatsGrid component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface StatsGridProps {
|
|
/** Stat groups to display */
|
|
stats: DeviceStatGroup[]
|
|
}
|
|
|
|
/**
|
|
* Props for StatItem component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface StatItemProps {
|
|
/** Stat item to display */
|
|
item: DeviceStatItem
|
|
|
|
/** Optional group icon for fallback */
|
|
groupIcon?: DeviceStatGroup['icon']
|
|
}
|
|
|
|
/**
|
|
* Props for SectionsGrid component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface SectionsGridProps {
|
|
/** Sections to display in grid */
|
|
sections: DeviceSection[]
|
|
}
|
|
|
|
/**
|
|
* Props for SectionCard component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface SectionCardProps {
|
|
/** Section data to render */
|
|
section: DeviceSection
|
|
}
|
|
|
|
/**
|
|
* Props for SectionRow component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface SectionRowProps {
|
|
/** Row data to render */
|
|
row: NonNullable<DeviceSection['rows']>[number]
|
|
}
|
|
|
|
/**
|
|
* Props for Rating component.
|
|
*
|
|
* @public
|
|
*/
|
|
export interface RatingProps {
|
|
/** Rating data to render */
|
|
rating: NonNullable<DeviceSection['rating']>
|
|
} |