diff --git a/base.scss b/base.scss index 7cb2d91fd..ba740b98f 100644 --- a/base.scss +++ b/base.scss @@ -6,6 +6,7 @@ @import "./src/styles/scss/legacy"; // Library +@import "./src/stories/Library/media-container/media-container"; @import "./src/stories/Library/links/links"; @import "./src/stories/Library/link-filters/link-filters"; @import "./src/stories/Library/Arrows/arrows"; @@ -132,6 +133,10 @@ @import "./src/stories/Library/icon-text-link/icon-text-link"; @import "./src/stories/Library/material-grid/material-grid"; @import "./src/stories/Library/error-message/error-message"; +@import "./src/stories/Library/dialog/dialog"; +@import "./src/stories/Library/opening-hours-editor/opening-hours-editor"; +@import "./src/stories/Library/opening-hours/opening-hours"; +@import "./src/stories/Library/opening-hours/opening-hours-skeleton"; // Autosuggest block styling needs to be loaded before the rest of the scss for autosuggest @import "./src/stories/Blocks/autosuggest/autosuggest"; diff --git a/package.json b/package.json index 564c20024..f14432f10 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "css:lint": "concurrently 'yarn:css:stylelint' 'yarn:css:prettier -- --check' --raw", "css:lint:watch": "chokidar 'src/**/*.scss' -c 'yarn css:lint'", "css:format": "concurrently 'yarn:css:stylelint -- --fix' 'yarn:css:prettier -- --write' --max-processes 1 --raw", - "css:build": "sass base.scss:src/styles/css/base.css wysiwyg.scss:src/styles/css/wysiwyg.css --style compressed", + "css:build": "sass base.scss:src/styles/css/base.css wysiwyg.scss:src/styles/css/wysiwyg.css src/stories/Library/opening-hours-editor/opening-hours-editor.scss:src/styles/css/opening-hours-editor.css --style compressed", "css:watch": "yarn css:build -- --watch", "build": "concurrently 'yarn:css:build' --raw", "markdown:lint": "markdownlint-cli2", diff --git a/src/stories/Blocks/event-page/EventPage.stories.tsx b/src/stories/Blocks/event-page/EventPage.stories.tsx index 9d772649b..389b74096 100644 --- a/src/stories/Blocks/event-page/EventPage.stories.tsx +++ b/src/stories/Blocks/event-page/EventPage.stories.tsx @@ -1,6 +1,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; import Event from "./EventPage"; +import ImageCredited from "../../Library/image-credited/ImageCredited"; export default { title: "Blocks / Event page", @@ -16,8 +17,16 @@ export default { type: "string", }, image: { - defaultValue: - "https://images.unsplash.com/photo-1531058020387-3be344556be6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8ZXZlbnR8fHx8fHwxNzAyOTEwMzE0&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1080", + defaultValue: ( + + ), + }, + placeholderText: { + defaultValue: "Noget spændende tekst", type: "string", }, descriptionDescription: { diff --git a/src/stories/Blocks/event-page/EventPage.tsx b/src/stories/Blocks/event-page/EventPage.tsx index c3b7c5e0c..e48dd7e7c 100644 --- a/src/stories/Blocks/event-page/EventPage.tsx +++ b/src/stories/Blocks/event-page/EventPage.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, ReactNode } from "react"; import Hero from "../../Library/Heros/hero/Hero"; import EventDescription, { EventDescriptionProps, @@ -8,12 +8,14 @@ import { EventParagraphs } from "../../Library/paragraphs/Paragraphs"; type EventPageProps = { title: string; date: string; - image: string; + placeholderText?: string; + image?: ReactNode; } & EventDescriptionProps; const EventPage: FC = ({ title, date, + placeholderText, image, descriptionDescription, horizontalTermLineData, @@ -25,6 +27,7 @@ const EventPage: FC = ({ title={title} date={date} image={image} + placeholderText={placeholderText} cta="Køb billet" tag="Arrangement" /> diff --git a/src/stories/Blocks/page/Page.stories.tsx b/src/stories/Blocks/page/Page.stories.tsx index 05399ea4e..1af0438b3 100644 --- a/src/stories/Blocks/page/Page.stories.tsx +++ b/src/stories/Blocks/page/Page.stories.tsx @@ -1,6 +1,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; import Page from "./Page"; +import ImageCredited from "../../Library/image-credited/ImageCredited"; export default { title: "Blocks / Pages", @@ -25,6 +26,7 @@ const Template: ComponentStory = (args) => ; export const frontPage = Template.bind({}); frontPage.args = { hero: { + placeholderText: "Forsiden har intet billede", contentType: "Arrangement", date: "06 Dec 2022", title: "Stine Pilgaard vinder De Gyldne Laurbær", @@ -36,8 +38,13 @@ frontPage.args = { export const branchPage = Template.bind({}); branchPage.args = { hero: { - image: - "https://images.unsplash.com/photo-1531058020387-3be344556be6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8ZXZlbnR8fHx8fHwxNzAyOTEwMzE0&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1080", + image: ( + + ), contentType: "Fillial", title: "Søborg", description: diff --git a/src/stories/Blocks/page/Page.tsx b/src/stories/Blocks/page/Page.tsx index 009e3e03f..7ee6fe024 100644 --- a/src/stories/Blocks/page/Page.tsx +++ b/src/stories/Blocks/page/Page.tsx @@ -14,6 +14,7 @@ const Page: FC = ({ hero }) => { + ), + }, + placeholderText: { + defaultValue: "En spændende tekst", + type: "string", }, contentType: { name: "Type", diff --git a/src/stories/Library/Heros/hero-link/HeroLink.tsx b/src/stories/Library/Heros/hero-link/HeroLink.tsx index 9ad85e802..026d2fa62 100644 --- a/src/stories/Library/Heros/hero-link/HeroLink.tsx +++ b/src/stories/Library/Heros/hero-link/HeroLink.tsx @@ -11,6 +11,7 @@ export type HeroLinkProps = { const HeroLink: React.FunctionComponent = ({ url, image, + placeholderText, contentType, date, title, @@ -34,7 +35,7 @@ const HeroLink: React.FunctionComponent = ({ /> - + ); }; diff --git a/src/stories/Library/Heros/hero/Hero.stories.tsx b/src/stories/Library/Heros/hero/Hero.stories.tsx index b4541a652..ee81b6fad 100644 --- a/src/stories/Library/Heros/hero/Hero.stories.tsx +++ b/src/stories/Library/Heros/hero/Hero.stories.tsx @@ -1,6 +1,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; import Hero from "./Hero"; +import ImageCredited from "../../image-credited/ImageCredited"; export default { title: "Library / Hero", @@ -14,10 +15,18 @@ export default { }, argTypes: { image: { - name: "Image", - defaultValue: - "https://images.unsplash.com/photo-1531058020387-3be344556be6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8ZXZlbnR8fHx8fHwxNzAyOTEwMzE0&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1080", - control: { type: "text" }, + defaultValue: ( + + ), + }, + placeholderText: { + defaultValue: "Stine Pilgaard vinder De Gyldne Laurbær", + type: "string", }, contentType: { name: "Type", diff --git a/src/stories/Library/Heros/hero/Hero.tsx b/src/stories/Library/Heros/hero/Hero.tsx index 115e011ff..c5d42ff32 100644 --- a/src/stories/Library/Heros/hero/Hero.tsx +++ b/src/stories/Library/Heros/hero/Hero.tsx @@ -1,14 +1,16 @@ -import React from "react"; +import React, { ReactNode } from "react"; import clsx from "clsx"; import HeroInner, { HeroInnerProps } from "./HeroInner"; import HeroVisual from "./HeroVisual"; export type HeroProps = { - image?: string; + image?: ReactNode; + placeholderText?: string; } & HeroInnerProps; const HeroLink: React.FunctionComponent = ({ image, + placeholderText, contentType, date, title, @@ -35,7 +37,7 @@ const HeroLink: React.FunctionComponent = ({ /> - + ); }; diff --git a/src/stories/Library/Heros/hero/HeroVisual.tsx b/src/stories/Library/Heros/hero/HeroVisual.tsx index a7b0d0cc5..fad3f4a8e 100644 --- a/src/stories/Library/Heros/hero/HeroVisual.tsx +++ b/src/stories/Library/Heros/hero/HeroVisual.tsx @@ -1,21 +1,19 @@ -import React from "react"; -import ImageCredited from "../../image-credited/ImageCredited"; +import React, { ReactNode } from "react"; +import MediaContainer from "../../media-container/MediaContainer"; export type HeroInnerProps = { - image?: string; + image?: ReactNode; + placeholderText?: string; }; -const HeroVisual: React.FunctionComponent = ({ image }) => { +const HeroVisual: React.FunctionComponent = ({ + image, + placeholderText, +}) => { return (
- {image && ( - - )} +
); diff --git a/src/stories/Library/Heros/hero/hero.scss b/src/stories/Library/Heros/hero/hero.scss index c58d704e0..a7f0abe1a 100644 --- a/src/stories/Library/Heros/hero/hero.scss +++ b/src/stories/Library/Heros/hero/hero.scss @@ -1,5 +1,13 @@ $_hero-column-breakpoint: "small"; +// On mobile, it makes no sense to show the placeholder text, +// as it just serves the purpose to fill out the hero on desktop. +@include media-query__name($_hero-column-breakpoint, "max-width") { + .hero--has-no-media .hero__visual { + display: none; + } +} + .hero__content, .hero__visual { @include media-query__name($_hero-column-breakpoint) { @@ -15,8 +23,8 @@ $_hero-column-breakpoint: "small"; } .hero__visual-inner { - height: 100%; width: 100%; + aspect-ratio: 5/4; } .hero { @@ -38,14 +46,6 @@ $_hero-column-breakpoint: "small"; } } -@include media-query__name($_hero-column-breakpoint) { - .hero.hero--has-no-media { - .hero__visual-inner { - @include identity-placeholder; - } - } -} - .hero__description { @include typography($typo__body-placeholder); flex-grow: 1; diff --git a/src/stories/Library/card-grid/card-grid.scss b/src/stories/Library/card-grid/card-grid.scss index e4640e54b..e8f5940f1 100644 --- a/src/stories/Library/card-grid/card-grid.scss +++ b/src/stories/Library/card-grid/card-grid.scss @@ -5,10 +5,7 @@ $_card-grid-gap: $s-lg; .card-grid { @include layout-container(); - - .card__placeholder-text { - @include typography($typo__card-placeholder--grid); - } + @include media-container--grid; } .card-grid--full-width { @@ -129,9 +126,7 @@ $_card-grid-gap: $s-lg; // there, there is plenty of space. @if ($name == "small") { @include media-query__small { - .card__placeholder-text { - font-size: 0; - } + @include media-container--small; } } } diff --git a/src/stories/Library/card/Card.stories.tsx b/src/stories/Library/card/Card.stories.tsx index 70a978743..4d06f23c4 100644 --- a/src/stories/Library/card/Card.stories.tsx +++ b/src/stories/Library/card/Card.stories.tsx @@ -24,10 +24,6 @@ export default { defaultValue: "Bøger som har gjort en forskel for romanens udvikling", type: "string", }, - placeholderText: { - defaultValue: "Stine Pilgaard vinder De Gyldne Laurbær", - type: "string", - }, href: { defaultValue: "https://google.com", type: "string", @@ -36,7 +32,9 @@ export default { defaultValue: ( ), - + }, + placeholderText: { + defaultValue: "Stine Pilgaard vinder De Gyldne Laurbær", type: "string", }, }, diff --git a/src/stories/Library/card/Card.tsx b/src/stories/Library/card/Card.tsx index e5258fed8..5568baddd 100644 --- a/src/stories/Library/card/Card.tsx +++ b/src/stories/Library/card/Card.tsx @@ -1,5 +1,6 @@ import { FC, ReactNode } from "react"; import clsx from "clsx"; +import MediaContainer from "../media-container/MediaContainer"; type CardProps = { variant?: string; @@ -19,18 +20,16 @@ const Card: FC = ({ dateTag, }) => { const classes = clsx("card", { - "card--has-no-image": !image, - "card--has-image": image, + "card--has-no-media": !image, + "card--has-media": !!image, }); return (
-
- {image || ( -
{placeholderText}
- )} -
+
+ +
{typeTag ? ( {typeTag} diff --git a/src/stories/Library/card/card.scss b/src/stories/Library/card/card.scss index 0b6c2df71..615a36e31 100644 --- a/src/stories/Library/card/card.scss +++ b/src/stories/Library/card/card.scss @@ -4,23 +4,6 @@ margin-bottom: $s-sm; } -.card--has-no-image { - .card__media { - @extend %identity-placeholder; - } -} - -.card__placeholder-text { - @extend %identity-placeholder-text; -} - -.card--has-image { - // This is necessary to get object-fit to work. - * { - height: 100%; - } -} - .card__tags { display: flex; margin-bottom: $s-sm; @@ -96,24 +79,27 @@ %card-variant--x-large, .card[data-variant="x-large"] { + @include media-container--card; + width: 200px; @include media-query__name($breakpoint__large-card) { width: 440px; } - &.card--has-no-image { + &.card--has-no-media { // We only want the page fold on 1:1 view-modes. @extend %identity-pagefold; } - .card__placeholder-text { - @include typography($typo__card-placeholder); + &.card--has-media { + .card__media { + @extend %identity-placeholder; + } } + // stylelint-disable-next-line no-descending-specificity -- Stylelint wants us to re-order the file, but it actually would make it less readable. .card__media { - @extend %identity-placeholder; - aspect-ratio: 1/1; } } @@ -122,21 +108,21 @@ .card[data-variant="small"] { width: 206px; + // stylelint-disable-next-line no-descending-specificity -- Stylelint wants us to re-order the file, but it actually would make it less readable. .card__media { aspect-ratio: 1/1; } - .card__tags, - .card__media { + // stylelint-disable-next-line no-descending-specificity -- Stylelint wants us to re-order the file, but it actually would make it less readable. + .card__media, + .card__tags { margin-bottom: $s-xs; } // On desktop sizes this small, there is no space for placeholder text, and // extra tags, but we can still show it for screenreaders. @include media-query__name($breakpoint__large-card) { - .card__placeholder-text { - font-size: 0; - } + @include media-container--small; .card__tag { @include typography($typo__byline-tags--small); @@ -156,6 +142,7 @@ width: 321px; } + // stylelint-disable-next-line no-descending-specificity -- Stylelint wants us to re-order the file, but it actually would make it less readable. .card__media { // Odd aspect ratio, taken from the design. aspect-ratio: 321/426; diff --git a/src/stories/Library/content-list-item/ContentListItem.stories.tsx b/src/stories/Library/content-list-item/ContentListItem.stories.tsx index 9ec69a21e..762fa2a78 100644 --- a/src/stories/Library/content-list-item/ContentListItem.stories.tsx +++ b/src/stories/Library/content-list-item/ContentListItem.stories.tsx @@ -1,18 +1,13 @@ import { ComponentStory, ComponentMeta } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; import { ContentListItem } from "./ContentListItem"; +import ImageCredited from "../image-credited/ImageCredited"; export default { title: "Library / Content List Item", component: ContentListItem, decorators: [withDesign], argTypes: { - image: { - defaultValue: - "https://plus.unsplash.com/premium_photo-1696886122527-e4303b76aa8f?q=80&w=5156&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - - control: { type: "text" }, - }, tagText: { defaultValue: "Foredrag", control: { type: "text" }, @@ -46,6 +41,15 @@ export default { defaultValue: "/", control: { type: "text" }, }, + image: { + defaultValue: ( + + ), + }, + placeholderText: { + defaultValue: "Stine Pilgaard vinder De Gyldne Laurbær", + type: "string", + }, }, parameters: { design: { diff --git a/src/stories/Library/content-list-item/ContentListItem.tsx b/src/stories/Library/content-list-item/ContentListItem.tsx index 9fcbf4e89..1552528ba 100644 --- a/src/stories/Library/content-list-item/ContentListItem.tsx +++ b/src/stories/Library/content-list-item/ContentListItem.tsx @@ -1,9 +1,12 @@ +import { ReactNode } from "react"; import { ReactComponent as ArrowSmallRight } from "../Arrows/icon-arrow-ui/icon-arrow-ui-small-right.svg"; import Tag from "../tag/Tag"; +import MediaContainer from "../media-container/MediaContainer"; export type ContentListItemProps = { eventSeriesId?: string; - image: string; + image?: ReactNode; + placeholderText?: string; tagText: string; title: string; description: string; @@ -17,6 +20,7 @@ export type ContentListItemProps = { export const ContentListItem: React.FC = ({ image, + placeholderText, tagText, title, description, @@ -33,7 +37,7 @@ export const ContentListItem: React.FC = ({ return (
- {title} +
{tagText && ( diff --git a/src/stories/Library/content-list-item/content-list-item.scss b/src/stories/Library/content-list-item/content-list-item.scss index cb8507eb7..587d77c48 100644 --- a/src/stories/Library/content-list-item/content-list-item.scss +++ b/src/stories/Library/content-list-item/content-list-item.scss @@ -68,23 +68,10 @@ $_stacked-reduce-width: 20px; } .content-list-item__image-container { - @extend %identity-placeholder-pseudo; grid-area: image; position: relative; width: 100%; aspect-ratio: 4 / 3; - - // We want to treat everything inside the image-container as image related. - // To make object-fit work, it is important that everything has 100% - // height and width set. We cannot know 100% what markup Drupal will use, - // so we'll use a wildcard here. - * { - width: 100%; - height: 100%; - object-fit: cover; - position: relative; - z-index: $z-10; - } } .content-list-item__content { @@ -201,6 +188,8 @@ $_stacked-reduce-width: 20px; } .content-list-item__image-container { + @include media-container--small; + grid-area: image; max-height: $_content-list-item--image-height; min-height: $_content-list-item--image-height; diff --git a/src/stories/Library/content-list/ContentList.stories.tsx b/src/stories/Library/content-list/ContentList.stories.tsx index b2e1ce36d..d3165c341 100644 --- a/src/stories/Library/content-list/ContentList.stories.tsx +++ b/src/stories/Library/content-list/ContentList.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta, ComponentStory } from "@storybook/react"; import ContentList from "./ContentList"; -import contentListData from "./ContentListData"; +import ContentListData from "./ContentListData"; export default { title: "Library / Content List", @@ -20,5 +20,5 @@ const Template: ComponentStory = (args) => ( export const Default = Template.bind({}); Default.args = { - items: contentListData, + items: ContentListData, }; diff --git a/src/stories/Library/content-list/ContentListData.ts b/src/stories/Library/content-list/ContentListData.tsx similarity index 66% rename from src/stories/Library/content-list/ContentListData.ts rename to src/stories/Library/content-list/ContentListData.tsx index 52f2693de..e7c866a92 100644 --- a/src/stories/Library/content-list/ContentListData.ts +++ b/src/stories/Library/content-list/ContentListData.tsx @@ -1,11 +1,12 @@ import { ContentListItemProps } from "../content-list-item/ContentListItem"; +import ImageCredited from "../image-credited/ImageCredited"; const contentListData: ContentListItemProps[] = [ { eventSeriesId: "a", - image: - "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - + image: ( + + ), tagText: "Foredrag", title: "Kunst og kultur i middelalderen", description: "En dybdegåendenalysef kunst og kultur i middelalderen.", @@ -17,8 +18,9 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "b", - image: - "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + image: ( + + ), tagText: "arrangement", title: "Fars Legestue", description: "Kom forbi til hygge i Fars Legestue", @@ -30,8 +32,9 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "b", - image: - "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + image: ( + + ), tagText: "arrangement", title: "Fars Legestue", description: "Kom forbi til hygge i Fars Legestue", @@ -43,8 +46,9 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "b", - image: - "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + image: ( + + ), tagText: "arrangement", title: "Fars Legestue", description: "Kom forbi til hygge i Fars Legestue", @@ -56,8 +60,9 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "b", - image: - "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + image: ( + + ), tagText: "arrangement", title: "Fars Legestue", description: "Kom forbi til hygge i Fars Legestue", @@ -69,9 +74,7 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "a", - image: - "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - + placeholderText: "Placeholder tekst", tagText: "Foredrag", title: "Kunst og kultur i middelalderen", description: "En dybdegåendenalysef kunst og kultur i middelalderen.", @@ -83,9 +86,9 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "a", - image: - "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - + image: ( + + ), tagText: "Foredrag", title: "Kunst og kultur i middelalderen", description: "En dybdegåendenalysef kunst og kultur i middelalderen.", @@ -97,9 +100,7 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "a", - image: - "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - + placeholderText: "Placeholder tekst", tagText: "Foredrag", title: "Kunst og kultur i middelalderen", description: "En dybdegåendenalysef kunst og kultur i middelalderen.", @@ -111,8 +112,7 @@ const contentListData: ContentListItemProps[] = [ }, { eventSeriesId: "b", - image: - "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + placeholderText: "Placeholder tekst", tagText: "arrangement", title: "Fars Legestue", description: "Kom forbi til hygge i Fars Legestue", diff --git a/src/stories/Library/dialog/Dialog.stories.tsx b/src/stories/Library/dialog/Dialog.stories.tsx new file mode 100644 index 000000000..677e5d50f --- /dev/null +++ b/src/stories/Library/dialog/Dialog.stories.tsx @@ -0,0 +1,14 @@ +import { ComponentMeta, ComponentStory } from "@storybook/react"; + +import DialogPlayGround from "./DialogPlayGround"; + +export default { + title: "Library / Dialog", + component: DialogPlayGround, +} as ComponentMeta; + +const Template: ComponentStory = () => ( + +); + +export const Default = Template.bind({}); diff --git a/src/stories/Library/dialog/Dialog.tsx b/src/stories/Library/dialog/Dialog.tsx new file mode 100644 index 000000000..1b2655369 --- /dev/null +++ b/src/stories/Library/dialog/Dialog.tsx @@ -0,0 +1,34 @@ +import React, { forwardRef } from "react"; + +export type DialogType = { + children: React.ReactNode; + closeDialog: () => void; +}; + +const Dialog = forwardRef( + ({ children, closeDialog }, ref) => { + return ( + { + if (currentTarget === target) { + closeDialog(); + } + }} + > + + {children} + + ); + } +); +export default Dialog; diff --git a/src/stories/Library/dialog/DialogContent.tsx b/src/stories/Library/dialog/DialogContent.tsx new file mode 100644 index 000000000..b4d226fd3 --- /dev/null +++ b/src/stories/Library/dialog/DialogContent.tsx @@ -0,0 +1,13 @@ +const DialogContent = () => { + return ( +
+

Dialog Content

+

+ Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quia officia + odio temporibus libero a labore sint omnis, autem quibusdam fugit quae, + eveniet incidunt vero illo facere aperiam voluptates in. Repellendus! +

+
+ ); +}; +export default DialogContent; diff --git a/src/stories/Library/dialog/DialogPlayGround.tsx b/src/stories/Library/dialog/DialogPlayGround.tsx new file mode 100644 index 000000000..ae6365b5a --- /dev/null +++ b/src/stories/Library/dialog/DialogPlayGround.tsx @@ -0,0 +1,36 @@ +import DialogContent from "./DialogContent"; +import Dialog from "./Dialog"; +import useDialog from "./useDialog"; +import OpeningHoursForm from "../opening-hours-editor/OpeningHoursForm"; + +const DialogPlayGround = () => { + const { dialogContent, openDialogWithContent, closeDialog, dialogRef } = + useDialog(); + + return ( + <> + + + + + {dialogContent} + + + ); +}; + +export default DialogPlayGround; diff --git a/src/stories/Library/dialog/dialog.scss b/src/stories/Library/dialog/dialog.scss new file mode 100644 index 000000000..f1064c573 --- /dev/null +++ b/src/stories/Library/dialog/dialog.scss @@ -0,0 +1,15 @@ +.dialog { + position: relative; + padding: 0; + border-radius: 4px; +} + +.dialog__close-button { + position: absolute; + top: 10px; + right: 10px; + border: 0; + cursor: pointer; + background-color: transparent; + padding: 10px; +} diff --git a/src/stories/Library/dialog/useDialog.tsx b/src/stories/Library/dialog/useDialog.tsx new file mode 100644 index 000000000..65841e9e5 --- /dev/null +++ b/src/stories/Library/dialog/useDialog.tsx @@ -0,0 +1,35 @@ +import { useRef, useState } from "react"; + +type UseDialogType = { + onClose?: () => void; +}; + +const useDialog = ({ onClose }: UseDialogType = {}) => { + const [dialogContent, setDialogContent] = useState(null); + + const dialogRef = useRef(null); + + const closeDialog = () => { + if (!dialogRef.current) { + return; + } + if (onClose) { + onClose(); + } + dialogRef.current.close(); + }; + + const openDialogWithContent = (content: React.ReactNode) => { + setDialogContent(content); + dialogRef.current?.showModal(); + }; + + return { + dialogContent, + dialogRef, + openDialogWithContent, + closeDialog, + }; +}; + +export default useDialog; diff --git a/src/stories/Library/image-credited/ImageCredited.tsx b/src/stories/Library/image-credited/ImageCredited.tsx index 21af01698..5144692f0 100644 --- a/src/stories/Library/image-credited/ImageCredited.tsx +++ b/src/stories/Library/image-credited/ImageCredited.tsx @@ -20,7 +20,9 @@ const ImageCredited: FC = ({
{src ? ( <> - {alt} +
+ {alt} +
{(description || year) && (
{description} diff --git a/src/stories/Library/image-credited/image-credited.scss b/src/stories/Library/image-credited/image-credited.scss index ee3567c10..c018287c5 100644 --- a/src/stories/Library/image-credited/image-credited.scss +++ b/src/stories/Library/image-credited/image-credited.scss @@ -1,5 +1,9 @@ -.image-credited__img { +.image-credited__image { width: 100%; + + * { + width: 100%; + } } .image-credited__info { diff --git a/src/stories/Library/media-container/MediaContainer.stories.tsx b/src/stories/Library/media-container/MediaContainer.stories.tsx new file mode 100644 index 000000000..ce6ed296b --- /dev/null +++ b/src/stories/Library/media-container/MediaContainer.stories.tsx @@ -0,0 +1,34 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import MediaContainer from "./MediaContainer"; +import ImageCredited from "../image-credited/ImageCredited"; + +export default { + title: "Library / Media container", + component: MediaContainer, + argTypes: { + media: { + defaultValue: ( + + ), + type: "string", + }, + placeholderText: { + defaultValue: "En placeholder tekst", + type: "string", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Default = Template.bind({}); +export const noMedia = Template.bind({}); +noMedia.args = { + media: undefined, +}; diff --git a/src/stories/Library/media-container/MediaContainer.tsx b/src/stories/Library/media-container/MediaContainer.tsx new file mode 100644 index 000000000..b000d5962 --- /dev/null +++ b/src/stories/Library/media-container/MediaContainer.tsx @@ -0,0 +1,30 @@ +import clsx from "clsx"; +import { FC, ReactNode } from "react"; + +type ImageCreditedProps = { + media?: ReactNode; + placeholderText?: string; +}; + +const MediaContainer: FC = ({ + media, + placeholderText = "", +}) => { + const classes = clsx("media-container", { + "media-container--placeholder": !media, + }); + + return ( +
+ {media ? ( +
{media}
+ ) : ( +
+ {placeholderText} +
+ )} +
+ ); +}; + +export default MediaContainer; diff --git a/src/stories/Library/media-container/media-container.scss b/src/stories/Library/media-container/media-container.scss new file mode 100644 index 000000000..ccc7aacec --- /dev/null +++ b/src/stories/Library/media-container/media-container.scss @@ -0,0 +1,62 @@ +@mixin media-container--grid { + .media-container { + .media-container__placeholder-text { + @include typography($typo__card-placeholder--grid); + } + } +} + +@mixin media-container--card { + .media-container { + .media-container__placeholder-text { + @include typography($typo__card-placeholder); + } + } +} + +@mixin media-container--small { + .media-container { + &--placeholder { + @include identity-placeholder($placeholder-paddings--small); + } + + .media-container__placeholder-text { + font-size: 14px; + line-height: 16px; + padding: $s-md; + } + } +} + +.media-container { + height: 100%; + width: 100%; + + &--placeholder { + @include identity-placeholder; + } +} + +.media-container__media { + height: 100%; + width: 100%; + + // This is necessary to make object fit work. + .image-credited__image, + figure, + img { + width: 100%; + height: 100%; + } + + img { + height: 100%; + width: 100%; + object-fit: cover; + object-position: center; + } +} + +.media-container__placeholder-text { + @extend %identity-placeholder-text; +} diff --git a/src/stories/Library/nav-spot/NavSpot.tsx b/src/stories/Library/nav-spot/NavSpot.tsx index f24094752..75fb3028b 100644 --- a/src/stories/Library/nav-spot/NavSpot.tsx +++ b/src/stories/Library/nav-spot/NavSpot.tsx @@ -1,6 +1,6 @@ import { FC, ReactNode } from "react"; -import clsx from "clsx"; import { ReactComponent as Arrow } from "../Arrows/icon-arrow-ui/icon-arrow-ui-large-right.svg"; +import MediaContainer from "../media-container/MediaContainer"; type NavSpotProps = { variant?: string; @@ -17,19 +17,15 @@ const NavSpot: FC = ({ media, placeholderText, }) => { - const classes = clsx("nav-spot", "arrow__hover--right-large", { - "nav-spot--has-no-media": !media, - "nav-spot--has-media": media, - }); - return ( -
+
-
- {media || ( -
{placeholderText}
- )} -
+
+ +

{title}

diff --git a/src/stories/Library/nav-spot/nav-spot.scss b/src/stories/Library/nav-spot/nav-spot.scss index 322f041e7..506507c06 100644 --- a/src/stories/Library/nav-spot/nav-spot.scss +++ b/src/stories/Library/nav-spot/nav-spot.scss @@ -23,17 +23,6 @@ $_text-padding: $s-xl; .nav-spot__media { aspect-ratio: 16/9; - - * { - height: 100%; - } - - img { - height: 100%; - width: 100%; - object-fit: cover; - object-position: center; - } } @include media-query__medium("max-width") { @@ -48,16 +37,6 @@ $_text-padding: $s-xl; @extend %nav-spot--default; } -.nav-spot--has-no-media { - .nav-spot__media { - @extend %identity-placeholder; - } -} - -.nav-spot__placeholder-text { - @extend %identity-placeholder-text; -} - %nav-spot--large, .nav-spot[data-variant="large"] { background-color: white; diff --git a/src/stories/Library/opening-hours-editor/OpeningHoursForm.tsx b/src/stories/Library/opening-hours-editor/OpeningHoursForm.tsx new file mode 100644 index 000000000..f8299be32 --- /dev/null +++ b/src/stories/Library/opening-hours-editor/OpeningHoursForm.tsx @@ -0,0 +1,100 @@ +import React from "react"; + +const OpeningHoursForm = () => { + const openingHoursCategories = [ + { + title: "Åbent", + color: "blue", + }, + { + title: "Selvbetjening", + color: "yellow", + }, + { + title: "Med betjening", + color: "green", + }, + { + title: "Telefontid", + color: "grey", + }, + { + title: "Borgerservice", + color: "orange", + }, + { + title: "Børneetagen", + color: "lightblue", + }, + { + title: "Makerlab", + color: "purple", + }, + ]; + + const [category, setCategory] = React.useState(openingHoursCategories[0]); + const [startTime, setStartTime] = React.useState("08:00"); + const [endTime, setEndTime] = React.useState("16:00"); + + return ( +
+ + + + setStartTime(e.target.value)} + /> + + setEndTime(e.target.value)} + min={startTime} + max="00:00" + /> + +
+ ); +}; + +export default OpeningHoursForm; diff --git a/src/stories/Library/opening-hours-editor/opening-hours-editor.scss b/src/stories/Library/opening-hours-editor/opening-hours-editor.scss new file mode 100644 index 000000000..09c61ab63 --- /dev/null +++ b/src/stories/Library/opening-hours-editor/opening-hours-editor.scss @@ -0,0 +1,66 @@ +// The Opening Hours Editor utilizes the Dialog component. +// We aim to consolidate all Opening Hours Editor styles into a single file. +// Because is used in drupal admin area +@import "../dialog/dialog"; +.opening-hours-editor-form { + display: grid; + background: #f8f8f8; + padding: 2.5rem; + min-width: 300px; + line-height: 1; +} + +.opening-hours-editor-form__label { + font-weight: bold; + color: #333; + margin-top: 0.75rem; + margin-bottom: 0.5rem; +} + +.opening-hours-editor-form__select, +.opening-hours-editor-form__time-input { + border: 2px solid #ddd; + border-radius: 0.5rem; + padding: 0.5rem; + color: #555; + background-color: #fff; +} + +.opening-hours-editor-form__submit, +.opening-hours-editor-form__remove { + cursor: pointer; + margin-top: 1rem; + color: #fff; + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + transition: background-color 0.3s; +} + +.opening-hours-editor-form__submit { + border: 0; + background-color: #22c55e; + + &:hover { + background-color: #15803d; + } +} + +.opening-hours-editor-form__remove { + border: 0; + background-color: #ef4444; + + &:hover { + background-color: #dc2626; + } +} + +.opening-hours-editor-event-content { + padding: 5px 10px; + cursor: pointer; +} + +// Override Drupal's default margin for tables inside .fc to eliminate top and bottom spacing +// Fixes the issue where the selected hour starts half an hour later than the actual selection. +.fc table { + margin: 0; +} diff --git a/src/stories/Library/opening-hours/OpeningHours.stories.tsx b/src/stories/Library/opening-hours/OpeningHours.stories.tsx new file mode 100644 index 000000000..411c35c91 --- /dev/null +++ b/src/stories/Library/opening-hours/OpeningHours.stories.tsx @@ -0,0 +1,37 @@ +import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; + +import OpeningHours from "./OpeningHours"; +import { groupedOpeningHoursExampleData } from "./OpeningHoursExampleData"; + +export default { + title: "Library / Opening Hours", + component: OpeningHours, + decorators: [withDesign], + argTypes: { + weekCurrentlyDisplayed: { + defaultValue: "Uge 4, 2023", + control: { + type: "text", + }, + }, + groupedOpeningHours: { + defaultValue: groupedOpeningHoursExampleData, + control: { + type: "object", + }, + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=7486-63527&mode=design&t=9DUvbqMhUcaeDTKR-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Default = Template.bind({}); diff --git a/src/stories/Library/opening-hours/OpeningHours.tsx b/src/stories/Library/opening-hours/OpeningHours.tsx new file mode 100644 index 000000000..a1b882a4e --- /dev/null +++ b/src/stories/Library/opening-hours/OpeningHours.tsx @@ -0,0 +1,46 @@ +import { FC } from "react"; +import { ReactComponent as ArrowLeft } from "../../../public/icons/collection/ArrowLeft.svg"; +import { ReactComponent as ArrowRight } from "../../../public/icons/collection/ArrowRight.svg"; +import { GroupedOpeningHours } from "./OpeningHoursExampleData"; +import OpeningHoursWeekList from "./OpeningHoursWeekList"; + +type OpeningHoursProps = { + title: string; + weekCurrentlyDisplayed: string; + groupedOpeningHours: GroupedOpeningHours; +}; + +const OpeningHours: FC = ({ + groupedOpeningHours, + weekCurrentlyDisplayed, +}) => { + return ( +
+
+

Åbningstider

+
+ +
+ {weekCurrentlyDisplayed} +
+ +
+
+ +
+ ); +}; + +export default OpeningHours; diff --git a/src/stories/Library/opening-hours/OpeningHoursDayEntry.tsx b/src/stories/Library/opening-hours/OpeningHoursDayEntry.tsx new file mode 100644 index 000000000..54240d31e --- /dev/null +++ b/src/stories/Library/opening-hours/OpeningHoursDayEntry.tsx @@ -0,0 +1,20 @@ +import { FC } from "react"; +import { DplOpeningHoursListGET200Item } from "./OpeningHoursExampleData"; + +type OpeningHoursDayEntryProps = { + data: DplOpeningHoursListGET200Item; +}; + +const OpeningHoursDayEntry: FC = ({ data }) => { + const { start_time: startTime, end_time: endTime, category } = data; + return ( +
  • +
    {category.title}
    +
    + {startTime} - {endTime} +
    +
  • + ); +}; + +export default OpeningHoursDayEntry; diff --git a/src/stories/Library/opening-hours/OpeningHoursExampleData.ts b/src/stories/Library/opening-hours/OpeningHoursExampleData.ts new file mode 100644 index 000000000..c933957e7 --- /dev/null +++ b/src/stories/Library/opening-hours/OpeningHoursExampleData.ts @@ -0,0 +1,250 @@ +// These types are based on the actual data structure returned from the API. +// The types starting with DplOpeningHours.. are generated with Orval in react +// and copy pasted here. +export type DplOpeningHoursListGET200Item = { + /** An serial unique id of the opening hours instance. */ + id: number; + category: DplOpeningHoursListGET200ItemCategory; + /** The date which the opening hours applies to. In ISO 8601 format. */ + date: string; + /** When the opening hours start. In format HH:MM */ + start_time: string; + /** When the opening hours end. In format HH:MM */ + end_time: string; + /** The id for the branch the instance belongs to */ + branch_id: number; +}; +export type DplOpeningHoursListGET200ItemCategory = { + title: string; + /** A CSS compatible color code which can be used to represent the category */ + color: string; +}; + +export type GroupedOpeningHours = Array<{ + day: string; + date: string; + openingHourEntries: DplOpeningHoursListGET200Item[]; +}>; + +// Example data in the format it is used in the grouped opening hours component +export const groupedOpeningHoursExampleData: GroupedOpeningHours = [ + { + day: "Mandag", + date: "2024-03-18", + openingHourEntries: [ + { + id: 0, + category: { + title: "Åbent", + color: "#0000FF", + }, + date: "2024-03-18", + start_time: "09:00", + end_time: "12:00", + branch_id: 1, + }, + { + id: 1, + category: { + title: "Selvbetjening", + color: "#FF0000", + }, + date: "2024-03-18", + start_time: "13:00", + end_time: "16:00", + branch_id: 1, + }, + { + id: 2, + category: { + title: "Med betjening", + color: "#008000", + }, + date: "2024-03-18", + start_time: "17:00", + end_time: "19:00", + branch_id: 1, + }, + ], + }, + { + day: "Tirsdag", + date: "2024-03-19", + openingHourEntries: [ + { + id: 3, + category: { + title: "Telefontid", + color: "#FFFF00", + }, + date: "2024-03-19", + start_time: "08:00", + end_time: "10:00", + branch_id: 1, + }, + { + id: 4, + category: { + title: "Borgerservice", + color: "#0000FF", + }, + date: "2024-03-19", + start_time: "11:00", + end_time: "13:00", + branch_id: 1, + }, + { + id: 5, + category: { + title: "Børneetagen", + color: "#FF0000", + }, + date: "2024-03-19", + start_time: "14:00", + end_time: "17:00", + branch_id: 1, + }, + ], + }, + { + day: "Onsdag", + date: "2024-03-20", + openingHourEntries: [ + { + id: 6, + category: { + title: "Makerlab", + color: "#0000FF", + }, + date: "2024-03-20", + start_time: "09:00", + end_time: "12:00", + branch_id: 1, + }, + { + id: 7, + category: { + title: "Åbent", + color: "#008000", + }, + date: "2024-03-20", + start_time: "13:00", + end_time: "15:00", + branch_id: 1, + }, + { + id: 8, + category: { + title: "Selvbetjening", + color: "#FFFF00", + }, + date: "2024-03-20", + start_time: "16:00", + end_time: "19:00", + branch_id: 1, + }, + ], + }, + { + day: "Torsdag", + date: "2024-03-21", + openingHourEntries: [ + { + id: 9, + category: { + title: "Med betjening", + color: "#0000FF", + }, + date: "2024-03-21", + start_time: "09:00", + end_time: "11:00", + branch_id: 1, + }, + { + id: 10, + category: { + title: "Telefontid", + color: "#FF0000", + }, + date: "2024-03-21", + start_time: "12:00", + end_time: "14:00", + branch_id: 1, + }, + { + id: 11, + category: { + title: "Borgerservice", + color: "#008000", + }, + date: "2024-03-21", + start_time: "15:00", + end_time: "18:00", + branch_id: 1, + }, + ], + }, + { + day: "Fredag", + date: "2024-03-22", + openingHourEntries: [ + { + id: 12, + category: { + title: "Børneetagen", + color: "#0000FF", + }, + date: "2024-03-22", + start_time: "10:00", + end_time: "13:00", + branch_id: 1, + }, + ], + }, + { + day: "Lørdag", + date: "2024-03-23", + openingHourEntries: [], + }, + { + day: "Søndag", + date: "2024-03-24", + openingHourEntries: [ + { + id: 18, + category: { + title: "Borgerservice", + color: "#008000", + }, + date: "2024-03-24", + start_time: "10:00", + end_time: "13:00", + branch_id: 1, + }, + { + id: 19, + category: { + title: "Børneetagen", + color: "#FFFF00", + }, + date: "2024-03-24", + start_time: "14:00", + end_time: "18:00", + branch_id: 1, + }, + { + id: 20, + category: { + title: "Makerlab", + color: "#0000FF", + }, + date: "2024-03-24", + start_time: "19:00", + end_time: "21:00", + branch_id: 1, + }, + ], + }, +]; + +export default groupedOpeningHoursExampleData; diff --git a/src/stories/Library/opening-hours/OpeningHoursWeekList.tsx b/src/stories/Library/opening-hours/OpeningHoursWeekList.tsx new file mode 100644 index 000000000..427092c11 --- /dev/null +++ b/src/stories/Library/opening-hours/OpeningHoursWeekList.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import OpeningHoursDayEntry from "./OpeningHoursDayEntry"; +import { GroupedOpeningHours } from "./OpeningHoursExampleData"; + +type OpeningHoursWeekListProps = { + groupedOpeningHours: GroupedOpeningHours; +}; + +const OpeningHoursWeekList: React.FC = ({ + groupedOpeningHours, +}) => { + return ( +
      + {groupedOpeningHours.map(({ day, date, openingHourEntries }) => { + const formattedDateForDisplay = new Date(date).toLocaleDateString( + "da-DK", + { + day: "numeric", + month: "2-digit", + } + ); + + return ( +
    1. +

      + {`${day}:`} + +

      + {openingHourEntries.length > 0 ? ( +
        + {openingHourEntries.map((item) => ( + + ))} +
      + ) : ( +

      + Biblioteket er lukket denne dag. +

      + )} +
    2. + ); + })} +
    + ); +}; + +export default OpeningHoursWeekList; diff --git a/src/stories/Library/opening-hours/opening-hours-skeleton.scss b/src/stories/Library/opening-hours/opening-hours-skeleton.scss new file mode 100644 index 000000000..7db963fed --- /dev/null +++ b/src/stories/Library/opening-hours/opening-hours-skeleton.scss @@ -0,0 +1,13 @@ +.opening-hours { + .ssc-line { + height: $s-xl; + } + .ssc-line--odd { + opacity: 0.5; + } + .ssc-line-headline { + height: 26px; + margin-bottom: $s-md; + width: 100px; + } +} diff --git a/src/stories/Library/opening-hours/opening-hours.scss b/src/stories/Library/opening-hours/opening-hours.scss new file mode 100644 index 000000000..7ab316538 --- /dev/null +++ b/src/stories/Library/opening-hours/opening-hours.scss @@ -0,0 +1,86 @@ +$_nav-control-height: 40px; +$_nav-control-border-width: 2px; +$_opening-hours-max-width: 600px; + +.opening-hours { + @include layout-container; +} + +.opening-hours__header { + display: flex; + justify-content: space-between; + flex-direction: column; + gap: $s-lg; + margin-bottom: $s-lg; + align-items: center; + max-width: $_opening-hours-max-width; + + @include media-query__small { + flex-direction: row; + } +} + +.opening-hours__content { + max-width: $_opening-hours-max-width; +} + +.opening-hours__heading { + @include typography($typo__h3); + align-self: flex-start; +} + +.opening-hours__row { + padding: $s-md 0 $s-lg 0; + border-bottom: 1px solid $color__global-tertiary-1; + @include typography($typo__body-placeholder); +} + +.opening-hours__individual-day { + @include typography($typo__body-medium); + font-weight: $font__weight--bold; + margin-bottom: $s-md; + @include media-query__small { + @include typography($typo__body-large); + font-weight: $font__weight--bold; + } +} + +.opening-hours__individual-opening { + display: flex; + justify-content: space-between; + padding: 0 $s-xs; + @include media-query__small { + line-height: 32px; + } +} +.opening-hours__individual-opening:nth-child(odd) { + background-color: $color__global-tertiary-1; +} + +.opening-hours__row:first-child { + border-top: 1px solid $color__global-tertiary-1; +} + +.opening-hours__navigation-controls { + display: flex; + gap: $s-sm; +} + +.opening-hours__navigation-control { + width: 40px; + height: $_nav-control-height; + background-color: $color__global-primary; + border: $_nav-control-border-width solid $color__global-tertiary-1; + display: flex; + justify-content: center; + align-items: center; +} + +.opening-hours__week-display { + border: $_nav-control-border-width solid $color__global-tertiary-1; + height: $_nav-control-height; + display: flex; + align-items: center; + gap: $s-xs; + padding: $s-xs $s-md; +} diff --git a/src/styles/scss/tools/placeholder.scss b/src/styles/scss/tools/placeholder.scss index da2d622ec..ee28135c3 100644 --- a/src/styles/scss/tools/placeholder.scss +++ b/src/styles/scss/tools/placeholder.scss @@ -82,11 +82,11 @@ @include typography($typo__body-small); } -@mixin identity-placeholder { +@mixin identity-placeholder($paddings: $placeholder-paddings) { background-color: var(--tint-color-120); border: $s-lg solid $color__identity-primary; - @each $breakpoint-name, $width in $placeholder-paddings { + @each $breakpoint-name, $width in $paddings { @include media-query__name($breakpoint-name) { border-width: $width; } diff --git a/src/styles/scss/tools/variables.spacings.scss b/src/styles/scss/tools/variables.spacings.scss index 98445bf8a..56cf7ea6b 100644 --- a/src/styles/scss/tools/variables.spacings.scss +++ b/src/styles/scss/tools/variables.spacings.scss @@ -29,3 +29,9 @@ $placeholder-paddings: ( small: $s-xl, medium: $s-2xl, ); + +$placeholder-paddings--small: ( + mobile: $s-md, + small: $s-lg, + medium: $s-xl, +);