get poetry stuff workin

This commit is contained in:
2024-05-29 18:33:13 -04:00
parent 3d22344e7f
commit 251620863c
42 changed files with 632 additions and 299 deletions

View File

@@ -1,7 +1,52 @@
<script lang="ts">
import App from '$lib/components/scenes/app/App.svelte';
<script>
import '../../app.css';
</script>
<App>
<slot />
</App>
<div class="flex flex-col h-screen">
<div class="navbar bg-base-300 sticky top-0 z-50">
<div class="navbar-start">
<div class="dropdown">
<div tabindex="-1" class="btn btn-ghost lg:hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</div>
<ul
tabindex="-1"
class="menu menu-sm dropdown-content mt-3 z-10 p-2 shadow bg-base-300 rounded-box w-52"
>
<li><a href="/thoughts">Thoughts</a></li>
<li><a href="/poetry">Poetry</a></li>
<li><a href="/projects">Projects</a></li>
<li><a href="/experiments">Experiments</a></li>
<li><a href="/services">Services</a></li>
</ul>
</div>
<a class="btn btn-outline btn-primary text-xl" href="/">silentsilas</a>
</div>
<div class="navbar-end hidden lg:flex">
<ul class="menu menu-horizontal px-1">
<li><a href="/thoughts">Thoughts</a></li>
<li><a href="/poetry">Poetry</a></li>
<li><a href="/projects">Projects</a></li>
<li><a href="/experiments">Experiments</a></li>
<li><a href="/services">Services</a></li>
</ul>
</div>
</div>
<div class="flex flex-col items-center flex-1 overflow-auto">
<slot />
</div>
</div>

View File

