Compare commits

...

26 Commits

Author SHA1 Message Date
582051ba20 Add recent albums section at index 2025-11-22 17:53:09 +13:00
a25500bb91 Removed swiper from album section 2025-11-22 17:19:22 +13:00
c3e05b44ea removed photos page... scary 2025-11-22 16:54:17 +13:00
b4f8a42e05 Disabled about page, enabled photos nav buttons, other fluff 2025-11-22 16:17:04 +13:00
ff486c01e3 Added album remarks, lazy loading images 2025-11-22 16:03:50 +13:00
33ead9d968 refactor 2025-11-22 15:28:17 +13:00
20f8b38c8a Add detail page for album 2025-11-22 15:18:57 +13:00
7f0b65fa20 makin an albums page :3 2025-11-22 15:03:49 +13:00
2fdaf64b47 removed paragraph from index 2025-11-20 11:18:20 +13:00
4bad9e095e Add field for film used in photos 2025-11-19 23:02:40 +13:00
facb2b0f99 update post info to use border separators 2025-11-19 12:14:31 +13:00
ef0c8dd981 Add spacing between Now entries 2025-11-19 11:55:58 +13:00
32b9a29028 Add header/metadata fields 2025-11-19 11:48:29 +13:00
1da77d6074 Add last updated section to now page 2025-11-18 19:21:48 +13:00
64ecc338be Add now page! 2025-11-18 18:39:10 +13:00
66623a64b4 increase thumbnail size 2025-11-18 17:11:48 +13:00
6997e313e6 redesigned H1, i should try get away from tailwind... 2025-11-18 15:44:43 +13:00
435ca0f2d7 h1-3 font sizes 2025-11-18 15:31:47 +13:00
3e742ba952 Improve TOC handling 2025-11-18 15:28:51 +13:00
caad696191 add post link 2025-11-18 15:18:10 +13:00
51419e4c7c yeah :) 2025-11-18 15:16:20 +13:00
4310c90f48 reaallly not sure on some of this stuff now huh 2025-11-18 15:13:46 +13:00
3378844823 Add recent posts section to index 2025-11-18 14:53:10 +13:00
02c7e2f45a increased size of photos on mobile 2025-11-18 14:23:32 +13:00
f0d58a1a33 even more improve 2025-11-18 14:19:17 +13:00
a37955cbec Greatly improve postCard design 2025-11-18 14:15:05 +13:00
20 changed files with 341 additions and 67 deletions

View File

@@ -0,0 +1,18 @@
---
import { authPB } from "@utils/pocketbase"
const { a } = Astro.props
const pb = await authPB()
---
<div class="swiper-slide flex flex-col md:flex-row items-center justify-center">
<a class="b1-no-underline" href={`/albums/${encodeURI(a.title)}`}>
<h1 class="text-center pb-0 md:flex-1">{a.title}</h1>
<p class="text-center">{a.date}</p>
<img
src={pb.files.getURL(a, a.images[0])}
class="w-full h-full object-contain"
loading="lazy"
alt={a.title}
/>
</a>
</div>

View File

@@ -12,10 +12,14 @@ const links = [
txt: "email",
lnk: "mailto:contact@breadone.net"
},
{
txt: "copyright",
lnk: "/copyright"
}
// {
// txt: "about",
// lnk: "/about"
// },
// {
// txt: "copyright",
// lnk: "/copyright"
// }
]
---

View File

