diff --git a/resources/js/Pages/ArtworkPage.jsx b/resources/js/Pages/ArtworkPage.jsx
index 9e3e5fa1..b66a8426 100644
--- a/resources/js/Pages/ArtworkPage.jsx
+++ b/resources/js/Pages/ArtworkPage.jsx
@@ -9,6 +9,7 @@ import ArtworkTags from '../components/artwork/ArtworkTags'
import ArtworkDescription from '../components/artwork/ArtworkDescription'
import ArtworkEvolutionPanel from '../components/artwork/ArtworkEvolutionPanel'
import ArtworkComments from '../components/artwork/ArtworkComments'
+import AdSenseUnit from '../components/ads/AdSenseUnit'
import ArtworkActionBar from '../components/artwork/ArtworkActionBar'
import ArtworkDetailsPanel from '../components/artwork/ArtworkDetailsPanel'
import CreatorSpotlight from '../components/artwork/CreatorSpotlight'
@@ -319,6 +320,10 @@ function publisherToGroupSummary(publisher) {
{/* Tags & categories */}
+ {!isAuthenticated ? (
+
+ ) : null}
+
{/* Comments */}
{
+ if (!enabled || !slot || pushed.current) {
+ return undefined
+ }
+
+ pushed.current = true
+
+ try {
+ window.adsbygoogle = window.adsbygoogle || []
+ window.adsbygoogle.push({})
+ } catch {
+ // AdSense may be blocked or not yet loaded (consent not granted).
+ }
+
+ return undefined
+ }, [enabled, slot])
+
+ if (!enabled || !slot) {
+ return null
+ }
+
+ return (
+
+
+
+ )
+}
diff --git a/resources/js/components/ads/AdSenseUnit.test.jsx b/resources/js/components/ads/AdSenseUnit.test.jsx
new file mode 100644
index 00000000..67d37842
--- /dev/null
+++ b/resources/js/components/ads/AdSenseUnit.test.jsx
@@ -0,0 +1,43 @@
+import React from 'react'
+import { afterEach, describe, expect, it, vi } from 'vitest'
+import { cleanup, render } from '@testing-library/react'
+import AdSenseUnit from './AdSenseUnit'
+
+describe('AdSenseUnit', () => {
+ afterEach(() => {
+ cleanup()
+ vi.restoreAllMocks()
+ delete window.adsbygoogle
+ })
+
+ it('renders the dashboard horizontal slot and pushes once', () => {
+ window.adsbygoogle = []
+
+ const { container } = render()
+ const unit = container.querySelector('ins.adsbygoogle')
+
+ expect(unit).not.toBeNull()
+ expect(container.firstChild.className).toContain('justify-center')
+ expect(unit.className).toContain('max-w-3xl')
+ expect(unit.getAttribute('data-ad-client')).toBe('ca-pub-6457864535683080')
+ expect(unit.getAttribute('data-ad-slot')).toBe('8766048277')
+ expect(unit.getAttribute('data-ad-format')).toBe('auto')
+ expect(unit.getAttribute('data-full-width-responsive')).toBe('true')
+ expect(window.adsbygoogle).toHaveLength(1)
+ })
+
+ it('renders nothing without a slot', () => {
+ const { container } = render()
+
+ expect(container.querySelector('ins.adsbygoogle')).toBeNull()
+ })
+
+ it('renders nothing when disabled for authenticated users', () => {
+ window.adsbygoogle = []
+
+ const { container } = render()
+
+ expect(container.querySelector('ins.adsbygoogle')).toBeNull()
+ expect(window.adsbygoogle).toHaveLength(0)
+ })
+})
diff --git a/resources/js/components/artwork/ArtworkActionBar.jsx b/resources/js/components/artwork/ArtworkActionBar.jsx
index 181162b2..746083a7 100644
--- a/resources/js/components/artwork/ArtworkActionBar.jsx
+++ b/resources/js/components/artwork/ArtworkActionBar.jsx
@@ -209,6 +209,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
const [reported, setReported] = useState(false)
const [reportOpen, setReportOpen] = useState(false)
const isLoggedIn = Boolean(artwork?.viewer?.is_authenticated)
+ const downloadUnavailable = ['missing', 'pending'].includes(String(artwork?.download_status || '').toLowerCase())
useEffect(() => {
setFavorited(Boolean(artwork?.viewer?.is_favorited))
}, [artwork?.id, artwork?.viewer?.is_favorited])
@@ -404,7 +405,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
{/* Download button */}
-
+ }
{/* ── Mobile fixed bottom bar ─────────────────────────────────── */}
@@ -491,7 +492,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
-
+ }
diff --git a/resources/views/components/ad-unit.blade.php b/resources/views/components/ad-unit.blade.php
index 3ac6c127..9ea52101 100644
--- a/resources/views/components/ad-unit.blade.php
+++ b/resources/views/components/ad-unit.blade.php
@@ -9,13 +9,14 @@
Renders nothing when:
- GOOGLE_ADSENSE_PUBLISHER_ID is not set in .env
+ - The visitor is authenticated
- User has not given consent (handled client-side via CSS class .ads-disabled)
--}}
@php
$publisherId = config('services.google_adsense.publisher_id');
@endphp
-@if($publisherId)
+@if($publisherId && ! auth()->check())
guest() && config('services.google_adsense.publisher_id'))
+ {{-- Google AdSense — guests only, consent-gated loader --}}
{{-- Script is only injected after the user accepts all cookies. --}}
{{-- If consent was given on a previous visit it fires on page load. --}}
@endif
+ @guest
+
+ @endguest
+
@php
$authBgRoutes = [
diff --git a/resources/views/web/home.blade.php b/resources/views/web/home.blade.php
index e6db47e8..ad80b416 100644
--- a/resources/views/web/home.blade.php
+++ b/resources/views/web/home.blade.php
@@ -100,8 +100,20 @@
@include('web.home.sections.news', ['items' => $props['news'] ?? []])
@include('web.home.sections.cta', ['isLoggedIn' => true])
@else
- @foreach ($guestArtworkSections as $section)
+ @foreach ($guestArtworkSections as $index => $section)
@include('web.home.sections.artwork-section', $section)
+ @if($index === 0)
+ {{-- Skinbase Dashboard Horizontal — guests only --}}
+
+
+
+
+ @endif
@endforeach
@include('web.home.sections.collections', ['collections' => $props['collections_trending'] ?: ($props['collections_featured'] ?: ($props['collections_editorial'] ?? []))])
@include('web.home.sections.world-spotlight', ['world' => $props['world_spotlight'] ?? null])
diff --git a/tests/Feature/HomePageTest.php b/tests/Feature/HomePageTest.php
index 981900fb..0bea12c6 100644
--- a/tests/Feature/HomePageTest.php
+++ b/tests/Feature/HomePageTest.php
@@ -64,6 +64,22 @@ it('authenticated home page sends private cache headers', function () {
->toContain('no-store');
});
+it('authenticated home page does not render ads', function () {
+ $user = User::factory()->create();
+
+ $this->actingAs($user)
+ ->get('/')
+ ->assertOk()
+ ->assertDontSee('data-ad-slot="8766048277"', false)
+ ->assertDontSee('pagead2.googlesyndication.com', false);
+});
+
+it('guest home page renders the dashboard horizontal ad', function () {
+ $this->get('/')
+ ->assertOk()
+ ->assertSee('data-ad-slot="8766048277"', false);
+});
+
it('home page includes a canonical link tag', function () {
$this->get('/')
->assertStatus(200)