@oussemasahbeni/keycloakify-login-shadcn 250004.0.2 → 250004.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/keycloak-theme/components/ui/alert.tsx +4 -4
  2. package/keycloak-theme/components/ui/dropdown-menu.tsx +5 -5
  3. package/keycloak-theme/components/ui/input.tsx +1 -1
  4. package/keycloak-theme/components/ui/select.tsx +4 -4
  5. package/keycloak-theme/components/ui/separator.tsx +1 -1
  6. package/keycloak-theme/login/KcContext.ts +23 -19
  7. package/keycloak-theme/login/KcPage.tsx +47 -60
  8. package/keycloak-theme/login/assets/img/auth-logo.svg +100 -100
  9. package/keycloak-theme/login/assets/img/shape.svg +71 -71
  10. package/keycloak-theme/login/components/LogoutOtherSessions.tsx +26 -26
  11. package/keycloak-theme/login/components/PasswordWrapper.tsx +35 -35
  12. package/keycloak-theme/login/components/Template/Template.tsx +227 -226
  13. package/keycloak-theme/login/components/Template/index.ts +1 -1
  14. package/keycloak-theme/login/components/Template/useInitializeTemplate.ts +61 -61
  15. package/keycloak-theme/login/components/UserProfileFormFields/AddRemoveButtonsMultiValuedAttribute.tsx +61 -61
  16. package/keycloak-theme/login/components/UserProfileFormFields/DO_MAKE_USER_CONFIRM_PASSWORD.ts +2 -2
  17. package/keycloak-theme/login/components/UserProfileFormFields/FieldErrors.tsx +28 -28
  18. package/keycloak-theme/login/components/UserProfileFormFields/GroupLabel.tsx +70 -70
  19. package/keycloak-theme/login/components/UserProfileFormFields/InputFieldByType.tsx +58 -58
  20. package/keycloak-theme/login/components/UserProfileFormFields/InputTag.tsx +116 -116
  21. package/keycloak-theme/login/components/UserProfileFormFields/InputTagSelects.tsx +135 -135
  22. package/keycloak-theme/login/components/UserProfileFormFields/SelectTag.tsx +114 -114
  23. package/keycloak-theme/login/components/UserProfileFormFields/TextareaTag.tsx +42 -42
  24. package/keycloak-theme/login/components/UserProfileFormFields/UserProfileFormFields.tsx +127 -127
  25. package/keycloak-theme/login/components/UserProfileFormFields/index.ts +1 -1
  26. package/keycloak-theme/login/i18n.ts +47 -51
  27. package/keycloak-theme/login/mocks/getKcContextMock.ts +22 -18
  28. package/keycloak-theme/login/pages/PageIndex.tsx +134 -134
  29. package/keycloak-theme/login/pages/code/Page.stories.tsx +62 -78
  30. package/keycloak-theme/login/pages/code/Page.tsx +89 -89
  31. package/keycloak-theme/login/pages/code/index.ts +3 -3
  32. package/keycloak-theme/login/pages/delete-account-confirm/Page.stories.tsx +39 -46
  33. package/keycloak-theme/login/pages/delete-account-confirm/Page.tsx +63 -63
  34. package/keycloak-theme/login/pages/delete-account-confirm/index.ts +3 -3
  35. package/keycloak-theme/login/pages/delete-credential/Page.stories.tsx +26 -30
  36. package/keycloak-theme/login/pages/delete-credential/Page.tsx +51 -51
  37. package/keycloak-theme/login/pages/delete-credential/index.ts +3 -3
  38. package/keycloak-theme/login/pages/error/Page.stories.tsx +47 -58
  39. package/keycloak-theme/login/pages/error/Page.tsx +42 -42
  40. package/keycloak-theme/login/pages/error/index.ts +3 -3
  41. package/keycloak-theme/login/pages/frontchannel-logout/Page.stories.tsx +25 -32
  42. package/keycloak-theme/login/pages/frontchannel-logout/Page.tsx +84 -84
  43. package/keycloak-theme/login/pages/frontchannel-logout/index.ts +3 -3
  44. package/keycloak-theme/login/pages/idp-review-user-profile/Page.stories.tsx +46 -58
  45. package/keycloak-theme/login/pages/idp-review-user-profile/Page.tsx +52 -52
  46. package/keycloak-theme/login/pages/idp-review-user-profile/index.ts +3 -3
  47. package/keycloak-theme/login/pages/info/Page.stories.tsx +50 -60
  48. package/keycloak-theme/login/pages/info/Page.tsx +92 -92
  49. package/keycloak-theme/login/pages/link-idp-action/Page.stories.tsx +32 -16
  50. package/keycloak-theme/login/pages/link-idp-action/Page.tsx +43 -43
  51. package/keycloak-theme/login/pages/link-idp-action/index.ts +3 -3
  52. package/keycloak-theme/login/pages/login/Form.tsx +242 -242
  53. package/keycloak-theme/login/pages/login/Info.tsx +29 -29
  54. package/keycloak-theme/login/pages/login/Page.stories.tsx +345 -365
  55. package/keycloak-theme/login/pages/login/Page.tsx +44 -44
  56. package/keycloak-theme/login/pages/login/SocialProviders.tsx +107 -107
  57. package/keycloak-theme/login/pages/login/index.ts +3 -3
  58. package/keycloak-theme/login/pages/login/providers/apple.svg +3 -3
  59. package/keycloak-theme/login/pages/login/providers/bitbucket.svg +11 -11
  60. package/keycloak-theme/login/pages/login/providers/discord.svg +4 -4
  61. package/keycloak-theme/login/pages/login/providers/facebook.svg +5 -5
  62. package/keycloak-theme/login/pages/login/providers/github.svg +3 -3
  63. package/keycloak-theme/login/pages/login/providers/gitlab.svg +7 -7
  64. package/keycloak-theme/login/pages/login/providers/google.svg +7 -7
  65. package/keycloak-theme/login/pages/login/providers/instagram.svg +31 -31
  66. package/keycloak-theme/login/pages/login/providers/linkedin.svg +3 -3
  67. package/keycloak-theme/login/pages/login/providers/microsoft.svg +6 -6
  68. package/keycloak-theme/login/pages/login/providers/oidc.svg +5 -5
  69. package/keycloak-theme/login/pages/login/providers/openshift.svg +7 -7
  70. package/keycloak-theme/login/pages/login/providers/paypal.svg +6 -6
  71. package/keycloak-theme/login/pages/login/providers/slack.svg +11 -11
  72. package/keycloak-theme/login/pages/login/providers/stackoverflow.svg +5 -5
  73. package/keycloak-theme/login/pages/login/providers/x.svg +3 -3
  74. package/keycloak-theme/login/pages/login/useProviderLogos.tsx +39 -39
  75. package/keycloak-theme/login/pages/login/useScript.tsx +62 -62
  76. package/keycloak-theme/login/pages/login-config-totp/Page.stories.tsx +45 -59
  77. package/keycloak-theme/login/pages/login-config-totp/Page.tsx +240 -240
  78. package/keycloak-theme/login/pages/login-config-totp/index.ts +3 -3
  79. package/keycloak-theme/login/pages/login-idp-link-confirm/Page.stories.tsx +30 -34
  80. package/keycloak-theme/login/pages/login-idp-link-confirm/Page.tsx +43 -43
  81. package/keycloak-theme/login/pages/login-idp-link-confirm/index.ts +3 -3
  82. package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.stories.tsx +16 -22
  83. package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.tsx +47 -47
  84. package/keycloak-theme/login/pages/login-idp-link-confirm-override/index.ts +3 -3
  85. package/keycloak-theme/login/pages/login-idp-link-email/Page.stories.tsx +54 -62
  86. package/keycloak-theme/login/pages/login-idp-link-email/Page.tsx +54 -54
  87. package/keycloak-theme/login/pages/login-idp-link-email/index.ts +3 -3
  88. package/keycloak-theme/login/pages/login-oauth-grant/Page.stories.tsx +39 -45
  89. package/keycloak-theme/login/pages/login-oauth-grant/Page.tsx +126 -126
  90. package/keycloak-theme/login/pages/login-oauth-grant/index.ts +3 -3
  91. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/Page.stories.tsx +38 -48
  92. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/Page.tsx +58 -58
  93. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/index.ts +3 -3
  94. package/keycloak-theme/login/pages/login-otp/Page.stories.tsx +82 -96
  95. package/keycloak-theme/login/pages/login-otp/Page.tsx +108 -108
  96. package/keycloak-theme/login/pages/login-otp/index.ts +3 -3
  97. package/keycloak-theme/login/pages/login-page-expired/Page.stories.tsx +28 -36
  98. package/keycloak-theme/login/pages/login-page-expired/Page.tsx +47 -47
  99. package/keycloak-theme/login/pages/login-page-expired/index.ts +3 -3
  100. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/Page.stories.tsx +20 -0
  101. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/Page.tsx +233 -233
  102. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/index.ts +3 -3
  103. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/useScript.tsx +63 -63
  104. package/keycloak-theme/login/pages/login-password/Page.stories.tsx +55 -56
  105. package/keycloak-theme/login/pages/login-password/Page.tsx +149 -149
  106. package/keycloak-theme/login/pages/login-password/index.ts +3 -3
  107. package/keycloak-theme/login/pages/login-password/useScript.tsx +63 -63
  108. package/keycloak-theme/login/pages/login-recovery-authn-code-config/Page.stories.tsx +28 -36
  109. package/keycloak-theme/login/pages/login-recovery-authn-code-config/Page.tsx +181 -181
  110. package/keycloak-theme/login/pages/login-recovery-authn-code-config/index.ts +3 -3
  111. package/keycloak-theme/login/pages/login-recovery-authn-code-config/useScript.tsx +145 -145
  112. package/keycloak-theme/login/pages/login-recovery-authn-code-input/Page.stories.tsx +16 -22
  113. package/keycloak-theme/login/pages/login-recovery-authn-code-input/Page.tsx +70 -70
  114. package/keycloak-theme/login/pages/login-recovery-authn-code-input/index.ts +3 -3
  115. package/keycloak-theme/login/pages/login-reset-otp/Page.stories.tsx +62 -74
  116. package/keycloak-theme/login/pages/login-reset-otp/Page.tsx +86 -86
  117. package/keycloak-theme/login/pages/login-reset-otp/index.ts +3 -3
  118. package/keycloak-theme/login/pages/login-reset-password/Form.tsx +68 -68
  119. package/keycloak-theme/login/pages/login-reset-password/Page.stories.tsx +44 -54
  120. package/keycloak-theme/login/pages/login-reset-password/Page.tsx +27 -27
  121. package/keycloak-theme/login/pages/login-reset-password/index.ts +3 -3
  122. package/keycloak-theme/login/pages/login-update-password/Page.stories.tsx +40 -50
  123. package/keycloak-theme/login/pages/login-update-password/Page.tsx +111 -111
  124. package/keycloak-theme/login/pages/login-update-password/index.ts +3 -3
  125. package/keycloak-theme/login/pages/login-update-profile/Page.stories.tsx +28 -36
  126. package/keycloak-theme/login/pages/login-update-profile/Page.tsx +68 -68
  127. package/keycloak-theme/login/pages/login-update-profile/index.ts +3 -3
  128. package/keycloak-theme/login/pages/login-username/Page.stories.tsx +32 -42
  129. package/keycloak-theme/login/pages/login-username/Page.tsx +246 -246
  130. package/keycloak-theme/login/pages/login-username/index.ts +3 -3
  131. package/keycloak-theme/login/pages/login-username/useScript.tsx +62 -62
  132. package/keycloak-theme/login/pages/login-verify-email/Page.stories.tsx +68 -80
  133. package/keycloak-theme/login/pages/login-verify-email/Page.tsx +38 -38
  134. package/keycloak-theme/login/pages/login-verify-email/index.ts +3 -3
  135. package/keycloak-theme/login/pages/login-x509-info/Page.stories.tsx +29 -37
  136. package/keycloak-theme/login/pages/login-x509-info/Page.tsx +75 -75
  137. package/keycloak-theme/login/pages/login-x509-info/index.ts +3 -3
  138. package/keycloak-theme/login/pages/logout-confirm/Page.stories.tsx +34 -42
  139. package/keycloak-theme/login/pages/logout-confirm/Page.tsx +53 -53
  140. package/keycloak-theme/login/pages/logout-confirm/index.ts +3 -3
  141. package/keycloak-theme/login/pages/register/Form.tsx +106 -106
  142. package/keycloak-theme/login/pages/register/Page.stories.tsx +23 -6
  143. package/keycloak-theme/login/pages/register/Page.tsx +26 -26
  144. package/keycloak-theme/login/pages/register/TermsAcceptance.tsx +56 -56
  145. package/keycloak-theme/login/pages/register/index.ts +3 -3
  146. package/keycloak-theme/login/pages/saml-post-form/Page.stories.tsx +16 -22
  147. package/keycloak-theme/login/pages/saml-post-form/Page.tsx +66 -66
  148. package/keycloak-theme/login/pages/saml-post-form/index.ts +3 -3
  149. package/keycloak-theme/login/pages/select-authenticator/Page.stories.tsx +83 -95
  150. package/keycloak-theme/login/pages/select-authenticator/Page.tsx +100 -100
  151. package/keycloak-theme/login/pages/select-authenticator/index.ts +3 -3
  152. package/keycloak-theme/login/pages/select-organization/Page.stories.tsx +62 -49
  153. package/keycloak-theme/login/pages/select-organization/Page.tsx +126 -126
  154. package/keycloak-theme/login/pages/select-organization/index.ts +3 -3
  155. package/keycloak-theme/login/pages/terms/Page.stories.tsx +15 -0
  156. package/keycloak-theme/login/pages/terms/Page.tsx +51 -51
  157. package/keycloak-theme/login/pages/terms/index.ts +3 -3
  158. package/keycloak-theme/login/pages/update-email/Page.stories.tsx +27 -35
  159. package/keycloak-theme/login/pages/update-email/Page.tsx +62 -62
  160. package/keycloak-theme/login/pages/update-email/index.ts +3 -3
  161. package/keycloak-theme/login/pages/webauthn-authenticate/Page.stories.tsx +112 -126
  162. package/keycloak-theme/login/pages/webauthn-authenticate/Page.tsx +202 -202
  163. package/keycloak-theme/login/pages/webauthn-authenticate/index.ts +3 -3
  164. package/keycloak-theme/login/pages/webauthn-authenticate/useScript.tsx +55 -55
  165. package/keycloak-theme/login/pages/webauthn-error/Page.stories.tsx +54 -66
  166. package/keycloak-theme/login/pages/webauthn-error/Page.tsx +73 -73
  167. package/keycloak-theme/login/pages/webauthn-error/index.ts +3 -3
  168. package/keycloak-theme/login/pages/webauthn-register/Page.stories.tsx +39 -49
  169. package/keycloak-theme/login/pages/webauthn-register/Page.tsx +78 -78
  170. package/keycloak-theme/login/pages/webauthn-register/index.ts +3 -3
  171. package/keycloak-theme/login/pages/webauthn-register/useScript.tsx +62 -62
  172. package/keycloak-theme/login/shared/getColorScheme.ts +45 -0
  173. package/keycloak-theme/login/styleLevelCustomization.tsx +36 -17
  174. package/package.json +6 -5
