diff options
| -rw-r--r-- | data/events.json | 9 | ||||
| -rw-r--r-- | data/events/noi.md | 11 | ||||
| -rw-r--r-- | data/events/nytc.md | 11 | ||||
| -rw-r--r-- | data/videos.json | 14 | ||||
| -rw-r--r-- | data/videos/eid2026.md | 1 | ||||
| -rw-r--r-- | data/videos/minds.md | 1 | ||||
| -rw-r--r-- | data/videos/paperverse.md | 5 | ||||
| -rw-r--r-- | data/videos/s3via.md | 5 | ||||
| -rw-r--r-- | data/videos/stringsoffreedom.md | 7 | ||||
| -rw-r--r-- | main.py | 18 | ||||
| -rw-r--r-- | pages.py | 38 | ||||
| -rw-r--r-- | templates/eventdetails.html | 38 | ||||
| -rw-r--r-- | templates/video.html | 26 | ||||
| -rw-r--r-- | www/about/index.html | 24 | ||||
| -rw-r--r-- | www/assets/.DS_Store | bin | 6148 -> 6148 bytes | |||
| -rw-r--r-- | www/scripts/video.js | 12 | ||||
| -rw-r--r-- | www/style.css | 33 |
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/" --- @@ -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") @@ -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 & 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 Binary files differindex 2322214..ae1cb79 100644 --- a/www/assets/.DS_Store +++ b/www/assets/.DS_Store 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;
|
