diff --git a/public/index.html b/public/index.html index 5896dfc..a3e8abd 100644 --- a/public/index.html +++ b/public/index.html @@ -42,6 +42,21 @@ + +
+
+
+ 🤖 Hire a Digital Worker that never sleeps – writes posts, generates images & handles tedious tasks on its own computer +
+ Start Free → + +
+
+
diff --git a/public/scripts/main.js b/public/scripts/main.js index 4883642..a5454a3 100644 --- a/public/scripts/main.js +++ b/public/scripts/main.js @@ -7,13 +7,15 @@ class PairDrop { this.$headerInstallBtn = $('install'); this.deferredStyles = [ - "styles/styles-deferred.css" + "styles/styles-deferred.css", + "styles/promo-banner.css" ]; this.deferredScripts = [ "scripts/browser-tabs-connector.js", "scripts/util.js", "scripts/network.js", "scripts/ui.js", + "scripts/promo-banner.js", "scripts/libs/heic2any.min.js", "scripts/libs/no-sleep.min.js", "scripts/libs/qr-code.min.js", diff --git a/public/scripts/promo-banner.js b/public/scripts/promo-banner.js new file mode 100644 index 0000000..3de6e0a --- /dev/null +++ b/public/scripts/promo-banner.js @@ -0,0 +1,49 @@ +/** + * Promotional banner functionality + * Handles banner appearance, theme switching, and user preferences + */ +(function () { + const banner = document.getElementById('promo-banner'); + const closeButton = document.getElementById('promo-banner-close'); + + // Check if user has previously dismissed the banner + const bannerDismissed = localStorage.getItem('promo-banner-dismissed'); + + if (bannerDismissed === 'true') { + banner.classList.add('hidden'); + } else { + // Set initial theme + setThemeClass(); + + // Listen for theme changes + const themeObserver = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + if (mutation.attributeName === 'class') { + setThemeClass(); + } + }); + }); + + // Start observing the document body for class changes (theme changes) + themeObserver.observe(document.body, { attributes: true }); + + // Handle close button click + closeButton.addEventListener('click', function () { + banner.classList.add('hidden'); + localStorage.setItem('promo-banner-dismissed', 'true'); + }); + } + + // Set appropriate theme class based on body class + function setThemeClass() { + // Remove existing theme classes + banner.classList.remove('light-theme', 'dark-theme'); + + // Check if body has dark-theme class + if (document.body.classList.contains('dark-theme')) { + banner.classList.add('dark-theme'); + } else { + banner.classList.add('light-theme'); + } + } +})(); diff --git a/public/service-worker.js b/public/service-worker.js index e1f4f45..6092daa 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,4 +1,4 @@ -const cacheVersion = 'v1.11.2'; +const cacheVersion = 'v1.11.3'; const cacheTitle = `pairdrop-cache-${cacheVersion}`; const relativePathsToCache = [ './', @@ -6,6 +6,7 @@ const relativePathsToCache = [ 'manifest.json', 'styles/styles-main.css', 'styles/styles-deferred.css', + 'styles/promo-banner.css', 'scripts/browser-tabs-connector.js', 'scripts/localization.js', 'scripts/main.js', @@ -14,6 +15,7 @@ const relativePathsToCache = [ 'scripts/ui.js', 'scripts/ui-main.js', 'scripts/util.js', + 'scripts/promo-banner.js', 'scripts/worker/canvas-worker.js', 'scripts/libs/heic2any.min.js', 'scripts/libs/no-sleep.min.js', diff --git a/public/styles/promo-banner.css b/public/styles/promo-banner.css new file mode 100644 index 0000000..0e05939 --- /dev/null +++ b/public/styles/promo-banner.css @@ -0,0 +1,123 @@ +/* Styles for the promotional banner */ +.promo-banner { + display: flex; + width: 100%; + background-color: var(--primary-color); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); + transition: all 0.3s ease; + font-size: 1.125rem; + margin: 0 0 8px 0; + position: relative; + z-index: 10; +} + +.promo-banner-content { + display: flex; + align-items: center; + justify-content: center; + padding: 10px 40px; + width: 100%; + max-width: 1200px; + margin: 0 auto; + flex-wrap: wrap; +} + +.promo-banner-text { + margin-right: 1rem; + line-height: 1.5; + color: white; + min-width: 200px; + font-weight: 500; + text-align: center; +} + +.promo-banner-cta { + white-space: nowrap; + padding: 8px 16px; + border-radius: 6px; + text-decoration: none; + font-weight: 600; + font-size: 1rem; + margin: 4px 0; + transition: all 0.2s ease; + background-color: white; + color: var(--primary-color); +} + +.promo-banner-cta:hover { + background-color: rgba(255, 255, 255, 0.9); + /* transform: translateY(-1px); */ +} + +.promo-banner-close { + position: absolute; + top: 50%; + right: 12px; + transform: translateY(-50%); + background: none; + border: none; + cursor: pointer; + padding: 4px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + opacity: 0.8; + transition: opacity 0.2s ease; + color: white; +} + +.promo-banner-close:hover { + opacity: 1; + background-color: rgba(255, 255, 255, 0.1); +} + +/* Light theme styles */ +.promo-banner.light-theme { + background-color: #6366f1; + background-image: linear-gradient(135deg, #6366f1, #8b5cf6); +} + +/* Dark theme styles */ +.promo-banner.dark-theme { + background-color: #4f46e5; + background-image: linear-gradient(135deg, #4f46e5, #7c3aed); +} + +/* Hidden state */ +.promo-banner.hidden { + display: none; +} + +/* Responsive styles */ +@media (max-width: 768px) { + .promo-banner-content { + padding: 10px 12px; + } + + .promo-banner-text { + font-size: 1rem; + } +} + +@media (max-width: 600px) { + .promo-banner-content { + flex-direction: column; + align-items: center; + text-align: center; + } + + .promo-banner-text { + margin-bottom: 0.5rem; + } + + .promo-banner-cta { + margin: 0; + } + + .promo-banner-close { + top: 8px; + right: 8px; + transform: none; + } +} \ No newline at end of file