@@ -1,226 +1,227 @@
1
- import { Languages } from '@/components/langauges';
2
- import { ModeToggle } from '@/components/theme-toggle';
3
- import { Alert, AlertDescription } from '@/components/ui/alert';
4
- import { Button } from '@/components/ui/button';
5
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
6
- import { kcSanitize } from "@keycloakify/login-ui/kcSanitize";
7
- import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
8
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip';
9
- import { useSetClassName } from "keycloakify/tools/useSetClassName";
10
- import { RotateCcw } from 'lucide-react';
11
- import type { ReactNode } from "react";
12
- import { useEffect } from "react";
13
- import { useI18n } from "../../i18n";
14
- import { useKcContext } from "../../KcContext";
15
- import companylogo from "./../../assets/img/auth-logo.svg";
16
- import shape from "./../../assets/img/shape.svg";
17
- import { useInitializeTemplate } from "./useInitializeTemplate";
18
-
19
- const APP_NAME = "Acme Inc.";
20
-
21
- export function Template(props: {
22
- displayInfo?: boolean;
23
- displayMessage?: boolean;
24
- displayRequiredFields?: boolean;
25
- headerNode: ReactNode;
26
- socialProvidersNode?: ReactNode;
27
- infoNode?: ReactNode;
28
- documentTitle?: string;
29
- bodyClassName?: string;
30
- children: ReactNode;
31
- }) {
32
- const {
33
- displayInfo = false,
34
- displayMessage = true,
35
- displayRequiredFields = false,
36
- headerNode,
37
- socialProvidersNode = null,
38
- infoNode = null,
39
- documentTitle,
40
- bodyClassName,
41
- children
42
- } = props;
43
-
44
- const { kcContext } = useKcContext();
45
-
46
- const { auth, url, message, isAppInitiatedAction } = kcContext;
47
-
48
-
49
- const { msg, msgStr, enabledLanguages } = useI18n();
50
-
51
- const { kcClsx } = useKcClsx();
52
-
53
- useEffect(() => {
54
- document.title =
55
- documentTitle ?? msgStr("loginTitle", kcContext.realm.displayName);
56
- }, []);
57
-
58
- useSetClassName({
59
- qualifiedName: "html",
60
- className: kcClsx("kcHtmlClass")
61
- });
62
-
63
- useSetClassName({
64
- qualifiedName: "body",
65
- className: bodyClassName ?? kcClsx("kcBodyClass")
66
- });
67
-
68
- const { isReadyToRender } = useInitializeTemplate();
69
-
70
- if (!isReadyToRender) {
71
- return null;
72
- }
73
-
74
- return (
75
- <div className="grid min-h-svh lg:grid-cols-2 bg-white dark:bg-background lg:bg-transparent">
76
- {/* Main content */}
77
- <div className="flex flex-col gap-4 px-0 py-0 pb-6 lg:p-6 lg:md:p-10 lg:pt-10 min-h-screen lg:min-h-0">
78
- {/* navigation */}
79
- <div className="absolute top-4 right-4 lg:left-4 z-20 flex gap-2">
80
- {/* <Button variant="outline" size="sm" className="border-gray-400 self-center font-medium text-base">
81
- <a className="flex items-center gap-1" href={kcContext.client.baseUrl ?? redirectUrlOrigin}>
82
- <FiArrowLeft /> {msg("home")}
83
- </a>
84
- </Button> */}
85
- {enabledLanguages.length > 1 && (
86
- <div className="bg-white/10 dark:bg-white/10 backdrop-blur-sm rounded-md">
87
- <Languages />
88
- </div>
89
- )}
90
- {kcContext.properties.ENABLE_THEME_TOGGLE == "true" && (
91
- <div className="bg-white/10 dark:bg-white/10 backdrop-blur-sm rounded-md">
92
- <ModeToggle />
93
- </div>
94
- )}
95
- </div>
96
-
97
- {/* Mobile header with logo */}
98
- <div className="lg:hidden relative pt-8 px-6">
99
- {/* Logo and welcome message */}
100
- <div className="flex flex-col items-center justify-center gap-3 mt-4">
101
- <div className=" mb-4 flex items-center gap-3">
102
- <img src={companylogo} alt="Logo" />
103
- <span className=" text-xl"> {APP_NAME}</span>
104
- </div>
105
- </div>
106
- </div>
107
-
108
- <div className="flex flex-1 items-start lg:items-center justify-center lg:mt-0 ">
109
- <div className="w-full max-w-xl ">
110
- <Card className=" shadow-none bg-transparent lg:bg-card border-0 lg:rounded-lg lg:border lg:shadow-sm rounded-t-2xl">
111
- <CardHeader className="text-center mb-3 px-6 pt-8 pb-4 lg:pt-6">
112
- <CardTitle>
113
- {(() => {
114
- const node = !(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
115
- <h1 className="text-xl">{headerNode}</h1>
116
- ) : (
117
- <div id="kc-username" className="flex items-center justify-center gap-2">
118
- <label className="font-semibold text-lg" id="kc-attempted-username">
119
- {auth.attemptedUsername}
120
- </label>
121
-
122
- <TooltipProvider>
123
- <Tooltip>
124
- <TooltipTrigger asChild>
125
- <Button variant="outline" size="icon" asChild>
126
- <a
127
- id="reset-login"
128
- href={url.loginRestartFlowUrl}
129
- aria-label={msgStr("restartLoginTooltip")}
130
- >
131
- <RotateCcw className="h-4 w-4" />
132
- </a>
133
- </Button>
134
- </TooltipTrigger>
135
- <TooltipContent>
136
- <p>{msg("restartLoginTooltip")}</p>
137
- </TooltipContent>
138
- </Tooltip>
139
- </TooltipProvider>
140
- </div>
141
- );
142
-
143
- if (displayRequiredFields) {
144
- return (
145
- <div className="flex items-center justify-between gap-2">
146
- <div>{node}</div>
147
- <div>
148
- <span className="subtitle">
149
- <span className="text-red-500">*</span>
150
- {msg("requiredFields")}
151
- </span>
152
- </div>
153
- </div>
154
- );
155
- }
156
-
157
- return node;
158
- })()}
159
- </CardTitle>
160
- </CardHeader>
161
- <CardContent className="px-6 pb-8">
162
- <div id="kc-content">
163
- <div id="kc-content-wrapper">
164
- {displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
165
- <Alert variant={message.type} className="my-3">
166
- <AlertDescription>
167
- <div>
168
- <span
169
- dangerouslySetInnerHTML={{
170
- __html: kcSanitize(message.summary)
171
- }}
172
- />
173
- </div>
174
- </AlertDescription>
175
- </Alert>
176
- )}
177
- <div className="children">{children}</div>
178
- {socialProvidersNode}
179
- {auth !== undefined && auth.showTryAnotherWayLink && (
180
- <form id="kc-select-try-another-way-form" action={url.loginAction} method="post">
181
- <div className={kcClsx("kcFormGroupClass")}>
182
- <input type="hidden" name="tryAnotherWay" value="on" />
183
- <a
184
- href="#"
185
- id="try-another-way"
186
- onClick={() => {
187
- document.forms["kc-select-try-another-way-form" as never].submit();
188
- return false;
189
- }}
190
- >
191
- {msg("doTryAnotherWay")}
192
- </a>
193
- </div>
194
- </form>
195
- )}
196
- {displayInfo && <div className="text-center text-sm mt-4">{infoNode}</div>}
197
- </div>
198
- </div>
199
- </CardContent>
200
- </Card>
201
- </div>
202
- </div>
203
- </div>
204
-
205
- <div className="bg-slate-950 relative hidden lg:block dark:bg-white/5">
206
- <div className="flex items-center pt-20 h-full justify-center z-1">
207
- <div className="absolute right-0 top-0 w-full max-w-62.5 xl:max-w-112.5">
208
- <img src={shape} alt="grid" />
209
- </div>
210
- <div className="absolute bottom-0 left-0 w-full max-w-62.5 rotate-180 xl:max-w-112.5">
211
- <img src={shape} alt="grid" />
212
- </div>
213
-
214
- <div className="flex justify-center my-auto flex-col items-center max-w-xs">
215
- <div className=" mb-4 flex items-center gap-3">
216
- <img src={companylogo} alt="Logo" />
217
- <span className="text-white text-xl"> {APP_NAME}</span>
218
- </div>
219
-
220
- <p className="text-center text-gray-400 dark:text-white/60">{msg("welcomeMessage")}</p>
221
- </div>
222
- </div>
223
- </div>
224
- </div>
225
- );
226
- }
1
+ import { Languages } from '@/components/langauges';
2
+ import { ModeToggle } from '@/components/theme-toggle';
3
+ import { Alert, AlertDescription } from '@/components/ui/alert';
4
+ import { Button } from '@/components/ui/button';
5
+ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
6
+ import { redirectUrlOrigin } from '@/login/shared/redirectUrlOrigin';
7
+ import { kcSanitize } from "@keycloakify/login-ui/kcSanitize";
8
+ import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
9
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip';
10
+ import { useSetClassName } from "keycloakify/tools/useSetClassName";
11
+ import { RotateCcw } from 'lucide-react';
12
+ import type { ReactNode } from "react";
13
+ import { useEffect } from "react";
14
+ import { FiHome } from 'react-icons/fi';
15
+ import { useI18n } from "../../i18n";
16
+ import { useKcContext } from "../../KcContext";
17
+ import companylogo from "./../../assets/img/auth-logo.svg";
18
+ import shape from "./../../assets/img/shape.svg";
19
+ import { useInitializeTemplate } from "./useInitializeTemplate";
20
+
21
+ const APP_NAME = "Acme Inc.";
22
+
23
+ export function Template(props: {
24
+ displayInfo?: boolean;
25
+ displayMessage?: boolean;
26
+ displayRequiredFields?: boolean;
27
+ headerNode: ReactNode;
28
+ socialProvidersNode?: ReactNode;
29
+ infoNode?: ReactNode;
30
+ documentTitle?: string;
31
+ bodyClassName?: string;
32
+ children: ReactNode;
33
+ }) {
34
+ const {
35
+ displayInfo = false,
36
+ displayMessage = true,
37
+ displayRequiredFields = false,
38
+ headerNode,
39
+ socialProvidersNode = null,
40
+ infoNode = null,
41
+ documentTitle,
42
+ bodyClassName,
43
+ children
44
+ } = props;
45
+
46
+ const { kcContext } = useKcContext();
47
+
48
+ const { auth, url, message, isAppInitiatedAction } = kcContext;
49
+
50
+
51
+ const { msg, msgStr, enabledLanguages } = useI18n();
52
+
53
+ const { kcClsx } = useKcClsx();
54
+
55
+ useEffect(() => {
56
+ document.title =
57
+ documentTitle ?? msgStr("loginTitle", kcContext.realm.displayName);
58
+ }, []);
59
+
60
+ useSetClassName({
61
+ qualifiedName: "html",
62
+ className: kcClsx("kcHtmlClass")
63
+ });
64
+
65
+ useSetClassName({
66
+ qualifiedName: "body",
67
+ className: bodyClassName ?? kcClsx("kcBodyClass")
68
+ });
69
+
70
+ const { isReadyToRender } = useInitializeTemplate();
71
+
72
+ if (!isReadyToRender) {
73
+ return null;
74
+ }
75
+
76
+ return (
77
+ <div className="grid min-h-svh lg:grid-cols-2 bg-white dark:bg-background lg:bg-transparent">
78
+ {/* Main content */}
79
+ <div className="flex flex-col gap-4 px-0 py-0 pb-6 lg:p-6 lg:md:p-10 lg:pt-10 min-h-screen lg:min-h-0">
80
+ {/* navigation */}
81
+ <div className="absolute top-4 right-4 lg:left-4 z-20 flex gap-2">
82
+ <Button variant="outline" size="icon" >
83
+ <a href={kcContext.client.baseUrl ?? redirectUrlOrigin}>
84
+ <FiHome />
85
+ </a>
86
+ </Button>
87
+
88
+ {enabledLanguages.length > 1 && (
89
+ <Languages />
90
+ )}
91
+
92
+
93
+ {kcContext.darkMode !== false && (
94
+ <ModeToggle />
95
+ )}
96
+ </div>
97
+
98
+ {/* Mobile header with logo */}
99
+ <div className="lg:hidden relative pt-8 px-6">
100
+ {/* Logo and welcome message */}
101
+ <div className="flex flex-col items-center justify-center gap-3 mt-4">
102
+ <div className=" mb-4 flex items-center gap-3">
103
+ <img src={companylogo} alt="Logo" />
104
+ <span className=" text-xl"> {APP_NAME}</span>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <div className="flex flex-1 items-start lg:items-center justify-center lg:mt-0 ">
110
+ <div className="w-full max-w-xl ">
111
+ <Card className=" shadow-none bg-transparent lg:bg-card border-0 lg:rounded-lg lg:border lg:shadow-sm rounded-t-2xl">
112
+ <CardHeader className="text-center mb-3 px-6 pt-8 pb-4 lg:pt-6">
113
+ <CardTitle>
114
+ {(() => {
115
+ const node = !(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
116
+ <h1 className="text-xl">{headerNode}</h1>
117
+ ) : (
118
+ <div id="kc-username" className="flex items-center justify-center gap-2">
119
+ <label className="font-semibold text-lg" id="kc-attempted-username">
120
+ {auth.attemptedUsername}
121
+ </label>
122
+
123
+ <TooltipProvider>
124
+ <Tooltip>
125
+ <TooltipTrigger asChild>
126
+ <Button variant="outline" size="icon" asChild>
127
+ <a
128
+ id="reset-login"
129
+ href={url.loginRestartFlowUrl}
130
+ aria-label={msgStr("restartLoginTooltip")}
131
+ >
132
+ <RotateCcw className="h-4 w-4" />
133
+ </a>
134
+ </Button>
135
+ </TooltipTrigger>
136
+ <TooltipContent>
137
+ <p>{msg("restartLoginTooltip")}</p>
138
+ </TooltipContent>
139
+ </Tooltip>
140
+ </TooltipProvider>
141
+ </div>
142
+ );
143
+
144
+ if (displayRequiredFields) {
145
+ return (
146
+ <div className="flex items-center justify-between gap-2">
147
+ <div>{node}</div>
148
+ <div>
149
+ <span className="subtitle">
150
+ <span className="text-red-500">*</span>
151
+ {msg("requiredFields")}
152
+ </span>
153
+ </div>
154
+ </div>
155
+ );
156
+ }
157
+
158
+ return node;
159
+ })()}
160
+ </CardTitle>
161
+ </CardHeader>
162
+ <CardContent className="px-6 pb-8">
163
+ <div id="kc-content">
164
+ <div id="kc-content-wrapper">
165
+ {displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
166
+ <Alert variant={message.type} className="my-3">
167
+ <AlertDescription>
168
+ <div>
169
+ <span
170
+ dangerouslySetInnerHTML={{
171
+ __html: kcSanitize(message.summary)
172
+ }}
173
+ />
174
+ </div>
175
+ </AlertDescription>
176
+ </Alert>
177
+ )}
178
+ <div className="children">{children}</div>
179
+ {socialProvidersNode}
180
+ {auth !== undefined && auth.showTryAnotherWayLink && (
181
+ <form id="kc-select-try-another-way-form" action={url.loginAction} method="post">
182
+ <div className={kcClsx("kcFormGroupClass")}>
183
+ <input type="hidden" name="tryAnotherWay" value="on" />
184
+ <a
185
+ href="#"
186
+ id="try-another-way"
187
+ onClick={() => {
188
+ document.forms["kc-select-try-another-way-form" as never].submit();
189
+ return false;
190
+ }}
191
+ >
192
+ {msg("doTryAnotherWay")}
193
+ </a>
194
+ </div>
195
+ </form>
196
+ )}
197
+ {displayInfo && <div className="text-center text-sm mt-4">{infoNode}</div>}
198
+ </div>
199
+ </div>
200
+ </CardContent>
201
+ </Card>
202
+ </div>
203
+ </div>
204
+ </div>
205
+
206
+ <div className="bg-slate-950 relative hidden lg:block dark:bg-white/5">
207
+ <div className="flex items-center pt-20 h-full justify-center z-1">
208
+ <div className="absolute right-0 top-0 w-full max-w-62.5 xl:max-w-112.5">
209
+ <img src={shape} alt="grid" />
210
+ </div>
211
+ <div className="absolute bottom-0 left-0 w-full max-w-62.5 rotate-180 xl:max-w-112.5">
212
+ <img src={shape} alt="grid" />
213
+ </div>
214
+
215
+ <div className="flex justify-center my-auto flex-col items-center max-w-xs">
216
+ <div className=" mb-4 flex items-center gap-3">
217
+ <img src={companylogo} alt="Logo" />
218
+ <span className="text-white text-xl"> {APP_NAME}</span>
219
+ </div>
220
+
221
+ <p className="text-center text-gray-400 dark:text-white/60">{msg("welcomeMessage")}</p>
222
+ </div>
223
+ </div>
224
+ </div>
225
+ </div>
226
+ );
227
+ }
@@ -1 +1 @@
1
- export * from "./Template";
1
+ export * from "./Template";
@@ -1,61 +1,61 @@
1
- import { useEffect } from "react";
2
- import { useInsertScriptTags } from "@keycloakify/login-ui/tools/useInsertScriptTags";
3
- import { useInsertLinkTags } from "@keycloakify/login-ui/tools/useInsertLinkTags";
4
- import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
5
- import { BASE_URL } from "../../../kc.gen";
6
- import { useKcContext } from "../../KcContext";
7
-
8
- export function useInitializeTemplate() {
9
- const { kcContext } = useKcContext();
10
-
11
- const { doUseDefaultCss } = useKcClsx();
12
-
13
- const { areAllStyleSheetsLoaded } = useInsertLinkTags({
14
- effectId: "Template",
15
- hrefs: !doUseDefaultCss
16
- ? []
17
- : [
18
- `${BASE_URL}keycloak-theme/login/resources-common/node_modules/@patternfly/patternfly/patternfly.min.css`,
19
- `${BASE_URL}keycloak-theme/login/resources-common/node_modules/patternfly/dist/css/patternfly.min.css`,
20
- `${BASE_URL}keycloak-theme/login/resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css`,
21
- `${BASE_URL}keycloak-theme/login/resources-common/lib/pficon/pficon.css`,
22
- `${BASE_URL}keycloak-theme/login/css/login.css`
23
- ]
24
- });
25
-
26
- const { insertScriptTags } = useInsertScriptTags({
27
- effectId: "Template",
28
- scriptTags: [
29
- // NOTE: The importmap is added in by the FTL script because it's too late to add it here.
30
- {
31
- type: "module",
32
- src: `${BASE_URL}keycloak-theme/login/js/menu-button-links.js`
33
- },
34
- ...(kcContext.scripts === undefined
35
- ? []
36
- : kcContext.scripts.map(src => ({
37
- type: "text/javascript" as const,
38
- src
39
- }))),
40
- {
41
- type: "module",
42
- textContent: [
43
- `import { startSessionPolling, checkAuthSession } from "${BASE_URL}keycloak-theme/login/js/authChecker.js";`,
44
- ``,
45
- `startSessionPolling("${kcContext.url.ssoLoginInOtherTabsUrl}");`,
46
- kcContext.authenticationSession === undefined
47
- ? ""
48
- : `checkAuthSession("${kcContext.authenticationSession.authSessionIdHash}");`
49
- ].join("\n")
50
- }
51
- ]
52
- });
53
-
54
- useEffect(() => {
55
- if (areAllStyleSheetsLoaded) {
56
- insertScriptTags();
57
- }
58
- }, [areAllStyleSheetsLoaded]);
59
-
60
- return { isReadyToRender: areAllStyleSheetsLoaded };
61
- }
1
+ import { useEffect } from "react";
2
+ import { useInsertScriptTags } from "@keycloakify/login-ui/tools/useInsertScriptTags";
3
+ import { useInsertLinkTags } from "@keycloakify/login-ui/tools/useInsertLinkTags";
4
+ import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
5
+ import { BASE_URL } from "../../../kc.gen";
6
+ import { useKcContext } from "../../KcContext";
7
+
8
+ export function useInitializeTemplate() {
9
+ const { kcContext } = useKcContext();
10
+
11
+ const { doUseDefaultCss } = useKcClsx();
12
+
13
+ const { areAllStyleSheetsLoaded } = useInsertLinkTags({
14
+ effectId: "Template",
15
+ hrefs: !doUseDefaultCss
16
+ ? []
17
+ : [
18
+ `${BASE_URL}keycloak-theme/login/resources-common/node_modules/@patternfly/patternfly/patternfly.min.css`,
19
+ `${BASE_URL}keycloak-theme/login/resources-common/node_modules/patternfly/dist/css/patternfly.min.css`,
20
+ `${BASE_URL}keycloak-theme/login/resources-common/node_modules/patternfly/dist/css/patternfly-additions.min.css`,
21
+ `${BASE_URL}keycloak-theme/login/resources-common/lib/pficon/pficon.css`,
22
+ `${BASE_URL}keycloak-theme/login/css/login.css`
23
+ ]
24
+ });
25
+
26
+ const { insertScriptTags } = useInsertScriptTags({
27
+ effectId: "Template",
28
+ scriptTags: [
29
+ // NOTE: The importmap is added in by the FTL script because it's too late to add it here.
30
+ {
31
+ type: "module",
32
+ src: `${BASE_URL}keycloak-theme/login/js/menu-button-links.js`
33
+ },
34
+ ...(kcContext.scripts === undefined
35
+ ? []
36
+ : kcContext.scripts.map(src => ({
37
+ type: "text/javascript" as const,
38
+ src
39
+ }))),
40
+ {
41
+ type: "module",
42
+ textContent: [
43
+ `import { startSessionPolling, checkAuthSession } from "${BASE_URL}keycloak-theme/login/js/authChecker.js";`,
44
+ ``,
45
+ `startSessionPolling("${kcContext.url.ssoLoginInOtherTabsUrl}");`,
46
+ kcContext.authenticationSession === undefined
47
+ ? ""
48
+ : `checkAuthSession("${kcContext.authenticationSession.authSessionIdHash}");`
49
+ ].join("\n")
50
+ }
51
+ ]
52
+ });
53
+
54
+ useEffect(() => {
55
+ if (areAllStyleSheetsLoaded) {
56
+ insertScriptTags();
57
+ }
58
+ }, [areAllStyleSheetsLoaded]);
59
+
60
+ return { isReadyToRender: areAllStyleSheetsLoaded };
61
+ }