Cleaned up repo with old files, and ammended logo size in sidebar/mobile overview

This commit is contained in:
2026-02-20 10:53:40 +00:00
parent d478276c3b
commit c651f0ed44
230 changed files with 108 additions and 25321 deletions
-2
View File
@@ -569,5 +569,3 @@ export function BootSequence({ onComplete }: BootSequenceProps) {
)
}
export type { BootConfig, BootLine, BootLineType }
export { BOOT_CONFIG }
+3 -3
View File
@@ -28,9 +28,9 @@ const FAN_RIGHT_STAGGER_S = 0 // stagger delay for right pill (s)
const TOTAL_ANIMATION_MS = FAN_DELAY_AFTER_RISE_MS + FAN_DURATION_S * 1000
// Overlap blend: multiply blend on fanning capsules (used by US-005)
export const OVERLAY_BLEND_START_PROGRESS = 0.2 // fan progress at which blend fades in
export const OVERLAP_BLEND_MAX_OPACITY = 0.3 // max blend opacity (20%)
export const OVERLAP_BLEND_TRANSITION_DURATION_S = FAN_DURATION_S * (1 - OVERLAY_BLEND_START_PROGRESS)
const OVERLAY_BLEND_START_PROGRESS = 0.2 // fan progress at which blend fades in
const OVERLAP_BLEND_MAX_OPACITY = 0.3 // max blend opacity (20%)
const OVERLAP_BLEND_TRANSITION_DURATION_S = FAN_DURATION_S * (1 - OVERLAY_BLEND_START_PROGRESS)
// Pivot point: bottom-center of the pill stack (in viewBox coords)
const PX = 300
-151
View File
@@ -1,151 +0,0 @@
import { useState } from 'react'
import { CardHeader } from './Card'
import { useDetailPanel } from '@/contexts/DetailPanelContext'
import { documents } from '@/data/documents'
import { educationExtras } from '@/data/educationExtras'
export function EducationSubsection() {
const { openPanel } = useDetailPanel()
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
const educationDocuments = [
documents.find((d) => d.id === 'doc-mary-seacole')!,
documents.find((d) => d.id === 'doc-mpharm')!,
documents.find((d) => d.id === 'doc-alevels')!,
]
const getExtras = (docId: string) =>
educationExtras.find((e) => e.documentId === docId)
const getInlineDetails = (doc: (typeof educationDocuments)[0]) => {
const extras = getExtras(doc.id)
switch (doc.id) {
case 'doc-mpharm':
return {
title: 'MPharm (Hons) — 2:1',
institution: 'University of East Anglia',
year: '20112015',
details: [
`Research project: Drug delivery & cocrystals, 75.1% (Distinction)`,
...(extras?.osceScore ? [`4th year OSCE: ${extras.osceScore}`] : []),
],
}
case 'doc-mary-seacole':
return {
title: 'NHS Leadership Academy — Mary Seacole Programme',
institution: 'NHS Leadership Academy',
year: '2018',
details: [
`Programme score: 78%`,
...(extras?.programmeDetail ? [extras.programmeDetail] : []),
],
}
case 'doc-alevels':
return {
title: 'A-Levels',
institution: 'Highworth Grammar School',
year: '20092011',
details: ['Mathematics (A*) · Chemistry (B) · Politics (C)'],
}
default:
return {
title: doc.title,
institution: doc.institution,
year: doc.date,
details: doc.classification ? [doc.classification] : [],
}
}
}
return (
<div style={{ marginTop: '24px' }}>
<CardHeader dotColor="purple" title="EDUCATION" />
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
{educationDocuments.map((doc, index) => {
const content = getInlineDetails(doc)
const isHovered = hoveredIndex === index
return (
<button
key={doc.id}
onClick={() => openPanel({ type: 'education', document: doc })}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(null)}
style={{
padding: '12px 16px',
background: 'var(--surface)',
border: `1px solid ${isHovered ? 'var(--accent)' : 'var(--border-light)'}`,
borderRadius: 'var(--radius-sm)',
fontSize: '13px',
color: 'var(--text-primary)',
cursor: 'pointer',
textAlign: 'left',
transition: 'border-color 150ms ease-out, box-shadow 150ms ease-out',
boxShadow: isHovered
? '0 2px 8px rgba(26,43,42,0.08)'
: '0 1px 2px rgba(26,43,42,0.05)',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'baseline',
gap: '12px',
marginBottom: '4px',
}}
>
<span style={{ fontWeight: 600, fontSize: '14px' }}>
{content.title}
</span>
<span
style={{
fontFamily: 'var(--font-geist-mono)',
fontSize: '11px',
color: 'var(--text-tertiary)',
whiteSpace: 'nowrap',
}}
>
{content.year}
</span>
</div>
<div
style={{
color: 'var(--text-secondary)',
fontSize: '12px',
marginBottom: content.details.length > 0 ? '6px' : '0',
}}
>
{content.institution}
</div>
{content.details.length > 0 && (
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '2px',
}}
>
{content.details.map((detail, i) => (
<div
key={i}
style={{
color: 'var(--text-tertiary)',
fontSize: '12px',
fontFamily: 'var(--font-geist-mono)',
}}
>
{detail}
</div>
))}
</div>
)}
</button>
)
})}
</div>
</div>
)
}
+1 -1
View File
@@ -66,7 +66,7 @@ export function MobileOverviewHeader({ onSearchClick }: MobileOverviewHeaderProp
>
{/* Logo + Search row */}
<div style={{ display: 'flex', alignItems: 'flex-end', gap: '6px', marginBottom: '12px' }}>
<CvmisLogo cssHeight="40px" />
<CvmisLogo cssHeight="50px" />
<button
type="button"
onClick={onSearchClick}
+2 -3
View File
@@ -232,7 +232,7 @@ export default function Sidebar({ activeSection, onNavigate, onSearchClick }: Si
width: '100%',
}}
>
<CvmisLogo cssHeight="48px" />
<CvmisLogo cssHeight="50px" />
<button
type="button"
onClick={onSearchClick}
@@ -240,7 +240,6 @@ export default function Sidebar({ activeSection, onNavigate, onSearchClick }: Si
aria-label={sidebarCopy.searchAriaLabel}
style={{
width: '100%',
minHeight: '44px',
border: '1px solid var(--border)',
borderRadius: 'var(--radius-sm)',
background: 'var(--surface)',
@@ -253,7 +252,7 @@ export default function Sidebar({ activeSection, onNavigate, onSearchClick }: Si
}}
>
<Search size={16} style={{ color: 'var(--text-tertiary)', flexShrink: 0 }} aria-hidden="true" />
<span style={{ flex: 1, textAlign: 'left', fontSize: '13px' }}>
<span style={{ flex: 1, textAlign: 'left', fontSize: '13px', padding: '5px 0' }}>
{sidebarCopy.searchLabel}
</span>
<kbd
@@ -1,6 +1,5 @@
// Sizing
export const MIN_HEIGHT = 400
export const MOBILE_FALLBACK_HEIGHT = 520
export const ROLE_WIDTH = 104
export const ROLE_HEIGHT = 32
export const ROLE_RX = 16
@@ -50,12 +49,6 @@ export const SKILL_Y_OFFSET_STEP_MOBILE = 26
export const SKILL_Y_GLOBAL_OFFSET_RATIO = -0.05
export const SKILL_Y_CENTER_BLEND = 0.55
export const SKILL_X_OVERLAP_MAX_RATIO = 1
// Entry animation
export const ENTRY_GUIDE_FADE_MS = 200
export const ENTRY_ROLE_STAGGER_MS = 80
export const ENTRY_ROLE_DURATION_MS = 300
export const ENTRY_SKILL_STAGGER_MS = 30
export const ENTRY_SKILL_DURATION_MS = 250
// Timeline animation
export const ANIM_CHRONOLOGICAL_ENABLED = true
@@ -66,8 +59,6 @@ export const ANIM_LINK_DRAW_MS = 600
export const ANIM_LINK_STAGGER_MS = 200
export const ANIM_REINFORCEMENT_MS = 700
export const ANIM_STEP_GAP_MS = 1000
export const ANIM_HOLD_MS = 15000
export const ANIM_RESET_MS = 800
export const ANIM_RESTART_DELAY_MS = 400
export const ANIM_SETTLE_ALPHA = 0.05
-14
View File
@@ -1,14 +0,0 @@
import type { Alert } from '@/types/pmr'
export const alerts: Alert[] = [
{
message: '£14.6M SAVINGS IDENTIFIED',
severity: 'alert',
icon: 'AlertTriangle',
},
{
message: '£215M BUDGET OVERSIGHT',
severity: 'amber',
icon: 'AlertCircle',
},
]
+1 -8
View File
@@ -495,17 +495,10 @@ export const timelineEntities: TimelineEntity[] = [...timelineEntitySeeds].sort(
return b.dateRange.start.localeCompare(a.dateRange.start)
})
export const timelineCareerEntities: TimelineEntity[] = timelineEntities.filter(
const timelineCareerEntities: TimelineEntity[] = timelineEntities.filter(
(entity) => entity.kind === 'career',
)
export const timelineEducationEntities: TimelineEntity[] = timelineEntities.filter(
(entity) => entity.kind === 'education',
)
// Compatibility alias retained for downstream consumers that still import role entities.
export const timelineRoleEntities = timelineCareerEntities
function mapTimelineToConsultation(entity: TimelineEntity): Consultation {
const codedEntries: CodedEntry[] = entity.codedEntries ?? entity.details.map((detail, index) => ({
code: `DET${String(index + 1).padStart(3, '0')}`,
+10 -21
View File
@@ -5,8 +5,8 @@
/* Premium UI fonts — Elvaro Grotesque (primary) */
@font-face {
font-family: 'Elvaro Grotesque';
src: url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-Regular.woff2') format('woff2'),
url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-Regular.woff') format('woff');
src: url('/fonts/elvaro/TBJElvaro-Regular.woff2') format('woff2'),
url('/fonts/elvaro/TBJElvaro-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
@@ -14,8 +14,8 @@
@font-face {
font-family: 'Elvaro Grotesque';
src: url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-Medium.woff2') format('woff2'),
url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-Medium.woff') format('woff');
src: url('/fonts/elvaro/TBJElvaro-Medium.woff2') format('woff2'),
url('/fonts/elvaro/TBJElvaro-Medium.woff') format('woff');
font-weight: 500;
font-style: normal;
font-display: swap;
@@ -23,8 +23,8 @@
@font-face {
font-family: 'Elvaro Grotesque';
src: url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-SemiBold.woff2') format('woff2'),
url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-SemiBold.woff') format('woff');
src: url('/fonts/elvaro/TBJElvaro-SemiBold.woff2') format('woff2'),
url('/fonts/elvaro/TBJElvaro-SemiBold.woff') format('woff');
font-weight: 600;
font-style: normal;
font-display: swap;
@@ -32,28 +32,18 @@
@font-face {
font-family: 'Elvaro Grotesque';
src: url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-Bold.woff2') format('woff2'),
url('/Fonts/Elvaro Grotesque Sans Family/WOFF/TBJElvaro-Bold.woff') format('woff');
src: url('/fonts/elvaro/TBJElvaro-Bold.woff2') format('woff2'),
url('/fonts/elvaro/TBJElvaro-Bold.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
/* Monospace — Interval Mono */
@font-face {
font-family: 'Interval Mono';
src: url('/Fonts/IntervalMono/WOFF/TBJInterval-Regular.woff2') format('woff2'),
url('/Fonts/IntervalMono/WOFF/TBJInterval-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
/* Premium UI fonts — Blumir (alternative) */
@font-face {
font-family: 'Blumir';
src: url('/Fonts/blumir-font-family/WOFF/Blumir-VF.woff2') format('woff2-variations'),
url('/Fonts/blumir-font-family/WOFF/Blumir-VF.woff') format('woff-variations');
src: url('/fonts/blumir/Blumir-VF.woff2') format('woff2-variations'),
url('/fonts/blumir/Blumir-VF.woff') format('woff-variations');
font-weight: 100 700;
font-style: normal;
font-display: swap;
@@ -114,7 +104,6 @@
--shadow-md: 0 2px 8px rgba(26,43,42,0.08);
--shadow-lg: 0 8px 32px rgba(26,43,42,0.12);
--font-body: var(--font-ui);
--font-mono-dashboard: 'Interval Mono', 'Fira Code', monospace;
/* Detail panel */
--panel-narrow: 400px;
+2 -2
View File
@@ -5,14 +5,14 @@ export interface ChatMessage {
content: string
}
export const LLM_MODEL = 'google/gemini-3-flash-preview'
const LLM_MODEL = 'google/gemini-3-flash-preview'
export const LLM_DISPLAY_NAME = 'Gemini 3 Flash'
export function isLLMAvailable(): boolean {
return true
}
export function buildSystemPrompt(): string {
function buildSystemPrompt(): string {
return LLM_SYSTEM_PROMPT
}
-6
View File
@@ -109,12 +109,6 @@ export interface Tag {
colorVariant: 'teal' | 'amber' | 'green'
}
export interface Alert {
message: string
severity: 'alert' | 'amber'
icon: string
}
export interface KPI {
id: string
value: string