40247-vm/index.php
2026-06-12 09:15:36 +00:00

290 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
@date_default_timezone_set('UTC');
$projectName = $_SERVER['PROJECT_NAME'] ?? 'Laegna & Spireason Trivia: LandScaper';
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'A structural console and document map for the Laegna & Spireason main webpage.';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
$now = date('Y-m-d H:i:s');
require_once __DIR__ . "/includes/curated_data.php";
function link_filename(array $link): string
{
$path = parse_url((string)($link['href'] ?? ''), PHP_URL_PATH);
return $path ? rawurldecode(basename($path)) : '';
}
function link_host(array $link): string
{
return strtolower((string)(parse_url((string)($link['href'] ?? ''), PHP_URL_HOST) ?: ''));
}
function link_category(array $link): string
{
$kind = strtolower((string)($link['kind'] ?? ''));
$href = strtolower((string)($link['href'] ?? ''));
$name = strtolower((string)($link['name'] ?? ''));
$host = link_host($link);
$path = strtolower((string)(parse_url($href, PHP_URL_PATH) ?: ''));
if ($kind === 'pdf' || str_ends_with($path, '.pdf')) return 'pdf';
if (str_contains($name . ' ' . $href, 'bot') || str_contains($host, 'perplexity.ai')) return 'bot';
if ($kind === 'dataset' || str_ends_with($path, '.json')) return 'dataset';
if ($kind === 'source' || str_ends_with($path, '.py')) return 'source';
if (str_contains($name, 'calculator') || str_contains($name, 'octave') || str_contains($name, 'frequency') || str_contains($name, 'counter')) return 'tool';
if ($kind === 'github' || str_contains($host, 'github')) return 'github';
if (str_contains($href, 'apples.html') || str_contains($kind, 'app')) return 'applet';
if ($kind === 'archive' || str_ends_with($path, '.zip')) return 'archive';
if ($kind === 'presentation' || str_contains($host, 'prezi')) return 'presentation';
if ($kind === 'media' || str_contains($host, 'youtube') || str_contains($host, 'notion')) return 'media';
if ($host !== '' && $host !== 'spireason.neocities.org') return 'external';
return $kind !== '' ? preg_replace('/[^a-z0-9-]+/', '-', $kind) : 'onsite';
}
function link_category_label(string $category): string
{
return [
'pdf' => 'PDF text',
'applet' => 'Applet',
'bot' => 'External bot/system',
'tool' => 'Tool',
'github' => 'Repository',
'archive' => 'Archive',
'presentation' => 'Presentation',
'media' => 'Media',
'dataset' => 'Dataset',
'source' => 'Source file',
'external' => 'External system',
'onsite' => 'On-site branch',
'branch' => 'Branch',
'research' => 'Research system',
'manual' => 'Manual',
'table' => 'Table',
][$category] ?? ucfirst(str_replace('-', ' ', $category));
}
$pdfLinks = array_values(array_filter($links, fn($link) => ($link['kind'] ?? '') === 'pdf'));
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= htmlspecialchars($projectName) ?></title>
<?php if ($projectDescription): ?>
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>">
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>">
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>">
<?php endif; ?>
<?php if ($projectImageUrl): ?>
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>">
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>">
<?php endif; ?>
<meta name="theme-color" content="#111111">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?= time() ?>">
</head>
<body>
<a class="skip-link" href="#document">Skip to document</a>
<header class="topbar" aria-label="Primary navigation">
<nav class="container-fluid d-flex align-items-center justify-content-between gap-3">
<a class="brand" href="#console" aria-label="Scroll to console"><span class="brand-mark">LS</span><span>LandScaper</span></a>
<div class="top-links" aria-label="Page areas">
<a href="#console">Console</a>
<a href="#natura">✦ Foundational Texts</a>
<a href="#bigbang">⟲ Continuing Studies</a>
<a href="#pdf-library">PDF Library</a>
<a href="curated-links.php">Curated Links</a>
<a href="#live-audit">Live Links</a>
</div>
<button class="theme-toggle" type="button" data-theme-toggle aria-pressed="false">Day</button>
</nav>
</header>
<main id="console">
<section class="console-screen" aria-labelledby="main-title">
<div class="fixed-cluster cluster-left" aria-label="Console fixed branch buttons">
<a href="https://laegna.notaku.site/" target="_blank" rel="noopener">Study</a>
<a href="https://spireason.neocities.org/repos.html" target="_blank" rel="noopener">Repos</a>
<a href="https://huggingface.co/datasets/tvaeli/LaegnaSpi/resolve/main/Spireason.zip" target="_blank" rel="noopener">PDFs.zip</a>
</div>
<div class="fixed-cluster cluster-right" aria-label="Console fixed discovery buttons">
<a href="https://spireason.neocities.org/Additional/bots.html" target="_blank" rel="noopener">Chat</a>
<a href="https://www.perplexity.ai/spaces/laegna-spireason-and-related-m-dLTaZz8CSd2FUCjIiYQARA" target="_blank" rel="noopener">Find</a>
<a href="https://spireason.neocities.org/apples.html" target="_blank" rel="noopener">Apps</a>
</div>
<div class="console-panel">
<p class="eyebrow">Structural clone · main webpage only</p>
<h1 id="main-title">Laegna &amp; Spireason Trivia: LandScaper.</h1>
<p class="lead">A restrained console layer folds into a document map. Each icon is treated as an owner: its source anchor owns the visible links until the next large icon, with a bonus shadow-books icon for the prelude.</p>
<div class="title-icons" aria-label="Major page parts">
<?php foreach ($sections as $section): ?>
<a href="#<?= htmlspecialchars($section['id']) ?>" data-section-jump data-title="<?= htmlspecialchars($section['title']) ?>" aria-label="<?= htmlspecialchars($section['title']) ?>"><?= htmlspecialchars($section['icon']) ?></a>
<?php endforeach; ?>
</div>
<div class="console-actions">
<a class="btn btn-dark btn-sm" href="#document">Enter Document</a>
<a class="btn btn-outline-dark btn-sm" href="curated-links.php">Curated links page</a>
<button class="btn btn-outline-dark btn-sm" type="button" data-open-map>Open structural map</button>
</div>
</div>
<a href="#document" class="scroll-cue" aria-label="Scroll down into document">↓</a>
</section>
<nav class="bottom-nav" data-bottom-nav aria-label="Section icon navigation">
<a class="chapter-link left" href="#natura">✦ <span>Foundational</span></a>
<div class="bottom-icons">
<?php foreach ($sections as $section): ?>
<a href="#<?= htmlspecialchars($section['id']) ?>" data-bs-toggle="tooltip" data-bs-title="<?= htmlspecialchars($section['title']) ?>"><?= htmlspecialchars($section['icon']) ?></a>
<?php endforeach; ?>
</div>
<a class="chapter-link right" href="#bigbang"><span>Continuing</span> ⟲</a>
</nav>
<section id="document" class="document-shell" aria-labelledby="document-title">
<div class="container-fluid px-3 px-lg-4">
<div class="doc-heading">
<p class="eyebrow">Document layer</p>
<h2 id="document-title">Console-to-document structural index</h2>
<p>This slice now follows the live ownership rule: <?= htmlspecialchars($sourceOwnershipNote) ?> It exposes <?= count($pdfLinks) ?> verified root PDFs, curated links, and a filtered visible-link scanner for the current reference page.</p>
</div>
<div class="toolbar" role="region" aria-label="View tools">
<label class="search-box"><span>Filter</span><input type="search" id="linkFilter" placeholder="Search links, PDFs, tools…"></label>
<div class="filter-status" id="filterStatus" role="status">Filter keeps card heights stable; non-matches dim instead of disappearing.</div>
<div class="mode-switch" aria-label="Display mode">
<button class="active" type="button" data-mode="blocks">Block mode</button>
<button type="button" data-mode="files">File mode</button>
<button type="button" data-mode="text">Text mode</button>
</div>
</div>
<div class="chapter-grid">
<article id="foundational" class="chapter-card">
<div class="chapter-kicker">✦ Foundational Texts</div>
<h3>Start: infinity, material magic, karma, chakra, meditation.</h3>
<p>PDF documents are treated as central files: they keep their exact names, direct links, and short summaries.</p>
</article>
<article id="continuing" class="chapter-card">
<div class="chapter-kicker">⟲ Continuing Studies</div>
<h3>Continuation: apps, repositories, datasets, generated studies.</h3>
<p>Main branches remain first-class paths; child links are represented as branch/file entities rather than hidden prose.</p>
</article>
</div>
<section id="pdf-library" class="pdf-library" data-pdf-library data-pdf-mode="intro" aria-labelledby="pdf-library-title">
<div class="pdf-library-head">
<div>
<p class="eyebrow">Verified PDF library</p>
<h2 id="pdf-library-title">25 root-folder PDFs, exact filenames preserved</h2>
<p>These are direct <code>spireason.neocities.org/&lt;filename&gt;.pdf</code> URLs. Mojibake dash text is normalized to the real en dash (<code></code>), while filenames stay visible in a quieter line.</p>
</div>
<div class="pdf-mode-switch" aria-label="PDF display mode">
<button type="button" data-pdf-view="icons">Icon-only</button>
<button type="button" data-pdf-view="title">Icon + title</button>
<button type="button" data-pdf-view="summary">Title + summary</button>
<button class="active" type="button" data-pdf-view="intro">Intro blocks</button>
</div>
</div>
<div class="pdf-grid" aria-label="Verified PDF files">
<?php foreach ($pdfLinks as $pdf): ?>
<?php $filename = link_filename($pdf); ?>
<a class="pdf-card link-kind-pdf" href="<?= htmlspecialchars($pdf['href']) ?>" target="_blank" rel="noopener" data-pdf-card data-search="<?= htmlspecialchars(strtolower($pdf['name'].' '.$pdf['summary'].' '.$filename)) ?>">
<span class="pdf-symbol" aria-hidden="true"><?= htmlspecialchars($pdf['icon']) ?></span>
<span class="pdf-title"><?= htmlspecialchars($pdf['name']) ?></span>
<span class="pdf-summary"><?= htmlspecialchars($pdf['summary']) ?></span>
<span class="pdf-filename"><?= htmlspecialchars($filename) ?></span>
<span class="pdf-open">Open direct PDF ↗</span>
</a>
<?php endforeach; ?>
</div>
</section>
<div class="sections-grid" data-section-grid>
<?php foreach ($sections as $section): ?>
<?php $sectionLinks = array_values(array_filter($links, fn($link) => $link['section'] === $section['id'])); ?>
<?php $previewLinks = array_slice($sectionLinks, 0, 4); $remainingLinks = max(0, count($sectionLinks) - count($previewLinks)); ?>
<article class="section-card" id="<?= htmlspecialchars($section['id']) ?>" data-section-card data-title="<?= htmlspecialchars(strtolower($section['title'])) ?>" data-chapter="<?= htmlspecialchars($section['chapter']) ?>">
<div class="section-head">
<div class="section-icon" aria-hidden="true"><?= htmlspecialchars($section['icon']) ?></div>
<div>
<div class="section-chapter"><?= htmlspecialchars($section['chapter']) ?></div>
<h3><?= htmlspecialchars($section['title']) ?></h3>
<div class="section-meta"><span>#<?= htmlspecialchars($section['id']) ?></span><span><?= (int)($section['source_count'] ?? count($sectionLinks)) ?> source links → <?= htmlspecialchars((string)($section['source_until'] ?? 'next')) ?></span></div>
</div>
</div>
<p><?= htmlspecialchars($section['summary']) ?></p>
<div class="file-list">
<?php if ($sectionLinks): foreach ($previewLinks as $link): ?>
<?php $category = link_category($link); $filename = link_filename($link); ?>
<a class="file-row link-kind-<?= htmlspecialchars($category) ?>" href="<?= htmlspecialchars($link['href']) ?>" target="_blank" rel="noopener" data-link-row data-kind="<?= htmlspecialchars($category) ?>" data-search="<?= htmlspecialchars(strtolower($link['name'].' '.$link['summary'].' '.$link['kind'].' '.$category.' '.$filename.' '.$section['title'])) ?>">
<span class="file-icon"><?= htmlspecialchars($link['icon']) ?></span>
<span class="file-copy">
<strong><?= htmlspecialchars($link['name']) ?></strong>
<small><span class="kind-pill kind-<?= htmlspecialchars($category) ?>"><?= htmlspecialchars(link_category_label($category)) ?></span><?php if ($filename): ?> <span class="filename"><?= htmlspecialchars($filename) ?></span><?php endif; ?> · <?= htmlspecialchars($link['summary']) ?></small>
</span>
<span class="file-arrow">↗</span>
</a>
<?php endforeach; ?>
<?php if ($remainingLinks > 0): ?>
<a class="file-row more-row" href="curated-links.php#<?= htmlspecialchars($section['id']) ?>" data-link-row data-kind="more" data-search="<?= htmlspecialchars(strtolower($section['title'] . ' curated full reference all resources')) ?>">
<span class="file-icon">↳</span>
<span class="file-copy"><strong>View all <?= (int)count($sectionLinks) ?> curated entries</strong><small>Full category browse lives on the dedicated curated links page.</small></span>
<span class="file-arrow">→</span>
</a>
<?php endif; ?>
<?php else: ?>
<div class="empty-state">No curated links yet. Use the live scanner below for current source links.</div>
<?php endif; ?>
</div>
</article>
<?php endforeach; ?>
</div>
<section id="live-audit" class="audit-panel" aria-labelledby="audit-title">
<div>
<p class="eyebrow">Automated scanner</p>
<h2 id="audit-title">New Links scanner</h2>
<p>Checks the live reference page, lists visible, human-facing anchors only, suppresses asset/script/noise and deliberately removed URLs, then flags links not represented in this curated structure.</p>
</div>
<button class="btn btn-dark btn-sm" type="button" id="scanLinks">Scan source links</button>
<div class="audit-status" id="auditStatus" role="status">Idle. Click scan to compare with the live page.</div>
<div class="scanner-policy">Policy: visible anchors only · no JavaScript/mail/asset links · known removals suppressed · unknown external hosts marked for review.</div>
<div class="audit-results" id="auditResults" data-known='<?= htmlspecialchars(json_encode(array_column($links, 'href'), JSON_UNESCAPED_SLASHES)) ?>'></div>
</section>
</div>
</section>
</main>
<div class="toast-wrap" aria-live="polite" aria-atomic="true"><div class="mini-toast" id="miniToast">Ready.</div></div>
<div class="modal fade" id="mapModal" tabindex="-1" aria-labelledby="mapModalTitle" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title fs-5" id="mapModalTitle">Structural map</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<ol class="map-list">
<?php foreach ($sections as $i => $section): ?>
<li><a href="#<?= htmlspecialchars($section['id']) ?>" data-map-target="<?= htmlspecialchars($section['id']) ?>" data-bs-dismiss="modal"><span><?= htmlspecialchars($section['icon']) ?></span><?= str_pad((string)($i + 1), 2, '0', STR_PAD_LEFT) ?> · <?= htmlspecialchars($section['title']) ?></a><small><?= htmlspecialchars($section['summary']) ?></small></li>
<?php endforeach; ?>
</ol>
</div>
</div>
</div>
</div>
<footer class="site-footer">
<span>Runtime: PHP <?= htmlspecialchars(PHP_VERSION) ?></span>
<span>Updated <?= htmlspecialchars($now) ?> UTC</span>
<a href="api/scan_links.php">Scanner API</a>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?= time() ?>" defer></script>
</body>
</html>