summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorilotterytea <me@ilotterytea.kz>2025-10-10 20:55:37 +0500
committerilotterytea <me@ilotterytea.kz>2025-10-10 20:55:37 +0500
commitb1a885ac229892bac528e6fea4e011a1b240867b (patch)
tree48152aa48c41defe7f850390ea1c99db2c725438
initial commit
-rw-r--r--.gitignore2
-rw-r--r--database.sql13
-rw-r--r--favicon.icobin0 -> 1150 bytes
-rw-r--r--index.php93
-rw-r--r--lib/time.php21
-rw-r--r--links.json22
-rw-r--r--projects.json46
-rw-r--r--rss.php49
-rw-r--r--static/img/bot.pngbin0 -> 6136 bytes
-rw-r--r--static/img/git.pngbin0 -> 302 bytes
-rwxr-xr-xstatic/img/letter.pngbin0 -> 641 bytes
-rwxr-xr-xstatic/img/pepe.pngbin0 -> 65268 bytes
-rw-r--r--static/img/pfp.pngbin0 -> 3280 bytes
-rw-r--r--static/img/radicle.pngbin0 -> 1082 bytes
-rw-r--r--static/img/rain.gifbin0 -> 92393 bytes
-rwxr-xr-xstatic/img/rss.pngbin0 -> 691 bytes
-rwxr-xr-xstatic/img/wiki.pngbin0 -> 593 bytes
-rw-r--r--static/projects/maxon/banner.pngbin0 -> 43859 bytes
-rw-r--r--static/projects/maxon/screenshots/1.pngbin0 -> 114418 bytes
-rw-r--r--static/projects/maxon/screenshots/2.pngbin0 -> 68548 bytes
-rw-r--r--static/projects/voxelphalia/banner.pngbin0 -> 42425 bytes
-rw-r--r--static/projects/voxelphalia/screenshots/1.pngbin0 -> 173964 bytes
-rw-r--r--static/projects/voxelphalia/screenshots/2.pngbin0 -> 141993 bytes
-rw-r--r--static/style.css174
-rw-r--r--status/index.php52
-rw-r--r--status/post.php84
26 files changed, 556 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..14ab828
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.db
+*.ini \ No newline at end of file
diff --git a/database.sql b/database.sql
new file mode 100644
index 0000000..ab284a5
--- /dev/null
+++ b/database.sql
@@ -0,0 +1,13 @@
+CREATE TABLE IF NOT EXISTS statuses (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ title TEXT NOT NULL,
+ contents TEXT,
+ posted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE IF NOT EXISTS comments (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ name TEXT,
+ contents TEXT NOT NULL,
+ posted_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+); \ No newline at end of file
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 0000000..0541c52
--- /dev/null
+++ b/favicon.ico
Binary files differ
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..6126901
--- /dev/null
+++ b/index.php
@@ -0,0 +1,93 @@
+<?php
+include_once $_SERVER['DOCUMENT_ROOT'] . '/lib/time.php';
+if (file_exists("{$_SERVER['DOCUMENT_ROOT']}/projects.json") && $contents = file_get_contents("{$_SERVER['DOCUMENT_ROOT']}/projects.json")) {
+ $projects = json_decode($contents, true);
+}
+if (file_exists("{$_SERVER['DOCUMENT_ROOT']}/links.json") && $contents = file_get_contents("{$_SERVER['DOCUMENT_ROOT']}/links.json")) {
+ $links = json_decode($contents, true);
+}
+$db = new PDO("sqlite:{$_SERVER['DOCUMENT_ROOT']}/database.db");
+$stmt = $db->query("SELECT id, title, posted_at FROM statuses ORDER BY posted_at DESC LIMIT 1");
+$last_status = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
+?>
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>ilotterytea</title>
+ <meta name="description" content="my personal website.">
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+ <link rel="stylesheet" href="/static/style.css">
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
+ <meta name="robots" content="nofollow">
+</head>
+
+<body>
+ <main>
+ <div class="rain">
+ <p><img src="/static/img/pepe.png" alt="FeelsBadMan ☔ " width="18" height="18"> I'm just a memer</p>
+ </div>
+ <?php if (isset($projects)): ?>
+ <section class="projects">
+ <?php foreach ($projects as $p): ?>
+ <div class="project">
+ <div class="icon-wrapper">
+ <img src="<?= $p['banner'] ?? '' ?>" alt="">
+ </div>
+ <div class="summary">
+ <div class="title">
+ <h2><?= $p['title'] ?? 'No title.' ?> <span class="year"><?= $p['year'] ?></span></h2>
+ <?php if (isset($p['links'])): ?>
+ <div class="links">
+ <?php foreach ($p['links'] as $l): ?>
+ <a href="<?= $l['url'] ?>" class="button <?= $l['style'] ?? '' ?>"><?= $l['name'] ?></a>
+ <?php endforeach; ?>
+ </div>
+ <?php endif; ?>
+ </div>
+ <p><?= $p['description'] ?? '<i>No description</i>' ?></p>
+ <?php if (isset($p['screenshots'])): ?>
+ <div class="screenshots">
+ <?php foreach ($p['screenshots'] as $s): ?>
+ <a href="<?= $s ?>" target="_BLANK"><img src="<?= $s ?>" alt="Screenshot"></a>
+ <?php endforeach; ?>
+ </div>
+ <?php endif; ?>
+ </div>
+ </div>
+ <?php endforeach; ?>
+ </section>
+ <?php endif; ?>
+ <?php if (isset($last_status)): ?>
+ <div class="status">
+ <p>Last status posted <?= format_timestamp(time() - strtotime($last_status['posted_at'])) ?> ago: <a
+ href="/status/?id=<?= $last_status['id'] ?>"><?= $last_status['title'] ?? 'No title.' ?></a></p>
+ <p style="font-size:10px;"><a href="/status/">[more...]</a> <a href="/rss.php"><img
+ src="/static/img/rss.png" alt="[rss]"></a></p>
+ </div>
+ <?php endif; ?>
+ <?php if (isset($links)): ?>
+ <div class="main-links">
+ <?php foreach ($links as $l): ?>
+ <a href="<?= $l['url'] ?>"><img src="/static/img/<?= $l['icon'] ?>.png" alt=""><?= $l['title'] ?></a>
+ <?php endforeach; ?>
+ </div>
+ <?php endif; ?>
+ </main>
+</body>
+
+<script>
+ const links = document.querySelector(".main-links");
+ if (links) {
+ const link = document.createElement("a");
+ link.href = [109, 97, 105, 108, 116, 111, 58, 105, 108, 116, 115, 117, 64, 97, 108, 114, 105, 103, 104, 116, 46, 112, 97, 114, 116, 121].map(x => String.fromCharCode(x)).join('');
+ const img = document.createElement("img");
+ img.src = "/static/img/letter.png";
+ img.alt = "";
+ link.appendChild(img);
+ link.innerHTML += atob(["bWFpb", "CB", "tZSE="].join(''));
+ links.appendChild(link);
+ }
+</script>
+
+</html> \ No newline at end of file
diff --git a/lib/time.php b/lib/time.php
new file mode 100644
index 0000000..dc8b54f
--- /dev/null
+++ b/lib/time.php
@@ -0,0 +1,21 @@
+<?php
+function format_timestamp(int $timestamp)
+{
+ $days = (int) floor($timestamp / (60.0 * 60.0 * 24.0));
+ $years = (int) floor($days / 365);
+ $hours = (int) floor(round($timestamp / (60 * 60)) % 24);
+ $minutes = (int) floor(round($timestamp % (60 * 60)) / 60);
+ $seconds = (int) floor($timestamp % 60);
+
+ if ($years == 0 && $days == 0 && $hours == 0 && $minutes == 0) {
+ return "$seconds second" . ($seconds > 1 ? "s" : "");
+ } else if ($years == 0 && $days == 0 && $hours == 0) {
+ return "$minutes minute" . ($minutes > 1 ? "s" : "");
+ } else if ($years == 0 && $days == 0) {
+ return "$hours hour" . ($hours > 1 ? "s" : "");
+ } else if ($years == 0) {
+ return "$days day" . ($days > 1 ? "s" : "");
+ } else {
+ return "$years year" . ($years > 1 ? "s" : "");
+ }
+} \ No newline at end of file
diff --git a/links.json b/links.json
new file mode 100644
index 0000000..033c4e6
--- /dev/null
+++ b/links.json
@@ -0,0 +1,22 @@
+[
+ {
+ "title": "wiki",
+ "icon": "wiki",
+ "url": "https://wiki.alright.party"
+ },
+ {
+ "title": "@teabot",
+ "icon": "bot",
+ "url": "https://bot.alright.party"
+ },
+ {
+ "title": "radicle",
+ "icon": "radicle",
+ "url": "https://app.radicle.xyz/nodes/seed.ilt.su"
+ },
+ {
+ "title": "git",
+ "icon": "git",
+ "url": "https://git.ilt.su"
+ }
+] \ No newline at end of file
diff --git a/projects.json b/projects.json
new file mode 100644
index 0000000..15491ff
--- /dev/null
+++ b/projects.json
@@ -0,0 +1,46 @@
+[
+ {
+ "title": "Maxon Petting Simulator",
+ "year": "2022",
+ "description": "A clicker game about a cute kitty whose cheeks must always be squished.",
+ "banner": "/static/projects/maxon/banner.png",
+ "links": [
+ {
+ "url": "https://ilotterytea.itch.io/maxon",
+ "name": "Download",
+ "style": "green"
+ },
+ {
+ "url": "https://git.ilt.su/maxon.git",
+ "name": "Source code",
+ "style": "gray"
+ }
+ ],
+ "screenshots": [
+ "/static/projects/maxon/screenshots/1.png",
+ "/static/projects/maxon/screenshots/2.png"
+ ]
+ },
+ {
+ "title": "Voxelphalia",
+ "year": "2025",
+ "description": "Another voxel-based sandbox game where you can build whatever you want...",
+ "banner": "/static/projects/voxelphalia/banner.png",
+ "links": [
+ {
+ "url": "https://ilotterytea.itch.io/voxelphalia",
+ "name": "Download",
+ "style": "green"
+ },
+ {
+ "url": "https://git.ilt.su/voxelphalia.git",
+ "name": "Source code",
+ "style": "gray"
+ }
+ ],
+ "screenshots": [
+ "/static/projects/voxelphalia/screenshots/1.png",
+ "/static/projects/voxelphalia/screenshots/2.png"
+ ]
+ }
+] \ No newline at end of file
diff --git a/rss.php b/rss.php
new file mode 100644
index 0000000..5a7c78c
--- /dev/null
+++ b/rss.php
@@ -0,0 +1,49 @@
+<?php
+include_once $_SERVER['DOCUMENT_ROOT'] . '/lib/time.php';
+$db = new PDO("sqlite:{$_SERVER['DOCUMENT_ROOT']}/database.db");
+$stmt = $db->query("SELECT * FROM statuses ORDER BY posted_at DESC");
+$statuses = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+header('Content-Type: application/xml');
+
+echo "<?xml version='1.0' encoding='UTF-8'?>";
+echo "<rss version='2.0' xmlns:content='http://purl.org/rss/1.0/modules/content/'>";
+echo "<channel>";
+
+echo "<title>ilt.su</title>";
+echo "<link>https://ilt.su</link>";
+echo "<description>ilotterytea's racist schizo thoughts. read and learn.</description>";
+echo "<language>en-us</language>";
+
+
+if (!empty($statuses)) {
+ $date = new DateTime($statuses[0]['posted_at']);
+ echo "<lastBuildDate>";
+ echo $date->format('D, d M Y H:i:s O');
+ echo "</lastBuildDate>";
+}
+
+foreach ($statuses as $s) {
+ $date = new DateTime($s['posted_at']);
+
+ echo "<item>";
+ echo "<title>";
+ echo $s['title'] ?: '-NO TITLE-';
+ echo "</title>";
+
+ echo '<guid isPermaLink="true">';
+ echo "https://ilt.su/statuses/?id=" . $s['id'];
+ echo "</guid>";
+
+ echo "<pubDate>";
+ echo $date->format('D, d M Y H:i:s O');
+ echo "</pubDate>";
+
+ echo "<content:encoded><![CDATA[";
+ echo $s['contents'] ?: '-NO CONTENT-';
+ echo "]]></content:encoded>";
+ echo "</item>";
+}
+
+echo "</channel></rss>";
+?> \ No newline at end of file
diff --git a/static/img/bot.png b/static/img/bot.png
new file mode 100644
index 0000000..4a30b26
--- /dev/null
+++ b/static/img/bot.png
Binary files differ
diff --git a/static/img/git.png b/static/img/git.png
new file mode 100644
index 0000000..e1f8acf
--- /dev/null
+++ b/static/img/git.png
Binary files differ
diff --git a/static/img/letter.png b/static/img/letter.png
new file mode 100755
index 0000000..7348aed
--- /dev/null
+++ b/static/img/letter.png
Binary files differ
diff --git a/static/img/pepe.png b/static/img/pepe.png
new file mode 100755
index 0000000..d5bf04f
--- /dev/null
+++ b/static/img/pepe.png
Binary files differ
diff --git a/static/img/pfp.png b/static/img/pfp.png
new file mode 100644
index 0000000..e3cf428
--- /dev/null
+++ b/static/img/pfp.png
Binary files differ
diff --git a/static/img/radicle.png b/static/img/radicle.png
new file mode 100644
index 0000000..429f5c2
--- /dev/null
+++ b/static/img/radicle.png
Binary files differ
diff --git a/static/img/rain.gif b/static/img/rain.gif
new file mode 100644
index 0000000..ad0426b
--- /dev/null
+++ b/static/img/rain.gif
Binary files differ
diff --git a/static/img/rss.png b/static/img/rss.png
new file mode 100755
index 0000000..315c4f4
--- /dev/null
+++ b/static/img/rss.png
Binary files differ
diff --git a/static/img/wiki.png b/static/img/wiki.png
new file mode 100755
index 0000000..b0f4dd7
--- /dev/null
+++ b/static/img/wiki.png
Binary files differ
diff --git a/static/projects/maxon/banner.png b/static/projects/maxon/banner.png
new file mode 100644
index 0000000..baac0a6
--- /dev/null
+++ b/static/projects/maxon/banner.png
Binary files differ
diff --git a/static/projects/maxon/screenshots/1.png b/static/projects/maxon/screenshots/1.png
new file mode 100644
index 0000000..30823a2
--- /dev/null
+++ b/static/projects/maxon/screenshots/1.png
Binary files differ
diff --git a/static/projects/maxon/screenshots/2.png b/static/projects/maxon/screenshots/2.png
new file mode 100644
index 0000000..35f9bc6
--- /dev/null
+++ b/static/projects/maxon/screenshots/2.png
Binary files differ
diff --git a/static/projects/voxelphalia/banner.png b/static/projects/voxelphalia/banner.png
new file mode 100644
index 0000000..981ae05
--- /dev/null
+++ b/static/projects/voxelphalia/banner.png
Binary files differ
diff --git a/static/projects/voxelphalia/screenshots/1.png b/static/projects/voxelphalia/screenshots/1.png
new file mode 100644
index 0000000..54df9a8
--- /dev/null
+++ b/static/projects/voxelphalia/screenshots/1.png
Binary files differ
diff --git a/static/projects/voxelphalia/screenshots/2.png b/static/projects/voxelphalia/screenshots/2.png
new file mode 100644
index 0000000..8ea6616
--- /dev/null
+++ b/static/projects/voxelphalia/screenshots/2.png
Binary files differ
diff --git a/static/style.css b/static/style.css
new file mode 100644
index 0000000..74332eb
--- /dev/null
+++ b/static/style.css
@@ -0,0 +1,174 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ width: 100%;
+ min-height: 100vh;
+ display: flex;
+ justify-content: center;
+}
+
+main {
+ width: 50%;
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+ margin-top: 32px;
+}
+
+a {
+ color: black;
+}
+
+a.gray {
+ background: lightgray;
+}
+
+a.green {
+ background: lime;
+}
+
+a:hover {
+ color: white;
+ background: black;
+ text-decoration: line-through;
+}
+
+p img {
+ vertical-align: bottom;
+}
+
+.status {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.main-links {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+}
+
+.main-links img {
+ vertical-align: middle;
+}
+
+.rain {
+ width: 100%;
+ min-height: 10%;
+ background-image: url('/static/img/rain.gif');
+ background-repeat: repeat;
+
+ display: flex;
+ justify-content: end;
+ align-items: end;
+}
+
+.rain p {
+ padding: 0 32px;
+ font-family: cursive, serif;
+}
+
+.rain img {
+ vertical-align: bottom;
+}
+
+.projects {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.project {
+ padding-top: 16px;
+ display: flex;
+ flex-direction: row;
+ gap: 8px;
+}
+
+.project .icon-wrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.icon-wrapper img {
+ width: 256px;
+}
+
+.project .summary {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.summary .title {
+ display: flex;
+ flex-direction: row;
+ gap: 16px;
+}
+
+.title .year {
+ font-size: 10px;
+}
+
+.project .screenshots {
+ display: flex;
+ flex-direction: row;
+ gap: 8px;
+}
+
+.screenshots a:hover {
+ background: unset;
+ color: unset
+}
+
+.screenshots img {
+ vertical-align: bottom;
+ width: 128px;
+}
+
+.links {
+ display: flex;
+ flex-direction: row;
+ gap: 8px;
+ align-items: center;
+}
+
+.projects>.project {
+ border-top: 1px solid black;
+}
+
+.projects>.project:first-child {
+ border-top: none;
+}
+
+@media only screen and (max-width: 1400px) {
+ main {
+ width: 70%;
+ }
+}
+
+@media only screen and (max-width: 1200px) {
+ main {
+ width: 80%;
+ }
+}
+
+@media only screen and (max-width: 1000px) {
+ main {
+ width: unset;
+ }
+
+ .project {
+ flex-direction: column;
+ }
+
+ .screenshots {
+ justify-content: center;
+ }
+} \ No newline at end of file
diff --git a/status/index.php b/status/index.php
new file mode 100644
index 0000000..13d5405
--- /dev/null
+++ b/status/index.php
@@ -0,0 +1,52 @@
+<?php
+include_once $_SERVER['DOCUMENT_ROOT'] . '/lib/time.php';
+$db = new PDO("sqlite:{$_SERVER['DOCUMENT_ROOT']}/database.db");
+
+if (isset($_GET['id']) && !empty(trim($_GET['id']))) {
+ $stmt = $db->prepare('SELECT * FROM statuses WHERE id = ?');
+ $stmt->execute([$_GET['id']]);
+
+ $status = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
+} else {
+ $stmt = $db->query('SELECT id, title, posted_at FROM statuses ORDER BY posted_at DESC');
+ $statuses = $stmt->fetchAll(PDO::FETCH_ASSOC);
+}
+?>
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>statuses - ilt.su</title>
+ <meta name="description" content="my statuses.">
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+ <link rel="stylesheet" href="/static/style.css">
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
+ <meta name="robots" content="noindex, nofollow">
+</head>
+
+<body>
+ <main>
+ <p><a href="/">ilt.su</a> - <a href="/status/">statuses</a></p>
+ <?php if (isset($status)): ?>
+ <h1><?= $status['title'] ?? '<i>No title.</i>' ?></h1>
+ <div>
+ <?= $status['contents'] ?? '<i>No contents.</i>' ?>
+ </div>
+ <p><i>Posted <?= format_timestamp(time() - strtotime($status['posted_at'])) ?> ago</i></p>
+ <?php endif; ?>
+
+ <?php if (isset($statuses)): ?>
+ <h1>Statuses</h1>
+ <ul>
+ <?php foreach ($statuses as $s): ?>
+ <li><a href="/status/?id=<?= $s['id'] ?>"><?= $s['title'] ?></a>
+ <i><?= format_timestamp(time() - strtotime($s['posted_at'])) ?>
+ ago</i>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+ <?php endif; ?>
+ </main>
+</body>
+
+</html> \ No newline at end of file
diff --git a/status/post.php b/status/post.php
new file mode 100644
index 0000000..064d86f
--- /dev/null
+++ b/status/post.php
@@ -0,0 +1,84 @@
+<?php
+include_once $_SERVER['DOCUMENT_ROOT'] . '/lib/time.php';
+
+function str_safe(string $s, int|null $max_length, bool $remove_new_lines = true): string
+{
+ $output = $s;
+
+ if ($remove_new_lines) {
+ $output = str_replace(PHP_EOL, "", $output);
+ }
+
+ $output = htmlspecialchars($output);
+ $output = strip_tags($output);
+
+ if ($max_length) {
+ $output = substr($output, 0, $max_length);
+ }
+
+ $output = trim($output);
+
+ return $output;
+}
+
+$db = new PDO("sqlite:{$_SERVER['DOCUMENT_ROOT']}/database.db");
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $title = str_safe($_POST['title'], 500, true) ?: null;
+ $contents = str_safe($_POST['contents'], null, false) ?: null;
+
+ $db->prepare('INSERT INTO statuses(title, contents) VALUES (?, ?)')
+ ->execute([$title, $contents]);
+
+ $id = $db->lastInsertId();
+
+ header("Location: /status/?id=$id");
+ exit;
+}
+
+if (isset($_GET['id']) && !empty(trim($_GET['id']))) {
+ $stmt = $db->prepare('SELECT * FROM statuses WHERE id = ?');
+ $stmt->execute([$_GET['id']]);
+
+ $status = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
+} else {
+ $stmt = $db->query('SELECT id, title, posted_at FROM statuses ORDER BY posted_at DESC');
+ $statuses = $stmt->fetchAll(PDO::FETCH_ASSOC);
+}
+?>
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>new status - ilt.su</title>
+ <meta name="description" content="my statuses.">
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+ <link rel="stylesheet" href="/static/style.css">
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
+ <meta name="robots" content="noindex, nofollow">
+</head>
+
+<body>
+ <main>
+ <p><a href="/">ilt.su</a> - <a href="/status/">statuses</a></p>
+ <h1>post a new status</h1>
+ <form action="/status/post.php" method="post">
+ <table>
+ <tr>
+ <th>title:</th>
+ <td><input type="text" name="title" required></td>
+ </tr>
+ <tr>
+ <th>contents:</th>
+ <td><textarea name="contents" placeholder="Can be empty"></textarea></td>
+ </tr>
+ <tr>
+ <th></th>
+ <td><button type="submit">post</button></td>
+ </tr>
+ </table>
+ </form>
+ </main>
+</body>
+
+</html> \ No newline at end of file