139 lines
5.2 KiB
TypeScript
139 lines
5.2 KiB
TypeScript
// These exports are folds `IconSrc` callbacks — `(filled?: boolean) =>
|
||
// JSX.Element` — that the folds `<Icon>` component invokes as `src(filled)`
|
||
// to populate the inner SVG content. They are NOT React components (they
|
||
// are never mounted via JSX as `<CallMicIcon />`), so the
|
||
// `react/function-component-definition` rule's "use a function
|
||
// declaration" guidance is misapplied here.
|
||
/* eslint-disable react/function-component-definition */
|
||
|
||
// Custom call-control icon set, drawn to match the design-system style
|
||
// captured in `docs/design/new-direct-messages-design/project/shared.jsx`
|
||
// (lines 4-19): 24×24 viewBox, stroke-only (no fill), 1.6px stroke weight
|
||
// for handset/mic/video glyphs, round line joins/caps, currentColor — so
|
||
// the same icons read consistently across the green/red/neutral variant
|
||
// flips of the IncomingCallStrip / CallControl buttons.
|
||
//
|
||
// Folds' `Icon` component owns the outer `<svg>` (viewBox=0 0 24 24,
|
||
// fill=none, sizing class via the `size` prop). An `IconSrc` therefore
|
||
// returns only the inner shapes — same convention as the stock
|
||
// `Icons.*` table (see folds/dist/index.js Icons block).
|
||
//
|
||
// `filled` is intentionally ignored: this is an outline icon family,
|
||
// the muted/active distinction is carried by the diagonal slash plus
|
||
// the button's variant color, not by an alternate filled shape.
|
||
|
||
import React from 'react';
|
||
import { IconSrc } from 'folds';
|
||
|
||
const STROKE = {
|
||
stroke: 'currentColor',
|
||
strokeWidth: 1.6,
|
||
strokeLinecap: 'round' as const,
|
||
strokeLinejoin: 'round' as const,
|
||
fill: 'none',
|
||
};
|
||
|
||
// Slightly heavier than the body strokes so the «muted» indicator
|
||
// reads as a deliberate cancellation rather than ornamentation.
|
||
const SLASH = {
|
||
...STROKE,
|
||
strokeWidth: 2,
|
||
};
|
||
|
||
export const CallMicIcon: IconSrc = () => (
|
||
<>
|
||
<rect x="9" y="3" width="6" height="12" rx="3" {...STROKE} />
|
||
<path d="M5 11a7 7 0 0 0 14 0" {...STROKE} />
|
||
<path d="M12 18v3" {...STROKE} />
|
||
</>
|
||
);
|
||
|
||
export const CallMicMuteIcon: IconSrc = () => (
|
||
<>
|
||
<rect x="9" y="3" width="6" height="12" rx="3" {...STROKE} />
|
||
<path d="M5 11a7 7 0 0 0 14 0" {...STROKE} />
|
||
<path d="M12 18v3" {...STROKE} />
|
||
<path d="M3 3l18 18" {...SLASH} />
|
||
</>
|
||
);
|
||
|
||
// Loudspeaker «on» — cone + two sound waves. Paired with the variant
|
||
// flip (Success when active) so «громкая связь» reads at a glance.
|
||
export const CallSpeakerIcon: IconSrc = () => (
|
||
<>
|
||
<path d="M4 9h3l5-4v14l-5-4H4z" {...STROKE} />
|
||
<path d="M16 9a4 4 0 0 1 0 6" {...STROKE} />
|
||
<path d="M18.5 6.5a8 8 0 0 1 0 11" {...STROKE} />
|
||
</>
|
||
);
|
||
|
||
// Speaker «off» (earpiece) — the same cone with the sound waves dropped,
|
||
// not a slash: audio still plays, just through the earpiece. The neutral
|
||
// Surface variant carries the «inactive» cue.
|
||
export const CallSpeakerMuteIcon: IconSrc = () => <path d="M4 9h3l5-4v14l-5-4H4z" {...STROKE} />;
|
||
|
||
export const CallVideoIcon: IconSrc = () => (
|
||
<>
|
||
<rect x="3" y="6" width="13" height="12" rx="2" {...STROKE} />
|
||
<path d="M16 10l5-3v10l-5-3" {...STROKE} />
|
||
</>
|
||
);
|
||
|
||
export const CallVideoMuteIcon: IconSrc = () => (
|
||
<>
|
||
<rect x="3" y="6" width="13" height="12" rx="2" {...STROKE} />
|
||
<path d="M16 10l5-3v10l-5-3" {...STROKE} />
|
||
<path d="M3 3l18 18" {...SLASH} />
|
||
</>
|
||
);
|
||
|
||
export const CallScreenShareIcon: IconSrc = () => (
|
||
<>
|
||
<rect x="3" y="4" width="18" height="13" rx="2" {...STROKE} />
|
||
<path d="M9 21h6M12 17v4" {...STROKE} />
|
||
<path d="M8.5 11l3.5-3.5L15.5 11" {...STROKE} />
|
||
<path d="M12 7.5V14" {...STROKE} />
|
||
</>
|
||
);
|
||
|
||
// Screenshare-off carries the same slash convention as the other muted
|
||
// glyphs so the on/off state has both a shape cue and a variant cue —
|
||
// matters for high-contrast / monochrome modes where the
|
||
// Success-vs-Surface variant flip alone is too subtle.
|
||
export const CallScreenShareMuteIcon: IconSrc = () => (
|
||
<>
|
||
<rect x="3" y="4" width="18" height="13" rx="2" {...STROKE} />
|
||
<path d="M9 21h6M12 17v4" {...STROKE} />
|
||
<path d="M8.5 11l3.5-3.5L15.5 11" {...STROKE} />
|
||
<path d="M12 7.5V14" {...STROKE} />
|
||
<path d="M3 3l18 18" {...SLASH} />
|
||
</>
|
||
);
|
||
|
||
// Classic «pick up» handset, used on the IncomingCallStrip Answer
|
||
// button. Kept upright (no rotation) so it reads as «receive call».
|
||
export const CallPhoneIcon: IconSrc = () => (
|
||
<path
|
||
d="M5 4h4l2 5-3 2a12 12 0 0 0 6 6l2-3 5 2v4a2 2 0 0 1-2 2A17 17 0 0 1 3 6a2 2 0 0 1 2-2z"
|
||
{...STROKE}
|
||
/>
|
||
);
|
||
|
||
// Same handset rotated 135° — universal «hang up / decline» glyph
|
||
// (handset tilted off the cradle). Reused for Decline (IncomingCallStrip)
|
||
// and Hangup (CallControl).
|
||
//
|
||
// The source handset fills a ~18×18 box whose centre sits at (12, 13), not
|
||
// (12, 12). Rotating it 135° about (12, 12) therefore (a) drifts the glyph
|
||
// off-centre and (b) pushes the rotated box (~25px diagonal) past the 24×24
|
||
// viewBox, so the corners clip. Fix: recentre the box on the viewBox centre,
|
||
// rotate, then scale to 0.82 so the rotated glyph fits with stroke margin.
|
||
// (SVG applies the transform list right-to-left.)
|
||
export const CallPhoneDownIcon: IconSrc = () => (
|
||
<g transform="translate(12 12) rotate(135) scale(0.82) translate(-12 -13)">
|
||
<path
|
||
d="M5 4h4l2 5-3 2a12 12 0 0 0 6 6l2-3 5 2v4a2 2 0 0 1-2 2A17 17 0 0 1 3 6a2 2 0 0 1 2-2z"
|
||
{...STROKE}
|
||
/>
|
||
</g>
|
||
);
|