65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
/**
|
|
* Shared UI primitives used by both hub and live-map frontends.
|
|
* Keep this package dependency-free (no Tailwind, no MUI) — apps
|
|
* style with their own CSS / framework.
|
|
*/
|
|
|
|
import { type ReactNode } from 'react';
|
|
|
|
export function Pill({ children, tone = 'neutral' }: { children: ReactNode; tone?: 'neutral' | 'success' | 'warn' | 'danger' }) {
|
|
const colorMap = {
|
|
neutral: 'var(--pill-neutral, #ddd)',
|
|
success: 'var(--pill-success, #2c5)',
|
|
warn: 'var(--pill-warn, #fa3)',
|
|
danger: 'var(--pill-danger, #e44)',
|
|
} as const;
|
|
return (
|
|
<span
|
|
style={{
|
|
display: 'inline-block',
|
|
padding: '0.125rem 0.5rem',
|
|
borderRadius: 999,
|
|
background: colorMap[tone],
|
|
color: 'white',
|
|
fontSize: '0.75rem',
|
|
fontWeight: 600,
|
|
letterSpacing: '0.02em',
|
|
}}
|
|
>
|
|
{children}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
export function Card({ children, title }: { children: ReactNode; title?: string }) {
|
|
return (
|
|
<section
|
|
style={{
|
|
border: '1px solid var(--card-border, #333)',
|
|
borderRadius: 8,
|
|
padding: '1rem',
|
|
background: 'var(--card-bg, rgba(255,255,255,0.03))',
|
|
}}
|
|
>
|
|
{title && (
|
|
<h3 style={{ margin: '0 0 0.5rem', fontSize: '1rem', fontWeight: 600 }}>{title}</h3>
|
|
)}
|
|
{children}
|
|
</section>
|
|
);
|
|
}
|
|
|
|
export function formatUtAsKspDate(ut: number): string {
|
|
// KSP year 1 day 1 00:00:00 is UT=0. A KSP day is 6 hours, a year is 426 days.
|
|
const KSP_DAY_SECONDS = 6 * 3600;
|
|
const KSP_YEAR_DAYS = 426;
|
|
const totalDays = ut / KSP_DAY_SECONDS;
|
|
const year = Math.floor(totalDays / KSP_YEAR_DAYS) + 1;
|
|
const day = (Math.floor(totalDays) % KSP_YEAR_DAYS) + 1;
|
|
const secondsInDay = ut % KSP_DAY_SECONDS;
|
|
const hour = Math.floor(secondsInDay / 3600);
|
|
const minute = Math.floor((secondsInDay % 3600) / 60);
|
|
const second = Math.floor(secondsInDay % 60);
|
|
return `Y${year} D${day} ${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:${String(second).padStart(2, '0')}`;
|
|
}
|