Skip to content

Commit

Permalink
Merge pull request #684 from danskernesdigitalebibliotek/develop
Browse files Browse the repository at this point in the history
Release 2024.28.0
  • Loading branch information
kasperg authored Jul 10, 2024
2 parents 50a60f2 + 2836266 commit 100e48a
Show file tree
Hide file tree
Showing 19 changed files with 477 additions and 16 deletions.
1 change: 1 addition & 0 deletions base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
@import "./src/stories/Library/filtered-event-list/filtered-event-list";
@import "./src/stories/Library/event-list-stacked/event-list-stacked";
@import "./src/stories/Library/material-search/material-search";
@import "./src/stories/Library/banner/banner";

// Autosuggest block styling needs to be loaded before the rest of the scss for autosuggest
@import "./src/stories/Blocks/autosuggest/autosuggest";
Expand Down
3 changes: 3 additions & 0 deletions public/icons/basic/icon-underlined.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 72 additions & 0 deletions src/stories/Library/banner/Banner.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import Banner from "./Banner";

export default {
title: "Library / Banner",
component: Banner,
decorators: [withDesign],
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/design/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?node-id=446-6957&t=IWAOniAbcjV2y2Hf-4",
},
},
argTypes: {
imageSrc: {
defaultValue: "images/campaign_cover.jpg",
control: { type: "text" },
},
title: {
name: "Title",
defaultValue: "Hvad skal jeg <u>høre?</u>",
control: { type: "text" },
},
description: {
name: "Description",
defaultValue:
"Om du er dedikeret musiknørd eller moderat musikinteresseret, så er dette siden til dig. Her kan du finde anbefalinger, digitale musikmagasiner, nyheder, musiklitteratur og meget mere.",
control: { type: "text" },
},
link: {
name: "Link",
defaultValue: "#",
control: { type: "text" },
},
},
} as ComponentMeta<typeof Banner>;

const Template: ComponentStory<typeof Banner> = (args) => <Banner {...args} />;

export const Default = Template.bind({});

export const NoImage = Template.bind({});
NoImage.args = {
imageSrc: undefined,
};

export const NoImageOnlyTitle = Template.bind({});
NoImageOnlyTitle.args = {
title: "Title <u>uden</u> billede",
imageSrc: undefined,
description: undefined,
};

export const NoImageOnlyDescription = Template.bind({});
NoImageOnlyDescription.args = {
title: undefined,
imageSrc: undefined,
description:
"Om du er dedikeret musiknørd eller moderat musikinteresseret, så er dette siden til dig. Her kan du finde anbefalinger, digitale musikmagasiner, nyheder, musiklitteratur og meget mere.",
};

export const WithImageOnlyTitle = Template.bind({});
WithImageOnlyTitle.args = {
title: "Banner <u>uden</u> beskrivelse",
description: undefined,
};
export const WithImageOnlyDescription = Template.bind({});
WithImageOnlyDescription.args = {
description:
"Om du er dedikeret musiknørd eller moderat musikinteresseret, så er dette siden til dig. Her kan du finde anbefalinger, digitale musikmagasiner, nyheder, musiklitteratur og meget mere.",
};
46 changes: 46 additions & 0 deletions src/stories/Library/banner/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import clsx from "clsx";
import { FC, ReactNode } from "react";
import { ReactComponent as ArrowLargeRight } from "../Arrows/icon-arrow-ui/icon-arrow-ui-large-right.svg";

type BannerType = {
link: string;
title: string;
imageSrc?: ReactNode;
description?: string;
};

const Banner: FC<BannerType> = ({ link, imageSrc, title, description }) => {
const backgroundImageStyle = imageSrc
? { backgroundImage: `url(${imageSrc})` }
: {};
return (
<a
href={link}
className={clsx(`banner arrow__hover--right-large`, {
"banner--has-image": imageSrc,
})}
style={backgroundImageStyle}
>
<div className="banner__content-wrapper">
<div
className={clsx("banner__content", {
"banner__content--has-image": imageSrc,
})}
>
{title && (
<h2
className="banner__title"
// We need to be able to replicate our WYSIWYG field in Drupal that makes it possible to underline (<u>) words.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: title }}
/>
)}
{description && <p className="banner__description">{description}</p>}
<ArrowLargeRight />
</div>
</div>
</a>
);
};

export default Banner;
79 changes: 79 additions & 0 deletions src/stories/Library/banner/banner.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
$_banner-content-wrapper-width: 944px;
$_banner-content-max-width-small: 330px;
$_banner-content-max-width-medium: 569px;
$_banner-content-no-image-max-width-small: $layout__max-width--small;
$_banner-height-small: 500px;
$_banner-height-medium: 810px;

.banner {
@include layout-container($layout__max-width--large, 0);

display: grid;
align-items: center;
text-decoration: none;
box-sizing: border-box;
background-color: $color__global-secondary;
min-height: $_banner-height-small;

&--has-image {
background-repeat: no-repeat;
background-position: center;
background-size: cover;
height: 100%;
width: 100%;
}

@include media-query__small {
min-height: $_banner-height-medium;
}
}

.banner__content-wrapper {
@include layout-container($_banner-content-wrapper-width, 0);
width: 100%;
padding: $s-2xl 0;

&--has-image {
padding-right: $s-2xl;
}

@include media-query__small {
padding-right: unset;
}
}

.banner__content {
display: flex;
flex-direction: column;
align-items: center;
gap: $s-md;
text-align: center;
padding: $s-xl;
margin: 0 auto;
max-width: $_banner-content-max-width-medium;

&--has-image {
padding: $s-xl;
margin: unset;
text-align: unset;
align-items: unset;
background-color: $color__global-white;
max-width: $_banner-content-max-width-small;
}

@include media-query__small {
gap: $s-lg;
padding: calc($s-2xl + 6px);
max-width: $_banner-content-max-width-medium;
}
}

