Initial commit
All checks were successful
Build / build (push) Successful in 17s

This commit is contained in:
2025-12-14 16:48:50 +00:00
commit 97eb93d3af
29 changed files with 3127 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
name: Build
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Install pnpm
uses: https://github.com/pnpm/action-setup@v4
with:
version: 9
run_install: false
- name: Install node
uses: https://github.com/actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Install packages
run: pnpm install
- name: Build project
run: pnpm run build
- name: Check project
run: pnpm run check
- name: Upload artifact
run: |
tar -czf build.tar.gz build
curl --user minijack:${{ secrets.PACKAGE_TOKEN }} \
--upload-file build.tar.gz \
https://git.quartznet.info/api/packages/quartznet/generic/artifacts/ref-${{ gitea.sha }}/build-${{ gitea.sha }}.tar.gz
echo https://git.quartznet.info/api/packages/quartznet/generic/artifacts/ref-${{ gitea.sha }}/build-${{ gitea.sha }}.tar.gz

View File

@@ -0,0 +1,27 @@
name: Deploy
on:
workflow_dispatch:
runs-on: selfhost
jobs:
deploy:
runs-on: selfhost
steps:
- uses: actions/checkout@v2
- name: Get artifact
run: |
curl --user minijack:${{ secrets.PACKAGE_TOKEN }} \
https://git.quartznet.info/api/packages/quartznet/generic/artifacts/ref-${{ gitea.sha }}/build-${{ gitea.sha }}.tar.gz > build.tar.gz
echo https://git.quartznet.info/api/packages/quartznet/generic/artifacts/ref-${{ gitea.sha }}/build-${{ gitea.sha }}.tar.gz
- name: Extract artifact
run: |
tar -xvzf build.tar.gz
- run: ls -la build
- run: ls -la /www/
- run: ls -la /www/quartznet-info/
- name: Clean Deploy Area
run: rm -rf /www/quartznet-info/build
- name: Deploy
run: mv build /www/quartznet-info/

4
.gitignore vendored Executable file
View File

@@ -0,0 +1,4 @@
.content-collections
.svelte-kit
build
node_modules

7
README.md Executable file
View File

@@ -0,0 +1,7 @@
# rgebee-info
Personal website.
1. `pnpm install`
2. `pnpm dev`

47
content-collections.ts Executable file
View File

@@ -0,0 +1,47 @@
import { defineCollection, defineConfig } from "@content-collections/core";
import { z } from "zod";
import remarkGfm from "remark-gfm";
import remarkParse from 'remark-parse'
import rehypePrettyCode from "rehype-pretty-code";
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'
import { unified } from 'unified'
const parser = unified()
.use(remarkParse)
.use(remarkGfm)
.use(remarkRehype)
.use(rehypeStringify)
.use(rehypePrettyCode, {
theme: "catppuccin-macchiato"
});
const posts = defineCollection({
name: "posts",
directory: "src/content/blog",
include: "**/*.md",
schema: z.object({
title: z.string(),
description: z.string(),
dateCreated: z.coerce.date(),
dateUpdated: z.coerce.date().optional(),
draft: z.boolean().optional(),
html: z.string().optional(),
slug: z.string().optional()
}),
transform: async (doc) => {
if (doc.content) {
const processed = await parser.process(doc.content);
return {
...doc,
html: String(processed),
slug: doc._meta.fileName.slice(0, -3),
};
}
return doc;
}
});
export default defineConfig({
collections: [posts],
});

33
package.json Executable file
View File

@@ -0,0 +1,33 @@
{
"name": "rgebee-info",
"version": "0.0.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@content-collections/core": "^0.11.1",
"@content-collections/vite": "^0.2.7",
"@shikijs/rehype": "^3.14.0",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.48.3",
"@sveltejs/vite-plugin-svelte": "^5.1.1",
"rehype-pretty-code": "^0.14.1",
"rehype-stringify": "^10.0.1",
"remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.2",
"shiki": "^3.14.0",
"svelte": "^5.43.0",
"svelte-check": "^4.3.3",
"svelte-preprocess": "^6.0.3",
"typescript": "^5.9.3",
"unified": "^11.0.5",
"vite": "^7.1.12",
"zod": "^4.1.12"
},
"type": "module"
}

