summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/events.json9
-rw-r--r--data/events/noi.md11
-rw-r--r--data/events/nytc.md11
-rw-r--r--data/videos.json14
-rw-r--r--data/videos/eid2026.md1
-rw-r--r--data/videos/minds.md1
-rw-r--r--data/videos/paperverse.md5
-rw-r--r--data/videos/s3via.md5
-rw-r--r--data/videos/stringsoffreedom.md7
-rw-r--r--main.py18
-rw-r--r--pages.py38
-rw-r--r--templates/eventdetails.html38
-rw-r--r--templates/video.html26
-rw-r--r--www/about/index.html24
-rw-r--r--www/assets/.DS_Storebin6148 -> 6148 bytes
-rw-r--r--www/scripts/video.js12
-rw-r--r--www/style.css33
17 files changed, 212 insertions, 41 deletions
diff --git a/data/events.json b/data/events.json
index 0967ef4..a3b2a49 100644
--- a/data/events.json
+++ b/data/events.json
@@ -1 +1,8 @@
-{}
+{
+ "noi": {
+ "path": "/data/events/noi.md"
+ },
+ "nytc": {
+ "path": "/data/events/nytc.md"
+ }
+}
diff --git a/data/events/noi.md b/data/events/noi.md
index e69de29..43fdd75 100644
--- a/data/events/noi.md
+++ b/data/events/noi.md
@@ -0,0 +1,11 @@
+---
+title: "NOI 2026 (and 2025)"
+type: "Achievement"
+---
+
++-+-+-
+
+NOI 2026 (and 2025)
+{ .heading }
+
+-+-+-+
diff --git a/data/events/nytc.md b/data/events/nytc.md
index e69de29..9a7355d 100644
--- a/data/events/nytc.md
+++ b/data/events/nytc.md
@@ -0,0 +1,11 @@
+---
+title: "hello"
+type: "Achievement"
+---
+
++-+-+-
+
+National Youth Tech Championship 2025
+{ .heading }
+
+-+-+-+
diff --git a/data/videos.json b/data/videos.json
index 7940394..ca72096 100644
--- a/data/videos.json
+++ b/data/videos.json
@@ -1,22 +1,26 @@
{
"stringsoffreedom": {
- "path": "/assets/videos/stringsoffreedom.mp4",
+ "path": "https://www.youtube-nocookie.com/embed/Du6_puKRT8c?si=kMz_sr6cLV-PaA5W",
+ "download_path": "https://video.altafcreator.com/stringsoffreedom.mp4",
"content_path": "/data/videos/stringsoffreedom.md"
},
"minds": {
- "path": "/assets/videos/minds.mp4",
+ "path": "https://www.youtube-nocookie.com/embed/KCc-HRC3E48?si=9Pxr8jJgjO3UeMEB",
"content_path": "/data/videos/minds.md"
},
"paperverse": {
- "path": "/assets/videos/paperverse.mp4",
+ "path": "https://www.youtube-nocookie.com/embed/-b7x8COvdjw?si=CpPCw51Mc5Clp-cR",
+ "download_path": "https://video.altafcreator.com/paperverse.mp4",
"content_path": "/data/videos/paperverse.md"
},
"eid2026": {
- "path": "/assets/videos/eid2026.mp4",
+ "path": "https://www.youtube-nocookie.com/embed/_KDITFRkdgI?si=4THdUFDFwJ-30dqb",
+ "download_path": "https://video.altafcreator.com/eid2026.mp4",
"content_path": "/data/videos/eid2026.md"
},
"s3via": {
- "path": "/assets/videos/VIA.mp4",
+ "path": "https://www.youtube-nocookie.com/embed/s4rL2r-PAvE?si=BCD1hQHIyUefiteO",
+ "download_path": "https://video.altafcreator.com/VIA.mp4",
"content_path": "/data/videos/s3via.md"
}
}
diff --git a/data/videos/eid2026.md b/data/videos/eid2026.md
index 84324e7..39d2bd0 100644
--- a/data/videos/eid2026.md
+++ b/data/videos/eid2026.md
@@ -5,5 +5,4 @@ date: "24 March 2026"
default_copyright: false
license: "<i class=\"fa-brands fa-creative-commons\"></i><i class=\"fa-brands fa-creative-commons-by\"></i> CC-BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
-downloadable: true
---
diff --git a/data/videos/minds.md b/data/videos/minds.md
index 78cc911..bc161cd 100644
--- a/data/videos/minds.md
+++ b/data/videos/minds.md
@@ -3,5 +3,4 @@ title: "MINDS Charity Car Wash Promotional"
description: "Volunteer work with MINDS to promote their Charity Car Wash in 2025."
date: "October 2025"
default_copyright: true
-downloadable: false
---
diff --git a/data/videos/paperverse.md b/data/videos/paperverse.md
index 66806c3..00de361 100644
--- a/data/videos/paperverse.md
+++ b/data/videos/paperverse.md
@@ -2,6 +2,7 @@
title: "Paperverse Hub"
description: "Paperverse Hub, a videography competition entry."
date: "March 2026"
-default_copyright: true
-downloadable: false
+default_copyright: false
+license: "<i class=\"fa-brands fa-creative-commons\"></i><i class=\"fa-brands fa-creative-commons-by\"></i><i class=\"fa-brands fa-creative-commons-sa\"></i> CC-BY-SA 4.0"
+license_url: "https://creativecommons.org/licenses/by-sa/4.0/"
---
diff --git a/data/videos/s3via.md b/data/videos/s3via.md
index a24652c..5f16bc5 100644
--- a/data/videos/s3via.md
+++ b/data/videos/s3via.md
@@ -3,7 +3,6 @@ title: "Secondary 3 VIA Project"
description: "Secondary 3 Class VIA Project"
date: "July 2025"
default_copyright: false
-license: "<i class=\"fa-brands fa-creative-commons\"></i><i class=\"fa-brands fa-creative-commons-by\"></i> CC-BY 4.0"
-license_url: "https://creativecommons.org/licenses/by/4.0/"
-downloadable: true
+license: "<i class=\"fa-brands fa-creative-commons\"></i><i class=\"fa-brands fa-creative-commons-by\"></i><i class=\"fa-brands fa-creative-commons-sa\"></i> CC-BY-SA 4.0"
+license_url: "https://creativecommons.org/licenses/by-sa/4.0/"
---
diff --git a/data/videos/stringsoffreedom.md b/data/videos/stringsoffreedom.md
index 53e3e4d..0ce8939 100644
--- a/data/videos/stringsoffreedom.md
+++ b/data/videos/stringsoffreedom.md
@@ -2,8 +2,7 @@
title: "Strings of Freedom"
description: "Top Winning Submission for Yellow Ribbon Arts Competition 2025."
date: "May 2025"
-default_copyright: true
-license: "<i class=\"fa-brands fa-creative-commons\"></i><i class=\"fa-brands fa-creative-commons-by\"></i> CC-BY 4.0"
-license_url: "https://creativecommons.org/licenses/by/4.0/"
-downloadable: false
+default_copyright: false
+license: "<i class=\"fa-brands fa-creative-commons\"></i><i class=\"fa-brands fa-creative-commons-by\"></i><i class=\"fa-brands fa-creative-commons-sa\"></i> CC-BY-SA 4.0"
+license_url: "https://creativecommons.org/licenses/by-sa/4.0/"
---
diff --git a/main.py b/main.py
index f8e56df..459f9a1 100644
--- a/main.py
+++ b/main.py
@@ -117,4 +117,22 @@ def video_page_redirect(video_name: str):
)
+@app.get("/event/{event_name}/")
+def event_page(event_name: str):
+ status, html = pages.render_event(event_name)
+
+ if status == 200:
+ return fastapi.responses.Response(content=html, media_type="text/html", status_code=200)
+ else:
+ raise fastapi.HTTPException(status_code=status, detail="Event / academic thing doesn't exist.")
+
+
+@app.get("/event/{event_name}", include_in_schema=False)
+def event_page_redirect(event_name: str):
+ return fastapi.responses.RedirectResponse(
+ url=f"/event/{event_name}/",
+ status_code=301
+ )
+
+
app.mount("/", fastapi.staticfiles.StaticFiles(directory="./www/", html=True), name="static")
diff --git a/pages.py b/pages.py
index 9f37762..fcde18e 100644
--- a/pages.py
+++ b/pages.py
@@ -148,6 +148,8 @@ def render_video(video_name: str) -> tuple:
metadata, rendered_content = markdown_renderer.md_to_html(source)
metadata["path"] = VIDEO_INDEX[video_name]["path"]
+ if "download_path" in VIDEO_INDEX[video_name]:
+ metadata["download_path"] = VIDEO_INDEX[video_name]["download_path"]
print(metadata, rendered_content)
html = html.replace("{[{content}]}", rendered_content)
@@ -159,7 +161,16 @@ def render_video(video_name: str) -> tuple:
soup = BeautifulSoup(html, "html.parser")
soup.title.string = soup.title.string.replace("{[{title}]}", metadata["title"])
- soup.select_one("#video")["src"] = metadata["path"]
+ if "youtube" in metadata["path"]:
+ pass
+ iframe = BeautifulSoup(f"""
+ <iframe src="{metadata["path"]}" id="iframe-yt" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
+ """, "html.parser")
+ soup.select_one("#video-parent").append(iframe)
+ soup.select_one("#video").decompose()
+ soup.select_one("#video-controls").decompose()
+ else:
+ soup.select_one("#video")["src"] = metadata["path"]
if metadata["default_copyright"]:
soup.select_one("#video-license-parent").string = "©️ All rights reserved"
@@ -167,9 +178,30 @@ def render_video(video_name: str) -> tuple:
soup.select_one("#video-license-info")["href"] = metadata["license_url"]
soup.select_one("#video-license-info").insert(0, BeautifulSoup(metadata["license"], "html.parser"))
- if metadata["downloadable"] and not metadata["default_copyright"]:
- soup.select_one("#video-download-btn").href = metadata["path"]
+ if "download_path" in metadata and not metadata["default_copyright"]:
+ soup.select_one("#video-download-btn")["href"] = metadata["download_path"]
else:
soup.select_one("#video-download-btn").decompose()
return (200, str(soup))
+
+
+def render_event(event_name: str) -> tuple:
+ html = HTML_EVENT_TEMPLATE
+ source = ""
+
+ if event_name not in EVENT_INDEX:
+ return (404, "")
+
+ with open("." + EVENT_INDEX[event_name]["path"], "r") as f:
+ source = f.read()
+
+ metadata, rendered_content = markdown_renderer.md_to_html(source)
+ print(metadata, rendered_content)
+
+ html = html.replace("{[{content}]}", rendered_content)
+
+ soup = BeautifulSoup(html, "html.parser")
+ soup.title.string = soup.title.string.replace("{[{title}]}", metadata["title"])
+
+ return (200, str(soup))
diff --git a/templates/eventdetails.html b/templates/eventdetails.html
index e69de29..064f27e 100644
--- a/templates/eventdetails.html
+++ b/templates/eventdetails.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="stylesheet" href="/style.css">
+ <link rel="icon" type="image/x-icon" href="/assets/images/favicon.ico">
+ <link rel="icon" type="image/x-icon" href="/assets/images/favicon.ico">
+ <title>{[{title}]} • altaf-creator</title>
+ <link rel="stylesheet" href="/packages/fontawesome-free-7.2.0-web/css/all.css">
+</head>
+
+<body onload="addNodes()">
+ <script defer src="/scripts/onload.js"></script>
+ <script defer src="/scripts/scroll.js"></script>
+ <script defer src="/scripts/bannervideo.js"></script>
+ <div class="floating-nav-container">
+ <div class="floating-nav">
+ <a href="/" class="mobile"><img src="/assets/images/hero/logo.png" alt="" class="sidebar-img mobile" style="margin-top: 0; margin-left: -20px;"></a>
+ <a href="/about/" class="link">About Me</a>
+ <a href="/projects/" class="link">Projects</a>
+ <a href="/blog/" class="link">Library</a>
+ </div>
+ </div>
+ <div class="sidebar" id="sidebar">
+ <a href="/">
+ <img src="/assets/images/hero/logo.png" alt="" class="sidebar-img">
+ </a>
+ <span>altaf-creator</span>
+ </div>
+ <div class="sidebar-progress-container" id="progressContainer">
+ </div>
+ {[{content}]}
+</body>
+
+</html>
diff --git a/templates/video.html b/templates/video.html
index 5f52065..8bba92b 100644
--- a/templates/video.html
+++ b/templates/video.html
@@ -32,21 +32,21 @@
</div>
<div class="sidebar-progress-container" id="progressContainer">
</div>
- <section class="normal-section video-section">
- <div class="shadow-filter">
- <video class="video" id="video">
- </video>
- <div class="shadow-filter">
- <div class="video-controls">
- <button id="video-controls-play"><i class="fa-solid fa-play"></i></button>
- <span><span id="video-controls-currenttime">00:00</span><span id="video-controls-totaltime" class="desktop half-opacity-text">/00:00</span>
- </span>
- <input type="range" id="video-controls-progress" min="0" max="1" value="0" step="any"></progress>
- <button id="video-controls-mutetoggle"><i class="fa-solid fa-volume"></i></button>
- <button id="video-controls-maximise"><i class="fa-solid fa-maximize"></i></button>
- </div>
+ <section class="normal-section video-section" id="video-section">
+ <div class="shadow-filter" id="video-parent">
+ <video class="video" id="video">
+ </video>
+ <div class="shadow-filter" id="video-controls">
+ <div class="video-controls">
+ <button id="video-controls-play"><i class="fa-solid fa-play"></i></button>
+ <span><span id="video-controls-currenttime">00:00</span><span id="video-controls-totaltime" class="desktop half-opacity-text">/00:00</span>
+ </span>
+ <input type="range" id="video-controls-progress" min="0" max="1" value="0" step="any"></progress>
+ <button id="video-controls-mutetoggle"><i class="fa-solid fa-volume"></i></button>
+ <button id="video-controls-maximise"><i class="fa-solid fa-maximize"></i></button>
</div>
</div>
+ </div>
</section>
<section class="normal-section">
<div class="center-grid">
diff --git a/www/about/index.html b/www/about/index.html
index e5aacf6..5e006e9 100644
--- a/www/about/index.html
+++ b/www/about/index.html
@@ -49,10 +49,10 @@
<span class="heading">About Me</span>
<p>
Hey there! I'm <b class="colored-text">Altaf</b>. I am a scholar studying abroad in <b class="colored-text">Singapore</b> from
- <b class="colored-text">Indonesia</b> who likes to <b class="colored-text">create</b> and <b class="colored-text">tinker</b> (mostly with computers).
+ <b class="colored-text">Indonesia</b> who likes to <b class="colored-text">create</b> and <b class="colored-text">tinker</b> with computers, usually.
</p>
<p>
- I'm mostly a <span class="colored-text">game developer</span> and <span class="colored-text">web developer</span>, but I
+ I'm mainly a <span class="colored-text">game developer</span> and <span class="colored-text">web developer</span>, but I
also like to make other things like desktop apps, and robots.<br>I'm still constantly learning and trying new things!
</p>
</div>
@@ -93,8 +93,24 @@
<section>
<div class="center-grid">
<div class="div-sizing">
- <h1>Academics &amp; Achievements</h1>
- <p>Under construction.</p>
+ <h1>Community and Events</h1>
+ <h2>Infocomm (Media Creation) CCA Vice President</h2>
+ <h2>Tinkertanker Internship</h2>
+ </div>
+ </div>
+ </section>
+ <section>
+ <div class="center-grid">
+ <div class="div-sizing">
+ <h1>Academics and Achievements</h1>
+ <h2>National Youth Tech Championship 2025</h2>
+ <h2>NOI 2026 (and 2025)</h2>
+ <h2>NOAI 2026</h2>
+ <h2>Temasek Engineering Olympiad 2026</h2>
+ <h2>Trans Studio Bandung Robotic Competition</h2>
+ <h2>Alarm Robotic Competition</h2>
+ <h2>ASEAN Robotic Day</h2>
+ <h2></h2>
</div>
</div>
</section>
diff --git a/www/assets/.DS_Store b/www/assets/.DS_Store
index 2322214..ae1cb79 100644
--- a/www/assets/.DS_Store
+++ b/www/assets/.DS_Store
Binary files differ
diff --git a/www/scripts/video.js b/www/scripts/video.js
index 9f32e96..bb5bb80 100644
--- a/www/scripts/video.js
+++ b/www/scripts/video.js
@@ -1,4 +1,6 @@
const video = document.getElementById("video");
+const videoParent = document.getElementById("video-parent");
+const videoSection = document.getElementById("video-section");
const videoControlsProgress = document.getElementById("video-controls-progress");
const videoControlsPlay = document.getElementById("video-controls-play");
const videoControlsVolume = document.getElementById("video-controls-mutetoggle");
@@ -55,13 +57,15 @@ function toggleMaximisation() {
if (videoMaximised) {
videoMaximised = false;
videoControlsMaximise.innerHTML = `<i class="fa-solid fa-maximize"></i>`;
- video.exitFullscreen();
- video.controls = false;
+ videoParent.classList.remove("video-fullscreen");
+ videoSection.appendChild(videoParent);
+ document.exitFullscreen();
} else {
videoMaximised = true;
videoControlsMaximise.innerHTML = `<i class="fa-solid fa-minimize"></i>`;
- video.requestFullscreen();
- video.controls = true;
+ videoParent.classList.add("video-fullscreen");
+ document.body.appendChild(videoParent);
+ document.documentElement.requestFullscreen();
}
}
diff --git a/www/style.css b/www/style.css
index 8bd39b9..8883fa0 100644
--- a/www/style.css
+++ b/www/style.css
@@ -154,6 +154,10 @@ section {
box-sizing: border-box;
}
+section:first-of-type {
+ border-top: none;
+}
+
hr {
border: none;
background-color: black;
@@ -1053,6 +1057,29 @@ li {
transition-delay: 0s;
}
+.video-fullscreen {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: black;
+ z-index: 10003;
+ height: 100vh;
+ width: 100vw;
+}
+
+.video-fullscreen > .video {
+ clip-path: none;
+ background-color: black;
+ height: 100vh;
+ width: 100vw;
+}
+
+.shadow-filter:has(.video-fullscreen) {
+ filter: none;
+}
+
.video-controls:hover {
opacity: 1;
transition-delay: 0s;
@@ -1318,6 +1345,12 @@ li {
bottom: 20px;
}
+#iframe-yt {
+ width: 100%;
+ aspect-ratio: 16/9;
+ clip-path: polygon(0 20.00px, 20px 20px, 20.00px 0, calc(100% - 20.00px) 0, calc(100% - 20px) 20px, 100% 20.00px, 100% calc(100% - 20.00px), calc(100% - 20px) calc(100% - 20px), calc(100% - 20.00px) 100%, 20.00px 100%, 20px calc(100% - 20px), 0 calc(100% - 20.00px));
+}
+
@media only screen and (max-width: 600px) {
.desktop {
visibility: collapse !important;