the horrors
This commit is contained in:
parent
0d9be3d002
commit
4245370f61
48 changed files with 2513 additions and 265 deletions
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"src/styles/global.css": "tailwindcss"
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,13 @@
|
|||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({});
|
||||
export default defineConfig({
|
||||
site: "https://ivyneeds.rest",
|
||||
prefetch: true,
|
||||
vite: {
|
||||
plugins: [tailwindcss()]
|
||||
}
|
||||
});
|
|
@ -6,9 +6,14 @@
|
|||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
"astro": "astro",
|
||||
"test": "ava"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^5.4.3"
|
||||
"@tailwindcss/vite": "^4.0.13",
|
||||
"astro": "^5.4.3",
|
||||
"ava": "^6.2.0",
|
||||
"luxon": "^3.5.0",
|
||||
"tailwindcss": "^4.0.13"
|
||||
}
|
||||
}
|
1454
pnpm-lock.yaml
generated
1454
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,9 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
Before Width: | Height: | Size: 749 B |
BIN
public/images/ivy.png
Normal file
BIN
public/images/ivy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 451 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="115" height="48"><path fill="#17191E" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="url(#a)" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="#17191E" d="M.02 30.31s4.02-1.95 8.05-1.95l3.04-9.4c.11-.45.44-.76.82-.76.37 0 .7.31.82.76l3.04 9.4c4.77 0 8.05 1.95 8.05 1.95L17 11.71c-.2-.56-.53-.91-.98-.91H7.83c-.44 0-.76.35-.97.9L.02 30.31Zm42.37-5.97c0 1.64-2.05 2.62-4.88 2.62-1.85 0-2.5-.45-2.5-1.41 0-1 .8-1.49 2.65-1.49 1.67 0 3.09.03 4.73.23v.05Zm.03-2.04a21.37 21.37 0 0 0-4.37-.36c-5.32 0-7.82 1.25-7.82 4.18 0 3.04 1.71 4.2 5.68 4.2 3.35 0 5.63-.84 6.46-2.92h.14c-.03.5-.05 1-.05 1.4 0 1.07.18 1.16 1.06 1.16h4.15a16.9 16.9 0 0 1-.36-4c0-1.67.06-2.93.06-4.62 0-3.45-2.07-5.64-8.56-5.64-2.8 0-5.9.48-8.26 1.19.22.93.54 2.83.7 4.06 2.04-.96 4.95-1.37 7.2-1.37 3.11 0 3.97.71 3.97 2.15v.57Zm11.37 3c-.56.07-1.33.07-2.12.07-.83 0-1.6-.03-2.12-.1l-.02.58c0 2.85 1.87 4.52 8.45 4.52 6.2 0 8.2-1.64 8.2-4.55 0-2.74-1.33-4.09-7.2-4.39-4.58-.2-4.99-.7-4.99-1.28 0-.66.59-1 3.65-1 3.18 0 4.03.43 4.03 1.35v.2a46.13 46.13 0 0 1 4.24.03l.02-.55c0-3.36-2.8-4.46-8.2-4.46-6.08 0-8.13 1.49-8.13 4.39 0 2.6 1.64 4.23 7.48 4.48 4.3.14 4.77.62 4.77 1.28 0 .7-.7 1.03-3.71 1.03-3.47 0-4.35-.48-4.35-1.47v-.13Zm19.82-12.05a17.5 17.5 0 0 1-6.24 3.48c.03.84.03 2.4.03 3.24l1.5.02c-.02 1.63-.04 3.6-.04 4.9 0 3.04 1.6 5.32 6.58 5.32 2.1 0 3.5-.23 5.23-.6a43.77 43.77 0 0 1-.46-4.13c-1.03.34-2.34.53-3.78.53-2 0-2.82-.55-2.82-2.13 0-1.37 0-2.65.03-3.84 2.57.02 5.13.07 6.64.11-.02-1.18.03-2.9.1-4.04-2.2.04-4.65.07-6.68.07l.07-2.93h-.16Zm13.46 6.04a767.33 767.33 0 0 1 .07-3.18H82.6c.07 1.96.07 3.98.07 6.92 0 2.95-.03 4.99-.07 6.93h5.18c-.09-1.37-.11-3.68-.11-5.65 0-3.1 1.26-4 4.12-4 1.33 0 2.28.16 3.1.46.03-1.16.26-3.43.4-4.43-.86-.25-1.81-.41-2.96-.41-2.46-.03-4.26.98-5.1 3.38l-.17-.02Zm22.55 3.65c0 2.5-1.8 3.66-4.64 3.66-2.81 0-4.61-1.1-4.61-3.66s1.82-3.52 4.61-3.52c2.82 0 4.64 1.03 4.64 3.52Zm4.71-.11c0-4.96-3.87-7.18-9.35-7.18-5.5 0-9.23 2.22-9.23 7.18 0 4.94 3.49 7.59 9.21 7.59 5.77 0 9.37-2.65 9.37-7.6Z"/><defs><linearGradient id="a" x1="6.33" x2="19.43" y1="40.8" y2="34.6" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient></defs></svg>
|
Before Width: | Height: | Size: 2.8 KiB |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="1024" fill="none"><path fill="url(#a)" fill-rule="evenodd" d="M-217.58 475.75c91.82-72.02 225.52-29.38 341.2-44.74C240 415.56 372.33 315.14 466.77 384.9c102.9 76.02 44.74 246.76 90.31 366.31 29.83 78.24 90.48 136.14 129.48 210.23 57.92 109.99 169.67 208.23 155.9 331.77-13.52 121.26-103.42 264.33-224.23 281.37-141.96 20.03-232.72-220.96-374.06-196.99-151.7 25.73-172.68 330.24-325.85 315.72-128.6-12.2-110.9-230.73-128.15-358.76-12.16-90.14 65.87-176.25 44.1-264.57-26.42-107.2-167.12-163.46-176.72-273.45-10.15-116.29 33.01-248.75 124.87-320.79Z" clip-rule="evenodd" style="opacity:.154"/><path fill="url(#b)" fill-rule="evenodd" d="M1103.43 115.43c146.42-19.45 275.33-155.84 413.5-103.59 188.09 71.13 409 212.64 407.06 413.88-1.94 201.25-259.28 278.6-414.96 405.96-130 106.35-240.24 294.39-405.6 265.3-163.7-28.8-161.93-274.12-284.34-386.66-134.95-124.06-436-101.46-445.82-284.6-9.68-180.38 247.41-246.3 413.54-316.9 101.01-42.93 207.83 21.06 316.62 6.61Z" clip-rule="evenodd" style="opacity:.154"/><defs><linearGradient id="b" x1="373" x2="1995.44" y1="1100" y2="118.03" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient><linearGradient id="a" x1="107.37" x2="1130.66" y1="1993.35" y2="1026.31" gradientUnits="userSpaceOnUse"><stop stop-color="#3245FF"/><stop offset="1" stop-color="#BC52EE"/></linearGradient></defs></svg>
|
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1,210 +0,0 @@
|
|||
---
|
||||
import astroLogo from '../assets/astro.svg';
|
||||
import background from '../assets/background.svg';
|
||||
---
|
||||
|
||||
<div id="container">
|
||||
<img id="background" src={background.src} alt="" fetchpriority="high" />
|
||||
<main>
|
||||
<section id="hero">
|
||||
<a href="https://astro.build"
|
||||
><img src={astroLogo.src} width="115" height="48" alt="Astro Homepage" /></a
|
||||
>
|
||||
<h1>
|
||||
To get started, open the <code><pre>src/pages</pre></code> directory in your project.
|
||||
</h1>
|
||||
<section id="links">
|
||||
<a class="button" href="https://docs.astro.build">Read our docs</a>
|
||||
<a href="https://astro.build/chat"
|
||||
>Join our Discord <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"
|
||||
><path
|
||||
fill="currentColor"
|
||||
d="M107.7 8.07A105.15 105.15 0 0 0 81.47 0a72.06 72.06 0 0 0-3.36 6.83 97.68 97.68 0 0 0-29.11 0A72.37 72.37 0 0 0 45.64 0a105.89 105.89 0 0 0-26.25 8.09C2.79 32.65-1.71 56.6.54 80.21a105.73 105.73 0 0 0 32.17 16.15 77.7 77.7 0 0 0 6.89-11.11 68.42 68.42 0 0 1-10.85-5.18c.91-.66 1.8-1.34 2.66-2a75.57 75.57 0 0 0 64.32 0c.87.71 1.76 1.39 2.66 2a68.68 68.68 0 0 1-10.87 5.19 77 77 0 0 0 6.89 11.1 105.25 105.25 0 0 0 32.19-16.14c2.64-27.38-4.51-51.11-18.9-72.15ZM42.45 65.69C36.18 65.69 31 60 31 53s5-12.74 11.43-12.74S54 46 53.89 53s-5.05 12.69-11.44 12.69Zm42.24 0C78.41 65.69 73.25 60 73.25 53s5-12.74 11.44-12.74S96.23 46 96.12 53s-5.04 12.69-11.43 12.69Z"
|
||||
></path></svg
|
||||
>
|
||||
</a>
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<a href="https://astro.build/blog/astro-5/" id="news" class="box">
|
||||
<svg width="32" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
d="M24.667 12c1.333 1.414 2 3.192 2 5.334 0 4.62-4.934 5.7-7.334 12C18.444 28.567 18 27.456 18 26c0-4.642 6.667-7.053 6.667-14Zm-5.334-5.333c1.6 1.65 2.4 3.43 2.4 5.333 0 6.602-8.06 7.59-6.4 17.334C13.111 27.787 12 25.564 12 22.666c0-4.434 7.333-8 7.333-16Zm-6-5.333C15.111 3.555 16 5.556 16 7.333c0 8.333-11.333 10.962-5.333 22-3.488-.774-6-4-6-8 0-8.667 8.666-10 8.666-20Z"
|
||||
fill="#111827"></path></svg
|
||||
>
|
||||
<h2>What's New in Astro 5.0?</h2>
|
||||
<p>
|
||||
From content layers to server islands, click to learn more about the new features and
|
||||
improvements in Astro 5.0
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
filter: blur(100px);
|
||||
}
|
||||
|
||||
#container {
|
||||
font-family: Inter, Roboto, 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', Arial, sans-serif;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
main {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#hero {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
#links {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
#links a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
color: #111827;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
#links a:hover {
|
||||
color: rgb(78, 80, 86);
|
||||
}
|
||||
|
||||
#links a svg {
|
||||
height: 1em;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
#links a.button {
|
||||
color: white;
|
||||
background: linear-gradient(83.21deg, #3245ff 0%, #bc52ee 100%);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.12),
|
||||
inset 0 -2px 0 rgba(0, 0, 0, 0.24);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#links a.button:hover {
|
||||
color: rgb(230, 230, 230);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family:
|
||||
ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono',
|
||||
monospace;
|
||||
font-weight: normal;
|
||||
background: linear-gradient(14deg, #d83333 0%, #f041ff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0 0 1em;
|
||||
font-weight: normal;
|
||||
color: #111827;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #4b5563;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
letter-spacing: -0.006em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
display: inline-block;
|
||||
background:
|
||||
linear-gradient(66.77deg, #f3cddd 0%, #f5cee7 100%) padding-box,
|
||||
linear-gradient(155deg, #d83333 0%, #f041ff 18%, #f5cee7 45%) border-box;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
|
||||
.box {
|
||||
padding: 16px;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border-radius: 16px;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
#news {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
max-width: 300px;
|
||||
text-decoration: none;
|
||||
transition: background 0.2s;
|
||||
backdrop-filter: blur(50px);
|
||||
}
|
||||
|
||||
#news:hover {
|
||||
background: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
@media screen and (max-height: 368px) {
|
||||
#news {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
#container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#hero {
|
||||
display: block;
|
||||
padding-top: 10%;
|
||||
}
|
||||
|
||||
#links {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#links a.button {
|
||||
padding: 14px 18px;
|
||||
}
|
||||
|
||||
#news {
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
bottom: 2.5rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
</style>
|
48
src/components/lists/BlogPostList.astro
Normal file
48
src/components/lists/BlogPostList.astro
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
import Date from "~/components/util/Date.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { getPublishedAndSortedPosts } from "~/lib/blog";
|
||||
|
||||
interface Props {
|
||||
collection: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
const { collection, limit } = Astro.props;
|
||||
const items = getPublishedAndSortedPosts(await getCollection(collection));
|
||||
const limitedItems = limit ? items.slice(0, limit) : items;
|
||||
|
||||
const getPostIcon = (item: { data: { icon?: string } }) => {
|
||||
if (item.data.icon && item.data.icon !== "fa-solid fa-blog") {
|
||||
return item.data.icon;
|
||||
}
|
||||
return "fa-solid fa-arrow-right";
|
||||
};
|
||||
---
|
||||
|
||||
<ul class="fa-ul space-y-4 my-2">
|
||||
{
|
||||
limitedItems.map((item) => (
|
||||
<li>
|
||||
<i class={`fa-li ${getPostIcon(item)}`} />
|
||||
|
||||
<a href={`/${collection}/${item.id}`}>
|
||||
<h3 class="font-bold mb-0.5">{item.data.title}</h3>
|
||||
</a>
|
||||
|
||||
<p class="text-sm text-light-tx-2 dark:text-dark-tx-2">
|
||||
<i class="fa-solid fa-calendar-alt mr-1 text-light-pu dark:text-dark-pu" />
|
||||
<Date date={item.data.date} />
|
||||
<i class="fa-solid fa-tags mx-1 text-light-pu dark:text-dark-pu" />
|
||||
{(item.data.tags ?? []).map((tag) => (
|
||||
<a class="bg-light-pu dark:bg-dark-pu text-white px-1 py-0.5 rounded-md" href={`/${collection}/tags/${tag}`}>{tag}</a>
|
||||
))}
|
||||
</p>
|
||||
|
||||
<blockquote class="border-l-2 border-light-pu dark:border-dark-pu pl-4 mt-2 text-light-tx-2 dark:text-dark-tx-2">
|
||||
{item.data.description}
|
||||
</blockquote>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
38
src/components/lists/NoteList.astro
Normal file
38
src/components/lists/NoteList.astro
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import { getPublishedAndSortedNotes } from "~/lib/blog";
|
||||
import Date from "~/components/util/Date.astro";
|
||||
import { render } from "astro:content";
|
||||
|
||||
interface Props {
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
const { limit } = Astro.props;
|
||||
const items = getPublishedAndSortedNotes(await getCollection("notes"));
|
||||
const limitedItems = limit ? items.slice(0, limit) : items;
|
||||
|
||||
// Render all note contents
|
||||
const renderedItems = await Promise.all(
|
||||
limitedItems.map(async (item) => {
|
||||
const { Content } = await render(item);
|
||||
return { ...item, Content };
|
||||
})
|
||||
);
|
||||
---
|
||||
|
||||
<ul class="fa-ul space-y-4 my-2">
|
||||
{
|
||||
renderedItems.map((item) => (
|
||||
<li>
|
||||
<i class={`fa-li ${item.data.icon}`} />
|
||||
<a href={`/notes/${item.id}`}>
|
||||
<Date date={item.data.date} />
|
||||
</a>
|
||||
<div>
|
||||
<item.Content />
|
||||
</div>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
45
src/components/lists/ProjectList.astro
Normal file
45
src/components/lists/ProjectList.astro
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
import Date from "~/components/util/Date.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
interface Props {
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
const { limit } = Astro.props;
|
||||
const items = await getCollection("projects");
|
||||
const limitedItems = limit ? items.slice(0, limit) : items;
|
||||
|
||||
---
|
||||
|
||||
<ul class="fa-ul space-y-4 my-2">
|
||||
{
|
||||
limitedItems.map((item) => (
|
||||
<li>
|
||||
<i class={`fa-li ${item.data.icon}`} />
|
||||
|
||||
<a href={`/projects/${item.id}`}>
|
||||
<h3 class="font-bold mb-0.5">{item.data.name}</h3>
|
||||
</a>
|
||||
|
||||
<p class="text-sm text-light-tx-2 dark:text-dark-tx-2">
|
||||
<i class="fa-solid fa-calendar-alt mr-1 text-light-pu dark:text-dark-pu" />
|
||||
<Date date={item.data.date} />
|
||||
<i class="fa-solid fa-tags mx-1 text-light-pu dark:text-dark-pu" />
|
||||
{(item.data.tags ?? []).map((tag) => (
|
||||
<a
|
||||
class="bg-light-pu dark:bg-dark-pu text-white px-1 py-0.5 rounded-md"
|
||||
href={`/${collection}/tags/${tag}`}
|
||||
>
|
||||
{tag}
|
||||
</a>
|
||||
))}
|
||||
</p>
|
||||
|
||||
<blockquote class="border-l-2 border-light-pu dark:border-dark-pu pl-4 mt-2 text-light-tx-2 dark:text-dark-tx-2">
|
||||
{item.data.description}
|
||||
</blockquote>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
20
src/components/ui/Box.astro
Normal file
20
src/components/ui/Box.astro
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
interface Props {
|
||||
title?: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
const { title, description, icon } = Astro.props;
|
||||
---
|
||||
|
||||
<div
|
||||
class="border-3 border-light-pu dark:border-dark-pu px-4 py-3 mt-5 w-fit"
|
||||
>
|
||||
<span class="mb-1">
|
||||
{icon && <i class={`fa-lg mr-1 ${icon}`} />}
|
||||
{title && <span class="text-lg font-bold">{title}</span>}
|
||||
{description && <span class="text-sm text-gray-500">{description}</span>}
|
||||
</span>
|
||||
<slot />
|
||||
</div>
|
14
src/components/ui/Footer.astro
Normal file
14
src/components/ui/Footer.astro
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
|
||||
---
|
||||
|
||||
<footer class="mt-12 text-sm text-light-tx-2 dark:text-dark-tx-2">
|
||||
<p>© {new Date().getFullYear()} Ivy Turner</p>
|
||||
<p>
|
||||
<a class="underline" href="https://github.com/ivyturner">github</a> ~
|
||||
<a class="underline" href="https://github.com/ivyturner/trellis">
|
||||
ivyturner/trellis
|
||||
</a>
|
||||
</p>
|
||||
<p>love yourself.</p>
|
||||
</footer>
|
40
src/components/ui/Head.astro
Normal file
40
src/components/ui/Head.astro
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
import siteConfig from "~/site.config";
|
||||
import { descriptionConstructor, titleConstructor } from "~/lib/metadata";
|
||||
|
||||
const { title, description } = Astro.props;
|
||||
---
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{titleConstructor(title)}</title>
|
||||
<meta name="description" content={descriptionConstructor(description)} />
|
||||
<meta name="author" content="Ivy Turner" />
|
||||
|
||||
{/* og */}
|
||||
<meta property="og:title" content={titleConstructor(title)} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://ivyneeds.rest" />
|
||||
<meta property="og:image" content="https://ivyneeds.rest/image.jpg" />
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<meta name="theme-color" content="#5E409D" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
|
||||
|
||||
{/* font awesone */}
|
||||
<link
|
||||
href="https://cdn.laker.tech/web/fa/css/fontawesome.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link href="https://cdn.laker.tech/web/fa/css/brands.css" rel="stylesheet" />
|
||||
<link href="https://cdn.laker.tech/web/fa/css/solid.css" rel="stylesheet" />
|
||||
|
||||
{/* analytics */}
|
||||
|
||||
|
||||
{/* astro generator */}
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
</head>
|
34
src/components/ui/Header.astro
Normal file
34
src/components/ui/Header.astro
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
import Navigation from "./Navigation.astro";
|
||||
import conf from "~/site.config";
|
||||
|
||||
let headertext = conf.siteName;
|
||||
let headerurl = "/";
|
||||
let headerarrow = false;
|
||||
|
||||
function isBlog() {
|
||||
return Astro.url.pathname.startsWith("/blog");
|
||||
}
|
||||
|
||||
if (isBlog()) {
|
||||
headertext = "Everything And The Girl";
|
||||
headerurl = "/blog";
|
||||
headerarrow = true;
|
||||
}
|
||||
---
|
||||
|
||||
<header class="md:flex md:justify-between md:items-center mb-4">
|
||||
<h1 class="text-2xl font-bold">
|
||||
{
|
||||
headerarrow && (
|
||||
<span class="mr-2">
|
||||
<a href="/">
|
||||
<i class="fa-solid fa-arrow-left text-light-pu dark:text-dark-pu" />
|
||||
</a>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
<a href={headerurl}>{headertext}</a>
|
||||
</h1>
|
||||
<Navigation />
|
||||
</header>
|
51
src/components/ui/Navigation.astro
Normal file
51
src/components/ui/Navigation.astro
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
const headerLinks = [
|
||||
{
|
||||
label: "About",
|
||||
href: "/about",
|
||||
icon: "fa-solid fa-user", // font awesome css class
|
||||
},
|
||||
{
|
||||
label: "Projects",
|
||||
href: "/projects",
|
||||
icon: "fa-solid fa-folder",
|
||||
},
|
||||
{
|
||||
label: "Notes",
|
||||
href: "/notes",
|
||||
icon: "fa-solid fa-sticky-note",
|
||||
},
|
||||
{
|
||||
label: "Blog",
|
||||
href: "/blog",
|
||||
icon: "fa-solid fa-blog",
|
||||
},
|
||||
{
|
||||
label: "Contact",
|
||||
href: "/contact",
|
||||
icon: "fa-solid fa-envelope",
|
||||
},
|
||||
{
|
||||
label: "More",
|
||||
href: "/more",
|
||||
icon: "fa-solid fa-ellipsis",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<nav class="flex flex-row gap-4">
|
||||
{
|
||||
headerLinks.map((link) => (
|
||||
<span>
|
||||
<i class={`${link.icon} mr-0.5 text-sm`} />
|
||||
<a
|
||||
href={link.href}
|
||||
class="underline decoration-wavy underline-offset-4 decoration-1.5
|
||||
decoration-light-pu dark:decoration-dark-pu"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
</span>
|
||||
))
|
||||
}
|
||||
</nav>
|
3
src/components/ui/SizeWarning.astro
Normal file
3
src/components/ui/SizeWarning.astro
Normal file
|
@ -0,0 +1,3 @@
|
|||
<div class="bg-light-ye dark:bg-dark-ye sm:block md:hidden text-black">
|
||||
<p>This view port may be too small.</p> <p>Try ivyneeds.rest on a bigger screen.</p>
|
||||
</div>
|
24
src/components/ui/Strapline.astro
Normal file
24
src/components/ui/Strapline.astro
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
import Date from "../util/Date.astro";
|
||||
|
||||
const { title, description, icon, date } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="mb-4">
|
||||
<h2 class="text-xl font-bold">
|
||||
<i class={`${icon} text-xl mr-2 text-light-pu dark:text-dark-pu`}></i>
|
||||
{title}
|
||||
</h2>
|
||||
<p class="mt-2 text-sm text-light-tx-2 dark:text-dark-tx-2">{description}</p>
|
||||
{
|
||||
() => {
|
||||
if (date) {
|
||||
return (
|
||||
<p class="mt-2 text-sm text-light-tx-2 dark:text-dark-tx-2">
|
||||
last updated: <Date date={date} />
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
17
src/components/util/Date.astro
Normal file
17
src/components/util/Date.astro
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
export interface Props {
|
||||
date: string | Date;
|
||||
}
|
||||
const { date } = Astro.props;
|
||||
|
||||
if (!date) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dateObj = typeof date === "string" ? new Date(date) : date;
|
||||
const options = { year: "numeric", month: "long", day: "numeric" };
|
||||
const formattedDate = dateObj.toLocaleDateString("en-GB", options);
|
||||
const isoDate = dateObj.toISOString();
|
||||
---
|
||||
|
||||
<time datetime={isoDate}>{formattedDate}</time>
|
12
src/components/util/StyledLink.astro
Normal file
12
src/components/util/StyledLink.astro
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
const { href, icon = "fa-solid fa-arrow-right" } = Astro.props;
|
||||
---
|
||||
|
||||
<ul class="fa-ul mb-2">
|
||||
<li>
|
||||
<a href={href} class="link">
|
||||
<i class={`fa-li ${icon}`} />
|
||||
<slot />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
53
src/content.config.ts
Normal file
53
src/content.config.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
// 1. Import utilities from `astro:content`
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
// 2. Import loader(s)
|
||||
import { glob } from "astro/loaders";
|
||||
|
||||
// 3. Define your collection(s)
|
||||
const blog = defineCollection({
|
||||
loader: glob({ pattern: "*.md", base: "src/content/blog" }),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
date: z.date().default(new Date()),
|
||||
tags: z.array(z.string()).optional(),
|
||||
draft: z.boolean().default(false),
|
||||
icon: z.string().optional().default("fa-solid fa-blog"),
|
||||
image: z
|
||||
.object({
|
||||
src: z.string(),
|
||||
alt: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
const notes = defineCollection({
|
||||
loader: glob({ pattern: "*.md", base: "src/content/notes" }),
|
||||
schema: z.object({
|
||||
title: z.string().optional(),
|
||||
exturl: z.string().url().optional(),
|
||||
date: z.date(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
icon: z.string().optional().default("fa-solid fa-sticky-note"),
|
||||
draft: z.boolean().default(false),
|
||||
}),
|
||||
});
|
||||
|
||||
const projects = defineCollection({
|
||||
loader: glob({ pattern: "*.md", base: "src/content/projects" }),
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
date: z.date(),
|
||||
url: z.string().url().optional(), // homepage
|
||||
repo: z.string().url().optional(), // git{hub,.sr.ht} link
|
||||
status: z.enum(["active", "finished", "backburner", "scrapped"]),
|
||||
version: z.string(),
|
||||
icon: z.string().optional().default("fa-solid fa-wrench"),
|
||||
}),
|
||||
});
|
||||
|
||||
// 4. Export a single `collections` object to register your collection(s)
|
||||
export const collections = { blog, notes, projects };
|
8
src/content/blog/meow.md
Normal file
8
src/content/blog/meow.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: meow
|
||||
description: meow meow meow
|
||||
date: 2025-03-17
|
||||
icon: fa-solid fa-cat
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat
|
8
src/content/blog/welcome.md
Normal file
8
src/content/blog/welcome.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: Welcome
|
||||
description: Lorem ipsum dolor sit amet irure tempor adipisicing esse minim nisi, aute duis elit. Adipisicing consequat pariatur duis incididunt nisi pariatur proident dolor deserunt et.
|
||||
tags:
|
||||
- welcome
|
||||
---
|
||||
|
||||
Something to do with the nature of truth and falsehood -- Chris Joel
|
8
src/content/notes/test.md
Normal file
8
src/content/notes/test.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: meow
|
||||
exturl: https://www.google.com
|
||||
date: 2025-03-16
|
||||
icon: fa-solid fa-cat
|
||||
---
|
||||
|
||||
Non voluptate dolore cupidatat ex culpa ea. Amet in cupidatat amet dolore officia. Eiusmod cupidatat do cillum quis. Sint sit duis eiusmod duis irure sit consequat veniam ea laborum veniam. Nisi et commodo commodo ea non minim. Sint amet excepteur deserunt duis id elit elit id excepteur occaecat cupidatat. Est exercitation excepteur laboris cillum ad do est fugiat minim.
|
9
src/content/projects/scramble.md
Normal file
9
src/content/projects/scramble.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: Scramble
|
||||
description: Music tracking for the modern age
|
||||
version: in development
|
||||
status: active
|
||||
date: 2025-03-17
|
||||
---
|
||||
|
||||
aaa
|
15
src/layouts/Base.astro
Normal file
15
src/layouts/Base.astro
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
import "~/styles/global.css";
|
||||
import Head from "~/components/ui/Head.astro";
|
||||
import { ClientRouter } from "astro:transitions";
|
||||
import SizeWarning from "~/components/ui/SizeWarning.astro";
|
||||
---
|
||||
|
||||
<html class="bg-light-bg text-light-tx dark:bg-dark-bg dark:text-dark-tx">
|
||||
<Head />
|
||||
<body class="pl-1 md:px-24 sm:pt-2 md:pt-6">
|
||||
<ClientRouter />
|
||||
<SizeWarning />
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
|
@ -1,22 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>Astro Basics</title>
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
45
src/layouts/Note.astro
Normal file
45
src/layouts/Note.astro
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
import Base from "~/layouts/Base.astro";
|
||||
import Header from "~/components/ui/Header.astro";
|
||||
import Date from "~/components/util/Date.astro";
|
||||
import { noteTitleConstructor } from "~/lib/metadata";
|
||||
const { title, exturl, icon, date } = Astro.props;
|
||||
---
|
||||
|
||||
<Base title={noteTitleConstructor(title, date)}>
|
||||
<Header />
|
||||
<ul class="fa-ul marker:text-accent">
|
||||
<li>
|
||||
<a href="/notes" class="link">
|
||||
<i class="fa-li fa-solid fa-arrow-left marker:text-accent" />
|
||||
Back to notes
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 class="text-2xl font-bold mt-2">A note from <Date date={date} /></h2>
|
||||
<div class="bg-light-bg-2 dark:bg-dark-bg-2 p-4 rounded-lg w-fit min-w-[500px] mt-4">
|
||||
<ul class="fa-ul">
|
||||
{
|
||||
title && (
|
||||
<li class="text-lg font-bold">
|
||||
<i class={`fa-li ${icon}`} />
|
||||
<h1 class="font-bold">{title}</h1>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
{
|
||||
exturl && (
|
||||
<li>
|
||||
<i class="fa-li fa-solid fa-link" />
|
||||
<a href={exturl} class="link">
|
||||
{exturl}
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<div class="pl-4 mt-2 prose dark:prose-invert">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</Base>
|
18
src/layouts/Page.astro
Normal file
18
src/layouts/Page.astro
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
import Layout from "~/layouts/Base.astro";
|
||||
import Header from "~/components/ui/Header.astro";
|
||||
import Strapline from "~/components/ui/Strapline.astro";
|
||||
import Footer from "~/components/ui/Footer.astro";
|
||||
const { title, description, icon, date } = Astro.props;
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<div>
|
||||
<Header />
|
||||
<main>
|
||||
<Strapline title={title} description={description} icon={icon} date={date} />
|
||||
<slot />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</Layout>
|
41
src/lib/blog.ts
Normal file
41
src/lib/blog.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import siteConfig from "~/site.config";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
|
||||
type PostWithDate = {
|
||||
data: {
|
||||
date: Date;
|
||||
};
|
||||
};
|
||||
|
||||
const sortByDateDescending = <T extends PostWithDate>(posts: T[]): T[] => {
|
||||
return posts.sort((a, b) =>
|
||||
isDateBefore(a.data.date, b.data.date) ? 1 : -1
|
||||
);
|
||||
};
|
||||
|
||||
const filterPublishedPosts = <T extends { data: { draft?: boolean } }>(
|
||||
posts: T[]
|
||||
): T[] => {
|
||||
if (import.meta.env.PROD) {
|
||||
return posts.filter((post) => !post.data.draft);
|
||||
}
|
||||
return siteConfig.devMode.showDraftPages
|
||||
? posts
|
||||
: posts.filter((post) => !post.data.draft);
|
||||
};
|
||||
|
||||
export const getPublishedAndSortedPosts = (
|
||||
allPosts: CollectionEntry<"blog">[]
|
||||
): CollectionEntry<"blog">[] => {
|
||||
return sortByDateDescending(filterPublishedPosts(allPosts));
|
||||
};
|
||||
|
||||
export const getPublishedAndSortedNotes = (
|
||||
allPosts: CollectionEntry<"notes">[]
|
||||
): CollectionEntry<"notes">[] => {
|
||||
return sortByDateDescending(allPosts);
|
||||
};
|
||||
|
||||
// helper function to check if date1 is before date2
|
||||
export const isDateBefore = (date1: Date, date2: Date): boolean =>
|
||||
date1.getTime() < date2.getTime();
|
33
src/lib/fun.ts
Normal file
33
src/lib/fun.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
// all the code for making fun stuff happen
|
||||
|
||||
const flavourText = [
|
||||
"LOVE YOURSELF",
|
||||
"Hack the planet!",
|
||||
"all your base are belong to us!",
|
||||
"must construct additional pylons",
|
||||
"Everybody's dead, Dave.",
|
||||
"Stay strange and be ace -- Yard Act",
|
||||
"I'm a rocketman!",
|
||||
"It's a fixer-upper!",
|
||||
"💜",
|
||||
"Sibelius crashed",
|
||||
"All toasters toast toast",
|
||||
"Trans rights are human rights!",
|
||||
":wq",
|
||||
];
|
||||
|
||||
export function getFlavourText() {
|
||||
return flavourText[Math.floor(Math.random() * flavourText.length)];
|
||||
}
|
||||
|
||||
export function isBirthday() {
|
||||
const today = new Date();
|
||||
const birthday = new Date(today.getFullYear(), 3, 13);
|
||||
const check =
|
||||
today.getMonth() === birthday.getMonth() &&
|
||||
today.getDate() === birthday.getDate();
|
||||
console.log(check);
|
||||
return check;
|
||||
}
|
||||
|
||||
|
17
src/lib/metadata.ts
Normal file
17
src/lib/metadata.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import conf from "~/site.config";
|
||||
// todo: add blog detection
|
||||
|
||||
export const titleConstructor = (title: string) => {
|
||||
if (!title) return conf.siteName;
|
||||
return `${title} | ${conf.siteName}`;
|
||||
};
|
||||
|
||||
export const descriptionConstructor = (description: string) => {
|
||||
if (!description) return conf.description;
|
||||
return `${description}`;
|
||||
};
|
||||
|
||||
export const noteTitleConstructor = (title: string, date: Date) => {
|
||||
if (title) return title;
|
||||
return `A note from ${date.toLocaleDateString()}`;
|
||||
};
|
0
src/lib/util.ts
Normal file
0
src/lib/util.ts
Normal file
14
src/pages/404.astro
Normal file
14
src/pages/404.astro
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
import Layout from "~/layouts/Base.astro";
|
||||
import Header from "~/components/ui/Header.astro";
|
||||
import Footer from "~/components/ui/Footer.astro";
|
||||
---
|
||||
|
||||
<Layout title="404" description="Page not found" icon="fa-solid fa-ghost">
|
||||
<Header />
|
||||
<main class="border-l-5 border-light-pu dark:border-dark-pu pl-4">
|
||||
<h2 class="text-2xl font-bold">404</h2>
|
||||
<p class="text-lg">Page not found</p>
|
||||
</main>
|
||||
<Footer />
|
||||
</Layout>
|
7
src/pages/about.astro
Normal file
7
src/pages/about.astro
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
import Page from "~/layouts/Page.astro";
|
||||
---
|
||||
|
||||
<Page title="About" description="do you wanna know?" icon="fa-solid fa-user" date="2025-03-13">
|
||||
<h1>i kiss girls</h1>
|
||||
</Page>
|
24
src/pages/blog/[id].astro
Normal file
24
src/pages/blog/[id].astro
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
import Page from "~/layouts/Page.astro";
|
||||
import { getCollection, render } from "astro:content";
|
||||
// 1. Generate a new path for every collection entry
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("blog");
|
||||
return posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
// 2. For your template, you can get the entry directly from the prop
|
||||
const { post } = Astro.props;
|
||||
const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<Page
|
||||
title={post.data.title}
|
||||
description={post.data.description}
|
||||
date={post.data.date}
|
||||
icon={post.data.icon}
|
||||
>
|
||||
<Content />
|
||||
</Page>
|
12
src/pages/blog/index.astro
Normal file
12
src/pages/blog/index.astro
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
import Page from "~/layouts/Page.astro";
|
||||
import BlogPostList from "~/components/lists/BlogPostList.astro";
|
||||
---
|
||||
|
||||
<Page
|
||||
title="Post index"
|
||||
description="A list of all my blog posts."
|
||||
icon="fa-solid fa-blog"
|
||||
>
|
||||
<BlogPostList collection="blog" />
|
||||
</Page>
|
35
src/pages/contact/index.astro
Normal file
35
src/pages/contact/index.astro
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
import Layout from "~/layouts/Page.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Contact"
|
||||
description="how to get a hold of me if you ever need to"
|
||||
icon="fa-solid fa-envelope"
|
||||
>
|
||||
<p>
|
||||
I'm not really active on social media, but you can contact me via email.
|
||||
</p>
|
||||
<p>
|
||||
<a href="mailto:hello@ivyneeds.rest">hello@ivyneeds.rest</a>
|
||||
</p>
|
||||
<h3 class="text-lg font-bold my-2">where i am / where i'm not</h3>
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
<i class="fa-li fa-brands fa-mastodon"></i>
|
||||
Fediverse: <a href="https://social.lol/ivy">@ivy@social.lol</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa-li fa-brands fa-github"></i>
|
||||
GitHub: <a href="https://github.com/ivyturner">@ivyturner</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa-li fa-brands fa-instagram"></i>
|
||||
Instagram: <a href="https://www.instagram.com/ivyturner">@ivyturner</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa-li fa-brands fa-twitter text-light-re dark:text-dark-re"></i>
|
||||
Twitter: haha fuck right off, elon should get his arms broken
|
||||
</li>
|
||||
</ul>
|
||||
</Layout>
|
23
src/pages/contact/verify.astro
Normal file
23
src/pages/contact/verify.astro
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
import Layout from "~/layouts/Page.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Verify"
|
||||
description="Everywhere you can find me, so you can check if it's me."
|
||||
icon="fa-solid fa-envelope"
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
Fediverse: <a href="https://social.lol/@ivy">@ivy@social.lol</a>,
|
||||
<a href="https://social.lol/@la">@la@social.lol</a>
|
||||
</li>
|
||||
<li>
|
||||
GitHub: <a href="https://github.com/ivyturner">@ivyturner</a>
|
||||
(previously @lxjv)
|
||||
</li>
|
||||
<li>
|
||||
Instagram: <a href="https://www.instagram.com/ivyturner">@ivyturner</a>
|
||||
</li>
|
||||
</ul>
|
||||
</Layout>
|
|
@ -1,11 +1,53 @@
|
|||
---
|
||||
import Welcome from '../components/Welcome.astro';
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
|
||||
// Welcome to Astro! Wondering what to do next? Check out the Astro documentation at https://docs.astro.build
|
||||
// Don't want to use any of this? Delete everything in this file, the `assets`, `components`, and `layouts` directories, and start fresh.
|
||||
import Layout from "~/layouts/Base.astro";
|
||||
import Header from "~/components/ui/Header.astro";
|
||||
import Footer from "~/components/ui/Footer.astro";
|
||||
import Box from "~/components/ui/Box.astro";
|
||||
import CollectionList from "~/components/lists/BlogPostList.astro";
|
||||
import NoteList from "~/components/lists/NoteList.astro";
|
||||
import StyledLink from "~/components/util/StyledLink.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Welcome />
|
||||
<Header />
|
||||
<main>
|
||||
<h1
|
||||
class="text-2xl font-bold underline decoration-wavy underline-offset-8 decoration-3
|
||||
decoration-light-pu dark:decoration-dark-pu mb-6"
|
||||
>
|
||||
Hi! I'm Ivy, welcome to my website!
|
||||
</h1>
|
||||
<p>
|
||||
I'm a musician, student, part-time software developer and <a
|
||||
href="/blog"
|
||||
class="link hover:decoration-solid">writer</a
|
||||
>. <br />
|
||||
I mostly work with <a
|
||||
href="https://www.rust-lang.org/"
|
||||
class="link hover:decoration-solid">Rust</a
|
||||
>, <a
|
||||
href="https://www.typescriptlang.org/"
|
||||
class="link hover:decoration-solid">Typescript</a
|
||||
>, and web frameworks like <a
|
||||
href="https://astro.build/"
|
||||
class="link hover:decoration-solid">Astro</a
|
||||
>, and <a href="https://11ty.dev/" class="link hover:decoration-solid"
|
||||
>Eleventy</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
<div class="md:flex md:flex-column gap-2">
|
||||
<Box title="latest blog posts" description="" icon="fa-solid fa-blog">
|
||||
<CollectionList collection="blog" limit={5} />
|
||||
<hr class="h-px my-8 bg-light-pu dark:bg-dark-pu" />
|
||||
<StyledLink href="/blog">see more</StyledLink>
|
||||
</Box>
|
||||
<Box title="latest notes" description="" icon="fa-solid fa-sticky-note">
|
||||
<NoteList limit={5} />
|
||||
<hr class="h-px my-8 bg-light-pu dark:bg-dark-pu border-0" />
|
||||
<StyledLink href="/notes">see more</StyledLink>
|
||||
</Box>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
<Footer />
|
||||
|
|
24
src/pages/notes/[id].astro
Normal file
24
src/pages/notes/[id].astro
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
import Note from "~/layouts/Note.astro";
|
||||
import { getCollection, render } from "astro:content";
|
||||
// 1. Generate a new path for every collection entry
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("notes");
|
||||
return posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
// 2. For your template, you can get the entry directly from the prop
|
||||
const { post } = Astro.props;
|
||||
const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<Note
|
||||
title={post.data.title}
|
||||
exturl={post.data.exturl}
|
||||
icon={post.data.icon}
|
||||
date={post.data.date}
|
||||
>
|
||||
<Content />
|
||||
</Note>
|
8
src/pages/notes/index.astro
Normal file
8
src/pages/notes/index.astro
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
import Page from "~/layouts/Page.astro";
|
||||
import NoteList from "~/components/lists/NoteList.astro";
|
||||
---
|
||||
|
||||
<Page title="Notes" description="A collection of notes I've written." icon="fa-solid fa-note-sticky">
|
||||
<NoteList />
|
||||
</Page>
|
24
src/pages/projects/[id].astro
Normal file
24
src/pages/projects/[id].astro
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
import Page from "~/layouts/Page.astro";
|
||||
import { getCollection, render } from "astro:content";
|
||||
// 1. Generate a new path for every collection entry
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("projects");
|
||||
return posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
// 2. For your template, you can get the entry directly from the prop
|
||||
const { post } = Astro.props;
|
||||
const { Content } = await render(post);
|
||||
---
|
||||
|
||||
<Page
|
||||
title={post.data.name}
|
||||
description={post.data.description}
|
||||
date={post.data.date}
|
||||
icon={post.data.icon}
|
||||
>
|
||||
<Content />
|
||||
</Page>
|
8
src/pages/projects/index.astro
Normal file
8
src/pages/projects/index.astro
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
import Page from "~/layouts/Page.astro";
|
||||
import ProjectList from "~/components/lists/ProjectList.astro";
|
||||
---
|
||||
|
||||
<Page title="Projects" description="stuff i'm working on" icon="fa-solid fa-wrench">
|
||||
<ProjectList limit={1000} />
|
||||
</Page>
|
8
src/site.config.ts
Normal file
8
src/site.config.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export default {
|
||||
siteName: "Ivy Turner",
|
||||
description: "Ivy Turner's personal website",
|
||||
fediverse: "@ivy@social.lol",
|
||||
devMode: {
|
||||
showDraftPages: true,
|
||||
},
|
||||
};
|
202
src/styles/global.css
Normal file
202
src/styles/global.css
Normal file
|
@ -0,0 +1,202 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
/* Disable default colors to prevent their use; feel free to re-enable as needed. */
|
||||
--color-amber-*: initial;
|
||||
--color-lime-*: initial;
|
||||
--color-emerald-*: initial;
|
||||
--color-teal-*: initial;
|
||||
--color-sky-*: initial;
|
||||
--color-indigo-*: initial;
|
||||
--color-violet-*: initial;
|
||||
--color-fuchsia-*: initial;
|
||||
--color-pink-*: initial;
|
||||
--color-rose-*: initial;
|
||||
--color-slate-*: initial;
|
||||
--color-zinc-*: initial;
|
||||
--color-neutral-*: initial;
|
||||
--color-stone-*: initial;
|
||||
|
||||
/* Specify new default colors. */
|
||||
--color-black: #100F0F;
|
||||
--color-paper: #FFFCF0;
|
||||
--color-base-50: #F2F0E5;
|
||||
--color-base-100: #E6E4D9;
|
||||
--color-base-150: #DAD8CE;
|
||||
--color-base-200: #CECDC3;
|
||||
--color-base-300: #B7B5AC;
|
||||
--color-base-400: #9F9D96;
|
||||
--color-base-500: #878580;
|
||||
--color-base-600: #6F6E69;
|
||||
--color-base-700: #575653;
|
||||
--color-base-800: #403E3C;
|
||||
--color-base-850: #343331;
|
||||
--color-base-900: #282726;
|
||||
--color-base-950: #1C1B1A;
|
||||
--color-red-50: #FFE1D5;
|
||||
--color-red-100: #FFCABB;
|
||||
--color-red-150: #FDB2A2;
|
||||
--color-red-200: #F89A8A;
|
||||
--color-red-300: #E8705F;
|
||||
--color-red-400: #D14D41;
|
||||
--color-red-500: #C03E35;
|
||||
--color-red-600: #AF3029;
|
||||
--color-red-700: #942822;
|
||||
--color-red-800: #6C201C;
|
||||
--color-red-850: #551B18;
|
||||
--color-red-900: #3E1715;
|
||||
--color-red-950: #261312;
|
||||
--color-orange-50: #FFE7CE;
|
||||
--color-orange-100: #FED3AF;
|
||||
--color-orange-150: #FCC192;
|
||||
--color-orange-200: #F9AE77;
|
||||
--color-orange-300: #EC8B49;
|
||||
--color-orange-400: #DA702C;
|
||||
--color-orange-500: #CB6120;
|
||||
--color-orange-600: #BC5215;
|
||||
--color-orange-700: #9D4310;
|
||||
--color-orange-800: #71320D;
|
||||
--color-orange-850: #59290D;
|
||||
--color-orange-900: #40200D;
|
||||
--color-orange-950: #27180E;
|
||||
--color-yellow-50: #FAEEC6;
|
||||
--color-yellow-100: #F6E2A0;
|
||||
--color-yellow-150: #F1D67E;
|
||||
--color-yellow-200: #ECCB60;
|
||||
--color-yellow-300: #DFB431;
|
||||
--color-yellow-400: #D0A215;
|
||||
--color-yellow-500: #BE9207;
|
||||
--color-yellow-600: #AD8301;
|
||||
--color-yellow-700: #8E6B01;
|
||||
--color-yellow-800: #664D01;
|
||||
--color-yellow-850: #503D02;
|
||||
--color-yellow-900: #3A2D04;
|
||||
--color-yellow-950: #241E08;
|
||||
--color-green-50: #EDEECF;
|
||||
--color-green-100: #DDE2B2;
|
||||
--color-green-150: #CDD597;
|
||||
--color-green-200: #BEC97E;
|
||||
--color-green-300: #A0AF54;
|
||||
--color-green-400: #879A39;
|
||||
--color-green-500: #768D21;
|
||||
--color-green-600: #66800B;
|
||||
--color-green-700: #536907;
|
||||
--color-green-800: #3D4C07;
|
||||
--color-green-850: #313D07;
|
||||
--color-green-900: #252D09;
|
||||
--color-green-950: #1A1E0C;
|
||||
--color-cyan-50: #DDF1E4;
|
||||
--color-cyan-100: #BFE8D9;
|
||||
--color-cyan-150: #A2DECE;
|
||||
--color-cyan-200: #87D3C3;
|
||||
--color-cyan-300: #5ABDAC;
|
||||
--color-cyan-400: #3AA99F;
|
||||
--color-cyan-500: #2F968D;
|
||||
--color-cyan-600: #24837B;
|
||||
--color-cyan-700: #1C6C66;
|
||||
--color-cyan-800: #164F4A;
|
||||
--color-cyan-850: #143F3C;
|
||||
--color-cyan-900: #122F2C;
|
||||
--color-cyan-950: #101F1D;
|
||||
--color-blue-50: #E1ECEB;
|
||||
--color-blue-100: #C6DDE8;
|
||||
--color-blue-150: #ABCFE2;
|
||||
--color-blue-200: #92BFDB;
|
||||
--color-blue-300: #66A0C8;
|
||||
--color-blue-400: #4385BE;
|
||||
--color-blue-500: #3171B2;
|
||||
--color-blue-600: #205EA6;
|
||||
--color-blue-700: #1A4F8C;
|
||||
--color-blue-800: #163B66;
|
||||
--color-blue-850: #133051;
|
||||
--color-blue-900: #12253B;
|
||||
--color-blue-950: #101A24;
|
||||
--color-purple-50: #F0EAEC;
|
||||
--color-purple-100: #E2D9E9;
|
||||
--color-purple-150: #D3CAE6;
|
||||
--color-purple-200: #C4B9E0;
|
||||
--color-purple-300: #A699D0;
|
||||
--color-purple-400: #8B7EC8;
|
||||
--color-purple-500: #735EB5;
|
||||
--color-purple-600: #5E409D;
|
||||
--color-purple-700: #4F3685;
|
||||
--color-purple-800: #3C2A62;
|
||||
--color-purple-850: #31234E;
|
||||
--color-purple-900: #261C39;
|
||||
--color-purple-950: #1A1623;
|
||||
--color-magenta-50: #FEE4E5;
|
||||
--color-magenta-100: #FCCFDA;
|
||||
--color-magenta-150: #F9B9CF;
|
||||
--color-magenta-200: #F4A4C2;
|
||||
--color-magenta-300: #E47DA8;
|
||||
--color-magenta-400: #CE5D97;
|
||||
--color-magenta-500: #B74583;
|
||||
--color-magenta-600: #A02F6F;
|
||||
--color-magenta-700: #87285E;
|
||||
--color-magenta-800: #641F46;
|
||||
--color-magenta-850: #4F1B39;
|
||||
--color-magenta-900: #39172B;
|
||||
--color-magenta-950: #24131D;
|
||||
}
|
||||
|
||||
/* Define some semantic aliases. */
|
||||
@theme inline {
|
||||
--color-light-bg: var(--color-paper);
|
||||
--color-light-bg-2: var(--color-base-50);
|
||||
--color-light-tx: var(--color-black);
|
||||
--color-light-tx-2: var(--color-base-600);
|
||||
--color-light-tx-3: var(--color-base-300);
|
||||
--color-light-ui: var(--color-base-100);
|
||||
--color-light-ui-2: var(--color-base-150);
|
||||
--color-light-ui-3: var(--color-base-200);
|
||||
--color-dark-bg: var(--color-black);
|
||||
--color-dark-bg-2: var(--color-base-950);
|
||||
--color-dark-tx: var(--color-base-200);
|
||||
--color-dark-tx-2: var(--color-base-500);
|
||||
--color-dark-tx-3: var(--color-base-700);
|
||||
--color-dark-ui: var(--color-base-900);
|
||||
--color-dark-ui-2: var(--color-base-850);
|
||||
--color-dark-ui-3: var(--color-base-800);
|
||||
--color-light-re: var(--color-red-600);
|
||||
--color-light-or: var(--color-orange-600);
|
||||
--color-light-ye: var(--color-yellow-600);
|
||||
--color-light-gr: var(--color-green-600);
|
||||
--color-light-cy: var(--color-cyan-600);
|
||||
--color-light-bl: var(--color-blue-600);
|
||||
--color-light-pu: var(--color-purple-600);
|
||||
--color-light-ma: var(--color-magenta-600);
|
||||
--color-dark-re: var(--color-red-400);
|
||||
--color-dark-or: var(--color-orange-400);
|
||||
--color-dark-ye: var(--color-yellow-400);
|
||||
--color-dark-gr: var(--color-green-400);
|
||||
--color-dark-cy: var(--color-cyan-400);
|
||||
--color-dark-bl: var(--color-blue-400);
|
||||
--color-dark-pu: var(--color-purple-400);
|
||||
--color-dark-ma: var(--color-magenta-400);
|
||||
--color-light-re-2: var(--color-red-400);
|
||||
--color-light-or-2: var(--color-orange-400);
|
||||
--color-light-ye-2: var(--color-yellow-400);
|
||||
--color-light-gr-2: var(--color-green-400);
|
||||
--color-light-cy-2: var(--color-cyan-400);
|
||||
--color-light-bl-2: var(--color-blue-400);
|
||||
--color-light-pu-2: var(--color-purple-400);
|
||||
--color-light-ma-2: var(--color-magenta-400);
|
||||
--color-dark-re-2: var(--color-red-600);
|
||||
--color-dark-or-2: var(--color-orange-600);
|
||||
--color-dark-ye-2: var(--color-yellow-600);
|
||||
--color-dark-gr-2: var(--color-green-600);
|
||||
--color-dark-cy-2: var(--color-cyan-600);
|
||||
--color-dark-bl-2: var(--color-blue-600);
|
||||
--color-dark-pu-2: var(--color-purple-600);
|
||||
--color-dark-ma-2: var(--color-magenta-600);
|
||||
|
||||
--color-accent: light-dark(var(--color-light-pu), var(--color-dark-pu));
|
||||
}
|
||||
|
||||
.link {
|
||||
@apply underline decoration-dotted underline-offset-2 decoration-2 decoration-light-pu dark:decoration-dark-pu
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply border-0 h-0.5 my-4 bg-light-pu dark:bg-dark-pu;
|
||||
}
|
|
@ -1,5 +1,11 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"include": [".astro/types.d.ts", "**/*"],
|
||||
"exclude": ["dist"]
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue