From e3f2cae296fd2f8fc354a0de53f86dbdc398d342 Mon Sep 17 00:00:00 2001 From: Bradley Shellnut Date: Fri, 3 Feb 2023 23:23:00 -0800 Subject: [PATCH] Fetching 500 Wallabag articles, since we cannot filter tags easily, then filter tags in the API. --- .gitignore | 3 ++- .vscode/settings.json | 11 ++++++++- package.json | 1 + pnpm-lock.yaml | 6 +++++ src/lib/stores/articleStore.ts | 41 +++++++++++++++++++++++++++++++ src/lib/types/article.ts | 26 +++++++++++++++++--- src/lib/types/articleTag.ts | 17 +++++++++++++ src/routes/+layout.server.ts | 5 ++-- src/routes/api.ts | 32 ++++++++++++++++++------ src/routes/articles/+page.svelte | 6 +++-- src/routes/articles/+page.ts | 2 +- src/routes/portfolio/+page.svelte | 2 +- 12 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 src/lib/stores/articleStore.ts create mode 100644 src/lib/types/articleTag.ts diff --git a/.gitignore b/.gitignore index 3c0291d..f0fb46b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ vite.config.js.timestamp-* vite.config.ts.timestamp-* .fleet -.idea \ No newline at end of file +.idea +.vercel \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 3bf95e4..2c11cb1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,12 @@ { - "cSpell.words": ["bradleyshellnut", "iconify", "Mullvad", "Obispo", "Syncthing"] + "cSpell.words": [ + "bradleyshellnut", + "iconify", + "Mullvad", + "nextjs", + "Obispo", + "selfhosting", + "Syncthing", + "Wallabag" + ] } diff --git a/package.json b/package.json index dc22c62..034e38d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a488ce3..53a0e4f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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'} diff --git a/src/lib/stores/articleStore.ts b/src/lib/stores/articleStore.ts new file mode 100644 index 0000000..927fa38 --- /dev/null +++ b/src/lib/stores/articleStore.ts @@ -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([]); + + 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(); diff --git a/src/lib/types/article.ts b/src/lib/types/article.ts index 3ef8156..b93b96c 100644 --- a/src/lib/types/article.ts +++ b/src/lib/types/article.ts @@ -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; -} \ No newline at end of file +}; + +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; +}; diff --git a/src/lib/types/articleTag.ts b/src/lib/types/articleTag.ts new file mode 100644 index 0000000..465a59f --- /dev/null +++ b/src/lib/types/articleTag.ts @@ -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' +} diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index 2ceb7d5..ca7eae2 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -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 = { diff --git a/src/routes/api.ts b/src/routes/api.ts index 1c608f1..a48a2d5 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -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) { diff --git a/src/routes/articles/+page.svelte b/src/routes/articles/+page.svelte index 65944b1..8755e4f 100644 --- a/src/routes/articles/+page.svelte +++ b/src/routes/articles/+page.svelte @@ -1,5 +1,7 @@