sendou.ink/app/components/NewTabs.tsx
Kalle b4cc185d1d
Some checks are pending
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run
Scrims (#2211)
* 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
2025-04-20 22:51:23 +03:00

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>
);
}