refactor: extract hexToRgba and prefersReducedMotion to shared utils
Move hexToRgba() (3 identical copies) and prefersReducedMotion (5 module-level copies) to src/lib/utils.ts. Re-export prefersReducedMotion from constellation/constants.ts to preserve existing importers. Add clarifying comments to constellation.ts and tags.ts re-export layers (Phase 1.4).
This commit is contained in:
@@ -12,8 +12,7 @@ import {
|
||||
import { buildPaletteData } from '@/lib/search'
|
||||
import type { PaletteItem, PaletteAction } from '@/lib/search'
|
||||
import { iconByType, iconColorStyles } from '@/lib/palette-icons'
|
||||
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
import { prefersReducedMotion } from '@/lib/utils'
|
||||
|
||||
const MAX_HISTORY = 10
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import type { PaletteItem, PaletteAction } from '@/lib/search'
|
||||
import { iconByType, iconColorStyles } from '@/lib/palette-icons'
|
||||
import { isModelReady, embedQuery } from '@/lib/embedding-model'
|
||||
import { semanticSearch, loadEmbeddings } from '@/lib/semantic-search'
|
||||
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
import { prefersReducedMotion } from '@/lib/utils'
|
||||
|
||||
interface CommandPaletteProps {
|
||||
isOpen: boolean
|
||||
|
||||
@@ -17,8 +17,7 @@ import { useDetailPanel } from '@/contexts/DetailPanelContext'
|
||||
import { timelineConsultations } from '@/data/timeline'
|
||||
import { skills } from '@/data/skills'
|
||||
import type { PaletteAction } from '@/lib/search'
|
||||
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
import { hexToRgba, prefersReducedMotion } from '@/lib/utils'
|
||||
|
||||
const sidebarVariants = {
|
||||
hidden: prefersReducedMotion ? { x: 0, opacity: 1 } : { x: -272, opacity: 0 },
|
||||
@@ -41,13 +40,6 @@ const contentVariants = {
|
||||
},
|
||||
}
|
||||
|
||||
function hexToRgba(hex: string, opacity: number): string {
|
||||
const r = parseInt(hex.slice(1, 3), 16)
|
||||
const g = parseInt(hex.slice(3, 5), 16)
|
||||
const b = parseInt(hex.slice(5, 7), 16)
|
||||
return `rgba(${r},${g},${b},${opacity})`
|
||||
}
|
||||
|
||||
interface LastConsultationSubsectionProps {
|
||||
highlightedRoleId?: string | null
|
||||
}
|
||||
|
||||
@@ -5,15 +5,7 @@ import { useDetailPanel } from '@/contexts/DetailPanelContext'
|
||||
import { timelineEntities, timelineConsultations } from '@/data/timeline'
|
||||
import { getExperienceEducationUICopy } from '@/lib/profile-content'
|
||||
import type { TimelineEntity } from '@/types/pmr'
|
||||
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
|
||||
function hexToRgba(hex: string, opacity: number): string {
|
||||
const r = parseInt(hex.slice(1, 3), 16)
|
||||
const g = parseInt(hex.slice(3, 5), 16)
|
||||
const b = parseInt(hex.slice(5, 7), 16)
|
||||
return `rgba(${r},${g},${b},${opacity})`
|
||||
}
|
||||
import { hexToRgba, prefersReducedMotion } from '@/lib/utils'
|
||||
|
||||
interface TimelineInterventionItemProps {
|
||||
entity: TimelineEntity
|
||||
|
||||
@@ -4,15 +4,7 @@ import { ChevronRight } from 'lucide-react'
|
||||
import { CardHeader } from './Card'
|
||||
import { timelineConsultations } from '@/data/timeline'
|
||||
import { useDetailPanel } from '@/contexts/DetailPanelContext'
|
||||
|
||||
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
|
||||
function hexToRgba(hex: string, opacity: number): string {
|
||||
const r = parseInt(hex.slice(1, 3), 16)
|
||||
const g = parseInt(hex.slice(3, 5), 16)
|
||||
const b = parseInt(hex.slice(5, 7), 16)
|
||||
return `rgba(${r},${g},${b},${opacity})`
|
||||
}
|
||||
import { hexToRgba, prefersReducedMotion } from '@/lib/utils'
|
||||
|
||||
interface RoleItemProps {
|
||||
consultation: typeof timelineConsultations[0]
|
||||
|
||||
@@ -86,5 +86,5 @@ export const HIDDEN_ENTITY_IDS = new Set([
|
||||
])
|
||||
|
||||
// Media queries (evaluated once at module level)
|
||||
export const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
export { prefersReducedMotion } from '@/lib/utils'
|
||||
export const supportsCoarsePointer = window.matchMedia('(pointer: coarse)').matches
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Module-level cache: buildConstellationData() is expensive (D3 graph construction).
|
||||
// 5 consumers import from here instead of calling the builder independently.
|
||||
import type { ConstellationLink, ConstellationNode, RoleSkillMapping } from '@/types/pmr'
|
||||
import { buildConstellationData } from '@/data/timeline'
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Derives sidebar tags from timeline skills with color assignment.
|
||||
// Separated from Sidebar.tsx to keep data derivation out of UI components.
|
||||
import type { Tag } from '@/types/pmr'
|
||||
import { getTopTimelineSkills } from '@/data/timeline'
|
||||
|
||||
|
||||
@@ -6,3 +6,12 @@ export function calculateSkillOffset(level: number, radius: number): number {
|
||||
export function formatBootLine(text: string): string {
|
||||
return text
|
||||
}
|
||||
|
||||
export function hexToRgba(hex: string, opacity: number): string {
|
||||
const r = parseInt(hex.slice(1, 3), 16)
|
||||
const g = parseInt(hex.slice(3, 5), 16)
|
||||
const b = parseInt(hex.slice(5, 7), 16)
|
||||
return `rgba(${r},${g},${b},${opacity})`
|
||||
}
|
||||
|
||||
export const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
|
||||
Reference in New Issue
Block a user