mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-04-24 15:08:44 -05:00
* Initial * Progress * Initial UI * Can submit request * Progress * Show text if no scrims * Can cancel request, tabs * Delete post * Popover if can't delete * Request rows * Progress * Scrim page initial * Fix migration order * Progress * Progress * Works again * Make it compile * Make it compile again * Work * Progress * Progress * Progress * Associations initial * Association visibility work * notFoundVisibility form fields initial * Progress * Association leave/join + reset invite code * Progress * Select test * Merge branch 'rewrite' into scrims * Remeda for groupBy * Select with search * Outline styling for select * Select done? * Fix prop names * Paginated badges * Less important * Select no results * Handle limiting select width * UserSearch non-working * Fix problem from merge * Remove UserSearch for now * Remove todo * Flaggable * Remove TODOs * i18n start + styling * Progress * i18n done * Add association e2e test * E2E tests * Done? * Couple leftovers
155 lines
3.4 KiB
TypeScript
155 lines
3.4 KiB
TypeScript
import { Tab } from "@headlessui/react";
|
|
import clsx from "clsx";
|
|
import * as React from "react";
|
|
|
|
interface NewTabsProps {
|
|
tabs: {
|
|
label: string;
|
|
number?: number;
|
|
icon?: React.ReactNode;
|
|
hidden?: boolean;
|
|
disabled?: boolean;
|
|
}[];
|
|
content: {
|
|
key: string;
|
|
element: React.ReactNode;
|
|
hidden?: boolean;
|
|
unmount?: boolean;
|
|
}[];
|
|
scrolling?: boolean;
|
|
selectedIndex?: number;
|
|
defaultIndex?: number;
|
|
setSelectedIndex?: (index: number) => void;
|
|
/** Don't take space when no tabs to show? */
|
|
disappearing?: boolean;
|
|
/** Show padding between tabs and content
|
|
* @default true
|
|
*/
|
|
padded?: boolean;
|
|
type?: "divider";
|
|
sticky?: boolean;
|
|
}
|
|
|
|
export function NewTabs(args: NewTabsProps) {
|
|
if (args.type === "divider") {
|
|
return <DividerTabs {...args} />;
|
|
}
|
|
|
|
const {
|
|
tabs,
|
|
content,
|
|
scrolling = true,
|
|
selectedIndex,
|
|
setSelectedIndex,
|
|
defaultIndex,
|
|
disappearing = false,
|
|
padded = true,
|
|
} = args;
|
|
|
|
const cantSwitchTabs = tabs.filter((t) => !t.hidden).length <= 1;
|
|
|
|
return (
|
|
<Tab.Group
|
|
selectedIndex={selectedIndex}
|
|
onChange={setSelectedIndex}
|
|
defaultIndex={defaultIndex}
|
|
>
|
|
<Tab.List
|
|
className={clsx("tab__buttons-container", {
|
|
"overflow-x-auto": scrolling,
|
|
invisible: cantSwitchTabs && !disappearing,
|
|
hidden: cantSwitchTabs && disappearing,
|
|
"tab__buttons-container__sticky": args.sticky,
|
|
})}
|
|
>
|
|
{tabs
|
|
.filter((t) => !t.hidden)
|
|
.map((tab) => {
|
|
return (
|
|
<Tab
|
|
key={tab.label}
|
|
className="button tab__button"
|
|
data-testid={`tab-${tab.label}`}
|
|
disabled={tab.disabled}
|
|
>
|
|
{tab.icon}
|
|
{tab.label}
|
|
{typeof tab.number === "number" && tab.number !== 0 && (
|
|
<span className="tab__number">{tab.number}</span>
|
|
)}
|
|
</Tab>
|
|
);
|
|
})}
|
|
</Tab.List>
|
|
<Tab.Panels
|
|
className={clsx({
|
|
"mt-4": padded && (!cantSwitchTabs || !disappearing),
|
|
})}
|
|
>
|
|
{content
|
|
.filter((c) => !c.hidden)
|
|
.map((c) => {
|
|
return (
|
|
<Tab.Panel key={c.key} unmount={c.unmount}>
|
|
{c.element}
|
|
</Tab.Panel>
|
|
);
|
|
})}
|
|
</Tab.Panels>
|
|
</Tab.Group>
|
|
);
|
|
}
|
|
|
|
function DividerTabs({
|
|
tabs,
|
|
content,
|
|
scrolling = true,
|
|
selectedIndex,
|
|
setSelectedIndex,
|
|
disappearing = false,
|
|
}: NewTabsProps) {
|
|
const cantSwitchTabs = tabs.filter((t) => !t.hidden).length <= 1;
|
|
|
|
return (
|
|
<Tab.Group selectedIndex={selectedIndex} onChange={setSelectedIndex}>
|
|
<Tab.List
|
|
className={clsx("divider-tab__buttons-container", {
|
|
"overflow-x-auto": scrolling,
|
|
invisible: cantSwitchTabs && !disappearing,
|
|
hidden: cantSwitchTabs && disappearing,
|
|
})}
|
|
>
|
|
{tabs
|
|
.filter((t) => !t.hidden)
|
|
.map((tab, i) => {
|
|
return (
|
|
<React.Fragment key={tab.label}>
|
|
<Tab
|
|
className="divider-tab__button"
|
|
data-testid={`tab-${tab.label}`}
|
|
>
|
|
{tab.label}
|
|
{typeof tab.number === "number" && tab.number !== 0 && (
|
|
<span className="ml-1">({tab.number})</span>
|
|
)}
|
|
</Tab>
|
|
{i !== tabs.length - 1 && (
|
|
<div className="divider-tab__line-guy" />
|
|
)}
|
|
</React.Fragment>
|
|
);
|
|
})}
|
|
</Tab.List>
|
|
<Tab.Panels
|
|
className={clsx({ "mt-4": !cantSwitchTabs || !disappearing })}
|
|
>
|
|
{content
|
|
.filter((c) => !c.hidden)
|
|
.map((c) => {
|
|
return <Tab.Panel key={c.key}>{c.element}</Tab.Panel>;
|
|
})}
|
|
</Tab.Panels>
|
|
</Tab.Group>
|
|
);
|
|
}
|