2187
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

14
src/app.html Executable file
View File

@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="description" content="Personal website" />
<link rel="stylesheet" href="/global.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
%sveltekit.head%
</head>
<body>
%sveltekit.body%
</body>
</html>

13
src/app.ts Normal file
View File

@@ -0,0 +1,13 @@
import { allPosts } from 'content-collections';
import type { Post } from 'content-collections';
export const SITE_AUTHOR = 'Rgebee';
export const SITE_TITLE = SITE_AUTHOR;
export const SITE_DESCRIPTION = 'Personal website';
export const SITE_URL = 'https://rgebee.quartznet.info';
export async function getBlogCollection(): Promise<Post[]> {
return (allPosts)
.filter(post => import.meta.env.DEV || !post.draft)
.sort((a, b) => b.dateCreated.valueOf() - a.dateCreated.valueOf());
}

View File

@@ -0,0 +1,30 @@
---
title: 'Desktop workflow thoughts'
description: 'Lorem ipsum dolor sit amet'
dateCreated: 'Oct 31 2025'
draft: true
---
Finding ways to be more efficient using my desktop. My goal was to quickly switch between windows and improve my
understanding of what options I have for my workflow.
## Starting out
I started by trying a few small features in the KDE desktop environment. I was used to floating so before trying
other options I wanted to see how efficient floating could get. The first thing I did was pin apps to the
taskbar allowing me to use shortcuts to quickly switch to them. Then I also tried some settings to maximise
windows by default. This sort of worked though had some issues(popups, not applying to certain windows).
## Improving things
Next I started using workspaces, took some time to adjust but I found it helped manage windows into tasks. I settled
on 3 main workspaces. Initially I kept using pinned apps but after a while switched to workspace shortcuts. This allowed me to easily change window focus on a workspace. For example browser on workspace 1, switch to file explorer
on workspace 1 and now meta+1 will show that instead.
## Tiling
The next part you see many videos and discussion about is tiling. For me I had 3 workspaces so flat tiling didn't work
for me since I couldn't have more than 1 maximised window per workspace and managing more workspaces added friction
I didn't want.
Though that is only flat tiling(no overlapping windows). That leaves 2 other options, tabbing and scrolling.

View File

@@ -0,0 +1,8 @@
---
title: 'Overthinking blog creation'
description: 'Lorem ipsum dolor sit amet'
dateCreated: 'Oct 31 2025'
draft: true
---
Testing

View File

@@ -0,0 +1,87 @@
---
title: 'Testing post content styles'
description: 'Lorem ipsum dolor sit amet'
dateCreated: 'Oct 28 2025'
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce bibendum neque eget
nunc mattis eu sollicitudin enim tincidunt. Vestibulum lacus tortor, ultricies id
dignissim ac, bibendum in velit.
# Test subheading (h1)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
## Test subheading (h2)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
### Test subheading (h3)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
#### Test subheading (h4)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
##### Test subheading (h5)
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
## Test unordered list
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Bullet point in the list
* Bullet point in the list
* Bullet point in the list
* Bullet point in the list
* Bullet point in the list
## Test ordered list
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
1. First item in the list
2. Second item in the list
3. Third item in the list
4. Fourth item in the list
## Test code
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```html
<html>
<head>
<title>Test title</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
```
## Test image
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
![xkcd computer problems](/images/computer-problems.png)
## Test blockquote
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
> Lorem ipsum dolor sit amet, consectetur adipiscing elit.
> Lorem ipsum dolor sit amet, consectetur adipiscing elit.
## Test table
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
| Title 1 | Title 2 |
| --------------------- | --------------------- |
| lorem ipsum dolor sit | lorem ipsum dolor sit |
| lorem ipsum dolor sit | lorem ipsum dolor sit |
| lorem ipsum dolor sit | lorem ipsum dolor sit |
| lorem ipsum dolor sit | lorem ipsum dolor sit |

