feat: sr2 theme
This commit is contained in:
parent
ab4ff8cd73
commit
0bf045eb85
12 changed files with 7077 additions and 6449 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +1,6 @@
|
||||||
|
# IntelliJ
|
||||||
|
/.idea
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.ico" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
|
||||||
6838
package-lock.json
generated
Normal file
6838
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"name": "keycloakify-starter",
|
"name": "sr2-theme",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"description": "Starter for Keycloakify 11",
|
"description": "SR2 Communications Keycloak Theme",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/codegouvfr/keycloakify-starter.git"
|
"url": "git://guardianproject.dev/sr2/keycloak-theme"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
public/logo-side.png
Normal file
BIN
public/logo-side.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
|
|
@ -1,5 +1,6 @@
|
||||||
// This file is auto-generated by the `update-kc-gen` command. Do not edit it manually.
|
// This file is auto-generated by the `update-kc-gen` command. Do not edit it manually.
|
||||||
// Hash: b0aa286dba4ed04c111c1265bdb6a76ba45c22a3d9b9e8dcf36302267d40c51a
|
// Hash: 072c0f667b4885bf8e22173ffe17f534b5143492fe8f083706bd6d06474e8ee2
|
||||||
|
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
|
|
@ -9,9 +10,9 @@
|
||||||
|
|
||||||
import { lazy, Suspense, type ReactNode } from "react";
|
import { lazy, Suspense, type ReactNode } from "react";
|
||||||
|
|
||||||
export type ThemeName = "keycloakify-starter";
|
export type ThemeName = "sr2-theme";
|
||||||
|
|
||||||
export const themeNames: ThemeName[] = ["keycloakify-starter"];
|
export const themeNames: ThemeName[] = ["sr2-theme"];
|
||||||
|
|
||||||
export type KcEnvName = never;
|
export type KcEnvName = never;
|
||||||
|
|
||||||
|
|
@ -24,7 +25,9 @@ export const kcEnvDefaults: Record<KcEnvName, string> = {};
|
||||||
* If you need to import the KcContext import it either from src/login/KcContext.ts or src/account/KcContext.ts.
|
* If you need to import the KcContext import it either from src/login/KcContext.ts or src/account/KcContext.ts.
|
||||||
* Depending on the theme type you are working on.
|
* Depending on the theme type you are working on.
|
||||||
*/
|
*/
|
||||||
export type KcContext = import("./login/KcContext").KcContext;
|
export type KcContext =
|
||||||
|
| import("./login/KcContext").KcContext
|
||||||
|
;
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
@ -34,14 +37,18 @@ declare global {
|
||||||
|
|
||||||
export const KcLoginPage = lazy(() => import("./login/KcPage"));
|
export const KcLoginPage = lazy(() => import("./login/KcPage"));
|
||||||
|
|
||||||
export function KcPage(props: { kcContext: KcContext; fallback?: ReactNode }) {
|
export function KcPage(
|
||||||
|
props: {
|
||||||
|
kcContext: KcContext;
|
||||||
|
fallback?: ReactNode;
|
||||||
|
}
|
||||||
|
) {
|
||||||
const { kcContext, fallback } = props;
|
const { kcContext, fallback } = props;
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={fallback}>
|
<Suspense fallback={fallback}>
|
||||||
{(() => {
|
{(() => {
|
||||||
switch (kcContext.themeType) {
|
switch (kcContext.themeType) {
|
||||||
case "login":
|
case "login": return <KcLoginPage kcContext={kcContext} />;
|
||||||
return <KcLoginPage kcContext={kcContext} />;
|
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
@ -49,7 +56,7 @@ export function KcPage(props: { kcContext: KcContext; fallback?: ReactNode }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is exported here only because in Webpack environnement it works differently
|
// NOTE: This is exported here only because in Webpack environnement it works differently
|
||||||
export const BASE_URL = import.meta.env.BASE_URL;
|
export const BASE_URL = import.meta.env.BASE_URL
|
||||||
|
|
||||||
// NOTE: This is only exported here because you're supposed to import type from different packages
|
// NOTE: This is only exported here because you're supposed to import type from different packages
|
||||||
// Depending of if you are using Vite, Webpack, ect...
|
// Depending of if you are using Vite, Webpack, ect...
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@ import type { ClassKey } from "keycloakify/login";
|
||||||
import type { KcContext } from "./KcContext";
|
import type { KcContext } from "./KcContext";
|
||||||
import { useI18n } from "./i18n";
|
import { useI18n } from "./i18n";
|
||||||
import DefaultPage from "keycloakify/login/DefaultPage";
|
import DefaultPage from "keycloakify/login/DefaultPage";
|
||||||
import Template from "keycloakify/login/Template";
|
import Template from "./Template";
|
||||||
const UserProfileFormFields = lazy(
|
const UserProfileFormFields = lazy(
|
||||||
() => import("keycloakify/login/UserProfileFormFields")
|
() => import("keycloakify/login/UserProfileFormFields")
|
||||||
);
|
);
|
||||||
|
import "./main.css";
|
||||||
|
|
||||||
const doMakeUserConfirmPassword = true;
|
const doMakeUserConfirmPassword = true;
|
||||||
|
|
||||||
|
|
|
||||||
185
src/login/Template.tsx
Normal file
185
src/login/Template.tsx
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { clsx } from "keycloakify/tools/clsx";
|
||||||
|
import { kcSanitize } from "keycloakify/lib/kcSanitize";
|
||||||
|
import type { TemplateProps } from "keycloakify/login/TemplateProps";
|
||||||
|
import { getKcClsx } from "keycloakify/login/lib/kcClsx";
|
||||||
|
import { useSetClassName } from "keycloakify/tools/useSetClassName";
|
||||||
|
import { useInitialize } from "keycloakify/login/Template.useInitialize";
|
||||||
|
import type { I18n } from "./i18n";
|
||||||
|
import type { KcContext } from "./KcContext";
|
||||||
|
|
||||||
|
export default function Template(props: TemplateProps<KcContext, I18n>) {
|
||||||
|
const {
|
||||||
|
displayInfo = false,
|
||||||
|
displayMessage = true,
|
||||||
|
displayRequiredFields = false,
|
||||||
|
headerNode,
|
||||||
|
socialProvidersNode = null,
|
||||||
|
infoNode = null,
|
||||||
|
documentTitle,
|
||||||
|
bodyClassName,
|
||||||
|
kcContext,
|
||||||
|
i18n,
|
||||||
|
doUseDefaultCss,
|
||||||
|
classes,
|
||||||
|
children
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const { kcClsx } = getKcClsx({ doUseDefaultCss, classes });
|
||||||
|
|
||||||
|
const { msg, msgStr, currentLanguage, enabledLanguages } = i18n;
|
||||||
|
|
||||||
|
const { realm, auth, url, message, isAppInitiatedAction } = kcContext;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = documentTitle ?? msgStr("loginTitle", realm.displayName);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useSetClassName({
|
||||||
|
qualifiedName: "html",
|
||||||
|
className: kcClsx("kcHtmlClass")
|
||||||
|
});
|
||||||
|
|
||||||
|
useSetClassName({
|
||||||
|
qualifiedName: "body",
|
||||||
|
className: bodyClassName ?? kcClsx("kcBodyClass")
|
||||||
|
});
|
||||||
|
|
||||||
|
const { isReadyToRender } = useInitialize({ kcContext, doUseDefaultCss });
|
||||||
|
|
||||||
|
if (!isReadyToRender) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={kcClsx("kcLoginClass")}>
|
||||||
|
<div id="kc-header" className={kcClsx("kcHeaderClass")}>
|
||||||
|
<div id="kc-header-wrapper" className={kcClsx("kcHeaderWrapperClass")}>
|
||||||
|
{msg("loginTitleHtml", realm.displayNameHtml)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={kcClsx("kcFormCardClass")}>
|
||||||
|
<header className={kcClsx("kcFormHeaderClass")}>
|
||||||
|
{enabledLanguages.length > 1 && (
|
||||||
|
<div className={kcClsx("kcLocaleMainClass")} id="kc-locale">
|
||||||
|
<div id="kc-locale-wrapper" className={kcClsx("kcLocaleWrapperClass")}>
|
||||||
|
<div id="kc-locale-dropdown" className={clsx("menu-button-links", kcClsx("kcLocaleDropDownClass"))}>
|
||||||
|
<button
|
||||||
|
tabIndex={1}
|
||||||
|
id="kc-current-locale-link"
|
||||||
|
aria-label={msgStr("languages")}
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="language-switch1"
|
||||||
|
>
|
||||||
|
{currentLanguage.label}
|
||||||
|
</button>
|
||||||
|
<ul
|
||||||
|
role="menu"
|
||||||
|
tabIndex={-1}
|
||||||
|
aria-labelledby="kc-current-locale-link"
|
||||||
|
aria-activedescendant=""
|
||||||
|
id="language-switch1"
|
||||||
|
className={kcClsx("kcLocaleListClass")}
|
||||||
|
>
|
||||||
|
{enabledLanguages.map(({ languageTag, label, href }, i) => (
|
||||||
|
<li key={languageTag} className={kcClsx("kcLocaleListItemClass")} role="none">
|
||||||
|
<a role="menuitem" id={`language-${i + 1}`} className={kcClsx("kcLocaleItemClass")} href={href}>
|
||||||
|
{label}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{(() => {
|
||||||
|
const node = !(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
|
||||||
|
<h1 id="kc-page-title">{headerNode}</h1>
|
||||||
|
) : (
|
||||||
|
<div id="kc-username" className={kcClsx("kcFormGroupClass")}>
|
||||||
|
<label id="kc-attempted-username">{auth.attemptedUsername}</label>
|
||||||
|
<a id="reset-login" href={url.loginRestartFlowUrl} aria-label={msgStr("restartLoginTooltip")}>
|
||||||
|
<div className="kc-login-tooltip">
|
||||||
|
<i className={kcClsx("kcResetFlowIcon")}></i>
|
||||||
|
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (displayRequiredFields) {
|
||||||
|
return (
|
||||||
|
<div className={kcClsx("kcContentWrapperClass")}>
|
||||||
|
<div className={clsx(kcClsx("kcLabelWrapperClass"), "subtitle")}>
|
||||||
|
<span className="subtitle">
|
||||||
|
<span className="required">*</span>
|
||||||
|
{msg("requiredFields")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-10">{node}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
})()}
|
||||||
|
</header>
|
||||||
|
<div id="kc-content">
|
||||||
|
<div id="kc-content-wrapper">
|
||||||
|
{/* App-initiated actions should not see warning messages about the need to complete the action during login. */}
|
||||||
|
{displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
`alert-${message.type}`,
|
||||||
|
kcClsx("kcAlertClass"),
|
||||||
|
`pf-m-${message?.type === "error" ? "danger" : message.type}`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="pf-c-alert__icon">
|
||||||
|
{message.type === "success" && <span className={kcClsx("kcFeedbackSuccessIcon")}></span>}
|
||||||
|
{message.type === "warning" && <span className={kcClsx("kcFeedbackWarningIcon")}></span>}
|
||||||
|
{message.type === "error" && <span className={kcClsx("kcFeedbackErrorIcon")}></span>}
|
||||||
|
{message.type === "info" && <span className={kcClsx("kcFeedbackInfoIcon")}></span>}
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className={kcClsx("kcAlertTitleClass")}
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: kcSanitize(message.summary)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
{auth !== undefined && auth.showTryAnotherWayLink && (
|
||||||
|
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post">
|
||||||
|
<div className={kcClsx("kcFormGroupClass")}>
|
||||||
|
<input type="hidden" name="tryAnotherWay" value="on" />
|
||||||
|
<a
|
||||||
|
id="try-another-way"
|
||||||
|
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
||||||
|
onClick={() => {
|
||||||
|
document.forms["kc-select-try-another-way-form" as never].requestSubmit();
|
||||||
|
return false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{msg("doTryAnotherWay")}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
{socialProvidersNode}
|
||||||
|
{displayInfo && (
|
||||||
|
<div id="kc-info" className={kcClsx("kcSignUpClass")}>
|
||||||
|
<div id="kc-info-wrapper" className={kcClsx("kcInfoAreaWrapperClass")}>
|
||||||
|
{infoNode}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
src/login/main.css
Normal file
29
src/login/main.css
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
body.kcBodyClass {
|
||||||
|
background: url(https://www.sr2.uk/img/new_tower.jpg) no-repeat center center fixed;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kcFormCardClass {
|
||||||
|
border-image: linear-gradient(to right, #01486f, #00a870) 1;
|
||||||
|
border-width: 4px;
|
||||||
|
border-style: solid;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kcHeaderWrapperClass {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kcFormHeaderClass h1:before {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
background: url(/logo-side.png) no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1360/338;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#kc-form, #kc-form-webauthn {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue