mirror of
https://github.com/JuLi0n21/homepage.git
synced 2026-04-19 23:30:06 +00:00
add client side shuffel so every page refresh it stays fresh
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
---
|
||||
// Import the global.css file here so that it is included on
|
||||
// all pages through the use of the <BaseHead /> component.
|
||||
import '@styles/global.css';
|
||||
import type { ImageMetadata } from 'astro';
|
||||
import { SITE_TITLE } from '@ptypes/consts.ts';
|
||||
import "@styles/global.css";
|
||||
import type { ImageMetadata } from "astro";
|
||||
import { SITE_TITLE } from "@ptypes/consts.ts";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
image?: ImageMetadata;
|
||||
title: string;
|
||||
description: string;
|
||||
image?: ImageMetadata;
|
||||
}
|
||||
|
||||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||
@@ -23,16 +23,28 @@ const { title, description } = Astro.props;
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
<link
|
||||
rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title={SITE_TITLE}
|
||||
href={new URL('rss.xml', Astro.site)}
|
||||
rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title={SITE_TITLE}
|
||||
href={new URL("rss.xml", Astro.site)}
|
||||
/>
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<!-- Font preloads -->
|
||||
<link rel="preload" href="/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin />
|
||||
<link rel="preload" href="/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin />
|
||||
<link
|
||||
rel="preload"
|
||||
href="/fonts/atkinson-regular.woff"
|
||||
as="font"
|
||||
type="font/woff"
|
||||
crossorigin
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="/fonts/atkinson-bold.woff"
|
||||
as="font"
|
||||
type="font/woff"
|
||||
crossorigin
|
||||
/>
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
---
|
||||
interface Props {
|
||||
date: Date;
|
||||
date: Date;
|
||||
}
|
||||
|
||||
const { date } = Astro.props;
|
||||
---
|
||||
|
||||
<time datetime={date.toISOString()}>
|
||||
{
|
||||
date.toLocaleDateString('en-us', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
})
|
||||
}
|
||||
{
|
||||
date.toLocaleDateString("en-us", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})
|
||||
}
|
||||
</time>
|
||||
|
||||
@@ -1,46 +1,49 @@
|
||||
---
|
||||
import { SITE_TITLE } from '@ptypes/consts.ts';
|
||||
import HeaderLink from '@components/HeaderLink.astro';
|
||||
import '@styles/indexHoverCss.css';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { SITE_TITLE } from "@ptypes/consts.ts";
|
||||
import HeaderLink from "@components/HeaderLink.astro";
|
||||
import "@styles/indexHoverCss.css";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
const personalPosts = (await getCollection('personal')).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
const personalPosts = (await getCollection("personal")).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
);
|
||||
const uniPosts = (await getCollection('uni')).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
const uniPosts = (await getCollection("uni")).sort(
|
||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||
);
|
||||
---
|
||||
<!DOCTYPE html>
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<h2><a href="/">{SITE_TITLE}</a></h2>
|
||||
<ul>
|
||||
<h4>Personal</h4>
|
||||
{
|
||||
personalPosts.map((post) => (
|
||||
<li>
|
||||
<HeaderLink href={`/blog/personal/${post.id}/`}>{post.data.title}</HeaderLink>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
<hr>
|
||||
<h4>University</h4>
|
||||
<h6>(Group Projects)</h6>
|
||||
{
|
||||
uniPosts.map((post) => (
|
||||
<li>
|
||||
<HeaderLink href={`/blog/university/${post.id}/`}>{post.data.title}</HeaderLink>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</body>
|
||||
<head>
|
||||
<style></style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<h2><a href="/">{SITE_TITLE}</a></h2>
|
||||
<ul>
|
||||
<h4>Personal</h4>
|
||||
{
|
||||
personalPosts.map((post) => (
|
||||
<li>
|
||||
<HeaderLink href={`/blog/personal/${post.id}/`}>
|
||||
{post.data.title}
|
||||
</HeaderLink>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
<hr />
|
||||
<h4>University</h4>
|
||||
<h6>(Group Projects)</h6>
|
||||
{
|
||||
uniPosts.map((post) => (
|
||||
<li>
|
||||
<HeaderLink href={`/blog/university/${post.id}/`}>
|
||||
{post.data.title}
|
||||
</HeaderLink>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
---
|
||||
import type { HTMLAttributes } from 'astro/types';
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
|
||||
type Props = HTMLAttributes<'a'>;
|
||||
type Props = HTMLAttributes<"a">;
|
||||
|
||||
const { href, class: className, ...props } = Astro.props;
|
||||
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '');
|
||||
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, "");
|
||||
const subpath = pathname.match(/[^\/]+/g);
|
||||
const isActive = href === pathname || href === '/' + (subpath?.[0] || '');
|
||||
const isActive = href === pathname || href === "/" + (subpath?.[0] || "");
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<a href={href} class:list={[className, { active: isActive }]} {...props}>
|
||||
<slot />
|
||||
</a>
|
||||
</body>
|
||||
<head> </head>
|
||||
<body>
|
||||
<a href={href} class:list={[className, { active: isActive }]} {...props}>
|
||||
<slot />
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,52 +1,58 @@
|
||||
---
|
||||
import BaseHead from '@components/BaseHead.astro';
|
||||
import Header from '@components/Header.astro';
|
||||
import GithubIcon from '@assets/github.svg'
|
||||
import BaseHead from "@components/BaseHead.astro";
|
||||
import Header from "@components/Header.astro";
|
||||
import GithubIcon from "@assets/github.svg";
|
||||
|
||||
const { title, description, gitLink } = Astro.props;
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<BaseHead title={title} description={description} />
|
||||
<!-- To add meta data here later -->
|
||||
<style>
|
||||
body {
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
main { display: flex;
|
||||
flex-direction: row;
|
||||
align-items: start;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
<head>
|
||||
<BaseHead title={title} description={description} />
|
||||
<!-- To add meta data here later -->
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: start;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
width: 0;
|
||||
padding: 1cm;
|
||||
margin: 1cm;
|
||||
}
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
min-width: 0;
|
||||
width: 0;
|
||||
padding: 1cm;
|
||||
margin: 1cm;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<Header />
|
||||
<div class="wrapper">
|
||||
<a href={gitLink ?? 'https://github.com/juli0n21'} style="position: relative;">
|
||||
<GithubIcon style="position: absolute; right:0;" width="50px" height="50px" />
|
||||
</a>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</body>
|
||||
<body>
|
||||
<main>
|
||||
<Header />
|
||||
<div class="wrapper">
|
||||
<a
|
||||
href={gitLink ?? "https://github.com/juli0n21"}
|
||||
style="position: relative;"
|
||||
>
|
||||
<GithubIcon
|
||||
style="position: absolute; right:0;"
|
||||
width="50px"
|
||||
height="50px"
|
||||
/>
|
||||
</a>
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import { getCollection, render } from 'astro:content';
|
||||
import BlogPost from '@layouts/BlogPost.astro';
|
||||
import { getCollection, render } from "astro:content";
|
||||
import BlogPost from "@layouts/BlogPost.astro";
|
||||
import type {
|
||||
InferGetStaticParamsType,
|
||||
InferGetStaticPropsType,
|
||||
@@ -8,11 +8,11 @@ import type {
|
||||
} from "astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('personal');
|
||||
return posts.map(post => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
const posts = await getCollection("personal");
|
||||
return posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
|
||||
getStaticPaths satisfies GetStaticPaths;
|
||||
@@ -25,5 +25,5 @@ const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<BlogPost {...post.data}>
|
||||
<Content />
|
||||
<Content />
|
||||
</BlogPost>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import { getCollection, render } from 'astro:content';
|
||||
import BlogPost from '@layouts/BlogPost.astro';
|
||||
import { getCollection, render } from "astro:content";
|
||||
import BlogPost from "@layouts/BlogPost.astro";
|
||||
import type {
|
||||
InferGetStaticParamsType,
|
||||
InferGetStaticPropsType,
|
||||
@@ -8,11 +8,11 @@ import type {
|
||||
} from "astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('uni');
|
||||
return posts.map(post => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
const posts = await getCollection("uni");
|
||||
return posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
|
||||
getStaticPaths satisfies GetStaticPaths;
|
||||
@@ -25,5 +25,5 @@ const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<BlogPost {...post.data}>
|
||||
<Content />
|
||||
<Content />
|
||||
</BlogPost>
|
||||
|
||||
@@ -1,143 +1,182 @@
|
||||
---
|
||||
import BaseHead from '@components/BaseHead.astro';
|
||||
import Header from '@components/Header.astro';
|
||||
import { SITE_DESCRIPTION, SITE_TITLE } from '@ptypes/consts.ts';
|
||||
import BaseHead from "@components/BaseHead.astro";
|
||||
import Header from "@components/Header.astro";
|
||||
import { SITE_DESCRIPTION, SITE_TITLE } from "@ptypes/consts.ts";
|
||||
|
||||
let top: string[] = [];
|
||||
let bottom: string[] = [];
|
||||
const api: string =
|
||||
"https://fshare.kami.boo/api/server/folder/cmm9jbqvt00025omwu5cnpw9i";
|
||||
const response = await fetch(api);
|
||||
|
||||
let shuffled: string[] = [];
|
||||
let images: string[] = [];
|
||||
const api: string = 'https://fshare.kami.boo/api/server/folder/cmm9jbqvt00025omwu5cnpw9i';
|
||||
const response = await fetch(api)
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const files = data.files.map((f: Response) => `https://fshare.kami.boo/raw${f.url.substring(2)}`).sort(() => Math.random() - .5) as string[];
|
||||
const middle = Math.round(files.length / 2);
|
||||
shuffled = files.slice(0,middle);
|
||||
images = files.slice(middle);
|
||||
} else {
|
||||
const errorBody = await response.text();
|
||||
console.error("FAILED TO FETCH", response.status, response.statusText, errorBody);
|
||||
process.exit(1);
|
||||
}
|
||||
const data = await response.json();
|
||||
const files = data.files.map(
|
||||
(f: Response) => `https://fshare.kami.boo/raw${f.url.substring(2)}`,
|
||||
) as string[];
|
||||
|
||||
const middle = Math.round(files.length / 2);
|
||||
top = files.slice(0, middle);
|
||||
bottom = files.slice(middle);
|
||||
} else {
|
||||
const errorBody = await response.text();
|
||||
console.error(
|
||||
"FAILED TO FETCH",
|
||||
response.status,
|
||||
response.statusText,
|
||||
errorBody,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||
<style>
|
||||
.layout {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
<head>
|
||||
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||
<style>
|
||||
.layout {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
}
|
||||
.sidebar {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.scrolling-gallery {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin: 1cm;
|
||||
}
|
||||
.scrolling-gallery {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin: 1cm;
|
||||
}
|
||||
|
||||
main {
|
||||
background: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
main {
|
||||
background: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gallery-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rem;
|
||||
transform: rotate(-8deg) scale(1.3);
|
||||
}
|
||||
.gallery-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rem;
|
||||
transform: rotate(-8deg) scale(1.3);
|
||||
}
|
||||
|
||||
.scroll-track {
|
||||
display: flex;
|
||||
gap: 3rem;
|
||||
width: max-content;
|
||||
animation: infiniteScroll 500s linear infinite;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
.scroll-track {
|
||||
display: flex;
|
||||
gap: 3rem;
|
||||
width: max-content;
|
||||
animation: infiniteScroll 500s linear infinite;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.track-reverse {
|
||||
animation: infiniteScrollReverse 600s linear infinite;
|
||||
}
|
||||
.track-reverse {
|
||||
animation: infiniteScrollReverse 600s linear infinite;
|
||||
}
|
||||
|
||||
.tilted-container {
|
||||
width: 220px;
|
||||
height: 280px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease;
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
|
||||
}
|
||||
.tilted-container {
|
||||
width: 220px;
|
||||
height: 280px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.tilted-container:hover {
|
||||
transform: scale(1.10);
|
||||
z-index: 1;
|
||||
}
|
||||
.tilted-container:hover {
|
||||
transform: scale(1.1);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tilted-container img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.tilted-container img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes infiniteScroll {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-50%); }
|
||||
}
|
||||
@keyframes infiniteScroll {
|
||||
0% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes infiniteScrollReverse {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(50%) }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<aside class="sidebar">
|
||||
<Header />
|
||||
</aside>
|
||||
@keyframes infiniteScrollReverse {
|
||||
0% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(50%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<aside class="sidebar">
|
||||
<Header />
|
||||
</aside>
|
||||
|
||||
<main class="scrolling-gallery">
|
||||
<div class="gallery-wrapper">
|
||||
<div class="scroll-track">
|
||||
{[...images, ...images].map((src) => (
|
||||
<a class="tilted-container" href={src} target="_blank">
|
||||
<img src={src} loading="lazy" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
{
|
||||
<main class="scrolling-gallery">
|
||||
<div class="gallery-wrapper">
|
||||
<div id="top-images" class="scroll-track">
|
||||
{
|
||||
[...top, ...top].map((src) => (
|
||||
<a class="tilted-container" href={src} target="_blank">
|
||||
<img src={src} loading="lazy" />
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
{}
|
||||
<div id="bottom-images" class="scroll-track track-reverse">
|
||||
{
|
||||
[...bottom, ...bottom].map((src) => (
|
||||
<a class="tilted-container" href={src} target="_blank">
|
||||
<img src={src} loading="lazy" />
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
function shuffleImages(selector: string) {
|
||||
const track = document.querySelector(selector);
|
||||
if (!track) return;
|
||||
|
||||
}
|
||||
<div class="scroll-track track-reverse">
|
||||
{[...shuffled,...shuffled].map((src) => (
|
||||
<a class="tilted-container" href={src} target="_blank">
|
||||
<img src={src} loading="lazy" />
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
const items = Array.from(track.children);
|
||||
const shuffled = items.sort(() => Math.random() - 0.5);
|
||||
|
||||
track.innerHTML = "";
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
[...shuffled, ...shuffled].forEach((item) => {
|
||||
fragment.appendChild(item.cloneNode(true));
|
||||
});
|
||||
|
||||
track.appendChild(fragment);
|
||||
}
|
||||
|
||||
shuffleImages("#top-images");
|
||||
shuffleImages("#bottom-images");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user