Files
embycovers/frontend/src/components/icons.tsx
T
2026-06-08 21:58:16 +12:00

192 lines
6.5 KiB
TypeScript

// Minimal feather-style icon set (stroke=currentColor) used across the app.
// A default 18px size keeps every icon consistent even where no CSS rule scopes
// it (e.g. category headers); callers can still override via CSS or the size prop.
type P = { className?: string };
const base = {
fill: "none",
stroke: "currentColor",
strokeWidth: 2,
strokeLinecap: "round" as const,
strokeLinejoin: "round" as const,
viewBox: "0 0 24 24",
width: 18,
height: 18,
};
export const IconImage = (p: P) => (
<svg {...base} {...p}>
<rect x="3" y="3" width="18" height="18" rx="2" />
<circle cx="8.5" cy="8.5" r="1.5" />
<path d="M21 15l-5-5L5 21" />
</svg>
);
export const IconLayers = (p: P) => (
<svg {...base} {...p}>
<path d="M12 2l9 5-9 5-9-5 9-5z" />
<path d="M3 12l9 5 9-5M3 17l9 5 9-5" />
</svg>
);
export const IconCalendar = (p: P) => (
<svg {...base} {...p}>
<rect x="3" y="4" width="18" height="18" rx="2" />
<path d="M16 2v4M8 2v4M3 10h18" />
</svg>
);
export const IconGrid = (p: P) => (
<svg {...base} {...p}>
<rect x="3" y="3" width="7" height="7" rx="1" />
<rect x="14" y="3" width="7" height="7" rx="1" />
<rect x="14" y="14" width="7" height="7" rx="1" />
<rect x="3" y="14" width="7" height="7" rx="1" />
</svg>
);
export const IconHeart = (p: P) => (
<svg {...base} {...p}>
<path d="M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1-1.1a5.5 5.5 0 0 0-7.8 7.8l1 1L12 21l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8z" />
</svg>
);
export const IconMusic = (p: P) => (
<svg {...base} {...p}>
<path d="M9 18V5l12-2v13" />
<circle cx="6" cy="18" r="3" />
<circle cx="18" cy="16" r="3" />
</svg>
);
export const IconDisc = (p: P) => (
<svg {...base} {...p}>
<circle cx="12" cy="12" r="10" />
<circle cx="12" cy="12" r="3" />
</svg>
);
export const IconWand = (p: P) => (
<svg {...base} {...p}>
<path d="M15 4V2M15 16v-2M8 9h2M20 9h2M17.8 11.8L19 13M15 9l-7 7-4 4" />
<path d="M17.8 6.2L19 5" />
</svg>
);
export const IconSearch = (p: P) => (
<svg {...base} {...p}>
<circle cx="11" cy="11" r="8" />
<path d="M21 21l-4.3-4.3" />
</svg>
);
export const IconHome = (p: P) => (
<svg {...base} {...p}>
<path d="M3 9.5L12 3l9 6.5V20a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1z" />
</svg>
);
export const IconServer = (p: P) => (
<svg {...base} {...p}>
<rect x="3" y="3" width="18" height="7" rx="2" />
<rect x="3" y="14" width="18" height="7" rx="2" />
<path d="M7 6.5h.01M7 17.5h.01" />
</svg>
);
export const IconRefresh = (p: P) => (
<svg {...base} {...p}>
<path d="M21 12a9 9 0 1 1-3-6.7L21 8" />
<path d="M21 3v5h-5" />
</svg>
);
export const IconCheck = (p: P) => (
<svg {...base} {...p}>
<path d="M20 6L9 17l-5-5" />
</svg>
);
export const IconUpload = (p: P) => (
<svg {...base} {...p}>
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<path d="M17 8l-5-5-5 5M12 3v12" />
</svg>
);
export const IconTrash = (p: P) => (
<svg {...base} {...p}>
<path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
</svg>
);
export const IconPlay = (p: P) => (
<svg {...base} {...p}>
<path d="M6 4l14 8-14 8V4z" />
</svg>
);
export const IconUser = (p: P) => (
<svg {...base} {...p}>
<circle cx="12" cy="8" r="4" />
<path d="M4 21v-1a6 6 0 0 1 6-6h4a6 6 0 0 1 6 6v1" />
</svg>
);
export const IconApple = (p: P) => (
<svg {...base} {...p}>
<path d="M15.3 12.2c0-1.7 1.4-2.6 1.5-2.7-.8-1.2-2.1-1.4-2.6-1.4-1.1-.1-2.1.6-2.7.6-.6 0-1.4-.6-2.3-.6-1.2 0-2.3.7-2.9 1.7-1.3 2.2-.3 5.6.9 7.3.6.8 1.3 1.8 2.2 1.7.9 0 1.2-.6 2.3-.6 1 0 1.4.6 2.3.6 1 0 1.6-.8 2.2-1.7.7-1 1-2 1-2.1-.1 0-1.9-.7-1.9-2.8z" />
<path d="M13.7 6.8c.5-.6.9-1.5.8-2.3-.8 0-1.7.5-2.2 1.1-.5.6-.9 1.4-.8 2.2.9.1 1.7-.4 2.2-1z" />
</svg>
);
export const IconAndroid = (p: P) => (
<svg {...base} {...p}>
<path d="M8 9l-1.8-2.7M16 9l1.8-2.7M9 5.5l.2-.1a7 7 0 0 1 5.6 0l.2.1" />
<rect x="6" y="9" width="12" height="8" rx="2.5" />
<path d="M8.5 17v2.5M15.5 17v2.5M4.5 10.5V15M19.5 10.5V15" />
<path d="M10 12h.01M14 12h.01" />
</svg>
);
export const IconWeb = (p: P) => (
<svg {...base} {...p}>
<circle cx="12" cy="12" r="9" />
<path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" />
</svg>
);
export const IconChevron = (p: P) => (
<svg {...base} {...p}>
<path d="M9 18l6-6-6-6" />
</svg>
);
export const IconFolder = (p: P) => (
<svg {...base} {...p}>
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
</svg>
);
export const IconBook = (p: P) => (
<svg {...base} {...p}>
<path d="M4 4a2 2 0 0 1 2-2h13v18H6a2 2 0 0 0-2 2z" />
<path d="M4 20a2 2 0 0 0 2 2h13" />
<path d="M9 7h6" />
</svg>
);
export const IconHeadphones = (p: P) => (
<svg {...base} {...p}>
<path d="M4 14v-2a8 8 0 0 1 16 0v2" />
<rect x="2.5" y="14" width="4.5" height="6" rx="1.5" />
<rect x="17" y="14" width="4.5" height="6" rx="1.5" />
</svg>
);
export const IconClock = (p: P) => (
<svg {...base} {...p}>
<circle cx="12" cy="12" r="9" />
<path d="M12 7v5l3 2" />
</svg>
);
export const IconSettings = (p: P) => (
<svg {...base} {...p}>
<circle cx="12" cy="12" r="3" />
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
</svg>
);
export const IconMenu = (p: P) => (
<svg {...base} {...p}>
<path d="M4 7h16M4 12h16M4 17h16" />
</svg>
);
export const IconClose = (p: P) => (
<svg {...base} {...p}>
<path d="M6 6l12 12M18 6L6 18" />
</svg>
);
// Stylized Emby media mark (rounded square + play). Inherits currentColor so it
// tints with nav state; swap in the official asset if you have it.
export const IconEmby = (p: P) => (
<svg viewBox="0 0 24 24" fill="none" width={18} height={18} className={p.className}>
<rect x="3" y="3" width="18" height="18" rx="5.5" stroke="currentColor" strokeWidth={2} />
<path d="M10 8.3l5.4 3.7-5.4 3.7z" fill="currentColor" />
</svg>
);