make everything noscript compatible as best as possible
This commit is contained in:
parent
bbdc4ea50e
commit
1a0eaf2dcb
|
|
@ -1,12 +0,0 @@
|
||||||
function animate() {
|
|
||||||
const animateElements = document.querySelectorAll('.animate')
|
|
||||||
|
|
||||||
animateElements.forEach((element, index) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
element.classList.add('show')
|
|
||||||
}, index * 150)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", animate)
|
|
||||||
document.addEventListener("astro:after-swap", animate)
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { formatDate } from "@/lib/utils";
|
import { formatDate } from "@/lib/utils";
|
||||||
import { Icon } from '@iconify-icon/solid';
|
import { Icon } from "@iconify-icon/solid";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
|
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
|
||||||
|
|
@ -31,13 +30,11 @@ export default function ArrowCard({ entry, pill }: Props) {
|
||||||
|
|
||||||
<div class="text-sm line-clamp-2">{entry.data.summary}</div>
|
<div class="text-sm line-clamp-2">{entry.data.summary}</div>
|
||||||
<ul class="flex flex-wrap mt-2 gap-1">
|
<ul class="flex flex-wrap mt-2 gap-1">
|
||||||
{entry.data.tags.map(
|
{entry.data.tags.map((tag) => (
|
||||||
(tag) => (
|
<li class="text-xs font-departure uppercase py-0.5 px-1 rounded bg-black/5 dark:bg-white/20 text-black/75 dark:text-white/75">
|
||||||
<li class="text-xs font-departure uppercase py-0.5 px-1 rounded bg-black/5 dark:bg-white/20 text-black/75 dark:text-white/75">
|
{tag}
|
||||||
{tag}
|
</li>
|
||||||
</li>
|
))}
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative overflow-hidden w-4 h-4">
|
<div class="relative overflow-hidden w-4 h-4">
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ const { title, description, image = "/open-graph.jpg" } = Astro.props;
|
||||||
<!-- Global Scripts -->
|
<!-- Global Scripts -->
|
||||||
<script is:inline src="/js/theme.js"></script>
|
<script is:inline src="/js/theme.js"></script>
|
||||||
<script is:inline src="/js/scroll.js"></script>
|
<script is:inline src="/js/scroll.js"></script>
|
||||||
<script is:inline src="/js/animate.js"></script>
|
|
||||||
|
|
||||||
<ClientRouter />
|
<ClientRouter />
|
||||||
|
|
||||||
|
|
@ -107,11 +106,3 @@ const { title, description, image = "/open-graph.jpg" } = Astro.props;
|
||||||
integrity="sha384-m7LqaUc4JRc2uA7D4zSVUs/sgkYhmOOe9+Gd8DFmmAXH8vzs15fmw05YXvpxsoQB"
|
integrity="sha384-m7LqaUc4JRc2uA7D4zSVUs/sgkYhmOOe9+Gd8DFmmAXH8vzs15fmw05YXvpxsoQB"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<noscript>
|
|
||||||
<style>
|
|
||||||
.noscript-hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</noscript>
|
|
||||||
|
|
|
||||||
|
|
@ -10,20 +10,23 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Blog({ data, tags }: Props) {
|
export default function Blog({ data, tags }: Props) {
|
||||||
|
function filterPosts(): CollectionEntry<"blog">[] {
|
||||||
|
return data.filter((entry) =>
|
||||||
|
Array.from(filter()).every((value) =>
|
||||||
|
entry.data.tags.some(
|
||||||
|
(tag: string) =>
|
||||||
|
tag.toLowerCase() === String(value).toLowerCase(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const [filter, setFilter] = createSignal(new Set<string>());
|
const [filter, setFilter] = createSignal(new Set<string>());
|
||||||
const [posts, setPosts] = createSignal<CollectionEntry<"blog">[]>([]);
|
const [posts, setPosts] =
|
||||||
|
createSignal<CollectionEntry<"blog">[]>(filterPosts());
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
setPosts(
|
setPosts(filterPosts());
|
||||||
data.filter((entry) =>
|
|
||||||
Array.from(filter()).every((value) =>
|
|
||||||
entry.data.tags.some(
|
|
||||||
(tag: string) =>
|
|
||||||
tag.toLowerCase() === String(value).toLowerCase()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleTag(tag: string) {
|
function toggleTag(tag: string) {
|
||||||
|
|
@ -32,14 +35,14 @@ export default function Blog({ data, tags }: Props) {
|
||||||
new Set(
|
new Set(
|
||||||
prev.has(tag)
|
prev.has(tag)
|
||||||
? [...prev].filter((t) => t !== tag)
|
? [...prev].filter((t) => t !== tag)
|
||||||
: [...prev, tag]
|
: [...prev, tag],
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
<div class="not-noscript:grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||||
<div class="col-span-3 sm:col-span-1">
|
<div class="col-span-3 sm:col-span-1 noscript:hidden">
|
||||||
<div class="sticky top-24">
|
<div class="sticky top-24">
|
||||||
<div class="text-sm font-semibold font-departure uppercase mb-2 text-black dark:text-white">
|
<div class="text-sm font-semibold font-departure uppercase mb-2 text-black dark:text-white">
|
||||||
Filter
|
Filter
|
||||||
|
|
@ -58,21 +61,27 @@ export default function Blog({ data, tags }: Props) {
|
||||||
"hover:bg-black/10 hover:dark:bg-white/15",
|
"hover:bg-black/10 hover:dark:bg-white/15",
|
||||||
"transition-colors duration-300 ease-in-out",
|
"transition-colors duration-300 ease-in-out",
|
||||||
filter().has(tag) &&
|
filter().has(tag) &&
|
||||||
"text-black dark:text-white"
|
"text-black dark:text-white",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div class={cn(
|
<div
|
||||||
"relative size-5 fill-black/50 dark:fill-white/50",
|
class={cn(
|
||||||
"transition-colors duration-300 ease-in-out",
|
"relative size-5 fill-black/50 dark:fill-white/50",
|
||||||
filter().has(tag) &&
|
"transition-colors duration-300 ease-in-out",
|
||||||
"fill-black dark:fill-white"
|
filter().has(tag) &&
|
||||||
)}>
|
"fill-black dark:fill-white",
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Icon icon="pixelarticons:square" />
|
<Icon icon="pixelarticons:square" />
|
||||||
<Icon icon="pixel:check" class={cn("absolute top-0 right-0",
|
<Icon
|
||||||
filter().has(tag)
|
icon="pixel:check"
|
||||||
? "block"
|
class={cn(
|
||||||
: "hidden"
|
"absolute top-0 right-0",
|
||||||
)} />
|
filter().has(tag)
|
||||||
|
? "block"
|
||||||
|
: "hidden",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{tag}
|
{tag}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ const { pathname } = Astro.url;
|
||||||
const subpath = pathname.match(/[^/]+/g);
|
const subpath = pathname.match(/[^/]+/g);
|
||||||
---
|
---
|
||||||
|
|
||||||
<header id="header" class="fixed top-0 w-full h-16 z-50">
|
<header
|
||||||
|
id="header"
|
||||||
|
class="fixed top-0 w-full h-16 z-50 noscript:bg-zinc-200/75 noscript:border-black/10 noscript:backdrop-blur-sm noscript:saturate-200"
|
||||||
|
>
|
||||||
<Container size="md">
|
<Container size="md">
|
||||||
<div
|
<div
|
||||||
class="relative h-full w-full flex flex-row justify-between items-center"
|
class="relative h-full w-full flex flex-row justify-between items-center"
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,23 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Projects({ data, tags }: Props) {
|
export default function Projects({ data, tags }: Props) {
|
||||||
|
function filterProjects(): CollectionEntry<"projects">[] {
|
||||||
|
return data.filter((entry) =>
|
||||||
|
Array.from(filter()).every((value) =>
|
||||||
|
entry.data.tags.some(
|
||||||
|
(tag: string) =>
|
||||||
|
tag.toLowerCase() === String(value).toLowerCase(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const [filter, setFilter] = createSignal(new Set<string>());
|
const [filter, setFilter] = createSignal(new Set<string>());
|
||||||
const [projects, setProjects] = createSignal<CollectionEntry<"projects">[]>(
|
const [projects, setProjects] =
|
||||||
[]
|
createSignal<CollectionEntry<"projects">[]>(filterProjects());
|
||||||
);
|
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
setProjects(
|
setProjects(filterProjects());
|
||||||
data.filter((entry) =>
|
|
||||||
Array.from(filter()).every((value) =>
|
|
||||||
entry.data.tags.some(
|
|
||||||
(tag: string) =>
|
|
||||||
tag.toLowerCase() === String(value).toLowerCase()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleTag(tag: string) {
|
function toggleTag(tag: string) {
|
||||||
|
|
@ -34,14 +35,14 @@ export default function Projects({ data, tags }: Props) {
|
||||||
new Set(
|
new Set(
|
||||||
prev.has(tag)
|
prev.has(tag)
|
||||||
? [...prev].filter((t) => t !== tag)
|
? [...prev].filter((t) => t !== tag)
|
||||||
: [...prev, tag]
|
: [...prev, tag],
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
<div class="not-noscript:grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||||
<div class="col-span-3 sm:col-span-1">
|
<div class="col-span-3 sm:col-span-1 noscript:hidden">
|
||||||
<div class="sticky top-24">
|
<div class="sticky top-24">
|
||||||
<div class="text-sm font-semibold font-departure uppercase mb-2 text-black dark:text-white">
|
<div class="text-sm font-semibold font-departure uppercase mb-2 text-black dark:text-white">
|
||||||
Filter
|
Filter
|
||||||
|
|
@ -60,21 +61,27 @@ export default function Projects({ data, tags }: Props) {
|
||||||
"hover:bg-black/10 hover:dark:bg-white/15",
|
"hover:bg-black/10 hover:dark:bg-white/15",
|
||||||
"transition-colors duration-300 ease-in-out",
|
"transition-colors duration-300 ease-in-out",
|
||||||
filter().has(tag) &&
|
filter().has(tag) &&
|
||||||
"text-black dark:text-white"
|
"text-black dark:text-white",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div class={cn(
|
<div
|
||||||
"relative size-5 fill-black/50 dark:fill-white/50",
|
class={cn(
|
||||||
"transition-colors duration-300 ease-in-out",
|
"relative size-5 fill-black/50 dark:fill-white/50",
|
||||||
filter().has(tag) &&
|
"transition-colors duration-300 ease-in-out",
|
||||||
"fill-black dark:fill-white"
|
filter().has(tag) &&
|
||||||
)}>
|
"fill-black dark:fill-white",
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Icon icon="pixelarticons:square" />
|
<Icon icon="pixelarticons:square" />
|
||||||
<Icon icon="pixel:check" class={cn("absolute top-0 right-0",
|
<Icon
|
||||||
filter().has(tag)
|
icon="pixel:check"
|
||||||
? "block"
|
class={cn(
|
||||||
: "hidden"
|
"absolute top-0 right-0",
|
||||||
)} />
|
filter().has(tag)
|
||||||
|
? "block"
|
||||||
|
: "hidden",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{tag}
|
{tag}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,10 @@ const { suffix } = Astro.props;
|
||||||
name="doomsday-year"
|
name="doomsday-year"
|
||||||
id="doomsday-year"
|
id="doomsday-year"
|
||||||
min="1583"
|
min="1583"
|
||||||
class="w-16 font-departure"
|
class="w-16 font-departure noscript:hidden"
|
||||||
/><span class="noscript-hide">{suffix}</span>
|
/><span class="text-red-500 not-noscript:hidden"
|
||||||
<noscript>
|
>JavaScript is required for this feature to work</span
|
||||||
<span class="text-red-500"
|
>{suffix}
|
||||||
>JavaScript is required for this feature to work.</span
|
|
||||||
>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#doomsday-year {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</noscript>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const currentYearInput = document.getElementById(
|
const currentYearInput = document.getElementById(
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ First, we take the last two digits of the year. If this number is odd, we add 11
|
||||||
Finally, we take 7 minus modulo 7 of the result and count forward that many days from the Doomsday of the century. The resulting weekday is the Doomsday of the year.
|
Finally, we take 7 minus modulo 7 of the result and count forward that many days from the Doomsday of the century. The resulting weekday is the Doomsday of the year.
|
||||||
This algorithm can be remembered with the following flowchart:
|
This algorithm can be remembered with the following flowchart:
|
||||||
|
|
||||||
|
<div class="noscript:hidden">
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
B[Let T = last two digits of year] --> C{Is T odd?}
|
B[Let T = last two digits of year] --> C{Is T odd?}
|
||||||
|
|
@ -116,6 +117,10 @@ flowchart TD
|
||||||
|
|
||||||
K --> L[Doomsday of the year]
|
K --> L[Doomsday of the year]
|
||||||
```
|
```
|
||||||
|
</div>
|
||||||
|
<div class="not-noscript:hidden font-semibold italic">
|
||||||
|
Please enable JavaScript to see the flowchart for the first method.
|
||||||
|
</div>
|
||||||
|
|
||||||
The second method is more mathematical and follows the steps:
|
The second method is more mathematical and follows the steps:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,12 +84,19 @@
|
||||||
.animate {
|
.animate {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(5px);
|
transform: translateY(5px);
|
||||||
transition: opacity 1s ease, transform 1s ease;
|
animation: fadeInUp 1s forwards;
|
||||||
|
animation-delay: 0.5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate.show {
|
@keyframes fadeInUp {
|
||||||
opacity: 1;
|
0% {
|
||||||
transform: translateY(0);
|
opacity: 0;
|
||||||
|
transform: translateY(5px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
article img {
|
article img {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue