@glideidentity/web-client-sdk 5.0.1-beta.0 → 5.1.1-beta.1
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 +8 -108
- package/dist/adapters/angular/index.js +1 -0
- package/dist/adapters/angular/phone-auth.service.d.ts +18 -0
- package/dist/adapters/angular/phone-auth.service.js +26 -0
- package/dist/adapters/react/index.js +3 -0
- package/dist/adapters/react/useClient.js +1 -0
- package/dist/adapters/react/usePhoneAuth.js +16 -1
- package/dist/adapters/vanilla/client.js +1 -0
- package/dist/adapters/vanilla/index.js +1 -0
- package/dist/adapters/vanilla/phone-auth.js +31 -0
- package/dist/adapters/vue/index.js +4 -0
- package/dist/adapters/vue/useClient.js +5 -0
- package/dist/adapters/vue/usePhoneAuth.js +20 -1
- package/dist/browser/web-client-sdk.min.js +1 -2
- package/dist/browser.js +6 -0
- package/dist/core/client.js +12 -0
- package/dist/core/logger.js +81 -1
- package/dist/core/phone-auth/api-types.d.ts +1 -4
- package/dist/core/phone-auth/api-types.js +83 -0
- package/dist/core/phone-auth/client.js +374 -38
- package/dist/core/phone-auth/error-utils.js +83 -1
- package/dist/core/phone-auth/index.d.ts +1 -1
- package/dist/core/phone-auth/index.js +2 -2
- package/dist/core/phone-auth/status-types.d.ts +78 -0
- package/dist/core/phone-auth/status-types.js +17 -0
- package/dist/core/phone-auth/strategies/desktop.d.ts +2 -0
- package/dist/core/phone-auth/strategies/desktop.js +136 -13
- package/dist/core/phone-auth/strategies/index.d.ts +4 -0
- package/dist/core/phone-auth/strategies/index.js +4 -0
- package/dist/core/phone-auth/strategies/link.d.ts +2 -0
- package/dist/core/phone-auth/strategies/link.js +97 -13
- package/dist/core/phone-auth/strategies/ts43.d.ts +19 -0
- package/dist/core/phone-auth/strategies/ts43.js +33 -2
- package/dist/core/phone-auth/strategies/types.js +4 -0
- package/dist/core/phone-auth/type-guards.js +131 -0
- package/dist/core/phone-auth/types.d.ts +5 -0
- package/dist/core/phone-auth/types.js +32 -0
- package/dist/core/phone-auth/ui/mobile-debug-console.js +28 -2
- package/dist/core/phone-auth/ui/modal.d.ts +55 -33
- package/dist/core/phone-auth/ui/modal.js +422 -889
- package/dist/core/phone-auth/validation-utils.d.ts +0 -9
- package/dist/core/phone-auth/validation-utils.js +34 -25
- package/dist/core/version.js +2 -1
- package/dist/esm/adapters/angular/index.js +1 -0
- package/dist/esm/adapters/angular/phone-auth.service.d.ts +18 -0
- package/dist/esm/adapters/angular/phone-auth.service.js +26 -0
- package/dist/esm/adapters/react/index.js +3 -0
- package/dist/esm/adapters/react/useClient.js +1 -0
- package/dist/esm/adapters/react/usePhoneAuth.js +16 -1
- package/dist/esm/adapters/vanilla/client.js +1 -0
- package/dist/esm/adapters/vanilla/index.js +1 -0
- package/dist/esm/adapters/vanilla/phone-auth.d.ts +24 -0
- package/dist/esm/adapters/vanilla/phone-auth.js +31 -0
- package/dist/esm/adapters/vue/index.js +4 -0
- package/dist/esm/adapters/vue/useClient.js +5 -0
- package/dist/esm/adapters/vue/usePhoneAuth.js +20 -1
- package/dist/esm/browser.js +6 -0
- package/dist/esm/core/client.d.ts +10 -0
- package/dist/esm/core/client.js +12 -0
- package/dist/esm/core/logger.d.ts +53 -0
- package/dist/esm/core/logger.js +81 -1
- package/dist/esm/core/phone-auth/api-types.d.ts +313 -1
- package/dist/esm/core/phone-auth/api-types.js +83 -0
- package/dist/esm/core/phone-auth/client.d.ts +144 -0
- package/dist/esm/core/phone-auth/client.js +375 -39
- package/dist/esm/core/phone-auth/error-utils.d.ts +29 -0
- package/dist/esm/core/phone-auth/error-utils.js +83 -1
- package/dist/esm/core/phone-auth/index.d.ts +1 -1
- package/dist/esm/core/phone-auth/index.js +4 -2
- package/dist/esm/core/phone-auth/status-types.d.ts +78 -0
- package/dist/esm/core/phone-auth/status-types.js +17 -0
- package/dist/esm/core/phone-auth/strategies/desktop.d.ts +65 -0
- package/dist/esm/core/phone-auth/strategies/desktop.js +136 -13
- package/dist/esm/core/phone-auth/strategies/index.d.ts +4 -0
- package/dist/esm/core/phone-auth/strategies/index.js +4 -0
- package/dist/esm/core/phone-auth/strategies/link.d.ts +50 -0
- package/dist/esm/core/phone-auth/strategies/link.js +97 -13
- package/dist/esm/core/phone-auth/strategies/ts43.d.ts +19 -0
- package/dist/esm/core/phone-auth/strategies/ts43.js +33 -2
- package/dist/esm/core/phone-auth/strategies/types.d.ts +13 -0
- package/dist/esm/core/phone-auth/strategies/types.js +4 -0
- package/dist/esm/core/phone-auth/type-guards.d.ts +128 -0
- package/dist/esm/core/phone-auth/type-guards.js +131 -0
- package/dist/esm/core/phone-auth/types.d.ts +113 -0
- package/dist/esm/core/phone-auth/types.js +32 -0
- package/dist/esm/core/phone-auth/ui/mobile-debug-console.d.ts +4 -0
- package/dist/esm/core/phone-auth/ui/mobile-debug-console.js +28 -2
- package/dist/esm/core/phone-auth/ui/modal.d.ts +68 -27
- package/dist/esm/core/phone-auth/ui/modal.js +422 -889
- package/dist/esm/core/phone-auth/validation-utils.d.ts +26 -4
- package/dist/esm/core/phone-auth/validation-utils.js +34 -24
- package/dist/esm/core/types.d.ts +35 -0
- package/dist/esm/core/version.js +2 -1
- package/dist/esm/index.js +9 -1
- package/dist/index.js +7 -0
- package/package.json +1 -1
- package/dist/browser/web-client-sdk.min.js.LICENSE.txt +0 -1
|
@@ -1,40 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Modal UI Component for Phone Authentication
|
|
4
|
+
*
|
|
5
|
+
* This file creates the UI components (modals, buttons) that are shown
|
|
6
|
+
* when the SDK is NOT in headless mode. Think of it like a popup window
|
|
7
|
+
* that handles the authentication flow for you.
|
|
8
|
+
*/
|
|
9
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
10
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
11
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
12
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
13
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
14
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
15
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
|
+
});
|
|
17
|
+
};
|
|
2
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
19
|
exports.AuthModal = void 0;
|
|
20
|
+
/**
|
|
21
|
+
* Creates and manages a modal dialog for authentication
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const modal = new AuthModal({
|
|
25
|
+
* title: "Verify Your Phone",
|
|
26
|
+
* description: "Complete authentication to continue"
|
|
27
|
+
* });
|
|
28
|
+
* modal.show();
|
|
29
|
+
*/
|
|
4
30
|
class AuthModal {
|
|
5
31
|
constructor(options, callbacks) {
|
|
6
32
|
this.container = null;
|
|
7
33
|
this.backdrop = null;
|
|
8
34
|
this.isOpen = false;
|
|
9
|
-
this.currentStep = 'os-choice';
|
|
10
|
-
this.qrCodeData = null;
|
|
11
|
-
this.statusMessage = '';
|
|
12
|
-
this.originalBodyOverflow = '';
|
|
13
|
-
this.isClosing = false;
|
|
14
|
-
this.iconApple = `<svg class="glide-icon glide-icon-os" viewBox="0 0 384 512" fill="currentColor"><path d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 52.3-11.4 69.5-34.3z"/></svg>`;
|
|
15
|
-
this.iconAndroid = `<svg class="glide-icon glide-icon-os" viewBox="0 0 576 512" fill="currentColor"><path d="M420.55,301.93a24,24,0,1,1,24-24,24,24,0,0,1-24,24m-265.1,0a24,24,0,1,1,24-24,24,24,0,0,1-24,24m273.7-144.48,47.94-83a10,10,0,1,0-17.27-10h0l-48.54,84.07a301.25,301.25,0,0,0-246.56,0L116.18,64.45a10,10,0,1,0-17.27,10h0l47.94,83C64.53,202.22,8.24,285.55,0,384H576c-8.24-98.45-64.54-181.78-146.85-226.55"/></svg>`;
|
|
16
|
-
this.iconBack = `<svg class="glide-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>`;
|
|
17
35
|
this.options = options || {};
|
|
18
36
|
this.callbacks = callbacks || {};
|
|
19
|
-
|
|
37
|
+
// Bind escape key handler
|
|
20
38
|
this.handleEscapeKey = this.handleEscapeKey.bind(this);
|
|
21
39
|
}
|
|
22
|
-
shouldUseDarkMode() {
|
|
23
|
-
if (this.theme === 'dark')
|
|
24
|
-
return true;
|
|
25
|
-
if (this.theme === 'light')
|
|
26
|
-
return false;
|
|
27
|
-
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
28
|
-
}
|
|
29
40
|
handleEscapeKey(event) {
|
|
30
41
|
var _a, _b;
|
|
31
42
|
if (event.key === 'Escape' && this.isOpen) {
|
|
43
|
+
// Check if escape closing is enabled (default true)
|
|
32
44
|
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.closeOnEscape) !== false) {
|
|
33
|
-
(_b = this.closeCallback) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
45
|
+
(_b = this.closeCallback) === null || _b === void 0 ? void 0 : _b.call(this); // Call the cancellation callback if set
|
|
34
46
|
this.close();
|
|
35
47
|
}
|
|
36
48
|
}
|
|
37
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Escape HTML to prevent XSS attacks
|
|
52
|
+
*/
|
|
38
53
|
escapeHtml(unsafe) {
|
|
39
54
|
return unsafe
|
|
40
55
|
.replace(/&/g, "&")
|
|
@@ -43,1023 +58,541 @@ class AuthModal {
|
|
|
43
58
|
.replace(/"/g, """)
|
|
44
59
|
.replace(/'/g, "'");
|
|
45
60
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Shows the modal with a QR code for desktop authentication
|
|
63
|
+
* Supports both single QR code (legacy) and dual-platform QR codes (iOS + Android)
|
|
64
|
+
*/
|
|
65
|
+
showQRCode(qrCodeData, statusMessage = 'Scan QR code with your phone') {
|
|
66
|
+
console.log('[Modal] showQRCode called with:', qrCodeData);
|
|
67
|
+
// If modal is already open, don't recreate it
|
|
68
|
+
if (this.isOpen) {
|
|
69
|
+
console.log('[Modal] Modal already open, skipping recreation');
|
|
70
|
+
return;
|
|
52
71
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
break;
|
|
72
|
+
// Check if it's the new dual-platform format with VALID Android QR code
|
|
73
|
+
if (typeof qrCodeData === 'object' && qrCodeData.iosQRCode) {
|
|
74
|
+
const hasValidAndroidQR = qrCodeData.androidQRCode &&
|
|
75
|
+
qrCodeData.androidQRCode.length > 0 &&
|
|
76
|
+
qrCodeData.androidQRCode !== qrCodeData.iosQRCode;
|
|
77
|
+
console.log('[Modal] Has valid Android QR?', hasValidAndroidQR);
|
|
78
|
+
if (hasValidAndroidQR) {
|
|
79
|
+
console.log('[Modal] Using dual-platform modal');
|
|
80
|
+
this.createDualPlatformQRModal(qrCodeData, statusMessage);
|
|
81
|
+
// Note: createDualPlatformQRModal calls show() internally
|
|
82
|
+
return;
|
|
65
83
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (isError) {
|
|
76
|
-
el.style.color = '#ff3b30';
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
el.style.color = '';
|
|
80
|
-
}
|
|
84
|
+
else {
|
|
85
|
+
console.log('[Modal] Android QR missing/empty, using single iOS QR');
|
|
86
|
+
// Only iOS QR code available - show single QR
|
|
87
|
+
this.createModal(`
|
|
88
|
+
<div class="glide-auth-qr-container">
|
|
89
|
+
<img src="${this.escapeHtml(qrCodeData.iosQRCode)}" alt="QR Code" class="glide-auth-qr-code" />
|
|
90
|
+
<p class="glide-auth-status">Scan with your iPhone to authenticate</p>
|
|
91
|
+
</div>
|
|
92
|
+
`);
|
|
81
93
|
}
|
|
82
94
|
}
|
|
83
|
-
}
|
|
84
|
-
setCloseCallback(callback) {
|
|
85
|
-
this.closeCallback = callback;
|
|
86
|
-
}
|
|
87
|
-
renderToggleMode(data, msg) {
|
|
88
|
-
let iosQR = '';
|
|
89
|
-
let androidQR = '';
|
|
90
|
-
if (typeof data === 'string') {
|
|
91
|
-
iosQR = data;
|
|
92
|
-
androidQR = data;
|
|
93
|
-
}
|
|
94
95
|
else {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<div class="glide-toggle-slider"></div>
|
|
102
|
-
<button class="glide-btn glide-toggle-btn active" data-platform="ios">${this.iconApple}<span>iOS</span></button>
|
|
103
|
-
<button class="glide-btn glide-toggle-btn" data-platform="android">${this.iconAndroid}<span>Android</span></button>
|
|
96
|
+
console.log('[Modal] Using legacy single QR code modal');
|
|
97
|
+
// Legacy single QR code
|
|
98
|
+
this.createModal(`
|
|
99
|
+
<div class="glide-auth-qr-container">
|
|
100
|
+
<img src="${this.escapeHtml(qrCodeData)}" alt="QR Code" class="glide-auth-qr-code" />
|
|
101
|
+
<p class="glide-auth-status">${this.escapeHtml(statusMessage)}</p>
|
|
104
102
|
</div>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
class="glide-qr-img"
|
|
109
|
-
id="glide-qr-img"
|
|
110
|
-
src="${this.escapeHtml(iosQR)}"
|
|
111
|
-
alt="QR Code"
|
|
112
|
-
class="glide-qr-img"
|
|
113
|
-
data-ios="${this.escapeHtml(iosQR)}"
|
|
114
|
-
data-android="${this.escapeHtml(androidQR)}"
|
|
115
|
-
/>
|
|
116
|
-
|
|
117
|
-
<!-- Animation Overlay (Inside QR Area for centering) -->
|
|
118
|
-
<div id="glide-phone-overlay" class="glide-phone-animation-overlay">
|
|
119
|
-
<div class="glide-outlined-phone">
|
|
120
|
-
<div class="glide-scan-line"></div>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
`;
|
|
126
|
-
this.createModal(content, '', true);
|
|
127
|
-
this.setupPlatformToggles();
|
|
128
|
-
this.setupHelpInteraction();
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
this.show();
|
|
129
106
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<div class="glide-scan-line"></div>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
`;
|
|
107
|
+
/**
|
|
108
|
+
* Creates a modal with iOS/Android platform toggle
|
|
109
|
+
*/
|
|
110
|
+
createDualPlatformQRModal(qrCodeData, statusMessage) {
|
|
138
111
|
this.createModal(`
|
|
139
|
-
<div class="glide-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
<div class="glide-separator-line"></div>
|
|
155
|
-
</div>
|
|
156
|
-
<div class="glide-dual-item">
|
|
157
|
-
<div class="glide-os-logo">
|
|
158
|
-
${this.iconAndroid}
|
|
159
|
-
<span>Android</span>
|
|
160
|
-
</div>
|
|
161
|
-
<div class="glide-qr-area">
|
|
162
|
-
<img src="${this.escapeHtml(data.androidQRCode || data.iosQRCode)}" alt="Android QR" class="glide-qr-img" />
|
|
163
|
-
${qrOverlayHtml}
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
112
|
+
<div class="glide-auth-qr-container">
|
|
113
|
+
<!-- Platform Switcher -->
|
|
114
|
+
<div class="glide-platform-switcher">
|
|
115
|
+
<button class="glide-platform-btn glide-platform-ios active" data-platform="ios">
|
|
116
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
|
117
|
+
<path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/>
|
|
118
|
+
</svg>
|
|
119
|
+
<span>iOS</span>
|
|
120
|
+
</button>
|
|
121
|
+
<button class="glide-platform-btn glide-platform-android" data-platform="android">
|
|
122
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
|
123
|
+
<path d="M17.6 9.48l1.84-3.18c.16-.31.04-.69-.26-.85-.29-.15-.65-.06-.83.22l-1.88 3.24c-2.86-1.21-6.08-1.21-8.94 0L5.65 5.67c-.19-.28-.54-.38-.83-.22-.3.16-.42.54-.26.85l1.84 3.18C4.08 11.08 2.4 13.97 2.4 17.2h19.2c0-3.23-1.68-6.12-4.0-7.72zM7.0 14.8c-.66 0-1.2-.54-1.2-1.2s.54-1.2 1.2-1.2 1.2.54 1.2 1.2-.54 1.2-1.2 1.2zm10 0c-.66 0-1.2-.54-1.2-1.2s.54-1.2 1.2-1.2 1.2.54 1.2 1.2-.54 1.2-1.2 1.2z"/>
|
|
124
|
+
</svg>
|
|
125
|
+
<span>Android</span>
|
|
126
|
+
</button>
|
|
166
127
|
</div>
|
|
128
|
+
|
|
129
|
+
<!-- QR Code Image -->
|
|
130
|
+
<img
|
|
131
|
+
id="glide-qr-code-img"
|
|
132
|
+
src="${this.escapeHtml(qrCodeData.iosQRCode)}"
|
|
133
|
+
alt="QR Code"
|
|
134
|
+
class="glide-auth-qr-code"
|
|
135
|
+
data-ios="${this.escapeHtml(qrCodeData.iosQRCode)}"
|
|
136
|
+
data-android="${this.escapeHtml(qrCodeData.androidQRCode || '')}"
|
|
137
|
+
/>
|
|
138
|
+
|
|
139
|
+
<!-- Status Message -->
|
|
140
|
+
<p class="glide-auth-status" id="glide-platform-message">Scan with your iPhone to authenticate</p>
|
|
167
141
|
</div>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
renderPreStepMode(data, msg) {
|
|
172
|
-
this.currentStep = 'os-choice';
|
|
173
|
-
const contentHtml = `
|
|
174
|
-
<div class="glide-pre-step-container">
|
|
175
|
-
<button class="glide-os-choice-btn" id="glide-btn-ios">
|
|
176
|
-
${this.iconApple}
|
|
177
|
-
<span>iOS</span>
|
|
178
|
-
</button>
|
|
179
|
-
<button class="glide-os-choice-btn" id="glide-btn-android">
|
|
180
|
-
${this.iconAndroid}
|
|
181
|
-
<span>Android</span>
|
|
182
|
-
</button>
|
|
183
|
-
</div>
|
|
184
|
-
`;
|
|
185
|
-
this.createModal(contentHtml, '', false);
|
|
186
|
-
this.setupPreStepListeners();
|
|
142
|
+
`);
|
|
143
|
+
// IMPORTANT: Call show() to actually display the modal!
|
|
187
144
|
this.show();
|
|
188
145
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.currentStep = 'ios-qr';
|
|
195
|
-
this.updatePreStepUI();
|
|
196
|
-
});
|
|
197
|
-
(_b = this.container.querySelector('#glide-btn-android')) === null || _b === void 0 ? void 0 : _b.addEventListener('click', () => {
|
|
198
|
-
this.currentStep = 'android-qr';
|
|
199
|
-
this.updatePreStepUI();
|
|
200
|
-
});
|
|
146
|
+
/**
|
|
147
|
+
* Sets a callback to be called when the modal is cancelled/closed
|
|
148
|
+
*/
|
|
149
|
+
setCloseCallback(callback) {
|
|
150
|
+
this.closeCallback = callback;
|
|
201
151
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Shows the modal with a button for Link authentication (App Clips)
|
|
154
|
+
* IMPORTANT: The button click is required for iOS to recognize the app link
|
|
155
|
+
*/
|
|
156
|
+
showLinkButton(url, buttonText) {
|
|
157
|
+
return new Promise((resolve) => {
|
|
158
|
+
var _a, _b, _c;
|
|
159
|
+
const text = buttonText || ((_a = this.options) === null || _a === void 0 ? void 0 : _a.buttonText) || 'Open Verification App';
|
|
160
|
+
this.createModal(`
|
|
161
|
+
<div class="glide-auth-link-container">
|
|
162
|
+
<p class="glide-auth-description">
|
|
163
|
+
${((_b = this.options) === null || _b === void 0 ? void 0 : _b.description) || 'Click below to verify your phone number'}
|
|
164
|
+
</p>
|
|
165
|
+
<button class="glide-auth-button" id="glide-auth-link-button">
|
|
166
|
+
${text}
|
|
217
167
|
</button>
|
|
168
|
+
<p class="glide-auth-helper-text">
|
|
169
|
+
You'll be redirected to complete verification
|
|
170
|
+
</p>
|
|
218
171
|
</div>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
</div>
|
|
240
|
-
`;
|
|
241
|
-
this.createModal(contentHtml, '', true, true);
|
|
242
|
-
this.setupBackButton();
|
|
243
|
-
this.setupHelpInteraction();
|
|
244
|
-
}
|
|
245
|
-
else if (this.currentStep === 'android-qr') {
|
|
246
|
-
const qr = (typeof this.qrCodeData === 'object' && ((_b = this.qrCodeData) === null || _b === void 0 ? void 0 : _b.androidQRCode))
|
|
247
|
-
? this.qrCodeData.androidQRCode
|
|
248
|
-
: (typeof this.qrCodeData === 'object' && ((_c = this.qrCodeData) === null || _c === void 0 ? void 0 : _c.iosQRCode))
|
|
249
|
-
? this.qrCodeData.iosQRCode
|
|
250
|
-
: this.qrCodeData;
|
|
251
|
-
contentHtml = `
|
|
252
|
-
<div class="glide-content">
|
|
253
|
-
<div class="glide-qr-area">
|
|
254
|
-
<img src="${this.escapeHtml(qr)}" alt="QR Code" class="glide-qr-img" />
|
|
255
|
-
|
|
256
|
-
<!-- Animation Overlay -->
|
|
257
|
-
<div id="glide-phone-overlay" class="glide-phone-animation-overlay">
|
|
258
|
-
<div class="glide-outlined-phone">
|
|
259
|
-
<div class="glide-scan-line"></div>
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
</div>
|
|
264
|
-
`;
|
|
265
|
-
this.createModal(contentHtml, '', true, true);
|
|
266
|
-
this.setupBackButton();
|
|
267
|
-
this.setupHelpInteraction();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
setupBackButton() {
|
|
271
|
-
var _a;
|
|
272
|
-
if (!this.container)
|
|
273
|
-
return;
|
|
274
|
-
(_a = this.container.querySelector('#glide-back-btn')) === null || _a === void 0 ? void 0 : _a.addEventListener('click', () => {
|
|
275
|
-
this.currentStep = 'os-choice';
|
|
276
|
-
this.updatePreStepUI();
|
|
172
|
+
`);
|
|
173
|
+
// Show modal first so elements are in the DOM
|
|
174
|
+
this.show();
|
|
175
|
+
// Add click handler for the button AFTER modal is in DOM
|
|
176
|
+
// CRITICAL: This click event is required for iOS to recognize the app link
|
|
177
|
+
// Do NOT call window.open automatically - it must be triggered by user interaction
|
|
178
|
+
const button = (_c = this.container) === null || _c === void 0 ? void 0 : _c.querySelector('#glide-auth-link-button');
|
|
179
|
+
if (button) {
|
|
180
|
+
button.addEventListener('click', (event) => {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
(_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onAuthStart) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
183
|
+
// User-initiated click is required for app links to work properly on iOS
|
|
184
|
+
// This ensures the OS recognizes it should open an app, not just a browser tab
|
|
185
|
+
window.open(url, '_blank');
|
|
186
|
+
resolve();
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.error('[Modal] Link button not found in modal');
|
|
191
|
+
}
|
|
277
192
|
});
|
|
278
193
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
this.
|
|
287
|
-
this.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Shows the modal with a button for TS43 authentication
|
|
196
|
+
* IMPORTANT: The button click is required for Digital Credentials API (transient activation)
|
|
197
|
+
*/
|
|
198
|
+
showTS43Button(onAuthenticate) {
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
var _a, _b, _c;
|
|
201
|
+
const text = ((_a = this.options) === null || _a === void 0 ? void 0 : _a.buttonText) || 'Verify with Carrier';
|
|
202
|
+
this.createModal(`
|
|
203
|
+
<div class="glide-auth-ts43-container">
|
|
204
|
+
<p class="glide-auth-description">
|
|
205
|
+
${((_b = this.options) === null || _b === void 0 ? void 0 : _b.description) || 'Verify using your carrier credentials'}
|
|
206
|
+
</p>
|
|
207
|
+
<button class="glide-auth-button" id="glide-auth-ts43-button">
|
|
208
|
+
${text}
|
|
209
|
+
</button>
|
|
210
|
+
<p class="glide-auth-helper-text">
|
|
211
|
+
Secure verification through your mobile carrier
|
|
212
|
+
</p>
|
|
213
|
+
</div>
|
|
214
|
+
`);
|
|
215
|
+
// Show modal first so elements are in the DOM
|
|
216
|
+
this.show();
|
|
217
|
+
// Add click handler for the button AFTER modal is in DOM
|
|
218
|
+
// CRITICAL: Digital Credentials API requires "transient activation" (user interaction)
|
|
219
|
+
// Do NOT call onAuthenticate automatically - it must be triggered by user click
|
|
220
|
+
const button = (_c = this.container) === null || _c === void 0 ? void 0 : _c.querySelector('#glide-auth-ts43-button');
|
|
221
|
+
if (button) {
|
|
222
|
+
button.addEventListener('click', (event) => __awaiter(this, void 0, void 0, function* () {
|
|
223
|
+
var _a, _b, _c, _d, _e, _f;
|
|
224
|
+
(_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onAuthStart) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
225
|
+
button.setAttribute('disabled', 'true');
|
|
226
|
+
button.textContent = 'Verifying...';
|
|
227
|
+
try {
|
|
228
|
+
const result = yield onAuthenticate();
|
|
229
|
+
(_d = (_c = this.callbacks) === null || _c === void 0 ? void 0 : _c.onAuthComplete) === null || _d === void 0 ? void 0 : _d.call(_c, result);
|
|
230
|
+
resolve(result);
|
|
231
|
+
this.close();
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
(_f = (_e = this.callbacks) === null || _e === void 0 ? void 0 : _e.onError) === null || _f === void 0 ? void 0 : _f.call(_e, error);
|
|
235
|
+
button.removeAttribute('disabled');
|
|
236
|
+
button.textContent = text;
|
|
237
|
+
reject(error);
|
|
238
|
+
}
|
|
239
|
+
}));
|
|
298
240
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
this.container.className = `glide-modal ${((_b = this.options) === null || _b === void 0 ? void 0 : _b.className) || ''} ${extraClass}`;
|
|
302
|
-
if (this.shouldUseDarkMode()) {
|
|
303
|
-
this.container.classList.add('dark');
|
|
241
|
+
else {
|
|
242
|
+
console.error('[Modal] TS43 button not found in modal');
|
|
304
243
|
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Updates the status message in the modal
|
|
248
|
+
*/
|
|
249
|
+
updateStatus(message, isError = false) {
|
|
250
|
+
var _a;
|
|
251
|
+
const statusEl = (_a = this.container) === null || _a === void 0 ? void 0 : _a.querySelector('.glide-auth-status');
|
|
252
|
+
if (statusEl) {
|
|
253
|
+
statusEl.textContent = message;
|
|
254
|
+
statusEl.className = isError ? 'glide-auth-status glide-auth-error' : 'glide-auth-status';
|
|
305
255
|
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Creates the modal HTML structure
|
|
259
|
+
*/
|
|
260
|
+
createModal(content) {
|
|
261
|
+
var _a, _b, _c;
|
|
262
|
+
// Clean up any existing modal
|
|
263
|
+
this.cleanup();
|
|
264
|
+
// Create backdrop (dark overlay)
|
|
265
|
+
this.backdrop = document.createElement('div');
|
|
266
|
+
this.backdrop.className = 'glide-auth-backdrop';
|
|
267
|
+
this.backdrop.style.cssText = `
|
|
268
|
+
position: fixed;
|
|
269
|
+
top: 0;
|
|
270
|
+
left: 0;
|
|
271
|
+
right: 0;
|
|
272
|
+
bottom: 0;
|
|
273
|
+
background: rgba(0, 0, 0, 0.5);
|
|
274
|
+
z-index: 9998;
|
|
275
|
+
opacity: 0;
|
|
276
|
+
transition: opacity 0.3s ease;
|
|
277
|
+
`;
|
|
278
|
+
// Create modal container
|
|
279
|
+
this.container = document.createElement('div');
|
|
280
|
+
this.container.className = `glide-auth-modal ${((_a = this.options) === null || _a === void 0 ? void 0 : _a.className) || ''}`;
|
|
281
|
+
this.container.style.cssText = `
|
|
282
|
+
position: fixed;
|
|
283
|
+
top: 50%;
|
|
284
|
+
left: 50%;
|
|
285
|
+
transform: translate(-50%, -50%) scale(0.9);
|
|
286
|
+
background: white;
|
|
287
|
+
border-radius: 12px;
|
|
288
|
+
padding: 24px;
|
|
289
|
+
max-width: 400px;
|
|
290
|
+
width: 90%;
|
|
291
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
292
|
+
z-index: 9999;
|
|
293
|
+
opacity: 0;
|
|
294
|
+
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
295
|
+
`;
|
|
296
|
+
// Add modal content
|
|
306
297
|
this.container.innerHTML = `
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
<div id="glide-modal-content">${content}</div>
|
|
322
|
-
<p class="glide-status" id="glide-status">${((_e = this.options) === null || _e === void 0 ? void 0 : _e.description) || ''}</p>
|
|
323
|
-
${includeHelpButton ? `
|
|
324
|
-
<button class="glide-btn glide-btn-help" id="glide-help-btn">?</button>
|
|
325
|
-
` : ''}
|
|
298
|
+
<div class="glide-auth-header">
|
|
299
|
+
${((_b = this.options) === null || _b === void 0 ? void 0 : _b.showCloseButton) !== false ? `
|
|
300
|
+
<button class="glide-auth-close" aria-label="Close">
|
|
301
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
302
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
303
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
304
|
+
</svg>
|
|
305
|
+
</button>
|
|
306
|
+
` : ''}
|
|
307
|
+
<h2 class="glide-auth-title">${((_c = this.options) === null || _c === void 0 ? void 0 : _c.title) || 'Phone Verification'}</h2>
|
|
308
|
+
</div>
|
|
309
|
+
<div class="glide-auth-content">
|
|
310
|
+
${content}
|
|
311
|
+
</div>
|
|
326
312
|
`;
|
|
313
|
+
// Add styles
|
|
327
314
|
this.injectStyles();
|
|
328
|
-
|
|
315
|
+
// Add close button handler
|
|
316
|
+
const closeBtn = this.container.querySelector('.glide-auth-close');
|
|
329
317
|
if (closeBtn) {
|
|
330
318
|
closeBtn.addEventListener('click', () => {
|
|
331
319
|
var _a;
|
|
332
|
-
(_a = this.closeCallback) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
320
|
+
(_a = this.closeCallback) === null || _a === void 0 ? void 0 : _a.call(this); // Call cancellation callback if set
|
|
333
321
|
this.close();
|
|
334
322
|
});
|
|
335
323
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
setupHelpInteraction() {
|
|
347
|
-
var _a;
|
|
348
|
-
const trigger = (_a = this.container) === null || _a === void 0 ? void 0 : _a.querySelector('#glide-help-btn');
|
|
349
|
-
if (trigger) {
|
|
350
|
-
trigger.addEventListener('click', () => {
|
|
351
|
-
var _a;
|
|
352
|
-
const overlays = (_a = this.container) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.glide-phone-animation-overlay');
|
|
353
|
-
if (overlays) {
|
|
354
|
-
overlays.forEach(overlay => {
|
|
355
|
-
overlay.classList.remove('playing');
|
|
356
|
-
void overlay.offsetWidth;
|
|
357
|
-
overlay.classList.add('playing');
|
|
358
|
-
setTimeout(() => {
|
|
359
|
-
overlay.classList.remove('playing');
|
|
360
|
-
}, 3000);
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
}
|
|
324
|
+
// Add backdrop click handler
|
|
325
|
+
this.backdrop.addEventListener('click', (e) => {
|
|
326
|
+
var _a, _b;
|
|
327
|
+
// Only close if backdrop itself was clicked and closeOnBackdrop is enabled (default true)
|
|
328
|
+
if (e.target === this.backdrop && ((_a = this.options) === null || _a === void 0 ? void 0 : _a.closeOnBackdrop) !== false) {
|
|
329
|
+
(_b = this.closeCallback) === null || _b === void 0 ? void 0 : _b.call(this); // Call cancellation callback if set
|
|
330
|
+
this.close();
|
|
331
|
+
}
|
|
332
|
+
});
|
|
365
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Injects CSS styles for the modal
|
|
336
|
+
*/
|
|
366
337
|
injectStyles() {
|
|
367
|
-
if (document.getElementById('glide-
|
|
338
|
+
if (document.getElementById('glide-auth-styles'))
|
|
368
339
|
return;
|
|
369
340
|
const styles = document.createElement('style');
|
|
370
|
-
styles.id = 'glide-
|
|
341
|
+
styles.id = 'glide-auth-styles';
|
|
371
342
|
styles.textContent = `
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
--glide-text: #1d1d1f;
|
|
375
|
-
--glide-bg-light: rgba(255, 255, 255, 0.6);
|
|
376
|
-
--glide-bg-dark: rgba(30, 30, 30, 0.6);
|
|
377
|
-
--glide-phone-border: #000000; /* High Contrast Black */
|
|
378
|
-
|
|
379
|
-
/* Button sizes */
|
|
380
|
-
--glide-btn-size: 28px;
|
|
381
|
-
--glide-help-btn-size: 24px;
|
|
382
|
-
--glide-toggle-icon-size: 14px;
|
|
383
|
-
--glide-dual-icon-size: 18px;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
#glide-backdrop {
|
|
387
|
-
position: fixed;
|
|
388
|
-
top: 0;
|
|
389
|
-
left: 0;
|
|
390
|
-
right: 0;
|
|
391
|
-
bottom: 0;
|
|
392
|
-
background: rgba(0, 0, 0, 0.2);
|
|
393
|
-
backdrop-filter: blur(8px);
|
|
394
|
-
-webkit-backdrop-filter: blur(8px);
|
|
395
|
-
z-index: 9998;
|
|
396
|
-
opacity: 0;
|
|
397
|
-
transition: opacity 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
|
343
|
+
.glide-auth-backdrop {
|
|
344
|
+
backdrop-filter: blur(4px);
|
|
398
345
|
}
|
|
399
346
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
top: 20px;
|
|
403
|
-
left: 50%;
|
|
404
|
-
transform: translateX(-50%) scale(0.94);
|
|
405
|
-
background: var(--glide-bg-light);
|
|
406
|
-
backdrop-filter: blur(24px) saturate(180%);
|
|
407
|
-
-webkit-backdrop-filter: blur(24px) saturate(180%);
|
|
408
|
-
border-radius: 24px;
|
|
409
|
-
padding: 32px;
|
|
410
|
-
width: 360px;
|
|
411
|
-
max-width: 90%;
|
|
412
|
-
box-shadow:
|
|
413
|
-
0 20px 40px rgba(0,0,0,0.2),
|
|
414
|
-
0 0 0 1px rgba(255,255,255,0.6) inset,
|
|
415
|
-
0 0 0 1px rgba(0,0,0,0.05);
|
|
416
|
-
z-index: 9999;
|
|
417
|
-
opacity: 0;
|
|
418
|
-
transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
|
419
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
420
|
-
text-align: center;
|
|
421
|
-
color: var(--glide-text);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
#glide-modal.glide-modal-wide {
|
|
425
|
-
width: 600px;
|
|
426
|
-
max-width: 95vw;
|
|
347
|
+
.glide-auth-modal {
|
|
348
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
427
349
|
}
|
|
428
350
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
box-shadow:
|
|
433
|
-
0 20px 40px rgba(0,0,0,0.4),
|
|
434
|
-
0 0 0 1px rgba(255,255,255,0.15) inset,
|
|
435
|
-
0 0 0 1px rgba(0,0,0,0.5);
|
|
436
|
-
--glide-phone-border: #ffffff; /* High Contrast White */
|
|
351
|
+
.glide-auth-header {
|
|
352
|
+
position: relative;
|
|
353
|
+
margin-bottom: 20px;
|
|
437
354
|
}
|
|
438
355
|
|
|
439
|
-
|
|
356
|
+
.glide-auth-close {
|
|
440
357
|
position: absolute;
|
|
441
|
-
top:
|
|
442
|
-
right:
|
|
443
|
-
|
|
444
|
-
height: var(--glide-btn-size);
|
|
445
|
-
min-width: var(--glide-btn-size);
|
|
446
|
-
min-height: var(--glide-btn-size);
|
|
447
|
-
max-width: var(--glide-btn-size);
|
|
448
|
-
max-height: var(--glide-btn-size);
|
|
449
|
-
background: rgba(118, 118, 128, 0.12);
|
|
358
|
+
top: 0;
|
|
359
|
+
right: 0;
|
|
360
|
+
background: none;
|
|
450
361
|
border: none;
|
|
451
|
-
border-radius: 50%;
|
|
452
|
-
display: flex;
|
|
453
|
-
align-items: center;
|
|
454
|
-
justify-content: center;
|
|
455
362
|
cursor: pointer;
|
|
456
|
-
color: rgba(0,0,0,0.5);
|
|
457
|
-
transition: background 0.2s;
|
|
458
363
|
padding: 0;
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
flex-shrink: 0;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
#glide-modal.dark .glide-btn-close {
|
|
465
|
-
background: rgba(255, 255, 255, 0.1);
|
|
466
|
-
color: rgba(255,255,255,0.5);
|
|
364
|
+
color: #666;
|
|
365
|
+
transition: color 0.2s;
|
|
467
366
|
}
|
|
468
367
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
#glide-modal.dark .glide-btn-close:hover {
|
|
474
|
-
background: rgba(255, 255, 255, 0.2);
|
|
368
|
+
.glide-auth-close:hover {
|
|
369
|
+
color: #000;
|
|
475
370
|
}
|
|
476
371
|
|
|
477
|
-
.glide-title {
|
|
478
|
-
margin: 0
|
|
479
|
-
font-size:
|
|
372
|
+
.glide-auth-title {
|
|
373
|
+
margin: 0;
|
|
374
|
+
font-size: 24px;
|
|
480
375
|
font-weight: 600;
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
.glide-status {
|
|
485
|
-
margin: 12px 0 0 0;
|
|
486
|
-
font-size: 13px;
|
|
487
|
-
color: rgba(0,0,0,0.5);
|
|
376
|
+
color: #333;
|
|
488
377
|
text-align: center;
|
|
489
|
-
min-height: 18px;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
.glide-status:empty {
|
|
493
|
-
display: none;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
#glide-modal.dark .glide-status {
|
|
497
|
-
color: rgba(255,255,255,0.5);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
.glide-content {
|
|
501
|
-
display: flex;
|
|
502
|
-
flex-direction: column;
|
|
503
|
-
align-items: center;
|
|
504
|
-
position: relative;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/* --- Sliding Toggle Switch --- */
|
|
508
|
-
#glide-toggle {
|
|
509
|
-
background: rgba(118, 118, 128, 0.12);
|
|
510
|
-
padding: 2px;
|
|
511
|
-
border-radius: 8px;
|
|
512
|
-
display: inline-flex;
|
|
513
|
-
margin-bottom: 24px;
|
|
514
|
-
margin-top: 16px;
|
|
515
|
-
position: relative;
|
|
516
|
-
height: 32px;
|
|
517
|
-
width: 200px;
|
|
518
|
-
box-sizing: border-box;
|
|
519
378
|
}
|
|
520
379
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/* The sliding background */
|
|
526
|
-
.glide-toggle-slider {
|
|
527
|
-
position: absolute;
|
|
528
|
-
top: 2px;
|
|
529
|
-
left: 2px;
|
|
530
|
-
width: calc(50% - 2px);
|
|
531
|
-
height: calc(100% - 4px);
|
|
532
|
-
background: white;
|
|
533
|
-
border-radius: 6px;
|
|
534
|
-
box-shadow: 0 3px 8px rgba(0,0,0,0.12), 0 3px 1px rgba(0,0,0,0.04);
|
|
535
|
-
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
536
|
-
z-index: 0;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
#glide-modal.dark .glide-toggle-slider {
|
|
540
|
-
background: #636366;
|
|
380
|
+
.glide-auth-content {
|
|
381
|
+
text-align: center;
|
|
541
382
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
383
|
+
|
|
384
|
+
.glide-auth-description {
|
|
385
|
+
color: #666;
|
|
386
|
+
margin: 0 0 20px 0;
|
|
387
|
+
font-size: 16px;
|
|
388
|
+
line-height: 1.5;
|
|
546
389
|
}
|
|
547
390
|
|
|
548
|
-
.glide-
|
|
549
|
-
|
|
550
|
-
|
|
391
|
+
.glide-auth-button {
|
|
392
|
+
background: #007AFF;
|
|
393
|
+
color: white;
|
|
551
394
|
border: none;
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
font-size:
|
|
395
|
+
border-radius: 8px;
|
|
396
|
+
padding: 12px 24px;
|
|
397
|
+
font-size: 16px;
|
|
555
398
|
font-weight: 500;
|
|
556
|
-
color: inherit;
|
|
557
399
|
cursor: pointer;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
transition: color 0.2s;
|
|
561
|
-
display: flex;
|
|
562
|
-
align-items: center;
|
|
563
|
-
justify-content: center;
|
|
564
|
-
gap: 6px;
|
|
565
|
-
min-height: auto;
|
|
566
|
-
height: auto;
|
|
567
|
-
min-width: auto;
|
|
568
|
-
border-radius: 0;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
#glide-modal .glide-toggle-btn .glide-icon-os,
|
|
572
|
-
#glide-modal .glide-toggle-btn svg {
|
|
573
|
-
width: var(--glide-toggle-icon-size);
|
|
574
|
-
height: var(--glide-toggle-icon-size);
|
|
575
|
-
flex-shrink: 0;
|
|
576
|
-
margin: 0;
|
|
577
|
-
padding: 0;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
.glide-toggle-btn span {
|
|
581
|
-
margin: 0;
|
|
582
|
-
padding: 0;
|
|
583
|
-
line-height: 1;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
#glide-modal.dark .glide-toggle-btn {
|
|
587
|
-
color: rgba(255,255,255,0.6);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
#glide-toggle[data-active="ios"] .glide-toggle-btn[data-platform="ios"],
|
|
591
|
-
#glide-toggle[data-active="android"] .glide-toggle-btn[data-platform="android"] {
|
|
592
|
-
color: #1d1d1f;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
#glide-modal.dark #glide-toggle[data-active="ios"] .glide-toggle-btn[data-platform="ios"],
|
|
596
|
-
#glide-modal.dark #glide-toggle[data-active="android"] .glide-toggle-btn[data-platform="android"] {
|
|
597
|
-
color: white;
|
|
400
|
+
transition: background 0.2s, transform 0.1s;
|
|
401
|
+
min-width: 200px;
|
|
598
402
|
}
|
|
599
403
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
margin: 0 auto;
|
|
404
|
+
.glide-auth-button:hover:not(:disabled) {
|
|
405
|
+
background: #0051D5;
|
|
406
|
+
transform: translateY(-1px);
|
|
604
407
|
}
|
|
605
408
|
|
|
606
|
-
.glide-
|
|
607
|
-
|
|
608
|
-
height: 200px;
|
|
609
|
-
object-fit: contain;
|
|
610
|
-
display: block;
|
|
611
|
-
border-radius: 16px;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
/* Dual Mode QR Area - no extra padding, same as single mode */
|
|
615
|
-
.glide-dual-mode .glide-qr-area {
|
|
616
|
-
background: transparent;
|
|
617
|
-
padding: 0;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
.glide-dual-mode .glide-qr-img {
|
|
621
|
-
width: 180px;
|
|
622
|
-
height: 180px;
|
|
623
|
-
border-radius: 16px;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
/* --- Help Icon & Interaction --- */
|
|
627
|
-
.glide-btn-help {
|
|
628
|
-
position: absolute;
|
|
629
|
-
bottom: 20px;
|
|
630
|
-
right: 20px;
|
|
631
|
-
width: var(--glide-help-btn-size);
|
|
632
|
-
height: var(--glide-help-btn-size);
|
|
633
|
-
min-width: var(--glide-help-btn-size);
|
|
634
|
-
min-height: var(--glide-help-btn-size);
|
|
635
|
-
max-width: var(--glide-help-btn-size);
|
|
636
|
-
max-height: var(--glide-help-btn-size);
|
|
637
|
-
border-radius: 50%;
|
|
638
|
-
border: 1.5px solid rgba(0,0,0,0.2);
|
|
639
|
-
color: rgba(0,0,0,0.4);
|
|
640
|
-
display: flex;
|
|
641
|
-
align-items: center;
|
|
642
|
-
justify-content: center;
|
|
643
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
644
|
-
font-size: 14px;
|
|
645
|
-
font-weight: 600;
|
|
646
|
-
line-height: 1;
|
|
647
|
-
cursor: pointer;
|
|
648
|
-
transition: all 0.2s;
|
|
649
|
-
background: transparent;
|
|
650
|
-
padding: 0;
|
|
651
|
-
margin: 0;
|
|
652
|
-
box-sizing: border-box;
|
|
653
|
-
z-index: 10;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
#glide-modal.dark .glide-btn-help {
|
|
657
|
-
border-color: rgba(255,255,255,0.3);
|
|
658
|
-
color: rgba(255,255,255,0.5);
|
|
409
|
+
.glide-auth-button:active {
|
|
410
|
+
transform: translateY(0);
|
|
659
411
|
}
|
|
660
412
|
|
|
661
|
-
.glide-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
background: rgba(0, 122, 255, 0.1);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/* Tooltip */
|
|
668
|
-
.glide-btn-help::after {
|
|
669
|
-
content: "Need help?";
|
|
670
|
-
position: absolute;
|
|
671
|
-
bottom: 100%;
|
|
672
|
-
left: 50%;
|
|
673
|
-
transform: translateX(-50%) translateY(-8px);
|
|
674
|
-
background: rgba(0,0,0,0.8);
|
|
675
|
-
color: white;
|
|
676
|
-
padding: 4px 8px;
|
|
677
|
-
border-radius: 4px;
|
|
678
|
-
font-size: 11px;
|
|
679
|
-
white-space: nowrap;
|
|
680
|
-
opacity: 0;
|
|
681
|
-
pointer-events: none;
|
|
682
|
-
transition: opacity 0.2s;
|
|
413
|
+
.glide-auth-button:disabled {
|
|
414
|
+
opacity: 0.6;
|
|
415
|
+
cursor: not-allowed;
|
|
683
416
|
}
|
|
684
|
-
|
|
685
|
-
.glide-
|
|
686
|
-
|
|
417
|
+
|
|
418
|
+
.glide-auth-helper-text {
|
|
419
|
+
color: #999;
|
|
420
|
+
font-size: 14px;
|
|
421
|
+
margin: 16px 0 0 0;
|
|
687
422
|
}
|
|
688
423
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
position: absolute;
|
|
692
|
-
top: 0;
|
|
693
|
-
left: 0;
|
|
424
|
+
.glide-auth-qr-code {
|
|
425
|
+
max-width: 256px;
|
|
694
426
|
width: 100%;
|
|
695
|
-
height:
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
justify-content: center;
|
|
699
|
-
pointer-events: none;
|
|
700
|
-
opacity: 0;
|
|
701
|
-
transition: opacity 0.3s;
|
|
702
|
-
border-radius: 16px;
|
|
703
|
-
background: rgba(255,255,255,0.8);
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
#glide-modal.dark .glide-phone-animation-overlay {
|
|
707
|
-
background: rgba(0,0,0,0.6);
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
.glide-phone-animation-overlay.playing {
|
|
711
|
-
opacity: 1;
|
|
427
|
+
height: auto;
|
|
428
|
+
margin: 20px auto;
|
|
429
|
+
display: block;
|
|
712
430
|
}
|
|
713
431
|
|
|
714
|
-
.glide-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
border-radius: 16px;
|
|
719
|
-
position: relative;
|
|
720
|
-
background: transparent;
|
|
721
|
-
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
|
722
|
-
transform: translateY(20px);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/* Notch */
|
|
726
|
-
.glide-outlined-phone::before {
|
|
727
|
-
content: '';
|
|
728
|
-
position: absolute;
|
|
729
|
-
top: -1px;
|
|
730
|
-
left: 50%;
|
|
731
|
-
transform: translateX(-50%);
|
|
732
|
-
width: 40%;
|
|
733
|
-
height: 12px;
|
|
734
|
-
background: var(--glide-phone-border);
|
|
735
|
-
border-bottom-left-radius: 8px;
|
|
736
|
-
border-bottom-right-radius: 8px;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
/* Scanning Line */
|
|
740
|
-
.glide-scan-line {
|
|
741
|
-
position: absolute;
|
|
742
|
-
top: 10%;
|
|
743
|
-
left: 5%;
|
|
744
|
-
width: 90%;
|
|
745
|
-
height: 2px;
|
|
746
|
-
background: var(--glide-primary);
|
|
747
|
-
box-shadow: 0 0 8px var(--glide-primary);
|
|
748
|
-
opacity: 0;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
/* Animation Keyframes */
|
|
752
|
-
@keyframes glide-scan-motion {
|
|
753
|
-
0% { top: 10%; opacity: 0; }
|
|
754
|
-
10% { opacity: 1; }
|
|
755
|
-
90% { opacity: 1; }
|
|
756
|
-
100% { top: 90%; opacity: 0; }
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
.glide-phone-animation-overlay.playing .glide-outlined-phone {
|
|
760
|
-
animation: glide-phone-appear 3s ease-in-out forwards;
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
.glide-phone-animation-overlay.playing .glide-scan-line {
|
|
764
|
-
animation: glide-scan-motion 2s ease-in-out 0.5s infinite;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
@keyframes glide-phone-appear {
|
|
768
|
-
0% { transform: translateY(20px); opacity: 0; }
|
|
769
|
-
10% { transform: translateY(0); opacity: 1; }
|
|
770
|
-
90% { transform: translateY(0); opacity: 1; }
|
|
771
|
-
100% { transform: translateY(20px); opacity: 0; }
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
/* Dual Mode */
|
|
775
|
-
.glide-dual-container {
|
|
776
|
-
display: flex;
|
|
777
|
-
justify-content: center;
|
|
778
|
-
align-items: stretch;
|
|
779
|
-
gap: 32px;
|
|
780
|
-
margin-top: 20px;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
.glide-dual-item {
|
|
784
|
-
display: flex;
|
|
785
|
-
flex-direction: column;
|
|
786
|
-
align-items: center;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
.glide-os-logo {
|
|
790
|
-
display: flex;
|
|
791
|
-
align-items: center;
|
|
792
|
-
gap: 8px;
|
|
793
|
-
font-weight: 600;
|
|
794
|
-
margin-bottom: 12px;
|
|
795
|
-
font-size: 15px;
|
|
796
|
-
color: inherit;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
/* Dual mode OS logo - aligned icons with text, spacing to QR */
|
|
800
|
-
.glide-dual-mode .glide-os-logo {
|
|
801
|
-
margin-bottom: 12px; /* Space between label and QR code */
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
#glide-modal .glide-dual-mode .glide-os-logo .glide-icon-os,
|
|
805
|
-
#glide-modal .glide-dual-mode .glide-os-logo svg {
|
|
806
|
-
width: var(--glide-dual-icon-size);
|
|
807
|
-
height: var(--glide-dual-icon-size);
|
|
808
|
-
margin: 0;
|
|
809
|
-
padding: 0;
|
|
810
|
-
flex-shrink: 0;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
.glide-dual-mode .glide-os-logo span {
|
|
814
|
-
margin: 0;
|
|
815
|
-
padding: 0;
|
|
816
|
-
line-height: 1;
|
|
432
|
+
.glide-auth-status {
|
|
433
|
+
color: #666;
|
|
434
|
+
font-size: 16px;
|
|
435
|
+
margin: 16px 0;
|
|
817
436
|
}
|
|
818
|
-
|
|
819
|
-
.glide-
|
|
820
|
-
|
|
821
|
-
height: 20px;
|
|
822
|
-
opacity: 0.8;
|
|
437
|
+
|
|
438
|
+
.glide-auth-error {
|
|
439
|
+
color: #FF3B30;
|
|
823
440
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
.glide-
|
|
827
|
-
|
|
828
|
-
flex-direction: column;
|
|
829
|
-
align-items: center;
|
|
830
|
-
justify-content: center;
|
|
831
|
-
align-self: stretch;
|
|
832
|
-
/* Offset for OS label (18px icon + 12px margin = ~30px) */
|
|
833
|
-
margin-top: 30px;
|
|
441
|
+
|
|
442
|
+
.glide-auth-qr-container,
|
|
443
|
+
.glide-auth-link-container,
|
|
444
|
+
.glide-auth-ts43-container {
|
|
834
445
|
padding: 20px 0;
|
|
835
446
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
flex: 1;
|
|
840
|
-
background: linear-gradient(to bottom, transparent, rgba(128,128,128,0.3), transparent);
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
.glide-separator-text {
|
|
844
|
-
padding: 8px 0;
|
|
845
|
-
font-size: 11px;
|
|
846
|
-
font-weight: 500;
|
|
847
|
-
color: rgba(128,128,128,0.5);
|
|
848
|
-
text-transform: uppercase;
|
|
849
|
-
letter-spacing: 0.5px;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
#glide-modal.dark .glide-separator-line {
|
|
853
|
-
background: linear-gradient(to bottom, transparent, rgba(255,255,255,0.2), transparent);
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
#glide-modal.dark .glide-separator-text {
|
|
857
|
-
color: rgba(255,255,255,0.4);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
/* Pre-Step */
|
|
861
|
-
.glide-pre-step-container {
|
|
447
|
+
|
|
448
|
+
/* Platform Switcher Styles */
|
|
449
|
+
.glide-platform-switcher {
|
|
862
450
|
display: flex;
|
|
863
|
-
gap: 20px;
|
|
864
451
|
justify-content: center;
|
|
865
|
-
|
|
452
|
+
gap: 10px;
|
|
453
|
+
margin-bottom: 20px;
|
|
866
454
|
}
|
|
867
|
-
|
|
868
|
-
.glide-
|
|
455
|
+
|
|
456
|
+
.glide-platform-btn {
|
|
869
457
|
display: flex;
|
|
870
|
-
flex-direction: column;
|
|
871
458
|
align-items: center;
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
border-radius:
|
|
877
|
-
background: rgba(255,255,255,0.4);
|
|
459
|
+
gap: 6px;
|
|
460
|
+
padding: 10px 20px;
|
|
461
|
+
border: 2px solid;
|
|
462
|
+
background: transparent;
|
|
463
|
+
border-radius: 8px;
|
|
878
464
|
cursor: pointer;
|
|
879
|
-
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
880
|
-
position: relative;
|
|
881
|
-
overflow: hidden;
|
|
882
465
|
font-size: 14px;
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
#glide-modal.dark .glide-os-choice-btn {
|
|
887
|
-
background: rgba(255,255,255,0.05);
|
|
888
|
-
border-color: rgba(255,255,255,0.1);
|
|
889
|
-
color: white;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
.glide-os-choice-btn:hover {
|
|
893
|
-
background: rgba(255,255,255,0.9);
|
|
894
|
-
transform: translateY(-4px);
|
|
895
|
-
box-shadow: 0 12px 24px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.04);
|
|
896
|
-
border-color: var(--glide-primary);
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
#glide-modal.dark .glide-os-choice-btn:hover {
|
|
900
|
-
background: rgba(255,255,255,0.15);
|
|
901
|
-
box-shadow: 0 12px 24px rgba(0,0,0,0.3);
|
|
902
|
-
border-color: var(--glide-primary);
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
.glide-icon-os {
|
|
906
|
-
width: 40px;
|
|
907
|
-
height: 40px;
|
|
908
|
-
margin-bottom: 12px;
|
|
909
|
-
transition: transform 0.3s;
|
|
910
|
-
fill: currentColor;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
.glide-os-choice-btn:hover .glide-icon-os {
|
|
914
|
-
transform: scale(1.1);
|
|
466
|
+
font-weight: 600;
|
|
467
|
+
transition: all 0.2s ease;
|
|
915
468
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
position: absolute;
|
|
919
|
-
top: 16px;
|
|
920
|
-
left: 16px;
|
|
921
|
-
width: var(--glide-btn-size);
|
|
922
|
-
height: var(--glide-btn-size);
|
|
923
|
-
min-width: var(--glide-btn-size);
|
|
924
|
-
min-height: var(--glide-btn-size);
|
|
925
|
-
max-width: var(--glide-btn-size);
|
|
926
|
-
max-height: var(--glide-btn-size);
|
|
927
|
-
background: rgba(118, 118, 128, 0.12);
|
|
928
|
-
border: none;
|
|
929
|
-
border-radius: 50%;
|
|
930
|
-
display: flex;
|
|
931
|
-
align-items: center;
|
|
932
|
-
justify-content: center;
|
|
933
|
-
cursor: pointer;
|
|
934
|
-
color: rgba(0,0,0,0.5);
|
|
935
|
-
transition: background 0.2s;
|
|
936
|
-
z-index: 20;
|
|
937
|
-
padding: 0;
|
|
938
|
-
margin: 0;
|
|
939
|
-
box-sizing: border-box;
|
|
469
|
+
|
|
470
|
+
.glide-platform-btn svg {
|
|
940
471
|
flex-shrink: 0;
|
|
941
472
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
color:
|
|
473
|
+
|
|
474
|
+
.glide-platform-ios {
|
|
475
|
+
border-color: #007AFF;
|
|
476
|
+
color: #007AFF;
|
|
946
477
|
}
|
|
947
478
|
|
|
948
|
-
.glide-
|
|
949
|
-
background:
|
|
479
|
+
.glide-platform-ios.active {
|
|
480
|
+
background: #007AFF;
|
|
481
|
+
color: white;
|
|
950
482
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
background: rgba(
|
|
483
|
+
|
|
484
|
+
.glide-platform-ios:hover:not(.active) {
|
|
485
|
+
background: rgba(0, 122, 255, 0.1);
|
|
954
486
|
}
|
|
955
|
-
|
|
956
|
-
.glide-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
border: 3px solid rgba(0,0,0,0.1);
|
|
960
|
-
border-top-color: var(--glide-primary);
|
|
961
|
-
border-radius: 50%;
|
|
962
|
-
animation: glide-spin 1s linear infinite;
|
|
963
|
-
margin: 40px auto;
|
|
487
|
+
|
|
488
|
+
.glide-platform-android {
|
|
489
|
+
border-color: #3DDC84;
|
|
490
|
+
color: #3DDC84;
|
|
964
491
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
492
|
+
|
|
493
|
+
.glide-platform-android.active {
|
|
494
|
+
background: #3DDC84;
|
|
495
|
+
color: white;
|
|
969
496
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
497
|
+
|
|
498
|
+
.glide-platform-android:hover:not(.active) {
|
|
499
|
+
background: rgba(61, 220, 132, 0.1);
|
|
973
500
|
}
|
|
974
501
|
`;
|
|
975
502
|
document.head.appendChild(styles);
|
|
976
503
|
}
|
|
504
|
+
/**
|
|
505
|
+
* Shows the modal with animation
|
|
506
|
+
*/
|
|
977
507
|
show() {
|
|
978
508
|
var _a, _b;
|
|
979
|
-
if (!this.container || !this.backdrop || this.isOpen)
|
|
980
|
-
if (this.isOpen && this.container && this.backdrop) {
|
|
981
|
-
document.removeEventListener('keydown', this.handleEscapeKey);
|
|
982
|
-
document.addEventListener('keydown', this.handleEscapeKey);
|
|
983
|
-
}
|
|
509
|
+
if (!this.container || !this.backdrop || this.isOpen)
|
|
984
510
|
return;
|
|
985
|
-
}
|
|
986
511
|
document.body.appendChild(this.backdrop);
|
|
987
512
|
document.body.appendChild(this.container);
|
|
988
|
-
|
|
513
|
+
// Add escape key listener for closing modal
|
|
989
514
|
document.addEventListener('keydown', this.handleEscapeKey);
|
|
515
|
+
// Setup platform toggle handlers if they exist
|
|
516
|
+
this.setupPlatformToggles();
|
|
517
|
+
// Trigger animation
|
|
990
518
|
requestAnimationFrame(() => {
|
|
991
519
|
if (this.backdrop && this.container) {
|
|
992
520
|
this.backdrop.style.opacity = '1';
|
|
993
521
|
this.container.style.opacity = '1';
|
|
994
|
-
this.container.style.transform = '
|
|
522
|
+
this.container.style.transform = 'translate(-50%, -50%) scale(1)';
|
|
995
523
|
}
|
|
996
524
|
});
|
|
997
525
|
this.isOpen = true;
|
|
998
526
|
(_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onOpen) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
999
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Setup click handlers for iOS/Android platform toggle
|
|
530
|
+
*/
|
|
1000
531
|
setupPlatformToggles() {
|
|
1001
|
-
var _a, _b, _c
|
|
1002
|
-
const
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
const message = (_d = this.container) === null || _d === void 0 ? void 0 : _d.querySelector('#glide-platform-message');
|
|
532
|
+
var _a, _b, _c;
|
|
533
|
+
const platformBtns = (_a = this.container) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.glide-platform-btn');
|
|
534
|
+
const qrImg = (_b = this.container) === null || _b === void 0 ? void 0 : _b.querySelector('#glide-qr-code-img');
|
|
535
|
+
const message = (_c = this.container) === null || _c === void 0 ? void 0 : _c.querySelector('#glide-platform-message');
|
|
1006
536
|
if (!platformBtns || !qrImg)
|
|
1007
537
|
return;
|
|
1008
538
|
platformBtns.forEach((btn) => {
|
|
1009
539
|
btn.addEventListener('click', (e) => {
|
|
1010
540
|
const target = e.currentTarget;
|
|
1011
541
|
const platform = target.getAttribute('data-platform');
|
|
1012
|
-
|
|
1013
|
-
container.setAttribute('data-active', platform);
|
|
1014
|
-
}
|
|
542
|
+
// Update active state
|
|
1015
543
|
platformBtns.forEach(b => b.classList.remove('active'));
|
|
1016
544
|
target.classList.add('active');
|
|
545
|
+
// Switch QR code
|
|
1017
546
|
if (platform === 'ios') {
|
|
1018
547
|
qrImg.src = qrImg.getAttribute('data-ios') || '';
|
|
1019
548
|
if (message)
|
|
1020
|
-
message.textContent = 'Scan with your iPhone
|
|
549
|
+
message.textContent = 'Scan with your iPhone to authenticate';
|
|
1021
550
|
}
|
|
1022
551
|
else if (platform === 'android') {
|
|
1023
552
|
qrImg.src = qrImg.getAttribute('data-android') || '';
|
|
1024
553
|
if (message)
|
|
1025
|
-
message.textContent = 'Scan with your Android
|
|
554
|
+
message.textContent = 'Scan with your Android device to authenticate';
|
|
1026
555
|
}
|
|
1027
556
|
});
|
|
1028
557
|
});
|
|
1029
558
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
}
|
|
1034
|
-
unlockBodyScroll() {
|
|
1035
|
-
document.body.style.overflow = this.originalBodyOverflow;
|
|
1036
|
-
}
|
|
559
|
+
/**
|
|
560
|
+
* Closes the modal with animation
|
|
561
|
+
*/
|
|
1037
562
|
close() {
|
|
1038
563
|
if (!this.container || !this.backdrop || !this.isOpen)
|
|
1039
564
|
return;
|
|
1040
|
-
|
|
565
|
+
// Remove escape key listener
|
|
1041
566
|
document.removeEventListener('keydown', this.handleEscapeKey);
|
|
567
|
+
// Animate out
|
|
1042
568
|
this.backdrop.style.opacity = '0';
|
|
1043
569
|
this.container.style.opacity = '0';
|
|
1044
|
-
this.container.style.transform = '
|
|
570
|
+
this.container.style.transform = 'translate(-50%, -50%) scale(0.9)';
|
|
571
|
+
// Clear any stored callbacks
|
|
1045
572
|
this.closeCallback = undefined;
|
|
573
|
+
// Remove after animation
|
|
1046
574
|
setTimeout(() => {
|
|
1047
575
|
var _a, _b;
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
(_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1053
|
-
}
|
|
1054
|
-
}, 400);
|
|
576
|
+
this.cleanup();
|
|
577
|
+
this.isOpen = false;
|
|
578
|
+
(_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
579
|
+
}, 300);
|
|
1055
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Removes modal elements from DOM
|
|
583
|
+
*/
|
|
1056
584
|
cleanup() {
|
|
1057
585
|
var _a, _b;
|
|
1058
586
|
(_a = this.container) === null || _a === void 0 ? void 0 : _a.remove();
|
|
1059
587
|
(_b = this.backdrop) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1060
588
|
this.container = null;
|
|
1061
589
|
this.backdrop = null;
|
|
1062
|
-
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Check if modal is currently open
|
|
593
|
+
*/
|
|
594
|
+
isModalOpen() {
|
|
595
|
+
return this.isOpen;
|
|
1063
596
|
}
|
|
1064
597
|
}
|
|
1065
598
|
exports.AuthModal = AuthModal;
|