diff options
| author | sillylaird <sillyfanboy@gmail.com> | 2026-09-03 00:33:59 +0000 |
|---|---|---|
| committer | sillylaird <sillyfanboy@gmail.com> | 2026-09-03 00:33:59 +0000 |
| commit | 898b52edcb47bcb3e9d6106e74ca73e74ea01e70 (patch) | |
| tree | 85c6ee5ad58b860144551184d4cf86b560c62b91 /startpage/render_cards.php | |
| download | www-main.tar.gz www-main.zip | |
Diffstat (limited to '')
| -rw-r--r-- | startpage/render_cards.php | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/startpage/render_cards.php b/startpage/render_cards.php new file mode 100644 index 0000000..369a5fd --- /dev/null +++ b/startpage/render_cards.php @@ -0,0 +1,76 @@ +<?php +if (realpath(__FILE__) === realpath($_SERVER['SCRIPT_FILENAME'] ?? '')) { http_response_code(404); exit; } + +function startpage_valid_card_url(string $url): bool { + if ($url === '') return false; + if ($url[0] === '/') return !str_starts_with($url, '//') && !str_contains($url, "\0"); + $scheme = strtolower(parse_url($url, PHP_URL_SCHEME) ?? ''); + return in_array($scheme, ['http', 'https', 'gemini', 'gopher'], true) && filter_var($url, FILTER_VALIDATE_URL) !== false; +} + +function startpage_valid_card_asset(string $ref): bool { + if ($ref === '' || str_contains($ref, "\0")) return false; + if (startpage_valid_card_url($ref)) return true; + return !str_contains($ref, '..') && preg_match('/^[A-Za-z0-9][A-Za-z0-9._\/-]*$/', $ref); +} + +function startpage_card_data(): array { + $file = __DIR__ . '/cards.txt'; + $raw = is_file($file) ? file_get_contents($file) : ''; + $cards = []; + $cur = null; + foreach (explode("\n", str_replace("\r\n", "\n", (string)$raw)) as $line) { + $line = trim($line); + if ($line === '') continue; + if ($line[0] === '#') { + if ($cur !== null) $cards[] = $cur; + $parts = array_map('trim', explode('|', ltrim($line, '#'), 3)); + $title = $parts[0] ?? ''; + $image = $parts[1] ?? ''; + $alt = $parts[2] ?? 'Visual'; + if ($title === '' || !startpage_valid_card_asset($image)) { $cur = null; continue; } + $cur = ['title' => $title, 'image' => $image, 'alt' => $alt !== '' ? $alt : 'Visual', 'links' => []]; + continue; + } + if ($cur === null) continue; + $parts = array_map('trim', explode('|', $line, 2)); + $label = $parts[0] ?? ''; + $url = $parts[1] ?? ''; + if ($label !== '' && startpage_valid_card_url($url)) $cur['links'][] = ['label' => $label, 'url' => $url]; + } + if ($cur !== null) $cards[] = $cur; + $all = array_values(array_filter($cards, fn($card) => $card['links'] !== [])); + return $all; +} + +function startpage_seasonal_sports_image(string $image): string { + // Sports card logo follows the local season: Belleville Senators (AHL) + // October–April, Belleville Kodiaks (OSL Sr B lacrosse) May–September. + if ($image !== 'belleville.png') return $image; + $month = (int)date('n'); + return ($month >= 5 && $month <= 9) ? 'kodiaks.png' : 'belleville.png'; +} + +$allCardData = startpage_card_data(); +foreach ($allCardData as &$card) { + $card['image'] = startpage_seasonal_sports_image($card['image']); +} +unset($card); +?> +<?php foreach ($allCardData as $card): ?> + <article class="card" data-title="<?= htmlspecialchars($card['title'], ENT_QUOTES, 'UTF-8') ?>" data-labels="<?= htmlspecialchars(implode(' ', array_column($card['links'], 'label')), ENT_QUOTES, 'UTF-8') ?>"> + <div class="card-titlebar"> + <span class="card-dots" aria-hidden="true"><span></span><span></span><span></span></span> + <span class="card-title"><?= htmlspecialchars($card['title'], ENT_QUOTES, 'UTF-8') ?></span> + </div> + <div class="card-body"> + <div class="thumb"><img src="<?= htmlspecialchars($card['image'], ENT_QUOTES, 'UTF-8') ?>" alt="<?= htmlspecialchars($card['alt'], ENT_QUOTES, 'UTF-8') ?>" loading="lazy" decoding="async" /></div> + <div class="card-links"> +<?php foreach ($card['links'] as $link): ?> + <a href="<?= htmlspecialchars($link['url'], ENT_QUOTES, 'UTF-8') ?>" title="<?= htmlspecialchars($link['label'] . ' — ' . $link['url'], ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($link['label'], ENT_QUOTES, 'UTF-8') ?></a> +<?php endforeach; ?> + </div> + </div> + </article> + +<?php endforeach; ?> |
