redesign: finish blog & projects
This commit is contained in:
parent
e09e36ccb7
commit
4080f8b3b3
|
|
@ -19,6 +19,7 @@
|
|||
"@astrojs/rss": "^4.0.17",
|
||||
"@astrojs/sitemap": "^3.6.0",
|
||||
"@astrojs/solid-js": "^6.0.0",
|
||||
"@iconify-icon/solid": "^3.0.3",
|
||||
"@iconify-json/devicon": "^1.2.61",
|
||||
"@iconify-json/material-icon-theme": "^1.2.56",
|
||||
"@iconify-json/pixel": "^1.2.1",
|
||||
|
|
@ -31,6 +32,7 @@
|
|||
"canvaskit-wasm": "^0.40.0",
|
||||
"clsx": "^2.1.1",
|
||||
"fuse.js": "^7.1.0",
|
||||
"iconify-icon": "^3.0.2",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"sharp": "^0.34.5",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ importers:
|
|||
'@astrojs/solid-js':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(solid-js@1.9.11)(yaml@2.8.2)
|
||||
'@iconify-icon/solid':
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3(solid-js@1.9.11)
|
||||
'@iconify-json/devicon':
|
||||
specifier: ^1.2.61
|
||||
version: 1.2.61
|
||||
|
|
@ -59,6 +62,9 @@ importers:
|
|||
fuse.js:
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0
|
||||
iconify-icon:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
rehype-katex:
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1
|
||||
|
|
@ -426,6 +432,11 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@iconify-icon/solid@3.0.3':
|
||||
resolution: {integrity: sha512-VUM8/gscfrU0e6dUWjitdsJrNzYoY1bGTp1+gfZIAbvo+tIGcP9bD3WAvFb6pHaCYL/5X6erZUUn8pL0c0xX9Q==}
|
||||
peerDependencies:
|
||||
solid-js: '>=1.0.0'
|
||||
|
||||
'@iconify-json/devicon@1.2.61':
|
||||
resolution: {integrity: sha512-GvJZrzyWbChwki9yscm8WaCfIHqFVi4hQbjNxoDS0JLsuAk4uyGOnmlHCJFN+SzAZ9FMU2RtmkdJGjYuw4G96w==}
|
||||
|
||||
|
|
@ -1501,6 +1512,9 @@ packages:
|
|||
http-cache-semantics@4.2.0:
|
||||
resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
|
||||
|
||||
iconify-icon@3.0.2:
|
||||
resolution: {integrity: sha512-DYPAumiUeUeT/GHT8x2wrAVKn1FqZJqFH0Y5pBefapWRreV1BBvqBVMb0020YQ2njmbR59r/IathL2d2OrDrxA==}
|
||||
|
||||
iconv-lite@0.6.3:
|
||||
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -3021,6 +3035,11 @@ snapshots:
|
|||
'@esbuild/win32-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@iconify-icon/solid@3.0.3(solid-js@1.9.11)':
|
||||
dependencies:
|
||||
iconify-icon: 3.0.2
|
||||
solid-js: 1.9.11
|
||||
|
||||
'@iconify-json/devicon@1.2.61':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
|
@ -4237,6 +4256,10 @@ snapshots:
|
|||
|
||||
http-cache-semantics@4.2.0: {}
|
||||
|
||||
iconify-icon@3.0.2:
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
iconv-lite@0.6.3:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import ArrowCardInner from "./ArrowCardInner";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
|
||||
export interface Props {
|
||||
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
|
||||
pill?: string;
|
||||
}
|
||||
|
||||
const { entry, pill } = Astro.props;
|
||||
---
|
||||
|
||||
<ArrowCardInner {entry} {pill}>
|
||||
<div class="relative overflow-hidden w-4 h-4">
|
||||
<Icon
|
||||
name="pixelarticons:arrow-right"
|
||||
class:list="absolute right-0 inset-y-0 text-lg origin-left
|
||||
scale-x-0 group-hover:scale-x-100
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
<Icon
|
||||
name="pixelarticons:chevron-right"
|
||||
class:list="absolute right-0 inset-y-0 text-lg
|
||||
group-hover:translate-x-4
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</ArrowCardInner>
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { formatDate } from "@/lib/utils";
|
||||
import { children } from "solid-js";
|
||||
import { Icon } from '@iconify-icon/solid';
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
|
||||
pill?: string;
|
||||
children: any;
|
||||
};
|
||||
|
||||
export default function ArrowCard({ entry, pill, children: c }: Props) {
|
||||
const arrow = children(() => c).toArray();
|
||||
export default function ArrowCard({ entry, pill }: Props) {
|
||||
return (
|
||||
<a
|
||||
href={`/${entry.collection}/${entry.id}/`}
|
||||
|
|
@ -42,7 +40,20 @@ export default function ArrowCard({ entry, pill, children: c }: Props) {
|
|||
)}
|
||||
</ul>
|
||||
</div>
|
||||
{arrow}
|
||||
<div class="relative overflow-hidden w-4 h-4">
|
||||
<Icon
|
||||
icon="pixelarticons:arrow-right"
|
||||
class="absolute right-0 inset-y-0 text-lg origin-left
|
||||
scale-x-0 group-hover:scale-x-100
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
<Icon
|
||||
icon="pixelarticons:chevron-right"
|
||||
class="absolute right-0 inset-y-0 text-lg
|
||||
group-hover:translate-x-4
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
import { render, type CollectionEntry } from "astro:content";
|
||||
import Container from "./Container.astro";
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<"projects"> | CollectionEntry<"blog">;
|
||||
};
|
||||
|
||||
const { entry } = Astro.props;
|
||||
|
||||
const { Content } = await render(entry);
|
||||
---
|
||||
|
||||
<Container size="md">
|
||||
<article class="animate content">
|
||||
<Content />
|
||||
</article>
|
||||
</Container>
|
||||
|
||||
<style is:global>
|
||||
article.content :is(h1, h2, h3, h4, h5, h6) {
|
||||
font-family: "DepartureMono", monospace;
|
||||
}
|
||||
|
||||
article.content a {
|
||||
font-family: "DepartureMono", monospace;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
article.content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -97,6 +97,10 @@ const { title, description, image = "/open-graph.jpg" } = Astro.props;
|
|||
);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import "iconify-icon";
|
||||
</script>
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/katex@0.16.27/dist/katex.css"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
import type { CollectionEntry } from "astro:content";
|
||||
import { createEffect, createSignal, For, Show } from "solid-js";
|
||||
import ArrowCard from "@/components/ArrowCard";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Icon } from "@iconify-icon/solid";
|
||||
|
||||
type Props = {
|
||||
tags: string[];
|
||||
data: CollectionEntry<"blog">[];
|
||||
};
|
||||
|
||||
export default function Blog({ data, tags }: Props) {
|
||||
const [filter, setFilter] = createSignal(new Set<string>());
|
||||
const [posts, setPosts] = createSignal<CollectionEntry<"blog">[]>([]);
|
||||
|
||||
createEffect(() => {
|
||||
setPosts(
|
||||
data.filter((entry) =>
|
||||
Array.from(filter()).every((value) =>
|
||||
entry.data.tags.some(
|
||||
(tag: string) =>
|
||||
tag.toLowerCase() === String(value).toLowerCase()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
function toggleTag(tag: string) {
|
||||
setFilter(
|
||||
(prev) =>
|
||||
new Set(
|
||||
prev.has(tag)
|
||||
? [...prev].filter((t) => t !== tag)
|
||||
: [...prev, tag]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
<div class="sticky top-24">
|
||||
<div class="text-sm font-semibold font-departure uppercase mb-2 text-black dark:text-white">
|
||||
Filter
|
||||
</div>
|
||||
<ul class="flex flex-wrap sm:flex-col gap-1.5">
|
||||
<For each={tags}>
|
||||
{(tag) => (
|
||||
<li>
|
||||
<button
|
||||
onClick={() => toggleTag(tag)}
|
||||
class={cn(
|
||||
"w-full px-2 py-1 rounded font-departure",
|
||||
"whitespace-nowrap overflow-hidden overflow-ellipsis",
|
||||
"flex gap-2 items-center",
|
||||
"bg-black/5 dark:bg-white/10",
|
||||
"hover:bg-black/10 hover:dark:bg-white/15",
|
||||
"transition-colors duration-300 ease-in-out",
|
||||
filter().has(tag) &&
|
||||
"text-black dark:text-white"
|
||||
)}
|
||||
>
|
||||
<div class={cn(
|
||||
"relative size-5 fill-black/50 dark:fill-white/50",
|
||||
"transition-colors duration-300 ease-in-out",
|
||||
filter().has(tag) &&
|
||||
"fill-black dark:fill-white"
|
||||
)}>
|
||||
<Icon icon="pixelarticons:square" />
|
||||
<Icon icon="pixel:check" class={cn("absolute top-0 right-0",
|
||||
filter().has(tag)
|
||||
? "block"
|
||||
: "hidden"
|
||||
)} />
|
||||
</div>
|
||||
{tag}
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2">
|
||||
<div class="flex flex-col">
|
||||
<div class="text-sm font-departure uppercase mb-2">
|
||||
SHOWING {posts().length} OF {data.length} POSTS
|
||||
</div>
|
||||
<ul class="flex flex-col gap-3">
|
||||
{posts().map((post) => (
|
||||
<li>
|
||||
<ArrowCard entry={post} />
|
||||
</li>
|
||||
))}
|
||||
|
||||
<Show when={posts().length == 0}>
|
||||
<h3 class="mt-5 text-2xl font-departure">
|
||||
There seem to be no blogs matching the filters
|
||||
yet...
|
||||
</h3>
|
||||
</Show>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ const subpath = pathname.match(/[^/]+/g);
|
|||
src={pictureOfMe}
|
||||
loading="eager"
|
||||
alt="Me"
|
||||
class="size-6 fill-current rounded-lg"
|
||||
class="size-6 fill-current rounded-lg mr-2"
|
||||
quality="low"
|
||||
/>
|
||||
<div class="font-departure font-bold">
|
||||
|
|
@ -49,7 +49,7 @@ const subpath = pathname.match(/[^/]+/g);
|
|||
"flex items-center justify-center",
|
||||
"transition-colors duration-300 ease-in-out",
|
||||
pathname === LINK.HREF ||
|
||||
"/" + subpath?.[0] === LINK.HREF
|
||||
"/" + subpath?.[0] + "/" === LINK.HREF
|
||||
? "bg-black dark:bg-white text-white dark:text-black"
|
||||
: "hover:bg-black/5 dark:hover:bg-white/20 hover:text-black dark:hover:text-white",
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
import type { CollectionEntry } from "astro:content";
|
||||
import { createEffect, createSignal, For, Show } from "solid-js";
|
||||
import ArrowCard from "@/components/ArrowCard";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Icon } from "@iconify-icon/solid";
|
||||
|
||||
type Props = {
|
||||
tags: string[];
|
||||
data: CollectionEntry<"projects">[];
|
||||
};
|
||||
|
||||
export default function Projects({ data, tags }: Props) {
|
||||
const [filter, setFilter] = createSignal(new Set<string>());
|
||||
const [projects, setProjects] = createSignal<CollectionEntry<"projects">[]>(
|
||||
[]
|
||||
);
|
||||
|
||||
createEffect(() => {
|
||||
setProjects(
|
||||
data.filter((entry) =>
|
||||
Array.from(filter()).every((value) =>
|
||||
entry.data.tags.some(
|
||||
(tag: string) =>
|
||||
tag.toLowerCase() === String(value).toLowerCase()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
function toggleTag(tag: string) {
|
||||
setFilter(
|
||||
(prev) =>
|
||||
new Set(
|
||||
prev.has(tag)
|
||||
? [...prev].filter((t) => t !== tag)
|
||||
: [...prev, tag]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
<div class="sticky top-24">
|
||||
<div class="text-sm font-semibold font-departure uppercase mb-2 text-black dark:text-white">
|
||||
Filter
|
||||
</div>
|
||||
<ul class="flex flex-wrap sm:flex-col gap-1.5">
|
||||
<For each={tags}>
|
||||
{(tag) => (
|
||||
<li>
|
||||
<button
|
||||
onClick={() => toggleTag(tag)}
|
||||
class={cn(
|
||||
"w-full px-2 py-1 rounded font-departure",
|
||||
"whitespace-nowrap overflow-hidden overflow-ellipsis",
|
||||
"flex gap-2 items-center",
|
||||
"bg-black/5 dark:bg-white/10",
|
||||
"hover:bg-black/10 hover:dark:bg-white/15",
|
||||
"transition-colors duration-300 ease-in-out",
|
||||
filter().has(tag) &&
|
||||
"text-black dark:text-white"
|
||||
)}
|
||||
>
|
||||
<div class={cn(
|
||||
"relative size-5 fill-black/50 dark:fill-white/50",
|
||||
"transition-colors duration-300 ease-in-out",
|
||||
filter().has(tag) &&
|
||||
"fill-black dark:fill-white"
|
||||
)}>
|
||||
<Icon icon="pixelarticons:square" />
|
||||
<Icon icon="pixel:check" class={cn("absolute top-0 right-0",
|
||||
filter().has(tag)
|
||||
? "block"
|
||||
: "hidden"
|
||||
)} />
|
||||
</div>
|
||||
{tag}
|
||||
</button>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-2">
|
||||
<div class="flex flex-col">
|
||||
<div class="text-sm font-departure uppercase mb-2">
|
||||
SHOWING {projects().length} OF {data.length} PROJECTS
|
||||
</div>
|
||||
<ul class="flex flex-col gap-3">
|
||||
{projects().map((project) => (
|
||||
<li>
|
||||
<ArrowCard entry={project} />
|
||||
</li>
|
||||
))}
|
||||
<Show when={projects().length == 0}>
|
||||
<h3 class="mt-5 text-2xl font-departure">
|
||||
There seem to be no projects matching the
|
||||
filters yet...
|
||||
</h3>
|
||||
</Show>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
import type { CollectionEntry } from "astro:content"
|
||||
import { createEffect, createSignal } from "solid-js"
|
||||
import Fuse from "fuse.js"
|
||||
// import ArrowCard from "@components/ArrowCard"
|
||||
import ArrowCard from "@/components/ArrowCard"
|
||||
|
||||
type Props = {
|
||||
data: CollectionEntry<"blog">[]
|
||||
}
|
||||
|
||||
export default function Search({data}: Props) {
|
||||
export default function Search({ data }: Props) {
|
||||
const [query, setQuery] = createSignal("")
|
||||
const [results, setResults] = createSignal<CollectionEntry<"blog">[]>([])
|
||||
|
||||
|
|
@ -34,21 +34,20 @@ export default function Search({data}: Props) {
|
|||
return (
|
||||
<div class="flex flex-col">
|
||||
<div class="relative">
|
||||
<input name="search" type="text" value={query()} onInput={onInput} autocomplete="off" spellcheck={false} placeholder="What are you looking for?" class="w-full px-2.5 py-1.5 pl-10 rounded outline-none text-black dark:text-white bg-black/5 dark:bg-white/15 border border-black/10 dark:border-white/20 focus:border-black focus:dark:border-white"/>
|
||||
<input name="search" type="text" value={query()} onInput={onInput} autocomplete="off" spellcheck={false} placeholder="What are you looking for?" class="w-full px-2.5 py-1.5 pl-10 rounded outline-none text-black dark:text-white bg-black/5 dark:bg-white/15 border border-black/10 dark:border-white/20 focus:border-black focus:dark:border-white" />
|
||||
<svg class="absolute size-6 left-1.5 top-1/2 -translate-y-1/2 stroke-current">
|
||||
<use href={`/ui.svg#search`}/>
|
||||
<use href={`/ui.svg#search`} />
|
||||
</svg>
|
||||
</div>
|
||||
{(query().length >= 2 && results().length >= 1) && (
|
||||
<div class="mt-12">
|
||||
<div class="text-sm uppercase mb-2">
|
||||
<div class="text-sm uppercase mb-2 font-departure">
|
||||
Found {results().length} results for {`'${query()}'`}
|
||||
</div>
|
||||
<ul class="flex flex-col gap-3">
|
||||
{results().map(result => (
|
||||
<li>
|
||||
{/* <ArrowCard entry={result} pill={true} /> */}
|
||||
<div>{JSON.stringify(result, undefined, 2)}</div>
|
||||
<ArrowCard entry={result} pill={result.collection} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
import { type CollectionEntry, getCollection, render } from "astro:content";
|
||||
import { type CollectionEntry, getCollection } from "astro:content";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<"blog"> | CollectionEntry<"projects">;
|
||||
|
|
@ -8,7 +9,6 @@ type Props = {
|
|||
// Get the requested entry
|
||||
const { entry } = Astro.props;
|
||||
const { collection } = entry;
|
||||
const { Content } = await render(entry);
|
||||
|
||||
// Get the next and prev entries (modulo to wrap index)
|
||||
const items = (await getCollection(collection))
|
||||
|
|
@ -20,9 +20,6 @@ const next = items[(index - 1 + items.length) % items.length];
|
|||
---
|
||||
|
||||
<div>
|
||||
<article>
|
||||
<Content />
|
||||
</article>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<a
|
||||
href={`/${prev.collection}/${prev.id}/`}
|
||||
|
|
@ -32,35 +29,26 @@ const next = items[(index - 1 + items.length) % items.length];
|
|||
class="order-2 w-full h-full group-hover:text-black group-hover:dark:text-white blend"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div class="text-sm uppercase">Prev</div>
|
||||
<div class="text-sm font-departure uppercase">Prev</div>
|
||||
</div>
|
||||
<div class="font-semibold mt-3 text-black dark:text-white">
|
||||
{prev.data.title}
|
||||
</div>
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="order-1 stroke-current group-hover:stroke-black group-hover:dark:stroke-white rotate-180"
|
||||
>
|
||||
<line
|
||||
x1="5"
|
||||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out"
|
||||
></line>
|
||||
<polyline
|
||||
points="12 5 19 12 12 19"
|
||||
class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out"
|
||||
></polyline>
|
||||
</svg>
|
||||
<div class="relative overflow-hidden w-4 h-4">
|
||||
<Icon
|
||||
name="pixelarticons:arrow-left"
|
||||
class:list="absolute left-0 inset-y-0 text-lg origin-right
|
||||
scale-x-0 group-hover:scale-x-100
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
<Icon
|
||||
name="pixelarticons:chevron-left"
|
||||
class:list="absolute left-0 inset-y-0 text-lg
|
||||
group-hover:-translate-x-4
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href={`/${next.collection}/${next.id}/`}
|
||||
|
|
@ -69,34 +57,25 @@ const next = items[(index - 1 + items.length) % items.length];
|
|||
<div
|
||||
class="w-full h-full text-right group-hover:text-black group-hover:dark:text-white blend"
|
||||
>
|
||||
<div class="text-sm uppercase">Next</div>
|
||||
<div class="text-sm font-departure uppercase">Next</div>
|
||||
<div class="font-semibold mt-3 text-black dark:text-white">
|
||||
{next.data.title}
|
||||
</div>
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white"
|
||||
>
|
||||
<line
|
||||
x1="5"
|
||||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
class="scale-x-0 group-hover:scale-x-100 translate-x-4 group-hover:translate-x-1 transition-all duration-300 ease-in-out"
|
||||
></line>
|
||||
<polyline
|
||||
points="12 5 19 12 12 19"
|
||||
class="translate-x-0 group-hover:translate-x-1 transition-all duration-300 ease-in-out"
|
||||
></polyline>
|
||||
</svg>
|
||||
<div class="relative overflow-hidden w-4 h-4">
|
||||
<Icon
|
||||
name="pixelarticons:arrow-right"
|
||||
class:list="absolute right-0 inset-y-0 text-lg origin-left
|
||||
scale-x-0 group-hover:scale-x-100
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
<Icon
|
||||
name="pixelarticons:chevron-right"
|
||||
class:list="absolute right-0 inset-y-0 text-lg
|
||||
group-hover:translate-x-4
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import { formatDate, readingTime } from "@/lib/utils";
|
||||
|
||||
type Props = {
|
||||
|
|
@ -19,50 +20,41 @@ const repoUrl = collection === "projects" ? data.repoUrl : null;
|
|||
href={`/${collection}/`}
|
||||
class="group w-fit p-1.5 gap-1.5 text-sm flex items-center border rounded hover:bg-black/5 hover:dark:bg-white/10 border-black/15 dark:border-white/20 transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="stroke-current group-hover:stroke-black group-hover:dark:stroke-white"
|
||||
>
|
||||
<line
|
||||
x1="19"
|
||||
y1="12"
|
||||
x2="5"
|
||||
y2="12"
|
||||
class="scale-x-0 group-hover:scale-x-100 translate-x-3 group-hover:translate-x-0 transition-all duration-300 ease-in-out"
|
||||
></line>
|
||||
<polyline
|
||||
points="12 19 5 12 12 5"
|
||||
class="translate-x-1 group-hover:translate-x-0 transition-all duration-300 ease-in-out"
|
||||
></polyline>
|
||||
</svg>
|
||||
<div class="relative overflow-hidden w-4 h-4">
|
||||
<Icon
|
||||
name="pixelarticons:arrow-left"
|
||||
class:list="absolute left-0 inset-y-0 text-lg origin-right
|
||||
scale-x-0 group-hover:scale-x-100
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
<Icon
|
||||
name="pixelarticons:chevron-left"
|
||||
class:list="absolute left-0 inset-y-0 text-lg
|
||||
group-hover:-translate-x-4
|
||||
transition-all duration-300 ease-in-out"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="w-full group-hover:text-black group-hover:dark:text-white transition-colors duration-300 ease-in-out"
|
||||
class="w-full font-departure group-hover:text-black group-hover:dark:text-white transition-colors duration-300 ease-in-out"
|
||||
>
|
||||
Back to {collection}
|
||||
</div>
|
||||
</a>
|
||||
<div class="flex flex-wrap text-sm uppercase mt-12 gap-3 opacity-75">
|
||||
<div
|
||||
class="flex flex-wrap text-sm font-departure uppercase mt-12 gap-3 opacity-75"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="size-5 stroke-current">
|
||||
<use href="/ui.svg#calendar"></use>
|
||||
</svg>
|
||||
<Icon name="pixelarticons:calendar-2" class:list="size-5" />
|
||||
{formatDate(date)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="size-5 stroke-current">
|
||||
<use href="/ui.svg#book-open"></use>
|
||||
</svg>
|
||||
<Icon name="pixelarticons:book-open" class:list="size-5" />
|
||||
{readingTime(body ?? "")}
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="text-3xl font-semibold text-black dark:text-white mt-2">
|
||||
<h1
|
||||
class="text-3xl font-semibold font-departure text-black dark:text-white mt-2"
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
<div class="mt-1">
|
||||
|
|
@ -77,13 +69,8 @@ const repoUrl = collection === "projects" ? data.repoUrl : null;
|
|||
target="_blank"
|
||||
class="group flex gap-2 items-center px-3 py-1.5 truncate rounded text-xs md:text-sm lg:text-base border border-black/25 dark:border-white/25 hover:bg-black/5 hover:dark:bg-white/15 blend"
|
||||
>
|
||||
<svg class="size-4">
|
||||
<use
|
||||
href="/ui.svg#globe"
|
||||
class="fill-current group-hover:fill-black group-hover:dark:fill-white blend"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-current group-hover:text-black group-hover:dark:text-white blend">
|
||||
<Icon name="pixelarticons:globe" class:list="size-4" />
|
||||
<span class="text-current font-departure group-hover:text-black group-hover:dark:text-white blend">
|
||||
See Demo
|
||||
</span>
|
||||
</a>
|
||||
|
|
@ -94,13 +81,8 @@ const repoUrl = collection === "projects" ? data.repoUrl : null;
|
|||
target="_blank"
|
||||
class="group flex gap-2 items-center px-3 py-1.5 truncate rounded text-xs md:text-sm lg:text-base border border-black/25 dark:border-white/25 hover:bg-black/5 hover:dark:bg-white/15 blend"
|
||||
>
|
||||
<svg class="size-4">
|
||||
<use
|
||||
href="/ui.svg#link"
|
||||
class="fill-current group-hover:fill-black group-hover:dark:fill-white blend"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-current group-hover:text-black group-hover:dark:text-white blend">
|
||||
<Icon name="pixelarticons:link" class:list="size-4" />
|
||||
<span class="text-current font-departure group-hover:text-black group-hover:dark:text-white blend">
|
||||
See Repository
|
||||
</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import TopLayout from "@/layouts/TopLayout.astro";
|
|||
import BottomLayout from "@/layouts/BottomLayout.astro";
|
||||
import ArticleTopLayout from "@/layouts/ArticleTopLayout.astro";
|
||||
import ArticleBottomLayout from "@/layouts/ArticleBottomLayout.astro";
|
||||
import ArticleContent from "@/components/ArticleContent.astro";
|
||||
|
||||
// Create the static blog pages
|
||||
export async function getStaticPaths() {
|
||||
|
|
@ -33,6 +34,7 @@ const { title, summary } = post.data;
|
|||
<ArticleTopLayout entry={post} />
|
||||
</div>
|
||||
</TopLayout>
|
||||
<ArticleContent entry={post} />
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<ArticleBottomLayout entry={post} />
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import PageLayout from "@/layouts/PageLayout.astro";
|
|||
import TopLayout from "@/layouts/TopLayout.astro";
|
||||
import BottomLayout from "@/layouts/BottomLayout.astro";
|
||||
import { BLOG } from "@/consts";
|
||||
import Blog from "@/components/Blog";
|
||||
|
||||
const posts = (await getCollection("blog"))
|
||||
.filter((post) => !post.data.draft)
|
||||
|
|
@ -22,9 +23,7 @@ const tags = [...new Set(posts.flatMap((post) => post.data.tags))].sort(
|
|||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<!-- <Blog client:load tags={tags} data={posts} /> -->
|
||||
<div>{JSON.stringify(posts)}</div>
|
||||
<div>{JSON.stringify(tags)}</div>
|
||||
<Blog client:load tags={tags} data={posts} />
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import PageLayout from "@/layouts/PageLayout.astro";
|
||||
import ArrowCard from "@/components/ArrowCard.astro";
|
||||
import ArrowCard from "@/components/ArrowCard";
|
||||
import StackCard from "@/components/StackCard.astro";
|
||||
import { SITE, SOCIALS } from "@/consts";
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import TopLayout from "@/layouts/TopLayout.astro";
|
|||
import BottomLayout from "@/layouts/BottomLayout.astro";
|
||||
import ArticleTopLayout from "@/layouts/ArticleTopLayout.astro";
|
||||
import ArticleBottomLayout from "@/layouts/ArticleBottomLayout.astro";
|
||||
import ArticleContent from "@/components/ArticleContent.astro";
|
||||
|
||||
// Create the static projects pages
|
||||
export async function getStaticPaths() {
|
||||
|
|
@ -33,6 +34,7 @@ const { title, summary } = project.data;
|
|||
<ArticleTopLayout entry={project} />
|
||||
</div>
|
||||
</TopLayout>
|
||||
<ArticleContent entry={project} />
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<ArticleBottomLayout entry={project} />
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { getCollection } from "astro:content";
|
|||
import PageLayout from "@/layouts/PageLayout.astro";
|
||||
import TopLayout from "@/layouts/TopLayout.astro";
|
||||
import BottomLayout from "@/layouts/BottomLayout.astro";
|
||||
// import Projects from "@components/Projects";
|
||||
import Projects from "@/components/Projects";
|
||||
import { PROJECTS } from "@/consts";
|
||||
|
||||
const projects = (await getCollection("projects"))
|
||||
|
|
@ -23,9 +23,7 @@ const tags = [
|
|||
</TopLayout>
|
||||
<BottomLayout>
|
||||
<div class="animate">
|
||||
<!-- <Projects client:load tags={tags} data={projects} /> -->
|
||||
<div>{JSON.stringify(projects)}</div>
|
||||
<div>{JSON.stringify(tags)}</div>
|
||||
<Projects client:load tags={tags} data={projects} />
|
||||
</div>
|
||||
</BottomLayout>
|
||||
</PageLayout>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const data = [...posts, ...projects] as CollectionEntry<"blog">[];
|
|||
|
||||
<PageLayout title={SEARCH.TITLE} description={SEARCH.DESCRIPTION}>
|
||||
<TopLayout>
|
||||
<div class="animate page-heading">
|
||||
<div class="animate page-heading font-departure">
|
||||
{SEARCH.TITLE}
|
||||
</div>
|
||||
</TopLayout>
|
||||
|
|
|
|||
Loading…
Reference in New Issue