- 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.
import { LABELS, MEMBERS, LABEL_STYLE } from "../data";
import type { Member } from "../types";
import { Avatar } from "./Avatar";
import { IconClose, IconSearch } from "../icons";
export interface FilterState {
assignees: string[];
labels: string[];
query: string;
}
interface FilterBarProps {
filters: FilterState;
activeCount: number;
shown: number;
total: number;
onToggleAssignee: (id: string) => void;
onToggleLabel: (id: string) => void;
onQuery: (q: string) => void;
onClear: () => void;
}
export function FilterBar(props: FilterBarProps) {
const { filters, activeCount, shown, total, onToggleAssignee, onToggleLabel, onQuery, onClear } = props;
const firstName = (m: Member) => m.name.split(" ")[0];
return (
<div className="filterbar">
<div className="filterbar__search">
<span className="filterbar__search-icon" aria-hidden="true">
<IconSearch />
</span>
<input
type="search"
className="search-input"
placeholder="Search titles and descriptions"
aria-label="Search card titles and descriptions"
value={filters.query}
onChange={(e) => onQuery(e.target.value)}
/>
{filters.query !== "" && (
<button
type="button"
className="search-clear"
aria-label="Clear search"
onClick={() => onQuery("")}
>
<IconClose width={13} height={13} />
</button>
)}
</div>
<div className="filterbar__groups">
<div className="chip-group" role="group" aria-label="Filter by assignee">
<span className="chip-group__label">Assignee</span>
{MEMBERS.map((m) => {
const active = filters.assignees.includes(m.id);
return (
<button
key={m.id}
type="button"
className="chip"
aria-pressed={active}
onClick={() => onToggleAssignee(m.id)}
>
<Avatar member={m} size={17} />
<span>{firstName(m)}</span>
</button>
);
})}
</div>
<div className="chip-group" role="group" aria-label="Filter by label">
<span className="chip-group__label">Label</span>
{LABELS.map((l) => {
const active = filters.labels.includes(l.id);
const style = LABEL_STYLE[l.id];
return (
<button
key={l.id}
type="button"
className="chip"
aria-pressed={active}
onClick={() => onToggleLabel(l.id)}
>
<span className="chip__dot" style={{ background: style?.fg }} aria-hidden="true" />
<span>{l.name}</span>
</button>
);
})}
</div>
</div>
<div className="filterbar__end">
{activeCount > 0 ? (
<>
<span className="filterbar__count" aria-live="off">
{shown} of {total} cards
</span>
<button type="button" className="btn btn--ghost btn--sm" onClick={onClear}>
Clear filters
</button>
</>
) : null}
</div>
</div>
);
}Source is browser-viewable only. There is no download or archive endpoint, and no additional license is granted beyond inspection and research.