8ae447e08d
Replace the labelled availability/metadata badges in track rows with small icon+tooltip indicators (cloud/hard-drives/warning/etc, derived from TrackAvailability and MetadataStatus). Add a `connection` slice fed by a single status poller (Sidebar) so other components can cheaply check backend reachability. TrackRow uses this plus the offline audio cache to show "Local" instead of a stale "On server" when the backend is down but the track is already cached.
105 lines
2.4 KiB
TypeScript
105 lines
2.4 KiB
TypeScript
/*
|
|
* Thin wrapper over @phosphor-icons/react so app code can reference icons by
|
|
* the kebab names used in the design reference (`<Icon name="vinyl-record" />`)
|
|
* instead of importing each component. modern-sk is intentionally icon-agnostic
|
|
* (its SearchField/MenuItem/Callout take an `icon` ReactNode), so the icon set
|
|
* is the app's concern.
|
|
*
|
|
* The rendered <svg> carries className "ph" and sizes to 1em, so the shell CSS
|
|
* controls size/colour via font-size + currentColor, exactly like the reference.
|
|
*/
|
|
// TODO: remove this component, use phosphor's icons project-wide
|
|
import type { CSSProperties } from 'react';
|
|
import {
|
|
ArrowCircleDown,
|
|
ArrowsClockwise,
|
|
CheckCircle,
|
|
Cloud,
|
|
CloudSlash,
|
|
DotsSixVertical,
|
|
GearSix,
|
|
HardDrives,
|
|
Heart,
|
|
Info,
|
|
MagnifyingGlass,
|
|
Pause,
|
|
Play,
|
|
Playlist,
|
|
Plus,
|
|
PushPin,
|
|
Queue,
|
|
Radio,
|
|
Repeat,
|
|
ShieldCheck,
|
|
Shuffle,
|
|
SignOut,
|
|
SkipBack,
|
|
SkipForward,
|
|
Sparkle,
|
|
SpeakerHigh,
|
|
SpeakerSimpleX,
|
|
ThumbsDown,
|
|
Trash,
|
|
UploadSimple,
|
|
VinylRecord,
|
|
WarningCircle,
|
|
X,
|
|
type IconProps,
|
|
} from '@phosphor-icons/react';
|
|
|
|
const ICONS = {
|
|
'vinyl-record': VinylRecord,
|
|
'magnifying-glass': MagnifyingGlass,
|
|
'arrow-circle-down': ArrowCircleDown,
|
|
'upload-simple': UploadSimple,
|
|
'hard-drives': HardDrives,
|
|
'push-pin': PushPin,
|
|
playlist: Playlist,
|
|
plus: Plus,
|
|
'shield-check': ShieldCheck,
|
|
'gear-six': GearSix,
|
|
queue: Queue,
|
|
trash: Trash,
|
|
x: X,
|
|
radio: Radio,
|
|
sparkle: Sparkle,
|
|
'dots-six-vertical': DotsSixVertical,
|
|
shuffle: Shuffle,
|
|
'skip-back': SkipBack,
|
|
play: Play,
|
|
pause: Pause,
|
|
'skip-forward': SkipForward,
|
|
repeat: Repeat,
|
|
heart: Heart,
|
|
info: Info,
|
|
'thumbs-down': ThumbsDown,
|
|
'speaker-high': SpeakerHigh,
|
|
'speaker-x': SpeakerSimpleX,
|
|
cloud: Cloud,
|
|
'cloud-slash': CloudSlash,
|
|
'check-circle': CheckCircle,
|
|
'warning-circle': WarningCircle,
|
|
'sign-out': SignOut,
|
|
'arrows-clockwise': ArrowsClockwise,
|
|
} satisfies Record<string, React.ComponentType<IconProps>>;
|
|
|
|
export type IconName = keyof typeof ICONS;
|
|
|
|
interface Props {
|
|
name: IconName;
|
|
fill?: boolean;
|
|
style?: CSSProperties;
|
|
className?: string;
|
|
}
|
|
|
|
export function Icon({ name, fill, style, className }: Props) {
|
|
const Cmp = ICONS[name];
|
|
return (
|
|
<Cmp
|
|
weight={fill ? 'fill' : 'regular'}
|
|
className={className ? `ph ${className}` : 'ph'}
|
|
style={{ flexShrink: 0, ...style }}
|
|
/>
|
|
);
|
|
}
|