Skip to content

Commit

Permalink
Improve series block ux (#1020)
Browse files Browse the repository at this point in the history
This moves the description of series blocks inside the block's box to
prevent confusion regarding its context in pages with multiple content
blocks. Longer descriptions are now collapsed by default and can be
expanded.
There are two things I still want to improve:
- [x] When the title is not shown, the description should be top-aligned
(see screenshot).
- [x] ~~The "controversial" series that led to this discussion (Opencast
Summit 2021 on the deployment's front page) actually doesn't use the
displaying option for title and description but rather a title and text
block. So this should be changed to use the `show title & description`
option instead.~~ Edit: fixed in deployment

See commit messages for more information.
<img width="1132" alt="Bildschirmfoto 2023-11-27 um 11 59 03"
src="https://github.com/elan-ev/tobira/assets/94838646/a9bc5a1b-c821-4ee1-8dbe-ac6a1e1b0a02">

When done, this:
- closes #1008 
- closes #1007
  • Loading branch information
LukasKalbertodt authored Jan 11, 2024
2 parents b89a3a0 + e7714fd commit ea8b45e
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 136 deletions.
2 changes: 1 addition & 1 deletion frontend/src/i18n/locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ video:
starts: Startet
starts-in: Startet {{duration}}
description:
show-more: Mehr anzeigen
show-more: ...mehr anzeigen
show-less: Weniger anzeigen
embed:
copy-embed-code-to-clipboard: Einbettungscode in Zwischenablage kopieren
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/i18n/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ video:
starts: Starts
starts-in: Starts {{duration}}
description:
show-more: Show more
show-more: ...show more
show-less: Show less
embed:
copy-embed-code-to-clipboard: Copy embed code to clipboard
Expand Down
104 changes: 11 additions & 93 deletions frontend/src/routes/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ import {
import { UserData$key } from "../__generated__/UserData.graphql";
import { NavigationData$key } from "../layout/__generated__/NavigationData.graphql";
import { getEventTimeInfo } from "../util/video";
import { Creators, formatDuration } from "../ui/Video";
import { Description } from "../ui/metadata";
import { formatDuration } from "../ui/Video";
import { ellipsisOverflowCss, focusStyle } from "../ui";
import { Card } from "../ui/Card";
import { realmBreadcrumbs } from "../util/realm";
Expand All @@ -63,6 +62,7 @@ import { COLORS } from "../color";
import { RelativeDate } from "../ui/time";
import { Modal, ModalHandle } from "../ui/Modal";
import { PlayerContextProvider, usePlayerContext } from "../ui/player/PlayerContext";
import { CollapsibleDescription } from "../ui/metadata";


// ===========================================================================================
Expand Down Expand Up @@ -352,50 +352,6 @@ const Metadata: React.FC<MetadataProps> = ({ id, event }) => {
},
};

const descriptionRef = useRef<HTMLDivElement>(null);
const descriptionContainerRef = useRef<HTMLDivElement>(null);

const [expanded, setExpanded] = useState(false);
const [showButton, setShowButton] = useState(false);

const resizeObserver = new ResizeObserver(() => {
if (descriptionRef.current && descriptionContainerRef.current) {
setShowButton(
descriptionRef.current.scrollHeight > descriptionContainerRef.current.offsetHeight
|| expanded,
);
}
});

useEffect(() => {
if (descriptionRef.current) {
resizeObserver.observe(descriptionRef.current);
}

return () => resizeObserver.disconnect();
});

const InnerDescription: React.FC<({ truncated?: boolean })> = ({ truncated = false }) => <>
<Creators creators={event.creators} css={{
fontWeight: "bold",
marginBottom: 12,
}} />
<Description
text={event.description}
css={{
color: COLORS.neutral80,
fontSize: 14,
maxWidth: "90ch",
...truncated && ellipsisOverflowCss(6),
}}
/>
</>;

const sharedStyle = {
padding: "20px 22px",
...showButton && { paddingBottom: 55 },
};

return <>
<div css={{
display: "flex",
Expand All @@ -407,7 +363,7 @@ const Metadata: React.FC<MetadataProps> = ({ id, event }) => {
}}>
<div>
<VideoTitle title={event.title} />
<VideoDate event={event} />
<VideoDate {...{ event }} />
</div>
{/* Buttons */}
<div css={{
Expand All @@ -426,7 +382,7 @@ const Metadata: React.FC<MetadataProps> = ({ id, event }) => {
</LinkButton>
)}
{CONFIG.showDownloadButton && <DownloadButton event={event} />}
<ShareButton event={event} />
<ShareButton {...{ event }} />
</div>
</div>
<div css={{
Expand All @@ -441,52 +397,14 @@ const Metadata: React.FC<MetadataProps> = ({ id, event }) => {
},
},
}}>
<div ref={descriptionContainerRef} css={{
flex: event.description ? "1 400px" : "1 200px",
alignSelf: "flex-start",
position: "relative",
overflow: "hidden",
}}>
<div ref={descriptionRef} css={{
position: expanded ? "initial" : "absolute",
top: 0,
left: 0,
...sharedStyle,
}}><InnerDescription /></div>
<div css={{
visibility: "hidden",
...sharedStyle,
...expanded && { display: "none" },
}}><InnerDescription truncated /></div>
<div css={{
...!showButton && { display: "none" },
...!expanded && {
background: `linear-gradient(transparent, ${COLORS.neutral10} 60%)`,
},
position: "absolute",
bottom: 0,
left: 0,
right: 0,
paddingTop: 30,
}}>
<ProtoButton onClick={() => setExpanded(b => !b)} css={{
textAlign: "center",
width: "100%",
fontSize: 12,
padding: "4px 0",
borderRadius: "0 0 8px 8px",
":hover, :focus-visible": { backgroundColor: COLORS.neutral15 },
...focusStyle({ inset: true }),
}}>
{expanded
? t("video.description.show-less")
: t("video.description.show-more")
}
</ProtoButton>
</div>
</div>
<CollapsibleDescription
type="video"
description={event.description}
creators={event.creators}
bottomPadding={40}
/>
<div css={{ flex: "1 200px", alignSelf: "flex-start", padding: "20px 22px" }}>
<MetadataTable event={event} />
<MetadataTable {...{ event }} />
</div>
</div>
</>;
Expand Down
89 changes: 51 additions & 38 deletions frontend/src/ui/Blocks/Series.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { RelativeDate } from "../time";
import { Card } from "../Card";
import { LuColumns, LuGrid, LuList, LuChevronLeft, LuChevronRight, LuPlay } from "react-icons/lu";
import { keyframes } from "@emotion/react";
import { Description, SmallDescription } from "../metadata";
import { CollapsibleDescription, SmallDescription } from "../metadata";
import { darkModeBoxShadow, ellipsisOverflowCss, focusStyle } from "..";
import { IconType } from "react-icons";
import { COLORS } from "../../color";
Expand Down Expand Up @@ -207,18 +207,11 @@ const ReadySeriesBlock: React.FC<ReadyProps> = ({
const eventsNotEmpty = series.events.length > 0;

return <OrderContext.Provider value={{ eventOrder, setEventOrder }}>
{showMetadata && !showTitle && <Description
text={series.syncedData.description}
css={{ maxWidth: "85ch" }}
/>}
<SeriesBlockContainer showViewOptions={eventsNotEmpty} title={finalTitle}>
{showMetadata && showTitle && series.syncedData.description && <>
<Description
text={series.syncedData.description}
css={{ fontSize: 14, padding: "14px 14px 0 14px", maxWidth: "85ch" }}
/>
<hr css={{ margin: "20px 0" }} />
</>}
<SeriesBlockContainer
showViewOptions={eventsNotEmpty}
title={finalTitle}
description={showMetadata ? series.syncedData.description : null}
>
{!eventsNotEmpty
? <div css={{ padding: 14 }}>{t("series.no-events")}</div>
: <>
Expand All @@ -238,6 +231,7 @@ type Event = SeriesBlockSeriesData$data["events"][0];

type SeriesBlockContainerProps = {
title?: string;
description?: string | null;
children: ReactNode;
showViewOptions: boolean;
};
Expand All @@ -255,7 +249,7 @@ const ViewContext = createContext<ViewContext>({
});

const SeriesBlockContainer: React.FC<SeriesBlockContainerProps> = (
{ title, children, showViewOptions },
{ title, description, children, showViewOptions },
) => {
const [viewState, setViewState] = useState<View>("gallery");
const isDark = useColorScheme().scheme === "dark";
Expand All @@ -268,32 +262,51 @@ const SeriesBlockContainer: React.FC<SeriesBlockContainerProps> = (
borderRadius: 10,
...isDark && darkModeBoxShadow,
}}>
<div css={{
display: "flex",
[screenWidthAtMost(VIDEO_GRID_BREAKPOINT)]: {
flexWrap: "wrap",
},
}}>
{title && <h2 css={{
display: "inline-block",
padding: "8px 12px",
color: isDark ? COLORS.neutral90 : COLORS.neutral80,
fontSize: 20,
lineHeight: 1.3,
}}>{title}</h2>}
{showViewOptions && <div css={{
<>
<div css={{
display: "flex",
alignItems: "center",
alignSelf: "flex-start",
marginLeft: "auto",
fontSize: 14,
gap: 16,
padding: 5,
justifyContent: "space-between",
...title && description && { flexDirection: "column" },
[screenWidthAtMost(VIDEO_GRID_BREAKPOINT)]: {
flexWrap: "wrap",
},
}}>
<OrderMenu />
<ViewMenu/>
</div>}
</div>
{title && <h2 css={{
display: "inline-block",
padding: "8px 12px",
color: isDark ? COLORS.neutral90 : COLORS.neutral80,
fontSize: 20,
lineHeight: 1.3,
}}>{title}</h2>}
<div css={{
display: "flex",
flexDirection: "row",
flexGrow: 1,
[screenWidthAtMost(VIDEO_GRID_BREAKPOINT)]: {
flexWrap: "wrap",
},
}}>
{description && <CollapsibleDescription
type="series"
bottomPadding={32}
{...{ description }}
/>}
{showViewOptions && <div css={{
display: "flex",
alignItems: "center",
alignSelf: description ? "flex-end" : "flex-start",
marginLeft: "auto",
fontSize: 14,
gap: 16,
padding: 5,
}}>
<OrderMenu />
<ViewMenu/>
</div>}
</div>
</div>
{description && <hr css={{ margin: "12px 6px 20px 6px" }} />}
</>
{children}
</div>
</ViewContext.Provider>;
Expand Down
Loading

0 comments on commit ea8b45e

Please sign in to comment.