Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/app/blog/BlogAd.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client';

import { useEffect, useState } from 'react';
import Script from 'next/script';
import { useAuthStore } from '@/lib/stores/auth.js';

// Standard CrawlProof ad snippet (data-cp-ad + ad.js), shown only to logged-out
// visitors on /blog/*. The auth store hydrates from localStorage on the client,
// so we wait for mount + the initial `loading` to settle before deciding, to
// avoid flashing an ad at a signed-in user. On client-side navigation ad.js may
// already be loaded, so we re-trigger its slot scan once shown.
export default function BlogAd() {
const [mounted, setMounted] = useState(false);
const user = useAuthStore((s) => s.user);
const loading = useAuthStore((s) => s.loading);

useEffect(() => {
setMounted(true);
}, []);

const show = mounted && !loading && !user;

useEffect(() => {
if (show && typeof window !== 'undefined') {
window.crawlproofAds?.scan?.();
}
}, [show]);

if (!show) return null;

return (
<>
<div className="container" style={{ maxWidth: '48rem', margin: '0 auto', padding: '1.5rem 0', display: 'flex', justifyContent: 'center' }}>
<div data-cp-ad data-slot="4a5b5f93-ebd9-4d02-b927-05544fdeb81e" data-format="banner_300x250"></div>
</div>
<Script src="https://crawlproof.com/ad.js" strategy="afterInteractive" />
</>
);
}
28 changes: 23 additions & 5 deletions src/app/blog/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import Script from 'next/script';
import BlogAd from './BlogAd.jsx';

const AD_SLOT = '4a5b5f93-ebd9-4d02-b927-05544fdeb81e';
const AD_FORMAT = 'banner_300x250';
const AD_WRAP = { maxWidth: '48rem', margin: '0 auto', padding: '1.5rem 0', display: 'flex', justifyContent: 'center' };

export default function BlogLayout({ children }) {
return (
<>
{children}
<div className="container" style={{ maxWidth: '48rem', margin: '0 auto', padding: '1.5rem 0', display: 'flex', justifyContent: 'center' }}>
<div data-cp-ad data-slot="4a5b5f93-ebd9-4d02-b927-05544fdeb81e" data-format="banner_300x250"></div>
</div>
<Script src="https://crawlproof.com/ad.js" strategy="afterInteractive" />
{/* Primary: standard CrawlProof snippet via ad.js, logged-out visitors only. */}
<BlogAd />
{/* No-JS fallback — renders only when JavaScript is disabled (e.g. Tor
Safest mode / .onion). A plain cross-origin iframe that renders and is
clickable with zero script. Auth can't be checked without JS, so it
shows to all no-JS visitors, which is fine for a public blog. */}
<noscript>
<div className="container" style={AD_WRAP}>
<iframe
src={`https://crawlproof.com/api/ads/frame?slot=${AD_SLOT}&format=${AD_FORMAT}`}
title="Advertisement"
width={300}
height={250}
scrolling="no"
style={{ border: 0, width: 300, height: 250, maxWidth: '100%' }}
/>
</div>
</noscript>
</>
);
}
Loading