Implement pagination, update the logo again

This commit is contained in:
Kaan Barmore-Genç 2024-05-05 23:53:42 -05:00
parent cf751dd397
commit 5e8eb94d6b
Signed by: kaan
GPG key ID: B2E280771CD62FCF
20 changed files with 217 additions and 96 deletions

View file

@ -1,7 +1,7 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"trailingComma": "all",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]

View file

@ -1,9 +1,9 @@
html {
--color-primary-h: 49;
--color-primary-s: 79%;
--color-primary-l: 53%;
--color-primary-h: 218;
--color-primary-s: 81%;
--color-primary-l: 24%;
--color-primary: hsl(var(--color-primary-h), var(--color-primary-s), var(--color-primary-l));
--color-secondary-h: 218;
--color-secondary-h: 100;
--color-secondary-s: 81%;
--color-secondary-l: 24%;
--color-secondary: hsl(
@ -59,6 +59,9 @@ html {
--z-index-modal: 100;
--clip-path: polygon(0% 0%, 75% 0%, 100% 100%, 25% 100%);
--clip-path-button: polygon(0px 0px, calc(100% - 10px) 0px, 100% 40px, 10px 40px);
background-color: var(--color-bg);
color: var(--color-text);
}
@ -104,6 +107,11 @@ svg {
max-width: 100%;
height: auto;
}
button {
background: none;
border: none;
cursor: pointer;
}
input,
button,
textarea,

37
src/lib/Button.svelte Normal file
View file

@ -0,0 +1,37 @@
<script lang="ts">
export let disabled = false;
export let href: string | undefined;
let className = '';
export { className as class };
</script>
{#if disabled}
<button class={className} disabled><slot /></button>
{:else}
<a class={className} {href}><slot /></a>
{/if}
<style>
a,
button {
display: inline-block;
color: hsl(var(--color-text-h), var(--color-text-s), calc(100% - var(--color-text-l)));
font-weight: 600;
text-decoration: none;
opacity: 0.8;
background-color: var(--color-primary);
padding: 0.5rem 1rem;
clip-path: var(--clip-path-button);
transition: all var(--animation-speed) var(--animation-type);
user-select: none;
}
button {
opacity: 0.6;
cursor: unset;
}
a:hover,
a:focus-visible {
opacity: 1;
text-decoration-color: unset;
}
</style>

5
src/params/integer.ts Normal file
View file

@ -0,0 +1,5 @@
import type { ParamMatcher } from '@sveltejs/kit';
export const match: ParamMatcher = (param) => {
return /^\d+$/.test(param);
};

View file

@ -24,16 +24,25 @@ React, SvelteKit, TailwindCSS, Rust, Docker, SQL, and AWS technologies
I'm an active contributor to the open-source world: check out
my [Github profile](https://github.com/SeriousBug)! For a closer look at my work,
visit my [portfolio](/portfolio) where I
visit my [portfolio](/portfolio/) where I
highlight my favorite projects. I sometimes write about the tools
I use or challenges I've solved on my [blog](/posts). I'm always open to feedback, reach out to me through my socials linked below.
I use or challenges I've solved on my [blog](/posts/). I'm always open to feedback, reach out to me through my socials linked below.
<div class="socials">
<a target="_blank" rel="noopener" href="mailto:kaan@bgenc.net">Email</a>
<a target="_blank" rel="noopener me" href="https://github.com/SeriousBug">Github</a>
<a target="_blank" rel="noopener me" href="https://fosstodon.org/@kaan">Mastodon</a>
<a target="_blank" rel="noopener me" href="https://www.linkedin.com/in/kaan-barmore-genc">LinkedIn</a>
<a target="_blank" rel="noopener me" href="/static/cv.pdf">CV</a>
</div>
<style>
picture {
max-width: 320px;
max-height: 320px;
margin: 0 auto;
clip-path: polygon(0% 0%, 75% 0%, 100% 100%, 25% 100%);
clip-path: var(--clip-path);
}
h1 {

View file

@ -45,12 +45,6 @@
display: flex;
flex-direction: row;
align-items: center;
opacity: 0.6;
transition: opacity var(--animation-speed) var(--animation-type);
}
.row:hover,
.row:focus-within {
opacity: 1;
}
.row > * {
flex-grow: 1;

View file

@ -1,4 +1,5 @@
<script>
import Button from '$lib/Button.svelte';
import Spacer from '$lib/Spacer.svelte';
import Avif from './logo.avif';
@ -19,13 +20,12 @@
</picture>
</a>
<Spacer />
<a href="/posts">Blog</a>
<a href="/portfolio">Portfolio</a>
<Button href="/posts/">Blog</Button>
<Button href="/portfolio/">Portfolio</Button>
</header>
<style>
header {
max-width: calc(var(--size-container) * 2);
display: flex;
flex-direction: row;
align-items: center;

View file

@ -1,5 +1,4 @@
export async function load({ params }) {
console.log('params', params);
const post = await import(`../posts/${params.slug}.md`);
const { title, date } = post.metadata;
const content = post.default;

BIN
src/routes/logo.avif (Stored with Git LFS)

Binary file not shown.

View file

@ -1,59 +0,0 @@
<script lang="ts">
import { format } from 'date-fns';
export let data;
function groupPosts(posts: any[]) {
const postsByYear = new Map<string, any[]>();
posts.forEach((post) => {
const year = format(new Date(post.meta.date), 'yyyy');
if (!postsByYear.has(year)) {
postsByYear.set(year, []);
}
postsByYear.get(year)!.push(post);
});
return postsByYear;
}
</script>
<ul class="years">
{#each groupPosts(data.posts).entries() as [year, posts]}
<li>
<h2>{year}</h2>
<ul class="posts">
{#each posts as post}
<a href={`/${post.path}`}>
<li>
<div>
{post.meta.title}
</div>
<time datetime={post.meta.date}>
{format(new Date(post.meta.date), 'MMMM d')}
</time>
</li>
</a>
{/each}
</ul>
</li>
{/each}
</ul>
<style>
time {
width: 8rem;
}
li {
list-style-type: none;
}
.years,
.posts {
display: flex;
flex-direction: column;
}
.years {
gap: 4rem;
}
.posts {
gap: 1.5rem;
}
</style>

View file

@ -0,0 +1,115 @@
<script lang="ts">
import Button from '$lib/Button.svelte';
import { format } from 'date-fns';
export let data;
function groupPosts(posts: any[]) {
const postsByYear = new Map<string, any[]>();
posts.forEach((post) => {
const year = format(new Date(post.meta.date), 'yyyy');
if (!postsByYear.has(year)) {
postsByYear.set(year, []);
}
postsByYear.get(year)!.push(post);
});
return postsByYear;
}
</script>
<ul class="years">
{#each groupPosts(data.posts).entries() as [year, posts]}
<li>
<h2>{year}</h2>
<ol class="posts">
{#each posts as post}
<a href={`/${post.path}`}>
<li>
<h5 class="post-title">
{post.meta.title}
</h5>
<time datetime={post.meta.date}>
{format(new Date(post.meta.date), 'MMMM d')}
</time>
</li>
</a>
{/each}
</ol>
</li>
{/each}
</ul>
<div class="pagination-controls">
<Button disabled={data.page < 3} href={'/posts/'}>{data.page < 3 ? '_' : data.page - 1}</Button>
<Button disabled={data.page === 1} href={data.page === 2 ? '/posts/' : `/posts/${data.page - 1}`}
>{data.page === 1 ? '_' : data.page - 1}</Button
>
<span class="current-page">{data.page}</span>
<Button disabled={!data.hasMore} href="/posts/{data.page + 1}"
>{data.hasMore ? data.page + 1 : '_'}</Button
>
<Button disabled={data.page > data.pageCount - 2} href="/posts/{data.pageCount}"
>{data.page > data.pageCount - 2 ? '_' : data.pageCount}</Button
>
</div>
<style>
time {
width: 8rem;
color: var(--color-text);
}
.pagination-controls {
display: flex;
justify-content: center;
gap: 0.2rem;
margin-top: 2rem;
}
:global(.pagination-controls > :first-child) {
margin-right: 1rem;
}
:global(.pagination-controls > :last-child) {
margin-left: 1rem;
}
.current-page {
display: inline-block;
color: hsl(var(--color-text-h), var(--color-text-s), calc(100% - var(--color-text-l)));
font-weight: 600;
text-decoration: none;
opacity: 0.6;
cursor: unset;
user-select: none;
background-color: var(--color-primary);
padding: 0.5rem 1rem;
clip-path: var(--clip-path-button);
transition: all var(--animation-speed) var(--animation-type);
}
.post-title {
margin-bottom: 0.3rem;
text-decoration: underline;
text-decoration-color: transparent;
transition: all var(--animation-speed) var(--animation-type);
}
a:hover .post-title {
text-decoration-color: unset;
}
.posts a {
text-decoration: none;
}
li {
list-style-type: none;
}
.years,
.posts {
display: flex;
flex-direction: column;
}
.years {
gap: 4rem;
}
.posts {
gap: 1.5rem;
}
</style>

View file

@ -1,6 +1,8 @@
import _ from 'lodash';
export async function load() {
const PAGE_SIZE = 10;
export async function load({ params }) {
const allPostFiles = import.meta.glob<SvelteAllProps>('/src/routes/posts/*.md');
const iterablePostFiles = Object.entries(allPostFiles);
@ -13,10 +15,21 @@ export async function load() {
return {
meta: metadata,
path: slug
path: slug,
};
})
}),
);
return { posts: _.reverse(_.sortBy(posts, ({ meta }) => meta.date)) };
// Get the page number, converting it to a 0-based index
const page = (params.page ? parseInt(params.page, 10) : 1) - 1;
return {
posts: _.reverse(_.sortBy(posts, ({ meta }) => meta.date)).slice(
page * PAGE_SIZE,
(page + 1) * PAGE_SIZE,
),
hasMore: posts.length > (page + 1) * PAGE_SIZE,
page: page + 1,
pageCount: Math.ceil(posts.length / PAGE_SIZE),
};
}

View file

@ -17,7 +17,7 @@ h6 {
font-size: 1.125rem;
}
a {
color: var(--color-secondary);
color: var(--color-primary);
font-weight: 600;
text-decoration-color: transparent;
opacity: 0.8;

BIN
static/android-chrome-192x192.png (Stored with Git LFS)

Binary file not shown.

BIN
static/android-chrome-512x512.png (Stored with Git LFS)

Binary file not shown.

BIN
static/apple-touch-icon.png (Stored with Git LFS)

Binary file not shown.

BIN
static/favicon-16x16.png (Stored with Git LFS)

Binary file not shown.

BIN
static/favicon-32x32.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/favicon.png (Stored with Git LFS)

Binary file not shown.