Skip to content

Commit b82bc5f

Browse files
committed
feat: show airfoil name in coefficients HUD with collapsible toggle
Made-with: Cursor
1 parent 1aed382 commit b82bc5f

1 file changed

Lines changed: 61 additions & 17 deletions

File tree

flexfoil-ui/src/components/AirfoilCanvas.tsx

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ export function AirfoilCanvas() {
629629

630630
// State from store (use shallow equality to prevent unnecessary re-renders)
631631
const {
632+
name: airfoilName,
632633
coordinates,
633634
panels,
634635
controlMode,
@@ -651,6 +652,7 @@ export function AirfoilCanvas() {
651652
inverseDesignResultCoords,
652653
} = useAirfoilStore(
653654
useShallow((state) => ({
655+
name: state.name,
654656
coordinates: state.coordinates,
655657
panels: state.panels,
656658
controlMode: state.controlMode,
@@ -813,6 +815,9 @@ export function AirfoilCanvas() {
813815
}>({ cp: [], cpX: [], cl: 0, cd: 0, cm: 0 });
814816

815817
// Stable viewport for adaptive streamlines - only updates after zooming settles
818+
// HUD collapse state
819+
const [hudCollapsed, setHudCollapsed] = useState(false);
820+
816821
// This prevents expensive streamline recalculation on every scroll tick
817822
const lastZoomRef = useRef(viewport.zoom);
818823
const [stableViewport, setStableViewport] = useState(viewport);
@@ -3417,35 +3422,74 @@ export function AirfoilCanvas() {
34173422
top: '12px',
34183423
left: '12px',
34193424
zIndex: 10,
3420-
pointerEvents: 'none',
3425+
pointerEvents: 'auto',
34213426
background: 'var(--bg-secondary, rgba(15,20,35,0.88))',
34223427
backdropFilter: 'blur(10px)',
3423-
padding: '8px 12px',
34243428
borderRadius: '6px',
34253429
border: '1px solid var(--border-color, rgba(255,255,255,0.08))',
34263430
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
34273431
fontSize: '11px',
34283432
lineHeight: '1.7',
34293433
color: 'var(--text-primary, #edf2ff)',
34303434
minWidth: '120px',
3435+
overflow: 'hidden',
34313436
}}
34323437
>
3433-
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3434-
<span style={{ opacity: 0.5 }}>α</span>
3435-
<span>{displayAlpha.toFixed(2)}°</span>
3436-
</div>
3437-
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3438-
<span style={{ opacity: 0.5 }}>C<sub>L</sub></span>
3439-
<span style={{ color: 'var(--accent-primary, #61dafb)' }}>{morphState.cl.toFixed(4)}</span>
3440-
</div>
3441-
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3442-
<span style={{ opacity: 0.5 }}>C<sub>D</sub></span>
3443-
<span style={{ color: 'var(--accent-secondary, #f472b6)' }}>{morphState.cd.toFixed(5)}</span>
3444-
</div>
3445-
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3446-
<span style={{ opacity: 0.5 }}>C<sub>M</sub></span>
3447-
<span>{morphState.cm.toFixed(4)}</span>
3438+
<div
3439+
onClick={() => setHudCollapsed((c) => !c)}
3440+
style={{
3441+
display: 'flex',
3442+
alignItems: 'center',
3443+
gap: '6px',
3444+
padding: '6px 12px',
3445+
cursor: 'pointer',
3446+
userSelect: 'none',
3447+
borderBottom: hudCollapsed ? 'none' : '1px solid var(--border-color, rgba(255,255,255,0.08))',
3448+
}}
3449+
>
3450+
<svg
3451+
width="8" height="8" viewBox="0 0 8 8"
3452+
style={{
3453+
transform: hudCollapsed ? 'rotate(-90deg)' : 'rotate(0deg)',
3454+
transition: 'transform 0.15s ease',
3455+
opacity: 0.4,
3456+
flexShrink: 0,
3457+
}}
3458+
>
3459+
<path d="M1 2.5L4 5.5L7 2.5" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round" />
3460+
</svg>
3461+
<span style={{
3462+
fontSize: '10px',
3463+
fontWeight: 600,
3464+
letterSpacing: '0.04em',
3465+
opacity: 0.7,
3466+
overflow: 'hidden',
3467+
textOverflow: 'ellipsis',
3468+
whiteSpace: 'nowrap',
3469+
}}>
3470+
{airfoilName}
3471+
</span>
34483472
</div>
3473+
{!hudCollapsed && (
3474+
<div style={{ padding: '4px 12px 8px' }}>
3475+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3476+
<span style={{ opacity: 0.5 }}>α</span>
3477+
<span>{displayAlpha.toFixed(2)}°</span>
3478+
</div>
3479+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3480+
<span style={{ opacity: 0.5 }}>C<sub>L</sub></span>
3481+
<span style={{ color: 'var(--accent-primary, #61dafb)' }}>{morphState.cl.toFixed(4)}</span>
3482+
</div>
3483+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3484+
<span style={{ opacity: 0.5 }}>C<sub>D</sub></span>
3485+
<span style={{ color: 'var(--accent-secondary, #f472b6)' }}>{morphState.cd.toFixed(5)}</span>
3486+
</div>
3487+
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '12px' }}>
3488+
<span style={{ opacity: 0.5 }}>C<sub>M</sub></span>
3489+
<span>{morphState.cm.toFixed(4)}</span>
3490+
</div>
3491+
</div>
3492+
)}
34493493
</div>
34503494
{/* Overlay controls - simplified, full controls in Visualization panel */}
34513495
<div

0 commit comments

Comments
 (0)