@@ -4,9 +4,13 @@ const links = [
txt: 'now',
lnk: '/now'
},
// {
// txt: 'photos',
// lnk: '/photos'
// },
{
txt: 'photos',
lnk: '/photos'
txt: 'albums',
lnk: '/albums'
},
{
txt: 'posts',

View File

@@ -0,0 +1,36 @@
---
import SummaryCard from "./summaryCard.astro";
import { authPB } from "@utils/pocketbase";
import { getFormattedDate } from "@utils/date";
const pb = await authPB()
const albums = await pb.collection('albums').getList(1, 3, {
sort: '-created',
})
const postImages = await Promise.all( albums.items.map(a => pb.files.getURL(a, a.images[0])) )
---
<SummaryCard
title="Recent Albums",
titleLink="/albums"
>
<div class="flex flex-col md:flex-row gap-4 md:gap-4">
{
albums.items.map((p, i) => (
<div class="flex md:flex-col flex-row gap-3 md:gap-2 flex-1">
<a href={`/albums/${encodeURI(p.title)}`} class="shrink-0">
<img class="w-24 h-24 md:w-full md:h-48 object-cover rounded-sm" src={postImages[i]} alt={p.title}/>
</a>
<div class="flex flex-col justify-start md:justify-start">
<a href={`/albums/${encodeURI(p.title)}`} class="b1-no-underline line-clamp-2 md:line-clamp-none">
{p.title}
</a>
</div>
</div>
))
}
</div>
</SummaryCard>

View File

@@ -0,0 +1,39 @@
---
import SummaryCard from "./summaryCard.astro";
import { authPB } from "@utils/pocketbase";
import { getFormattedDate } from "@utils/date";
const pb = await authPB()
const posts = await pb.collection('posts').getList(1, 3, {
sort: '-publishDate',
filter: 'published=true',
})
const postImages = await Promise.all( posts.items.map(p => pb.files.getURL(p, p.headerImage)) )
---
<SummaryCard
title="Recent Posts",
titleLink="/posts"
>
<div class="flex flex-col md:flex-row gap-4 md:gap-4">
{
posts.items.map((p, i) => (
<div class="flex md:flex-col flex-row gap-3 md:gap-2 flex-1">
<time class="hidden md:block text-sm text-gray-500" datetime={p.publishDate}>{getFormattedDate(p.publishDate)}</time>
<a href={`/posts/${p.slug}`} class="shrink-0">
<img class="w-24 h-24 md:w-full md:h-48 object-cover rounded-sm" src={postImages[i]} alt={p.title}/>
</a>
<div class="flex flex-col justify-start md:justify-start">
<a href={`/posts/${p.slug}`} class="b1-no-underline line-clamp-2 md:line-clamp-none">
{p.title}
</a>
<time class="md:hidden text-sm text-gray-500" datetime={p.publishDate}>{getFormattedDate(p.publishDate)}</time>
</div>
</div>
))
}
</div>
</SummaryCard>

View File

@@ -0,0 +1,14 @@
---
const { title, titleLink } = Astro.props
---
<div>
<a href={titleLink} rel="prefetch" class="b1-no-underline">
<h2 class="text-xl">{title}</h2>
</a>
<div class="flex flex-row gap-2">
<slot/>
</div>
</div>

View File

@@ -5,11 +5,12 @@ import { authPB } from "src/utils/pocketbase";
const pb = await authPB()
const photos = await pb.collection('photos').getFullList({
sort: '-created'
sort: '-created',
filter: 'published=true'
})
const photoLinks = await Promise.all(
photos.map(p => pb.files.getURL(p, p.image))
photos.map(p => pb.files.getURL(p, p.image, { thumb: '0x1800' }))
)
---
@@ -25,6 +26,7 @@ const photoLinks = await Promise.all(
const photoLinks = photoLinksElement ? JSON.parse(photoLinksElement.textContent || '[]') : [];
const titleEl = document.getElementById('photo-title');
const cameraEl = document.getElementById('photo-camera');
const filmEl = document.getElementById('photo-film');
const locationEl = document.getElementById('photo-location');
const currentPosIndicator = document.getElementById('current-pos');
const maxPosIndicator = document.getElementById('max-pos');
@@ -36,18 +38,10 @@ const photoLinks = await Promise.all(
currentPosIndicator.innerText = '1';
}
function preloadImages() {
photoLinks.forEach((url: string) => {
const preloadImg = new Image();
preloadImg.src = url;
});
}
// Call preload on page load
preloadImages();
const swiper = new Swiper('.swiper', {
modules: [Navigation, Keyboard, EffectFade],
spaceBetween: 20,
effect: 'cards',
fadeEffect: {
crossFade: true
@@ -77,6 +71,9 @@ const photoLinks = await Promise.all(
if (cameraEl && currentPhoto) {
cameraEl.textContent = `📸 ${currentPhoto.camera}`;
}
if (filmEl && currentPhoto) {
filmEl.textContent = currentPhoto.film !== "" ? `🎞️ ${currentPhoto.film}` : "";
}
if (locationEl && currentPhoto) {
locationEl.textContent = `📌 ${currentPhoto.location}`;
}
@@ -89,13 +86,14 @@ const photoLinks = await Promise.all(
<div class="hidden" id="carousel-data">{JSON.stringify(photos)}</div>
<div class="hidden" id="photo-links-data">{JSON.stringify(photoLinks)}</div>
<div class="swiper w-full h-[60vh] md:h-[calc(100vh-7rem)]">
<div class="swiper w-full h-[70vh] md:h-[calc(100vh-7rem)]">
<div class="swiper-wrapper">
{photos.map((photo, i) => (
<div class="swiper-slide flex items-center justify-center">
<img
src={photoLinks[i]}
class="w-full h-full object-contain"
loading="lazy"
alt={photo.title || 'Photo'}
/>
</div>

View File

@@ -3,15 +3,23 @@ import { getFormattedDate } from '@utils/date'
const { publishDate, wordCount, readTime, tags } = Astro.props
---
<time datetime={publishDate}>{getFormattedDate(publishDate)}</time> |
<span title={`${wordCount} words`}>{readTime} min. read</span> |
{
tags.map((tag, i) => (
<>
<a class="b1-no-underline" href={`/posts/tag/${tag}/`}>
#{tag}
</a>
{i < tags.length - 1 && ", "}
</>
))
}
<div class="flex flex-row gap-1">
<time datetime={publishDate}>{getFormattedDate(publishDate)}</time>
<span class="tag-separator"/>
<span title={`${wordCount} words`}>{readTime} min. read</span>
<span class="tag-separator"/>
{
tags.map((tag, i) => (
<>
<a class="b1-no-underline" href={`/posts/tag/${tag}/`}>
#{tag}
</a>
{i < tags.length - 1 && ", "}
</>
))
}
</div>

View File

@@ -38,14 +38,11 @@
}
// get all titles in the page
const titles = document.querySelectorAll('h2, h3')
const titles = document.querySelectorAll('h1, h2, h3')
const toc = document.getElementById('toc') as Element
const toc_cnt = document.getElementById('toc-container') as Element
console.log(titles)
// if there's more than two titles (ie, there's more than just the article title and TOC title, then appropriate to show)
if (titles.length > 2) {
if (titles.length > 0) {
toc_cnt.classList.add('lg:block')
}
@@ -54,19 +51,7 @@
// Assign IDs in case they haven't been (by me)
t.id = t.innerHTML
let depth = 1
// determine what depth to use
switch (t.tagName) {
case 'H2':
depth = 1
break
case 'H3':
depth = 2
break
}
let depth = t.tagName.substring(1) as number
addLink(t, depth)
}
</script>

View File

@@ -1,27 +1,40 @@
---
import { getFormattedDate } from "@utils/date"
import { calcReadTime } from "@utils/post"
import { authPB } from "@utils/pocketbase"
import PostInfo from "@components/post/postInfo"
const pb = await authPB()
const { p } = Astro.props
const wordCount = p.content.split(' ').length;
const readTime = calcReadTime(wordCount);
---
<div class="mb-8 pb-4 md:pb-8 border-b border-gray-200 last:border-b-0 flex flex-col md:flex-row gap-4 md:gap-3">
<div class="mb-8 pb-7 md:pb-8 border-b border-gray-200 last:border-b-0 flex flex-col md:flex-row gap-4 md:gap-3">
<!-- Text content on left -->
<div class="flex-1 flex flex-col justify-start order-2 md:order-1">
<time datetime={p.publishDate} class="text-sm text-gray-500">{getFormattedDate(p.publishDate)}</time>
<a href={`/posts/${p.slug}/`} rel="prefetch" class="no-underline hover:underline">
<h2 class="text-xl font-bold ">{p.title}</h2>
<h2 class="text-xl ">{p.title}</h2>
</a>
{
p.description !== "" &&
<q class="line-clamp-3 block italic text-gray-700">{p['description']}</q>
<p class="line-clamp-3 block italic text-gray-600">{p.description}</p>
}
<PostInfo
publishDate={p.publishDate},
wordCount={wordCount},
readTime={readTime},
tags={p.tags}
/>
</div>
<!-- Image on right -->
<div class="md:w-80 order-1 md:order-2">
<div class="md:max-w-1/2 order-1 md:order-2">
<a href={`/posts/${p.slug}/`} rel="prefetch">
<img src={ pb.files.getURL(p, p.headerImage) } class="rounded-sm w-full h-48 md:h-full object-cover" alt={p['title']}/>
</a>

View File

@@ -3,11 +3,27 @@ import BaseHead from "./BaseHead.astro"
import Sidebar from "@components/sidebar"
import Navbar from "@components/index/navbar"
import Footer from "@components/footer"
const {
meta = {}
} = Astro.props;
const {
title = "",
description = "",
ogImage = "",
articleDate = ""
} = meta;
---
<html>
<head>
<BaseHead/>
<BaseHead
title={title}
description={description}
ogImage={ogImage}
articleDate={articleDate}
/>
</head>

View File

@@ -0,0 +1,27 @@
---
import Base from "@layout/Base";
import { authPB } from "@utils/pocketbase";
export const prerender = false
const { title } = Astro.params
const pb = await authPB()
const album = await pb.collection('albums').getFirstListItem(`title ~ "${decodeURI(title!)}"`)
const images = await Promise.all(
album.images.map(i => pb.files.getURL(album, i))
)
---
<Base meta={{title: "album", description: album.title, ogImage: images[0]}}>
<div slot="sidebar">
<h1>{album.title}</h1>
<p>{album.date}</p>
<p>{album.location}</p><br>
<Fragment set:html={album.remarks}/>
</div>
<div slot="content">
{ images.map(img => <img class="pb-2" src={img}/> ) }
</div>
</Base>

View File

@@ -0,0 +1,49 @@
---
import Base from "@layout/Base";
import { authPB } from "@utils/pocketbase";
import AlbumCard from "@components/albums/albumCard";
export const prerender = false
const pb = await authPB()
const albums = await pb.collection('albums').getFullList({
sort: '-created'
})
---
<script>
import Swiper from "swiper";
import { Keyboard } from 'swiper/modules';
import 'swiper/css';
const s = new Swiper('.swiper-album', {
modules: [Keyboard],
slidesPerView: 1,
spaceBetween: 0,
speed: 400,
loop: true,
keyboard: {
enabled: true,
onlyInViewport: false,
}
}
)
</script>
<Base meta={{title: "albums"}}>
<div slot="sidebar">
<p class="text-left"> More focused, themed collections of photos compared to the more miscellaneous images of the (now defunct) <a href="/photos">photos page.</a> Best viewed on a large screen!</p>
<!-- <br>
← / → -->
</div>
<div slot="content">
<div class=" w-full">
<div class="">
{ albums.map(a => <AlbumCard a={a}/> ) }
</div>
</div>
</div>
</Base>

View File

@@ -3,7 +3,7 @@ import Base from "src/layout/Base.astro"
import Sidebar from "src/components/sidebar.astro"
---
<Base>
<Base meta={{title: "copyright"}}>
<div slot="content">
<p class="text-xl">Copyright & License</p>

View File

@@ -1,13 +1,25 @@
---
import Base from "src/layout/Base.astro"
import RecentPosts from "@components/index/recentPosts"
import RecentAlbums from "@components/index/recentAlbums"
export const prerender = false
---
<Base>
<div slot="sidebar">
sidebar stuff
<div slot="sidebar" class="text-left">
<p>New website new me!</p> <br>
<p>This is the third major iteration of the website, and by far the most flexible and best designed (imo!)</p><br>
<p>I'm... really not sure what else to put on this landing page, make sure to check out some of the photos and posts I've added recently, I've been totally revamping those too and I'm really proud of this batch.</p><br>
<p>Hope you enjoy your time here :)</p>
</div>
<div slot="content">
ya
<div slot="content" class="md:py-10 space-y-4">
<RecentAlbums/>
<RecentPosts/>
</div>
</Base>

37
web/src/pages/now.astro Normal file
View File

@@ -0,0 +1,37 @@
---
import Base from "@layout/Base";
import { authPB } from "@utils/pocketbase";
import { getFormattedDate } from '@utils/date'
export const prerender = false
const pb = await authPB()
const records = await pb.collection('now').getFullList({
sort: '-updated'
})
const lastUpdated = getFormattedDate(records[0].updated)
---
<Base meta={{title: "now"}}>
<div slot="sidebar" class="text-left">
<h2>The Now!</h2>
<p>Trying out a <a href="https://nownownow.com/about">Now Page</a>, inspired by some other personal sites such as <a href="https://lai.nz">this great one.</a></p><br>
<p>I'll update this every now and then; the gist is "this is what you would tell someone that you haven't seem in a year, what you've been up to". Love that concept!</p>
</div>
<div slot="content" class="">
<p class="mb-1 md:mt-5 italic ">Last Updated: {lastUpdated}</p>
{
records.map(r => (
<div class="mb-3">
<h3>{r.heading}</h3>
<Fragment set:html={r.content}/>
</div>
))
}
</div>
</Base>

View File

@@ -11,15 +11,16 @@ const photos = await pb.collection('photos').getFullList({
})
---
<Base>
<Base meta={{title: "photos"}}>
<div slot="sidebar">
<p id="photo-title" class="bold text-2xl">{photos[0].title === "" ? "Untitled" : photos[0].title}</p>
<p id="photo-camera" class="text-sm">📸 {photos[0].camera}</p>
<p id="photo-film" class="text-sm">{photos[0].film !== "" ? `🎞️ ${photos[0].film}` : ""}</p>
<p id="photo-location" class="text-sm">📌 {photos[0].location}</p>
<!-- <button id="dec-button" onclick="dec()">&lt;</button> -->
<button id="dec-button" onclick="dec()">&lt;</button>
<span id="current-pos" /> of <span id="max-pos" />
<!-- <button id="inc-button" onclick="inc()">&gt;</button> -->
<button id="inc-button" onclick="inc()">&gt;</button>
</div>
<div slot="content" class="">

View File

@@ -20,7 +20,7 @@ const readTime = calcReadTime(wordCount);
---
<Base>
<Base meta={{title: "post", description: title, ogImage: headerImage, articleDate: publishDate}}>
<div slot="sidebar" class="text-left">
<img src={headerImage}/>

View File

@@ -17,7 +17,7 @@ const tags = posts.flatMap(p => p.tags)
const uniqueTags = tags.filter((v, i, a) => a.indexOf(v) === i)
---
<Base>
<Base meta={{title: "posts"}}>
<div slot="sidebar" class="text-left">
A few thoughts I've had, whenever I feel like it as you can see!

View File

@@ -42,9 +42,22 @@
@apply hover:decoration-(--accent);
}
h2 {
@apply text-xl;
h1 {
font-size: 28px;
@apply py-4;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 20px;
}
}
.tag-separator {
@apply border-l border-gray-400;
}
.content-panel {