feat: integrate shadcn/ui with Tailwind v4

This commit is contained in:
2026-07-01 14:38:20 +00:00
parent 11ce5b59b3
commit 4d98eaccbd
21 changed files with 1896 additions and 13217 deletions
+7 -4
View File
@@ -1,10 +1,9 @@
import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../i18n";
import { Alert, AlertTitle } from "@/components/ui/alert";
export default function QrLoginCanceled(
props: PageProps<Extract<KcContext, { pageId: "qr-login-canceled.ftl" }>, I18n>
) {
export default function QrLoginCanceled(props: PageProps<Extract<KcContext, { pageId: "qr-login-canceled.ftl" }>, I18n>) {
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msg } = i18n;
@@ -17,7 +16,11 @@ export default function QrLoginCanceled(
displayInfo={false}
headerNode={msg("consentDenied")}
>
<div id="kc-qr-canceled-message" className={classes?.kcFormClass} />
<div id="kc-qr-canceled-message" className={classes?.kcFormClass}>
<Alert variant="destructive" className="border-white/45 bg-white/40 backdrop-blur-md">
<AlertTitle>{msg("consentDenied")}</AlertTitle>
</Alert>
</div>
</Template>
);
}
+12 -12
View File
@@ -2,10 +2,9 @@ import { useEffect, useRef, useState } from "react";
import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../i18n";
import { Button } from "@/components/ui/button";
export default function QrLoginScan(
props: PageProps<Extract<KcContext, { pageId: "qr-login-scan.ftl" }>, I18n>
) {
export default function QrLoginScan(props: PageProps<Extract<KcContext, { pageId: "qr-login-scan.ftl" }>, I18n>) {
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { url, QRauthImage, QRauthExecId, QRauthToken, tabId, alignment, ShortCode, ShortCodeLink, refreshRate = 15 } = kcContext;
@@ -73,8 +72,9 @@ export default function QrLoginScan(
{ShortCode && (
<p id="com-hadleyso-qr-auth-short-zone" className="kcQrShortCodeZone">
<a
href="#"
<Button
variant="link"
size="sm"
id="com-hadleyso-qr-auth-short-start"
onClick={event => {
setShowShortCode(true);
@@ -82,9 +82,11 @@ export default function QrLoginScan(
}}
>
{msg("CannotScan")}
</a>{" "}
</Button>{" "}
|{" "}
<a href={ShortCodeLink}>{msg("UseShortCode")}</a>
<Button variant="link" size="sm" asChild>
<a href={ShortCodeLink}>{msg("UseShortCode")}</a>
</Button>
</p>
)}
@@ -105,11 +107,9 @@ export default function QrLoginScan(
method="post"
>
<input type="hidden" name="authenticationExecution" value={QRauthExecId ?? ""} />
<input
type="submit"
value={msgStr("doLogIn")}
className={`${classes?.kcButtonClass ?? ""} ${classes?.kcButtonPrimaryClass ?? ""} ${classes?.kcButtonLargeClass ?? ""}`}
/>
<Button type="submit" size="lg">
{msgStr("doLogIn")}
</Button>
</form>
</div>
</Template>
+8 -11
View File
@@ -1,10 +1,11 @@
import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../i18n";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export default function QrLoginShortStart(
props: PageProps<Extract<KcContext, { pageId: "qr-login-short-start.ftl" }>, I18n>
) {
export default function QrLoginShortStart(props: PageProps<Extract<KcContext, { pageId: "qr-login-short-start.ftl" }>, I18n>) {
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msg, msgStr } = i18n;
@@ -21,11 +22,11 @@ export default function QrLoginShortStart(
<div className={classes?.kcFormGroupClass}>
<p className="kcQrShortCodeInfoClass">{msg("doShortCodeInfo")}</p>
<label htmlFor="shortCode" className={classes?.kcLabelClass}>
<Label htmlFor="shortCode" className={classes?.kcLabelClass}>
{msg("doShortCode")}
</label>
</Label>
<input
<Input
id="shortCode"
name="shortCode"
type="number"
@@ -41,11 +42,7 @@ export default function QrLoginShortStart(
</div>
<div className={classes?.kcFormGroupClass}>
<input
type="submit"
value={msgStr("doSubmit")}
className={`${classes?.kcButtonClass ?? ""} ${classes?.kcButtonPrimaryClass ?? ""}`}
/>
<Button type="submit">{msgStr("doSubmit")}</Button>
</div>
</form>
</Template>
+5 -4
View File
@@ -1,10 +1,9 @@
import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../i18n";
import { Alert, AlertTitle } from "@/components/ui/alert";
export default function QrLoginSuccess(
props: PageProps<Extract<KcContext, { pageId: "qr-login-success.ftl" }>, I18n>
) {
export default function QrLoginSuccess(props: PageProps<Extract<KcContext, { pageId: "qr-login-success.ftl" }>, I18n>) {
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { msg } = i18n;
@@ -18,7 +17,9 @@ export default function QrLoginSuccess(
headerNode={msg("successQrCodeLoginTitle")}
>
<div id="kc-qr-success-message" className={classes?.kcFormClass}>
<p className="kcQrSuccessMessageClass">{msg("successQrCodeLoginMessage")}</p>
<Alert className="kcQrSuccessMessageClass border-white/45 bg-white/40 backdrop-blur-md">
<AlertTitle>{msg("successQrCodeLoginMessage")}</AlertTitle>
</Alert>
</div>
</Template>
);
+14 -20
View File
@@ -1,10 +1,10 @@
import type { PageProps } from "keycloakify/login/pages/PageProps";
import type { KcContext } from "../KcContext";
import type { I18n } from "../i18n";
import { Button } from "@/components/ui/button";
import { Alert, AlertTitle } from "@/components/ui/alert";
export default function QrLoginVerify(
props: PageProps<Extract<KcContext, { pageId: "qr-login-verify.ftl" }>, I18n>
) {
export default function QrLoginVerify(props: PageProps<Extract<KcContext, { pageId: "qr-login-verify.ftl" }>, I18n>) {
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
const { ua_device, ua_os, ua_agent, local_localized, tabId, approveURL, rejectURL } = kcContext;
@@ -20,11 +20,13 @@ export default function QrLoginVerify(
headerNode={msg("doQrCodeVerify")}
>
<div id="kc-qr-verify-form" className={classes?.kcFormClass}>
<p className="kcQrWarningClass">{msg("doQrCodeWarning")}</p>
<Alert variant="destructive" className="kcQrWarningClass mb-4">
<AlertTitle>{msg("doQrCodeWarning")}</AlertTitle>
</Alert>
<p className="kcQrDeviceInfoClass">
You are authorizing a session on a <b>{ua_device}</b> running <b>{ua_os}</b> / <b>{ua_agent}</b> in
locale <b>{local_localized}</b>.
You are authorizing a session on a <b>{ua_device}</b> running <b>{ua_os}</b> / <b>{ua_agent}</b> in locale{" "}
<b>{local_localized}</b>.
</p>
{tabId && (
@@ -34,20 +36,12 @@ export default function QrLoginVerify(
)}
<div className="kcQrVerifyButtonsClass">
<a
href={approveURL}
type="button"
className={`${classes?.kcButtonClass ?? ""} ${classes?.kcButtonPrimaryClass ?? ""} ${classes?.kcButtonLargeClass ?? ""}`}
>
{msg("doAccept")}
</a>
<a
href={rejectURL}
type="button"
className={`${classes?.kcButtonClass ?? ""} ${classes?.kcButtonDefaultClass ?? ""} ${classes?.kcButtonLargeClass ?? ""}`}
>
{msg("doDecline")}
</a>
<Button asChild size="lg">
<a href={approveURL}>{msg("doAccept")}</a>
</Button>
<Button variant="secondary" asChild size="lg">
<a href={rejectURL}>{msg("doDecline")}</a>
</Button>
</div>
</div>
</Template>