Add a mobile-specific sticky ad banner at the bottom of the screen

Introduces a new `MobileStickyAd` component that displays a 320x50px ad banner at the bottom of the screen on mobile devices only. The ad appears after a 2-second delay and can be dismissed by the user for the session. The footer dynamically adjusts its padding to prevent content overlap with the sticky ad. The `replit.md` file is updated to reflect this new feature.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 23852c00-4779-460a-9e0c-d09fee4b6c92
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: db8604a4-d491-44c8-b0ac-b67d779b436a
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/23852c00-4779-460a-9e0c-d09fee4b6c92/tdiozLO
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
sebastjanartic 2026-03-08 07:03:52 +00:00
parent 0248e83a15
commit dc6648c54d
4 changed files with 62 additions and 0 deletions

View File

@ -21,6 +21,7 @@ import KontaktPage from "@/pages/kontakt";
import AdminGalleryPage from "@/pages/admin-gallery";
import AdminPushPage from "@/pages/admin-push";
import CookieConsent from "@/components/cookie-consent";
import MobileStickyAd from "@/components/mobile-sticky-ad";
function ScrollToTop() {
const [location] = useLocation();
@ -63,6 +64,7 @@ function App() {
<TooltipProvider>
<Toaster />
<Router />
<MobileStickyAd />
</TooltipProvider>
</QueryClientProvider>
);

View File

@ -1,5 +1,6 @@
import { Link } from "wouter";
import { SiFacebook, SiInstagram, SiYoutube, SiTiktok } from "react-icons/si";
import { useIsMobile } from "@/hooks/use-mobile";
const SOCIAL_LINKS = [
{ href: "https://www.facebook.com/folxtv/", icon: SiFacebook, label: "Facebook", testId: "link-social-facebook" },
@ -8,7 +9,13 @@ const SOCIAL_LINKS = [
{ href: "https://www.tiktok.com/@folxtv", icon: SiTiktok, label: "TikTok", testId: "link-social-tiktok" },
];
const STICKY_AD_DISMISS_KEY = "folx-sticky-ad-dismissed";
export default function Footer({ narrow }: { narrow?: boolean }) {
const isMobile = useIsMobile();
const stickyAdDismissed = typeof window !== "undefined" && sessionStorage.getItem(STICKY_AD_DISMISS_KEY);
const showStickyPadding = isMobile && !stickyAdDismissed;
return (
<footer className="border-t border-border mt-10" data-testid="footer">
<div className={`${narrow ? "max-w-4xl" : "max-w-7xl"} mx-auto px-4 sm:px-6 lg:px-8 py-8 relative z-20`}>
@ -113,6 +120,7 @@ export default function Footer({ narrow }: { narrow?: boolean }) {
</p>
</div>
</div>
{showStickyPadding && <div className="h-20" aria-hidden="true" />}
</footer>
);
}

View File

@ -0,0 +1,51 @@
import { useState, useEffect } from "react";
import { X } from "lucide-react";
import { useIsMobile } from "@/hooks/use-mobile";
import AdSense from "./adsense";
const DISMISS_KEY = "folx-sticky-ad-dismissed";
export default function MobileStickyAd() {
const isMobile = useIsMobile();
const [visible, setVisible] = useState(false);
useEffect(() => {
if (!isMobile) return;
const dismissed = sessionStorage.getItem(DISMISS_KEY);
if (dismissed) return;
const timer = setTimeout(() => setVisible(true), 2000);
return () => clearTimeout(timer);
}, [isMobile]);
const close = () => {
setVisible(false);
sessionStorage.setItem(DISMISS_KEY, "1");
};
if (!isMobile || !visible) return null;
return (
<div className="fixed bottom-0 left-0 right-0 z-[100] animate-in slide-in-from-bottom duration-300" data-testid="mobile-sticky-ad">
<div className="relative bg-card border-t border-card-border shadow-2xl">
<button
onClick={close}
className="absolute -top-8 right-2 w-7 h-7 flex items-center justify-center rounded-full bg-card border border-card-border shadow-lg text-muted-foreground hover:text-foreground transition-colors"
data-testid="button-sticky-ad-close"
aria-label="Schließen"
>
<X className="w-4 h-4" />
</button>
<div className="text-[9px] text-muted-foreground/40 text-center pt-1 uppercase tracking-widest">Anzeige</div>
<div className="flex justify-center pb-1">
<AdSense
slot="4154017639"
format="horizontal"
style={{ display: "inline-block", width: "320px", height: "50px" }}
responsive={false}
/>
</div>
</div>
</div>
);
}

View File

@ -30,6 +30,7 @@ The official website for Folx Music Television (folx.tv). Dark-themed bento grid
- Google AdSense integration (ca-pub-4465464714854276)
- Interstitial overlay ad on article pages (3s delay, shows every other article visit, sessionStorage counter)
- Parallax/reveal ad below article content (sticky background ad revealed on scroll)
- Mobile sticky banner ad at bottom of screen (2s delay, session-dismissible, mobile-only via useIsMobile hook)
- Web Push Notifications (bell icon in header, auto-send on new articles, admin panel at /admin/push)
- Article listing with featured carousel and category filtering
- HTML content supports embedded iframes (bunny.net, YouTube, Facebook, Instagram, TikTok)