diff --git a/src/components/card/card.scss b/src/components/card/card.scss index 8d381e9d..da48a37c 100644 --- a/src/components/card/card.scss +++ b/src/components/card/card.scss @@ -4,7 +4,6 @@ box-sizing: border-box; display: flex; flex-direction: column; - //overflow: clip; // Turned off for now to allow DatePicker to overflow Card and Modal. width: 100%; &__header { @@ -16,4 +15,35 @@ & + & { margin-block-start: var(--spacing-v); } + + &--halign-start { + align-items: flex-start; + text-align: left; + } + + &--halign-center { + align-items: center; + text-align: center; + } + + &--halign-end { + align-items: flex-end; + text-align: right; + } + + &--valign-start { + justify-content: flex-start; + } + + &--valign-center { + justify-content: center; + } + + &--valign-end { + justify-content: flex-end; + } + + &--shadow { + box-shadow: 0px 0px 5px 0.5px var(--page-color-shadow); + } } diff --git a/src/components/card/card.tsx b/src/components/card/card.tsx index 0ff98e4a..628ae8f8 100644 --- a/src/components/card/card.tsx +++ b/src/components/card/card.tsx @@ -8,6 +8,9 @@ import "./card.scss"; export type CardProps = React.PropsWithChildren<{ controls?: ButtonProps[]; title?: string | React.ReactNode; + halign?: "start" | "center" | "end"; + valign?: "start" | "center" | "end"; + shadow?: boolean; }>; /** @@ -17,9 +20,17 @@ export const Card: React.FC = ({ controls = [], children, title, + halign = "start", + valign = "start", + shadow = false, ...props }) => ( -
+
{(controls.length || title) && (
diff --git a/src/components/layout/page/page.scss b/src/components/layout/page/page.scss index 5876633f..bacba2ca 100644 --- a/src/components/layout/page/page.scss +++ b/src/components/layout/page/page.scss @@ -27,3 +27,32 @@ justify-content: center; } } + +.mykn-background-image { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; /* Ensure it is behind the content */ + + &__background { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + } + + &__overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: black; /* Black overlay */ + } +} diff --git a/src/components/layout/page/page.tsx b/src/components/layout/page/page.tsx index 6fc776a7..a62a623b 100644 --- a/src/components/layout/page/page.tsx +++ b/src/components/layout/page/page.tsx @@ -9,6 +9,12 @@ export type PageProps = React.PropsWithChildren<{ /** Whether to apply padding to the page. */ pad?: boolean | "h" | "v"; + + /** A background image */ + backgroundImageUrl?: string; + + /** The background image opacity */ + backgroundOverlayOpacity?: number; }>; /** @@ -18,16 +24,53 @@ export const Page: React.FC = ({ children, pad = false, valign, + backgroundImageUrl, + backgroundOverlayOpacity = 0.5, ...props +}) => { + return ( +
+ {backgroundImageUrl && ( + + )} + {children} +
+ ); +}; + +export type BackgroundImageProps = React.PropsWithChildren<{ + backgroundImageUrl: string; + backgroundOverlayOpacity: number; +}>; + +/** + * BackgroundImage component + * @param children + * @param props + * @constructor + */ +const BackgroundImage: React.FC = ({ + backgroundImageUrl, + backgroundOverlayOpacity, }) => ( -
- {children} +
+
+
); diff --git a/src/lib/i18n/compiled/en.json b/src/lib/i18n/compiled/en.json index 9ee3c0b3..5137066c 100644 --- a/src/lib/i18n/compiled/en.json +++ b/src/lib/i18n/compiled/en.json @@ -37,5 +37,8 @@ "mykn.components.Select.labelClear": "clear value", "mykn.components.Sidebar.collapse": "Collapse sidebar", "mykn.components.Sidebar.expand": "Expand sidebar", - "mykn.templates.Login.labelLogin": "inloggen" -} \ No newline at end of file + "mykn.templates.Login.labelLogin": "inloggen", + "mykn.templates.Login.titleLogin": "Welcome back", + "mykn.templates.Login.titlePasswordForgotten": "Password forgotten?", + "mykn.templates.Login.linkPasswordForgotten": "Click here" +} diff --git a/src/lib/i18n/compiled/nl.json b/src/lib/i18n/compiled/nl.json index c556ff63..0f834ae0 100644 --- a/src/lib/i18n/compiled/nl.json +++ b/src/lib/i18n/compiled/nl.json @@ -37,5 +37,8 @@ "mykn.components.Select.labelClear": "waarde wissen", "mykn.components.Sidebar.collapse": "Zijbalk inklappen", "mykn.components.Sidebar.expand": "Zijbalk uitklappen", - "mykn.templates.Login.labelLogin": "inloggen" -} \ No newline at end of file + "mykn.templates.Login.labelLogin": "inloggen", + "mykn.templates.Login.titleLogin": "Welkom terug", + "mykn.templates.Login.titlePasswordForgotten": "Wachtwoord vergeten?", + "mykn.templates.Login.linkPasswordForgotten": "Klik hier" +} diff --git a/src/lib/i18n/messages/en.json b/src/lib/i18n/messages/en.json index 6eeda7d8..55f42a4e 100644 --- a/src/lib/i18n/messages/en.json +++ b/src/lib/i18n/messages/en.json @@ -193,5 +193,20 @@ "defaultMessage": "inloggen", "description": "templates.Login: The login button label", "originalDefault": "inloggen" + }, + "mykn.templates.Login.titleLogin": { + "defaultMessage": "Welcome back", + "description": "templates.Login: The login title", + "originalDefault": "Welkom terug" + }, + "mykn.templates.Login.titlePasswordForgotten": { + "defaultMessage": "Password forgotten?", + "description": "templates.Login: The password forgotten title", + "originalDefault": "Wachtwoord vergeten?" + }, + "mykn.templates.Login.linkPasswordForgotten": { + "defaultMessage": "Click here", + "description": "templates.Login: The link to the password forgotten page", + "originalDefault": "Klik hier" } } diff --git a/src/lib/i18n/messages/nl.json b/src/lib/i18n/messages/nl.json index 0d4a6e43..d9e18fac 100644 --- a/src/lib/i18n/messages/nl.json +++ b/src/lib/i18n/messages/nl.json @@ -193,5 +193,20 @@ "defaultMessage": "inloggen", "description": "templates.Login: The login button label", "originalDefault": "inloggen" + }, + "mykn.templates.Login.titleLogin": { + "defaultMessage": "Welkom terug", + "description": "templates.Login: The login title", + "originalDefault": "Welkom terug" + }, + "mykn.templates.Login.titlePasswordForgotten": { + "defaultMessage": "Wachtwoord vergeten?", + "description": "templates.Login: The password forgotten title", + "originalDefault": "Wachtwoord vergeten?" + }, + "mykn.templates.Login.linkPasswordForgotten": { + "defaultMessage": "Klik hier", + "description": "templates.Login: The link to the password forgotten page", + "originalDefault": "Klik hier" } } diff --git a/src/templates/base/base.tsx b/src/templates/base/base.tsx index ec7883f0..b54967d6 100644 --- a/src/templates/base/base.tsx +++ b/src/templates/base/base.tsx @@ -27,6 +27,9 @@ export type BaseTemplateProps = React.PropsWithChildren & { /** Primary navigation items. */ primaryNavigationItems?: ToolbarItem[]; + /** Background image */ + backgroundImageUrl?: string; + /** Sidebar items. */ sidebarItems?: ToolbarItem[]; diff --git a/src/templates/login/login.stories.tsx b/src/templates/login/login.stories.tsx index 82180879..26bd05e4 100644 --- a/src/templates/login/login.stories.tsx +++ b/src/templates/login/login.stories.tsx @@ -29,3 +29,24 @@ export const loginTemplate: Story = { labelLogin: "Log in", }, }; + +export const loginTemplateWithBackground: Story = { + args: { + formProps: { + autoComplete: "off", + fields: [ + { + label: "Gebruikersnaam", + name: "username", + }, + { + label: "Wachtwoord", + name: "Password", + }, + ], + }, + labelLogin: "Log in", + backgroundImageUrl: + "https://s3-alpha-sig.figma.com/img/18d5/48c4/f78435ff97a760d6c9433645c785f392?Expires=1724025600&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4&Signature=MFKwLX5b6hitZ-uchYo3jmmQD4cpkCdj3czvBiQ93Fxw6BNpTpm4mrPkt6RqEfr6eE2gUQJ~qZjOOdrm2sRmwQmz1XXaLC41eDGcXrvr478IL39PjsrpRX4lsetP2lBGO0wtWu3nVl-9-ubqGqA1qY~2PmnOhAjZ7BiQ4IQRTfe6IT3BN3Ty7wfeIFP8tvyMrsTPE1vNgwBgfC8G~N0cCJ7uuxwv9T-54FFpDvDKQb~Dd2svIGIoUFfl8~E~AMUtPyVLFmUdeDXuK4yUyiwTWtncIPnA~GgeI~em0L~OYmqbh-otzZgWBTLngDZxzUhjyYIKkYGI3sNGYeW8oyGygQ__", + }, +}; diff --git a/src/templates/login/login.tsx b/src/templates/login/login.tsx index 5671bfef..a13d1075 100644 --- a/src/templates/login/login.tsx +++ b/src/templates/login/login.tsx @@ -1,8 +1,8 @@ import React, { useContext } from "react"; -import { Body, Card, Form, FormProps, Hr, Logo } from "../../components"; +import { A, Body, Card, Form, FormProps, H1, Logo, P } from "../../components"; import { ConfigContext } from "../../contexts"; -import { ucFirst } from "../../lib/format/string"; +import { ucFirst } from "../../lib"; import { useIntl } from "../../lib/i18n/useIntl"; import { BaseTemplate, BaseTemplateProps } from "../base"; @@ -12,9 +12,24 @@ export type LoginTemplateProps = BaseTemplateProps & { /** Form props. */ formProps: FormProps; + /** Password Forgotten Href */ + passwordForgottenHref?: string; + /** The login form label. */ labelLogin?: FormProps["labelSubmit"]; + /** The login form title. */ + titleLogin?: string; + + /** The password forgotten title. */ + titlePasswordForgotten?: string; + + /** The password forgotten "click here" link. */ + linkPasswordForgotten?: string; + + /** Background image */ + backgroundImageUrl?: string; + /** Logo (JSX) slot. */ slotLogo?: React.ReactNode; }; @@ -25,7 +40,12 @@ export type LoginTemplateProps = BaseTemplateProps & { */ export const LoginTemplate: React.FC = ({ formProps, + passwordForgottenHref, labelLogin, + titleLogin, + titlePasswordForgotten, + linkPasswordForgotten, + backgroundImageUrl, slotLogo, ...props }) => { @@ -40,18 +60,60 @@ export const LoginTemplate: React.FC = ({ defaultMessage: "inloggen", }); + const _titleLogin = titleLogin + ? titleLogin + : intl.formatMessage({ + id: "mykn.templates.Login.titleLogin", + description: "templates.Login: The login title", + defaultMessage: "Welkom Terug", + }); + + const _titlePasswordForgotten = titlePasswordForgotten + ? titlePasswordForgotten + : intl.formatMessage({ + id: "mykn.templates.Login.titlePasswordForgotten", + description: "templates.Login: The password forgotten title", + defaultMessage: "Wachtwoord vergeten?", + }); + + const _linkPasswordForgotten = linkPasswordForgotten + ? linkPasswordForgotten + : intl.formatMessage({ + id: "mykn.templates.Login.linkPasswordForgotten", + description: "templates.Login: The password forgotten link", + defaultMessage: "Klik hier", + }); + return ( - + {slotLogo || CustomLogo || } -
-
+
+
+

{_titleLogin}

+
+ + {passwordForgottenHref && ( +

+ {_titlePasswordForgotten}{" "} + {_linkPasswordForgotten} +

+ )}