From 624cf74bd819bfeaef9240a13964edd8bd143312 Mon Sep 17 00:00:00 2001 From: Tero Tikkanen Date: Wed, 11 Oct 2023 19:14:48 +0300 Subject: [PATCH] Use icons in lieu category image --- components/common/{Card.js => Card.tsx} | 105 ++++++++++++------ .../contentblocks/CategoryListBlock.tsx | 59 ++++++++-- 2 files changed, 125 insertions(+), 39 deletions(-) rename components/common/{Card.js => Card.tsx} (51%) diff --git a/components/common/Card.js b/components/common/Card.tsx similarity index 51% rename from components/common/Card.js rename to components/common/Card.tsx index 924e7764..044bec57 100644 --- a/components/common/Card.js +++ b/components/common/Card.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import SVG from 'react-inlinesvg'; import { Card as BSCard, CardBody } from 'reactstrap'; import styled from 'styled-components'; import { transparentize } from 'polished'; @@ -50,14 +49,24 @@ const StyledCard = styled(BSCard)` } `; -const ImgArea = styled.div` +const ImgArea = styled.div<{ colorEffect?: string }>` + height: 9rem; position: relative; + display: flex; + align-items: center; + justify-content: center; + background-color: ${(props) => props.colorEffect}; border-bottom: ${(props) => (props.colorEffect ? '6px' : '0')} solid ${(props) => props.colorEffect}; + + @media (min-width: ${(props) => props.theme.breakpointMd}) { + height: 8rem; + } `; -const ImgBg = styled.div` +const ImgBg = styled.div<{ background: string; imageAlign: string }>` height: 9rem; + flex: 1 1 100%; background-image: url(${(props) => props.background}); background-position: ${(props) => props.imageAlign}; background-size: cover; @@ -67,51 +76,83 @@ const ImgBg = styled.div` } `; -const Card = (props) => { +const SvgIcon = styled(SVG)` + position: absolute; + right: ${(props) => props.theme.spaces.s050}; + top: ${(props) => props.theme.spaces.s050}; + width: ${(props) => props.theme.spaces.s300}; + fill: white; +`; + +const BitmapIcon = styled.div<{ imageSrc: string }>` + width: ${(props) => props.theme.spaces.s800}; + height: ${(props) => props.theme.spaces.s800}; + background-image: url(${(props) => props.imageSrc || 'none'}); + background-size: cover; + background-position: center center; +`; + +interface CardProps { + imageUrl?: string; + imageAlign?: string; + imageType?: 'svgIcon' | 'bitmapIcon' | 'image'; + colorEffect?: string; + negative?: boolean; + customColor?: string; + children: React.ReactNode; + outline?: boolean; +} + +const Card = (props: CardProps) => { const { imageUrl, colorEffect, - imageAlign, + imageAlign = 'center center', + imageType = 'image', negative, customColor, children, outline, } = props; + /* + Support svgIcon, bitmapIcon, image as cards main image + */ + const ImageComponent = () => { + if (imageType === 'svgIcon') { + return ( + + {imageUrl && } + + ); + } + if (imageType === 'bitmapIcon') { + return ( + + {imageUrl && } + + ); + } + if (imageType === 'image' && imageUrl) { + return ( + + + + ); + } + return null; + }; + return ( - {/* TODO: maybe animate transition */} - {imageUrl && ( - - - - )} + {children} ); }; -Card.defaultProps = { - imageUrl: '', - imageAlign: 'center', - colorEffect: undefined, - negative: false, - customColor: '', - outline: false, -}; - -Card.propTypes = { - imageUrl: PropTypes.string, - imageAlign: PropTypes.string, - colorEffect: PropTypes.string, - negative: PropTypes.bool, - customColor: PropTypes.string, - children: PropTypes.element.isRequired, - outline: PropTypes.bool, -}; - export default Card; diff --git a/components/contentblocks/CategoryListBlock.tsx b/components/contentblocks/CategoryListBlock.tsx index e63fa813..45a5c0f0 100644 --- a/components/contentblocks/CategoryListBlock.tsx +++ b/components/contentblocks/CategoryListBlock.tsx @@ -27,6 +27,12 @@ const CATEGORY_FRAGMENT = gql` ...MultiUseImageFragment } color + iconSvgUrl + iconImage { + rendition(size: "400x400", crop: false) { + src + } + } categoryPage { title urlPath @@ -122,6 +128,12 @@ export type CategoryListBlockCategory = { id: string; image?: MultiUseImageFragmentFragment | null; color?: string | null; + iconSvgUrl?: string | null; + iconImage?: { + rendition: { + src: string; + }; + }; identifier: string; name: string; shortDescription?: string; @@ -153,6 +165,42 @@ const CategoryListBlock = (props: CategoryListBlockProps) => { categories = fallbackCategories, } = props; + /* + Determine what image to use on category card + If category has no own image but has icon use icon on colored bg + If category has no own image and no icon use fallback image + If category has own image use that + */ + type CardImageType = (category: CategoryListBlockCategory) => { + type: 'image' | 'svgIcon' | 'bitmapIcon'; + src: string | undefined; + alignment: string; + }; + + const getCardImage: CardImageType = (category) => { + const categryImageSrc = category.image?.small?.src; + + if (!categryImageSrc && category.iconSvgUrl) { + return { + type: 'svgIcon', + src: category.iconSvgUrl, + alignment: 'center', + }; + } + if (!categryImageSrc && category.iconImage) { + return { + type: 'bitmapIcon', + src: category.iconImage?.rendition?.src, + alignment: 'center', + }; + } else + return { + type: 'image', + src: categryImageSrc || fallbackImage?.small?.src, + alignment: getBgImageAlignment(category.image || fallbackImage), + }; + }; + return ( @@ -175,13 +223,10 @@ const CategoryListBlock = (props: CategoryListBlockProps) => {