feat: format
This commit is contained in:
parent
b0df7bebb0
commit
da030f3dc1
30 changed files with 603 additions and 348 deletions
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import { getCollection } from "astro:content";
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const categories = ['algorithms', 'software', 'operating-systems', 'meditations'];
|
||||
|
||||
return categories.map(category => {
|
||||
const categories = ["algorithms", "software", "meditations"];
|
||||
|
||||
return categories.map((category) => {
|
||||
return {
|
||||
params: { category },
|
||||
props: { category },
|
||||
|
|
@ -14,7 +14,10 @@ export async function getStaticPaths() {
|
|||
}
|
||||
|
||||
const { category } = Astro.props;
|
||||
const posts = await getCollection('posts', (post) => post.data.category === category);
|
||||
const posts = await getCollection(
|
||||
"posts",
|
||||
(post) => post.data.category === category,
|
||||
);
|
||||
|
||||
posts.sort((a, b) => {
|
||||
const dateA = a.data.date ? new Date(a.data.date) : new Date(0);
|
||||
|
|
@ -22,29 +25,30 @@ posts.sort((a, b) => {
|
|||
return dateB.getTime() - dateA.getTime();
|
||||
});
|
||||
|
||||
const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1);
|
||||
const capitalizedCategory =
|
||||
category.charAt(0).toUpperCase() + category.slice(1);
|
||||
---
|
||||
|
||||
<BaseLayout title={capitalizedCategory}>
|
||||
<div class="content">
|
||||
<h1>{capitalizedCategory}</h1>
|
||||
<div class="posts">
|
||||
{posts.map(post => (
|
||||
<div class="post">
|
||||
<a href={`/posts/${category}/${post.slug}`}>
|
||||
{post.data.title}
|
||||
</a>
|
||||
{post.data.date && (
|
||||
<time datetime={post.data.date}>
|
||||
{new Date(post.data.date).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</time>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{
|
||||
posts.map((post) => (
|
||||
<div class="post">
|
||||
<a href={`/posts/${category}/${post.slug}`}>{post.data.title}</a>
|
||||
{post.data.date && (
|
||||
<time datetime={post.data.date}>
|
||||
{new Date(post.data.date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})}
|
||||
</time>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
|
@ -55,29 +59,29 @@ const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1)
|
|||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
||||
.posts {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
.post {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
|
||||
.post a {
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
text-decoration: underline;
|
||||
color: var(--topic-color, inherit);
|
||||
}
|
||||
|
||||
|
||||
time {
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
|
|
@ -87,14 +91,14 @@ const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1)
|
|||
</style>
|
||||
|
||||
<script define:vars={{ category }}>
|
||||
import { getTopicColor } from '../utils/colors.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
import { getTopicColor } from "../utils/colors.js";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.documentElement.style.setProperty(
|
||||
'--topic-color',
|
||||
getTopicColor(category)
|
||||
"--topic-color",
|
||||
getTopicColor(category),
|
||||
);
|
||||
|
||||
|
||||
window.getTopicColor = getTopicColor;
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -9,27 +9,27 @@ import BaseLayout from "../layouts/BaseLayout.astro";
|
|||
</header>
|
||||
<article class="post-article">
|
||||
<p>
|
||||
I am a software developer studying computer science at the
|
||||
University of Virginia.
|
||||
I am a software developer studying computer science at the University of
|
||||
Virginia.
|
||||
</p>
|
||||
<p>
|
||||
I began working as a software engineer part-time with
|
||||
<a target="blank" href="https://gotransverse.com/">GoTransverse</a>
|
||||
in high school. After developing an interest in the
|
||||
financial/venture capital world, I transitioned to
|
||||
in high school. After developing an interest in the financial/venture capital
|
||||
world, I transitioned to
|
||||
<a target="blank" href="https://www.nthventure.com/">Nth Venture</a>
|
||||
in the spring of my second year. I worked at
|
||||
<a target="blank" href="https://usa.visa.com/">VISA</a> and
|
||||
<a href="https://trbcap.com" target="_blank">TRB Capital Management</a>
|
||||
during the summer of 2024. Luckily enough, I'll be joining
|
||||
<a href="https://drw.com" target="_blank">DRW</a> and
|
||||
<a href="https://ramp.com" target="_blank">Ramp</a> in the summer
|
||||
and spring of 2025.
|
||||
<a href="https://ramp.com" target="_blank">Ramp</a> in the summer and spring
|
||||
of 2025.
|
||||
</p>
|
||||
<p>
|
||||
I've a developing interest in high-performance computing,
|
||||
quantitative finance, and open-source software. I am also a
|
||||
passionate contributor to the (Neo)Vim ecosystem and beyond.
|
||||
I've a developing interest in high-performance computing, quantitative
|
||||
finance, and open-source software. I am also a passionate contributor to
|
||||
the (Neo)Vim ecosystem and beyond.
|
||||
</p>
|
||||
<p>
|
||||
You can see my related contributions on
|
||||
|
|
@ -37,9 +37,8 @@ import BaseLayout from "../layouts/BaseLayout.astro";
|
|||
</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
|
||||
<slot name="head" slot="head">
|
||||
<link rel="stylesheet" href="/styles/post.css" />
|
||||
<link rel="stylesheet" href="/styles/posts.css" />
|
||||
</slot>
|
||||
</BaseLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,28 @@
|
|||
---
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import { getTopicColor } from "../utils/colors.js";
|
||||
|
||||
const title = "Barrett Ruth";
|
||||
|
||||
const allPosts = await getCollection("posts");
|
||||
const postsByCategory = allPosts.reduce((acc, post) => {
|
||||
const category = post.id.split('/')[0];
|
||||
const category = post.id.split("/")[0];
|
||||
if (!acc[category]) acc[category] = [];
|
||||
acc[category].push(post);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
Object.keys(postsByCategory).forEach(category => {
|
||||
Object.keys(postsByCategory).forEach((category) => {
|
||||
postsByCategory[category].sort((a, b) => {
|
||||
const dateA = a.data.date ? new Date(a.data.date) : new Date(0);
|
||||
const dateB = b.data.date ? new Date(b.data.date) : new Date(0);
|
||||
const parseEuroDate = (dateStr) => {
|
||||
if (!dateStr) return new Date(0);
|
||||
const [day, month, year] = dateStr.split("/");
|
||||
return new Date(year, month - 1, day);
|
||||
};
|
||||
|
||||
const dateA = parseEuroDate(a.data.date);
|
||||
const dateB = parseEuroDate(b.data.date);
|
||||
return dateB.getTime() - dateA.getTime();
|
||||
});
|
||||
});
|
||||
|
|
@ -45,8 +52,6 @@ Object.keys(postsByCategory).forEach(category => {
|
|||
switch (topicName) {
|
||||
case "software":
|
||||
return "#0073e6";
|
||||
case "operating-systems":
|
||||
return "#009975";
|
||||
case "algorithms":
|
||||
return "#d50032";
|
||||
case "meditations":
|
||||
|
|
@ -55,24 +60,25 @@ Object.keys(postsByCategory).forEach(category => {
|
|||
return "#000000";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const TERMINAL_PROMPT = "barrett@ruth:~$ ";
|
||||
let typing = false;
|
||||
let clearing = false;
|
||||
|
||||
|
||||
function clearPrompt(delay, callback) {
|
||||
if (clearing) return;
|
||||
clearing = true;
|
||||
|
||||
|
||||
const terminalPrompt = document.querySelector(".terminal-prompt");
|
||||
if (!terminalPrompt) {
|
||||
clearing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const topicLength = terminalPrompt.innerHTML.length - TERMINAL_PROMPT.length;
|
||||
|
||||
const topicLength =
|
||||
terminalPrompt.innerHTML.length - TERMINAL_PROMPT.length;
|
||||
let i = 0;
|
||||
|
||||
|
||||
function removeChar() {
|
||||
if (i++ < topicLength) {
|
||||
terminalPrompt.textContent = terminalPrompt.textContent.slice(0, -1);
|
||||
|
|
@ -83,33 +89,33 @@ Object.keys(postsByCategory).forEach(category => {
|
|||
callback && callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
removeChar();
|
||||
}
|
||||
|
||||
|
||||
function typechars(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
const topicElement = e.target;
|
||||
if (topicElement.classList.contains("active")) return;
|
||||
if (typing) return;
|
||||
typing = true;
|
||||
|
||||
|
||||
const topic = topicElement.dataset.topic;
|
||||
const terminalText = ` /${topic.toLowerCase()}`;
|
||||
const terminalPrompt = document.querySelector(".terminal-prompt");
|
||||
const delay =
|
||||
terminalPrompt.innerHTML.length > TERMINAL_PROMPT.length ? 250 : 500;
|
||||
|
||||
|
||||
const topics = document.querySelectorAll(".topic a");
|
||||
topics.forEach((t) => {
|
||||
t.classList.remove("active");
|
||||
t.style.color = "";
|
||||
});
|
||||
|
||||
|
||||
topicElement.classList.add("active");
|
||||
topicElement.style.color = getTopicColor(topic);
|
||||
|
||||
|
||||
clearPrompt(delay, () => {
|
||||
let i = 0;
|
||||
function typechar() {
|
||||
|
|
@ -124,60 +130,63 @@ Object.keys(postsByCategory).forEach(category => {
|
|||
typechar();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function renderPosts(topic) {
|
||||
const posts = document.getElementById("posts");
|
||||
posts.innerHTML = "";
|
||||
|
||||
|
||||
const categoryPosts = postsByCategory[topic];
|
||||
|
||||
|
||||
if (!categoryPosts) {
|
||||
console.error(`No posts found for topic: ${topic}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
categoryPosts.forEach((post) => {
|
||||
const postDiv = document.createElement("div");
|
||||
postDiv.classList.add("post");
|
||||
|
||||
|
||||
const link = document.createElement("a");
|
||||
const slug = post.id.split('/').pop().replace(/\.mdx?$/, '');
|
||||
|
||||
const slug = post.id
|
||||
.split("/")
|
||||
.pop()
|
||||
.replace(/\.mdx?$/, "");
|
||||
|
||||
link.href = `/posts/${topic}/${slug}`;
|
||||
link.textContent = post.data.title;
|
||||
link.style.textDecoration = "underline";
|
||||
|
||||
|
||||
postDiv.appendChild(link);
|
||||
posts.appendChild(postDiv);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const topics = document.querySelectorAll('.topic a');
|
||||
|
||||
topics.forEach(topic => {
|
||||
topic.addEventListener('click', typechars);
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const topics = document.querySelectorAll(".topic a");
|
||||
|
||||
topics.forEach((topic) => {
|
||||
topic.addEventListener("click", typechars);
|
||||
|
||||
const topicName = topic.dataset.topic;
|
||||
|
||||
topic.addEventListener('mouseenter', () => {
|
||||
|
||||
topic.addEventListener("mouseenter", () => {
|
||||
const color = getTopicColor(topicName);
|
||||
topic.style.color = color;
|
||||
});
|
||||
|
||||
topic.addEventListener('mouseleave', () => {
|
||||
if (!topic.classList.contains('active')) {
|
||||
|
||||
topic.addEventListener("mouseleave", () => {
|
||||
if (!topic.classList.contains("active")) {
|
||||
topic.style.color = "";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
const terminalPrompt = document.querySelector('.terminal-prompt');
|
||||
|
||||
window.addEventListener("beforeunload", () => {
|
||||
const terminalPrompt = document.querySelector(".terminal-prompt");
|
||||
if (terminalPrompt) {
|
||||
terminalPrompt.innerHTML = TERMINAL_PROMPT;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</BaseLayout>
|
||||
</BaseLayout>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import PostLayout from '../../../layouts/PostLayout.astro';
|
||||
import path from 'path';
|
||||
import { getCollection } from "astro:content";
|
||||
import PostLayout from "../../../layouts/PostLayout.astro";
|
||||
import path from "path";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const allPosts = await getCollection('posts');
|
||||
|
||||
const allPosts = await getCollection("posts");
|
||||
|
||||
const routes = [];
|
||||
|
||||
|
||||
for (const post of allPosts) {
|
||||
const filePath = post.id;
|
||||
|
||||
const pathParts = filePath.split('/');
|
||||
|
||||
const pathParts = filePath.split("/");
|
||||
const category = pathParts[0];
|
||||
|
||||
|
||||
const slug = path.basename(post.id, path.extname(post.id));
|
||||
|
||||
|
||||
routes.push({
|
||||
params: { category, slug },
|
||||
props: { post },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue