mirror of
https://github.com/JuLi0n21/homepage.git
synced 2026-04-19 15:20:05 +00:00
add client side shuffel so every page refresh it stays fresh
This commit is contained in:
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["prettier-plugin-astro"],
|
||||||
|
"overrides":
|
||||||
|
[{ "files": "*.astro", "*.md", "*.mdx", "options": { "parser": "astro" } }],
|
||||||
|
}
|
||||||
47
package-lock.json
generated
47
package-lock.json
generated
@@ -13,9 +13,12 @@
|
|||||||
"@astrojs/rss": "^4.0.15",
|
"@astrojs/rss": "^4.0.15",
|
||||||
"@astrojs/sitemap": "^3.7.0",
|
"@astrojs/sitemap": "^3.7.0",
|
||||||
"astro": "^5.17.1",
|
"astro": "^5.17.1",
|
||||||
"prettier": "^3.8.1",
|
|
||||||
"sharp": "^0.34.3",
|
"sharp": "^0.34.3",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "3.8.1",
|
||||||
|
"prettier-plugin-astro": "0.14.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/check": {
|
"node_modules/@astrojs/check": {
|
||||||
@@ -5005,6 +5008,21 @@
|
|||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier-plugin-astro": {
|
||||||
|
"version": "0.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.1.tgz",
|
||||||
|
"integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/compiler": "^2.9.1",
|
||||||
|
"prettier": "^3.0.0",
|
||||||
|
"sass-formatter": "^0.7.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.15.0 || >=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prismjs": {
|
"node_modules/prismjs": {
|
||||||
"version": "1.30.0",
|
"version": "1.30.0",
|
||||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
||||||
@@ -5447,6 +5465,23 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/s.color": {
|
||||||
|
"version": "0.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz",
|
||||||
|
"integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/sass-formatter": {
|
||||||
|
"version": "0.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz",
|
||||||
|
"integrity": "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"suf-log": "^2.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sax": {
|
"node_modules/sax": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz",
|
||||||
@@ -5681,6 +5716,16 @@
|
|||||||
"inline-style-parser": "0.2.7"
|
"inline-style-parser": "0.2.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/suf-log": {
|
||||||
|
"version": "2.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz",
|
||||||
|
"integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"s.color": "0.0.15"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svgo": {
|
"node_modules/svgo": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
|
||||||
|
|||||||
@@ -17,8 +17,11 @@
|
|||||||
"@astrojs/rss": "^4.0.15",
|
"@astrojs/rss": "^4.0.15",
|
||||||
"@astrojs/sitemap": "^3.7.0",
|
"@astrojs/sitemap": "^3.7.0",
|
||||||
"astro": "^5.17.1",
|
"astro": "^5.17.1",
|
||||||
"prettier": "^3.8.1",
|
|
||||||
"sharp": "^0.34.3",
|
"sharp": "^0.34.3",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "3.8.1",
|
||||||
|
"prettier-plugin-astro": "0.14.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
// Import the global.css file here so that it is included on
|
// Import the global.css file here so that it is included on
|
||||||
// all pages through the use of the <BaseHead /> component.
|
// all pages through the use of the <BaseHead /> component.
|
||||||
import '@styles/global.css';
|
import "@styles/global.css";
|
||||||
import type { ImageMetadata } from 'astro';
|
import type { ImageMetadata } from "astro";
|
||||||
import { SITE_TITLE } from '@ptypes/consts.ts';
|
import { SITE_TITLE } from "@ptypes/consts.ts";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -26,13 +26,25 @@ const { title, description } = Astro.props;
|
|||||||
rel="alternate"
|
rel="alternate"
|
||||||
type="application/rss+xml"
|
type="application/rss+xml"
|
||||||
title={SITE_TITLE}
|
title={SITE_TITLE}
|
||||||
href={new URL('rss.xml', Astro.site)}
|
href={new URL("rss.xml", Astro.site)}
|
||||||
/>
|
/>
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
|
||||||
<!-- Font preloads -->
|
<!-- Font preloads -->
|
||||||
<link rel="preload" href="/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin />
|
<link
|
||||||
<link rel="preload" href="/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin />
|
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 -->
|
<!-- Canonical URL -->
|
||||||
<link rel="canonical" href={canonicalURL} />
|
<link rel="canonical" href={canonicalURL} />
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ const { date } = Astro.props;
|
|||||||
|
|
||||||
<time datetime={date.toISOString()}>
|
<time datetime={date.toISOString()}>
|
||||||
{
|
{
|
||||||
date.toLocaleDateString('en-us', {
|
date.toLocaleDateString("en-us", {
|
||||||
year: 'numeric',
|
year: "numeric",
|
||||||
month: 'short',
|
month: "short",
|
||||||
day: 'numeric',
|
day: "numeric",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</time>
|
</time>
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
---
|
---
|
||||||
import { SITE_TITLE } from '@ptypes/consts.ts';
|
import { SITE_TITLE } from "@ptypes/consts.ts";
|
||||||
import HeaderLink from '@components/HeaderLink.astro';
|
import HeaderLink from "@components/HeaderLink.astro";
|
||||||
import '@styles/indexHoverCss.css';
|
import "@styles/indexHoverCss.css";
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
const personalPosts = (await getCollection('personal')).sort(
|
const personalPosts = (await getCollection("personal")).sort(
|
||||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||||
);
|
);
|
||||||
const uniPosts = (await getCollection('uni')).sort(
|
const uniPosts = (await getCollection("uni")).sort(
|
||||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
<!DOCTYPE html>
|
|
||||||
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style></style>
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav>
|
<nav>
|
||||||
@@ -25,22 +25,25 @@ const uniPosts = (await getCollection('uni')).sort(
|
|||||||
{
|
{
|
||||||
personalPosts.map((post) => (
|
personalPosts.map((post) => (
|
||||||
<li>
|
<li>
|
||||||
<HeaderLink href={`/blog/personal/${post.id}/`}>{post.data.title}</HeaderLink>
|
<HeaderLink href={`/blog/personal/${post.id}/`}>
|
||||||
|
{post.data.title}
|
||||||
|
</HeaderLink>
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
<hr>
|
<hr />
|
||||||
<h4>University</h4>
|
<h4>University</h4>
|
||||||
<h6>(Group Projects)</h6>
|
<h6>(Group Projects)</h6>
|
||||||
{
|
{
|
||||||
uniPosts.map((post) => (
|
uniPosts.map((post) => (
|
||||||
<li>
|
<li>
|
||||||
<HeaderLink href={`/blog/university/${post.id}/`}>{post.data.title}</HeaderLink>
|
<HeaderLink href={`/blog/university/${post.id}/`}>
|
||||||
|
{post.data.title}
|
||||||
|
</HeaderLink>
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
---
|
---
|
||||||
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 { 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 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">
|
<html lang="en">
|
||||||
<head>
|
<head> </head>
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<a href={href} class:list={[className, { active: isActive }]} {...props}>
|
<a href={href} class:list={[className, { active: isActive }]} {...props}>
|
||||||
<slot />
|
<slot />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import BaseHead from '@components/BaseHead.astro';
|
import BaseHead from "@components/BaseHead.astro";
|
||||||
import Header from '@components/Header.astro';
|
import Header from "@components/Header.astro";
|
||||||
import GithubIcon from '@assets/github.svg'
|
import GithubIcon from "@assets/github.svg";
|
||||||
|
|
||||||
const { title, description, gitLink } = Astro.props;
|
const { title, description, gitLink } = Astro.props;
|
||||||
---
|
---
|
||||||
@@ -15,7 +15,8 @@ const { title, description, gitLink } = Astro.props;
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
main { display: flex;
|
main {
|
||||||
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -33,7 +34,6 @@ const { title, description, gitLink } = Astro.props;
|
|||||||
padding: 1cm;
|
padding: 1cm;
|
||||||
margin: 1cm;
|
margin: 1cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -41,12 +41,18 @@ const { title, description, gitLink } = Astro.props;
|
|||||||
<main>
|
<main>
|
||||||
<Header />
|
<Header />
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<a href={gitLink ?? 'https://github.com/juli0n21'} style="position: relative;">
|
<a
|
||||||
<GithubIcon style="position: absolute; right:0;" width="50px" height="50px" />
|
href={gitLink ?? "https://github.com/juli0n21"}
|
||||||
|
style="position: relative;"
|
||||||
|
>
|
||||||
|
<GithubIcon
|
||||||
|
style="position: absolute; right:0;"
|
||||||
|
width="50px"
|
||||||
|
height="50px"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { getCollection, render } from 'astro:content';
|
import { getCollection, render } from "astro:content";
|
||||||
import BlogPost from '@layouts/BlogPost.astro';
|
import BlogPost from "@layouts/BlogPost.astro";
|
||||||
import type {
|
import type {
|
||||||
InferGetStaticParamsType,
|
InferGetStaticParamsType,
|
||||||
InferGetStaticPropsType,
|
InferGetStaticPropsType,
|
||||||
@@ -8,8 +8,8 @@ import type {
|
|||||||
} from "astro";
|
} from "astro";
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await getCollection('personal');
|
const posts = await getCollection("personal");
|
||||||
return posts.map(post => ({
|
return posts.map((post) => ({
|
||||||
params: { id: post.id },
|
params: { id: post.id },
|
||||||
props: { post },
|
props: { post },
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { getCollection, render } from 'astro:content';
|
import { getCollection, render } from "astro:content";
|
||||||
import BlogPost from '@layouts/BlogPost.astro';
|
import BlogPost from "@layouts/BlogPost.astro";
|
||||||
import type {
|
import type {
|
||||||
InferGetStaticParamsType,
|
InferGetStaticParamsType,
|
||||||
InferGetStaticPropsType,
|
InferGetStaticPropsType,
|
||||||
@@ -8,8 +8,8 @@ import type {
|
|||||||
} from "astro";
|
} from "astro";
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await getCollection('uni');
|
const posts = await getCollection("uni");
|
||||||
return posts.map(post => ({
|
return posts.map((post) => ({
|
||||||
params: { id: post.id },
|
params: { id: post.id },
|
||||||
props: { post },
|
props: { post },
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,27 +1,36 @@
|
|||||||
---
|
---
|
||||||
import BaseHead from '@components/BaseHead.astro';
|
import BaseHead from "@components/BaseHead.astro";
|
||||||
import Header from '@components/Header.astro';
|
import Header from "@components/Header.astro";
|
||||||
import { SITE_DESCRIPTION, SITE_TITLE } from '@ptypes/consts.ts';
|
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) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
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 files = data.files.map(
|
||||||
|
(f: Response) => `https://fshare.kami.boo/raw${f.url.substring(2)}`,
|
||||||
|
) as string[];
|
||||||
|
|
||||||
const middle = Math.round(files.length / 2);
|
const middle = Math.round(files.length / 2);
|
||||||
shuffled = files.slice(0,middle);
|
top = files.slice(0, middle);
|
||||||
images = files.slice(middle);
|
bottom = files.slice(middle);
|
||||||
} else {
|
} else {
|
||||||
const errorBody = await response.text();
|
const errorBody = await response.text();
|
||||||
console.error("FAILED TO FETCH", response.status, response.statusText, errorBody);
|
console.error(
|
||||||
|
"FAILED TO FETCH",
|
||||||
|
response.status,
|
||||||
|
response.statusText,
|
||||||
|
errorBody,
|
||||||
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||||
@@ -88,7 +97,7 @@ if (response.ok) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tilted-container:hover {
|
.tilted-container:hover {
|
||||||
transform: scale(1.10);
|
transform: scale(1.1);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +109,21 @@ if (response.ok) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes infiniteScroll {
|
@keyframes infiniteScroll {
|
||||||
0% { transform: translateX(0%); }
|
0% {
|
||||||
100% { transform: translateX(-50%); }
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes infiniteScrollReverse {
|
@keyframes infiniteScrollReverse {
|
||||||
0% { transform: translateX(0%); }
|
0% {
|
||||||
100% { transform: translateX(50%) }
|
transform: translateX(0%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(50%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -118,18 +135,19 @@ if (response.ok) {
|
|||||||
|
|
||||||
<main class="scrolling-gallery">
|
<main class="scrolling-gallery">
|
||||||
<div class="gallery-wrapper">
|
<div class="gallery-wrapper">
|
||||||
<div class="scroll-track">
|
<div id="top-images" class="scroll-track">
|
||||||
{[...images, ...images].map((src) => (
|
{
|
||||||
|
[...top, ...top].map((src) => (
|
||||||
<a class="tilted-container" href={src} target="_blank">
|
<a class="tilted-container" href={src} target="_blank">
|
||||||
<img src={src} loading="lazy" />
|
<img src={src} loading="lazy" />
|
||||||
</a>
|
</a>
|
||||||
))}
|
))
|
||||||
</div>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
<div class="scroll-track track-reverse">
|
</div>
|
||||||
{[...shuffled,...shuffled].map((src) => (
|
{}
|
||||||
|
<div id="bottom-images" class="scroll-track track-reverse">
|
||||||
|
{
|
||||||
|
[...bottom, ...bottom].map((src) => (
|
||||||
<a class="tilted-container" href={src} target="_blank">
|
<a class="tilted-container" href={src} target="_blank">
|
||||||
<img src={src} loading="lazy" />
|
<img src={src} loading="lazy" />
|
||||||
</a>
|
</a>
|
||||||
@@ -139,5 +157,26 @@ if (response.ok) {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
function shuffleImages(selector: string) {
|
||||||
|
const track = document.querySelector(selector);
|
||||||
|
if (!track) return;
|
||||||
|
|
||||||
|
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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user