aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2024-07-07 12:09:08 -0400
committerAndrew Lee <alee14498@protonmail.com>2024-07-07 12:09:08 -0400
commit7205caf6afb58bee230a04a5830842ea6e5b10ff (patch)
treec3a3eaeb0b1907be6d7ab909793b87fa0090cba4
parentb659ac111c8c3ea16be0d856b095cb6a85c2beef (diff)
downloadpersonal-website-7205caf6afb58bee230a04a5830842ea6e5b10ff.tar.gz
personal-website-7205caf6afb58bee230a04a5830842ea6e5b10ff.tar.bz2
personal-website-7205caf6afb58bee230a04a5830842ea6e5b10ff.zip
Added videos page
-rw-r--r--src/components/GitHubProjects.svelte3
-rw-r--r--src/components/Loader.svelte30
-rw-r--r--src/components/Navbar.svelte1
-rw-r--r--src/components/YouTubeVideos.svelte133
-rw-r--r--src/pages/videos.astro10
5 files changed, 176 insertions, 1 deletions
diff --git a/src/components/GitHubProjects.svelte b/src/components/GitHubProjects.svelte
index 2753b89..9d9d569 100644
--- a/src/components/GitHubProjects.svelte
+++ b/src/components/GitHubProjects.svelte
@@ -1,5 +1,6 @@
<script>
import { onMount } from 'svelte';
+ import Loader from "./Loader.svelte";
export let username;
export let isOrganization;
let repos = [];
@@ -54,7 +55,7 @@
<div>
{#if isLoading}
- <div>Loading...</div>
+ <Loader />
{:else}
{#if error}
<div class="error">{error}</div>
diff --git a/src/components/Loader.svelte b/src/components/Loader.svelte
new file mode 100644
index 0000000..55d1d40
--- /dev/null
+++ b/src/components/Loader.svelte
@@ -0,0 +1,30 @@
+<style>
+ .loader {
+ width: 48px;
+ height: 48px;
+ border: 5px solid #b3f69e;
+ border-bottom-color: #609460;
+ border-radius: 50%;
+ display: inline-block;
+ box-sizing: border-box;
+ animation: rotation 1s linear infinite;
+ }
+
+ @keyframes rotation {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+ }
+ .centre {
+ display: flex;
+ justify-content: center;
+ }
+
+</style>
+
+<div class="centre">
+ <span class="loader"></span>
+</div>
diff --git a/src/components/Navbar.svelte b/src/components/Navbar.svelte
index 11f2ef3..3211799 100644
--- a/src/components/Navbar.svelte
+++ b/src/components/Navbar.svelte
@@ -109,6 +109,7 @@
<li><a href="/projects" class="nav-link" on:click={toggleNav}>Projects</a></li>
<li><a href="/blog" class="nav-link" on:click={toggleNav}>Blog</a></li>
<li><a href="/guestbook" class="nav-link" on:click={toggleNav}>Guestbook</a></li>
+ <li><a href="/videos" class="nav-link" on:click={toggleNav}>Videos</a></li>
<!-- <li><a href="https://archive.alee14.me" class="nav-link" on:click={toggleNav}>Archive</a></li>-->
<li><a href="/contacts" class="nav-link" on:click={toggleNav}>Contacts</a></li>
</ul>
diff --git a/src/components/YouTubeVideos.svelte b/src/components/YouTubeVideos.svelte
new file mode 100644
index 0000000..677e502
--- /dev/null
+++ b/src/components/YouTubeVideos.svelte
@@ -0,0 +1,133 @@
+<script>
+ import { onMount, onDestroy } from 'svelte';
+ import Loader from './Loader.svelte';
+ import { formatDate } from "../util";
+
+ let error = null;
+ let isLoading = true;
+ let videos = [];
+ let nextPageToken = '';
+
+ const fetchVideos = async (pageToken = '') => {
+ isLoading = true;
+ const url = `${import.meta.env.PUBLIC_API_URL}/youtube?pageToken=${pageToken}`;
+ try {
+ const response = await fetch(url);
+ if (!response.ok) {
+ console.error('HTTP Error: ' + response.statusText);
+ error = 'HTTP Error: ' + response.statusText;
+ return;
+ }
+ const data = await response.json();
+ videos = [...videos, ...data.items];
+ nextPageToken = data.nextPageToken || '';
+ } catch (e) {
+ console.error(e);
+ error = e.message;
+ } finally {
+ isLoading = false;
+ }
+ };
+
+ function onScroll() {
+ const nearBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 2;
+ if (nearBottom && !isLoading && nextPageToken) {
+ fetchVideos(nextPageToken);
+ }
+ }
+
+ onMount(() => {
+ if (typeof window !== 'undefined') {
+ window.addEventListener('scroll', onScroll);
+ fetchVideos().then(() => isLoading = false);
+ }
+ });
+
+ onDestroy(() => {
+ if (typeof window !== 'undefined') {
+ window.removeEventListener('scroll', onScroll);
+ }
+ });
+</script>
+
+<style>
+ .title {
+ margin-top: .2em;
+ margin-bottom: .2em;
+ }
+
+ img {
+ width: 100%;
+ height: auto;
+ border-radius: 1em;
+ object-fit: cover;
+ }
+
+ .card small {
+ display: block;
+ margin-bottom: 1em;
+ }
+
+ .zoom {
+ transition: transform 0.2s ease; /* Smooth transition for the transform property */
+ display: block; /* Ensures the image is block-level for proper scaling */
+ margin: auto; /* Keeps the image centered */
+ max-width: 100%; /* Ensures the image does not exceed its container's width */
+ }
+
+ .zoom:hover {
+ transform: scale(1.1); /* Scales the image to 110% of its original size on hover */
+ }
+
+ .container {
+ display: grid;
+ gap: 1em; /* Adjusts the gap between grid items */
+ }
+
+ @media (min-width: 992px) {
+ .container {
+ grid-template-columns: repeat(3, 1fr); /* Original setting for large screens */
+ }
+ }
+
+ @media (max-width: 991px) and (min-width: 768px) {
+ .container {
+ grid-template-columns: repeat(2, 1fr); /* Adjusts to 2 columns for tablets */
+ }
+ }
+
+ @media (max-width: 767px) {
+ .container {
+ grid-template-columns: 1fr; /* Adjusts to a single column for mobile */
+ }
+ }
+
+</style>
+
+<div>
+ <div>
+ {#if isLoading && videos.length === 0}
+ <Loader />
+ {:else}
+ {#if error}
+ <div class="error">{error}</div>
+ {:else}
+ <div class="container">
+ {#each videos as video}
+ <div class="card">
+ <a href={`https://youtu.be/${video.snippet.resourceId.videoId}`} target="_blank">
+ <h3 class="title">{video.snippet.title}</h3>
+ <small>{formatDate(video.snippet.publishedAt)}</small>
+ <img src={video.snippet.thumbnails.medium.url} alt={video.snippet.title} class="zoom" />
+ </a>
+ </div>
+ {/each}
+ </div>
+ <div class="load-more"></div>
+ {/if}
+ {/if}
+ {#if isLoading && videos.length > 0}
+ <Loader />
+ {/if}
+ </div>
+</div>
diff --git a/src/pages/videos.astro b/src/pages/videos.astro
new file mode 100644
index 0000000..c276fe7
--- /dev/null
+++ b/src/pages/videos.astro
@@ -0,0 +1,10 @@
+---
+import Page from "../layouts/Page.astro";
+import "../styles/cards.css";
+import YouTubeVideos from "../components/YouTubeVideos.svelte";
+---
+<Page title="Videos" description="All videos that I have made on YouTube">
+ <main>
+ <YouTubeVideos client:load />
+ </main>
+</Page>