feat: show collection descriptions in the category banner style

A collection's description sits in the same tinted box as a category's, between the sort options and the grid. The box is now a shared InfoBanner.
This commit is contained in:
Tautvydas Derzinskas committed 2026-10-20 00:09:22 +02:00
1 parent 68a1481707
commit 27c42fe790
3 files changed
+50 -33

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { alpha } from "@mui/material/styles";
type Props = {
title?: string | null;
description?: string | null;
};
/** The tinted box above a model grid that says what the grid is: a category's or a collection's description. Nothing
* when there's neither a title nor a description. */
export default function InfoBanner({ title, description }: Props) {
if (!title && !description) return null;
return (
<Box
sx={{
borderRadius: 2,
px: 2.5,
py: 2,
background: (theme) =>
theme.palette.mode === "dark"
? "linear-gradient(45deg, #5061ff 0%, #31ceff 100%)"
: alpha(theme.palette.primary.main, 0.08),
}}
>
{title && (
<Typography variant="h6" sx={{ color: (theme) => (theme.palette.mode === "dark" ? "#fff" : undefined) }}>
{title}
</Typography>
)}
{description && (
<Typography
variant="body2"
sx={{
mt: title ? 0.5 : 0,
whiteSpace: "pre-line",
color: (theme) => (theme.palette.mode === "dark" ? "#fff" : "text.secondary"),
}}
>
{description}
</Typography>
)}
</Box>
);
}
@@ -19,6 +19,7 @@ import CollectionActionsMenu from "./CollectionActionsMenu";
import CollectionBookmarkButton from "./CollectionBookmarkButton";
import CollectionSyncDialog from "./CollectionSyncDialog";
import CollectionSyncIndicator from "../../components/CollectionSyncIndicator";
import InfoBanner from "../../components/InfoBanner";
import { CardSkeletons } from "../../components/media/CardSkeleton";
import { cardGridSx } from "../../components/media/cardGrid";
@@ -174,17 +175,14 @@ export default function CollectionDetailPage({
return (
<Stack spacing={2} sx={{ maxWidth: "1920px", mx: "auto" }}>
{collection.description && (
<Typography variant="body2" color="text.secondary">
{collection.description}
</Typography>
)}
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
{collection.sync && <CollectionSyncIndicator sync={collection.sync} onClick={() => setSyncOpen(true)} />}
<Box sx={{ ml: "auto" }}>
<SortTabs value={sortMode} onChange={setSortMode} />
</Box>
</Box>
{/* Its name is already the page's title. */}
<InfoBanner description={collection.description} />
{syncOpen && collection.sync && (
<CollectionSyncDialog
collection={{ ...collection, sync: collection.sync }}
@@ -1,8 +1,6 @@
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { alpha } from "@mui/material/styles";
import { useTranslation } from "react-i18next";
import { type Category } from "../../api/categories";
import InfoBanner from "../../components/InfoBanner";
import { translateCategoryDisplay } from "../../utils/translateCategoryDisplay";
type Props = {
@@ -14,29 +12,5 @@ export default function CategoryBanner({ category }: Props) {
const { i18n } = useTranslation();
const display = translateCategoryDisplay(category, i18n);
if (!display.metaTitle) return null;
return (
<Box
sx={{
borderRadius: 2,
px: 2.5,
py: 2,
background: (theme) =>
theme.palette.mode === "dark"
? "linear-gradient(45deg, #5061ff 0%, #31ceff 100%)"
: alpha(theme.palette.primary.main, 0.08),
}}
>
<Typography variant="h6" sx={{ color: (theme) => (theme.palette.mode === "dark" ? "#fff" : undefined) }}>
{display.metaTitle}
</Typography>
{display.metaDescription && (
<Typography
variant="body2"
sx={{ mt: 0.5, color: (theme) => (theme.palette.mode === "dark" ? "#fff" : "text.secondary") }}
>
{display.metaDescription}
</Typography>
)}
</Box>
);
return <InfoBanner title={display.metaTitle} description={display.metaDescription} />;
}