- Run record
- loading
Loading this Run…
Loading the Revisions of this Run…
A published source file of Revision 0 of Boardly — Website Relaunch 1.1.0, shown as text in the browser.
Source is browser-viewable only. There is no download or archive endpoint, and no additional license is granted beyond inspection and research.
import type { ReactNode } from "react";
import { MEMBER_COLORS, initials, type Member } from "../model";
type IconProps = { size?: number; className?: string };
function Icon({ size = 16, className, children }: IconProps & { children: ReactNode }) {
return (
<svg
className={className}
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={1.9}
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
focusable="false"
>
{children}
</svg>
);
}
export function IconSearch(p: IconProps) {
return (
<Icon {...p}>
<circle cx="11" cy="11" r="7" />
<path d="m16.6 16.6 4.2 4.2" />
</Icon>
);
}
export function IconCalendar(p: IconProps) {
return (
<Icon {...p}>
<rect x="3.5" y="5" width="17" height="16" rx="2.5" />
<path d="M3.5 10h17M8 3v4M16 3v4" />
</Icon>
);
}
export function IconCheckSquare(p: IconProps) {
return (
<Icon {...p}>
<path d="m9 11.5 2.7 2.7 5.8-6.4" />
<path d="M21 12.5V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" />
</Icon>
);
}
export function IconFlag(p: IconProps) {
return (
<Icon {...p}>
<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V4s-1 1-4 1-5-2-8-2-4 1-4 1z" />
<path d="M4 22v-7" />
</Icon>
);
}
export function IconMove(p: IconProps) {
return (
<Icon {...p}>
<path d="M12 2v20M2 12h20" />
<path d="m5 9-3 3 3 3" />
<path d="m9 5 3-3 3 3" />
<path d="m15 19-3 3-3-3" />
<path d="m19 9 3 3-3 3" />
</Icon>
);
}
export function IconPlus(p: IconProps) {
return (
<Icon {...p}>
<path d="M12 5v14M5 12h14" />
</Icon>
);
}
export function IconClose(p: IconProps) {
return (
<Icon {...p}>
<path d="M6 6l12 12M18 6 6 18" />
</Icon>
);
}
export function IconUndo(p: IconProps) {
return (
<Icon {...p}>
<path d="M9 14 4 9l5-5" />
<path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11" />
</Icon>
);
}
export function IconRefresh(p: IconProps) {
return (
<Icon {...p}>
<path d="M3 12a9 9 0 1 0 3-6.7L3 8" />
<path d="M3 3v5h5" />
</Icon>
);
}
export function IconTrash(p: IconProps) {
return (
<Icon {...p}>
<path d="M3 6h18" />
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" />
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
<path d="M10 11v6M14 11v6" />
</Icon>
);
}
export function IconAlert(p: IconProps) {
return (
<Icon {...p}>
<path d="m10.3 3.9-8 13.4A2 2 0 0 0 4 20.5h16a2 2 0 0 0 1.7-3.2l-8-13.4a2 2 0 0 0-3.4 0Z" />
<path d="M12 9.5v4" />
<path d="M12 17h.01" />
</Icon>
);
}
export function IconPerson(p: IconProps) {
return (
<Icon {...p}>
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</Icon>
);
}
export function Logo({ size = 26 }: { size?: number }) {
return (
<svg width={size} height={size} viewBox="0 0 32 32" aria-hidden="true" focusable="false">
<rect x="1" y="1" width="30" height="30" rx="8.5" fill="#2C6E63" />
<rect x="7" y="17.5" width="5" height="7.5" rx="1.7" fill="#9FCEC0" />
<rect x="13.5" y="11.5" width="5" height="13.5" rx="1.7" fill="#F1F8F4" />
<rect x="20" y="7" width="5" height="18" rx="1.7" fill="#9FCEC0" />
</svg>
);
}
export function Avatar({ member, size = 22 }: { member?: Member; size?: number }) {
if (!member) {
return (
<span className="avatar avatar-none" style={{ width: size, height: size }} role="img" aria-label="Unassigned">
<IconPerson size={Math.max(10, size - 9)} />
</span>
);
}
const bg = MEMBER_COLORS[member.id] ?? "#5C6B72";
return (
<span
className="avatar"
style={{ width: size, height: size, background: bg, fontSize: Math.max(8, size * 0.42) }}
role="img"
aria-label={member.name}
title={`${member.name} · ${member.role}`}
>
{initials(member.name)}
</span>
);
}