5
src/routes/+error.svelte Normal file
View File

@@ -0,0 +1,5 @@
<script lang="ts">
import { page } from '$app/state';
</script>
<h1>{page.status} {page?.error?.message}</h1>

71
src/routes/+layout.svelte Executable file
View File

@@ -0,0 +1,71 @@
<script>
import { SITE_URL, SITE_TITLE } from '../app';
</script>
<svelte:head>
<link
rel="alternate"
type="application/atom+xml"
title={SITE_TITLE}
href={new URL("feed.atom", SITE_URL).toString()}
/>
</svelte:head>
<header class="container">
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/blog">Blog</a>
</li>
</ul>
</nav>
</header>
<main class="container">
<slot />
</main>
<footer class="container">
<a href="/feed.atom" target="_blank" rel="noopener">RSS</a>
</footer>
<style>
header {
color: var(--text-color);
margin-bottom: 10px;
}
nav {
max-width: 1200px;
margin: 0 auto;
}
ul {
display: flex;
gap: 25px;
list-style: none;
padding-left: 0;
margin-top: 0;
margin-bottom: 0;
}
nav li {
font-weight: bold;
padding-top: 2px;
padding-bottom: 2px;
}
footer {
display: flex;
justify-content: space-between;
margin-top: 20px;
margin-bottom: 20px;
padding-top: 10px;
padding-bottom: 10px;
border-top: 3px solid var(--border1-color);
color: var(--text-color);
}
</style>

2
src/routes/+layout.ts Executable file
View File

@@ -0,0 +1,2 @@
export const prerender = true;
export const trailingSlash = 'always';

78
src/routes/+page.svelte Executable file
View File

