fix: make all apps category tab scrollable (#5113)

* feat: make left and right button workable

* refactor: separate category tab into a seperate component
to reduce unnecessary re-rendering while scrolling through the arrow buttons.

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: alannnc <alannnc@gmail.com>
pull/5132/head^2
Nafees Nazik 2022-10-20 23:29:24 +05:30 committed by GitHub
parent bb45b9617b
commit bc6f959c7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 85 additions and 61 deletions

View File

@ -38,13 +38,95 @@ export function useShouldShowArrows() {
type AllAppsPropsType = { apps: (App & { credentials: Credential[] | undefined })[] };
export default function AllApps({ apps }: AllAppsPropsType) {
interface CategoryTabProps {
selectedCategory: string | null;
categories: string[];
}
function CategoryTab({ selectedCategory, categories }: CategoryTabProps) {
const { t } = useLocale();
const router = useRouter();
const { ref, calculateScroll, leftVisible, rightVisible } = useShouldShowArrows();
const handleLeft = () => {
if (ref.current) {
ref.current.scrollLeft -= 100;
}
};
const handleRight = () => {
if (ref.current) {
ref.current.scrollLeft += 100;
}
};
return (
<div className="relative mb-4 flex flex-col justify-between lg:flex-row lg:items-center">
<h2 className="text-lg font-semibold text-gray-900 ">
{t("explore_apps", {
category:
(selectedCategory && selectedCategory[0].toUpperCase() + selectedCategory.slice(1)) ||
t("all_apps"),
})}
</h2>
{leftVisible && (
<button onClick={handleLeft} className="absolute top-9 flex md:left-1/2 md:-top-1">
<div className="flex h-12 w-5 items-center justify-end bg-white">
<ChevronLeft className="h-4 w-4 text-gray-500" />
</div>
<div className="flex h-12 w-5 bg-gradient-to-l from-transparent to-white" />
</button>
)}
<ul
className="no-scrollbar mt-3 flex max-w-full space-x-1 overflow-x-auto lg:mt-0 lg:max-w-[50%]"
onScroll={(e) => calculateScroll(e)}
ref={ref}>
<li
onClick={() => {
router.replace(router.asPath.split("?")[0], undefined, { shallow: true });
}}
className={classNames(
selectedCategory === null ? "bg-gray-900 text-gray-50" : "bg-gray-50 text-gray-900",
"rounded-md px-4 py-2.5 text-sm font-medium hover:cursor-pointer hover:bg-gray-900 hover:text-gray-50"
)}>
{t("all_apps")}
</li>
{categories.map((cat, pos) => (
<li
key={pos}
onClick={() => {
if (selectedCategory === cat) {
router.replace(router.asPath.split("?")[0], undefined, { shallow: true });
} else {
router.replace(router.asPath.split("?")[0] + `?category=${cat}`, undefined, {
shallow: true,
});
}
}}
className={classNames(
selectedCategory === cat ? "bg-gray-900 text-gray-50" : "bg-gray-50 text-gray-900",
"rounded-md px-4 py-2.5 text-sm font-medium hover:cursor-pointer hover:bg-gray-900 hover:text-gray-50"
)}>
{cat[0].toUpperCase() + cat.slice(1)}
</li>
))}
</ul>
{rightVisible && (
<button onClick={handleRight} className="absolute top-9 right-0 flex md:-top-1">
<div className="flex h-12 w-5 bg-gradient-to-r from-transparent to-white" />
<div className="flex h-12 w-5 items-center justify-end bg-white">
<ChevronRight className="h-4 w-4 text-gray-500" />
</div>
</button>
)}
</div>
);
}
export default function AllApps({ apps }: AllAppsPropsType) {
const router = useRouter();
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [appsContainerRef] = useAutoAnimate<HTMLDivElement>();
const { ref, calculateScroll, leftVisible, rightVisible } = useShouldShowArrows();
const categories = apps
.map((app) => app.category)
.filter((cat, pos, self) => {
@ -61,65 +143,7 @@ export default function AllApps({ apps }: AllAppsPropsType) {
return (
<div className="mb-16">
<div className="relative mb-4 flex flex-col justify-between lg:flex-row lg:items-center">
<h2 className="text-lg font-semibold text-gray-900 ">
{t("explore_apps", {
category:
(selectedCategory && selectedCategory[0].toUpperCase() + selectedCategory.slice(1)) ||
t("all_apps"),
})}
</h2>
{leftVisible && (
<div className="absolute top-9 flex md:left-1/2 md:-top-1">
<div className="flex h-12 w-5 items-center justify-end bg-white">
<ChevronLeft className="h-4 w-4 text-gray-500" />
</div>
<div className="flex h-12 w-5 bg-gradient-to-l from-transparent to-white" />
</div>
)}
<ul
className="no-scrollbar mt-3 flex max-w-full space-x-1 overflow-x-auto lg:mt-0 lg:max-w-[50%]"
onScroll={(e) => calculateScroll(e)}
ref={ref}>
<li
onClick={() => {
router.replace(router.asPath.split("?")[0], undefined, { shallow: true });
}}
className={classNames(
selectedCategory === null ? "bg-gray-900 text-gray-50" : "bg-gray-50 text-gray-900",
"rounded-md px-4 py-2.5 text-sm font-medium hover:cursor-pointer hover:bg-gray-900 hover:text-gray-50"
)}>
{t("all_apps")}
</li>
{categories.map((cat, pos) => (
<li
key={pos}
onClick={() => {
if (selectedCategory === cat) {
router.replace(router.asPath.split("?")[0], undefined, { shallow: true });
} else {
router.replace(router.asPath.split("?")[0] + `?category=${cat}`, undefined, {
shallow: true,
});
}
}}
className={classNames(
selectedCategory === cat ? "bg-gray-900 text-gray-50" : "bg-gray-50 text-gray-900",
"rounded-md px-4 py-2.5 text-sm font-medium hover:cursor-pointer hover:bg-gray-900 hover:text-gray-50"
)}>
{cat[0].toUpperCase() + cat.slice(1)}
</li>
))}
</ul>
{rightVisible && (
<div className="absolute top-9 right-0 flex md:-top-1">
<div className="flex h-12 w-5 bg-gradient-to-r from-transparent to-white" />
<div className="flex h-12 w-5 items-center justify-end bg-white">
<ChevronRight className="h-4 w-4 text-gray-500" />
</div>
</div>
)}
</div>
<CategoryTab selectedCategory={selectedCategory} categories={categories} />
<div
className="grid gap-3 lg:grid-cols-4 [@media(max-width:1270px)]:grid-cols-3 [@media(max-width:730px)]:grid-cols-2 [@media(max-width:500px)]:grid-cols-1"
ref={appsContainerRef}>