@hotosm/hanko-auth 0.3.5 β 0.4.2
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.
- package/README.md +71 -6
- package/dist/hanko-auth.esm.js +2854 -2089
- package/dist/hanko-auth.iife.js +472 -360
- package/dist/hanko-auth.umd.js +472 -360
- package/package.json +1 -5
- package/src/hanko-auth.styles.ts +430 -0
- package/src/hanko-auth.ts +89 -346
- package/src/hanko-i18n-es.ts +229 -0
- package/src/hanko-i18n-fr.ts +229 -0
- package/src/hanko-i18n-pt.ts +229 -0
- package/src/translations.ts +87 -0
package/src/hanko-auth.ts
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
import { LitElement, html, css } from "lit";
|
|
13
13
|
import { customElement, property, state } from "lit/decorators.js";
|
|
14
14
|
import { register } from "@teamhanko/hanko-elements";
|
|
15
|
+
import { en } from "@teamhanko/hanko-elements/i18n/en";
|
|
16
|
+
import { es } from "./hanko-i18n-es";
|
|
17
|
+
import { fr } from "./hanko-i18n-fr";
|
|
18
|
+
import { pt } from "./hanko-i18n-pt";
|
|
19
|
+
import { styles } from "./hanko-auth.styles";
|
|
20
|
+
import { translations } from "./translations";
|
|
15
21
|
//Icons
|
|
16
22
|
import accountIcon from "../assets/icon-account.svg";
|
|
17
23
|
import logoutIcon from "../assets/icon-logout.svg";
|
|
@@ -50,6 +56,7 @@ interface OSMData {
|
|
|
50
56
|
|
|
51
57
|
@customElement("hotosm-auth")
|
|
52
58
|
export class HankoAuth extends LitElement {
|
|
59
|
+
static styles = styles;
|
|
53
60
|
// Properties (from attributes)
|
|
54
61
|
@property({ type: String, attribute: "hanko-url" }) hankoUrlAttr = "";
|
|
55
62
|
@property({ type: String, attribute: "base-path" }) basePath = "";
|
|
@@ -74,6 +81,18 @@ export class HankoAuth extends LitElement {
|
|
|
74
81
|
@property({ type: String, attribute: "app-id" }) appId = "";
|
|
75
82
|
// Custom login page URL (for standalone mode - overrides ${hankoUrl}/app)
|
|
76
83
|
@property({ type: String, attribute: "login-url" }) loginUrl = "";
|
|
84
|
+
// Language code (en, es, fr, pt, etc.)
|
|
85
|
+
@property({ type: String }) lang = "en";
|
|
86
|
+
// Button variant (filled, outline, plain)
|
|
87
|
+
@property({ type: String, attribute: "button-variant" }) buttonVariant:
|
|
88
|
+
| "filled"
|
|
89
|
+
| "outline"
|
|
90
|
+
| "plain" = "plain";
|
|
91
|
+
// Button color (primary, neutral, danger)
|
|
92
|
+
@property({ type: String, attribute: "button-color" }) buttonColor:
|
|
93
|
+
| "primary"
|
|
94
|
+
| "neutral"
|
|
95
|
+
| "danger" = "primary";
|
|
77
96
|
|
|
78
97
|
// Internal state
|
|
79
98
|
@state() private user: UserState | null = null;
|
|
@@ -84,15 +103,26 @@ export class HankoAuth extends LitElement {
|
|
|
84
103
|
@state() private error: string | null = null;
|
|
85
104
|
@state() private profileDisplayName: string = "";
|
|
86
105
|
@state() private hasAppMapping = false; // True if user has mapping in the app
|
|
106
|
+
@state() private userProfileLanguage: string | null = null; // Language from user profile
|
|
87
107
|
// dropdown
|
|
88
108
|
@state() private isOpen = false;
|
|
89
109
|
|
|
90
110
|
private toggleDropdown() {
|
|
91
111
|
this.isOpen = !this.isOpen;
|
|
112
|
+
if (this.isOpen) {
|
|
113
|
+
// Add listener when dropdown opens
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
document.addEventListener("click", this.handleOutsideClick);
|
|
116
|
+
}, 0);
|
|
117
|
+
} else {
|
|
118
|
+
// Remove listener when dropdown closes
|
|
119
|
+
document.removeEventListener("click", this.handleOutsideClick);
|
|
120
|
+
}
|
|
92
121
|
}
|
|
93
122
|
|
|
94
123
|
private closeDropdown() {
|
|
95
124
|
this.isOpen = false;
|
|
125
|
+
document.removeEventListener("click", this.handleOutsideClick);
|
|
96
126
|
}
|
|
97
127
|
private handleOutsideClick = (event: MouseEvent) => {
|
|
98
128
|
if (!this.contains(event.target as Node)) {
|
|
@@ -107,332 +137,6 @@ export class HankoAuth extends LitElement {
|
|
|
107
137
|
private _hanko: any = null;
|
|
108
138
|
private _isPrimary = false; // Is this the primary instance?
|
|
109
139
|
|
|
110
|
-
static styles = css`
|
|
111
|
-
:host {
|
|
112
|
-
display: block;
|
|
113
|
-
font-family: var(--hot-font-sans);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.container {
|
|
117
|
-
max-width: 400px;
|
|
118
|
-
margin: 0 auto;
|
|
119
|
-
padding: var(--hot-spacing-large);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.loading {
|
|
123
|
-
text-align: center;
|
|
124
|
-
padding: var(--hot-spacing-3x-large);
|
|
125
|
-
color: var(--hot-color-gray-600);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.osm-connecting {
|
|
129
|
-
display: flex;
|
|
130
|
-
flex-direction: column;
|
|
131
|
-
align-items: center;
|
|
132
|
-
gap: var(--hot-spacing-small);
|
|
133
|
-
padding: var(--hot-spacing-large);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.spinner {
|
|
137
|
-
width: var(--hot-spacing-3x-large);
|
|
138
|
-
height: var(--hot-spacing-3x-large);
|
|
139
|
-
border: var(--hot-spacing-2x-small) solid var(--hot-color-gray-50);
|
|
140
|
-
border-top: var(--hot-spacing-2x-small) solid var(--hot-color-red-600);
|
|
141
|
-
border-radius: 50%;
|
|
142
|
-
animation: spin 1s linear infinite;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
@keyframes spin {
|
|
146
|
-
0% {
|
|
147
|
-
transform: rotate(0deg);
|
|
148
|
-
}
|
|
149
|
-
100% {
|
|
150
|
-
transform: rotate(360deg);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.connecting-text {
|
|
155
|
-
font-size: var(--hot-font-size-small);
|
|
156
|
-
color: var(--hot-color-gray-600);
|
|
157
|
-
font-weight: var(--hot-font-weight-semibold);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
button {
|
|
161
|
-
width: 100%;
|
|
162
|
-
padding: 12px 20px;
|
|
163
|
-
border: none;
|
|
164
|
-
border-radius: 6px;
|
|
165
|
-
font-size: 14px;
|
|
166
|
-
font-weight: 500;
|
|
167
|
-
cursor: pointer;
|
|
168
|
-
transition: all 0.2s;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.btn-primary {
|
|
172
|
-
background: var(--hot-color-gray-700);
|
|
173
|
-
color: white;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.btn-primary:hover {
|
|
177
|
-
background: var(--hot-color-gray-600);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.btn-secondary {
|
|
181
|
-
border: 1px solid var(--hot-color-gray-700);
|
|
182
|
-
border-radius: var(--hot-border-radius-medium);
|
|
183
|
-
background-color: white;
|
|
184
|
-
color: var(--hot-color-gray-700);
|
|
185
|
-
margin-top: 8px;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.btn-secondary:hover {
|
|
189
|
-
background: var(--hot-color-gray-50);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.error {
|
|
193
|
-
background: var(--hot-color-red-50);
|
|
194
|
-
border: var(--hot-border-width, 1px) solid var(--hot-color-red-200);
|
|
195
|
-
border-radius: var(--hot-border-radius-medium);
|
|
196
|
-
padding: var(--hot-spacing-small);
|
|
197
|
-
color: var(--hot-color-red-700);
|
|
198
|
-
margin-bottom: var(--hot-spacing-medium);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.profile {
|
|
202
|
-
background: var(--hot-color-gray-50);
|
|
203
|
-
border-radius: var(--hot-border-radius-large);
|
|
204
|
-
padding: var(--hot-spacing-large);
|
|
205
|
-
margin-bottom: var(--hot-spacing-medium);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.profile-header {
|
|
209
|
-
display: flex;
|
|
210
|
-
align-items: center;
|
|
211
|
-
gap: var(--hot-spacing-small);
|
|
212
|
-
margin-bottom: var(--hot-spacing-medium);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
.profile-avatar {
|
|
216
|
-
width: var(--hot-spacing-3x-large);
|
|
217
|
-
height: var(--hot-spacing-3x-large);
|
|
218
|
-
border-radius: 50%;
|
|
219
|
-
background: var(--hot-color-gray-200);
|
|
220
|
-
display: flex;
|
|
221
|
-
align-items: center;
|
|
222
|
-
justify-content: center;
|
|
223
|
-
font-size: var(--hot-font-size-large);
|
|
224
|
-
font-weight: var(--hot-font-weight-bold);
|
|
225
|
-
color: var(--hot-color-gray-600);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.profile-info {
|
|
229
|
-
padding: var(--hot-spacing-x-small) var(--hot-spacing-medium);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.profile-email {
|
|
233
|
-
font-size: var(--hot-font-size-small);
|
|
234
|
-
font-weight: var(--hot-font-weight-bold);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
.osm-section {
|
|
238
|
-
border-top: var(--hot-border-width, 1px) solid var(--hot-color-gray-100);
|
|
239
|
-
padding-top: var(--hot-spacing-medium);
|
|
240
|
-
padding-bottom: var(--hot-spacing-small);
|
|
241
|
-
margin-top: var(--hot-spacing-medium);
|
|
242
|
-
text-align: center;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
.osm-connected {
|
|
246
|
-
display: flex;
|
|
247
|
-
align-items: center;
|
|
248
|
-
justify-content: center;
|
|
249
|
-
padding: var(--hot-spacing-small);
|
|
250
|
-
background: linear-gradient(
|
|
251
|
-
135deg,
|
|
252
|
-
var(--hot-color-success-50) 0%,
|
|
253
|
-
var(--hot-color-success-50) 100%
|
|
254
|
-
);
|
|
255
|
-
border-radius: var(--hot-border-radius-large);
|
|
256
|
-
border: var(--hot-border-width, 1px) solid var(--hot-color-success-200);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.osm-badge {
|
|
260
|
-
display: flex;
|
|
261
|
-
align-items: center;
|
|
262
|
-
gap: var(--hot-spacing-x-small);
|
|
263
|
-
color: var(--hot-color-success-800);
|
|
264
|
-
font-weight: var(--hot-font-weight-semibold);
|
|
265
|
-
font-size: var(--hot-font-size-small);
|
|
266
|
-
text-align: left;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.osm-badge-icon {
|
|
270
|
-
font-size: var(--hot-font-size-medium);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
.osm-username {
|
|
274
|
-
font-size: var(--hot-font-size-x-small);
|
|
275
|
-
color: var(--hot-color-success-700);
|
|
276
|
-
margin-top: var(--hot-spacing-2x-small);
|
|
277
|
-
}
|
|
278
|
-
.osm-prompt {
|
|
279
|
-
background: var(--hot-color-warning-50);
|
|
280
|
-
border: var(--hot-border-width, 1px) solid var(--hot-color-warning-200);
|
|
281
|
-
border-radius: var(--hot-border-radius-large);
|
|
282
|
-
padding: var(--hot-spacing-large);
|
|
283
|
-
margin-bottom: var(--hot-spacing-medium);
|
|
284
|
-
text-align: center;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.osm-prompt-title {
|
|
288
|
-
font-weight: var(--hot-font-weight-semibold);
|
|
289
|
-
font-size: var(--hot-font-size-medium);
|
|
290
|
-
margin-bottom: var(--hot-spacing-small);
|
|
291
|
-
color: var(--hot-color-gray-900);
|
|
292
|
-
text-align: center;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.osm-prompt-text {
|
|
296
|
-
font-size: var(--hot-font-size-small);
|
|
297
|
-
color: var(--hot-color-gray-600);
|
|
298
|
-
margin-bottom: var(--hot-spacing-medium);
|
|
299
|
-
line-height: var(--hot-line-height-normal);
|
|
300
|
-
text-align: center;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
.osm-status-badge {
|
|
304
|
-
position: absolute;
|
|
305
|
-
top: 2px;
|
|
306
|
-
right: 2px;
|
|
307
|
-
width: var(--hot-font-size-small);
|
|
308
|
-
height: var(--hot-font-size-small);
|
|
309
|
-
border-radius: 50%;
|
|
310
|
-
border: var(--hot-spacing-3x-small) solid white;
|
|
311
|
-
display: flex;
|
|
312
|
-
align-items: center;
|
|
313
|
-
justify-content: center;
|
|
314
|
-
font-size: var(--hot-font-size-2x-small);
|
|
315
|
-
color: white;
|
|
316
|
-
font-weight: var(--hot-font-weight-bold);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
.osm-status-badge.connected {
|
|
320
|
-
background-color: var(--hot-color-success-600);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
.osm-status-badge.required {
|
|
324
|
-
background-color: var(--hot-color-warning-600);
|
|
325
|
-
}
|
|
326
|
-
.header-avatar {
|
|
327
|
-
width: var(--hot-spacing-2x-large);
|
|
328
|
-
height: var(--hot-spacing-2x-large);
|
|
329
|
-
border-radius: 50%;
|
|
330
|
-
background: var(--hot-color-gray-800);
|
|
331
|
-
display: inline-flex;
|
|
332
|
-
align-items: center;
|
|
333
|
-
justify-content: center;
|
|
334
|
-
font-size: var(--hot-font-size-small);
|
|
335
|
-
font-weight: var(--hot-font-weight-semibold);
|
|
336
|
-
color: white;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
.login-link {
|
|
340
|
-
color: var(--hot-color-neutral-950);
|
|
341
|
-
font-size: var(--hot-font-size-small);
|
|
342
|
-
border-radius: var(--hot-border-radius-medium);
|
|
343
|
-
text-decoration: none;
|
|
344
|
-
padding: 14px;
|
|
345
|
-
}
|
|
346
|
-
.login-link:hover {
|
|
347
|
-
background: var(--hot-color-gray-50);
|
|
348
|
-
}
|
|
349
|
-
/* Dropdown styles */
|
|
350
|
-
.dropdown {
|
|
351
|
-
position: relative;
|
|
352
|
-
display: inline-block;
|
|
353
|
-
}
|
|
354
|
-
.dropdown-trigger {
|
|
355
|
-
background: none;
|
|
356
|
-
border: none;
|
|
357
|
-
padding: var(--hot-spacing-x-small);
|
|
358
|
-
cursor: pointer;
|
|
359
|
-
position: relative;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
.dropdown-trigger.no-hover:hover,
|
|
363
|
-
.dropdown-trigger.no-hover:active,
|
|
364
|
-
.dropdown-trigger.no-hover:focus {
|
|
365
|
-
background: none;
|
|
366
|
-
outline: none;
|
|
367
|
-
}
|
|
368
|
-
.dropdown-content {
|
|
369
|
-
position: absolute;
|
|
370
|
-
right: 0;
|
|
371
|
-
background: white;
|
|
372
|
-
border: 1px solid var(--hot-color-gray-100);
|
|
373
|
-
border-radius: var(--hot-border-radius-medium);
|
|
374
|
-
z-index: 1000;
|
|
375
|
-
opacity: 0;
|
|
376
|
-
visibility: hidden;
|
|
377
|
-
transform: translateY(-10px);
|
|
378
|
-
transition:
|
|
379
|
-
opacity 0.2s ease,
|
|
380
|
-
visibility 0.2s ease,
|
|
381
|
-
transform 0.2s ease;
|
|
382
|
-
}
|
|
383
|
-
@media (max-width: 768px) {
|
|
384
|
-
.dropdown-content {
|
|
385
|
-
position: fixed;
|
|
386
|
-
width: 100%;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
.dropdown-content.open {
|
|
391
|
-
opacity: 1;
|
|
392
|
-
visibility: visible;
|
|
393
|
-
transform: translateY(0);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
.dropdown-content button {
|
|
397
|
-
display: flex;
|
|
398
|
-
align-items: center;
|
|
399
|
-
width: 100%;
|
|
400
|
-
padding: var(--hot-spacing-small) var(--hot-spacing-medium);
|
|
401
|
-
background: none;
|
|
402
|
-
border: none;
|
|
403
|
-
cursor: pointer;
|
|
404
|
-
text-align: left;
|
|
405
|
-
transition: background-color 0.2s ease;
|
|
406
|
-
gap: var(--hot-spacing-small);
|
|
407
|
-
font-size: var(--hot-font-size-small);
|
|
408
|
-
color: var(--hot-color-gray-900);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
.dropdown-content button:hover {
|
|
412
|
-
background-color: var(--hot-color-gray-50);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
.dropdown-content button:focus {
|
|
416
|
-
background-color: var(--hot-color-gray-50);
|
|
417
|
-
outline: 2px solid var(--hot-color-gray-500);
|
|
418
|
-
outline-offset: -2px;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
.dropdown-content .profile-info {
|
|
422
|
-
padding: var(--hot-spacing-small) var(--hot-spacing-medium);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
.dropdown-content .profile-email {
|
|
426
|
-
font-size: var(--hot-font-size-small);
|
|
427
|
-
font-weight: var(--hot-font-weight-bold);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
.icon {
|
|
431
|
-
width: 20px;
|
|
432
|
-
height: 20px;
|
|
433
|
-
}
|
|
434
|
-
`;
|
|
435
|
-
|
|
436
140
|
// Get computed hankoUrl (priority: attribute > meta tag > window.HANKO_URL > origin)
|
|
437
141
|
get hankoUrl(): string {
|
|
438
142
|
if (this.hankoUrlAttr) {
|
|
@@ -619,6 +323,21 @@ export class HankoAuth extends LitElement {
|
|
|
619
323
|
}
|
|
620
324
|
}
|
|
621
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Get translated string for the current language
|
|
328
|
+
* Falls back to English if translation not found
|
|
329
|
+
* When user is logged in, uses their profile language instead of the lang prop
|
|
330
|
+
*/
|
|
331
|
+
private t(key: keyof typeof translations.en): string {
|
|
332
|
+
// When user is logged in, use their profile language
|
|
333
|
+
const effectiveLang =
|
|
334
|
+
this.user && this.userProfileLanguage
|
|
335
|
+
? this.userProfileLanguage
|
|
336
|
+
: this.lang;
|
|
337
|
+
const langTranslations = translations[effectiveLang] || translations.en;
|
|
338
|
+
return langTranslations[key] || translations.en[key] || key;
|
|
339
|
+
}
|
|
340
|
+
|
|
622
341
|
private warn(...args: any[]) {
|
|
623
342
|
console.warn(...args);
|
|
624
343
|
}
|
|
@@ -648,11 +367,12 @@ export class HankoAuth extends LitElement {
|
|
|
648
367
|
return path;
|
|
649
368
|
}
|
|
650
369
|
|
|
370
|
+
// styles injected to ensure global availability
|
|
651
371
|
private injectHotStyles() {
|
|
652
372
|
const stylesheets = [
|
|
653
373
|
{
|
|
654
374
|
id: "hot-design-system",
|
|
655
|
-
href: "https://cdn.jsdelivr.net/npm/
|
|
375
|
+
href: "https://cdn.jsdelivr.net/npm/@hotosm/ui-design@latest/dist/hot.css",
|
|
656
376
|
},
|
|
657
377
|
{
|
|
658
378
|
id: "google-font-archivo",
|
|
@@ -678,10 +398,16 @@ export class HankoAuth extends LitElement {
|
|
|
678
398
|
return;
|
|
679
399
|
}
|
|
680
400
|
|
|
401
|
+
// DEBUG: Add delay to see loading state longer (remove in production)
|
|
402
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
403
|
+
|
|
681
404
|
try {
|
|
682
405
|
await register(this.hankoUrl, {
|
|
683
406
|
enablePasskeys: false,
|
|
684
407
|
hidePasskeyButtonOnLogin: true,
|
|
408
|
+
translations: { en, es, fr, pt },
|
|
409
|
+
translationsLocation: null,
|
|
410
|
+
fallbackLanguage: "en",
|
|
685
411
|
});
|
|
686
412
|
|
|
687
413
|
// Create persistent Hanko instance and set up session event listeners
|
|
@@ -1072,7 +798,7 @@ export class HankoAuth extends LitElement {
|
|
|
1072
798
|
}
|
|
1073
799
|
}
|
|
1074
800
|
|
|
1075
|
-
// Fetch profile display name from login backend
|
|
801
|
+
// Fetch profile display name and language from login backend
|
|
1076
802
|
private async fetchProfileDisplayName() {
|
|
1077
803
|
try {
|
|
1078
804
|
const profileUrl = `${this.hankoUrl}/api/profile/me`;
|
|
@@ -1091,6 +817,12 @@ export class HankoAuth extends LitElement {
|
|
|
1091
817
|
`${profile.first_name || ""} ${profile.last_name || ""}`.trim();
|
|
1092
818
|
this.log("π€ Display name set to:", this.profileDisplayName);
|
|
1093
819
|
}
|
|
820
|
+
|
|
821
|
+
// Set language from user profile if available
|
|
822
|
+
if (profile.language) {
|
|
823
|
+
this.userProfileLanguage = profile.language;
|
|
824
|
+
this.log("π Language set from profile:", this.userProfileLanguage);
|
|
825
|
+
}
|
|
1094
826
|
}
|
|
1095
827
|
} catch (error) {
|
|
1096
828
|
this.log("β οΈ Could not fetch profile:", error);
|
|
@@ -1426,6 +1158,7 @@ export class HankoAuth extends LitElement {
|
|
|
1426
1158
|
this.osmConnected = false;
|
|
1427
1159
|
this.osmData = null;
|
|
1428
1160
|
this.hasAppMapping = false;
|
|
1161
|
+
this.userProfileLanguage = null; // Clear user's language preference
|
|
1429
1162
|
|
|
1430
1163
|
// Broadcast state changes to other instances
|
|
1431
1164
|
if (this._isPrimary) {
|
|
@@ -1590,7 +1323,7 @@ export class HankoAuth extends LitElement {
|
|
|
1590
1323
|
);
|
|
1591
1324
|
|
|
1592
1325
|
if (this.loading) {
|
|
1593
|
-
return html
|
|
1326
|
+
return html`<span class="loading-placeholder"><span class="loading-placeholder-text">${this.t("logIn")}</span><span class="spinner-small"></span></span>`;
|
|
1594
1327
|
}
|
|
1595
1328
|
|
|
1596
1329
|
if (this.error) {
|
|
@@ -1631,7 +1364,9 @@ export class HankoAuth extends LitElement {
|
|
|
1631
1364
|
${this.osmRequired && this.osmLoading
|
|
1632
1365
|
? html`
|
|
1633
1366
|
<div class="osm-section">
|
|
1634
|
-
<div class="loading">
|
|
1367
|
+
<div class="loading">
|
|
1368
|
+
${this.t("checkingOsmConnection")}
|
|
1369
|
+
</div>
|
|
1635
1370
|
</div>
|
|
1636
1371
|
`
|
|
1637
1372
|
: this.osmRequired && this.osmConnected
|
|
@@ -1641,7 +1376,7 @@ export class HankoAuth extends LitElement {
|
|
|
1641
1376
|
<div class="osm-badge">
|
|
1642
1377
|
<span class="osm-badge-icon">πΊοΈ</span>
|
|
1643
1378
|
<div>
|
|
1644
|
-
<div
|
|
1379
|
+
<div>${this.t("connectedToOpenStreetMap")}</div>
|
|
1645
1380
|
${this.osmData?.osm_username
|
|
1646
1381
|
? html`
|
|
1647
1382
|
<div class="osm-username">
|
|
@@ -1663,20 +1398,22 @@ export class HankoAuth extends LitElement {
|
|
|
1663
1398
|
<div class="osm-connecting">
|
|
1664
1399
|
<div class="spinner"></div>
|
|
1665
1400
|
<div class="connecting-text">
|
|
1666
|
-
πΊοΈ
|
|
1401
|
+
πΊοΈ ${this.t("connectingToOpenStreetMap")}
|
|
1667
1402
|
</div>
|
|
1668
1403
|
</div>
|
|
1669
1404
|
`
|
|
1670
1405
|
: html`
|
|
1671
|
-
<div class="osm-prompt-title"
|
|
1406
|
+
<div class="osm-prompt-title">
|
|
1407
|
+
π ${this.t("osmRequired")}
|
|
1408
|
+
</div>
|
|
1672
1409
|
<div class="osm-prompt-text">
|
|
1673
|
-
|
|
1410
|
+
${this.t("osmRequiredText")}
|
|
1674
1411
|
</div>
|
|
1675
1412
|
<button
|
|
1676
1413
|
@click=${this.handleOSMConnect}
|
|
1677
1414
|
class="btn-primary"
|
|
1678
1415
|
>
|
|
1679
|
-
|
|
1416
|
+
${this.t("connectOsmAccount")}
|
|
1680
1417
|
</button>
|
|
1681
1418
|
`}
|
|
1682
1419
|
</div>
|
|
@@ -1684,7 +1421,7 @@ export class HankoAuth extends LitElement {
|
|
|
1684
1421
|
: ""}
|
|
1685
1422
|
|
|
1686
1423
|
<button @click=${this.handleLogout} class="btn-secondary">
|
|
1687
|
-
|
|
1424
|
+
${this.t("logOut")}
|
|
1688
1425
|
</button>
|
|
1689
1426
|
</div>
|
|
1690
1427
|
</div>
|
|
@@ -1695,7 +1432,7 @@ export class HankoAuth extends LitElement {
|
|
|
1695
1432
|
<div class="dropdown">
|
|
1696
1433
|
<button
|
|
1697
1434
|
@click=${this.toggleDropdown}
|
|
1698
|
-
aria-label="
|
|
1435
|
+
aria-label="${this.t("openAccountMenu")}"
|
|
1699
1436
|
aria-expanded=${this.isOpen}
|
|
1700
1437
|
aria-haspopup="true"
|
|
1701
1438
|
class="dropdown-trigger"
|
|
@@ -1706,7 +1443,8 @@ export class HankoAuth extends LitElement {
|
|
|
1706
1443
|
? html`
|
|
1707
1444
|
<span
|
|
1708
1445
|
class="osm-status-badge connected"
|
|
1709
|
-
title="
|
|
1446
|
+
title="${this.t("connectedToOsmAs")} @${this.osmData
|
|
1447
|
+
?.osm_username}"
|
|
1710
1448
|
>β</span
|
|
1711
1449
|
>
|
|
1712
1450
|
`
|
|
@@ -1714,7 +1452,7 @@ export class HankoAuth extends LitElement {
|
|
|
1714
1452
|
? html`
|
|
1715
1453
|
<span
|
|
1716
1454
|
class="osm-status-badge required"
|
|
1717
|
-
title="
|
|
1455
|
+
title="${this.t("osmConnectionRequired")}"
|
|
1718
1456
|
>!</span
|
|
1719
1457
|
>
|
|
1720
1458
|
`
|
|
@@ -1728,14 +1466,15 @@ export class HankoAuth extends LitElement {
|
|
|
1728
1466
|
</div>
|
|
1729
1467
|
<button data-action="profile" @click=${this.handleDropdownSelect}>
|
|
1730
1468
|
<img src="${accountIcon}" class="icon" alt="Account icon" />
|
|
1731
|
-
|
|
1469
|
+
${this.t("myHotAccount")}
|
|
1732
1470
|
</button>
|
|
1733
1471
|
${this.osmRequired
|
|
1734
1472
|
? this.osmConnected
|
|
1735
1473
|
? html`
|
|
1736
1474
|
<button class="osm-connected" disabled>
|
|
1737
1475
|
<img src="${checkIcon}" alt="Check icon" class="icon" />
|
|
1738
|
-
|
|
1476
|
+
${this.t("connectedToOsm")}
|
|
1477
|
+
(@${this.osmData?.osm_username})
|
|
1739
1478
|
</button>
|
|
1740
1479
|
`
|
|
1741
1480
|
: html`
|
|
@@ -1744,13 +1483,13 @@ export class HankoAuth extends LitElement {
|
|
|
1744
1483
|
@click=${this.handleDropdownSelect}
|
|
1745
1484
|
>
|
|
1746
1485
|
<img src="${mapIcon}" alt="Check icon" class="icon" />
|
|
1747
|
-
|
|
1486
|
+
${this.t("connectToOsm")}
|
|
1748
1487
|
</button>
|
|
1749
1488
|
`
|
|
1750
1489
|
: ""}
|
|
1751
1490
|
<button data-action="logout" @click=${this.handleDropdownSelect}>
|
|
1752
1491
|
<img src="${logoutIcon}" alt="Log out icon" class="icon" />
|
|
1753
|
-
|
|
1492
|
+
${this.t("logOut")}
|
|
1754
1493
|
</button>
|
|
1755
1494
|
</div>
|
|
1756
1495
|
</div>
|
|
@@ -1785,7 +1524,7 @@ export class HankoAuth extends LitElement {
|
|
|
1785
1524
|
--headline2-font-weight: var(--hot-font-weight-semibold);
|
|
1786
1525
|
"
|
|
1787
1526
|
>
|
|
1788
|
-
<hanko-auth></hanko-auth>
|
|
1527
|
+
<hanko-auth lang="${this.lang}"></hanko-auth>
|
|
1789
1528
|
</div>
|
|
1790
1529
|
`;
|
|
1791
1530
|
} else {
|
|
@@ -1810,9 +1549,13 @@ export class HankoAuth extends LitElement {
|
|
|
1810
1549
|
const loginBase = this.loginUrl || `${baseUrl}/app`;
|
|
1811
1550
|
const loginUrl = `${loginBase}?return_to=${encodeURIComponent(
|
|
1812
1551
|
returnTo,
|
|
1813
|
-
)}${this.osmRequired ? "&osm_required=true" : ""}${autoConnectParam}`;
|
|
1552
|
+
)}${this.osmRequired ? "&osm_required=true" : ""}${autoConnectParam}&lang=${this.lang}`;
|
|
1814
1553
|
|
|
1815
|
-
return html`<a
|
|
1554
|
+
return html`<a
|
|
1555
|
+
class="login-link ${this.buttonVariant} ${this.buttonColor}"
|
|
1556
|
+
href="${loginUrl}"
|
|
1557
|
+
>${this.t("logIn")}</a
|
|
1558
|
+
> `;
|
|
1816
1559
|
}
|
|
1817
1560
|
}
|
|
1818
1561
|
}
|