@@ -0,0 +1,78 @@
<script lang="ts">
import type { PageProps } from './$types';
import { SITE_TITLE } from '../app';
let { data }: PageProps = $props();
</script>
<svelte:head>
<title>{SITE_TITLE}</title>
</svelte:head>
<div class="title">
<img src="/images/logo.png" alt="logo" />
<h1>{SITE_TITLE}</h1>
</div>
<p>Welcome to my website. I'm a software developer interested in game development and design.</p>
<div class="posts">
<h2>Latest posts</h2>
<ul class="post-list">
{#each data.posts as post}
<li class="post">
<div>
<a href="/blog/{post.slug}">{post.title}</a>
</div>
<span class="post-meta">{post.dateCreated.toISOString().split("T")[0]}</span>
</li>
{/each}
</ul>
<a class="blog-link" href="/blog">All posts &#x2192;</a>
</div>
<style>
.title {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
}
.title h1 {
margin-top: 0px;
margin-bottom: 0px;
}
.title img {
width: 64px;
height: 64px;
border-radius: 5px;
}
.post-list {
margin-top: 0;
margin-bottom: 10px;
list-style: none;
padding: 0;
}
.post {
display: flex;
flex-direction: column;
gap: 4px;
padding: 10px 0px;
}
.post a {
font-size: 1.25rem;
font-weight: bold;
}
.post-meta {
font-size: 0.875rem;
}
.blog-link {
font-size: 1rem;
}
</style>

10
src/routes/+page.ts Executable file
View File

@@ -0,0 +1,10 @@
import type { PageLoad } from './$types';
import { getBlogCollection } from '../app'
export const load: PageLoad = async ( fetch ) => {
let posts = (await getBlogCollection()).slice(0, 5);
return {
posts,
};
};

58
src/routes/blog/+page.svelte Executable file
View File

@@ -0,0 +1,58 @@
<script lang="ts">
import type { PageProps } from './$types';
import { SITE_TITLE } from '../../app';
let { data }: PageProps = $props();
</script>
<svelte:head>
<title>Blog - {SITE_TITLE}</title>
</svelte:head>
<div class="title">
<h1>Blog</h1>
</div>
<div class="posts">
<ul class="post-list">
{#each data.posts as post}
<li class="post">
<div>
<a href="/blog/{post.slug}">{post.title}</a>
</div>
<span class="post-meta">{post.dateCreated.toISOString().split("T")[0]}</span>
</li>
{/each}
</ul>
</div>
<style>
.title h1 {
margin-top: 0px;
margin-bottom: 10px;
}
.post-list {
padding-top: 0;
margin-top: 0;
margin-bottom: 0;
list-style: none;
padding: 0;
}
.post {
display: flex;
flex-direction: column;
gap: 4px;
padding: 10px 0px;
}
.post a {
font-size: 1.25rem;
font-weight: bold;
}
.post-meta {
font-size: 0.875rem;
}
</style>

9
src/routes/blog/+page.ts Executable file
View File

@@ -0,0 +1,9 @@
import type { PageLoad } from './$types';
import { getBlogCollection } from '../../app';
export const load: PageLoad = async () => {
let posts = await getBlogCollection();
return {
posts,
};
};

View File

@@ -0,0 +1,40 @@
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
const post = data.post;
</script>
<svelte:head>
<title>{post.title}</title>
</svelte:head>
<div class="title">
<h1>{post.title}</h1>
<span>{post.dateCreated.toISOString().split("T")[0]}</span>
</div>
{@html post.html}
<style>
.title {
display: flex;
flex-direction: column;
gap: 10px;
border-bottom: 3px solid var(--border1-color);
margin-bottom: 20px;
}
.title h1 {
margin-top: 0px;
margin-bottom: 0px;
}
.title span {
margin-bottom: 10px;
font-size: 0.875rem;
font-weight: normal;
color: var(--text-color);
}
</style>

14
src/routes/blog/[slug]/+page.ts Executable file
View File

@@ -0,0 +1,14 @@
import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
import { getBlogCollection } from '../../../app';
export const load: PageLoad = async ({ params }) => {
const post = (await getBlogCollection()).find((post) => post.slug == params.slug);
if (!post) {
error(404, `Could not find ${params.slug}`);
}
return {
post: post
};
};

72
src/routes/feed.atom/+server.ts Executable file
View File

@@ -0,0 +1,72 @@
import { getBlogCollection } from '../../app';
import { SITE_AUTHOR, SITE_TITLE, SITE_DESCRIPTION, SITE_URL } from '../../app';
export const prerender = true;
function escapeXml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
export async function GET() {
const posts = await getBlogCollection();
const dateUpdated = posts.length
? new Date(
Math.max(
...posts.map(post => {
const updated = post.dateUpdated ? post.dateUpdated.getTime() : 0;
const created = post.dateCreated ? post.dateCreated.getTime() : 0;
return Math.max(updated, created);
})
)
)
: null;
// Start Atom feed
let atomXml = `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>${SITE_URL}/</id>
<title>${escapeXml(SITE_TITLE)}</title>
<subtitle>${escapeXml(SITE_DESCRIPTION)}</subtitle>
<link href="${SITE_URL}/feed.atom" rel="self"/>
<link href="${SITE_URL}"/>
<updated>${dateUpdated?.toISOString()}</updated>
<author>
<name>${SITE_AUTHOR}</name>
</author>`;
posts.forEach((post) => {
const url = `${SITE_URL}/blog/${post.slug}`;
const dateCreated = post.dateCreated;
const dateUpdated = post.dateUpdated ?? post.dateCreated;
const htmlContent = post.html ?? '';
atomXml += `
<entry>
<id>${url}</id>
<title>${post.title}</title>
<link href="${url}"/>
<published>${dateCreated?.toISOString()}</published>
<updated>${dateUpdated?.toISOString()}</updated>
<author>
<name>${SITE_AUTHOR}</name>
</author>
<content type="html">
${escapeXml(htmlContent)}
</content>
<summary>${post.description || ''}</summary>
</entry>`;
});
atomXml += '\n</feed>';
return new Response(atomXml, {
headers: { 'Content-Type': 'application/atom+xml' }
});
}

48
static/favicon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

175
static/global.css Executable file
View File

@@ -0,0 +1,175 @@
:root {
--background-color: #212529;
--text-color: #ededed;
--primary-color: #133b6e;
--accent-color: #dc7c28;
--link-color: #569cd6;
--border1-color: #dc7c28;
--border2-color: #3d444d;
}
body {
box-sizing: border-box;
background-color: var(--background-color);
color: var(--text-color);
font-family: sans-serif;
font-weight: 400;
line-height: 1.5;
margin: 0 auto;
}
html {
min-height: 100%;
scroll-behavior: smooth;
font-size: 100%;
} /* 16px */
h1 {
font-size: 1.802rem; /* 28.8px */
}
h2 {
font-size: 1.602rem; /* 25.6px */
}
h3 {
font-size: 1.424rem; /* 22.72px */
}
h4 {
font-size: 1.266rem; /* 20.32px */
}
h5 {
font-size: 1.125rem; /* 18.08px */
}
small {
font-size: 0.889rem; /* 14.24px */
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 24px;
margin-bottom: 10px;
color: var(--text-color);
line-height: 1.2;
font-weight: 700;
}
p {
margin-top: 8px;
}
ul,
ol {
list-style-position: inside;
padding-left: 0px;
}
ul ul {
list-style-type: disc;
padding-left: 20px;
}
table {
margin-bottom: 1rem;
width: 100%;
border-collapse: collapse;
}
td,
th {
padding: 0.25rem 0.5rem;
border-color: inherit;
border-style: solid;
border-width: 1px;
}
th {
text-align: left;
}
.container {
max-width: 600px;
width: 100%;
margin-right: auto;
margin-left: auto;
padding: 10px;
}
@media (min-width: 576px) {
.container {
width: 540px;
}
}
@media (min-width: 768px) {
.container {
width: 720px;
}
}
@media (min-width: 992px) {
.container {
width: 960px;
}
}
@media (min-width: 1200px) {
.container {
width: 1140px;
}
}
hr {
background-color: var(--border1-color);
}
blockquote {
border-left: 4px solid var(--border1-color);
margin-left: 0px;
padding-left: 10px;
}
a {
border-bottom: 2px solid transparent;
color: var(--link-color);
text-decoration: none;
}
a:hover {
border-bottom: 2px solid var(--link-color);
text-decoration: none;
}
main {
color: var(--text-color);
font-size: 1rem;
}
main img {
max-width: 100%;
}
/* Code highlighting */
figure {
margin: 0;
}
pre {
padding: 8px;
border: 1px solid var(--border2-color);
}
pre code {
overflow-x: scroll;
display: block;
border-radius: 0;
color: #e1e4e8;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
static/images/logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

17
svelte.config.js Executable file
View File

@@ -0,0 +1,17 @@
import adapter from "@sveltejs/adapter-static";
import sveltePreprocess from "svelte-preprocess";
import path from 'path';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter(),
alias: {
"content-collections": "./.content-collections/generated",
}
},
extensions: [".svelte", ".md"],
preprocess: [sveltePreprocess()],
};
export default config;

19
tsconfig.json Normal file
View File

@@ -0,0 +1,19 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// To make changes to top-level options such as include and exclude, we recommend extending
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
}

8
vite.config.ts Executable file
View File

@@ -0,0 +1,8 @@
import { sveltekit } from '@sveltejs/kit/vite';
import contentCollections from "@content-collections/vite";
const config = {
plugins: [sveltekit(), contentCollections()]
};
export default config;