GG.deals clone: CodeIgniter 4 + MongoDB game price tracker
- Full gg.deals-style UI: deal feed with filters, game pages with price history charts, rankings, vouchers, news, prepaids, subscriptions, bundles, franchises, wishlist, API docs - Real data crawlers: * gg:crawl (Steam Store API + GOG Catalog + Epic free games) * gg:catalog (252K game slugs from gg.deals sitemaps) * gg:ggdeals (per-game prices via FlareSolverr session, JSON-LD parsing) * gg:seed / gg:crawl-covers (demo seed + Steam CDN cover art) - 24/7 self-updating scheduler (scripts/scheduler_loop.php, lockfile-protected) - Tailwind v4 dark/light theme, Alpine.js, Chart.js
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
<?= $this->extend('layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<div class="text-xs text-muted mb-4 flex items-center gap-1.5">
|
||||
<a href="/news" class="hover:text-accent">News</a>
|
||||
<span>›</span>
|
||||
<span class="text-zinc-400">Bundles</span>
|
||||
</div>
|
||||
|
||||
<!-- bundle header -->
|
||||
<div class="bg-panel border border-line rounded-2xl p-6 mb-6">
|
||||
<div class="flex flex-col lg:flex-row lg:items-center gap-5">
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="kind-tag kind-keyshop mb-2 inline-block">Bundle</span>
|
||||
<h1 class="text-2xl font-extrabold text-white tracking-tight leading-tight"><?= esc($bundle['title']) ?></h1>
|
||||
<p class="text-sm text-muted mt-2 leading-relaxed max-w-2xl"><?= esc($bundle['desc']) ?></p>
|
||||
<div class="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted">
|
||||
<span><span class="text-zinc-300 font-semibold"><?= (int) $bundle['game_count'] ?></span> games</span>
|
||||
<span>Regular value <span class="text-zinc-300 line-through"><?= money((float) $bundle['regular']) ?></span></span>
|
||||
<span>You save <span class="text-accent font-bold">-<?= (int) round((1 - (float) $bundle['price'] / (float) $bundle['regular']) * 100) ?>%</span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:w-[280px] shrink-0 bg-card border border-line rounded-xl p-4">
|
||||
<div class="text-[11px] font-bold uppercase tracking-wider text-muted">Bundle price</div>
|
||||
<div class="mt-2 flex items-baseline gap-2">
|
||||
<span class="text-3xl font-extrabold text-accent"><?= money((float) $bundle['price']) ?></span>
|
||||
<span class="text-xs text-muted line-through"><?= money((float) $bundle['regular']) ?></span>
|
||||
</div>
|
||||
<?php $bStore = $stores[$bundle['store']] ?? null; ?>
|
||||
<div class="mt-2 flex items-center gap-1.5 text-xs text-muted">
|
||||
<?php if ($bStore): ?><?= view('partials/store_badge', ['store' => $bStore]) ?><?php endif; ?>
|
||||
<span><?= esc($bStore['name'] ?? '') ?></span>
|
||||
</div>
|
||||
<a href="https://www.google.com/search?q=<?= rawurlencode('buy ' . $bundle['title'] . ' bundle') ?>" target="_blank" rel="nofollow noopener"
|
||||
class="mt-4 block text-center bg-accent text-accent-ink font-extrabold text-sm py-3 rounded-lg hover:bg-accent/90 transition-colors">
|
||||
Get the bundle →
|
||||
</a>
|
||||
<?php if ($bundle['expires'] instanceof MongoDB\BSON\UTCDateTime): ?>
|
||||
<div class="mt-2 text-center text-[11px] text-amber-400/90">
|
||||
ends in <?= max(1, (int) floor(($bundle['expires']->toDateTime()->getTimestamp() - time()) / 86400)) ?> days
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- games in bundle -->
|
||||
<h2 class="text-sm font-bold text-zinc-200 uppercase tracking-wider mb-3">Games in this bundle</h2>
|
||||
<div class="grid sm:grid-cols-2 gap-2.5 mb-8">
|
||||
<?php foreach ($games as $g): ?>
|
||||
<div class="flex items-center gap-3 bg-card border border-line rounded-xl p-2.5 hover:border-accent/40 transition-colors group">
|
||||
<a href="/game/<?= $g['slug'] ?>" class="shrink-0 rounded-md overflow-hidden ring-1 ring-line">
|
||||
<img src="<?= esc($g['cover']['file']) ?>" alt="" class="w-[104px] h-[49px] object-cover" loading="lazy">
|
||||
</a>
|
||||
<div class="min-w-0 flex-1">
|
||||
<a href="/game/<?= $g['slug'] ?>" class="block text-[13px] font-semibold text-zinc-100 truncate group-hover:text-accent"><?= esc($g['title']) ?></a>
|
||||
<div class="text-[11px] text-muted mt-0.5">
|
||||
<span class="score-chip mr-1">MC <?= (int) $g['score'] ?></span>
|
||||
<span><?= money($g['base_price']) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?= $this->endSection() ?>
|
||||
Reference in New Issue
Block a user