the re-write begins...
|
@ -1,13 +0,0 @@
|
||||||
version = 1
|
|
||||||
|
|
||||||
[[analyzers]]
|
|
||||||
name = "javascript"
|
|
||||||
|
|
||||||
[analyzers.meta]
|
|
||||||
environment = [
|
|
||||||
"browser",
|
|
||||||
"nodejs"
|
|
||||||
]
|
|
||||||
|
|
||||||
[[transformers]]
|
|
||||||
name = "prettier"
|
|
|
@ -1,2 +0,0 @@
|
||||||
PUBLIC_ADDRESS="https://gay.leggy.dev"
|
|
||||||
PUBLIC_COMMENTS="false"
|
|
BIN
.github/screenshots/Blog.png
vendored
Before Width: | Height: | Size: 987 KiB |
BIN
.github/screenshots/Index.png
vendored
Before Width: | Height: | Size: 995 KiB |
31
.gitignore
vendored
|
@ -1,28 +1,5 @@
|
||||||
# build output
|
.idea
|
||||||
dist/
|
.vscode
|
||||||
|
|
||||||
# generated types
|
|
||||||
.astro/
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# logs
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
|
|
||||||
# environment variables
|
|
||||||
.env
|
|
||||||
.env.production
|
|
||||||
|
|
||||||
# macOS-specific files
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# jetbrains setting folder
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# vscode settings folder
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
|
_site
|
||||||
|
_cache
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
trailingComma: "all"
|
|
||||||
tabWidth: 4
|
|
||||||
semi: true
|
|
||||||
singleQuote: false
|
|
|
@ -1,24 +0,0 @@
|
||||||
when:
|
|
||||||
- event: push
|
|
||||||
branch: main
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build
|
|
||||||
image: node:23-alpine3.20
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm run build
|
|
||||||
- name: deploy
|
|
||||||
image: alpine:latest
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache openssh-client
|
|
||||||
- mkdir -p ~/.ssh
|
|
||||||
- echo "$SSH_KEY" > ~/.ssh/id_rsa
|
|
||||||
- chmod 600 ~/.ssh/id_rsa
|
|
||||||
- ssh -o StrictHostKeyChecking=no uncertainty@192.168.0.42 "rm -r $COPY_TO || true"
|
|
||||||
- scp -o StrictHostKeyChecking=no -r $COPY_FROM uncertainty@192.168.0.42:$COPY_TO
|
|
||||||
environment:
|
|
||||||
COPY_FROM: dist
|
|
||||||
COPY_TO: /home/uncertainty/www/gay_leggy_dev
|
|
||||||
SSH_KEY:
|
|
||||||
from_secret: ssh_key
|
|
13
README.md
|
@ -1,14 +1,3 @@
|
||||||
# website
|
# website
|
||||||
|
|
||||||
Made in Astro because idk, but I hated it
|
This branch is dedicated to the re-write in lume, yes, rewriting my site, again...
|
||||||
|
|
||||||
Mostly used to show what I can do, kinda a portfolio I guess?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
aurgh
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { defineConfig } from "astro/config";
|
|
||||||
import syntaxTheme from "./syntax-theme.json";
|
|
||||||
|
|
||||||
import mdx from "@astrojs/mdx";
|
|
||||||
|
|
||||||
// https://astro.build/config
|
|
||||||
export default defineConfig({
|
|
||||||
output: "static",
|
|
||||||
markdown: {
|
|
||||||
syntaxHighlight: "shiki",
|
|
||||||
shikiConfig: {
|
|
||||||
theme: syntaxTheme,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
integrations: [mdx()],
|
|
||||||
});
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"origins": [
|
|
||||||
"https://gay.leggy.dev",
|
|
||||||
"https://portfolio.leggy.dev"
|
|
||||||
]
|
|
||||||
}
|
|
7344
package-lock.json
generated
22
package.json
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"name": "website",
|
|
||||||
"type": "module",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "astro dev",
|
|
||||||
"start": "astro dev",
|
|
||||||
"build": "astro check && astro build",
|
|
||||||
"preview": "astro preview",
|
|
||||||
"astro": "astro"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@astrojs/check": "^0.9.4",
|
|
||||||
"@astrojs/mdx": "^3.1.9",
|
|
||||||
"astro": "4.16.10",
|
|
||||||
"typescript": "^5.6.3"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"sass": "^1.80.6",
|
|
||||||
"sass-migrator": "^2.2.1"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
/*!
|
|
||||||
* Modified from GitHub's Dark Dimmed theme, licensed under the MIT License
|
|
||||||
* Copyright (c) 2018 GitHub Inc.
|
|
||||||
* https://github.com/primer/primitives/blob/main/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
main {
|
|
||||||
--color-prettylights-syntax-comment: #768390;
|
|
||||||
--color-prettylights-syntax-constant: #6cb6ff;
|
|
||||||
--color-prettylights-syntax-entity: #dcbdfb;
|
|
||||||
--color-prettylights-syntax-storage-modifier-import: #adbac7;
|
|
||||||
--color-prettylights-syntax-entity-tag: #8ddb8c;
|
|
||||||
--color-prettylights-syntax-keyword: #f47067;
|
|
||||||
--color-prettylights-syntax-string: #96d0ff;
|
|
||||||
--color-prettylights-syntax-variable: #f69d50;
|
|
||||||
--color-prettylights-syntax-brackethighlighter-unmatched: #e5534b;
|
|
||||||
--color-prettylights-syntax-invalid-illegal-text: #cdd9e5;
|
|
||||||
--color-prettylights-syntax-invalid-illegal-bg: #922323;
|
|
||||||
--color-prettylights-syntax-carriage-return-text: #cdd9e5;
|
|
||||||
--color-prettylights-syntax-carriage-return-bg: #ad2e2c;
|
|
||||||
--color-prettylights-syntax-string-regexp: #8ddb8c;
|
|
||||||
--color-prettylights-syntax-markup-list: #eac55f;
|
|
||||||
--color-prettylights-syntax-markup-heading: #316dca;
|
|
||||||
--color-prettylights-syntax-markup-italic: #adbac7;
|
|
||||||
--color-prettylights-syntax-markup-bold: #adbac7;
|
|
||||||
--color-prettylights-syntax-markup-deleted-text: #ffd8d3;
|
|
||||||
--color-prettylights-syntax-markup-deleted-bg: #78191b;
|
|
||||||
--color-prettylights-syntax-markup-inserted-text: #b4f1b4;
|
|
||||||
--color-prettylights-syntax-markup-inserted-bg: #1b4721;
|
|
||||||
--color-prettylights-syntax-markup-changed-text: #ffddb0;
|
|
||||||
--color-prettylights-syntax-markup-changed-bg: #682d0f;
|
|
||||||
--color-prettylights-syntax-markup-ignored-text: #adbac7;
|
|
||||||
--color-prettylights-syntax-markup-ignored-bg: #255ab2;
|
|
||||||
--color-prettylights-syntax-meta-diff-range: #dcbdfb;
|
|
||||||
--color-prettylights-syntax-brackethighlighter-angle: #768390;
|
|
||||||
--color-prettylights-syntax-sublimelinter-gutter-mark: #545d68;
|
|
||||||
--color-prettylights-syntax-constant-other-reference-link: #96d0ff;
|
|
||||||
|
|
||||||
--color-btn-text: #f0e9e4;
|
|
||||||
--color-btn-bg: #312620;
|
|
||||||
--color-btn-border: rgba(168, 99, 56, 0.1);
|
|
||||||
--color-btn-shadow: 0 0 transparent;
|
|
||||||
--color-btn-inset-shadow: 0 0 transparent;
|
|
||||||
--color-btn-hover-bg: #382e28;
|
|
||||||
--color-btn-hover-border: #a86338;
|
|
||||||
--color-btn-active-bg: hsl(25deg 27% 27% / 100%);
|
|
||||||
--color-btn-active-border: #a86338;
|
|
||||||
--color-btn-selected-bg: #312620;
|
|
||||||
|
|
||||||
--color-btn-primary-text: #f0e9e4;
|
|
||||||
--color-btn-primary-bg: #a86338;
|
|
||||||
--color-btn-primary-border: transparent;
|
|
||||||
--color-btn-primary-shadow: 0 0 transparent;
|
|
||||||
--color-btn-primary-inset-shadow: 0 0 transparent;
|
|
||||||
--color-btn-primary-hover-bg: #995a32;
|
|
||||||
--color-btn-primary-hover-border: transparent;
|
|
||||||
--color-btn-primary-selected-bg: #a86338;
|
|
||||||
--color-btn-primary-selected-shadow: 0 0 transparent;
|
|
||||||
--color-btn-primary-disabled-text: #bfbab6;
|
|
||||||
--color-btn-primary-disabled-bg: #804b2a;
|
|
||||||
--color-btn-primary-disabled-border: transparent;
|
|
||||||
|
|
||||||
--color-action-list-item-default-hover-bg: rgba(168, 99, 56, 0.12);
|
|
||||||
|
|
||||||
--color-segmented-control-bg: rgba(56, 46, 40, 0.1);
|
|
||||||
--color-segmented-control-button-bg: #312620;
|
|
||||||
--color-segmented-control-button-selected-border: #a86338;
|
|
||||||
|
|
||||||
--color-fg-default: #f0e9e4;
|
|
||||||
--color-fg-muted: #adbac7;
|
|
||||||
--color-fg-subtle: #545d68;
|
|
||||||
|
|
||||||
--color-canvas-default: #312620;
|
|
||||||
--color-canvas-overlay: #382e28;
|
|
||||||
--color-canvas-inset: rgba(49, 38, 32, 1);
|
|
||||||
--color-canvas-subtle: rgba(56, 46, 40, 1);
|
|
||||||
|
|
||||||
--color-border-default: #382e28;
|
|
||||||
--color-border-muted: #312620;
|
|
||||||
|
|
||||||
--color-neutral-muted: rgba(56, 46, 40, 0.4);
|
|
||||||
|
|
||||||
--color-accent-fg: #a86338;
|
|
||||||
--color-accent-emphasis: #a86338;
|
|
||||||
--color-accent-muted: rgba(168, 99, 56, 0.4);
|
|
||||||
--color-accent-subtle: rgba(168, 99, 56, 0.1);
|
|
||||||
|
|
||||||
--color-success-fg: #a86338;
|
|
||||||
|
|
||||||
--color-attention-fg: #a88538;
|
|
||||||
--color-attention-muted: #755b27;
|
|
||||||
--color-attention-subtle: #423315;
|
|
||||||
|
|
||||||
--color-danger-fg: #a83838;
|
|
||||||
--color-danger-muted: #752727;
|
|
||||||
--color-danger-subtle: #421616;
|
|
||||||
|
|
||||||
--color-primer-shadow-inset: 0 0 transparent;
|
|
||||||
|
|
||||||
--color-scale-gray-7: #382e28;
|
|
||||||
--color-scale-blue-8: #4b3b3a;
|
|
||||||
|
|
||||||
/*! Extensions from @primer/css/alerts/flash.scss */
|
|
||||||
--color-social-reaction-bg-hover: var(--color-scale-gray-7);
|
|
||||||
--color-social-reaction-bg-reacted-hover: var(--color-scale-blue-8);
|
|
||||||
}
|
|
||||||
|
|
||||||
main .pagination-loader-container {
|
|
||||||
background-image: url("https://github.com/images/modules/pulls/progressive-disclosure-line-dark.svg");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Custom CSS */
|
|
||||||
|
|
||||||
.gsc-main {
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gsc-reactions {
|
|
||||||
padding-bottom: 32px !important;
|
|
||||||
}
|
|
||||||
.gsc-reactions > div {
|
|
||||||
margin-top: 0 !important;
|
|
||||||
}
|
|
||||||
.gsc-reactions-count {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gsc-header {
|
|
||||||
padding-bottom: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gsc-comment-box-tabs {
|
|
||||||
border-radius: 0 !important;
|
|
||||||
}
|
|
||||||
.gsc-comment-box-write {
|
|
||||||
/*border: 2px solid #382e28;*/
|
|
||||||
}
|
|
||||||
.gsc-comment-box:not(.gsc-comment-box-is-reply) {
|
|
||||||
border-width: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gsc-comments {
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
.gsc-comments > .gsc-comment-box,
|
|
||||||
.gsc-comments > .gsc-comment {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
.gsc-comment > div {
|
|
||||||
border-width: 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
border-radius: 9999px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
main .gsc-loading-image {
|
|
||||||
background-image: url("https://github.githubassets.com/images/mona-loading-dimmed.gif");
|
|
||||||
}
|
|
BIN
public/leg.webp
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 267 KiB |
Before Width: | Height: | Size: 602 KiB |
Before Width: | Height: | Size: 184 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 415 KiB |
Before Width: | Height: | Size: 322 KiB |
Before Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 107 KiB |
|
@ -1,121 +0,0 @@
|
||||||
---
|
|
||||||
import { getMonth, getDaySuffix } from "../utils";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
post: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
const { post } = Astro.props;
|
|
||||||
|
|
||||||
const date = new Date(post.data.pubDate);
|
|
||||||
---
|
|
||||||
|
|
||||||
<li class="link-card">
|
|
||||||
<a href=`/posts/${post.slug}`>
|
|
||||||
<h3>
|
|
||||||
{post.data.title}
|
|
||||||
</h3>
|
|
||||||
{post.data.pubDate ? (
|
|
||||||
<p>{date.getDate()}{getDaySuffix(date)} {getMonth(date)} {date.getFullYear()} • {post.data.description}</p>
|
|
||||||
) : (
|
|
||||||
<p>{post.data.description}</p>
|
|
||||||
)}
|
|
||||||
</a>
|
|
||||||
<div class="link-card-corner" />
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../styles/vars.scss";
|
|
||||||
|
|
||||||
$corner-speed: 0.2s;
|
|
||||||
|
|
||||||
.link-card {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
|
|
||||||
list-style: none;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
min-height: 81px;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
border: 2px solid $gray;
|
|
||||||
background-color: $dark;
|
|
||||||
color: $light;
|
|
||||||
|
|
||||||
transition: background-color $corner-speed ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card-corner {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
bottom: -40px;
|
|
||||||
right: -40px;
|
|
||||||
|
|
||||||
border-top-left-radius: $radius;
|
|
||||||
border-top: 2px solid $gray;
|
|
||||||
border-left: 2px solid $gray;
|
|
||||||
background-image: linear-gradient(135deg, rgba($accent, 0.03), darken($dark, 1%));
|
|
||||||
background-color: $dark;
|
|
||||||
color: $light;
|
|
||||||
|
|
||||||
box-shadow: -4px -4px 0 rgba(#000, 0);
|
|
||||||
|
|
||||||
transition:
|
|
||||||
right $corner-speed ease-in-out,
|
|
||||||
bottom $corner-speed ease-in-out,
|
|
||||||
box-shadow $corner-speed ease-in-out;
|
|
||||||
pointer-events: none;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: +3;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: -16px;
|
|
||||||
left: -16px;
|
|
||||||
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
|
|
||||||
border-top: 2px solid $gray;
|
|
||||||
background-color: $dark;
|
|
||||||
|
|
||||||
transition: left $corner-speed ease-in-out, top $corner-speed ease-in-out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover, &:focus-within {
|
|
||||||
> a {
|
|
||||||
background-color: rgba($accent, 0.03);
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-card-corner {
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
box-shadow: -4px -4px 10px rgba(#000, 0.1);
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
top: 3px;
|
|
||||||
left: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,32 +0,0 @@
|
||||||
---
|
|
||||||
import { getMonth, getDaySuffix } from "../utils";
|
|
||||||
|
|
||||||
const { certificate } = Astro.props;
|
|
||||||
|
|
||||||
const date = new Date(certificate.data.achieved);
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class="certificate">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
|
||||||
<rect width="256" height="256" fill="none"/>
|
|
||||||
<path d="M168,157.94h0a44,44,0,1,1,56-67.88h0V56a8,8,0,0,0-8-8H40a8,8,0,0,0-8,8V184a8,8,0,0,0,8,8H168Z" opacity="0.2"/>
|
|
||||||
<line x1="72" y1="136" x2="120" y2="136" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
||||||
<line x1="72" y1="104" x2="120" y2="104" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
||||||
<circle cx="196" cy="124" r="44" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
||||||
<path d="M168,192H40a8,8,0,0,1-8-8V56a8,8,0,0,1,8-8H216a8,8,0,0,1,8,8V90.06" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><polyline points="168 157.94 168 224 196 208 224 224 224 157.94" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/>
|
|
||||||
</svg>
|
|
||||||
<div>
|
|
||||||
<h3>{certificate.data.title}</h3>
|
|
||||||
<hr style="width: 100%">
|
|
||||||
<p>{date.getDate()}{getDaySuffix(date)} {getMonth(date)} {date.getFullYear()}</p>
|
|
||||||
<p>Presented by {certificate.data.provider}</p>
|
|
||||||
|
|
||||||
{certificate.data.skills && (
|
|
||||||
<ul class="pill-list">
|
|
||||||
{certificate.data.skills.map((skill: string) => ( <li class="pill">{skill}</li> ))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{certificate.data.link && ( <a href={certificate.data.link} class="button">View Full</a> )}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
---
|
|
||||||
|
|
||||||
<a class="button" href="/" id="home">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256">
|
|
||||||
<path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"></path>
|
|
||||||
</svg>
|
|
||||||
Homepage
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div />
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
div {
|
|
||||||
height: calc(35px + 8px - 32px + 32px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#home {
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
import leg from "../assets/leg.webp";
|
|
||||||
---
|
|
||||||
|
|
||||||
<a class="button" id="music" href="https://www.last.fm/user/Fluffy_Bean_" target="_blank">
|
|
||||||
<img
|
|
||||||
src={leg.src}
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
loading="eager"
|
|
||||||
alt="Track cover art"
|
|
||||||
class="music-img music-bg"
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
src={leg.src}
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
loading="eager"
|
|
||||||
alt="Track cover art"
|
|
||||||
class="music-img music-cover"
|
|
||||||
/>
|
|
||||||
<ul>
|
|
||||||
<li id="music-title" style="font-weight: 600;">Track Name</li>
|
|
||||||
<li id="music-artist">by Artist</li>
|
|
||||||
<li id="music-album">on Album</li>
|
|
||||||
</ul>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", async () => {
|
|
||||||
const request = await fetch("https://lastfm-last-played.biancarosa.com.br/Fluffy_Bean_/latest-song");
|
|
||||||
const data = await request.json();
|
|
||||||
|
|
||||||
( document.querySelectorAll(".music-img") as NodeListOf<HTMLImageElement> ).forEach((img) => {
|
|
||||||
img.src = data["track"]["image"][2]["#text"];
|
|
||||||
});
|
|
||||||
( document.querySelector("#music-title") as HTMLParagraphElement ).innerText = `${data["track"]["name"]}`;
|
|
||||||
( document.querySelector("#music-artist") as HTMLParagraphElement ).innerText = `by ${data["track"]["artist"]["#text"]}`;
|
|
||||||
( document.querySelector("#music-album") as HTMLParagraphElement ).innerText = `on ${data["track"]["album"]["#text"]}`;
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
interface Props {
|
|
||||||
text: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
const { text } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class="note">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z"></path></svg>
|
|
||||||
<span>{text}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../styles/vars.scss";
|
|
||||||
|
|
||||||
.note {
|
|
||||||
margin: 16px 0;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-start;
|
|
||||||
|
|
||||||
font-weight: 500;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
background-color: $accent;
|
|
||||||
color: $light;
|
|
||||||
|
|
||||||
> svg {
|
|
||||||
min-width: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> span {
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Databases with SQL and Python",
|
|
||||||
"provider": "Hyperskill",
|
|
||||||
"achieved": "2023-07-01",
|
|
||||||
"skills": [ "SQL", "SQLAlchemy", "Python", "SQLite" ],
|
|
||||||
"link": ""
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Introduction to Command Line and Unix Shell",
|
|
||||||
"provider": "Hyperskill",
|
|
||||||
"achieved": "2023-07-01",
|
|
||||||
"skills": [ "Bash", "Shell Scripting", "Linux", "Unix" ],
|
|
||||||
"link": ""
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Introduction to Python",
|
|
||||||
"provider": "Hyperskill",
|
|
||||||
"achieved": "2023-07-01",
|
|
||||||
"skills": [ "Python" ],
|
|
||||||
"link": ""
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Introduction to SQL",
|
|
||||||
"provider": "Hyperskill",
|
|
||||||
"achieved": "2023-07-01",
|
|
||||||
"skills": [ "SQL", "SQLite", "Databases" ],
|
|
||||||
"link": ""
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
import { z, defineCollection, reference } from "astro:content";
|
|
||||||
|
|
||||||
const posts = defineCollection({
|
|
||||||
type: "content",
|
|
||||||
schema: z.object({
|
|
||||||
draft: z.boolean().optional().default(false),
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
pubDate: z.string().transform((str) => new Date(str)),
|
|
||||||
tags: z.array(reference("tags")),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const certificates = defineCollection({
|
|
||||||
type: "data",
|
|
||||||
schema: z.object({
|
|
||||||
title: z.string(),
|
|
||||||
provider: z.string(),
|
|
||||||
achieved: z.date(),
|
|
||||||
skills: z.array(z.string()).optional(),
|
|
||||||
link: z.string().optional(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const tags = defineCollection({
|
|
||||||
type: "content",
|
|
||||||
schema: z.object({
|
|
||||||
name: z.string(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const collections = {
|
|
||||||
posts,
|
|
||||||
certificates,
|
|
||||||
tags,
|
|
||||||
};
|
|
|
@ -1,53 +0,0 @@
|
||||||
---
|
|
||||||
title: Hello, Django!
|
|
||||||
description: Django is fun!
|
|
||||||
pubDate: 2023-06-19
|
|
||||||
tags:
|
|
||||||
- python
|
|
||||||
- django
|
|
||||||
- caddy
|
|
||||||
- networking
|
|
||||||
- webdev
|
|
||||||
---
|
|
||||||
|
|
||||||
import Note from "../../components/Note.astro";
|
|
||||||
|
|
||||||
<Note text="This is an older blog post imported from my old Django website" />
|
|
||||||
|
|
||||||
Wow, first ever blog! It's kind of ridiculous that somebody would think to start that only in 2023, since the cool thing to do now is to post on social media. Then again, the entire internet feels like it's falling apart now—fun!
|
|
||||||
|
|
||||||
Welp, where to start? Maybe how this page was made and the suffering I went through to get it running? sound good to me!
|
|
||||||
|
|
||||||
## Why Django????
|
|
||||||
|
|
||||||
This website runs on [Django](https://www.djangoproject.com/), a Python framework that I went with for a few reasons.
|
|
||||||
|
|
||||||
Firstly, I love Python and how fast and easy it is to make things in it. If you need to make something using it, most likely there is a package for it out there or a guide to making it yourself.
|
|
||||||
|
|
||||||
Secondly, I wanted to try something other than Flask. While Flask is great and all, I wanted to try something else, as Flask is terribly slow at serving static files, something that'll come to bite me later.
|
|
||||||
|
|
||||||
Lastly, I don't like JavaScript, why is this important? Someone out there will tell me to have used something like Vue to make this page. My answer is no. Not every single page out there needs to be made using an entire framework, you can get the exact same results with a static HTML file and a little bit of vanilla JS.
|
|
||||||
|
|
||||||
## On I love networking.
|
|
||||||
|
|
||||||
During the writing of this post, I actually experienced a lot of issues, none that Django itself caused but rather the terrible way I got everything setup. As I was setting this page up with Docker, Caddy was my proxy for my network, and it did its job for the most part. But it was very different from what I was used to with Nginx and lacked many features I wanted, such as RTMP, which it was not made for but Nginx comes with by default.
|
|
||||||
|
|
||||||
My network is also setup in a way that I have my websites running on a different container than my proxy, this is how I always had it, Nginx never complained, but oh boy, did Caddy give me a lot of issues that I'll get into in just a moment.
|
|
||||||
|
|
||||||
So, why is this an issue?
|
|
||||||
|
|
||||||
Django doesn't serve static files, the main reason being that the developers aren't interested in making a web server but a web framework. This means that Caddy had to handle the serving of static files. This is cool and all, but I've never done this before, so down a rabbit hole I went.
|
|
||||||
|
|
||||||
First I tried the obvious, getting Caddy to `root` the files on `webserver.ip/website/static` and `webserver.ip/website/media`. Nope! Apparently, Caddy can only serve static files from local files, not from a subdomain on a local IP. This would mean I have three options:
|
|
||||||
|
|
||||||
1. Move Caddy onto my web server.
|
|
||||||
2. SSH mount the files from my web server to my proxy server.
|
|
||||||
3. Use a different proxy server.
|
|
||||||
|
|
||||||
In the end, I went with the third option, I went back to `Nginx Proxy Manager` (amazing tool, by the way), and setup everything from scratch again. If you are reading this, then I got everything working, yey!
|
|
||||||
|
|
||||||
## Final thoughts
|
|
||||||
|
|
||||||
After all of that, switching proxies, dropping Docker, and a lot of suffering, I got this page working. Overall, would I go with Django again? Most likely! It was fast and easy to learn, and it has some really nice features. Though I wish Python was faster so I could use this for larger projects :c
|
|
||||||
|
|
||||||
While I continue to work out bugs on this page and my terrible server management, enjoy reading the slop in the blog 😋
|
|
|
@ -1,159 +0,0 @@
|
||||||
---
|
|
||||||
title: Astro is hard....
|
|
||||||
description: Writing blogs is even harder
|
|
||||||
pubDate: 2024-05-28
|
|
||||||
tags:
|
|
||||||
- astro
|
|
||||||
- typescript
|
|
||||||
- webdev
|
|
||||||
---
|
|
||||||
|
|
||||||
Hello! Welcome to my new website, or at least as of writing this blog.
|
|
||||||
It's been written from scratch with Astro, Typescript and a lot of suffering, mostly due to bugs and random annoyances...
|
|
||||||
|
|
||||||
So where do I start, maybe _why_ I have chosen Astro over other existing options.
|
|
||||||
|
|
||||||
## Why Astro
|
|
||||||
|
|
||||||
TLDR: I don't know :3
|
|
||||||
|
|
||||||
I've been trying to learn Typescript for about a month now, mainly to broaden my skill set, but to also help me with job
|
|
||||||
searching. Firstly through Svelte for a college project (which I may write about), but now Astro.
|
|
||||||
|
|
||||||
I've chosen Astro for two main reasons
|
|
||||||
|
|
||||||
1. It's statically compiled, meaning that I don't ship any smelly Javascript to the browser, which I detest doing when not needed
|
|
||||||
2. It looked simple enough compared to other options
|
|
||||||
|
|
||||||
So, what was the experience like so far you may be asking, ehh...
|
|
||||||
|
|
||||||
## The problems
|
|
||||||
|
|
||||||
### `Image` and `Picture`
|
|
||||||
|
|
||||||
The first and biggest hurdle I faced was the `Image` and `Picture` elements from Astro. I could not for the life of me,
|
|
||||||
figure out a good solution for using both a file path, and a URL for the `frontmatter` data. I tried:
|
|
||||||
|
|
||||||
- `getImage()`
|
|
||||||
- Checking if the start of the string begins with `https://`
|
|
||||||
- Loading the image using `getImage()` on every page that passed the image data into the `Layout.astro` to set as the banner image
|
|
||||||
|
|
||||||
**NOTHING FUCKING WORKED.**
|
|
||||||
|
|
||||||
I spent a good few hours trying to get that working, until I came across the `image()` schema helper. I followed the
|
|
||||||
documentation, I followed videos, I copied code from existing repositories, nothing worked, it refused to load images
|
|
||||||
by file path, instead returning a string every time...
|
|
||||||
|
|
||||||
So I simply gave up, and I think that's for the best considering I want to keep my hair, and I had better things todo.
|
|
||||||
You win Astro, you win.
|
|
||||||
|
|
||||||
### PhotoSwipe
|
|
||||||
|
|
||||||
When working on the Refsheet part of this website, I wanted to use a library to be able to view images fullscreen. Maybe
|
|
||||||
I'm stupid, maybe I'm dumb, but I could not get [PhotoSwipe](https://photoswipe.com/) to work, at least when using
|
|
||||||
multiple sets of images on a page.
|
|
||||||
|
|
||||||
I tried stupid things such as creating unique IDs for each gallery element, but when
|
|
||||||
passing them into a `<script>` tag, it would break imports, as passing Astro variables into these for use on the user
|
|
||||||
side, it would put them _above_ the `import`s.
|
|
||||||
|
|
||||||
I know I'll figure this out, as I've already created a `plugins` section for my Layout, that looks as such.
|
|
||||||
|
|
||||||
```astro
|
|
||||||
---
|
|
||||||
// Layout.astro
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title: string;
|
|
||||||
plugins?: {
|
|
||||||
katex?: boolean,
|
|
||||||
}
|
|
||||||
seo?: {
|
|
||||||
description?: string,
|
|
||||||
tags?: string[],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { title, plugins, seo } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>{title}</title>
|
|
||||||
{plugins?.katex && (
|
|
||||||
<!-- Import Katex here -->
|
|
||||||
)}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>Balls</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
```
|
|
||||||
|
|
||||||
```astro
|
|
||||||
---
|
|
||||||
// Markdown.astro
|
|
||||||
|
|
||||||
import Layout from "./Layout.astro";
|
|
||||||
|
|
||||||
// Get post data here
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout
|
|
||||||
plugins={{
|
|
||||||
katex: true,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
```
|
|
||||||
|
|
||||||
So I know it's possible...
|
|
||||||
|
|
||||||
### Broken `getEntries()`...
|
|
||||||
|
|
||||||
My last gripe I had with Astro was the broken `getEntries()` function, while it made it annoying to not get tag data for
|
|
||||||
posts, it wasn't hard to implement myself for the use of this blog. It's not that well optimised in my option, but it
|
|
||||||
does what it needs todo and doesn't run in the users browser anyway, thanks Astro.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// utils.ts
|
|
||||||
|
|
||||||
export async function getTagsBySlug(
|
|
||||||
postTags: string[],
|
|
||||||
): Promise<CollectionEntry<"tags">[]> {
|
|
||||||
const allTags: CollectionEntry<"tags">[] = await getCollection("tags");
|
|
||||||
|
|
||||||
// Loop through all the tags in a post and the tags in the collections
|
|
||||||
// To see if they match, if they do we'll return them
|
|
||||||
const tags: CollectionEntry<"tags">[] = [];
|
|
||||||
postTags.forEach((postTag) => {
|
|
||||||
allTags.forEach((allTag) => {
|
|
||||||
if (allTag.slug === postTag) tags.push(allTag);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Yeet
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## What I've learned
|
|
||||||
|
|
||||||
While Astro was a meh experience, I doubt all the problems I encountered where an Astro issue, most where probably a
|
|
||||||
skill issue tbh.
|
|
||||||
|
|
||||||
That said, trial by error (or fire when doing JavaScript/TypeScript) is a good way to learn, so I did learn much indeed,
|
|
||||||
both on Astro and TypeScript.
|
|
||||||
|
|
||||||
Other things I wasn't expecting to learn on the way was digging through Documentation more thoroughly and trying MDX. So
|
|
||||||
that's a win!
|
|
||||||
|
|
||||||
## Final words
|
|
||||||
|
|
||||||
I'm hoping to write more blogs in the future, mainly to practice my writing skills, and sharing my options publicly,
|
|
||||||
regardless if it's something political or programming related. But life's in a tangle right now
|
|
||||||
|
|
||||||
<div style="width: 200px">
|
|
||||||
 [Art
|
|
||||||
by Pulex](https://www.pulexart.com/)
|
|
||||||
</div>
|
|
|
@ -1,71 +0,0 @@
|
||||||
---
|
|
||||||
title: The Pebble Time!
|
|
||||||
description: '"Smart" watches are not smart at all!'
|
|
||||||
pubDate: 2024-06-06
|
|
||||||
tags:
|
|
||||||
- pebble
|
|
||||||
- impressions
|
|
||||||
---
|
|
||||||
|
|
||||||
Today I finally managed to get my hands on the Pebble Time! I've been looking for a watch to fulfil my three main needs,
|
|
||||||
without all the wacky account creation, data collection, and general annoyances sprinkled in for a while now, then I
|
|
||||||
found the Pebble Time. And now about a year later, here's my first impressions/review of the Pebble Time
|
|
||||||
([only 9 years late...](<https://en.wikipedia.org/wiki/Pebble_(watch)#Pebble_Time>))
|
|
||||||
|
|
||||||
## My Three Wishes
|
|
||||||
|
|
||||||
### Timekeeping
|
|
||||||
|
|
||||||
This seems quite stupid to put as a requirement for a watch "review" of sorts. But with all these watches coming out,
|
|
||||||
less and less of them can do what they were originally designed to do—show the time. Instead, they're packed with
|
|
||||||
features nobody will actually use that drain the life of the watch,
|
|
||||||
[barely get a day of battery life at times.](https://9to5google.com/2022/05/31/pixel-watch-battery-life/)
|
|
||||||
|
|
||||||
The Pebble Time, when released, was advertised to have 7 days of battery life,
|
|
||||||
[and it performed as advertised!](https://www.theverge.com/2015/5/27/8661863/pebble-time-review-wearable-smartwatch)
|
|
||||||
But nearly nine years later, does it still hold up? I can only answer after a few days of use, so watch out for an
|
|
||||||
update!
|
|
||||||
|
|
||||||
But how could Pebble do this? Through the smart optimisation of their PebbleOS and the use of an E-Ink display
|
|
||||||
(which I love)
|
|
||||||
|
|
||||||
### Notifications
|
|
||||||
|
|
||||||
This will make me sound old, but I hate having to pick up my phone constantly to check for notifications. It drives me
|
|
||||||
insane sometimes with the amount of stuff that tries to get my attention, even with most apps' notifications disabled.
|
|
||||||
|
|
||||||
Being able to quickly check if I should care to pull out my phone from my pocket is really handy, and something I missed
|
|
||||||
when my Samsung Gear S2 Classic finally kicked the bucket.
|
|
||||||
|
|
||||||
The Pebble Time does a great job at it, and I'd hope so since this was one of its main advertisement points. When do I
|
|
||||||
get a notification, it stays on my screen until I acknowledge it, which it can only do through the funky technology of
|
|
||||||
E-Ink.
|
|
||||||
|
|
||||||
### Quick Controls
|
|
||||||
|
|
||||||
Similarly, I don't want to have to take out my phone for some more simple things, like quickly changing the music I'm
|
|
||||||
listening to or toggling my desk lamp as I'm running for the train in the morning. Having access to
|
|
||||||
[Home Assistant](https://github.com/Willow-Systems/pebble-home-assistant) from my wrist is quite a lot more useful than
|
|
||||||
I thought at first. Though can be quite slow being written in JavaScript.
|
|
||||||
|
|
||||||
With the Samsung Gear S2 Classic, I didn't have such controls, due to the bloated TizenOS hogging down the limited 512MB
|
|
||||||
of ram and slow Qualcomm Snapdragon 400 CPU, along with the already dropped support at the time when I bought it.
|
|
||||||
|
|
||||||
## Annoyances
|
|
||||||
|
|
||||||
While there is many things I can say about the watch and the interface, like its funny little animations, cool design
|
|
||||||
and physical buttons to navigate. I have _already_ experienced crashes when trying to reply to notifications and "you
|
|
||||||
are not connected to the internet" block when trying to set up the watch,
|
|
||||||
[which Rebble does cover how todo](https://help.rebble.io/setup-android/#7), but still, it took me 3 attempts.
|
|
||||||
|
|
||||||
## What I miss from the Gear S2
|
|
||||||
|
|
||||||
While there isn't much here, I do want to point out just how useful the rotating crown of the Gear S2 was. It was a
|
|
||||||
really nice way of interacting with the operating system, similarly, I like the physical buttons on the Pebble Time. We
|
|
||||||
need less touchscreens in this world, not more!
|
|
||||||
|
|
||||||
## Final notes
|
|
||||||
|
|
||||||
I will probably post an update post for a more long-term review of the watch. I also want to try to write an app for the
|
|
||||||
Pebble, and I've been meaning to learn C, and with the extensive guides that are available for the watch, I think it's a
|
|
||||||
good time as ever to get into the land of low level!
|
|
|
@ -1,84 +0,0 @@
|
||||||
---
|
|
||||||
draft: true
|
|
||||||
title: Urchin project
|
|
||||||
description: The game that maybe could be
|
|
||||||
pubDate: 2024-06-08
|
|
||||||
tags:
|
|
||||||
- python
|
|
||||||
- go
|
|
||||||
- raylib
|
|
||||||
- gamedev
|
|
||||||
- algorithms
|
|
||||||
---
|
|
||||||
|
|
||||||
'Tis I again.
|
|
||||||
|
|
||||||
Recently I've made quite a lot of progress on a project of mine and my brothers. I dubbed it "Urchin Project" because
|
|
||||||
urchin sounds funny, but also I have zero clue what to call the game.
|
|
||||||
|
|
||||||
## What was originally
|
|
||||||
|
|
||||||
This project actually started [around 10 months ago](https://www.youtube.com/watch?v=z9P-KlNKXAA), but this version was
|
|
||||||
abandoned for a few reasons. Main one being, I had zero fucking clue what I was doing, I didn't plan out a single part
|
|
||||||
of the project, I didn't even know what the story was going to be. Quickly, there was a lot of foot-guns in place and
|
|
||||||
horribly designed systems.
|
|
||||||
|
|
||||||
Urchin Project, though not called it back then, was written on PyGame, a Python wrapper for SDL with a few helpful
|
|
||||||
features. PyGame is more than suitable for most project and tests, as its quite simple to use and relatively fast to get
|
|
||||||
the hang of when first getting into writing games. One of the biggest gripes I have with it was the software based
|
|
||||||
rendering, but that shouldn't be an issu-
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
oh, yeah, that. While basically impossible to see on the screenshot, what ran at 300FPS on my 1080p monitor ran at barely 40fps on
|
|
||||||
a 5k one, this was going to be an issue, not only when it came to scaling things, but also the general design of the
|
|
||||||
game.
|
|
||||||
|
|
||||||
The only option I had was either to:
|
|
||||||
|
|
||||||
1. Ignore the issue and deal with it later
|
|
||||||
2. Use something like ModernGL to make an OpenGL context, and use PyGame as the input and audio manager
|
|
||||||
|
|
||||||
Guess which I've taken!
|
|
||||||
|
|
||||||
From the [previously linked video](https://www.youtube.com/watch?v=z9P-KlNKXAA), you can see I made quite a bit of
|
|
||||||
progress on the game. I even made a [world generator of some sorts](https://github.com/Fluffy-Bean/py_map_generation)!
|
|
||||||
But it was all horribly slow, terribly implemented and wasn't going to get far, and it didn't.
|
|
||||||
|
|
||||||
Eventually I gave up and moved onto other things, such as dealing with upcoming college.
|
|
||||||
|
|
||||||
## Go
|
|
||||||
|
|
||||||
Then around October 2023 I picked up Go. Go is a pretty neat little language, it has the simplicity of Python, and a
|
|
||||||
_pythonic_ sort of syntax in some ways, but the speeds of languages such as Java!
|
|
||||||
|
|
||||||
{/* I believe I read somewhere that Go can preform faster than Rust, but I cannot find the video/resource to back this up */}
|
|
||||||
|
|
||||||
Since then, I've used Go for most of my new projects, because since then I realised that Functional is the way to go for
|
|
||||||
me.
|
|
||||||
|
|
||||||
At one point I even tried to make something using a Go SDL wrapper, but that didn't really go anywhere and I gave up
|
|
||||||
even quicker with that.
|
|
||||||
|
|
||||||
## raylib
|
|
||||||
|
|
||||||
Now, here's where things get interesting!
|
|
||||||
|
|
||||||
- What have I been working on in the past week
|
|
||||||
- How the project started originally
|
|
||||||
- Why did I choose RayLib and Go over python
|
|
||||||
|
|
||||||
- Python was slow
|
|
||||||
- I didn't plan out the project well
|
|
||||||
- PyGame wasn't for me
|
|
||||||
- Gocurrency
|
|
||||||
|
|
||||||
- Physics system
|
|
||||||
|
|
||||||
- SAT
|
|
||||||
- QuadTrees
|
|
||||||
- Greedy Meshing
|
|
||||||
|
|
||||||
- What I want todo next
|
|
||||||
- World Generation
|
|
||||||
- Time/Temperature based systems
|
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
draft: true
|
|
||||||
title: ESPHome
|
|
||||||
description: Making little controllers do magic
|
|
||||||
pubDate: 2024-06-29
|
|
||||||
tags:
|
|
||||||
- esphome
|
|
||||||
- ha
|
|
||||||
- networking
|
|
||||||
---
|
|
||||||
|
|
||||||
ToDo
|
|
|
@ -1,237 +0,0 @@
|
||||||
---
|
|
||||||
draft: false
|
|
||||||
title: umami
|
|
||||||
description: Goob bye Plausible
|
|
||||||
pubDate: 2024-11-07
|
|
||||||
tags:
|
|
||||||
- alpine
|
|
||||||
- linux
|
|
||||||
- webdev
|
|
||||||
- networking
|
|
||||||
---
|
|
||||||
|
|
||||||
import Note from "../../components/Note.astro";
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
This little blog post thang will be about umami, and why I went with it over fixing my Plausible install. While the
|
|
||||||
reason is pretty simple, really and can be summed up in two points.
|
|
||||||
|
|
||||||
- Its resource usage is low
|
|
||||||
- Has (nearly) all the features I used in Plausible
|
|
||||||
|
|
||||||
I want to talk a bit about how I got to the point where I chosen it, and the steps I've taken to actually install and
|
|
||||||
setup an Alpine CT with itttt
|
|
||||||
|
|
||||||
## Other options
|
|
||||||
|
|
||||||
Before I landed on umami, here's the other options I checked out, none of this is gonna really be "scientific", so do
|
|
||||||
some of your own research too, I'll provide links were ever I can, otherwise the information was brought to me in my
|
|
||||||
delusions.
|
|
||||||
|
|
||||||
### Matomo
|
|
||||||
|
|
||||||
I've seen Matomo get suggested in a few places before I went with Plausible originally, but I never checked it out till
|
|
||||||
now. While it looked solid, it also has _too_ much stuff... I didn't need or want a heatmap of interactions throughout
|
|
||||||
my website, nor session recording, or any ecommerce stuff.
|
|
||||||
|
|
||||||
Even with all that, I didn't particularly like the design, it was cluttered and confusing to go through the demo site.
|
|
||||||
|
|
||||||
### PostHog
|
|
||||||
|
|
||||||
PostHog was the second thing I've checked out, while it looked promising, it was just too much along with not solving my
|
|
||||||
problem of _having_ to use docker.
|
|
||||||
|
|
||||||
The requirements were also a bit insane for my needs, 8GBs of ram (recommended minimum) in comparison to the 256MB the
|
|
||||||
CT running umami currently has.
|
|
||||||
|
|
||||||
### Fathom
|
|
||||||
|
|
||||||
This was the last one I checked out before going with umami, I liked the design as it was similar to Plausible, and had
|
|
||||||
the feature set that I was looking for, with no complicated dashboards.
|
|
||||||
|
|
||||||
Buuuuuut, there is no self-hostable option, [kinda](https://github.com/usefathom/fathom). The lite version is no longer
|
|
||||||
maintained. Which is a shame, as it fathom looked promising and Go is a nice language to work with...
|
|
||||||
|
|
||||||
Maybe I could pick it up in the future, and bring it back to life again
|
|
||||||
|
|
||||||
### Services feature comparison
|
|
||||||
|
|
||||||
<Note text="Blank sections are due to me not being able to find information on the feature" />
|
|
||||||
|
|
||||||
| | Matomo | PostHog | umami | Fathom lite | Plausible |
|
|
||||||
|-------------------------------|--------|----------------------------|-----------------------------|------------------------------|----------------------------|
|
|
||||||
| Self-Hostable | Yes | Yes | Yes | Yes [^fathom-self-host] | Yes |
|
|
||||||
| Hosting method | PHP | Docker | Node or Docker | Go [^fathom-language] | Docker |
|
|
||||||
| GDPR compliant | Yes | Yes | Yes | No [^fathom-gdpr-compliance] | Yes |
|
|
||||||
| Email reports | Yes | Yes | | | Yes |
|
|
||||||
| Tracking events | Yes | Yes | Yes [^umami-event-tracking] | | No |
|
|
||||||
| Simple (and pretty) dashboard | No | Mostly | Yes | Yes | Yes |
|
|
||||||
| Minimum RAM | 1GB | 8GB | 256MB [^umamo-memory-usage] | | 1GB |
|
|
||||||
| Supported Databases | MySQL | N/A [^supported-databases] | Postgres or MySQL | SQLite | N/A [^supported-databases] |
|
|
||||||
|
|
||||||
## So what was wrong with Plausible?
|
|
||||||
|
|
||||||
Simply put, too heavy for my use-case. It was designed for websites that see thousands of people per week, maybe even a
|
|
||||||
day, but I haven't even reached a thousand views in a year! Secondly, docker, it has it's uses, but since all my
|
|
||||||
services already run in LXT/Proxmox containers, no point of putting them within another container.
|
|
||||||
|
|
||||||
All that I could've lived with fine, if not for trying to upgrade it. It broke, even in a docker container, it refused
|
|
||||||
to start after an update and wouldn't show any signs of life other that pushing my CPU usage to 100%, then freezing the
|
|
||||||
container!
|
|
||||||
|
|
||||||
Downgrading - worked. But since database migrations have been complete, a lot of the pages no longer worked, so I just
|
|
||||||
left it alone, until I was bothered with finding an alternative solution.
|
|
||||||
|
|
||||||
## umami
|
|
||||||
|
|
||||||
Finally, something I was looking for, it has all the features I need, with not too much extra stuff I'll never use. AND
|
|
||||||
it's self-hostable with a non-docker option!
|
|
||||||
|
|
||||||
Though, I did run into some issues compiling the project, specifically needing 2GBs of ram, lol
|
|
||||||

|
|
||||||
|
|
||||||
And here's a dashboard comparison, before umami and Plausible
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
## Now onto the fun stuff
|
|
||||||
|
|
||||||
<Note text="As mencioned before, this isn't supposed to be a full tutorial, but the steps I've taken to setup up umami" />
|
|
||||||
|
|
||||||
### Alpine
|
|
||||||
|
|
||||||
For this, I went with Alpine! It was my first time trying it, but it went great, and will probably be moving all my
|
|
||||||
services to it at some point, but that should be its own blog post. Main hurdle I had was understanding `OpenRC`, as
|
|
||||||
Alpine doesn't use `systemd`, but once I gotten used to `rc-update add <service>` and
|
|
||||||
`rc-service <service> start/stop/status` it went very smoothly.
|
|
||||||
|
|
||||||
Obviously firstly we should update all the available packages and install some useful tools
|
|
||||||
|
|
||||||
```bash
|
|
||||||
apk update
|
|
||||||
apk upgrade
|
|
||||||
apk add vim git
|
|
||||||
```
|
|
||||||
|
|
||||||
### Caddy
|
|
||||||
|
|
||||||
I didn't reaaaaaly need caddy for this, as it would mean the service would be behind two proxies, but I wanted to setup
|
|
||||||
caddy anyway. It was quite simple really
|
|
||||||
```bash
|
|
||||||
apk add caddy
|
|
||||||
rc-update add caddy
|
|
||||||
# Reboot
|
|
||||||
rc-service caddy start
|
|
||||||
# And make the required dirs and files
|
|
||||||
mkdir /var/www/html
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, in `/etc/caddy`, we edit the `Caddyfile`, use your favorite editor for this, but I like vim, so for me I would run
|
|
||||||
`vim Caddyfile`. Then set the contents to the following
|
|
||||||
```caddyfile
|
|
||||||
:8080
|
|
||||||
reverse_proxy localhost:3000
|
|
||||||
```
|
|
||||||
<Note text="3000 is the default port for yarn, but adjust for your needs" />
|
|
||||||
|
|
||||||
And finally we just need to reload the service, still within `/etc/caddy`, with `caddy reload`!
|
|
||||||
|
|
||||||
### Postgres
|
|
||||||
|
|
||||||
It was slightly more manual than I'm used to on Ubuntu, but I found [a great guide by luppeng](https://luppeng.wordpress.com/2020/02/28/install-and-start-postgresql-on-alpine-linux)
|
|
||||||
that is still up-to-date as of writing this.
|
|
||||||
|
|
||||||
Then I just needed to get into the database with `psql -U postgres` and run `CREATE DATABASE umami;`.
|
|
||||||
|
|
||||||
<Note text="Creating a user specific to this service, along with setting correct network permissions, would be the safest, but you can figure that out" />
|
|
||||||
|
|
||||||
### Installing umami
|
|
||||||
|
|
||||||
The [official documentation](https://umami.is/docs/install) is the nicest, but there is some extra stuff you need todo
|
|
||||||
outside-of their tutorial
|
|
||||||
|
|
||||||
Firstly we make the required directory and clone the project `mkdir /var/www/html`
|
|
||||||
|
|
||||||
<Note text="Before you go any further, follow the official documentation, then come back :3" />
|
|
||||||
|
|
||||||
Now we're gonna set umami as a service! [They have a guide on doing that with PM2](https://umami.is/docs/install#running-umami),
|
|
||||||
but I prefer to use system native stuff, most likely for you this would be `systemd`, but if you're following along,
|
|
||||||
we'll be using `openrc`
|
|
||||||
|
|
||||||
Making a service on OpenRC is actually quite simple,[they have a guide for making services too](https://github.com/OpenRC/openrc/blob/master/service-script-guide.md). But first, make a
|
|
||||||
user for the service, such as `umami`. Next, we must make a file in `/etc/init.d`, such as `/etc/init.d/umami`. You can
|
|
||||||
do this by simply running `vim /etc/init.d/umami` that'll create and open the file for you. Then enter the following
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/sbin/openrc-run
|
|
||||||
|
|
||||||
YARN_USER="umami"
|
|
||||||
PROJECT_DIR="/var/www/html/umami"
|
|
||||||
YARN_CMD="/usr/local/bin/yarn start"
|
|
||||||
APP_NAME="umami"
|
|
||||||
|
|
||||||
command="$YARN_CMD"
|
|
||||||
command_args="start"
|
|
||||||
command_user="$YARN_USER"
|
|
||||||
pidfile="/var/run/${APP_NAME}.pid"
|
|
||||||
output_log="/var/log/${APP_NAME}.log"
|
|
||||||
error_log="/var/log/${APP_NAME}_error.log"
|
|
||||||
|
|
||||||
depend() {
|
|
||||||
need net
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
ebegin "Starting ${APP_NAME}"
|
|
||||||
|
|
||||||
start-stop-daemon --start --user "$YARN_USER" \
|
|
||||||
--make-pidfile --pidfile "$pidfile" \
|
|
||||||
--chdir "$PROJECT_DIR" \
|
|
||||||
--exec "$command" -- $command_args >> "$output_log" 2>> "$error_log" &
|
|
||||||
|
|
||||||
eend $?
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
ebegin "Stopping ${APP_NAME}"
|
|
||||||
|
|
||||||
start-stop-daemon --stop --pidfile "$pidfile"
|
|
||||||
|
|
||||||
eend $?
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
and run the following - same - commands as we did earlier for caddy
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rc-update add umami
|
|
||||||
# Reboot
|
|
||||||
rc-service umami start
|
|
||||||
```
|
|
||||||
|
|
||||||
And we're done! Depending on your network setup, and if you used caddy or not, you should be able to visit the page from
|
|
||||||
something like `192.168.0.0:8000`, the default login is `admin`, `umami`.
|
|
||||||
|
|
||||||
## Some thoughts
|
|
||||||
|
|
||||||
You may also now notice new text on the bottom of the page
|
|
||||||
|
|
||||||
> This website tracks anonymous analytics. To see them in action visit umami.leggy.dev!
|
|
||||||
|
|
||||||
So far, I really enjoyed using umami, it's a nice project! But if you really don't like the idea of your visit being
|
|
||||||
counted, just paste the following into the JS console of your browser.
|
|
||||||
|
|
||||||
```js
|
|
||||||
localStorage.setItem("umami.disabled", 1);
|
|
||||||
```
|
|
||||||
|
|
||||||
All following visits will no-longer be counted. While I'd prefer your _not_ to remove yourself from the statistics, as
|
|
||||||
they're useful to me, you have the option to now.
|
|
||||||
|
|
||||||
[^fathom-self-host]: The paid version, that most people are probably know about, isn't self-hostable
|
|
||||||
[^fathom-language]: The self-hosted (lite) version uses Go, the paid version uses [Laravel](https://github.com/usefathom/fathom/issues/336#issuecomment-1079549690).
|
|
||||||
[^fathom-gdpr-compliance]: The paid version of Fathom [does comply, through their isolation layer](https://usefathom.com/features/eu-isolation), the lite version does not guarantee this.
|
|
||||||
[^umami-event-tracking]: unami doesn't track events automatically [and needs to be setup manually across the website](https://umami.is/docs/track-events).
|
|
||||||
[^umamo-memory-usage]: unami doesn't list minimum requirements, so far from my testing, this is about what I needed for all my websites. For installs that have higher page visit counts, I imagine more would be needed.
|
|
||||||
[^supported-databases]: The service is run within Docker containers, so I don't get to choose what database I can actually use :(
|
|
|
@ -1,106 +0,0 @@
|
||||||
---
|
|
||||||
draft: true
|
|
||||||
title: "Code Examples"
|
|
||||||
description: "Aurghhhhhh"
|
|
||||||
pubDate: 2022-07-08
|
|
||||||
tags:
|
|
||||||
- "code"
|
|
||||||
---
|
|
||||||
|
|
||||||
```astro
|
|
||||||
---
|
|
||||||
import { getPosts } from "../../utils";
|
|
||||||
import Layout from "../../layouts/Layout.astro";
|
|
||||||
import Markdown from "../../layouts/Markdown.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const collection = await getPosts("projects");
|
|
||||||
|
|
||||||
return collection.map((post, i) => ({
|
|
||||||
params: { slug: post.slug },
|
|
||||||
props: {
|
|
||||||
post: post,
|
|
||||||
prev: i > 0 ? collection[i - 1] : undefined,
|
|
||||||
next: i < collection.length - 1 ? collection[i + 1] : undefined
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { post, prev, next } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title=`Leggy Land - ${post.data.title}` src={post.data.image.url} alt={post.data.image.alt}>
|
|
||||||
<Markdown {post} {prev} {next} base="/projects" />
|
|
||||||
</Layout>
|
|
||||||
```
|
|
||||||
|
|
||||||
```scss
|
|
||||||
.astro-code {
|
|
||||||
padding: 36px 8px 8px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "lang: " attr(data-language);
|
|
||||||
|
|
||||||
padding: 4px 8px;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 28px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
background-color: $gray;
|
|
||||||
color: $light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (p *penTool) Render() raylib.Texture2D {
|
|
||||||
offset := raylib.Vector2Scale(canvas.Offset, -1)
|
|
||||||
texture := raylib.LoadRenderTexture(int32(canvas.Size.X), int32(canvas.Size.Y))
|
|
||||||
|
|
||||||
raylib.BeginTextureMode(texture)
|
|
||||||
raylib.ClearBackground(raylib.Fade(raylib.Black, 0))
|
|
||||||
for i := 0; i < len(p.Points)-1; i++ {
|
|
||||||
startPointOffset := raylib.Vector2Add(p.Points[i], offset)
|
|
||||||
endPointOffset := raylib.Vector2Add(p.Points[i+1], offset)
|
|
||||||
raylib.DrawLineEx(startPointOffset, endPointOffset, p.Size, p.Color)
|
|
||||||
raylib.DrawCircle(int32(startPointOffset.X), int32(startPointOffset.Y), p.Size/2, p.Color)
|
|
||||||
}
|
|
||||||
if len(p.Points) > 0 {
|
|
||||||
endPointOffset := raylib.Vector2Add(p.Points[len(p.Points)-1], offset)
|
|
||||||
raylib.DrawCircle(int32(endPointOffset.X), int32(endPointOffset.Y), p.Size/2, p.Color)
|
|
||||||
}
|
|
||||||
raylib.EndTextureMode()
|
|
||||||
|
|
||||||
return texture.Texture
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class Article(models.Model):
|
|
||||||
title = models.CharField(max_length=255)
|
|
||||||
slug = models.SlugField()
|
|
||||||
body = models.TextField()
|
|
||||||
date = models.DateTimeField(auto_now_add=True)
|
|
||||||
thumb = models.ImageField(default="default.png", blank=True)
|
|
||||||
published = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.title
|
|
||||||
```
|
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
draft: true
|
|
||||||
title: "Image Examples"
|
|
||||||
description: "fug"
|
|
||||||
pubDate: 2024-07-08
|
|
||||||
tags:
|
|
||||||
- "code"
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
critter time!!!!
|
|
|
@ -1,130 +0,0 @@
|
||||||
---
|
|
||||||
draft: true
|
|
||||||
title: This is an example Post
|
|
||||||
description: "Cheat Sheet for Markdown"
|
|
||||||
pubDate: 2022-07-08
|
|
||||||
tags:
|
|
||||||
- "code"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Markdown Cheat Sheet
|
|
||||||
|
|
||||||
Thanks for visiting [The Markdown Guide](https://www.markdownguide.org)!
|
|
||||||
|
|
||||||
This Markdown cheat sheet provides a quick overview of all the Markdown syntax elements. It can’t cover every edge case, so if you need more information about any of these elements, refer to the reference guides for [basic syntax](https://www.markdownguide.org/basic-syntax/) and [extended syntax](https://www.markdownguide.org/extended-syntax/).
|
|
||||||
|
|
||||||
## Basic Syntax
|
|
||||||
|
|
||||||
These are the elements outlined in John Gruber’s original design document. All Markdown applications support these elements.
|
|
||||||
|
|
||||||
### Heading
|
|
||||||
|
|
||||||
# H1
|
|
||||||
|
|
||||||
## H2
|
|
||||||
|
|
||||||
### H3
|
|
||||||
|
|
||||||
### Bold
|
|
||||||
|
|
||||||
**bold text**
|
|
||||||
|
|
||||||
### Italic
|
|
||||||
|
|
||||||
_italicized text_
|
|
||||||
|
|
||||||
### Blockquote
|
|
||||||
|
|
||||||
> blockquote
|
|
||||||
|
|
||||||
### Ordered List
|
|
||||||
|
|
||||||
1. First item
|
|
||||||
2. Second item
|
|
||||||
3. Third item
|
|
||||||
|
|
||||||
### Unordered List
|
|
||||||
|
|
||||||
- First item
|
|
||||||
- Second item
|
|
||||||
- Third item
|
|
||||||
|
|
||||||
### Code
|
|
||||||
|
|
||||||
`code`
|
|
||||||
|
|
||||||
### Horizontal Rule
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Link
|
|
||||||
|
|
||||||
[Markdown Guide](https://www.markdownguide.org)
|
|
||||||
|
|
||||||
### Image
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Extended Syntax
|
|
||||||
|
|
||||||
These elements extend the basic syntax by adding additional features. Not all Markdown applications support these elements.
|
|
||||||
|
|
||||||
### Table
|
|
||||||
|
|
||||||
| Syntax | Description |
|
|
||||||
| --------- | ----------- |
|
|
||||||
| Header | Title |
|
|
||||||
| Paragraph | Text |
|
|
||||||
|
|
||||||
### Fenced Code Block
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"firstName": "John",
|
|
||||||
"lastName": "Smith",
|
|
||||||
"age": 25
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Footnote
|
|
||||||
|
|
||||||
Here's a sentence with a footnote. [^1]
|
|
||||||
|
|
||||||
[^1]: This is the footnote.
|
|
||||||
|
|
||||||
### Heading ID
|
|
||||||
|
|
||||||
### My Great Heading \{#custom-id}
|
|
||||||
|
|
||||||
### Definition List
|
|
||||||
|
|
||||||
term
|
|
||||||
: definition
|
|
||||||
|
|
||||||
### Strikethrough
|
|
||||||
|
|
||||||
~~The world is flat.~~
|
|
||||||
|
|
||||||
### Task List
|
|
||||||
|
|
||||||
- [x] Write the press release
|
|
||||||
- [ ] Update the website
|
|
||||||
- [ ] Contact the media
|
|
||||||
|
|
||||||
### Emoji
|
|
||||||
|
|
||||||
That is so funny! :joy:
|
|
||||||
|
|
||||||
(See also [Copying and Pasting Emoji](https://www.markdownguide.org/extended-syntax/#copying-and-pasting-emoji))
|
|
||||||
|
|
||||||
### Highlight
|
|
||||||
|
|
||||||
I need to highlight these ==very important words==.
|
|
||||||
|
|
||||||
### Subscript
|
|
||||||
|
|
||||||
H~2~O
|
|
||||||
|
|
||||||
### Superscript
|
|
||||||
|
|
||||||
X^2^
|
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
draft: true
|
|
||||||
title: "Math Examples"
|
|
||||||
description: "REEEEEE"
|
|
||||||
pubDate: 2024-06-08
|
|
||||||
tags:
|
|
||||||
- "code"
|
|
||||||
- "math"
|
|
||||||
---
|
|
||||||
|
|
||||||
Some simple mathematical expressions:
|
|
||||||
|
|
||||||
$$ \sqrt\{3x-1}+(1+x)^2 $$
|
|
||||||
|
|
||||||
$$\frac\{ax^2+bx+c}\{(a+b)^2}=0$$
|
|
||||||
|
|
||||||
$$f(x) = \pm A \sin\left(\frac\{2\pi}\{4} + \theta\right)$$
|
|
||||||
|
|
||||||
More complicated examples (from [KateX home page](https://katex.org)):
|
|
||||||
|
|
||||||
$$\displaystyle \frac\{1}\{\Bigl(\sqrt\{\phi \sqrt\{5}}-\phi\Bigr) e^\{\frac25 \pi}} = 1+\frac\{e^\{-2\pi}} \{1+\frac\{e^\{-4\pi}} \{1+\frac\{e^\{-6\pi}} \{1+\frac\{e^\{-8\pi}} \{1+\cdots} } } }$$
|
|
||||||
|
|
||||||
$$\displaystyle \left( \sum_\{k=1}^n a_k b_k \right)^2 \leq \left( \sum_\{k=1}^n a_k^2 \right) \left( \sum_\{k=1}^n b_k^2 \right)$$
|
|
||||||
|
|
||||||
$$\displaystyle \{1 + \frac\{q^2}\{(1-q)}+\frac\{q^6}\{(1-q)(1-q^2)}+\cdots }= \prod_\{j=0}^\{\infty}\frac\{1}\{(1-q^\{5j+2})(1-q^\{5j+3})}, \quad\quad \text\{for }\lvert q\rvert\<1. $$
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Algorithms
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Alpine
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Astro
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Caddy
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Django
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: ESPHome
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Game Development
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Go
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: HomeAssistant
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: First Impressions
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Linux/GNU
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Networking
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Pebble
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Python
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: raylib
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Review
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Typescript
|
|
||||||
---
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
name: Web Development
|
|
||||||
---
|
|
2
src/env.d.ts
vendored
|
@ -1,2 +0,0 @@
|
||||||
/// <reference path="../.astro/types.d.ts" />
|
|
||||||
/// <reference types="astro/client" />
|
|
|
@ -1,179 +0,0 @@
|
||||||
---
|
|
||||||
import "../styles/styles.scss";
|
|
||||||
import Banner from "../assets/banner.png";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title: string;
|
|
||||||
plugins?: {
|
|
||||||
katex?: boolean,
|
|
||||||
giscus?: boolean,
|
|
||||||
}
|
|
||||||
seo?: {
|
|
||||||
description?: string,
|
|
||||||
tags?: string[],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { title, plugins, seo } = Astro.props;
|
|
||||||
|
|
||||||
const address = import.meta.env.PUBLIC_ADDRESS;
|
|
||||||
---
|
|
||||||
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>{title}</title>
|
|
||||||
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="description" content={seo?.description ? seo?.description : "Premium Legs only"} />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<meta name="generator" content={Astro.generator} />
|
|
||||||
<meta name="keywords" content={seo?.tags ? seo?.tags.join(', ') : "furry, gay, homosegs"} />
|
|
||||||
|
|
||||||
<meta property="og:title" content={title} />
|
|
||||||
<meta property="og:description" content={seo?.description ? seo?.description : "Premium Legs only"} />
|
|
||||||
<meta property="og:url" content="https://gay.leggy.dev" />
|
|
||||||
<meta property="og:type" content="website" />
|
|
||||||
|
|
||||||
<link
|
|
||||||
rel="icon"
|
|
||||||
type="image/webp"
|
|
||||||
href="/leg.webp"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<link
|
|
||||||
rel="preconnect"
|
|
||||||
href="https://api.fontshare.com"
|
|
||||||
>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://api.fontshare.com/v2/css?f[]=jet-brains-mono@400&f[]=general-sans@1&display=swap"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If you want to disable your visits from being counted,
|
|
||||||
run "localStorage.setItem('umami.disabled', 1);"
|
|
||||||
in the JS console (without the quotation marks).
|
|
||||||
-->
|
|
||||||
<script
|
|
||||||
is:inline
|
|
||||||
defer
|
|
||||||
src="https://umami.leggy.dev/script.js"
|
|
||||||
data-website-id="e8c4fb4f-6ff2-4179-8873-957d635c862c"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{plugins?.katex && (
|
|
||||||
<link
|
|
||||||
rel="preconnect"
|
|
||||||
href="https://cdn.jsdelivr.net"
|
|
||||||
>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css"
|
|
||||||
integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<script
|
|
||||||
is:inline
|
|
||||||
defer
|
|
||||||
src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js"
|
|
||||||
integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
></script>
|
|
||||||
<script
|
|
||||||
is:inline
|
|
||||||
defer
|
|
||||||
src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js"
|
|
||||||
integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
onload="renderMathInElement(document.body);"
|
|
||||||
></script>
|
|
||||||
)}
|
|
||||||
{plugins?.giscus && (
|
|
||||||
<script
|
|
||||||
is:inline
|
|
||||||
src="https://giscus.app/client.js"
|
|
||||||
data-repo="Fluffy-Bean/website"
|
|
||||||
data-repo-id="R_kgDOL-t-KQ"
|
|
||||||
data-category="General"
|
|
||||||
data-category-id="DIC_kwDOL-t-Kc4CfxFh"
|
|
||||||
data-mapping="title"
|
|
||||||
data-strict="0"
|
|
||||||
data-reactions-enabled="1"
|
|
||||||
data-emit-metadata="0"
|
|
||||||
data-input-position="top"
|
|
||||||
data-theme=`${address}/custom/giscus.css`
|
|
||||||
data-lang="en"
|
|
||||||
data-loading="lazy"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
async
|
|
||||||
></script>
|
|
||||||
)}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<a href="#content-skip" tabindex="0" id="content-skip-button">Skip to content</a>
|
|
||||||
<div class="banner">
|
|
||||||
<img
|
|
||||||
src={Banner.src}
|
|
||||||
alt="Stretch of road leading to cloudy hills with houses in the horizon"
|
|
||||||
width="1080"
|
|
||||||
height="700"
|
|
||||||
loading="eager"
|
|
||||||
decoding="async"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<main>
|
|
||||||
<slot />
|
|
||||||
<p id="anal_notice">
|
|
||||||
This website tracks anonymous analytics. To see them in action visit
|
|
||||||
<a href="https://umami.leggy.dev/share/jNKQaN97seslziXY/gay.leggy.dev" target="_blank">umami.leggy.dev</a>!
|
|
||||||
</p>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
function update(element: HTMLElement) { element.style.top = `${window.scrollY * 0.75 }px`; }
|
|
||||||
const img = document.querySelector(".banner > img") as HTMLImageElement;
|
|
||||||
document.addEventListener("scroll", () => update(img))
|
|
||||||
document.addEventListener("DOMContentLoaded", () => update(img))
|
|
||||||
</script>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../styles/vars.scss";
|
|
||||||
|
|
||||||
#content-skip-button {
|
|
||||||
padding: 16px 32px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: -1000000px;
|
|
||||||
left: -1000000px;
|
|
||||||
z-index: 999999999;
|
|
||||||
|
|
||||||
font-weight: bolder;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
background-color: $accent;
|
|
||||||
color: $light;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
outline: 0 solid transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#anal_notice {
|
|
||||||
padding-top: 16px;
|
|
||||||
margin-bottom: -16px;
|
|
||||||
color: $light;
|
|
||||||
font-size: 11px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: $accent;
|
|
||||||
&:hover {
|
|
||||||
color: $light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,327 +0,0 @@
|
||||||
---
|
|
||||||
import { getMonth, getDaySuffix, getTagsBySlug } from "../utils";
|
|
||||||
import Layout from "./Layout.astro";
|
|
||||||
import HomeButton from "../components/HomeButton.astro";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
post: any,
|
|
||||||
prev?: any,
|
|
||||||
next?: any,
|
|
||||||
base: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
const { post, prev, next } = Astro.props;
|
|
||||||
|
|
||||||
// 183 average w/p
|
|
||||||
const readTime = `${Math.ceil(post.body.split(" ").length / 183)} min read`;
|
|
||||||
const date = new Date(post.data.pubDate);
|
|
||||||
const tags = await getTagsBySlug(post.data.tags);
|
|
||||||
|
|
||||||
const comments = import.meta.env.PUBLIC_COMMENTS === "true";
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout
|
|
||||||
title=`Leggy Land - ${post.data.title}`
|
|
||||||
plugins={{
|
|
||||||
katex: true,
|
|
||||||
giscus: comments,
|
|
||||||
}}
|
|
||||||
seo={{
|
|
||||||
description: post.data.description,
|
|
||||||
tags: post.data.tags,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<HomeButton />
|
|
||||||
|
|
||||||
<!-- If I ever move anything around, this will fucking break -->
|
|
||||||
<a href=`https://github.com/Fluffy-Bean/website/tree/main/src/content/posts/${post.id}` id="source" class="button" aria-label="Source Code">
|
|
||||||
<span>Source Code</span>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M69.12,94.15,28.5,128l40.62,33.85a8,8,0,1,1-10.24,12.29l-48-40a8,8,0,0,1,0-12.29l48-40a8,8,0,0,1,10.24,12.3Zm176,27.7-48-40a8,8,0,1,0-10.24,12.3L227.5,128l-40.62,33.85a8,8,0,1,0,10.24,12.29l48-40a8,8,0,0,0,0-12.29ZM162.73,32.48a8,8,0,0,0-10.25,4.79l-64,176a8,8,0,0,0,4.79,10.26A8.14,8.14,0,0,0,96,224a8,8,0,0,0,7.52-5.27l64-176A8,8,0,0,0,162.73,32.48Z"></path></svg>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Sticky could be added, but it makes it a buit difficult to read things on mobile-->
|
|
||||||
<div class="header">
|
|
||||||
<h1>{post.data.title}</h1>
|
|
||||||
{post.data.pubDate ? (
|
|
||||||
<p>{date.getDate()}{getDaySuffix(date)} {getMonth(date)} {date.getFullYear()} • {readTime} • {post.data.description}</p>
|
|
||||||
) : (
|
|
||||||
<p>{readTime} • {post.data.description}</p>
|
|
||||||
)}
|
|
||||||
<ul id="tags" class="pill-list" role="list">
|
|
||||||
{tags.map((tag) => (
|
|
||||||
<li>
|
|
||||||
<a class="pill" href=`/search/${tag.slug}`>
|
|
||||||
<!--<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" fill="currentColor" viewBox="0 0 256 256"><path d="M216,152H168V104h48a8,8,0,0,0,0-16H168V40a8,8,0,0,0-16,0V88H104V40a8,8,0,0,0-16,0V88H40a8,8,0,0,0,0,16H88v48H40a8,8,0,0,0,0,16H88v48a8,8,0,0,0,16,0V168h48v48a8,8,0,0,0,16,0V168h48a8,8,0,0,0,0-16Zm-112,0V104h48v48Z"></path></svg>-->
|
|
||||||
{tag.data.name}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<div id="markdown">
|
|
||||||
<div style="margin-bottom: 32px" />
|
|
||||||
<slot></slot>
|
|
||||||
<div style="margin-top: 32px" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{(prev || next) && ( <hr> )}
|
|
||||||
|
|
||||||
<ul id="controls" role="list">
|
|
||||||
<li>
|
|
||||||
{prev && (
|
|
||||||
<a class="button" href=`/posts/${prev.slug}` id="prev">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"></path></svg>
|
|
||||||
Newer
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
{next && (
|
|
||||||
<a class="button" href=`/posts/${next.slug}` id="next">
|
|
||||||
Older
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M221.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L196.69,136H40a8,8,0,0,1,0-16H196.69L138.34,61.66a8,8,0,0,1,11.32-11.32l72,72A8,8,0,0,1,221.66,133.66Z"></path></svg>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{comments && (
|
|
||||||
<hr>
|
|
||||||
<div class="giscus" id="giscus" />
|
|
||||||
)}
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style is:global lang="scss">
|
|
||||||
@import "../styles/vars";
|
|
||||||
|
|
||||||
#source {
|
|
||||||
padding: 0 10px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
|
|
||||||
transition: padding 1s cubic-bezier(0, 1, 0, 1);
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover, &:focus-visible {
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
> svg {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-content: center;
|
|
||||||
|
|
||||||
> li > .button {
|
|
||||||
min-width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#markdown {
|
|
||||||
margin: -32px 0;
|
|
||||||
display: block;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
|
|
||||||
:target {
|
|
||||||
scroll-margin-block: 5ex;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
line-height: 1.1;
|
|
||||||
text-wrap: balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
color: $accent;
|
|
||||||
|
|
||||||
&:hover, &:focus-visible {
|
|
||||||
color: $light;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
border-radius: $radius;
|
|
||||||
outline: 1px solid $light;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:is([class]) {
|
|
||||||
text-decoration-skip-ink: auto;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ol, ul {
|
|
||||||
margin: 16px 0;
|
|
||||||
padding-left: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
margin: 16px 0;
|
|
||||||
border: 0;
|
|
||||||
border-top: 2px solid $gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Style code only if it's not a child of .astro-code
|
|
||||||
:not(.astro-code) > code {
|
|
||||||
padding: 2px 4px;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
background-color: $gray;
|
|
||||||
color: $light;
|
|
||||||
|
|
||||||
overflow-x: auto
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 8px 0 8px 16px;
|
|
||||||
padding: 0 8px;
|
|
||||||
|
|
||||||
font-style: italic;
|
|
||||||
|
|
||||||
border-left: 2px solid $accent;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
margin: 16px 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-bottom: 2px solid $gray;
|
|
||||||
|
|
||||||
tr {
|
|
||||||
&:nth-child(even) td {
|
|
||||||
background-color: rgba($gray, 0.15);
|
|
||||||
}
|
|
||||||
&:last-of-type > td {
|
|
||||||
/*border-bottom: 2px solid darken($gray, 2%);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
padding: 8px 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
/*border-bottom: 2px solid darken($gray, 2%);*/
|
|
||||||
background-color: $gray;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-top-left-radius: $radius;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
border-top-right-radius: $radius;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin: 16px 0;
|
|
||||||
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
.astro-code {
|
|
||||||
margin: 20px 0;
|
|
||||||
|
|
||||||
padding: 40px 8px 8px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
border: 2px solid rgba(#000, 0.1);
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: attr(data-language);
|
|
||||||
|
|
||||||
padding: 4px 16px;
|
|
||||||
|
|
||||||
width: max-content;
|
|
||||||
height: 28px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
text-transform: capitalize;
|
|
||||||
|
|
||||||
border-top-right-radius: 9999px;
|
|
||||||
border-bottom-right-radius: 9999px;
|
|
||||||
background-color: $gray;
|
|
||||||
color: $light;
|
|
||||||
|
|
||||||
z-index: +1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 1px solid $light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footnotes {
|
|
||||||
margin-top: 32px;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
background-color: $gray;
|
|
||||||
|
|
||||||
> h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,112 +0,0 @@
|
||||||
---
|
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
|
|
||||||
import { getPosts } from "../utils";
|
|
||||||
import Layout from "../layouts/Layout.astro";
|
|
||||||
import Card from "../components/Card.astro";
|
|
||||||
import Certificate from "../components/Certificate.astro";
|
|
||||||
import Music from "../components/Music.astro";
|
|
||||||
|
|
||||||
const tools = ["Proxmox", "JetBrain IDEs", "Docker", "Linux", "SQLite", "Postgres", "MySQL"];
|
|
||||||
const languages = ["Go", "Python", "HTML", "CSS", "Sass", "TypeScript", "JavaScript", "Scratch", "PHP", "SQL", "Bash"];
|
|
||||||
const frameworks = ["Gin", "Echo", "Flask", "Svelte", "Astro", "raylib"];
|
|
||||||
const certificates = await getCollection("certificates");
|
|
||||||
const posts = await getPosts("posts");
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title="Leggy Land">
|
|
||||||
<div class="header">
|
|
||||||
<h1>Leggy Land</h1>
|
|
||||||
<p>Made with Coffee, lots of it.</p>
|
|
||||||
<Music />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Who am I</h2>
|
|
||||||
<p>My name is Michał, I go by Fluffy, I'm 20 and I like computers</p>
|
|
||||||
<p>I mainly do website stuff, work with the front and backend, but I also like networking and breaking things</p>
|
|
||||||
<p>My favorite language currently is Go, but I also know a few other languages that are listed below!</p>
|
|
||||||
<p>In my free time, which isn't that often anymore, I enjoy playing games, such as The Witcher, Spin RhythmXD and other random stuff</p>
|
|
||||||
<p>I use Arch btw.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Stalk me here</h2>
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
<li><a class="button" href="https://www.twitter.com/fluffybeanUwU" target="_blank">Twitter</a></li>
|
|
||||||
<li><a class="button" href="https://bsky.app/profile/leggy.dev" target="_blank">BlueSky</a></li>
|
|
||||||
<li><a class="button" href="https://t.me/Fluffy_Bean" target="_blank">Telegram</a></li>
|
|
||||||
<li><a class="button" href="https://github.com/Fluffy-Bean" target="_blank">GitHub</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Tools</h2>
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
{tools.map(tool => (
|
|
||||||
<li class="pill large">
|
|
||||||
{tool}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Languages</h2>
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
{languages.map(language => (
|
|
||||||
<li class="pill large">
|
|
||||||
{language}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Frameworks</h2>
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
{frameworks.map(framework => (
|
|
||||||
<li class="pill large">
|
|
||||||
{framework}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Recent Posts</h2>
|
|
||||||
{(posts.length > 0) ? (
|
|
||||||
<ul class="project-list" role="list">
|
|
||||||
{posts.slice(0, 2).map(post => (
|
|
||||||
<Card {post} />
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<a class="button" id="see-all-posts" href="/posts">All Posts</a>
|
|
||||||
) : (
|
|
||||||
<p>No Posts yet made!</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Certificates</h2>
|
|
||||||
<ul class="project-list" role="list">
|
|
||||||
{certificates.map(certificate => (
|
|
||||||
<li>
|
|
||||||
<Certificate {certificate} />
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../styles/vars.scss";
|
|
||||||
|
|
||||||
#see-all-projects,
|
|
||||||
#see-all-posts {
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
import Layout from "../layouts/Layout.astro";
|
|
||||||
import HomeButton from "../components/HomeButton.astro";
|
|
||||||
import GwaGwa from "../assets/fumble.jpg";
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title="LEG LEG LEG LEG LEG LEG LEG LEG LEG LEG LEG LEG LEG">
|
|
||||||
<HomeButton />
|
|
||||||
|
|
||||||
<div class="header">
|
|
||||||
<h1>Maned Wolf Jumpscare</h1>
|
|
||||||
<p>GwaGwa</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<div class="secrtion">
|
|
||||||
<img
|
|
||||||
src={GwaGwa.src}
|
|
||||||
alt="Two Maned wolfs having a disagreement"
|
|
||||||
width="851"
|
|
||||||
height="575"
|
|
||||||
style="height: auto"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
import { getPosts } from "../../utils";
|
|
||||||
import Markdown from "../../layouts/Markdown.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const collection = await getPosts("posts");
|
|
||||||
|
|
||||||
return collection.map((post, i) => ({
|
|
||||||
params: { slug: post.slug },
|
|
||||||
props: {
|
|
||||||
post: post,
|
|
||||||
prev: i > 0 ? collection[i - 1] : undefined,
|
|
||||||
next: i < collection.length - 1 ? collection[i + 1] : undefined,
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { post, prev, next } = Astro.props;
|
|
||||||
|
|
||||||
const { Content } = await post.render();
|
|
||||||
---
|
|
||||||
|
|
||||||
<Markdown post={post} prev={prev} next={next} base="posts">
|
|
||||||
<Content />
|
|
||||||
</Markdown>
|
|
|
@ -1,53 +0,0 @@
|
||||||
---
|
|
||||||
import { getPosts } from "../../utils";
|
|
||||||
import Layout from "../../layouts/Layout.astro";
|
|
||||||
import HomeButton from "../../components/HomeButton.astro";
|
|
||||||
import Card from "../../components/Card.astro";
|
|
||||||
|
|
||||||
const posts = await getPosts("posts");
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title="Leggy Land - All Posts">
|
|
||||||
<HomeButton />
|
|
||||||
|
|
||||||
<a href="/search" id="search" class="button" aria-label="Search">
|
|
||||||
Search
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M230.6,49.53A15.81,15.81,0,0,0,216,40H40A16,16,0,0,0,28.19,66.76l.08.09L96,139.17V216a16,16,0,0,0,24.87,13.32l32-21.34A16,16,0,0,0,160,194.66V139.17l67.74-72.32.08-.09A15.8,15.8,0,0,0,230.6,49.53ZM40,56h0Zm106.18,74.58A8,8,0,0,0,144,136v58.66L112,216V136a8,8,0,0,0-2.16-5.47L40,56H216Z"></path></svg>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="header">
|
|
||||||
<h1>All Posts</h1>
|
|
||||||
<p>Books of egg</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<ul role="list" class="project-list">
|
|
||||||
{posts.map(post => (
|
|
||||||
<Card {post}/>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style is:global lang="scss">
|
|
||||||
@import "../../styles/vars";
|
|
||||||
|
|
||||||
#search {
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
|
|
||||||
transition: padding 1s cubic-bezier(0, 1, 0, 1);
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
---
|
|
||||||
import Layout from "../layouts/Layout.astro";
|
|
||||||
import HomeButton from "../components/HomeButton.astro";
|
|
||||||
import Ref from "../assets/art/ref.png";
|
|
||||||
import Sneak from "../assets/art/sneak.png";
|
|
||||||
import Taidum from "../assets/art/taidum.png";
|
|
||||||
import Men from "../assets/art/kissing-men.png";
|
|
||||||
import Mood from "../assets/art/mood.png";
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title="Leggy Land - Refsheet">
|
|
||||||
<HomeButton />
|
|
||||||
|
|
||||||
<div class="header">
|
|
||||||
<h1>Refsheet</h1>
|
|
||||||
<p>Maned Wolf moment</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Refsheet</h2>
|
|
||||||
<img src={Ref.src} alt="FluffyBean" class="art max" />
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
<li class="pill size-button">mrHDash</li>
|
|
||||||
<li><a href="https://twitter.com/mrHDash" class="button">Twitter</a></li>
|
|
||||||
<li><a href="https://instagram.com/mrhdash_arts" class="button">Instagram</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<h2>Shep</h2>
|
|
||||||
<img src={Sneak.src} alt="FluffyBean" class="art" />
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
<li class="pill size-button">Shep</li>
|
|
||||||
<li><a href="https://twitter.com/ShepGoesBlep" class="button">Twitter</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="section">
|
|
||||||
<h2>Zadok</h2>
|
|
||||||
<img src={Taidum.src} alt="FluffyBean" class="art" />
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
<li class="pill size-button">Zadok</li>
|
|
||||||
<li><a href="https://twitter.com/Zadoktater" class="button">Twitter</a></li>
|
|
||||||
<li><button onclick="navigator.clipboard.writeText('zadoknchip'); return;" class="button">Discord</button></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="section">
|
|
||||||
<h2>LordPulex</h2>
|
|
||||||
<img src={Men.src} alt="FluffyBean" class="art" />
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
<li class="pill size-button">LordPulex</li>
|
|
||||||
<li><a href="https://twitter.com/LordPulex" class="button">Twitter</a></li>
|
|
||||||
<li><a href="https://pulex.carrd.co/" class="button">Website</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="section">
|
|
||||||
<h2>OggyTheFox</h2>
|
|
||||||
<img src={Mood.src} alt="FluffyBean" class="art" />
|
|
||||||
<ul class="pill-list" role="list">
|
|
||||||
<li class="pill size-button">OggyTheFox</li>
|
|
||||||
<li><a href="https://twitter.com/OggyOsbourne" class="button">Twitter</a></li>
|
|
||||||
<li><a href="https://oggy123.eu/" class="button">Website</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../styles/vars.scss";
|
|
||||||
|
|
||||||
.art {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
/*padding: 8px;*/
|
|
||||||
|
|
||||||
max-width: 400px;
|
|
||||||
|
|
||||||
border-radius: $radius;
|
|
||||||
/*background: $gray;*/
|
|
||||||
|
|
||||||
&.max {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,69 +0,0 @@
|
||||||
---
|
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
|
|
||||||
import { getPosts } from "../../utils";
|
|
||||||
import Layout from "../../layouts/Layout.astro";
|
|
||||||
import Card from "../../components/Card.astro";
|
|
||||||
import HomeButton from "../../components/HomeButton.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const collection = await getCollection("tags");
|
|
||||||
|
|
||||||
// Filter by file name, such as linux-kernel instead of "Linux Kernel"
|
|
||||||
return collection.map((tag) => ({
|
|
||||||
params: { filter: tag.slug },
|
|
||||||
props: { tag }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { tag } = Astro.props;
|
|
||||||
|
|
||||||
const allPosts = await getPosts("posts");
|
|
||||||
const filteredPosts = allPosts.filter((project) => project.data.tags.includes(tag.slug));
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title=`Leggy Land - Searching for ${tag.data.name}`>
|
|
||||||
<HomeButton />
|
|
||||||
|
|
||||||
<a href="/search" id="reset-filters" class="button" aria-label="Reset Filters">
|
|
||||||
Reset Filters
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M227.82,66.76A16,16,0,0,0,216,40H40A16,16,0,0,0,28.19,66.76l.08.09L96,139.17V216a16,16,0,0,0,24.87,13.32l32-21.34A16,16,0,0,0,160,194.66V139.17l67.73-72.32ZM40,56h0Zm106.19,74.59A8,8,0,0,0,144,136v58.66L112,216V136a8,8,0,0,0-2.16-5.46L40,56H216Zm99.49,79.81a8,8,0,0,1-11.32,11.32L216,203.32l-18.34,18.35a8,8,0,0,1-11.31-11.32L204.69,192l-18.34-18.35a8,8,0,0,1,11.31-11.31L216,180.69l18.34-18.34a8,8,0,0,1,11.32,11.31L227.31,192Z"></path></svg>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="header">
|
|
||||||
<h1>Search: {tag.data.name}</h1>
|
|
||||||
<p>Showing {filteredPosts.length}/{allPosts.length} posts</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<div class="section">
|
|
||||||
<ul role="list" class="project-list">
|
|
||||||
{filteredPosts.map(post => (
|
|
||||||
<Card {post} />
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style is:global lang="scss">
|
|
||||||
@import "../../styles/vars";
|
|
||||||
|
|
||||||
#reset-filters {
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
|
|
||||||
transition: padding 1s cubic-bezier(0, 1, 0, 1);
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,66 +0,0 @@
|
||||||
---
|
|
||||||
import { getCollection} from "astro:content";
|
|
||||||
|
|
||||||
import { getPosts } from "../../utils";
|
|
||||||
import Layout from "../../layouts/Layout.astro";
|
|
||||||
import HomeButton from "../../components/HomeButton.astro";
|
|
||||||
|
|
||||||
const tags = await getCollection("tags");
|
|
||||||
const posts = await getPosts("posts");
|
|
||||||
|
|
||||||
// Get post count for reach tag
|
|
||||||
tags.forEach((tag) => {
|
|
||||||
tag.data.postCount = posts.filter((project) => {
|
|
||||||
return project.data.tags.includes(tag.slug);
|
|
||||||
}).length;
|
|
||||||
})
|
|
||||||
// Dunno if Astro auto-sorts stuff
|
|
||||||
tags.sort((a, b) => {
|
|
||||||
return a.data.name.localeCompare(b.data.name);
|
|
||||||
});
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title="Leggy Land - All Projects">
|
|
||||||
<HomeButton />
|
|
||||||
|
|
||||||
<div class="header">
|
|
||||||
<h1>Search</h1>
|
|
||||||
<p>Filter posts by tags</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="content-skip" />
|
|
||||||
|
|
||||||
<ul role="list" class="pill-list">
|
|
||||||
{tags.map(tag => (
|
|
||||||
<li>
|
|
||||||
<a class="pill large" href=`/search/${tag.slug}`>
|
|
||||||
<!--<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 256 256"><path d="M216,152H168V104h48a8,8,0,0,0,0-16H168V40a8,8,0,0,0-16,0V88H104V40a8,8,0,0,0-16,0V88H40a8,8,0,0,0,0,16H88v48H40a8,8,0,0,0,0,16H88v48a8,8,0,0,0,16,0V168h48v48a8,8,0,0,0,16,0V168h48a8,8,0,0,0,0-16Zm-112,0V104h48v48Z"></path></svg>-->
|
|
||||||
{tag.data.name} <span class="blob">{tag.data.postCount}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../../styles/vars.scss";
|
|
||||||
|
|
||||||
.blob {
|
|
||||||
margin-left: 8px;
|
|
||||||
|
|
||||||
min-width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: $font-mono;
|
|
||||||
|
|
||||||
border-radius: 9999px;
|
|
||||||
background-color: $accent;
|
|
||||||
color: $light;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,27 +0,0 @@
|
||||||
.banner {
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
box-shadow: 0 8px 8px rgba(#000, 0.3);
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 0 20px;
|
|
||||||
|
|
||||||
width: max-content;
|
|
||||||
height: 35px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
border-radius: 9999px;
|
|
||||||
border: 0 solid transparent;
|
|
||||||
background-color: rgba(vars.$light, 0.04);
|
|
||||||
color: vars.$light;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: "";
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
border-radius: 9999px;
|
|
||||||
background-color: rgba(vars.$accent, 0.13);
|
|
||||||
|
|
||||||
opacity: 0;
|
|
||||||
transform: scaleX(0%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 0 solid transparent;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scaleX(100%);
|
|
||||||
transition:
|
|
||||||
opacity 0.5s cubic-bezier(0, 1, 0, 1),
|
|
||||||
transform 0.5s cubic-bezier(0, 1, 0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
.certificate {
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
border-radius: vars.$radius;
|
|
||||||
border: 2px solid vars.$gray;
|
|
||||||
background-color: vars.$dark;
|
|
||||||
color: vars.$light;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
> svg {
|
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: -37px;
|
|
||||||
left: -25px;
|
|
||||||
|
|
||||||
opacity: 0.03;
|
|
||||||
z-index: +1;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
z-index: +2;
|
|
||||||
|
|
||||||
> hr {
|
|
||||||
margin: calc(16px - 4px) 0;
|
|
||||||
|
|
||||||
border: 0 solid transparent;
|
|
||||||
border-bottom: 2px solid vars.$gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .pill-list {
|
|
||||||
margin-top: 4px;
|
|
||||||
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .button {
|
|
||||||
margin-top: 4px;
|
|
||||||
padding: 0 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
.header {
|
|
||||||
margin: -32px -32px 32px;
|
|
||||||
padding: 32px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
border-bottom: 2px solid vars.$gray;
|
|
||||||
background-color: vars.$dark;
|
|
||||||
|
|
||||||
z-index: 999;
|
|
||||||
|
|
||||||
> h1 {
|
|
||||||
margin-bottom: calc((16px - 4px) * -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.sticky {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-follow {
|
|
||||||
margin: calc(-32px - 50px + 2px) 0 0;
|
|
||||||
height: 0;
|
|
||||||
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
padding: 0 32px;
|
|
||||||
|
|
||||||
width: calc(100% + 64px);
|
|
||||||
height: 50px;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
left: -32px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
border-bottom: 2px solid vars.$gray;
|
|
||||||
background-color: vars.$dark;
|
|
||||||
color: vars.$light;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
main {
|
|
||||||
margin: 200px auto 0;
|
|
||||||
padding: 32px;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
max-width: 800px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
border-top-left-radius: vars.$radius;
|
|
||||||
border-top-right-radius: vars.$radius;
|
|
||||||
border: 2px solid vars.$gray;
|
|
||||||
border-bottom: 0 solid transparent;
|
|
||||||
background-color: vars.$dark;
|
|
||||||
|
|
||||||
box-shadow: 0 8px 8px rgba(#000, 0.3);
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
> h1 {
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> hr {
|
|
||||||
margin: 32px 0;
|
|
||||||
|
|
||||||
border: 0 solid transparent;
|
|
||||||
border-bottom: 2px solid vars.$gray;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
#music {
|
|
||||||
padding: 20px;
|
|
||||||
|
|
||||||
width: unset;
|
|
||||||
height: unset;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: unset;
|
|
||||||
align-items: unset;
|
|
||||||
|
|
||||||
text-decoration: none;
|
|
||||||
font-size: 16px;
|
|
||||||
|
|
||||||
border-radius: vars.$radius;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-radius: vars.$radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
.music-bg {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
filter: blur(1px) saturate(110%);
|
|
||||||
mask-image: linear-gradient(to right, rgba(#fff, 0.4), rgba(#fff, 0));
|
|
||||||
|
|
||||||
object-fit: cover;
|
|
||||||
z-index: +1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.music-cover {
|
|
||||||
margin-right: 4px;
|
|
||||||
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
|
|
||||||
border-radius: vars.$radius;
|
|
||||||
|
|
||||||
object-fit: cover;
|
|
||||||
z-index: +2;
|
|
||||||
}
|
|
||||||
|
|
||||||
> ul {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
z-index: +2;
|
|
||||||
|
|
||||||
> li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 500px) {
|
|
||||||
#music {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
.pill {
|
|
||||||
padding: 0 10px;
|
|
||||||
|
|
||||||
width: max-content;
|
|
||||||
height: 30px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
border-radius: 99999px;
|
|
||||||
border: 2px solid rgba(vars.$light, 0.04);
|
|
||||||
background-color: vars.$dark;
|
|
||||||
color: vars.$light;
|
|
||||||
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.large {
|
|
||||||
padding: 0 16px;
|
|
||||||
height: 40px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.size-button {
|
|
||||||
padding: 0 20px;
|
|
||||||
height: 35px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If its a clickable element
|
|
||||||
a.pill,
|
|
||||||
button.pill {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus-visible {
|
|
||||||
border: 2px solid vars.$accent;
|
|
||||||
background-color: rgba(vars.$accent, 0.1);
|
|
||||||
outline: 0 solid transparent;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
.pill-list {
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
.project-list {
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
scrollbar-color: vars.$accent transparent;
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 8px;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: vars.$accent;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: vars.$accent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
min-height: 100vh;
|
|
||||||
|
|
||||||
font-size: 100%;
|
|
||||||
font-family: vars.$font-regular;
|
|
||||||
font-weight: 420;
|
|
||||||
line-height: 1.5;
|
|
||||||
|
|
||||||
text-size-adjust: none;
|
|
||||||
-webkit-text-size-adjust: none;
|
|
||||||
-moz-text-size-adjust: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
padding: 0 16px;
|
|
||||||
|
|
||||||
min-height: 100vh;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
background-color: #261f1b;
|
|
||||||
color: vars.$light;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul[role="list"],
|
|
||||||
ol[role="list"] {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
code *,
|
|
||||||
pre * {
|
|
||||||
font-family: vars.$font-mono !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
img,
|
|
||||||
picture {
|
|
||||||
max-width: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
.section {
|
|
||||||
padding-bottom: 32px;
|
|
||||||
|
|
||||||
> h2 {
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> p {
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> img {
|
|
||||||
border-radius: vars.$radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-of-type {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
@use "vars";
|
|
||||||
|
|
||||||
@use "reset";
|
|
||||||
@use "main";
|
|
||||||
@use "banner";
|
|
||||||
@use "header";
|
|
||||||
@use "section";
|
|
||||||
@use "button";
|
|
||||||
@use "pill";
|
|
||||||
@use "pill_list";
|
|
||||||
@use "project_list";
|
|
||||||
@use "music";
|
|
||||||
@use "certificate";
|
|
|
@ -1,9 +0,0 @@
|
||||||
$dark: #312620;
|
|
||||||
$gray: #382e28;
|
|
||||||
$light: #f0e9e4;
|
|
||||||
$accent: #a86338;
|
|
||||||
|
|
||||||
$radius: 4px;
|
|
||||||
|
|
||||||
$font-regular: "General Sans", sans-serif;
|
|
||||||
$font-mono: "JetBrains Mono", sans-serif;
|
|
62
src/utils.ts
|
@ -1,62 +0,0 @@
|
||||||
import {
|
|
||||||
type CollectionEntry,
|
|
||||||
type ContentEntryMap,
|
|
||||||
getCollection,
|
|
||||||
} from "astro:content";
|
|
||||||
|
|
||||||
// https://github.com/hellotham/hello-astro/blob/e05706cf488bcec6e4c5494a622eedfc4e47d763/src/config.ts#L55C1-L62C2
|
|
||||||
export async function getPosts(collection: keyof ContentEntryMap) {
|
|
||||||
const posts = await getCollection(collection, ({ data }) => {
|
|
||||||
return data.draft !== true;
|
|
||||||
});
|
|
||||||
return posts.sort((a, b) =>
|
|
||||||
a.data.pubDate && b.data.pubDate
|
|
||||||
? Number(b.data.pubDate) - Number(a.data.pubDate)
|
|
||||||
: 0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMonth(date: Date): string {
|
|
||||||
const months = [
|
|
||||||
"January",
|
|
||||||
"February",
|
|
||||||
"March",
|
|
||||||
"April",
|
|
||||||
"May",
|
|
||||||
"June",
|
|
||||||
"July",
|
|
||||||
"August",
|
|
||||||
"September",
|
|
||||||
"October",
|
|
||||||
"November",
|
|
||||||
"December",
|
|
||||||
];
|
|
||||||
|
|
||||||
return months[date.getMonth()];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDaySuffix(date: Date): string {
|
|
||||||
let suffix = "th";
|
|
||||||
if (date.getDate() % 10 === 1 && date.getDate() !== 11) {
|
|
||||||
suffix = "st";
|
|
||||||
} else if (date.getDate() % 10 === 2 && date.getDate() !== 12) {
|
|
||||||
suffix = "nd";
|
|
||||||
} else if (date.getDate() % 10 === 3 && date.getDate() !== 13) {
|
|
||||||
suffix = "rd";
|
|
||||||
}
|
|
||||||
|
|
||||||
return suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getTagsBySlug(
|
|
||||||
postTags: string[],
|
|
||||||
): Promise<CollectionEntry<"tags">[]> {
|
|
||||||
const allTags: CollectionEntry<"tags">[] = await getCollection("tags");
|
|
||||||
const tags: CollectionEntry<"tags">[] = [];
|
|
||||||
postTags.forEach((postTag) => {
|
|
||||||
allTags.forEach((allTag) => {
|
|
||||||
if (allTag.slug === postTag) tags.push(allTag);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return tags;
|
|
||||||
}
|
|
1174
syntax-theme.json
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "astro/tsconfigs/strict"
|
|
||||||
}
|
|