mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-25 00:01:47 +00:00
47671d52e0
FE6: split the oversized page and panel components into thin layout shells plus colocated use<Component> hooks, .constants.ts, .helpers.ts (with tests) and presentational sub-components, following the established 'logic in a hook, render in slices' pattern. Behaviour, markup, classes and effect order are unchanged. Largest reductions: PackingListPanel 1598->42, FileManager 1055->36, AdminPage 1525->167, BudgetPanel 1266->146, JourneyDetailPage 2822->547, PlacesSidebar 945->66, CollabChat 861->106, CollabNotes 1417->532. DayPlanSidebar's drag-and-drop render body was left intact (ref-identity sensitive) and only its toolbar/modals/constants were extracted.
74 lines
2.9 KiB
TypeScript
74 lines
2.9 KiB
TypeScript
import { currencyDecimals } from '../../utils/formatters'
|
|
import { SYMBOLS, SPLIT_COLORS } from './BudgetPanel.constants'
|
|
|
|
export function widgetTheme(dark: boolean) {
|
|
if (dark) return {
|
|
bg: 'linear-gradient(180deg, #17171d 0%, #0d0d12 100%)',
|
|
border: 'rgba(255,255,255,0.07)',
|
|
text: '#ffffff',
|
|
sub: 'rgba(255,255,255,0.6)',
|
|
faint: 'rgba(255,255,255,0.4)',
|
|
track: 'rgba(255,255,255,0.04)',
|
|
divider: 'rgba(255,255,255,0.07)',
|
|
iconBg: 'rgba(255,255,255,0.08)',
|
|
iconBorder: 'rgba(255,255,255,0.12)',
|
|
iconColor: 'rgba(255,255,255,0.9)',
|
|
centerBg: '#17171d',
|
|
flowBg: 'rgba(255,255,255,0.05)',
|
|
flowBorder: 'rgba(255,255,255,0.07)',
|
|
flowHoverBg: 'rgba(255,255,255,0.08)',
|
|
flowHoverBorder: 'rgba(255,255,255,0.12)',
|
|
rowHover: 'rgba(255,255,255,0.03)',
|
|
shadow: '0 20px 50px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.04)',
|
|
donutShadow: 'drop-shadow(0 0 20px rgba(0,0,0,0.3))',
|
|
}
|
|
return {
|
|
bg: 'linear-gradient(180deg, #ffffff 0%, #f9fafb 100%)',
|
|
border: 'rgba(15,23,42,0.08)',
|
|
text: '#111827',
|
|
sub: 'rgba(17,24,39,0.6)',
|
|
faint: 'rgba(17,24,39,0.4)',
|
|
track: 'rgba(15,23,42,0.05)',
|
|
divider: 'rgba(15,23,42,0.08)',
|
|
iconBg: 'rgba(15,23,42,0.05)',
|
|
iconBorder: 'rgba(15,23,42,0.1)',
|
|
iconColor: 'rgba(17,24,39,0.75)',
|
|
centerBg: '#ffffff',
|
|
flowBg: 'rgba(15,23,42,0.03)',
|
|
flowBorder: 'rgba(15,23,42,0.08)',
|
|
flowHoverBg: 'rgba(15,23,42,0.06)',
|
|
flowHoverBorder: 'rgba(15,23,42,0.14)',
|
|
rowHover: 'rgba(15,23,42,0.04)',
|
|
shadow: '0 12px 32px rgba(15,23,42,0.08), 0 2px 6px rgba(0,0,0,0.04)',
|
|
donutShadow: 'drop-shadow(0 4px 18px rgba(15,23,42,0.12))',
|
|
}
|
|
}
|
|
|
|
export function hexLighten(hex: string, amount: number): string {
|
|
const m = hex.replace('#', '').match(/.{2}/g)
|
|
if (!m || m.length !== 3) return hex
|
|
const mix = (c: number) => Math.min(255, Math.round(c + (255 - c) * amount))
|
|
const [r, g, b] = m.map(x => parseInt(x, 16))
|
|
return `#${[mix(r), mix(g), mix(b)].map(v => v.toString(16).padStart(2, '0')).join('')}`
|
|
}
|
|
|
|
export const fmtNum = (v: number | null | undefined, locale: string, cur: string) => {
|
|
if (v == null || isNaN(v)) return '-'
|
|
const d = currencyDecimals(cur)
|
|
return Number(v).toLocaleString(locale, { minimumFractionDigits: d, maximumFractionDigits: d }) + ' ' + (SYMBOLS[cur] || cur)
|
|
}
|
|
|
|
type NumOrNull = number | null | undefined
|
|
|
|
export const calcPP = (p: NumOrNull, n: NumOrNull) => (n! > 0 ? (p as number) / (n as number) : null)
|
|
export const calcPD = (p: NumOrNull, d: NumOrNull) => (d! > 0 ? (p as number) / (d as number) : null)
|
|
export const calcPPD = (p: NumOrNull, n: NumOrNull, d: NumOrNull) => (n! > 0 && d! > 0 ? (p as number) / ((n as number) * (d as number)) : null)
|
|
|
|
export function splitColorFor(userId: number, order: number) {
|
|
return SPLIT_COLORS[order % SPLIT_COLORS.length]
|
|
}
|
|
|
|
export function colorForUserId(userId: number) {
|
|
return SPLIT_COLORS[((userId | 0) - 1 + SPLIT_COLORS.length * 1000) % SPLIT_COLORS.length]
|
|
}
|