Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions openless-all/app/src/components/Capsule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ interface AudioBarsProps {

function AudioBars({ level }: AudioBarsProps) {
const envelope = [0.55, 0.85, 1.0, 0.85, 0.55];
const base = 4;
const max = 18;
const base = 2;
const max = 24;
const voice = Math.min(1, Math.max(0, level));
const silenceGate = 0.012;
const responseCeiling = 0.34;
const gatedVoice = Math.min(1, Math.max(0, (voice - silenceGate) / (responseCeiling - silenceGate)));
const easedVoice = gatedVoice * gatedVoice * (3 - 2 * gatedVoice);
const visualVoice = Math.pow(easedVoice, 0.42);
return (
<div
style={{
Expand All @@ -35,10 +40,11 @@ function AudioBars({ level }: AudioBarsProps) {
style={{
display: 'inline-block',
width: 3,
height: base + (max - base) * voice * env,
height: base + (max - base) * visualVoice * env,
borderRadius: 999,
background: 'var(--ol-blue)',
opacity: 0.82,
transformOrigin: 'center',
transition: 'height 0.08s var(--ol-motion-quick)',
}}
/>
Expand Down Expand Up @@ -108,6 +114,8 @@ interface CircleButtonProps {
function CircleButton({ variant, enabled, onClick }: CircleButtonProps) {
const { t } = useTranslation();
const isCancel = variant === 'cancel';
const os = detectOS();
const useBackdrop = os !== 'win' && isCancel;
return (
<button
onClick={enabled ? onClick : undefined}
Expand All @@ -118,15 +126,16 @@ function CircleButton({ variant, enabled, onClick }: CircleButtonProps) {
height: 28,
borderRadius: 999,
background: isCancel ? 'rgba(255, 255, 255, 0.55)' : 'rgba(255, 255, 255, 0.92)',
backdropFilter: isCancel ? 'blur(12px) saturate(160%)' : 'none',
WebkitBackdropFilter: isCancel ? 'blur(12px) saturate(160%)' : 'none',
backdropFilter: useBackdrop ? 'blur(12px) saturate(160%)' : 'none',
WebkitBackdropFilter: useBackdrop ? 'blur(12px) saturate(160%)' : 'none',
color: 'var(--ol-ink)',
border: '0.8px solid rgba(0, 0, 0, 0.08)',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
cursor: enabled ? 'default' : 'not-allowed',
opacity: enabled ? 1 : 0.42,
visibility: 'visible',
flexShrink: 0,
padding: 0,
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.06)',
Expand Down Expand Up @@ -217,9 +226,7 @@ function Pill({ os, state, level, insertedChars, message, onCancel, onConfirm }:
const ambient = state === 'recording' ? Math.min(1, Math.max(0, level)) : 0;
const scale = os === 'win' ? 1 : 1 + ambient * 0.018;
const shadowAlpha = 0.20 + ambient * 0.10;
const dropShadow = os === 'win'
? `drop-shadow(0 12px 24px rgba(0, 0, 0, ${(0.15 + ambient * 0.06).toFixed(3)}))`
: 'none';
const useBackdrop = os !== 'win';

return (
<div
Expand All @@ -233,23 +240,22 @@ function Pill({ os, state, level, insertedChars, message, onCancel, onConfirm }:
height: metrics.height,
borderRadius: 999,
background: 'rgba(255, 255, 255, 0.62)',
backdropFilter: 'blur(28px) saturate(180%)',
WebkitBackdropFilter: 'blur(28px) saturate(180%)',
backdropFilter: useBackdrop ? 'blur(28px) saturate(180%)' : 'none',
WebkitBackdropFilter: useBackdrop ? 'blur(28px) saturate(180%)' : 'none',
border: '1px solid rgba(255, 255, 255, 0.55)',
boxShadow: os === 'win'
? '0 0 0 0.5px rgba(0, 0, 0, 0.08), inset 0 0.5px 0 rgba(255, 255, 255, 0.55)'
? `0 10px 24px -14px rgba(0, 0, 0, ${(0.24 + ambient * 0.06).toFixed(3)}), 0 0 0 0.5px rgba(0, 0, 0, 0.08), inset 0 0.5px 0 rgba(255, 255, 255, 0.55)`
: `0 18px 50px -10px rgba(0, 0, 0, ${shadowAlpha.toFixed(3)}), 0 0 0 0.5px rgba(0, 0, 0, 0.08), inset 0 0.5px 0 rgba(255, 255, 255, 0.55)`,
color: 'var(--ol-ink)',
fontFamily: 'var(--ol-font-sans)',
transform: `scale(${scale.toFixed(4)})`,
transformOrigin: 'center',
transition: 'transform 0.08s var(--ol-motion-quick), box-shadow 0.08s var(--ol-motion-quick)',
willChange: 'transform, box-shadow',
filter: dropShadow,
}}
>
<CircleButton variant="cancel" enabled={enabled} onClick={onCancel} />
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<div style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
{center}
</div>
<CircleButton variant="confirm" enabled={enabled} onClick={onConfirm} />
Expand Down
2 changes: 1 addition & 1 deletion openless-all/app/src/lib/capsuleLayout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function assertEqual<T>(actual: T, expected: T, name: string) {
const winMetrics = getCapsulePillMetrics('win');
assertEqual(winMetrics.width, 196, 'windows capsule widens pill');
assertEqual(winMetrics.height, 52, 'windows capsule increases pill height');
assertEqual(winMetrics.textWidth, 118, 'windows capsule widens text slot');
assertEqual(winMetrics.textWidth, 104, 'windows capsule keeps side controls clear');

const macMetrics = getCapsulePillMetrics('mac');
assertEqual(macMetrics.width, 176, 'mac capsule keeps existing pill width');
Expand Down
2 changes: 1 addition & 1 deletion openless-all/app/src/lib/capsuleLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface CapsuleMessageLayout {

export function getCapsulePillMetrics(os: OS): CapsulePillMetrics {
if (os === 'win') {
return { width: 196, height: 52, textWidth: 118 };
return { width: 196, height: 52, textWidth: 104 };
}

return { width: 176, height: 42, textWidth: 84 };
Expand Down
Loading