Compare commits
14 Commits
7e97459c93
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fbdfebe507 | |||
| 79c5a1f06e | |||
| 6ae23fb783 | |||
| aee0035a4f | |||
| 7f04b1befd | |||
| f6819b42bd | |||
| 650164e412 | |||
| ff22696b49 | |||
| fb291b2725 | |||
| 83bf4b4119 | |||
| ca078295e2 | |||
| 85a2d0345f | |||
| b5337d9b3f | |||
| 1ba5ee1b41 |
@@ -1,6 +1,6 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.next
|
.next
|
||||||
Dockerfile
|
|
||||||
.git
|
.git
|
||||||
.gitignore
|
.gitea
|
||||||
*.mdx
|
*.md
|
||||||
|
.env*
|
||||||
|
|||||||
@@ -14,10 +14,25 @@ jobs:
|
|||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Rebuild and Deploy with Docker Compose
|
- name: Set up Docker Buildx
|
||||||
run: |
|
uses: docker/setup-buildx-action@v3
|
||||||
docker build --target release -t local/gabriel-blog:latest .
|
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
# Clean up any old, unused images to save disk space
|
- name: Build image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
target: release
|
||||||
|
tags: local/gabriel-blog:latest
|
||||||
|
load: true
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=min
|
||||||
|
|
||||||
|
- name: Rotate cache
|
||||||
|
run: |
|
||||||
|
rm -rf /tmp/.buildx-cache
|
||||||
|
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||||
|
|
||||||
|
- name: Deploy and cleanup
|
||||||
|
run: |
|
||||||
|
docker compose up -d
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
3
.gitignore
vendored
@@ -39,3 +39,6 @@ yarn-error.log*
|
|||||||
# typescript
|
# typescript
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
|
# brainstorm
|
||||||
|
.superpowers/
|
||||||
|
|||||||
@@ -130,3 +130,13 @@ body {
|
|||||||
.prose :not(pre) > code::after {
|
.prose :not(pre) > code::after {
|
||||||
content: none !important;
|
content: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Corner ribbon animation ── */
|
||||||
|
@keyframes blink {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.4; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility animate-blink {
|
||||||
|
animation: blink 0.8s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|||||||
49
app/not-found.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import Window from "@/components/window";
|
||||||
|
import GoBackButton from "@/components/go-back-button";
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-md pt-16">
|
||||||
|
<Window title="Oopsie doopsie! You're lost!">
|
||||||
|
<div className="flex items-start gap-4 mb-6">
|
||||||
|
<div className="flex-shrink-0 flex h-10 w-10 items-center justify-center rounded-full bg-red-600 shadow-inner">
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 18 18"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M3 3L15 15M3 15L15 3"
|
||||||
|
stroke="white"
|
||||||
|
strokeWidth="2.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 className="font-bold text-gray-900 text-base mb-1">
|
||||||
|
404 — Not Found
|
||||||
|
</h2>
|
||||||
|
<p className="text-sm text-gray-600 leading-relaxed">
|
||||||
|
The page you're looking for doesn't exist. Check the address or
|
||||||
|
head back home.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t border-gray-200/60 pt-4 flex justify-end gap-2">
|
||||||
|
<GoBackButton />
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
className="px-4 py-1.5 text-sm bg-gradient-to-b from-blue-100 to-blue-200 border border-blue-300 rounded hover:from-blue-200 hover:to-blue-300 transition-colors"
|
||||||
|
>
|
||||||
|
Home
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</Window>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
app/page.tsx
@@ -1,12 +1,20 @@
|
|||||||
import { getSortedPostsData, PostMeta } from "../lib/posts";
|
import { getSortedPostsData, PostMeta } from "../lib/posts";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Window from "../components/window";
|
import Window from "../components/window";
|
||||||
|
import Badges from "../components/badges";
|
||||||
|
|
||||||
|
function isNew(dateStr: string): boolean {
|
||||||
|
const postDate = new Date(dateStr);
|
||||||
|
const now = new Date();
|
||||||
|
const diffDays = (now.getTime() - postDate.getTime()) / (1000 * 60 * 60 * 24);
|
||||||
|
return diffDays <= 30;
|
||||||
|
}
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const allPostsData: PostMeta[] = getSortedPostsData();
|
const allPostsData: PostMeta[] = getSortedPostsData();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-12">
|
<div className="space-y-6">
|
||||||
<header className="text-center">
|
<header className="text-center">
|
||||||
<h1 className="text-5xl font-bold text-white [text-shadow:_2px_2px_4px_rgb(0_0_0_/_40%)]">
|
<h1 className="text-5xl font-bold text-white [text-shadow:_2px_2px_4px_rgb(0_0_0_/_40%)]">
|
||||||
Gabriel's Kaszewski Blog
|
Gabriel's Kaszewski Blog
|
||||||
@@ -17,16 +25,25 @@ export default function Home() {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
{/* The list of posts is displayed inside our custom Window component */}
|
<Window title="Blog Posts" showRss>
|
||||||
<Window title="Blog Posts">
|
|
||||||
{allPostsData.length > 0 ? (
|
{allPostsData.length > 0 ? (
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
{allPostsData.map(({ id, date, title }) => (
|
{allPostsData.map(({ id, date, title, wip }) => (
|
||||||
<li key={id}>
|
<li key={id}>
|
||||||
<Link
|
<Link
|
||||||
href={`/posts/${id}`}
|
href={`/posts/${id}`}
|
||||||
className="block rounded-md bg-white/50 p-4 transition-all duration-200 hover:bg-white/80 hover:shadow-md"
|
className="relative block overflow-hidden rounded-md bg-white/50 p-4 transition-all duration-200 hover:bg-white/80 hover:shadow-md"
|
||||||
>
|
>
|
||||||
|
{isNew(date) && !wip && (
|
||||||
|
<div className="animate-blink absolute top-[10px] right-[-24px] w-[100px] rotate-[35deg] bg-[#e05010] py-0.5 text-center text-[9px] font-bold text-white shadow-sm">
|
||||||
|
NEW!
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{wip && (
|
||||||
|
<div className="absolute top-[10px] right-[-24px] w-[100px] rotate-[35deg] bg-amber-500 py-0.5 text-center text-[9px] font-bold text-white shadow-sm">
|
||||||
|
🚧 WIP
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<h3 className="font-bold text-lg text-blue-800">{title}</h3>
|
<h3 className="font-bold text-lg text-blue-800">{title}</h3>
|
||||||
<small className="text-gray-600">
|
<small className="text-gray-600">
|
||||||
{new Date(date).toLocaleDateString("en-US", {
|
{new Date(date).toLocaleDateString("en-US", {
|
||||||
|
|||||||
@@ -1,37 +1,40 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { getPostData, getAllPostIds } from "@/lib/posts";
|
import { getPostData, getAllPostIds, getAdjacentPosts } from "@/lib/posts";
|
||||||
import type { PostData } from "@/lib/posts";
|
import type { PostData } from "@/lib/posts";
|
||||||
import Window from "../../../components/window";
|
import Window from "@/components/window";
|
||||||
|
import TableOfContents from "@/components/table-of-contents";
|
||||||
import { MDXRemote } from "next-mdx-remote/rsc";
|
import { MDXRemote } from "next-mdx-remote/rsc";
|
||||||
import rehypePrettyCode from "rehype-pretty-code";
|
import rehypePrettyCode from "rehype-pretty-code";
|
||||||
|
import rehypeSlug from "rehype-slug";
|
||||||
|
import remarkGfm from "remark-gfm";
|
||||||
|
import Video from "@/components/video";
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: {
|
params: Promise<{ slug: string }>;
|
||||||
slug: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function tells Next.js which blog posts exist at build time
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
const paths = getAllPostIds();
|
const paths = getAllPostIds();
|
||||||
return paths.map((path) => ({ slug: path.params.slug }));
|
return paths.map((path) => ({ slug: path.params.slug }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates metadata (like the title tag) for each blog post page
|
|
||||||
export async function generateMetadata({ params }: PageProps) {
|
export async function generateMetadata({ params }: PageProps) {
|
||||||
const postData = await getPostData(params.slug);
|
const { slug } = await params;
|
||||||
|
const postData = await getPostData(slug);
|
||||||
return {
|
return {
|
||||||
title: `${postData.title} | Gabriel's Kaszewski Blog`,
|
title: `${postData.title} | Gabriel's Kaszewski Blog`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Post({ params }: PageProps) {
|
export default async function Post({ params }: PageProps) {
|
||||||
// Fetch the specific post's content based on the URL slug
|
const { slug } = await params;
|
||||||
const postData: PostData = await getPostData(params.slug);
|
const postData: PostData = await getPostData(slug);
|
||||||
|
const { prev, next } = getAdjacentPosts(slug);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto max-w-4xl">
|
<div className="mx-auto max-w-6xl">
|
||||||
<Window title={postData.title}>
|
<div className="lg:flex lg:gap-4 lg:items-start">
|
||||||
|
<Window title={postData.title} showProgress className="lg:flex-1 min-w-0">
|
||||||
<article>
|
<article>
|
||||||
<div className="mb-4 text-gray-500 flex flex-col gap-1">
|
<div className="mb-4 text-gray-500 flex flex-col gap-1">
|
||||||
<span>
|
<span>
|
||||||
@@ -41,16 +44,32 @@ export default async function Post({ params }: PageProps) {
|
|||||||
day: "numeric",
|
day: "numeric",
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm text-gray-400">
|
<span className="text-sm text-gray-400">{postData.readingTime}</span>
|
||||||
{postData.readingTime}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="prose lg:prose-xl max-w-none">
|
|
||||||
|
{postData.wip && (
|
||||||
|
<div className="mb-6 flex items-center gap-3 rounded-lg border border-amber-300 bg-amber-50/70 px-4 py-3 text-sm text-amber-800">
|
||||||
|
<span className="text-lg">🚧</span>
|
||||||
|
<span>This post is a work in progress — content may change.</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Mobile TOC — inline above article, hidden on lg+ */}
|
||||||
|
{postData.headings.length > 0 && (
|
||||||
|
<div className="lg:hidden mb-6 bg-white/20 backdrop-blur border border-white/30 rounded-lg p-4">
|
||||||
|
<TableOfContents headings={postData.headings} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="prose lg:prose-lg max-w-none">
|
||||||
<MDXRemote
|
<MDXRemote
|
||||||
source={postData.content}
|
source={postData.content}
|
||||||
|
components={{ Video }}
|
||||||
options={{
|
options={{
|
||||||
mdxOptions: {
|
mdxOptions: {
|
||||||
|
remarkPlugins: [remarkGfm],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
|
rehypeSlug,
|
||||||
[
|
[
|
||||||
rehypePrettyCode,
|
rehypePrettyCode,
|
||||||
{
|
{
|
||||||
@@ -65,13 +84,48 @@ export default async function Post({ params }: PageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</Window>
|
</Window>
|
||||||
<div className="mt-8 text-center">
|
|
||||||
|
{/* Desktop TOC — separate Aero Window, sticky on the right */}
|
||||||
|
{postData.headings.length > 0 && (
|
||||||
|
<div className="hidden lg:block w-56 flex-shrink-0 sticky top-8">
|
||||||
|
<Window title="Contents">
|
||||||
|
<TableOfContents headings={postData.headings} />
|
||||||
|
</Window>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 flex items-center justify-between gap-4">
|
||||||
|
{prev ? (
|
||||||
|
<Link
|
||||||
|
href={`/posts/${prev.id}`}
|
||||||
|
className="inline-block max-w-[38%] truncate rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
|
||||||
|
title={prev.title}
|
||||||
|
>
|
||||||
|
← {prev.title}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span />
|
||||||
|
)}
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="inline-block rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
|
className="inline-block shrink-0 rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
|
||||||
>
|
>
|
||||||
← Back to home
|
Home
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
{next ? (
|
||||||
|
<Link
|
||||||
|
href={`/posts/${next.id}`}
|
||||||
|
className="inline-block max-w-[38%] truncate rounded-full bg-white/80 px-6 py-2 font-semibold text-blue-700 shadow-md transition-all hover:bg-white"
|
||||||
|
title={next.title}
|
||||||
|
>
|
||||||
|
{next.title} →
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
50
bun.lock
@@ -14,7 +14,9 @@
|
|||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"reading-time": "^1.5.0",
|
"reading-time": "^1.5.0",
|
||||||
"rehype-pretty-code": "^0.14.3",
|
"rehype-pretty-code": "^0.14.3",
|
||||||
|
"rehype-slug": "^6.0.0",
|
||||||
"remark": "^15.0.1",
|
"remark": "^15.0.1",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
"remark-html": "^16.0.1",
|
"remark-html": "^16.0.1",
|
||||||
"rss": "^1.2.2",
|
"rss": "^1.2.2",
|
||||||
"shiki": "^4.0.2",
|
"shiki": "^4.0.2",
|
||||||
@@ -254,6 +256,8 @@
|
|||||||
|
|
||||||
"esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="],
|
"esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="],
|
||||||
|
|
||||||
|
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||||
|
|
||||||
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
|
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
|
||||||
|
|
||||||
"estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="],
|
"estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="],
|
||||||
@@ -274,6 +278,8 @@
|
|||||||
|
|
||||||
"extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="],
|
"extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="],
|
||||||
|
|
||||||
|
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||||
|
|
||||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
"gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="],
|
"gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="],
|
||||||
@@ -282,6 +288,8 @@
|
|||||||
|
|
||||||
"hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="],
|
"hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="],
|
||||||
|
|
||||||
|
"hast-util-heading-rank": ["hast-util-heading-rank@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA=="],
|
||||||
|
|
||||||
"hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="],
|
"hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="],
|
||||||
|
|
||||||
"hast-util-sanitize": ["hast-util-sanitize@5.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "unist-util-position": "^5.0.0" } }, "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg=="],
|
"hast-util-sanitize": ["hast-util-sanitize@5.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "unist-util-position": "^5.0.0" } }, "sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg=="],
|
||||||
@@ -358,8 +366,24 @@
|
|||||||
|
|
||||||
"markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
|
"markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
|
||||||
|
|
||||||
|
"markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="],
|
||||||
|
|
||||||
|
"mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="],
|
||||||
|
|
||||||
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="],
|
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="],
|
||||||
|
|
||||||
|
"mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="],
|
||||||
|
|
||||||
|
"mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="],
|
||||||
|
|
||||||
|
"mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="],
|
||||||
|
|
||||||
|
"mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="],
|
||||||
|
|
||||||
|
"mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="],
|
||||||
|
|
||||||
|
"mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="],
|
||||||
|
|
||||||
"mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="],
|
"mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="],
|
||||||
|
|
||||||
"mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
|
"mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="],
|
||||||
@@ -380,6 +404,20 @@
|
|||||||
|
|
||||||
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
|
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="],
|
||||||
|
|
||||||
|
"micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="],
|
||||||
|
|
||||||
"micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="],
|
"micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="],
|
||||||
|
|
||||||
"micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="],
|
"micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "micromark-factory-mdx-expression": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-events-to-acorn": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="],
|
||||||
@@ -494,8 +532,12 @@
|
|||||||
|
|
||||||
"rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="],
|
"rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="],
|
||||||
|
|
||||||
|
"rehype-slug": ["rehype-slug@6.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "github-slugger": "^2.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-to-string": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A=="],
|
||||||
|
|
||||||
"remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="],
|
"remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="],
|
||||||
|
|
||||||
|
"remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="],
|
||||||
|
|
||||||
"remark-html": ["remark-html@16.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "hast-util-sanitize": "^5.0.0", "hast-util-to-html": "^9.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0" } }, "sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ=="],
|
"remark-html": ["remark-html@16.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "hast-util-sanitize": "^5.0.0", "hast-util-to-html": "^9.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0" } }, "sha512-B9JqA5i0qZe0Nsf49q3OXyGvyXuZFDzAP2iOFLEumymuYJITVpiH1IgsTEwTpdptDmZlMDMWeDmSawdaJIGCXQ=="],
|
||||||
|
|
||||||
"remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="],
|
"remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "^3.0.0", "micromark-extension-mdxjs": "^3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="],
|
||||||
@@ -614,6 +656,10 @@
|
|||||||
|
|
||||||
"hast-util-to-jsx-runtime/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"hast-util-to-jsx-runtime/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
|
"mdast-util-find-and-replace/unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="],
|
||||||
|
|
||||||
|
"mdast-util-find-and-replace/unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
|
||||||
|
|
||||||
"mdast-util-from-markdown/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"mdast-util-from-markdown/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
"mdast-util-mdx-jsx/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"mdast-util-mdx-jsx/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
@@ -646,6 +692,10 @@
|
|||||||
|
|
||||||
"vfile-message/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"vfile-message/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
|
"mdast-util-find-and-replace/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
|
"mdast-util-find-and-replace/unist-util-visit-parents/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
|
|
||||||
"mdast-util-phrasing/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
"mdast-util-phrasing/unist-util-is/@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
85
components/badges.tsx
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
interface BadgeProps {
|
||||||
|
href?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Badge({ href, children, style }: BadgeProps) {
|
||||||
|
const base = (
|
||||||
|
<div
|
||||||
|
className="flex items-center justify-center border border-white/40 text-center font-mono leading-tight select-none"
|
||||||
|
style={{ width: 88, height: 31, fontSize: 9, ...style }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (href) {
|
||||||
|
if (href.startsWith("http")) {
|
||||||
|
return (
|
||||||
|
<a href={href} target="_blank" rel="noopener noreferrer" className="hover:opacity-80 transition-opacity">
|
||||||
|
{base}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Link href={href} className="hover:opacity-80 transition-opacity">
|
||||||
|
{base}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Badges() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
<Badge
|
||||||
|
href="https://nextjs.org"
|
||||||
|
style={{ background: "linear-gradient(135deg, #0d0d0d, #1a1a2e)", color: "#7dd3fc", borderColor: "#334155" }}
|
||||||
|
>
|
||||||
|
<span>⬛ Next.js</span>
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
<Badge
|
||||||
|
href="https://bun.sh"
|
||||||
|
style={{ background: "linear-gradient(135deg, #1a0a00, #2d1500)", color: "#fb923c", borderColor: "#7c2d12" }}
|
||||||
|
>
|
||||||
|
🍞 Powered by Bun
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
<Badge
|
||||||
|
style={{ background: "linear-gradient(135deg, #0c1a3a, #1e3a6e)", color: "#93c5fd", borderColor: "#1e40af" }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div>Best viewed</div>
|
||||||
|
<div>1024×768</div>
|
||||||
|
</div>
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
<Badge
|
||||||
|
href="/feed.xml"
|
||||||
|
style={{ background: "linear-gradient(135deg, #431407, #7c2d12)", color: "#fde68a", borderColor: "#b45309" }}
|
||||||
|
>
|
||||||
|
📡 Valid RSS
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
<Badge
|
||||||
|
style={{ background: "linear-gradient(135deg, #0f172a, #1e1b4b)", color: "#c4b5fd", borderColor: "#4c1d95" }}
|
||||||
|
>
|
||||||
|
Made with ♥
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
<Badge
|
||||||
|
style={{ background: "linear-gradient(135deg, #0369a1, #0ea5e9)", color: "white", borderColor: "#38bdf8" }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontSize: 8 }}>✦ Frutiger</div>
|
||||||
|
<div style={{ fontSize: 8 }}>Aero ✦</div>
|
||||||
|
</div>
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
25
components/go-back-button.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function GoBackButton() {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
if (window.history.length > 1) {
|
||||||
|
router.back();
|
||||||
|
} else {
|
||||||
|
router.push("/");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={handleBack}
|
||||||
|
aria-label="Go back to previous page"
|
||||||
|
className="px-4 py-1.5 text-sm bg-gradient-to-b from-blue-100 to-blue-200 border border-blue-300 rounded hover:from-blue-200 hover:to-blue-300 transition-colors"
|
||||||
|
>
|
||||||
|
← Go Back
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
components/reading-progress.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function ReadingProgress() {
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
const scrollable = document.body.scrollHeight - window.innerHeight;
|
||||||
|
if (scrollable > 0) {
|
||||||
|
setProgress((window.scrollY / scrollable) * 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleScroll();
|
||||||
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
|
return () => window.removeEventListener("scroll", handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-[3px] w-full bg-black/20">
|
||||||
|
<div
|
||||||
|
className="h-full transition-[width] duration-100"
|
||||||
|
style={{
|
||||||
|
width: `${progress}%`,
|
||||||
|
background:
|
||||||
|
"linear-gradient(90deg, rgba(255,255,255,0.9) 0%, rgba(180,230,255,0.75) 100%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
64
components/table-of-contents.tsx
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import type { Heading } from "@/lib/posts";
|
||||||
|
|
||||||
|
interface TableOfContentsProps {
|
||||||
|
headings: Heading[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TableOfContents({ headings }: TableOfContentsProps) {
|
||||||
|
const [activeSlug, setActiveSlug] = useState(() => headings[0]?.slug ?? "");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (headings.length === 0) return;
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
setActiveSlug(entry.target.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ rootMargin: "0% 0% -70% 0%", threshold: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
headings.forEach(({ slug }) => {
|
||||||
|
const el = document.getElementById(slug);
|
||||||
|
if (el) observer.observe(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [headings]);
|
||||||
|
|
||||||
|
if (headings.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav>
|
||||||
|
<p className="text-xs font-bold uppercase tracking-widest text-blue-800 mb-3">
|
||||||
|
Contents
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-1.5">
|
||||||
|
{headings.map(({ slug, text, level }) => (
|
||||||
|
<li
|
||||||
|
key={slug}
|
||||||
|
className={level === 3 ? "pl-3" : ""}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={`#${slug}`}
|
||||||
|
aria-current={activeSlug === slug ? "true" : undefined}
|
||||||
|
className={`text-sm leading-snug transition-colors duration-150 ${
|
||||||
|
activeSlug === slug
|
||||||
|
? "text-blue-700 font-semibold"
|
||||||
|
: "text-gray-600 hover:text-blue-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
components/video.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
interface VideoProps {
|
||||||
|
src: string;
|
||||||
|
caption?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Video({ src, caption }: VideoProps) {
|
||||||
|
return (
|
||||||
|
<figure className="my-4">
|
||||||
|
<div className="rounded-lg border border-white/30 bg-white/10 backdrop-blur-sm overflow-hidden shadow-md">
|
||||||
|
<video
|
||||||
|
src={src}
|
||||||
|
className="w-full"
|
||||||
|
aria-label={caption ?? src}
|
||||||
|
preload="metadata"
|
||||||
|
controls
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{caption && (
|
||||||
|
<figcaption className="mt-2 text-center text-sm text-gray-500 italic">
|
||||||
|
{caption}
|
||||||
|
</figcaption>
|
||||||
|
)}
|
||||||
|
</figure>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import RSSIcon from "./rss-icon";
|
import RSSIcon from "./rss-icon";
|
||||||
|
import ReadingProgress from "./reading-progress";
|
||||||
|
|
||||||
const CloseIcon = () => (
|
const CloseIcon = () => (
|
||||||
<svg
|
<svg
|
||||||
@@ -45,23 +46,30 @@ interface WindowProps {
|
|||||||
title: string;
|
title: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
showProgress?: boolean;
|
||||||
|
showRss?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Window({
|
export default function Window({
|
||||||
title,
|
title,
|
||||||
children,
|
children,
|
||||||
className = "",
|
className = "",
|
||||||
|
showProgress = false,
|
||||||
|
showRss = false,
|
||||||
}: WindowProps) {
|
}: WindowProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`rounded-lg border border-white/30 bg-white/70 shadow-window backdrop-blur-xl ${className}`}
|
className={`rounded-lg border border-white/30 bg-white/70 shadow-window backdrop-blur-xl ${className}`}
|
||||||
>
|
>
|
||||||
<div className="flex select-none items-center justify-between rounded-t-md bg-gradient-to-b from-blue-500 to-window-title px-4 py-1.5 font-bold text-white text-sm">
|
<div className="rounded-t-md overflow-hidden sticky top-0 z-10">
|
||||||
|
<div className="flex select-none items-center justify-between bg-gradient-to-b from-blue-500 to-window-title px-4 py-1.5 font-bold text-white text-sm">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<span>{title}</span>
|
<span>{title}</span>
|
||||||
|
{showRss && (
|
||||||
<Link href="/feed.xml" title="RSS Feed">
|
<Link href="/feed.xml" title="RSS Feed">
|
||||||
<RSSIcon className="h-4 w-4 opacity-80 hover:opacity-100" />
|
<RSSIcon className="h-4 w-4 opacity-80 hover:opacity-100" />
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="flex h-4 w-4 items-center justify-center opacity-80">
|
<div className="flex h-4 w-4 items-center justify-center opacity-80">
|
||||||
@@ -78,6 +86,8 @@ export default function Window({
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{showProgress && <ReadingProgress />}
|
||||||
|
</div>
|
||||||
<div className="p-6">{children}</div>
|
<div className="p-6">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
39
lib/posts.ts
@@ -2,9 +2,16 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import matter from 'gray-matter';
|
import matter from 'gray-matter';
|
||||||
import readingTime from 'reading-time';
|
import readingTime from 'reading-time';
|
||||||
|
import { notFound } from 'next/navigation';
|
||||||
|
|
||||||
const postsDirectory = path.join(process.cwd(), 'posts');
|
const postsDirectory = path.join(process.cwd(), 'posts');
|
||||||
|
|
||||||
|
export interface Heading {
|
||||||
|
level: number;
|
||||||
|
text: string;
|
||||||
|
slug: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PostData {
|
export interface PostData {
|
||||||
id: string;
|
id: string;
|
||||||
date: string;
|
date: string;
|
||||||
@@ -12,6 +19,8 @@ export interface PostData {
|
|||||||
description: string;
|
description: string;
|
||||||
content: string;
|
content: string;
|
||||||
readingTime: string;
|
readingTime: string;
|
||||||
|
headings: Heading[];
|
||||||
|
wip: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PostMeta {
|
export interface PostMeta {
|
||||||
@@ -20,6 +29,22 @@ export interface PostMeta {
|
|||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
readingTime: string;
|
readingTime: string;
|
||||||
|
wip: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractHeadings(content: string): Heading[] {
|
||||||
|
const regex = /^(#{2,3})\s+(.+)$/gm;
|
||||||
|
const headings: Heading[] = [];
|
||||||
|
let match;
|
||||||
|
while ((match = regex.exec(content)) !== null) {
|
||||||
|
const text = match[2].trim();
|
||||||
|
const slug = text
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/(^-|-$)/g, '');
|
||||||
|
headings.push({ level: match[1].length, text, slug });
|
||||||
|
}
|
||||||
|
return headings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSortedPostsData(): PostMeta[] {
|
export function getSortedPostsData(): PostMeta[] {
|
||||||
@@ -40,6 +65,7 @@ export function getSortedPostsData(): PostMeta[] {
|
|||||||
title: matterResult.data.title as string,
|
title: matterResult.data.title as string,
|
||||||
description: matterResult.data.description as string,
|
description: matterResult.data.description as string,
|
||||||
readingTime: stats.text,
|
readingTime: stats.text,
|
||||||
|
wip: matterResult.data.wip ?? false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,8 +89,19 @@ export function getAllPostIds() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAdjacentPosts(slug: string): { prev: PostMeta | null; next: PostMeta | null } {
|
||||||
|
const posts = getSortedPostsData(); // newest → oldest
|
||||||
|
const index = posts.findIndex((p) => p.id === slug);
|
||||||
|
if (index === -1) return { prev: null, next: null };
|
||||||
|
return {
|
||||||
|
prev: posts[index + 1] ?? null, // older
|
||||||
|
next: posts[index - 1] ?? null, // newer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function getPostData(id: string): Promise<PostData> {
|
export async function getPostData(id: string): Promise<PostData> {
|
||||||
const fullPath = path.join(postsDirectory, `${id}.mdx`);
|
const fullPath = path.join(postsDirectory, `${id}.mdx`);
|
||||||
|
if (!fs.existsSync(fullPath)) notFound();
|
||||||
const fileContents = fs.readFileSync(fullPath, 'utf8');
|
const fileContents = fs.readFileSync(fullPath, 'utf8');
|
||||||
const matterResult = matter(fileContents);
|
const matterResult = matter(fileContents);
|
||||||
const stats = readingTime(matterResult.content);
|
const stats = readingTime(matterResult.content);
|
||||||
@@ -76,5 +113,7 @@ export async function getPostData(id: string): Promise<PostData> {
|
|||||||
title: matterResult.data.title,
|
title: matterResult.data.title,
|
||||||
description: matterResult.data.description,
|
description: matterResult.data.description,
|
||||||
readingTime: stats.text,
|
readingTime: stats.text,
|
||||||
|
headings: extractHeadings(matterResult.content),
|
||||||
|
wip: matterResult.data.wip ?? false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
4167
package-lock.json
generated
Normal file
@@ -18,17 +18,19 @@
|
|||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"reading-time": "^1.5.0",
|
"reading-time": "^1.5.0",
|
||||||
"rehype-pretty-code": "^0.14.3",
|
"rehype-pretty-code": "^0.14.3",
|
||||||
|
"rehype-slug": "^6.0.0",
|
||||||
"remark": "^15.0.1",
|
"remark": "^15.0.1",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
"remark-html": "^16.0.1",
|
"remark-html": "^16.0.1",
|
||||||
"rss": "^1.2.2",
|
"rss": "^1.2.2",
|
||||||
"shiki": "^4.0.2"
|
"shiki": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"@tailwindcss/postcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"tailwindcss": "^4"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
posts/about-me.mdx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "About Me"
|
||||||
|
description: "First post — introducing myself as an 17-year-old developer from Gdańsk with big dreams."
|
||||||
|
date: "2019-05-09"
|
||||||
|
---
|
||||||
|
|
||||||
|
First of all, I am aware that blogs are kind of a 2010–2012 thing. But since I am really bored and I've watched a lot of Victorious and iCarly recently, I thought that I'll also make my own blog, or at least try...
|
||||||
|
|
||||||
|
So, let's talk about me.
|
||||||
|
|
||||||
|
Hi, I'm an 17-year-old boy who lives in Gdańsk, Poland — well, for at least five days a week. I go to III High School and I'm in a bilingual class.
|
||||||
|
|
||||||
|
Like every other teenager, I have hobbies. My main hobby is **programming**. I've been coding since I was 11. I started with C++ but moved into C# very quickly. Currently, I make mobile apps, desktop applications, games, microservices, and many other interesting things. In the future, I want to work as a Software Developer in a big tech company like Google or Microsoft.
|
||||||
|
|
||||||
|
I also take photos. In my junior high, I had Photography classes and since then I've been interested in it. Although I don't plan anything with it in my future — it'll stay as a hobby, I guess.
|
||||||
|
|
||||||
|
Another hobby is very related to the last one: **filmmaking**. Since I was a little kid I wanted to make movies. When I was 11, I uploaded my first video on YouTube — not really a movie, but a Minecraft let's play I recorded with my friend. After that I started uploading other let's plays, tutorials, and vlogs. I've been to some summer camps where I learned how to make a movie, write a script, etc. I also was in a film group in my primary school and junior high. I've made 3 short movies but I want to make more.
|
||||||
|
|
||||||
|
This year I started going to the gym and... I loved it. I recommend everyone start going — it's fun and you can improve your health a lot.
|
||||||
|
|
||||||
|
Despite all those things, I'm trying to learn how to play the guitar and how to sing. The singing part is a spontaneous decision. I kinda like singing but I suck at it, so I want to learn how to do it properly. I'm pretty sure I'm gonna fail, but hey — it's worth trying, isn't it?
|
||||||
|
|
||||||
|
After high school, I want to study Computer Science and Data Engineering. Then I want to move to the United States, probably somewhere near Silicon Valley, and start my life there. I've wanted that since I was a little kid. My ultimate life goal is to have a good life, a lovely family, and a great job.
|
||||||
|
|
||||||
|
Okay, I think this is everything. I'm pretty sure no one will read this but I don't care — I just wanted to write some stuff and put it on the internet.
|
||||||
|
|
||||||
|
Have a nice day!
|
||||||
17
posts/beginning-of-tough-week.mdx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: "The Beginning of a Tough Week"
|
||||||
|
description: "3:30 AM coding sessions, a Physics homework nightmare, and a week packed with tests ahead."
|
||||||
|
date: "2019-05-13"
|
||||||
|
---
|
||||||
|
|
||||||
|
It's 3:30 AM on a Monday morning. Saturday's party was great — I danced a lot and, of course, ate a lot too.
|
||||||
|
|
||||||
|
Today I finally got my test project for work. I thought it was going to be much harder than it actually was. I've just finished working on those tasks. For almost 3 hours I was trying just to *run* the project. It took me that long because CMake couldn't find the libraries, so I downloaded Linux and did my work there.
|
||||||
|
|
||||||
|
Now I'm working on my Physics homework, which is not easy — mostly because I have no idea how to do it. My task is to draw a graph of a planet's journey around the sun and its apparent retrograde motion. The main problem is that I've got no idea where to get the data about Mars positions. I'll probably end up making them up.
|
||||||
|
|
||||||
|
This whole week isn't going to be easy either. On Tuesday I'm retaking two recent Math exams and I also have a Chemistry test. On Wednesday there's a Geography pop quiz from Europe's physical relief map. On Thursday I think I'm free, but I'll study before Friday's Math test.
|
||||||
|
|
||||||
|
As you can see, this week is really tough. But the bright side is that after this week, summer break will be a little closer.
|
||||||
|
|
||||||
|
Okay, I gotta get back to that Physics homework.
|
||||||
17
posts/boring-civics-class.mdx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: "Boring civics class, blood drawn, and lime coke"
|
||||||
|
description: "First day back after teacher strikes, downloading my Google data, and anxiously waiting for a job test project."
|
||||||
|
date: "2019-05-09"
|
||||||
|
---
|
||||||
|
|
||||||
|
Welcome! Today it was my first day in school since last month. Teachers in my country went on strike, so we didn't have classes. But the strike is over — and so is my free time.
|
||||||
|
|
||||||
|
I had easy classes today: civics, English, two hours of Polish, and that's it. Civics was the worst. My teacher somehow changes the speed of the clock — I always feel like it's two hours instead of one. Today's topic actually wasn't that bad though; we were talking about the European Union and how it works, because last week was the 15th anniversary of Poland joining the EU. Tomorrow I have a day off because I'm going to the doctor.
|
||||||
|
|
||||||
|
After school I went home, watched a new episode of Riverdale on Netflix, and then downloaded my Google, Snapchat, and Facebook data. I found a few interesting things — for example, I didn't know that when Google tracks my location, it saves whether I was walking or driving. I also found some really embarrassing things from my past.
|
||||||
|
|
||||||
|
I've been checking my email for almost 8 days now. I'm waiting for a test project that will decide if I'm going to get a job as a C++ Software Engineer. I'm so pumped about this but also a little afraid. If I get this job, I'd have to keep up with school and work at the same time. I don't know how I'm going to do it, but I'll figure it out later. The job is 100% remote so that's at least good news. I've never worked before so all of this is new to me, and I'm thrilled.
|
||||||
|
|
||||||
|
I haven't had dinner yet and I'm literally starving — I had blood drawn this morning and couldn't have breakfast, so today I've eaten only two chocolate bars and drank lime coke so far.
|
||||||
|
|
||||||
|
I think that's it for now. Really, I gotta eat something.
|
||||||
15
posts/chill-saturday.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "Chill Saturday"
|
||||||
|
description: "Housework, singing practice, and exciting news about an early summer break."
|
||||||
|
date: "2019-05-18"
|
||||||
|
---
|
||||||
|
|
||||||
|
Hey! I've just pushed the last changes to my test project for work.
|
||||||
|
|
||||||
|
Today's weather was awesome. In the morning it was sunny, then it rained for a while, and now it's sunny and really warm. I was alone in the house so I did groceries, laundry, and washed dishes. After all that housework I had a little time for myself before I had to go back to work, so I practiced my singing. Actually, it wasn't that bad — I think I'm getting better at it. Maybe I'll do some covers soon, who knows.
|
||||||
|
|
||||||
|
A funny thing happened today: the Prime Minister of Poland said that summer break is going to be sooner than it was supposed to be. I'm going to have a summer vacation in literally a month. I'm so happy about this news. I just have to survive the next two weeks and I'll finally be free.
|
||||||
|
|
||||||
|
Well, not really free — if my evaluation tomorrow goes great, I'll have to work. But that's okay.
|
||||||
|
|
||||||
|
I tried to record something for my YouTube channel but didn't have any ideas. So I think that's it for today. See you soon.
|
||||||
19
posts/decisions.mdx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
title: "Decisions"
|
||||||
|
description: "Weighing university options from Poland to Stanford, and discovering Gavin James and MAX."
|
||||||
|
date: "2020-03-11"
|
||||||
|
---
|
||||||
|
|
||||||
|
As you may already know, I'm a junior in high school, which means I'll have to choose a college soon. So today I took my time and checked universities in my country, in Europe, and I also looked at Stanford University. Having done that, I've come to some conclusions.
|
||||||
|
|
||||||
|
Firstly, I would love to study in the US, especially in California. But if I wanted to accomplish that, I'd have to start working on my GPA (which is not the best right now — 3.40) and prepare for the SAT. Secondly, I couldn't find any university in Europe (excluding the UK) that would suit me best, and I don't want to go study abroad just for the sake of it. If I went abroad, I'd want to study at a prestigious university that is respected globally.
|
||||||
|
|
||||||
|
Poland has some pretty good universities, but they rank very low in both world and European rankings. So I have to decide now, because there's a lot to do. If I choose Stanford, I'll have to ask teachers for recommendation letters, write a personal essay, and register for the SAT in Poland. Fortunately, Stanford doesn't require TOEFL.
|
||||||
|
|
||||||
|
The biggest problem is my GPA. I kind of messed up my grades during my freshman year and I can't change those anymore — they're pulling my GPA down. To hit a 4.0, I'd need to get top marks in Math, Physics, Spanish, and Polish. Maybe not all of it, but Math will definitely be the hardest. I'm not really worried about the SAT though — I did a mock one a few months ago and it went pretty well. The Math section was actually the easiest part.
|
||||||
|
|
||||||
|
I'll have to do more research on European universities. Maybe something will catch my eye.
|
||||||
|
|
||||||
|
On a completely different note: since last week I've been listening to Gavin James and MAX (also known as Max Schneider). I find Gavin's music very soothing, especially his album *Only Ticket Home*. I used to listen to MAX through Kurt Hugo Schneider's covers. Kurt also makes great music — if you haven't listened to him yet, go check him out. You might like it.
|
||||||
|
|
||||||
|
I think this is all for now. See ya sometime in the future!
|
||||||
19
posts/end-of-july.mdx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
title: "The End of July"
|
||||||
|
description: "Lake house fishing, C++ and math homework, Minecraft, The Lion King, and Victoria Justice's new song."
|
||||||
|
date: "2019-08-01"
|
||||||
|
---
|
||||||
|
|
||||||
|
So July has come to an end. It's been a quite normal month — I haven't done anything particularly special.
|
||||||
|
|
||||||
|
I spent last week at the lake house with my family. I didn't bring a computer, so instead I took a book about C++ programming and my math notebook, calculator, and pencil case — because my math teacher sent me an email with 4 PDF files full of exercises about quadratic functions. I knew the day would come when my teacher would email me homework during vacation. And sadly it did. Actually, I was surprised that I still remembered how to solve those exercises and still had the equations down.
|
||||||
|
|
||||||
|
The lake house was near an actual lake, so I wanted to try fishing a little. I didn't have a fishing rod, so I made one myself. It was a really satisfying experience. I managed to catch 3 fish.
|
||||||
|
|
||||||
|
When I got back, I spent most of the week playing Minecraft and coding a game in C++. I'm really glad that Minecraft got popular again and that I actually have fun playing it. I feel like I'm 10 again.
|
||||||
|
|
||||||
|
Also, an amazing thing happened this week: Victoria Justice posted on Instagram that she's recording a brand new song! I'm so happy — I had literally just started listening to her songs and was thinking "I wonder when she'll make a new song," and then BANG, a new one is coming.
|
||||||
|
|
||||||
|
Oh, and I almost forgot — I went to see *The Lion King* twice! I was skeptical before seeing it, but after I watched it I changed my mind. I really liked the remake, although the original is still the best.
|
||||||
|
|
||||||
|
So that wraps up my recent activities. As you can see, nothing too crazy happened — maybe except for the Victoria thing.
|
||||||
13
posts/first-of-september.mdx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
title: "1st of September"
|
||||||
|
description: "Summer's over, moving into a new apartment, and reflecting on a surprisingly productive vacation."
|
||||||
|
date: "2019-09-01"
|
||||||
|
---
|
||||||
|
|
||||||
|
So summertime has come and gone... and unfortunately, school starts tomorrow.
|
||||||
|
|
||||||
|
I've just moved into a new apartment with my best friend. Honestly, I'm a little worried about the upcoming school year — math is going to be much harder, and I'm living alone for the first time in my life.
|
||||||
|
|
||||||
|
To summarize my vacation: I did many interesting nerdy things. I built my own blog website (didn't deploy it though), wrote a video sharing website (same story), started writing a dating website (didn't finish), made a short movie (I have to publish it someday), got better at C++ programming, and finally became more productive — although I put off gym training and now I'll have to start again at some point.
|
||||||
|
|
||||||
|
Okay, I think this is all for now. See ya.
|
||||||
21
posts/hey-ho-im-alive.mdx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
title: "Hey Ho... I Am Alive"
|
||||||
|
description: "Adjusting to living alone, surviving a brutal school schedule, and squeezing in some coding between naps."
|
||||||
|
date: "2019-10-11"
|
||||||
|
---
|
||||||
|
|
||||||
|
Yeah, I know — I wasn't posting anything for a while. Honestly, I didn't expect such a big change in my life.
|
||||||
|
|
||||||
|
First of all, living alone (without your parents) is quite challenging. There are a lot of house chores I didn't notice before. The fridge becomes empty *very* quickly so I have to do groceries every two days. You're running short on flatware every time you want to prepare something to eat. It's not as great as you'd think.
|
||||||
|
|
||||||
|
School doesn't give me any slack either. I have a lot of math and physics. My daily routine looks something like this: wake up, grab something to eat (usually cornflakes), go to school, stop at the store on the way to buy lunch, sit through 7–8 hours of school, go back to the apartment, take a nap (sometimes 3 hours), prepare dinner, do homework and prepare for the next day's classes, take a shower, and finally go to sleep.
|
||||||
|
|
||||||
|
I don't have much time to code anything or practice singing or playing an instrument. This week I brought my harmonica and wanted to practice, but — no time.
|
||||||
|
|
||||||
|
Even though there are a lot of classes, my grades are not that bad so far. Tomorrow I have a very important math test and a Polish test. I honestly hate Polish as a school subject. It is so pointless and irritating. Nevertheless, I somehow managed to work a little on my video sharing website, and I'm quite proud of the result. It still looks ugly but I don't care about the frontend right now — the backend works perfectly.
|
||||||
|
|
||||||
|
HackHeroes started this week. It's an IT contest where contestants have to come up with an app that helps solve one of the global problems. I still have no idea what I want to build, but I'll figure it out.
|
||||||
|
|
||||||
|
Unfortunately, I stopped going to the gym. The reason is simple: no time, and no gym near me anymore. I was thinking about doing some in-house training but I haven't prepared a plan yet.
|
||||||
|
|
||||||
|
Anyway, it's already 2 AM and I still have a lot of studying to do. See you sometime in the future.
|
||||||
15
posts/hope.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "Hope"
|
||||||
|
description: "Math resit passed, test postponed, surviving on sleep deprivation with summer break just 26 days away."
|
||||||
|
date: "2019-05-15"
|
||||||
|
---
|
||||||
|
|
||||||
|
It's Wednesday afternoon — finally, half of the week is behind me. My Math resit went great and I got a better grade. Friday's test was postponed to next week, so I don't have any tests or pop quizzes until the end of this week.
|
||||||
|
|
||||||
|
But I'm really sleep-deprived. I don't sleep because I've got homework, the Erasmus project, and my job. On the other hand, I only have 26 more days to get through like this, and then I'll have a summer break. I can definitely do it.
|
||||||
|
|
||||||
|
Yesterday I watched *No Kiss List* and *The Outcast*. The Outcast was quite boring but No Kiss List turned out to be fine. My whole body is sore today because I went to the gym yesterday — my first training after almost a two-week break.
|
||||||
|
|
||||||
|
From now on, no more breaks. Summer is closer every day, and I gotta work on my body.
|
||||||
|
|
||||||
|
Okay, I think that's it for now.
|
||||||
15
posts/i-got-a-job.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "I Got a Job!"
|
||||||
|
description: "Landing my first commercial programming job in the game dev industry — despite never wanting to work in game dev."
|
||||||
|
date: "2019-10-23"
|
||||||
|
---
|
||||||
|
|
||||||
|
So I finally got my first job. I'm obviously very happy, but the whole thing is a little ironic. I've always said I don't want to work in the game dev industry — and yet my first job is in the game dev industry.
|
||||||
|
|
||||||
|
I got hired as a programmer (obviously). Unfortunately I can't write much about it because I signed an NDA. But I can tell you that the job is great and it's good money. Of course, I'm happy for more reasons than just the pay — I'll finally have some commercial experience on my resume, which should make getting new jobs easier. Or at least that's what I hope.
|
||||||
|
|
||||||
|
My school life is also great right now. I passed all the exams and my grades are solid. Although I do miss hanging out with friends and summer parties — I don't have much time for those anymore.
|
||||||
|
|
||||||
|
So yeah, that was a quick life update. Have a nice day!
|
||||||
|
|
||||||
|
*(I really have to improve the formatting of these posts. Maybe I'll do it this weekend.)*
|
||||||
15
posts/interesting-friday.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "Interesting Friday"
|
||||||
|
description: "Doctor's visit, a new suit, pizza, and finally watching Avengers: Endgame."
|
||||||
|
date: "2019-05-11"
|
||||||
|
---
|
||||||
|
|
||||||
|
What a day. I slept only an hour today and didn't go to school because I had an appointment with the doctor. I waited for an hour because my mom got stuck in traffic. The doctor said everything is okay with me, so I'm happy. After the short visit we drove back to my city.
|
||||||
|
|
||||||
|
Tomorrow I'm going to my cousin's 18th birthday party and I didn't have a suit, so we went to the city center and bought me a new one. Then my sister and I went to some restaurant to get pizza. Weirdly I couldn't finish mine, which was strange because I was starving. Then I went home and as soon as I got there, I fell asleep. When I woke up it was 10 PM, so I finally watched Avengers: Endgame.
|
||||||
|
|
||||||
|
**Spoiler warning!**
|
||||||
|
|
||||||
|
I'm sad that the directors killed Tony Stark and not Captain America.
|
||||||
|
|
||||||
|
Okay, it's 3 AM now and I'll try to go back to sleep.
|
||||||
17
posts/interesting-weekend.mdx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: "Interesting Weekend"
|
||||||
|
description: "Discovering Ron Pope, party games, watching a Bill Gates documentary, and ordering books."
|
||||||
|
date: "2019-10-27"
|
||||||
|
---
|
||||||
|
|
||||||
|
It's Sunday, 10 PM, and I sat down to write this post. This weekend passed so quickly. I don't remember anything from Friday to be honest — nothing really happened. Saturday was quite interesting: I was working, dealing with documents, and also did some house chores like vacuuming, cleaning dishes, and taking out the trash.
|
||||||
|
|
||||||
|
I started listening to Ron Pope, especially *Bitterness or Sympathy* and *One Grain of the Sand*. When I was in 4th grade I heard *A Drop in the Ocean* and really liked it, and this week while I was studying with Spotify in the background, those songs came on. I'm glad that happened. Thanks to Spotify's auto-play, I also discovered the AJR band a few years ago — and by the way, they dropped a new single this week: *Dear Winter 2.0*.
|
||||||
|
|
||||||
|
In the evening I had a party at my friend's house. We chatted, played some party games like spin the bottle and never have I ever. We also managed to dance what we call in Poland "Belgian dance." It was quite challenging because we did it in a very small room, but it was fun.
|
||||||
|
|
||||||
|
Today I was also working, and had a small chat with my coworker about deadlines. I watched one part of a documentary about Bill Gates and it motivated me to start reading books again. So I ordered *A Brief History of Time* by Stephen Hawking and *The Subtle Art of Not Giving a F\*ck*. I also watched *17 Again* — loved it. I love stupid comedies. So I watched another one: *American Pie 2*. Also great. Fun fact: I've never actually watched the original *American Pie*, so I'll have to fix that soon.
|
||||||
|
|
||||||
|
The upcoming week is going to be a piece of work. I have a few exams and I have to retake a Physics test and a recent Spanish pop quiz — both of which I failed. But I'll worry about that later.
|
||||||
|
|
||||||
|
To summarize: I'm happy and a little tired. That's it for now.
|
||||||
17
posts/july-update.mdx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: "What Has Been Going On With My Life and Other Things..."
|
||||||
|
description: "Playing the DOS Dune game, Minecraft, web development, and rewriting a microservice."
|
||||||
|
date: "2019-07-22"
|
||||||
|
---
|
||||||
|
|
||||||
|
So July is coming to an end — well, not really, but half of it is already gone. For all that time I've been doing literally nothing. Hence the no new posts.
|
||||||
|
|
||||||
|
Today I discovered the old DOS game *Dune*, which is an adaptation of Frank Herbert's novel. I read that book back in April and it was amazing. Currently I'm on the third part of the series. Anyway, the game turned out to be really addictive. I spent 5 hours playing it today instead of Minecraft — which, by the way, I started playing again (thanks PewDiePie). Sadly, Dune keeps crashing at one specific mission and I can't progress anymore.
|
||||||
|
|
||||||
|
I did a little web development during the first week of July. I wrote my own blog platform. But I'm too lazy to finish configuring it for deployment, so I'm still using Blogger for these posts. Yesterday I rewrote a microservice for my music streaming platform.
|
||||||
|
|
||||||
|
Unfortunately I stopped going to the gym. I guess vacation time made me really lazy.
|
||||||
|
|
||||||
|
Last week I finished watching Stranger Things season 3. I was surprised because this season was actually good — I didn't like the previous one.
|
||||||
|
|
||||||
|
So I have no idea what else to write, so I guess bye until the next post!
|
||||||
25
posts/learning-spanish.mdx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
title: "Learning Spanish"
|
||||||
|
description: "Planning a Flutter app to gamify Spanish vocabulary learning because passive sitting in class just wasn't cutting it."
|
||||||
|
date: "2019-05-09"
|
||||||
|
---
|
||||||
|
|
||||||
|
Hello, it's me again. This is my 3rd post today. Anyway — this year I started learning Spanish, or I should say I signed up for Spanish classes at school, because I don't really *learn* there.
|
||||||
|
|
||||||
|
What I mean is that I attend the classes but I mostly just sit passively and listen to whatever the teacher says. So I decided to change my attitude. I was thinking for a while about how I can learn vocabulary and grammar in the fastest and most efficient way, and I came up with a solution.
|
||||||
|
|
||||||
|
Since I'm lazy and a programmer, I thought about making a simple app. A few months back I was making a game — an FPS shooter where, to destroy an enemy, you have to type the Spanish equivalent of an English word shown on the screen. I didn't finish that project, but I did make a tool that takes a CSV file with data and converts it into a JSON file. That way I can easily add words to a dictionary and parse it through the application.
|
||||||
|
|
||||||
|
The app itself will show me a new word (one in English, one in Spanish). But since I'm lazy and I really doubt I'll open the app every day, I'd have the option to add a widget to my home screen and have the app send me a daily notification. Might sound complicated, but it's not. All I need is a cup of tea and the Flutter docs.
|
||||||
|
|
||||||
|
I really need to start actually learning Spanish because:
|
||||||
|
|
||||||
|
1. I'd love to know this language.
|
||||||
|
2. It would boost my self-esteem.
|
||||||
|
3. I could brag that I know Spanish. 😂
|
||||||
|
|
||||||
|
So far I only know how to greet and introduce myself, read and speak, count, and describe my appearance or someone else's.
|
||||||
|
|
||||||
|
*Mi español es pobre.*
|
||||||
|
|
||||||
|
*Nos vemos más tarde, amigos!*
|
||||||
@@ -25,6 +25,8 @@ But that wasn't all I did in the first month of 2024. I had this crazy idea to c
|
|||||||
|
|
||||||
Next, I wrote a **Minesweeper** game in C++ using Raylib. That was pretty fun! The code, however, isn't really good—it's not idiomatic C++, more like C with classes—but the point of the project was just to have fun. That’s why I’m not going to link the repo. However, if someone is interested, they can easily find it on my GitHub.
|
Next, I wrote a **Minesweeper** game in C++ using Raylib. That was pretty fun! The code, however, isn't really good—it's not idiomatic C++, more like C with classes—but the point of the project was just to have fun. That’s why I’m not going to link the repo. However, if someone is interested, they can easily find it on my GitHub.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## February - Small but Fun Projects
|
## February - Small but Fun Projects
|
||||||
|
|
||||||
February, the shortest month of the year! I hopped from project to project, but some were actually finished and published.
|
February, the shortest month of the year! I hopped from project to project, but some were actually finished and published.
|
||||||
@@ -37,18 +39,28 @@ You might ask, _Why use Rust for that instead of JavaScript?_ Great question! Th
|
|||||||
|
|
||||||
Next, I started working on a **Missile Commander clone**—a recreation of the old Atari game **Missile Command**. I actually managed to replicate the core gameplay, but since I’m terrible at designing games and coming up with new mechanics, levels, and features, I abandoned it pretty quickly. I even wrote a **level editor** for it! The game and editor were both written in Rust using **macroquad**, as I wanted to export it to the web. Unfortunately, I ran into some errors when trying to export and gave up.
|
Next, I started working on a **Missile Commander clone**—a recreation of the old Atari game **Missile Command**. I actually managed to replicate the core gameplay, but since I’m terrible at designing games and coming up with new mechanics, levels, and features, I abandoned it pretty quickly. I even wrote a **level editor** for it! The game and editor were both written in Rust using **macroquad**, as I wanted to export it to the web. Unfortunately, I ran into some errors when trying to export and gave up.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<Video src="/posts/missile_commander.mp4" />
|
||||||
|
|
||||||
## March - A Sokoban Game in Java
|
## March - A Sokoban Game in Java
|
||||||
|
|
||||||
In March, I only worked on one toy project—a **Sokoban game in Java** using Raylib. Why Java? No idea. I guess I just wanted to refresh my skills in the language.
|
In March, I only worked on one toy project—a **Sokoban game in Java** using Raylib. Why Java? No idea. I guess I just wanted to refresh my skills in the language.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## April - The RTS Struggle
|
## April - The RTS Struggle
|
||||||
|
|
||||||
In April, I really wanted to create an **RTS game**. Unfortunately, I didn’t succeed. Nevertheless, I made an attempt at creating an **RTS engine in Rust** using the _comfy_ crate. Later, I tried moving to Bevy, but pathfinding defeated me. I haven't given up on the idea completely, though—I may go back to it in the future, because I love RTS and strategy games so much.
|
In April, I really wanted to create an **RTS game**. Unfortunately, I didn’t succeed. Nevertheless, I made an attempt at creating an **RTS engine in Rust** using the _comfy_ crate. Later, I tried moving to Bevy, but pathfinding defeated me. I haven't given up on the idea completely, though—I may go back to it in the future, because I love RTS and strategy games so much.
|
||||||
|
|
||||||
|
<Video src="/posts/rts.mp4" caption="My failed RTS engine attempt" />
|
||||||
|
|
||||||
While researching RTS mechanics, I wrote my own **quadtree** in Rust and visualized it using Raylib. That was pretty fun and easy.
|
While researching RTS mechanics, I wrote my own **quadtree** in Rust and visualized it using Raylib. That was pretty fun and easy.
|
||||||
|
|
||||||
I also got into **ray tracing** and, thanks to _Ray Tracing in One Weekend_, I wrote my own **software ray tracer** in Rust.
|
I also got into **ray tracing** and, thanks to _Ray Tracing in One Weekend_, I wrote my own **software ray tracer** in Rust.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Another Rust project from April was an **Otodom scraper** with a frontend in React. Otodom is a website listing real estate for sale or rent, and since I was house-hunting, I needed a better way to filter available listings. So I wrote a simple service using _Axum_ that scrapes the data every ten minutes, allowing me to easily filter through listings.
|
Another Rust project from April was an **Otodom scraper** with a frontend in React. Otodom is a website listing real estate for sale or rent, and since I was house-hunting, I needed a better way to filter available listings. So I wrote a simple service using _Axum_ that scrapes the data every ten minutes, allowing me to easily filter through listings.
|
||||||
|
|
||||||
Last but not least, I created **better_notepad**, a Notepad-like app because I was annoyed that the default Windows Notepad didn’t close tabs when the app was closed. I wrote mine in C++ with wxWidgets. Later, I learned that you can actually turn that behavior off in the Notepad settings... oops.
|
Last but not least, I created **better_notepad**, a Notepad-like app because I was annoyed that the default Windows Notepad didn’t close tabs when the app was closed. I wrote mine in C++ with wxWidgets. Later, I learned that you can actually turn that behavior off in the Notepad settings... oops.
|
||||||
@@ -57,10 +69,16 @@ Last but not least, I created **better_notepad**, a Notepad-like app because I w
|
|||||||
|
|
||||||
In May, I started a **2D platformer in Unity**, inspired by **Brave Dwarves 2** (a childhood favorite). I focused on **composition over inheritance**, and I loved that approach—so much that I still use it in all future projects. Unfortunately, I abandoned the game.
|
In May, I started a **2D platformer in Unity**, inspired by **Brave Dwarves 2** (a childhood favorite). I focused on **composition over inheritance**, and I loved that approach—so much that I still use it in all future projects. Unfortunately, I abandoned the game.
|
||||||
|
|
||||||
|
<Video src="/posts/dwarves.mp4" />
|
||||||
|
|
||||||
I also built a **tiny social network** inspired by the late 2000s and early 2010s, when social media was more about you and your friends rather than memes, ads, and algorithm-driven feeds. My idea was simple: users could publish short thoughts (up to 128 characters), follow friends, and see only their friends' posts in the feed. I used Django, but I plan to rewrite it in Rust for lower memory usage. I might even make it **decentralized using ActivityPub**, because I recently fell in love with that concept.
|
I also built a **tiny social network** inspired by the late 2000s and early 2010s, when social media was more about you and your friends rather than memes, ads, and algorithm-driven feeds. My idea was simple: users could publish short thoughts (up to 128 characters), follow friends, and see only their friends' posts in the feed. I used Django, but I plan to rewrite it in Rust for lower memory usage. I might even make it **decentralized using ActivityPub**, because I recently fell in love with that concept.
|
||||||
|
|
||||||
|
<Video src="/posts/thoughts-2024.mp4" />
|
||||||
|
|
||||||
I also built my own **r/place clone** in Rust, using WebSockets via _socket.io_ and plain JavaScript for the client. It worked pretty well! However, I ran into an issue where I was sending data inefficiently, which caused massive memory usage—something like **~100MB per user connection**. I don’t remember if I ever fixed it, but debugging network-related stuff is still a bit of a mystery to me.
|
I also built my own **r/place clone** in Rust, using WebSockets via _socket.io_ and plain JavaScript for the client. It worked pretty well! However, I ran into an issue where I was sending data inefficiently, which caused massive memory usage—something like **~100MB per user connection**. I don’t remember if I ever fixed it, but debugging network-related stuff is still a bit of a mystery to me.
|
||||||
|
|
||||||
|
<Video src="/posts/rplace.mp4" />
|
||||||
|
|
||||||
## June - A Grand Strategy Game Attempt
|
## June - A Grand Strategy Game Attempt
|
||||||
|
|
||||||
In June, I made another attempt at an **RTS/Strategy game**, this time a **turn-based grand strategy game** similar to _Civilization_. I used **Bevy** and the **hexx crate**, but as you can imagine, I didn’t get very far—I got stuck on the turn system :p
|
In June, I made another attempt at an **RTS/Strategy game**, this time a **turn-based grand strategy game** similar to _Civilization_. I used **Bevy** and the **hexx crate**, but as you can imagine, I didn’t get very far—I got stuck on the turn system :p
|
||||||
@@ -73,16 +91,22 @@ In **August**, I experimented with **Godot** and started developing a **boomer s
|
|||||||
|
|
||||||
This was yet another project I left unfinished. While I enjoy working with **Godot**, I found its 3D tools a bit too clunky for my workflow.
|
This was yet another project I left unfinished. While I enjoy working with **Godot**, I found its 3D tools a bit too clunky for my workflow.
|
||||||
|
|
||||||
|
<Video src="/posts/boomer_shooter_attempt.mp4" />
|
||||||
|
|
||||||
## September - My Own Podcast Platform
|
## September - My Own Podcast Platform
|
||||||
|
|
||||||
In September, I built my own **podcast platform**! I wrote the backend in **Loco.rs** and the frontend in **Svelte**. I was really happy with how it turned out, but after recording just **one episode**, I lost interest. Shame.
|
In September, I built my own **podcast platform**! I wrote the backend in **Loco.rs** and the frontend in **Svelte**. I was really happy with how it turned out, but after recording just **one episode**, I lost interest. Shame.
|
||||||
|
|
||||||
|
<Video src="/posts/podcast.mp4" />
|
||||||
|
|
||||||
In the meantime, I created a **mod for VTOL VR**, which currently has **623 subscribers**! One day, I would love to create my own **VR game**, but for now, I have **zero ideas** for what it could be :<
|
In the meantime, I created a **mod for VTOL VR**, which currently has **623 subscribers**! One day, I would love to create my own **VR game**, but for now, I have **zero ideas** for what it could be :<
|
||||||
|
|
||||||
## December - Back to Game Development
|
## December - Back to Game Development
|
||||||
|
|
||||||
In December, I tried **Advent of Code**, but I gave up after **three days** :p. Instead, I started working again on my **2D platformer game, Mr. Brick Adventures**. This time, I _vow_ to finish it and release it on **Steam**! I’m using **Godot** again, and I have to admit—it’s quite nice for 2D development. I wanted to use Rust, but it was a bit too tedious, so I stuck with GDScript.
|
In December, I tried **Advent of Code**, but I gave up after **three days** :p. Instead, I started working again on my **2D platformer game, Mr. Brick Adventures**. This time, I _vow_ to finish it and release it on **Steam**! I’m using **Godot** again, and I have to admit—it’s quite nice for 2D development. I wanted to use Rust, but it was a bit too tedious, so I stuck with GDScript.
|
||||||
|
|
||||||
|
<Video src="/posts/mr_brick_2024.mp4" />
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 2025 Roadmap
|
# 2025 Roadmap
|
||||||
|
|||||||
15
posts/my-life.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "My Life"
|
||||||
|
description: "Feeling sick before important exams and a party, reviving Twitter, and hoping to survive the night."
|
||||||
|
date: "2019-05-21"
|
||||||
|
---
|
||||||
|
|
||||||
|
Tuesday, 10 PM — I finally came back to being alive. I slept for 4 hours right after I came back from school.
|
||||||
|
|
||||||
|
Lately I've been having this weird cough but it didn't hurt or anything so I simply ignored it. But today after the second period I was shaking a little bit and didn't feel well. I still don't feel right — I have a headache and I'm pretty sure I have a fever. But I have to keep studying and pretend like I'm not sick for two reasons.
|
||||||
|
|
||||||
|
First, I have really important exams this weekend so I can't miss them. Second, my friend is throwing a party this Saturday and I really want to go — so I have to feel better by Friday.
|
||||||
|
|
||||||
|
Recently I also revived my Twitter account, so I'm quite active on social media these days.
|
||||||
|
|
||||||
|
That's it for today. To the next time... I hope I'm not going to die in my sleep tonight.
|
||||||
17
posts/quite-active-friday.mdx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: "Quite Active Friday"
|
||||||
|
description: "Skipped the date but had a great gym session, swam at the lake alone, and caught a breathtaking sunset."
|
||||||
|
date: "2019-06-15"
|
||||||
|
---
|
||||||
|
|
||||||
|
So I didn't ask my crush out. Apparently she came to Gdańsk with her friends when I was on the train back home, so we couldn't really meet.
|
||||||
|
|
||||||
|
Instead of going on a date, I went to the gym and had an amazing training session. I did my usual full body workout and some abs exercises, but today was different — after my routine I did cardio and some boxing. I have to say, I loved punching the punching bag. I'm considering training boxing for real. It could be useful, and it's a great exercise for improving physical condition. Also, when you're punching a bag, you can completely blow off steam you've gathered over a whole week. That's amazing.
|
||||||
|
|
||||||
|
After the gym, I finally got my bike from the basement and rode to the lake. Unfortunately I was alone there because some of my friends were with my crush in Gdańsk and others weren't available. So I swam for a while and rode back home.
|
||||||
|
|
||||||
|
On my way back I saw such an amazing sunset. It was the most breathtaking view I've seen this year. I was really upset that I didn't have my DSLR camera with me. Well, I didn't lose much — every summer I have this view, so I'll take a picture of it someday and post it here.
|
||||||
|
|
||||||
|
When I got back I made myself a second dinner: scrambled eggs with beef steaks and a strawberry milkshake my mom made before. After that I worked a little on my game, and now I'm writing this post while waiting for Flutter to finish updating so I can implement new features to my app. After that I want to start coding a brand new app — more info on that later.
|
||||||
|
|
||||||
|
So to sum up: no date today, but I did awesome things anyway. I see this as an absolute win.
|
||||||
@@ -20,14 +20,14 @@ Nevertheless, Rust got me interested and I feel like writing some simple 2D game
|
|||||||
|
|
||||||
The second technology is **Machine Learning**. Machine learning has become more and more popular lately; the famous [Chat GPT](https://chat.openai.com/), or [stable-diffusion](https://stablediffusionweb.com/), [MidJourney](https://www.midjourney.com/) and many other machine learning projects. Machine learning has interested me a lot since middle school, but somehow I can't grasp it. I understand the theory and how neural networks work, but I can't create a model that recognizes how many fingers we show, for example. I'd like to grasp this eventually and create one project I've been considering for about a year. It's a project that involves automatic audio de-noising, I know [OBS](https://obsproject.com/) has such filters, although I'd like to make my own software for this, yes for educational purposes. My next project is to automatically create .srt files based on song lyrics and audio. In January I created a [mod](https://github.com/GKaszewski/BeatLyrics) for [BeatSaber](https://beatsaber.com/) that adds song lyrics, unfortunately, the mod requires an srt file with the given time and lyrics. I would like to automate the process of creating these files, just using artificial intelligence to do it.
|
The second technology is **Machine Learning**. Machine learning has become more and more popular lately; the famous [Chat GPT](https://chat.openai.com/), or [stable-diffusion](https://stablediffusionweb.com/), [MidJourney](https://www.midjourney.com/) and many other machine learning projects. Machine learning has interested me a lot since middle school, but somehow I can't grasp it. I understand the theory and how neural networks work, but I can't create a model that recognizes how many fingers we show, for example. I'd like to grasp this eventually and create one project I've been considering for about a year. It's a project that involves automatic audio de-noising, I know [OBS](https://obsproject.com/) has such filters, although I'd like to make my own software for this, yes for educational purposes. My next project is to automatically create .srt files based on song lyrics and audio. In January I created a [mod](https://github.com/GKaszewski/BeatLyrics) for [BeatSaber](https://beatsaber.com/) that adds song lyrics, unfortunately, the mod requires an srt file with the given time and lyrics. I would like to automate the process of creating these files, just using artificial intelligence to do it.
|
||||||
|
|
||||||
_A dog generated by MidJourney AI_
|
_A dog generated by MidJourney AI_
|
||||||
|
|
||||||
The last thing is **game dev** in a broad sense. Creating games in **_Typescript_**, making some games in VR in [Unity](https://unity.com/), finishing a clone of **_Sammy Suricate_**, and super if I could make some simple strategy game. I love RTS games.
|
The last thing is **game dev** in a broad sense. Creating games in **_Typescript_**, making some games in VR in [Unity](https://unity.com/), finishing a clone of **_Sammy Suricate_**, and super if I could make some simple strategy game. I love RTS games.
|
||||||
|
|
||||||
_My Sammy Suricate clone. Made in Unity_
|
_My Sammy Suricate clone. Made in Unity_
|
||||||
|
|
||||||
### Conclusion (none)
|
### Conclusion (none)
|
||||||
|
|
||||||
That's pretty much it at the moment, it's pretty late and I think I'll keep updating this post as something else pops into this crazy head of mine. For now, this is my farewell to you and I wish you a good day.
|
That's pretty much it at the moment, it's pretty late and I think I'll keep updating this post as something else pops into this crazy head of mine. For now, this is my farewell to you and I wish you a good day.
|
||||||
|
|
||||||
_Aaaaaand this is my cat. Piernik ✨_
|
_Aaaaaand this is my cat. Piernik ✨_
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ In the previous post I have written that I would have wanted to get into Rust. I
|
|||||||
Okay, so the first 'project' that I did in Rust was a simple program that creates Mandelbrot's set image. The code for that was provided by the book _Programming Rust: Fast, Safe Systems Development 2nd Edition_
|
Okay, so the first 'project' that I did in Rust was a simple program that creates Mandelbrot's set image. The code for that was provided by the book _Programming Rust: Fast, Safe Systems Development 2nd Edition_
|
||||||
I did it because it seemed cool and in High School I made similar program but in Java.
|
I did it because it seemed cool and in High School I made similar program but in Java.
|
||||||
This one was more interesting because it used multithreading.
|
This one was more interesting because it used multithreading.
|
||||||

|

|
||||||
But that was just a **hello world** program, I did not write my 'own' code.
|
But that was just a **hello world** program, I did not write my 'own' code.
|
||||||
|
|
||||||
**Repo:** [mandelbrot](https://github.com/GKaszewski/mandelbrot)
|
**Repo:** [mandelbrot](https://github.com/GKaszewski/mandelbrot)
|
||||||
@@ -38,6 +38,8 @@ Repo: [screensaver](https://github.com/GKaszewski/screensaver)
|
|||||||
|
|
||||||
The last project that I have been working on is asteroids game. It is actually just a remake of my C project (I used SDL2 for that one). In this one I am using **Bevy engine** and I have to admit it is pretty handy and straight-forward to use. I love the data driven design. I have yet still to add HUD, power-ups, boss fight and second-player feature to the game and then I will publish it on my website. In the future I am planning to make my first **commercial game** with Bevy. But we will see.
|
The last project that I have been working on is asteroids game. It is actually just a remake of my C project (I used SDL2 for that one). In this one I am using **Bevy engine** and I have to admit it is pretty handy and straight-forward to use. I love the data driven design. I have yet still to add HUD, power-ups, boss fight and second-player feature to the game and then I will publish it on my website. In the future I am planning to make my first **commercial game** with Bevy. But we will see.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Conclusion
|
### Conclusion
|
||||||
|
|
||||||
Rust is fun, I had no idea that I would find myself in that language but I am pleasantly surprised. Same thing was with Python 😜. I really love the eco-system of Rust. Cargo is just the best. I hated in C and C++ the linking and compiling of external libraries and setting up the toolchain, in Rust all of those problems just fade away. The match feature is also cool.
|
Rust is fun, I had no idea that I would find myself in that language but I am pleasantly surprised. Same thing was with Python 😜. I really love the eco-system of Rust. Cargo is just the best. I hated in C and C++ the linking and compiling of external libraries and setting up the toolchain, in Rust all of those problems just fade away. The match feature is also cool.
|
||||||
|
|||||||
15
posts/school-trip.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "School Trip"
|
||||||
|
description: "Writing from a hotel in Poznań, exhausted from sightseeing, and planning to finally ask my crush out."
|
||||||
|
date: "2019-06-11"
|
||||||
|
---
|
||||||
|
|
||||||
|
So I haven't been posting anything new for a while. Honestly, I don't have much time lately — every weekend I go out with my friends or go to parties. My social life is quite decent now and I'm really glad about that.
|
||||||
|
|
||||||
|
Right now I'm lying on the bed in my hotel room. I'm in Poznań on my school trip. The trip is actually pretty good. I'm exhausted from walking and visiting a lot of buildings, but the vibe is good and the weather is great. Today it was 93°F — that's insane. Tomorrow is going to be at least 96°F. I think I'm gonna melt.
|
||||||
|
|
||||||
|
But honestly I can't wait to get back to Gdańsk. I'm going to ask my crush out, so I'm excited and terrified at the same time. I'd be so happy if she said yes. I hope I find the courage to actually do it on Friday.
|
||||||
|
|
||||||
|
The thing I'm most worried about is that our relationship will get worse if she says no. But whoever doesn't take action doesn't really know what life is about — or something like that.
|
||||||
|
|
||||||
|
Wish me luck, and hopefully I'll write about my amazing date on Friday night.
|
||||||
23
posts/solved-problem.mdx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: "Solved Problem"
|
||||||
|
description: "A breakthrough in socializing, realizing conversations work differently than I thought, and reflecting on work habits."
|
||||||
|
date: "2019-11-07"
|
||||||
|
---
|
||||||
|
|
||||||
|
Today a magical thing happened. I accidentally solved my problem with having conversations with people.
|
||||||
|
|
||||||
|
I've always had trouble starting a conversation with anyone. I thought that asking questions like "how are you?" or "how was your day?" was stupid because they didn't give me any valuable information. So by thinking that way, I struggled with socializing.
|
||||||
|
|
||||||
|
But today I came to the realization that this is completely normal — asking casual questions. And this is brilliant. If I know how to start a conversation, I can talk with people more often, and I'll be less awkward around them. What's more, I boosted my self-esteem and started caring less about what people think about me. Previously I didn't really care either, but I wasn't very confident or sure about my actions.
|
||||||
|
|
||||||
|
I also realized that girls are actual human beings. I know that sounds weird, so let me explain. When I was talking with a girl, I had some filter on — I was choosing my words very carefully for no real reason. But recently I stopped doing that, and the results are awesome. You can actually just have a normal conversation.
|
||||||
|
|
||||||
|
I watched *The Society* and it gave me a lot to think about. I really didn't expect to come away with thoughts from a teen drama TV show. I kept thinking: how would I and my friends deal with a similar situation?
|
||||||
|
|
||||||
|
I've slowly started to regret some of my life decisions. I have a job and that's great, but I am so not qualified for it. I know how to code and I think I'm a decent coder, but the job turned out not to be about coding that much. There are so many things I wasn't prepared for.
|
||||||
|
|
||||||
|
Also, school gave me bad habits around deadlines — I'm used to doing all my homework or school projects just one day before the deadline. And that is **so wrong** in the real world. I need to start sticking to my schedule.
|
||||||
|
|
||||||
|
So I have a few things to work on. One: I have to really get to work. Two: I have to prepare my TED Talk for the Erasmus thing. Three: I have to finally ask my crush out. Hopefully I'll do all of it by the end of November.
|
||||||
|
|
||||||
|
See ya!
|
||||||
19
posts/summer-time.mdx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
title: "Summer Time"
|
||||||
|
description: "Missing friends during summer break, working on games, a birthday party, and discovering Jon Bellion and classical music."
|
||||||
|
date: "2019-06-30"
|
||||||
|
---
|
||||||
|
|
||||||
|
The second week of my vacation has just started, and I have to admit — even though I have summer break — I don't feel as happy as I thought I would. I guess the problem is the absence of my friends. Some went to various summer camps, others are working, so we can't hang out together.
|
||||||
|
|
||||||
|
Nevertheless, I managed to finish my Spanish learning game last week. Now I'm working on a Pepsiman remake with a friend. I'm also still working on my other projects like my game engine and some other things.
|
||||||
|
|
||||||
|
Yesterday I was at my cousin's 18th birthday party and it was a really great one. This time I wasn't the photographer — my ex-classmate from junior high took that job. I talked with her about some stuff and danced with her and obviously other people too. I don't really like dancing because I just don't know how to dance. But if it's a party, you've got to have fun, so dancing is what you do.
|
||||||
|
|
||||||
|
Sadly I haven't been to the gym since June 15th. This makes me sad. I can't motivate myself to go. Even though I really want to, it's 90°F so I spend most of my time at the lake, and when I come back I'm too tired to go. Maybe it'll change this week.
|
||||||
|
|
||||||
|
Recently I started listening to Jon Bellion and — wait for it — classical music. It's really weird. I've never liked classical music, but a few days ago when I was sunbathing on the patio I thought: let's try some classical music. And since that moment I listen to it. It turned out it's not as bad as I always thought.
|
||||||
|
|
||||||
|
And Jon Bellion's music makes me really happy. My favorites are Stupid Deep (acoustic version), 80s Films, and Human (acoustic version).
|
||||||
|
|
||||||
|
So that's it for now. How is your summer break?
|
||||||
21
posts/task-failed-successfully.mdx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
title: "Task Failed Successfully"
|
||||||
|
description: "Getting rejected but feeling accomplished anyway, and figuring out that having money is surprisingly hard to manage."
|
||||||
|
date: "2019-11-21"
|
||||||
|
---
|
||||||
|
|
||||||
|
I was meaning to write this post last week but I got caught up in homework and work, so I'm writing it now.
|
||||||
|
|
||||||
|
Last week was wonderful. I finally got enough courage and asked out my crush. You're probably curious about her response — well, she said no. She said she didn't want to date anyone at that moment, so I got rejected. But I was quite happy with the result. I mean, I finally asked somebody out. The feeling of overcoming your fear is awesome. By doing it I boosted my confidence so much.
|
||||||
|
|
||||||
|
My cousin's daughter had her 1-year birthday party on Saturday, so naturally we went. I actually enjoyed my time there — I talked to my uncle about my job and economics.
|
||||||
|
|
||||||
|
This week, on the other hand, was strange. I was feeling weird. Last week I had been feeling somewhat accomplished and full of joy. But this week was completely different — I didn't have any goal to accomplish, which could explain the weird feelings. I got some not-so-great grades and had two difficult tests.
|
||||||
|
|
||||||
|
But I also got paid yesterday, and oh man... that feeling when you get your payment is so joyous I honestly can't describe it. You have to experience it yourself.
|
||||||
|
|
||||||
|
And with it, I found a new problem to solve. I started spending money like water. The problem is that I have a fairly nice bank balance at the moment, and when I spend 100 or 50 PLN, I don't see that much change in my account. So my brain thinks I'm not spending much and proceeds to spend even more. And **this is bad**.
|
||||||
|
|
||||||
|
I guess I have to get used to having a little more money than I've ever had before.
|
||||||
|
|
||||||
|
So the last two weeks flew right in front of my eyes. Thanksgiving is next week but my family doesn't celebrate it, so I'm just waiting for Black Friday — maybe I'll buy something cool this year.
|
||||||
15
posts/the-final-week.mdx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: "The Final Week!"
|
||||||
|
description: "Erasmus visitors, a massive house party, and just two tests left before summer freedom."
|
||||||
|
date: "2019-06-02"
|
||||||
|
---
|
||||||
|
|
||||||
|
Hello everybody! I haven't posted anything new for a while — it was caused mostly by my social life and school. I'm so glad that I started going out with my friends again on weekends. I really missed it.
|
||||||
|
|
||||||
|
Last week I had the Erasmus thing going on at school. I have to admit, my English wasn't that bad compared to the Italian and Portuguese guys. Also last week I was at an amazing party at my friend's house. It was supposed to be a small gathering but it turned into a really big one — instead of 30 people, almost 40 came. And it wouldn't have been that bad if they hadn't brought gallons of alcohol. I actually didn't drink much through the whole party. Right at the beginning I drank the beer I had bought before, and later I didn't drink anything. So I was sober through the entire event. I helped my best friend keep the house safe, talked with my friends, and helped one of them down the stairs. To summarize: the party was great.
|
||||||
|
|
||||||
|
The week after the party wasn't the best, but I made it through. That Erasmus thing was really interesting and I'm definitely going to take part in such an event next year. It's a lot of fun and you get to meet people from different cultures across Europe. I really liked the Dutch students — their English was decent and they were friendly. They tried to teach me some Dutch but failed. It's impossible for me to pronounce those sentences.
|
||||||
|
|
||||||
|
This week is my **final week** with tests. I only have two more and then I'm completely free. After Wednesday I can chill by the seashore. Can't wait to come back home. I'm going with some friends to a lake to play volleyball and swim, and later we'll probably set a campfire. Also during this week I'm probably going to work a little on my game.
|
||||||
|
|
||||||
|
I hope tomorrow's Physics test will be easy. That's it for tonight.
|
||||||
37
posts/what-have-i-been-up-to.mdx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
title: "What Have I Been Up to Lately?"
|
||||||
|
description: "Four months of life updates: losing and gaining a job, turning 18, writing audio software, and a birthday party."
|
||||||
|
date: "2020-02-24"
|
||||||
|
---
|
||||||
|
|
||||||
|
My last post was a very long time ago — four months to be exact. During that period I lost my job but got another one, became an adult, got addicted to Minecraft again, lost interest in ukulele (which I'd picked up during Christmas), wrote audio recording software, and became more attractive and handsome. I'd had no idea that was even possible. I was already perfect. (/s)
|
||||||
|
|
||||||
|
But let's start from the beginning.
|
||||||
|
|
||||||
|
## December
|
||||||
|
|
||||||
|
The first half of December was pretty terrible. There were a lot of tests and I had a lot of stuff from work on my plate. We were running 2 weeks behind schedule and there were a lot of unresolved tickets. I couldn't keep up with Math, Physics, and work at the same time. I knew I had to drop either my education or work. That problem ended up solving itself at the beginning of January — more on that later.
|
||||||
|
|
||||||
|
The second half of December was much more pleasant. First: Christmas break — no school. Second: I love Christmas season because my entire family gathers at my grandparents' house and there's this friendly, loving vibe everywhere. The smells are great. It's just magical. Third: I was playing Minecraft constantly and enjoying it like I did when I was a little kid back in 2011–2013.
|
||||||
|
|
||||||
|
The last night of that decade I spent at my friend's house at a New Year's party. There were a lot of people — my friends and their friends. The party was great.
|
||||||
|
|
||||||
|
## January
|
||||||
|
|
||||||
|
Which brings us to January 1st... oh boy, it was a very busy night. I came back home around 11 AM, sat down at my desk, and played Minecraft. Around 5 PM I packed my stuff and went back to my friend's house because we were heading back to our apartment in Gdańsk for school. I was pretty hungry — I hadn't eaten anything all day. When we got to the apartment I made myself french fries and grabbed a diet coke from the fridge. Then I went to sleep.
|
||||||
|
|
||||||
|
A week and a half after the Christmas break we had another one: Winter Break, which lasted two weeks as usual. During that break I hung out with friends and slept through most of it. Oh, and I got another job — this time making a website for the dental clinic where my mom works. After the break there were those exams again. Obviously I passed all of them. I did have to retake one Math test about polynomial equations and inequalities, but I got a 4 from the retake, which was nice.
|
||||||
|
|
||||||
|
My music taste also expanded: Jon Bellion and his *The Human Condition* album, and Michael Jackson. I actually didn't know that "I Want You Back" was originally performed by The Jacksons — I thought it was created for the show *Victorious*. Every day you learn something new.
|
||||||
|
|
||||||
|
## February
|
||||||
|
|
||||||
|
I have a warm feeling about this month — my birthday is on the 27th, and I have nice memories tied to this time of year.
|
||||||
|
|
||||||
|
During the first week, I wrote audio recording software and started working on another piece of software: a screen recorder. I haven't completed it yet, but I'm very close. I also think I finally figured out OpenGL, which is a huge milestone.
|
||||||
|
|
||||||
|
I had my 18th birthday party on the 15th. It was quite decent. Last week I took a mock bilingual English "matura" exam (something like the SATs in the US), and the last task is always to write an opinion essay. Well, I hadn't written any essays in a while, and this one I wrote so badly I can't even describe it. There was no structure. Arguments were weak. It seemed like I had no idea what I wanted to say — which honestly wasn't that far from the truth.
|
||||||
|
|
||||||
|
Today I helped my friend shoot a short ad for his class. We had a lot of fun even though it was freezing cold and raining outside. But we managed to shoot it, and the results are astonishing.
|
||||||
|
|
||||||
|
Well, that's it for today. Have a nice day and stay safe!
|
||||||
|
After Width: | Height: | Size: 970 KiB |
BIN
public/posts/asteroids2.webp
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
public/posts/boomer_shooter_attempt.mp4
Executable file
BIN
public/posts/cat.jpg
Executable file
|
After Width: | Height: | Size: 48 KiB |
BIN
public/posts/dwarves.mp4
Executable file
BIN
public/posts/minesweeper.webp
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
public/posts/missile_commander.mp4
Executable file
BIN
public/posts/missile_commander.webp
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
public/posts/mr_brick_2024.mp4
Executable file
BIN
public/posts/output.png
Executable file
|
After Width: | Height: | Size: 976 KiB |
BIN
public/posts/podcast.mp4
Executable file
BIN
public/posts/raytracer.webp
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
public/posts/rplace.mp4
Executable file
BIN
public/posts/rts.mp4
Executable file
BIN
public/posts/screenshot-2022-12-28T19-05-22-0041341Z.png
Executable file
|
After Width: | Height: | Size: 867 KiB |
BIN
public/posts/sokoban.webp
Normal file
|
After Width: | Height: | Size: 109 KiB |