From aca5d1d3c3abada6a1bddea0e53e430a5446c56c Mon Sep 17 00:00:00 2001 From: Karl Andin Date: Tue, 20 Aug 2024 14:52:30 +0200 Subject: [PATCH] feat(KUI-1149): add "show more" feature for item with long content in Round info grid. --- i18n/messages.en.js | 4 ++ i18n/messages.se.js | 4 ++ public/css/kursinfo-web.scss | 36 ++++++++++++++ .../RoundInformationInfoGrid.jsx | 48 ++++++++++++++++++- 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/i18n/messages.en.js b/i18n/messages.en.js index 18e988de..1b356541 100644 --- a/i18n/messages.en.js +++ b/i18n/messages.en.js @@ -39,6 +39,10 @@ module.exports = { menu_panel_close: 'Close', menu_panel_menu: 'Menu', }, + showMoreContent: { + show: 'Show more', + hide: 'Hide', + }, bankIdAlertText: `Please note that Students not located in Sweden may have problems attending a course at KTH.
You could meet obstacles if you're required to pay fees or if you do not have a Swedish Mobile BankID. `, courseLabels: { label_course_description: 'Introduction to course', diff --git a/i18n/messages.se.js b/i18n/messages.se.js index 93ebd0ca..f6a475d7 100644 --- a/i18n/messages.se.js +++ b/i18n/messages.se.js @@ -40,6 +40,10 @@ module.exports = { menu_panel_close: 'Stäng', menu_panel_menu: 'Meny', }, + showMoreContent: { + show: 'Visa mer', + hide: 'Dölj', + }, bankIdAlertText: 'Du behöver ett KTH-konto för att läsa en kurs på KTH, kontot aktiveras med Mobilt BankID eller genom att besöka KTH:s campus. Det enda sättet att starta en kurs utan att besöka campus, är om du har Mobilt BankID.', courseLabels: { diff --git a/public/css/kursinfo-web.scss b/public/css/kursinfo-web.scss index d3a6665a..df1c22eb 100644 --- a/public/css/kursinfo-web.scss +++ b/public/css/kursinfo-web.scss @@ -140,6 +140,42 @@ margin-bottom: 1.5rem; } + .roundInformation__infoGridItem { + display: flex; + flex-direction: column; + + .roundInformation__infoGridItemContent { + position: relative; + overflow: hidden; + max-height: 96px; + transition: max-height 200ms ease-in; + + &.hidden::after { + content: ''; + position: absolute; + bottom: 0; + height: 24px; + width: 100%; + background: linear-gradient(to bottom, transparent, var(--color-background-alt)); + display: block; + } + } + + .roundInformation__infoGridItemShowMoreButton { + background-color: transparent; + border: none; + padding: 0; + margin-top: 4px; + color: var(--color-tertiary); + cursor: pointer; + align-self: flex-end; + + &:hover { + text-decoration: underline; + } + } + } + .kth-alert { background-color: var(--color-background); } diff --git a/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx b/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx index 8ab06e78..b14f5104 100644 --- a/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx +++ b/public/js/app/components/RoundInformation/RoundInformationInfoGrid.jsx @@ -1,12 +1,49 @@ -import React from 'react' +import React, { useEffect, useState, useRef } from 'react' import { useLanguage } from '../../hooks/useLanguage' import InfoModal from '../InfoModal' import { CourseMemoLink } from './CourseMemoLink' import { CourseScheduleLink } from './CourseScheduleLink' import { PlannedModules } from './PlannedModules' +// Calculates if a "Show more" button should be displayed, and creates props for content and button elements. +const useShowMoreContent = content => { + const ref = useRef(null) + const [hasMoreContent, setHasMoreContent] = useState(false) + const [contentHeight, setHeight] = useState(undefined) + const { translation } = useLanguage() + + const showMoreContent = hasMoreContent && !!contentHeight + const hideMoreContent = hasMoreContent && !showMoreContent + useEffect(() => { + if (ref.current) { + const el = ref.current + const isOverflowing = el.clientHeight < el.scrollHeight + setHasMoreContent(isOverflowing) + } + }, [content]) + + const contentProps = { + ref, + style: { maxHeight: contentHeight }, // set max height for animation from the max value specified in css to actual content height + className: `roundInformation__infoGridItemContent ${hideMoreContent ? 'hidden' : ''}`, + } + + const showMoreButtonProps = hasMoreContent + ? { + onClick: () => { + setHeight(showMoreContent ? undefined : ref.current.scrollHeight) + }, + children: showMoreContent ? translation.showMoreContent.hide : translation.showMoreContent.show, + className: 'roundInformation__infoGridItemShowMoreButton', + } + : undefined + + return { contentProps, showMoreButtonProps } +} + const Item = ({ children, html, title, infoModalContent }) => { const { translation } = useLanguage() + const { contentProps, showMoreButtonProps } = useShowMoreContent(html ?? children) return (
@@ -21,7 +58,14 @@ const Item = ({ children, html, title, infoModalContent }) => { /> )} - {html ?
:
{children}
} +
+ {html ? ( +
+ ) : ( +
{children}
+ )} + {showMoreButtonProps &&
) }