mirror of
https://github.com/BradNut/personal-website-sveltekit
synced 2025-09-08 23:20:18 +00:00
Fetching 500 Wallabag articles, since we cannot filter tags easily, then filter tags in the API.
This commit is contained in:
parent
139fea9490
commit
e3f2cae296
12 changed files with 133 additions and 19 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -11,3 +11,4 @@ vite.config.ts.timestamp-*
|
|||
|
||||
.fleet
|
||||
.idea
|
||||
.vercel
|
||||
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
|
|
@ -1,3 +1,12 @@
|
|||
{
|
||||
"cSpell.words": ["bradleyshellnut", "iconify", "Mullvad", "Obispo", "Syncthing"]
|
||||
"cSpell.words": [
|
||||
"bradleyshellnut",
|
||||
"iconify",
|
||||
"Mullvad",
|
||||
"nextjs",
|
||||
"Obispo",
|
||||
"selfhosting",
|
||||
"Syncthing",
|
||||
"Wallabag"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"iconify-icon": "^1.0.3",
|
||||
"just-intersect": "^4.3.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ specifiers:
|
|||
eslint-config-prettier: ^8.5.0
|
||||
eslint-plugin-svelte3: ^4.0.0
|
||||
iconify-icon: ^1.0.3
|
||||
just-intersect: ^4.3.0
|
||||
postcss: ^8.4.21
|
||||
postcss-import: ^15.1.0
|
||||
postcss-load-config: ^4.0.1
|
||||
|
|
@ -57,6 +58,7 @@ devDependencies:
|
|||
eslint-config-prettier: 8.6.0_eslint@8.32.0
|
||||
eslint-plugin-svelte3: 4.0.0_tmo5zkisvhu6htudosk5k7m6pu
|
||||
iconify-icon: 1.0.3
|
||||
just-intersect: 4.3.0
|
||||
postcss: 8.4.21
|
||||
postcss-import: 15.1.0_postcss@8.4.21
|
||||
postcss-load-config: 4.0.1_postcss@8.4.21
|
||||
|
|
@ -2369,6 +2371,10 @@ packages:
|
|||
dev: true
|
||||
optional: true
|
||||
|
||||
/just-intersect/4.3.0:
|
||||
resolution: {integrity: sha512-XdAiJUmfM7VOoBUh7I4xo+0YYuzCPiV0Xf21oAmR+1j6a/P8KxJUCigZDblmURZmkIWffNziY2sbSaHrJbNcuA==}
|
||||
dev: true
|
||||
|
||||
/kleur/4.1.5:
|
||||
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
|
|||
41
src/lib/stores/articleStore.ts
Normal file
41
src/lib/stores/articleStore.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { writable } from 'svelte/store';
|
||||
import type { Article } from '$lib/types/article';
|
||||
|
||||
// Custom store
|
||||
const state = () => {
|
||||
const { subscribe, set, update } = writable<Article[]>([]);
|
||||
|
||||
function addAll(articles: Article[]) {
|
||||
for (const article of articles) {
|
||||
add(article);
|
||||
}
|
||||
}
|
||||
|
||||
function add(article: Article) {
|
||||
update((store) => [...store, article]);
|
||||
}
|
||||
|
||||
function addSorted(article: Article, index: number) {
|
||||
update((store) => {
|
||||
store.splice(index, 0, article);
|
||||
return store;
|
||||
});
|
||||
}
|
||||
|
||||
function remove(hashed_url: string) {
|
||||
update((store) => {
|
||||
const newStore = store.filter((item: Article) => item.hashed_url !== hashed_url);
|
||||
return [...newStore];
|
||||
});
|
||||
}
|
||||
|
||||
function removeAll() {
|
||||
update(() => {
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
return { subscribe, set, update, add, addSorted, addAll, remove, removeAll };
|
||||
};
|
||||
|
||||
export const articleStore = state();
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
export type Article {
|
||||
tags: string[];
|
||||
import type { ArticleTag } from './articleTag';
|
||||
|
||||
export type Article = {
|
||||
tags: ArticleTag[];
|
||||
title: string;
|
||||
url: URL;
|
||||
hashed_url: string;
|
||||
|
|
@ -8,4 +10,22 @@ export type Article {
|
|||
created_at: Date;
|
||||
updated_at: Date;
|
||||
archived_at: Date | null;
|
||||
}
|
||||
};
|
||||
|
||||
export type WallabagArticle = {
|
||||
tags: WallabagTag[];
|
||||
title: string;
|
||||
url: URL;
|
||||
hashed_url: string;
|
||||
reading_time: number;
|
||||
preview_picture: string;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
archived_at: Date | null;
|
||||
};
|
||||
|
||||
export type WallabagTag = {
|
||||
id: number;
|
||||
label: string;
|
||||
slug: string;
|
||||
};
|
||||
|
|
|
|||
17
src/lib/types/articleTag.ts
Normal file
17
src/lib/types/articleTag.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
export enum ArticleTag {
|
||||
TECH = 'tech',
|
||||
TECHNOLOGY = 'technology',
|
||||
SELFHOSTING = 'selfhosting',
|
||||
PROGRAMMING = 'programming',
|
||||
PRIVACY = 'privacy',
|
||||
DEVELOPMENT = 'development',
|
||||
VITE = 'vite',
|
||||
SVELTE = 'svelte',
|
||||
REACT = 'react',
|
||||
JAVASCRIPT = 'javascript',
|
||||
GATSBY = 'gatsby',
|
||||
SVELTEKIT = 'sveltekit',
|
||||
NEXTJS = 'nextjs',
|
||||
CSS = 'css',
|
||||
HTML = 'html'
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { error, type ServerLoad } from '@sveltejs/kit';
|
||||
import { fetchArticlesApi } from './api';
|
||||
// import type { PageServerLoad } from './$types';
|
||||
export const prerender = true;
|
||||
import { type ServerLoad } from '@sveltejs/kit';
|
||||
|
||||
export const load: ServerLoad = async ({ isDataRequest, cookies, params, setHeaders }) => {
|
||||
const queryParams = {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import {
|
|||
WALLABAG_PASSWORD,
|
||||
WALLABAG_URL
|
||||
} from '$env/static/private';
|
||||
import type { Article } from '$root/lib/types/article';
|
||||
import intersect from 'just-intersect';
|
||||
import type { Article, WallabagArticle } from '$root/lib/types/article';
|
||||
import { ArticleTag } from '$root/lib/types/articleTag';
|
||||
import type { PageQuery } from '$root/lib/types/pageQuery';
|
||||
import { URLSearchParams } from 'url';
|
||||
|
||||
|
|
@ -37,7 +39,7 @@ export async function fetchArticlesApi(
|
|||
|
||||
const pageQuery: PageQuery = {
|
||||
sort: 'updated',
|
||||
perPage: 6,
|
||||
perPage: 500,
|
||||
since: 0
|
||||
};
|
||||
const entriesQueryParams = new URLSearchParams(pageQuery);
|
||||
|
|
@ -67,11 +69,27 @@ export async function fetchArticlesApi(
|
|||
// do {
|
||||
// nbEntries += entries._embedded.items.length;
|
||||
console.log(`number of articles fetched: ${entries._embedded.items.length}`);
|
||||
entries._embedded.items.forEach((article: Article) => {
|
||||
article.created_at = new Date(article.created_at);
|
||||
article.updated_at = new Date(article.updated_at);
|
||||
article.archived_at = article.archived_at ? new Date(article.archived_at) : null;
|
||||
articles.push(article);
|
||||
entries._embedded.items.forEach((article: WallabagArticle) => {
|
||||
if (articles?.length === 30) {
|
||||
console.log('Reached 30 articles');
|
||||
return;
|
||||
}
|
||||
const rawTags = article?.tags?.map((tag) => tag.slug);
|
||||
if (intersect(rawTags, Object.values(ArticleTag))?.length > 0) {
|
||||
const tags = rawTags.map((rawTag) => rawTag as unknown as ArticleTag);
|
||||
|
||||
articles.push({
|
||||
tags,
|
||||
title: article.title,
|
||||
url: article.url,
|
||||
hashed_url: article.hashed_url,
|
||||
reading_time: article.reading_time,
|
||||
preview_picture: article.preview_picture,
|
||||
created_at: new Date(article.created_at),
|
||||
updated_at: new Date(article.updated_at),
|
||||
archived_at: article.archived_at ? new Date(article.archived_at) : null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// if (!entries._links.next) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/stores";
|
||||
import { Article } from "$lib/types/article";
|
||||
import { ArticleTag } from "$lib/types/articleTag";
|
||||
import SEO from "$root/lib/components/SEO.svelte";
|
||||
|
||||
$: ({ articles } = $page.data);
|
||||
|
|
@ -24,7 +26,7 @@
|
|||
base="/articles"
|
||||
/> -->
|
||||
<div class="articlesStyles">
|
||||
{#each articles as article}
|
||||
{#each articles as article (article.hashed_url)}
|
||||
<div class="articleStyles card">
|
||||
<section>
|
||||
<h3>
|
||||
|
|
@ -43,7 +45,7 @@
|
|||
<div class="tagStyles">
|
||||
<p>Tags:</p>
|
||||
{#each article.tags as tag}
|
||||
<p>{tag.label}</p>
|
||||
<p>{tag}</p>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export const load: PageLoad = async ({ fetch, parent, url, setHeaders }) => {
|
|||
const parentData = await parent();
|
||||
|
||||
const cacheBust = getCurrentCookieValue('articles-cache') || parentData.articlesCacheBust;
|
||||
const search = url.searchParams.get('search') || '';
|
||||
// const search = url.searchParams.get('search') || '';
|
||||
|
||||
const resp = await fetch(`/api/articles?cache=${cacheBust}`);
|
||||
const articles: Article[] = await resp.json();
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Bee, Shell, Nut, and Adventure Icons made by{' '}
|
||||
Bee, Shell, Nut, and Seattle Icons made by{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://www.flaticon.com/authors/freepik"
|
||||
|
|
|
|||
Loading…
Reference in a new issue