@@ -1,23 +1,106 @@
<script lang="ts">
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
type Greeting = {
greeting: string;
language: string;
romanisation?: string;
};
const GREETINGS: Greeting[] = [
{ greeting: '你好', language: 'Mandarin', romanisation: 'Nǐ hǎo' },
{ greeting: 'नमस्ते', language: 'Hindi', romanisation: 'Namaste' },
{ greeting: 'Hola', language: 'Spanish' },
{ greeting: 'হ্যালো', language: 'Bengali', romanisation: 'Hyālō' },
{ greeting: 'ہیلو', language: 'Urdu', romanisation: 'Hello' },
{ greeting: 'Oi', language: 'Portuguese' },
{ greeting: 'Здравствуйте', language: 'Russian', romanisation: 'Zdravstvuyte' },
{ greeting: 'こんにちは', language: 'Japanese', romanisation: "Kon'nichiwa" },
{ greeting: 'Merhaba', language: 'Turkish' },
{ greeting: '안녕하세요', language: 'Korean', romanisation: 'Annyeonghaseyo' },
{ greeting: 'Hallo', language: 'German' },
{ greeting: 'สวัสดี', language: 'Thai', romanisation: 'S̄wạs̄dī' },
{ greeting: 'مرحبا', language: 'Arabic', romanisation: 'Marhaba' },
{ greeting: 'היי', language: 'Hebrew', romanisation: 'Hi' },
{ greeting: 'Helo', language: 'Welsh' },
{ greeting: 'Pozdrav', language: 'Croatian' },
{ greeting: 'Hej', language: 'Swedish' },
{ greeting: 'Hyālō', language: 'Bengali' },
{ greeting: 'Salut', language: 'French' },
{ greeting: 'Ciao', language: 'Italian' }
];
let greetings = [...GREETINGS];
let currentGreeting: Greeting = { greeting: 'Hello', language: 'English' };
let visible = false;
onMount(() => {
visible = true;
const interval = setInterval(getRandomGreeting, 3000);
return () => clearInterval(interval);
});
async function getRandomGreeting() {
visible = false;
await new Promise((r) => setTimeout(r, 1000));
if (greetings.length === 0) {
greetings = [...GREETINGS];
}
const greetingIndex = Math.floor(Math.random() * greetings.length);
const greeting = greetings[greetingIndex];
greetings = greetings.filter((_, index) => index !== greetingIndex);
currentGreeting = greeting;
visible = true;
return greeting;
}
</script>
<MenuItem position={[-2.5, 7.5, 0]} htmlContent="Poetry" href="/poetry" />
<MenuItem
position={[2.5, 2.5, -2.5]}
htmlContent="Projects"
clickHandler={() => console.log('clicked!')}
/>
<MenuItem
position={[-2.5, -2.5, -2.5]}
htmlContent="Thoughts"
clickHandler={() => console.log('clicked!')}
/>
<MenuItem
position={[2.5, -7.5, 2.5]}
htmlContent="About"
clickHandler={() => console.log('clicked!')}
/>
<div class="container mx-auto flex flex-col justify-center items-center flex-1">
<div class="justify-center items-center text-center m-10">
{#if visible && currentGreeting}
<div
transition:fade={{ duration: 1200 }}
>
<span class="font-bold">{currentGreeting.greeting}</span>
{#if currentGreeting.romanisation}
<span class="text-gray-500">( {currentGreeting.romanisation} )</span>
{/if}
</div>
<p class="mt-2 text-gray-700" transition:fade={{ delay: 400, duration: 400 }}>
That's {currentGreeting.language} for hello!
</p>
{/if}
</div>
<div class="text-center prose px-4">
<p>
The name's Silas. I write code for a living, and sometimes for fun. I use <a
href="https://elixir-lang.org/"
target="_blank">Elixir</a
>
at my day job, and recently have been messing around with
<a href="https://elixir-lang.org/" target="_blank">Rust</a>,
<a href="https://kit.svelte.dev/" target="_blank">Svelte</a>, and
<a href="https://threejs.org/" target="_blank">three.js</a>
</p>
<p>
Here you can browse my shower <a href="/thoughts" class="link">thoughts</a> and bad
<a href="/poetry" class="link">poetry</a>. Opinions are personally mine and not endorsed by my
employer.
</p>
<p>
I tend to start a lot of <a href="/projects" class="link">projects</a>, but I'm trying to
finish more. I also like to toy with weird web technologies and will host the
<a href="/experiments" class="link">experiments</a> here.
</p>
<p>
I self-host a lot of <a href="/services" class="link">services</a> I find useful. None of them
run any analytics or log your activity, but the software/servers may be outdated, so use at your
own risk.
</p>
<p>Shalom.</p>
</div>
</div>

View File

@@ -0,0 +1,15 @@
export const load = async ({ fetch, url }) => {
const limit = 8;
const page = Number(url.searchParams.get('page')) || 1;
const response = await fetch(`/api/poetry?limit=${limit}&page=${page}`);
const { posts, total } = await response.json();
return {
posts,
total,
page,
limit
};
};

View File

@@ -1,39 +1,70 @@
<script lang="ts">
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
import type { PageData } from './$types';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import type { PageData } from '../poetry/$types';
export let data: PageData;
const xMin = -2.5,
xMax = 2.5;
const yMin = -7.5,
yMax = 7.5;
const zMin = -2.5,
zMax = 2.5;
// Calculate positions
const calculatePositions = (numPosts: number): Array<[number, number, number]> => {
const positions: Array<[number, number, number]> = [];
const numRows = Math.ceil(Math.sqrt(numPosts));
const numCols = Math.ceil(numPosts / numRows);
for (let i = 0; i < numPosts; i++) {
const row = Math.floor(i / numCols);
const col = i % numCols;
const x = xMin + (xMax - xMin) * (col / (numCols - 1));
const y = yMin + (yMax - yMin) * (row / (numRows - 1));
const z = zMin;
positions.push([x, y, z]);
}
return positions;
const formatDate = (date: string) => {
return new Date(date).toLocaleDateString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric'
});
};
// Generate positions based on the number of posts
const positions = calculatePositions(data.posts.length);
let { posts, total } = data;
const limit = 8;
let currentPage = Number($page.url.searchParams.get('page')) || 1;
let totalPages = Math.ceil(total / limit);
$: $page.url.searchParams.get('page'),
(currentPage = Number($page.url.searchParams.get('page')) || 1);
async function fetchData(page: number) {
const response = await fetch(`/api/poetry?limit=${limit}&page=${page}`);
const newData = await response.json();
currentPage = page;
posts = newData.posts;
total = newData.total;
totalPages = Math.ceil(total / limit);
}
function navigate(page: number) {
fetchData(page);
goto(`/poetry/?page=${page}`, { replaceState: true });
}
</script>
{#each data.posts as post, i}
<MenuItem position={positions[i]} htmlContent={post.meta.title} href={post.path} />
{/each}
<div class="container mx-auto flex flex-col items-center py-10">
<div class="prose">
<h1 class="py-6">Poetry</h1>
</div>
<ul>
{#each posts as post}
<li class="py-4">
<h3 class="pb-1">
<a class="link" href={post.path}>
{post.meta.title}
</a>
</h3>
<p class="text-sm">{formatDate(post.meta.date)}</p>
</li>
{/each}
</ul>
</div>
{#if total > 1}
<nav class="join justify-end">
<button
class="join-item btn-primary btn btn-outline"
on:click={() => navigate(currentPage - 1)}
disabled={currentPage === 1}>Prev</button
>
<button class="join-item btn btn-outline">{currentPage} of {totalPages}</button>
<button
class="join-item btn btn-primary btn-outline"
on:click={() => navigate(currentPage + 1)}
disabled={currentPage === totalPages}>Next</button
>
</nav>
{/if}

View File

@@ -1,19 +1,16 @@
<script lang="ts">
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
import type { PageData } from './$types';
import DomPortal from '$lib/utils/DomPortal.svelte';
export let data: PageData;
const { title, date: _date, Content, categories: _ } = data;
</script>
<MenuItem position={[-2.5, 10, 0]} htmlContent="Back" href="/poetry" />
<DomPortal target="#overlay">
<div class="py-4">
<h1 class="text-xl font-medium text-black pb-2">{title}</h1>
<div>
<Content />
</div>
<div class="container mx-auto flex flex-col items-center py-10">
<div class="prose">
<h1 class="py-6">{title}</h1>
</div>
</DomPortal>
<div class="prose">
<Content />
</div>
<a href="/poetry" class="link mt-10">Back to Poetry</a>
</div>

View File

@@ -13,6 +13,7 @@ export async function load({ params }) {
Content,
title,
date: validDate,
categories
categories,
post
};
}

View File

@@ -1,38 +1 @@
<script lang="ts">
import CanvasContainer from '$lib/components/scenes/app/CanvasContainer.svelte';
import '../app.css';
</script>
<CanvasContainer>
<slot />
</CanvasContainer>
<div class="overlay container" id="overlay"></div>
<style>
:global(body) {
margin: 0;
}
.canvas {
width: 100%;
height: 100%;
background: rgb(0, 36, 6);
background: linear-gradient(180deg, rgba(0, 36, 6, 1) 0%, rgba(0, 0, 0, 1) 100%);
position: absolute;
justify-content: center;
align-items: center;
}
.overlay {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(16, 56, 30, 0.9);
}
</style>
<slot />

View File

@@ -1,2 +1,2 @@
export const prerender = true
export const ssr = false
export const ssr = true

View File

@@ -2,13 +2,14 @@ import { fetchMarkdownPosts } from '$lib/utils';
import { json } from '@sveltejs/kit';
export const GET = async ({ url }) => {
const limit = Number(url.searchParams.get('limit')) || 6;
const offset = Number(url.searchParams.get('offset')) || 0;
const allPosts = await fetchMarkdownPosts('poetry', limit, offset);
const page = Number(url.searchParams.get('page')) || 1;
const limit = Number(url.searchParams.get('limit')) || 8;
const offset = (page - 1) * limit;
const {posts: allPosts, total: total} = await fetchMarkdownPosts('poetry', limit, offset);
const sortedPosts = allPosts.sort((a, b) => {
return new Date(b.meta.date).getTime() - new Date(a.meta.date).getTime();
});
return json(sortedPosts);
return json({posts: sortedPosts, total: total, page: page});
};

View File

@@ -0,0 +1,42 @@
<script lang="ts">
import App from '$lib/components/scenes/app/App.svelte';
import CanvasContainer from '$lib/components/scenes/app/CanvasContainer.svelte';
import '../../app.css'
</script>
<CanvasContainer>
<App>
<slot />
</App>
</CanvasContainer>
<div class="overlay container" id="overlay"></div>
<style>
:global(body) {
margin: 0;
}
.canvas {
width: 100%;
height: 100%;
background: rgb(0, 36, 6);
background: linear-gradient(180deg, rgba(0, 36, 6, 1) 0%, rgba(0, 0, 0, 1) 100%);
position: absolute;
justify-content: center;
align-items: center;
}
.overlay {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(16, 56, 30, 0.9);
}
</style>

View File

@@ -0,0 +1,2 @@
export const prerender = true
export const ssr = false

View File

@@ -0,0 +1,37 @@
<script lang="ts">
import MenuItem from '$lib/components/scenes/app/MenuItem.svelte';
import type { PageData } from './$types';
export let data: PageData;
const xMin = -2.5,
xMax = 2.5;
const yMin = -7.5,
yMax = 7.5;
const zMin = -2.5,
zMax = 2.5;
const calculatePositions = (numPosts: number): Array<[number, number, number]> => {
const positions: Array<[number, number, number]> = [];
const numRows = Math.ceil(Math.sqrt(numPosts));
const numCols = Math.ceil(numPosts / numRows);
for (let i = 0; i < numPosts; i++) {
const row = Math.floor(i / numCols);
const col = i % numCols;
const x = xMin + (xMax - xMin) * (col / (numCols - 1));
const y = yMin + (yMax - yMin) * (row / (numRows - 1));
const z = zMin;
positions.push([x, y, z]);
}
return positions;
};
const positions = calculatePositions(data.posts.length);
</script>
{#each data.posts as post, i}
<MenuItem position={positions[i]} htmlContent={post.meta.title} href={post.path} />
{/each}