diff --git a/.common/resources/smtc-bridge-icon.png b/.common/resources/smtc-bridge-icon.png new file mode 100644 index 0000000..a17927d Binary files /dev/null and b/.common/resources/smtc-bridge-icon.png differ diff --git a/.common/utils/helpers.js b/.common/utils/helpers.js index 3e2816e..d0f1789 100644 --- a/.common/utils/helpers.js +++ b/.common/utils/helpers.js @@ -484,4 +484,242 @@ async function GetAccentPalette(imageUrl) { resolve(hexPalette); }); }); +} + +// Generic popup +function showPopup(iconSrc, title, subtitle, attribute, background, button) { + // 1. Check if a popup is already on screen + const existingOverlay = document.getElementById('global-common-overlay'); + + // If it exists AND isn't already in the middle of fading out, DO NOTHING + if (existingOverlay && !existingOverlay.classList.contains('common-closing')) { + return null; + } + + // If there IS a popup but it IS fading out, kill it instantly to make room for the new one + if (existingOverlay) { + existingOverlay.remove(); + } + + // 2. Inject global styles if they don't already exist in the head + if (!document.getElementById('global-common-popup-styles')) { + const styleSheet = document.createElement('style'); + styleSheet.id = 'global-common-popup-styles'; + styleSheet.innerText = ` + #global-common-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: transparent; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + display: flex; + align-items: center; + justify-content: center; + z-index: 999999; + animation: commonFadeIn 2s cubic-bezier(0.16, 1, 0.3, 1) forwards; + } + .common-popup-card { + width: 90%; + max-width: 500px; + border-radius: 24px; + box-sizing: border-box; + display: flex; + flex-direction: row; + align-items: stretch; + overflow: hidden; + box-shadow: 0 30px 60px rgba(0,0,0,0.4), + 0 0 0 1px rgba(255, 255, 255, 0.08); + animation: commonScaleIn 2.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; + gap: 32px; + padding: 32px; + } + .common-popup-icon-container { + display: flex; + align-items: center; + justify-content: center; + background: transparent; + } + .common-popup-img { + height: 48px; + width: auto; + object-fit: contain; + display: block; + } + .common-popup-text-content { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + text-align: left; + gap: 8px; + } + .common-popup-title { + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 22px; + font-weight: 700; + color: #ffffff; + letter-spacing: -0.02em; + line-height: 1.2; + } + .common-popup-title:last-child { + margin-bottom: 0; + } + .common-popup-subtitle { + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 14px; + font-weight: 400; + color: rgba(255, 255, 255, 0.65); + margin: 0; + line-height: 1.5; + } + .common-popup-attribute { + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 13px; + color: rgba(255, 255, 255, 0.4); + word-break: break-all; + } + /* 💎 GLASSMORPHIC BUTTON STYLES */ + .common-popup-button { + margin-top: 6px; + padding: 10px 20px; + border-radius: 12px; + border: 1px solid rgba(255, 255, 255, 0.15); + background: rgba(255, 255, 255, 0.1); + color: #ffffff; + font-family: system-ui, sans-serif; + font-size: 13px; + font-weight: 600; + cursor: pointer; + transition: background 0.2s ease, border-color 0.2s ease, transform 0.1s ease; + text-align: center; + width: fit-content; + } + .common-popup-button:hover { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.3); + } + .common-popup-button:active { + transform: scale(0.97); + } + @keyframes commonFadeIn { + from { opacity: 0; } to { opacity: 1; } + } + @keyframes commonScaleIn { + from { transform: scale(0.95) translateY(10px); opacity: 0; } + to { transform: scale(1) translateY(0); opacity: 1; } + } + #global-common-overlay.common-closing { + animation: commonFadeOut 2s cubic-bezier(0.16, 1, 0.3, 1) forwards; + } + .common-closing .common-popup-card { + animation: commonScaleOut 2.5s cubic-bezier(0.16, 1, 0.3, 1) forwards; + } + @keyframes commonFadeOut { + from { opacity: 1; } to { opacity: 0; } + } + @keyframes commonScaleOut { + from { transform: scale(1) translateY(0); opacity: 1; } + to { transform: scale(0.95) translateY(10px); opacity: 0; } + } + `; + document.head.appendChild(styleSheet); + } + + // 3. Create elements + const overlay = document.createElement('div'); + overlay.id = 'global-common-overlay'; + + const card = document.createElement('div'); + card.className = 'common-popup-card'; + card.style.background = background || 'linear-gradient(135deg, #1a1a1e 0%, #111113 100%)'; + + // 4. Construct Inner Content (Strict Conditional Rendering) + const iconMarkup = iconSrc + ? `
` + : ''; + + const titleMarkup = title + ? `` + : ''; + + const subtitleMarkup = subtitle + ? `` + : ''; + + const attributeMarkup = attribute + ? `` + : ''; + + // Render button conditional markup + const buttonMarkup = (button && button.text) + ? `` + : ''; + + card.innerHTML = ` + ${iconMarkup} +