diff --git a/modules/admin/AdminController.php b/modules/admin/AdminController.php index 6903c8f..dfeed39 100644 --- a/modules/admin/AdminController.php +++ b/modules/admin/AdminController.php @@ -399,6 +399,13 @@ class AdminController 'source' => 'Pages module', 'enabled' => true, ], + [ + 'tag' => '[home-catalog]', + 'description' => 'Complete homepage catalog block (hero + releases + chart + artists + newsletter).', + 'example' => '[home-catalog release_limit="8" artist_limit="6" chart_limit="10"]', + 'source' => 'Pages module', + 'enabled' => true, + ], [ 'tag' => '[login-link]', 'description' => 'Renders an account login link.', @@ -503,6 +510,7 @@ class AdminController 'sale-chart', 'top-sellers', 'hero', + 'home-catalog', 'login-link', 'account-link', 'cart-link', @@ -565,6 +573,10 @@ class AdminController . '.ac-shortcode-newsletter-row{display:grid;grid-template-columns:1fr auto;gap:8px;}' . '.ac-shortcode-newsletter-input{height:40px;border:1px solid rgba(255,255,255,.16);border-radius:10px;background:rgba(8,10,16,.6);color:#f5f7ff;padding:0 12px;font-size:14px;}' . '.ac-shortcode-newsletter-btn{height:40px;padding:0 14px;border:1px solid rgba(57,244,179,.6);border-radius:999px;background:rgba(57,244,179,.16);color:#9ff8d8;font-size:12px;letter-spacing:.14em;text-transform:uppercase;font-family:"IBM Plex Mono",monospace;cursor:pointer;}' + . '.ac-home-catalog{display:grid;gap:14px;}' + . '.ac-home-columns{display:grid;grid-template-columns:minmax(0,2.2fr) minmax(280px,1fr);gap:14px;align-items:start;}' + . '.ac-home-main,.ac-home-side{display:grid;gap:14px;align-content:start;}' + . '@media (max-width:1200px){.ac-home-columns{grid-template-columns:1fr;}}' . '' . '
' . htmlspecialchars($code, ENT_QUOTES, 'UTF-8') . '
' . $rendered diff --git a/modules/pages/PagesController.php b/modules/pages/PagesController.php index e20c392..88c7938 100644 --- a/modules/pages/PagesController.php +++ b/modules/pages/PagesController.php @@ -39,12 +39,22 @@ class PagesController return $this->notFound(); } + $rendered = Shortcodes::render((string)$page['content_html'], [ + 'page_slug' => $slug, + 'page_title' => (string)$page['title'], + ]); + // WYSIWYG editors often wrap shortcode blocks in

, which breaks grid placement. + $rendered = preg_replace( + '~

\s*(<(?:section|div|form|a)[^>]*class="[^"]*ac-shortcode[^"]*"[^>]*>.*?)\s*

~is', + '$1', + $rendered + ) ?? $rendered; + $rendered = preg_replace('~(<(?:section|div|form|a)[^>]*class="[^"]*ac-shortcode[^"]*"[^>]*>)\s*~i', '$1', $rendered) ?? $rendered; + $rendered = preg_replace('~\s*()~i', '$1', $rendered) ?? $rendered; + return new Response($this->view->render('site/show.php', [ 'title' => (string)$page['title'], - 'content_html' => Shortcodes::render((string)$page['content_html'], [ - 'page_slug' => $slug, - 'page_title' => (string)$page['title'], - ]), + 'content_html' => $rendered, ])); } diff --git a/modules/pages/module.php b/modules/pages/module.php index c063941..8b60688 100644 --- a/modules/pages/module.php +++ b/modules/pages/module.php @@ -33,6 +33,26 @@ Shortcodes::register('hero', static function (array $attrs = []): string { return $html; }); +Shortcodes::register('home-catalog', static function (array $attrs = []): string { + $releaseLimit = max(1, min(12, (int)($attrs['release_limit'] ?? 8))); + $artistLimit = max(1, min(10, (int)($attrs['artist_limit'] ?? 6))); + $chartLimit = max(1, min(20, (int)($attrs['chart_limit'] ?? 10))); + + $hero = Shortcodes::render('[hero eyebrow="Catalog Focus" title="Latest Drops" subtitle="Fresh releases, artists, and best sellers." cta_text="Browse Releases" cta_url="/releases" secondary_text="Meet Artists" secondary_url="/artists"]'); + $releases = Shortcodes::render('[latest-releases limit="' . $releaseLimit . '"]'); + $artists = Shortcodes::render('[new-artists limit="' . $artistLimit . '"]'); + $chart = Shortcodes::render('[sale-chart type="tracks" window="latest" limit="' . $chartLimit . '"]'); + $newsletter = Shortcodes::render('[newsletter-signup title="Join the list" button="Subscribe"]'); + + return '
' + . $hero + . '
' + . '
' . $releases . $chart . '
' + . '' + . '
' + . '
'; +}); + return function (Router $router): void { $controller = new PagesController(); $router->get('/page', [$controller, 'show']); diff --git a/modules/pages/views/site/show.php b/modules/pages/views/site/show.php index 44dea21..df93f7a 100644 --- a/modules/pages/views/site/show.php +++ b/modules/pages/views/site/show.php @@ -4,7 +4,7 @@ $contentHtml = $content_html ?? ''; ob_start(); ?>
-
+
diff --git a/views/site/layout.php b/views/site/layout.php index e12f8c2..09df284 100644 --- a/views/site/layout.php +++ b/views/site/layout.php @@ -67,7 +67,7 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] body { margin: 0; font-family: 'Syne', sans-serif; - background-color: #14151a; + background-color: #0f1115; color: var(--text); position: relative; min-height: 100vh; @@ -78,9 +78,8 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] inset: 0; z-index: -2; background: - radial-gradient(120% 70% at 50% 12%, rgba(68, 94, 155, 0.12), transparent 62%), - radial-gradient(140% 90% at 50% 80%, rgba(12, 16, 26, 0.65), transparent 70%), - linear-gradient(180deg, #1a1b1f 0%, #15161b 55%, #111217 100%); + radial-gradient(120% 75% at 50% -10%, rgba(38, 78, 138, 0.16), transparent 55%), + linear-gradient(180deg, #13161d 0%, #0f1116 45%, #0d1014 100%); } body::after { content: ''; @@ -91,7 +90,14 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] pointer-events: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E"); } - .shell { max-width: 1080px; margin: 0 auto; padding: 18px 24px 28px; } + .shell { max-width: 1400px; margin: 0 auto; padding: 16px 24px 24px; } + .site-header-shell { + position: sticky; + top: 0; + z-index: 40; + padding-top: 10px; + backdrop-filter: blur(10px); + } .shell-main { padding-top: 8px; } .shell-notice { padding-top: 2px; padding-bottom: 4px; } .site-notice { @@ -142,8 +148,8 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] border-radius: 24px; background: rgba(20, 22, 28, 0.75); border: 1px solid rgba(255,255,255,0.12); - box-shadow: 0 20px 50px rgba(0,0,0,0.3); - padding: 28px; + box-shadow: 0 18px 42px rgba(0,0,0,0.28); + padding: 22px; } .nav { display: flex; @@ -171,6 +177,30 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] align-items: center; gap: 8px; } + .nav-search-form { + display: inline-flex; + align-items: center; + gap: 8px; + height: 36px; + border-radius: 10px; + border: 1px solid rgba(255,255,255,0.12); + background: rgba(8,12,18,0.72); + color: var(--muted); + padding: 0 10px; + min-width: 220px; + } + .nav-search-form input { + width: 100%; + border: 0; + outline: none; + background: transparent; + color: var(--text); + font-size: 12px; + font-family: 'IBM Plex Mono', monospace; + } + .nav-search-form input::placeholder { + color: rgba(255,255,255,0.45); + } .nav-account { display: inline-flex; align-items: center; @@ -302,8 +332,8 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] } .page-content { display: grid; - grid-template-columns: minmax(0, 1.6fr) minmax(240px, 1fr); - gap: 16px; + grid-template-columns: minmax(0, 2.2fr) minmax(280px, 1fr); + gap: 14px; align-items: start; } .page-content > .ac-shortcode-hero, @@ -339,18 +369,18 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] } .ac-shortcode-release-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); - justify-content: start; - gap: 12px; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 10px; } .ac-shortcode-release-card { text-decoration: none; color: inherit; border: 1px solid rgba(255,255,255,0.1); - background: rgba(15,18,24,0.6); - border-radius: 14px; + background: rgba(14,17,23,0.75); + border-radius: 12px; overflow: hidden; display: grid; + grid-template-rows: auto 1fr; min-height: 100%; transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease; } @@ -379,12 +409,12 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] letter-spacing: 0.2em; } .ac-shortcode-release-meta { - padding: 10px; + padding: 8px 10px 10px; display: grid; - gap: 4px; + gap: 3px; } .ac-shortcode-release-title { - font-size: 18px; + font-size: 16px; line-height: 1.2; font-weight: 600; } @@ -395,19 +425,21 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] } .ac-shortcode-artists-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 240px)); - justify-content: start; - gap: 12px; + grid-template-columns: 1fr; + gap: 8px; } .ac-shortcode-artist-card { text-decoration: none; color: inherit; border: 1px solid rgba(255,255,255,0.1); - background: rgba(15,18,24,0.6); - border-radius: 14px; + background: rgba(14,17,23,0.75); + border-radius: 12px; overflow: hidden; display: grid; - min-height: 100%; + grid-template-columns: 52px minmax(0, 1fr); + align-items: center; + gap: 10px; + padding: 8px; transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease; } .ac-shortcode-artist-card:hover { @@ -416,11 +448,13 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] box-shadow: 0 10px 24px rgba(0,0,0,.25); } .ac-shortcode-artist-avatar { - aspect-ratio: 1 / 1; + width: 52px; + height: 52px; background: rgba(255,255,255,0.03); display: grid; place-items: center; overflow: hidden; + border-radius: 10px; } .ac-shortcode-artist-avatar img { width: 100%; @@ -429,12 +463,11 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] display: block; } .ac-shortcode-artist-meta { - padding: 10px; display: grid; - gap: 4px; + gap: 2px; } .ac-shortcode-artist-name { - font-size: 18px; + font-size: 15px; line-height: 1.2; font-weight: 600; } @@ -445,10 +478,10 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] .ac-shortcode-hero { border: 1px solid rgba(255,255,255,0.14); border-radius: 18px; - padding: 18px; + padding: 16px 18px; background: linear-gradient(135deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)); display: grid; - gap: 10px; + gap: 8px; } .ac-shortcode-hero-eyebrow { font-size: 10px; @@ -458,7 +491,7 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] font-family: 'IBM Plex Mono', monospace; } .ac-shortcode-hero-title { - font-size: clamp(30px, 5vw, 54px); + font-size: clamp(30px, 4vw, 50px); line-height: 1.05; font-weight: 700; margin: 0; @@ -505,12 +538,12 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] } .ac-shortcode-sale-item { border: 1px solid rgba(255,255,255,0.1); - background: rgba(15,18,24,0.6); + background: rgba(14,17,23,0.75); border-radius: 10px; - padding: 10px 12px; + padding: 8px 10px; display: grid; - grid-template-columns: auto 1fr auto; - gap: 10px; + grid-template-columns: auto minmax(0,1fr) auto; + gap: 8px; align-items: center; } .ac-shortcode-sale-rank { @@ -519,15 +552,8 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] color: var(--muted); letter-spacing: 0.15em; } - .ac-shortcode-sale-title { - font-size: 14px; - line-height: 1.3; - } - .ac-shortcode-sale-meta { - font-size: 12px; - color: var(--muted); - white-space: nowrap; - } + .ac-shortcode-sale-title { font-size: 14px; line-height: 1.3; } + .ac-shortcode-sale-meta { font-size: 12px; color: var(--muted); white-space: nowrap; } .ac-shortcode-link { display: inline-flex; align-items: center; @@ -590,6 +616,30 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] font-family: 'IBM Plex Mono', monospace; cursor: pointer; } + .ac-home-catalog { + display: grid; + gap: 14px; + } + .ac-home-columns { + display: grid; + grid-template-columns: minmax(0, 2.2fr) minmax(280px, 1fr); + gap: 14px; + align-items: start; + } + .ac-home-main, + .ac-home-side { + display: grid; + gap: 14px; + align-content: start; + } + @media (max-width: 1200px) { + .ac-shortcode-release-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .ac-home-columns { + grid-template-columns: 1fr; + } + } @media (max-width: 900px) { .shell { padding: 12px 14px 18px; @@ -648,6 +698,10 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] flex: 1 1 auto; justify-content: center; } + .nav-search-form { + min-width: 0; + width: 100%; + } .nav-cart { flex: 1 1 auto; } @@ -663,6 +717,9 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] .page-content { grid-template-columns: 1fr; } + .ac-shortcode-release-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } .page-content > .ac-shortcode-releases, .page-content > .ac-shortcode-artists, .page-content > .ac-shortcode-sale-chart, @@ -671,6 +728,14 @@ if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['ac_site_notice'] grid-column: 1; } } + @media (max-width: 620px) { + .ac-shortcode-release-grid { + grid-template-columns: 1fr; + } + .ac-shortcode-hero-title { + font-size: clamp(28px, 10vw, 42px); + } + }