.banner__title {
@include typography($typo__h2);
@include u-extending-underline-style;
}

.banner__description {
@include typography($typo__body-placeholder);
line-height: 160%;
}
5 changes: 4 additions & 1 deletion src/stories/Library/cover/Cover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Cover: FC<CoverProps> = ({
alt,
shadow,
ariaLabel = "Link to the material",
isHiddenFromScreenReaders,
}) => {
const [imageLoaded, setImageLoaded] = useState<boolean | null>(null);

Expand All @@ -28,7 +29,7 @@ const Cover: FC<CoverProps> = ({
),
};

if (coverUrl && alt) {
if (coverUrl) {
// Images inside links must have an non-empty alt text to meet accessibility requirements.
// Only render the cover as a link if we have both an url and a description.
return (
Expand All @@ -38,6 +39,8 @@ const Cover: FC<CoverProps> = ({
aria-label={ariaLabel}
aria-labelledby="cover labelled by"
title="cover title text"
tabIndex={isHiddenFromScreenReaders ? -1 : 0}
aria-hidden={isHiddenFromScreenReaders}
>
<CoverImage
setImageLoaded={() => setImageLoaded(true)}
Expand Down
1 change: 1 addition & 0 deletions src/stories/Library/cover/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export type CoverProps = {
alt?: string;
shadow?: "small" | "medium";
ariaLabel?: string;
isHiddenFromScreenReaders?: boolean;
};
7 changes: 7 additions & 0 deletions src/stories/Library/material-search/Errors/ErrorState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const enum ErrorState {
NoError = "NoError",
WorkError = "WorkError",
MaterialTypeError = "MaterialTypeError",
}

export default ErrorState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import { ReactComponent as WarningIcon } from "../../../../public/icons/basic/icon-warning.svg";

interface MaterialSearchBaseErrorProps {
children: React.ReactNode;
}

const MaterialSearchBaseError: React.FC<MaterialSearchBaseErrorProps> = ({
children,
}) => {
return (
<div className="material-search__error">
<div className="material-search__error-header">
<WarningIcon className="material-search__error-icon" />
<h3 className="material-search__error-header-text">
This material is outdated.
</h3>
</div>
{children}
</div>
);
};

export default MaterialSearchBaseError;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { PreviewData } from "../MaterialSearchExampleData";
import MaterialSearchBaseError from "./MaterialSearchBaseError";

const MaterialTypeNotFoundError: React.FC = () => {
const { protocol } = window.location;

const exampleUrl = `${protocol}/hostname/work/${PreviewData.workId}`;

return (
<MaterialSearchBaseError>
<div className="material-search__error-content">
<p className="material-search__error-description">
The currently selected type of the material is no longer available in
the system. As a result of this, the link is likely broken. Use the
title or link underneath to find and update the material and its type.
</p>
<div className="material-search__error-material-content">
<div className="material-search__error-item">
<span className="material-search__error-term">Title:</span>
<span className="material-search__error-detail">
{PreviewData.title}
</span>
</div>
<div className="material-search__error-item">
<span className="material-search__error-term">Author:</span>
<span className="material-search__error-detail">
{PreviewData.author}
</span>
</div>
<div className="material-search__error-item">
<span className="material-search__error-term">Link: </span>
<a
href={exampleUrl}
target="_blank"
className="material-search__error-link"
rel="noreferrer noopener"
>
{exampleUrl}
</a>
</div>
</div>
</div>
</MaterialSearchBaseError>
);
};

export default MaterialTypeNotFoundError;
18 changes: 18 additions & 0 deletions src/stories/Library/material-search/Errors/WorkNotFoundError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import MaterialSearchBaseError from "./MaterialSearchBaseError";

const WorkNotFoundError: React.FC = () => {
return (
<MaterialSearchBaseError>
<div className="material-search__error-content">
<p className="material-search__error-description">
The material that was previously selected is no longer available in
the system. Either delete this entry or search for a new material to
replace it.
</p>
</div>
</MaterialSearchBaseError>
);
};

export default WorkNotFoundError;
28 changes: 24 additions & 4 deletions src/stories/Library/material-search/MaterialSearch.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { ComponentMeta, ComponentStory } from "@storybook/react";

import MaterialSearch from "./MaterialSearch";
import ErrorState from "./Errors/ErrorState";

export default {
title: "Library / Material Search",
component: MaterialSearch,
argTypes: {},
argTypes: {
errorState: {
control: {
type: "select",
options: ["NoError", "WorkError", "MaterialTypeError"],
},
},
},
args: {
errorState: "NoError",
},
} as ComponentMeta<typeof MaterialSearch>;

const uniqueIdentifier = Math.floor(Math.random() * 10000);

const Template: ComponentStory<typeof MaterialSearch> = () => {
const Template: ComponentStory<typeof MaterialSearch> = (args) => {
return (
<div className="material-search">
<div className="material-search__inputs-container">
Expand Down Expand Up @@ -43,9 +53,19 @@ const Template: ComponentStory<typeof MaterialSearch> = () => {
</label>
</div>

<MaterialSearch />
<MaterialSearch {...args} />
</div>
);
};

export const Default = Template.bind({});

export const withWorkError = Template.bind({});
withWorkError.args = {
errorState: ErrorState.WorkError,
};

export const withMaterialTypeError = Template.bind({});
withMaterialTypeError.args = {
errorState: ErrorState.MaterialTypeError,
};
Loading

0 comments on commit 100e48a

Please sign in to comment.