Files
ringularity/index.php
2026-03-10 14:26:44 -04:00

240 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
header("Content-Type: text/html; charset=UTF-8");
header("X-Content-Type-Options: nosniff");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Permissions-Policy: geolocation=(), microphone=(), camera=()");
header(
"Content-Security-Policy: default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors *",
);
if (function_exists("header_remove")) {
header_remove("X-Frame-Options");
}
function normalizeHost(string $value): ?string
{
$value = trim(strtolower($value));
if ($value === "") {
return null;
}
if (preg_match("#^https?://#", $value) === 1) {
$parsedHost = parse_url($value, PHP_URL_HOST);
if (!is_string($parsedHost) || $parsedHost === "") {
return null;
}
$value = strtolower($parsedHost);
}
$value = explode("/", $value, 2)[0];
if (
preg_match(
"/\A(?=.{1,253}\z)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}\z/",
$value,
) !== 1
) {
return null;
}
return $value;
}
$rawSites = file(
__DIR__ . "/sites.txt",
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES,
);
if ($rawSites === false) {
http_response_code(500);
echo ";_;";
exit();
}
$sites = [];
foreach ($rawSites as $rawSite) {
$normalized = normalizeHost($rawSite);
if ($normalized !== null) {
$sites[] = $normalized;
}
}
$sites = array_values(array_unique($sites));
if (count($sites) < 2) {
http_response_code(500);
echo "did't find at least two sites to ring among";
exit();
}
$current = normalizeHost((string) ($_GET["site"] ?? ""));
if ($current === null) {
http_response_code(400);
echo "genuinely what are we doing here";
exit();
}
$index = array_search($current, $sites, true);
if ($index === false) {
http_response_code(404);
echo "This site isn't actually part of the ringularity ;-;";
exit();
}
$total = count($sites);
$prev = $sites[($index - 1 + $total) % $total];
$next = $sites[($index + 1) % $total];
?>
<div id="ring" role="navigation" aria-label="Webring navigation">
<a href="https://<?= htmlspecialchars(
$prev,
ENT_QUOTES | ENT_SUBSTITUTE,
"UTF-8",
) ?>" target="_top" rel="noopener noreferrer">&larr; PREV</a>
<span aria-hidden="true" class="specialtxt">The Ringularity</span>
<a href="https://<?= htmlspecialchars(
$next,
ENT_QUOTES | ENT_SUBSTITUTE,
"UTF-8",
) ?>" target="_top" rel="noopener noreferrer">NEXT &rarr;</a>
</div>
<style>
:root {
--bg-1: #1d2021;
--bg0: #282828;
--bg1: #3c3836;
--bg2: #504945;
--bg3: #665c54;
--bg4: #7c6f64;
--gray0: #928374;
--gray1: #a89984;
--fg0: #fbf1c7;
--fg1: #ebdbb2;
--fg2: #d5c4a1;
--fg3: #bdae93;
--red0: #cc241d;
--red1: #fb4934;
--green0: #98971a;
--green1: #b8bb26;
--yellow0: #d79921;
--yellow1: #fabd2f;
--blue0: #458588;
--blue1: #83a598;
--purple0: #b16286;
--purple1: #d3869b;
--aqua0: #689d6a;
--aqua1: #8ec07c;
--orange0: #d65d0e;
--orange1: #fe8019;
}
#ring {
border-radius: var(--brad);
background-color: var(--bg2);
color: var(--blue1);
transition: scale 0.2s linear;
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: nowrap;
height: 1em;
padding: 1em;
align-items: center;
}
#ring:hover a {
transition: transform 1.3s ease-in-out;
transform: scaleX(4) scaleY(1.5);
animation: wheee 0.2s linear infinite;
animation-delay: 1.3s;
}
#ring:hover .specialtxt {
font-weight: bold;
text-transform: uppercase;
position: relative;
animation: bob 1.8s infinite ease-in-out;
background: linear-gradient(
90deg,
var(--red1),
var(--orange1),
var(--yellow1)
);
-webkit-background-clip: text;
color: transparent;
}
#ring:hover .specialtxt::before,
#ring:hover .specialtxt::after {
content: "The Ringularity";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
var(--red0),
var(--orange0),
var(--yellow0)
);
-webkit-background-clip: text;
color: transparent;
z-index: -1;
transform: scaleY(1);
opacity: 0.5;
animation: smear 1.8s infinite ease-in-out;
}
#ring:hover .specialtxt::after {
filter: blur(8px);
opacity: 0.8;
}
@keyframes bob {
0%,
100% {
transform: translateY(8px) scaleX(1.2) scaleY(0.8);
}
50% {
transform: translateY(-8px) scaleX(0.8) scaleY(1.2);
}
}
@keyframes smear {
0%,
100%,
50% {
transform: scaleY(1) translateY(0px);
opacity: 0.5;
}
25% {
transform: scaleY(1.5) translateY(2px);
opacity: 0.7;
}
75% {
transform: scaleY(1.5) translateY(-2px);
opacity: 0.7;
}
}
@keyframes wheee {
from {
transform: rotate(0deg) scaleX(4) scaleY(1.5);
}
to {
transform: rotate(360deg) scaleX(4) scaleY(1.5);
}
}
</style>