diff --git a/miniapp/index.html b/miniapp/index.html index c2ca47c9..4d314365 100644 --- a/miniapp/index.html +++ b/miniapp/index.html @@ -87,7 +87,7 @@ max-width: 480px; margin: 0 auto; padding: 16px; - padding-bottom: 32px; + padding-bottom: 120px; } /* Animations */ @@ -2401,7 +2401,7 @@ align-items: center; justify-content: center; padding: 24px; - z-index: 1000; + z-index: 950; backdrop-filter: blur(4px); } @@ -3991,6 +3991,170 @@ display: none !important; } + /* Floating connect button */ + .floating-connect-button { + position: fixed; + right: 16px; + bottom: 24px; + border: none; + border-radius: 999px; + background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.95), rgba(59, 130, 246, 0.95)); + color: var(--tg-theme-button-text-color); + box-shadow: 0 12px 32px rgba(var(--primary-rgb), 0.35); + padding: 0; + cursor: pointer; + transition: transform 0.2s ease, box-shadow 0.3s ease, opacity 0.2s ease; + width: min(320px, 50vw); + min-width: 200px; + z-index: 950; + } + + .floating-connect-button:disabled { + cursor: not-allowed; + opacity: 0.6; + box-shadow: none; + } + + .floating-connect-button:not(:disabled):hover { + transform: translateY(-2px); + box-shadow: 0 16px 40px rgba(var(--primary-rgb), 0.45); + } + + .floating-connect-button__content { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + padding: 16px 24px; + font-weight: 700; + font-size: 15px; + } + + .floating-connect-button__icon { + width: 22px; + height: 22px; + } + + .floating-connect-button__label { + white-space: nowrap; + } + + @media (max-width: 480px) { + .floating-connect-button { + left: 16px; + width: calc(100vw - 32px); + min-width: 0; + } + } + + /* Installation modal */ + .guide-modal-backdrop { + position: fixed; + inset: 0; + background: rgba(15, 23, 42, 0.4); + display: flex; + align-items: flex-end; + justify-content: center; + padding: 24px 16px; + z-index: 2000; + backdrop-filter: blur(6px); + } + + .guide-modal { + background: var(--bg-primary); + border-radius: 24px 24px 16px 16px; + width: min(480px, 100%); + max-height: min(90vh, 640px); + box-shadow: var(--shadow-lg); + display: flex; + flex-direction: column; + overflow: hidden; + } + + .guide-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 24px 12px; + } + + .guide-modal-title { + font-size: 18px; + font-weight: 700; + } + + .guide-modal-close { + width: 40px; + height: 40px; + border-radius: 50%; + border: 2px solid var(--border-color); + background: var(--bg-secondary); + color: var(--text-secondary); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease; + } + + .guide-modal-close:hover { + border-color: var(--primary); + color: var(--primary); + } + + .guide-modal-body { + padding: 0 24px 24px; + overflow-y: auto; + } + + .installation-card { + background: transparent; + box-shadow: none; + margin-bottom: 0; + } + + .installation-card-content { + padding: 0; + } + + .step-final-action { + margin-top: 16px; + } + + .step-final-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 12px 20px; + border-radius: 999px; + font-weight: 600; + font-size: 14px; + color: var(--tg-theme-button-text-color); + background: linear-gradient(135deg, rgba(var(--primary-rgb), 1), rgba(59, 130, 246, 0.9)); + box-shadow: 0 8px 24px rgba(var(--primary-rgb), 0.35); + text-decoration: none; + border: none; + cursor: pointer; + transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; + } + + .step-final-button:disabled { + cursor: not-allowed; + opacity: 0.6; + box-shadow: none; + } + + .step-final-button:not(:disabled):hover { + transform: translateY(-1px); + box-shadow: 0 12px 28px rgba(var(--primary-rgb), 0.45); + } + + .step-final-button svg { + width: 18px; + height: 18px; + } + /* Mobile Optimizations */ @media (max-width: 480px) { .container { @@ -4676,13 +4840,6 @@
- -
+ +
@@ -4863,33 +5029,44 @@
- -
-
-
Installation Guide
-
-
-
- - - -
+
+
+
+
+ + + + +
-
- +
+ +
+
+
@@ -8326,6 +8503,19 @@
`; }).join(''); + + container.querySelectorAll('.step-final-button').forEach(button => { + button.addEventListener('click', () => { + const link = getConnectLink(); + if (!link) { + return; + } + closeInstallationModal(); + openExternalLink(link); + }); + }); + + updateInstructionConnectButtons(); } function renderAppSteps(app) { @@ -8382,9 +8572,64 @@ `; } + const connectLabelRaw = t('button.connect.default'); + const connectLabel = connectLabelRaw === 'button.connect.default' + ? 'Connect to VPN' + : connectLabelRaw; + + html += ` +
+ +
+ `; + return html; } + function updateInstructionConnectButtons(hasConnect = Boolean(getConnectLink())) { + document.querySelectorAll('.step-final-button').forEach(button => { + button.disabled = !hasConnect; + }); + } + + function openInstallationModal() { + const modal = document.getElementById('installationModal'); + if (!modal) { + return; + } + + renderApps(); + setActivePlatformButton(); + updateInstructionConnectButtons(Boolean(getConnectLink())); + + modal.classList.remove('hidden'); + document.body.classList.add('modal-open'); + + const focusTarget = modal.querySelector('.guide-modal-close'); + if (focusTarget && typeof focusTarget.focus === 'function') { + try { + focusTarget.focus({ preventScroll: true }); + } catch (error) { + focusTarget.focus(); + } + } + } + + function closeInstallationModal() { + const modal = document.getElementById('installationModal'); + if (!modal) { + return; + } + + modal.classList.add('hidden'); + document.body.classList.remove('modal-open'); + } + function getLocalizedText(textObj) { if (!textObj) { return ''; @@ -15849,16 +16094,17 @@ } function updateActionButtons() { - const connectBtn = document.getElementById('connectBtn'); const copyBtn = document.getElementById('copyBtn'); + const guideBtn = document.getElementById('openGuideBtn'); const connectLink = getConnectLink(); - if (connectBtn) { - const hasConnect = Boolean(connectLink); - connectBtn.disabled = !hasConnect; - connectBtn.classList.toggle('hidden', !hasConnect); + + if (guideBtn) { + guideBtn.disabled = false; } + updateInstructionConnectButtons(Boolean(connectLink)); + const subscriptionUrl = getCurrentSubscriptionUrl(); if (copyBtn) { const hasUrl = Boolean(subscriptionUrl); @@ -15901,9 +16147,18 @@ }); }); - document.getElementById('connectBtn')?.addEventListener('click', () => { - const link = getConnectLink(); - openExternalLink(link); + document.getElementById('openGuideBtn')?.addEventListener('click', () => { + openInstallationModal(); + }); + + document.getElementById('installationModalClose')?.addEventListener('click', () => { + closeInstallationModal(); + }); + + document.getElementById('installationModal')?.addEventListener('click', event => { + if (event.target === event.currentTarget) { + closeInstallationModal(); + } }); const topupButton = document.getElementById('topupBalanceBtn'); @@ -15929,6 +16184,11 @@ closeTopupModal(); return; } + const installationModal = document.getElementById('installationModal'); + if (installationModal && !installationModal.classList.contains('hidden')) { + closeInstallationModal(); + return; + } if (subscriptionPurchaseModalOpen) { closeSubscriptionPurchaseModal(); }