// hod-components.jsx — HUD/dashboard components za Autoškolu HOD // ═══════════════════════════════════════════════════════════════ // BRZINOMJER (Speedometer / RPM gauge) // ═══════════════════════════════════════════════════════════════ function HodGauge({ value = 0.72, label = "SIMPATIKUS", sublabel = "krvni tlak / disanje / kortizol", accent = "var(--hod-accent-hot)", size = 320 }) { // gauge od -135° do +135° (270° ukupno) const startAngle = -225; const endAngle = 45; const totalArc = 270; const cx = size / 2; const cy = size / 2; const r = size / 2 - 24; const polar = (deg, radius) => { const rad = (deg * Math.PI) / 180; return [cx + Math.cos(rad) * radius, cy + Math.sin(rad) * radius]; }; // generate tick marks every 10% const ticks = []; for (let i = 0; i <= 10; i++) { const t = i / 10; const angle = startAngle + totalArc * t; const major = i % 2 === 0; const [x1, y1] = polar(angle, r); const [x2, y2] = polar(angle, r - (major ? 14 : 8)); ticks.push({ x1, y1, x2, y2, major, label: i * 10 }); } const valueAngle = startAngle + totalArc * value; const [nx, ny] = polar(valueAngle, r - 20); // arc path const [ax1, ay1] = polar(startAngle, r); const [ax2, ay2] = polar(valueAngle, r); const largeArc = totalArc * value > 180 ? 1 : 0; const arcPath = `M ${ax1} ${ay1} A ${r} ${r} 0 ${largeArc} 1 ${ax2} ${ay2}`; const [bgx1, bgy1] = polar(startAngle, r); const [bgx2, bgy2] = polar(endAngle, r); const bgPath = `M ${bgx1} ${bgy1} A ${r} ${r} 0 1 1 ${bgx2} ${bgy2}`; return ( {/* outer ring */} {/* background arc */} {/* value arc */} {/* ticks */} {ticks.map((t, i) => ( {t.major && (() => { const angle = startAngle + totalArc * (t.label / 100); const [lx, ly] = polar(angle, r - 30); return ( {t.label} ); })()} ))} {/* needle */} {/* center label */} {label} {sublabel} {/* value readout */} {Math.round(value * 100)} % ); } // ═══════════════════════════════════════════════════════════════ // HUD CARD — framed dashboard widget // ═══════════════════════════════════════════════════════════════ function HudCard({ label, code, children, accent, style = {} }) { return (
{label} {code && {code}}
{children}
); } // ═══════════════════════════════════════════════════════════════ // ROAD SIGN — prometni znak (diamond / circle / triangle) // ═══════════════════════════════════════════════════════════════ function RoadSign({ shape = "diamond", color = "var(--hod-accent-hot)", children, small = false }) { const size = small ? 64 : 92; const inner = (
{children}
); if (shape === "diamond") { return (
{children}
); } if (shape === "circle") { return (
{children}
); } if (shape === "triangle") { return (
{children}
); } return inner; } // ═══════════════════════════════════════════════════════════════ // TICK BAR — horizontal scale with reading // ═══════════════════════════════════════════════════════════════ function TickBar({ value = 0.5, label, unit = "", accent = "var(--hod-accent-hot)", steps = 20 }) { return (
{label &&
{label}{Math.round(value * 100)}{unit}
}
{Array.from({ length: steps }).map((_, i) => { const active = i / steps < value; return ( ); })}
); } // ═══════════════════════════════════════════════════════════════ // CROSSHAIR — corner markers for "instrument panel" sections // ═══════════════════════════════════════════════════════════════ function Crosshair({ children, label, code, onHover }) { return (
{(label || code) && (
{label && {label}} {code && {code}}
)}
{children}
); } // ═══════════════════════════════════════════════════════════════ // EYEBROW / LABEL // ═══════════════════════════════════════════════════════════════ function Eyebrow({ children, code, accent }) { return (
{code && {code}} {children}
); } Object.assign(window, { HodGauge, HudCard, RoadSign, TickBar, Crosshair, Eyebrow });