From a97250591285e287ec9a04a44f57221eaede10ba Mon Sep 17 00:00:00 2001 From: Pascal Achard Date: Fri, 2 Feb 2024 20:04:08 +0100 Subject: [PATCH] Merge pull request #76 * feat: Create Notion API and fetch data * feat: Add load more behavior * feat: WIP - Add query url support for cursor, pagesize and status * feat: WIP - Add "reading" page * feat: WIP - Add filters * fix: Fix card image issue * feat: Add readings sort * chore(deps): Update deps --- .env.example | 4 + app.vue | 2 +- assets/scss/abstracts/_variables.scss | 4 +- assets/scss/base/_base.scss | 11 + assets/scss/base/_forms.scss | 10 + assets/scss/base/_index.scss | 1 + assets/scss/base/_typography.scss | 7 + assets/scss/components/_badge.scss | 45 +++ assets/scss/components/_index.scss | 1 + components/layout/TheHeader.vue | 7 + components/shared/AppCard.vue | 52 ++++ composables/useBubblesEffect.ts | 6 +- content/en/readings.md | 8 + content/en/test.md | 8 + content/fr/readings.md | 9 + content/fr/test.md | 8 + locales/en.json | 24 ++ locales/fr.json | 24 ++ nuxt.config.ts | 2 + package.json | 3 + pages/index.vue | 2 +- pages/lab.vue | 14 +- pages/readings.vue | 346 ++++++++++++++++++++++ pages/test.vue | 6 +- pnpm-lock.yaml | 403 +++++++++++++++----------- server/api/notion-page-image.post.ts | 25 ++ server/api/notion-page-list.get.ts | 30 ++ server/api/notion-page-list.post.ts | 94 ++++++ server/tsconfig.json | 3 + tailwind.config.js | 17 ++ types/notion/notion-databases.ts | 119 ++++++++ 31 files changed, 1095 insertions(+), 200 deletions(-) create mode 100644 assets/scss/base/_forms.scss create mode 100644 assets/scss/components/_badge.scss create mode 100644 components/shared/AppCard.vue create mode 100644 content/en/readings.md create mode 100644 content/en/test.md create mode 100644 content/fr/readings.md create mode 100644 content/fr/test.md create mode 100644 pages/readings.vue create mode 100644 server/api/notion-page-image.post.ts create mode 100644 server/api/notion-page-list.get.ts create mode 100644 server/api/notion-page-list.post.ts create mode 100644 server/tsconfig.json create mode 100644 types/notion/notion-databases.ts diff --git a/.env.example b/.env.example index b873168..e6c574f 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,12 @@ # APIS NUXT_PUBLIC_LASTFM_API_KEY= +NUXT_NOTION_API_PRIVATE_KEY= # Used by NuxtSimpeSitemap NUXT_PUBLIC_SITE_URL= +# Notion db id +NUXT_NOTION_DATABASE_ID= + # Define IDE. LAUNCH_EDITOR=webstorm diff --git a/app.vue b/app.vue index cf8bdb2..0ce3de9 100644 --- a/app.vue +++ b/app.vue @@ -3,7 +3,7 @@ import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger); -ScrollTrigger.defaults({ markers: process.env.NODE_ENV === 'development' }); +// ScrollTrigger.defaults({ markers: process.env.NODE_ENV === 'development' }); const { t } = useI18n(); diff --git a/assets/scss/abstracts/_variables.scss b/assets/scss/abstracts/_variables.scss index 02ebdb4..48e7c60 100644 --- a/assets/scss/abstracts/_variables.scss +++ b/assets/scss/abstracts/_variables.scss @@ -89,14 +89,14 @@ $colors: ( $color-primary: color.scale($color-blue, $lightness: -7%); $color-secondary: $nord-8; $color-accent: $color-green; -$color-neutral: $color-gray-600; +$color-neutral: $nord-3; // Theme colors dark $color-primary-dark: $nord-8; $color-secondary-dark: $nord-11; $color-accent-dark: $color-green; -$color-neutral-dark: $color-gray-600; +$color-neutral-dark: $nord-6; // Darken and lighten amount $darken-amount: -60%; diff --git a/assets/scss/base/_base.scss b/assets/scss/base/_base.scss index 12da3aa..59b7b0a 100644 --- a/assets/scss/base/_base.scss +++ b/assets/scss/base/_base.scss @@ -60,3 +60,14 @@ button { .fouc-hidden { visibility: hidden; } + +// Vue transition +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.3s ease; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} diff --git a/assets/scss/base/_forms.scss b/assets/scss/base/_forms.scss new file mode 100644 index 0000000..ca3299b --- /dev/null +++ b/assets/scss/base/_forms.scss @@ -0,0 +1,10 @@ +// Select +select { + @apply block w-full rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3 + focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6; +} + +input[type="text"] { + @apply block w-full rounded-md border-0 py-1.5 text-body-txt shadow-sm ring-1 ring-inset ring-polarnight-nord-3 + focus:ring-2 focus:ring-inset focus:ring-accent sm:max-w-xs sm:text-sm sm:leading-6; +} diff --git a/assets/scss/base/_index.scss b/assets/scss/base/_index.scss index 38f4381..636da60 100644 --- a/assets/scss/base/_index.scss +++ b/assets/scss/base/_index.scss @@ -11,3 +11,4 @@ @forward "base"; @forward "typography"; @forward "nuxt-content"; +@forward "forms"; diff --git a/assets/scss/base/_typography.scss b/assets/scss/base/_typography.scss index 2cd483d..4518c70 100644 --- a/assets/scss/base/_typography.scss +++ b/assets/scss/base/_typography.scss @@ -79,3 +79,10 @@ h6, /*strong { @apply font-rubik-bold; }*/ + +// Flow +// ------------------------- + +.flow > *:where(:not(:first-child)) { + margin-top: 1em; +} diff --git a/assets/scss/components/_badge.scss b/assets/scss/components/_badge.scss new file mode 100644 index 0000000..fa3d115 --- /dev/null +++ b/assets/scss/components/_badge.scss @@ -0,0 +1,45 @@ + + +.badge { + @apply inline-flex items-center max-w-full px-[0.6em] py-[0.1em] rounded text-sm font-medium bg-[#E2EFFE] text-[#1D5695]; + + > span { + @apply block truncate; + } + + &, &--is-default { + @apply bg-snowstorm-nord-4; + } + + &--is-info { + @apply bg-info text-info-content; + } + + &--is-danger { + @apply bg-danger text-danger-content; + } + + &--is-warning { + @apply bg-warning text-warning-content; + } + + &--is-success { + @apply bg-success text-success-content; + } + + &--is-neutral { + @apply bg-neutral text-neutral-content; + } + + &--is-small { + @apply text-xs; + } + + &--is-medium { + @apply text-sm; + } + + &--is-large { + @apply text-base; + } +} diff --git a/assets/scss/components/_index.scss b/assets/scss/components/_index.scss index 38ca803..e096c74 100644 --- a/assets/scss/components/_index.scss +++ b/assets/scss/components/_index.scss @@ -8,3 +8,4 @@ @import "btn"; @import "wrapper-outline"; +@import "badge"; diff --git a/components/layout/TheHeader.vue b/components/layout/TheHeader.vue index 20b730d..657ce49 100644 --- a/components/layout/TheHeader.vue +++ b/components/layout/TheHeader.vue @@ -31,6 +31,13 @@ const localePath = useLocalePath(); > {{ t("navigation.home") }} + + {{ t("navigation.reading") }} + +// Typescript Props with default values +interface Props { + as?: string +} + +const props = withDefaults(defineProps(), { + as: 'article', +}); + + + + + diff --git a/composables/useBubblesEffect.ts b/composables/useBubblesEffect.ts index 4a97dff..cfd198e 100644 --- a/composables/useBubblesEffect.ts +++ b/composables/useBubblesEffect.ts @@ -28,7 +28,7 @@ export function useBubblesEffect(options: BubblesOptions = {}) { const vwPercent = vw * 0.4; const { - bubbleCount = 10, + bubbleCount = 2, bubbleSizeMin = vwPercent * 0.35, bubbleSizeMax = vwPercent, bubbleColors = [ @@ -38,8 +38,8 @@ export function useBubblesEffect(options: BubblesOptions = {}) { ], } = options; - const spawnBubbleX = (buubleWidth: number) => { - return gsap.utils.random(-buubleWidth, (bubblesContainer.value?.clientWidth || 0) - buubleWidth / 2); + const spawnBubbleX = (bubbleWidth: number) => { + return gsap.utils.random(-bubbleWidth, (bubblesContainer.value?.clientWidth || 0) - bubbleWidth / 2); }; const createBubble = () => { diff --git a/content/en/readings.md b/content/en/readings.md new file mode 100644 index 0000000..ddcfc69 --- /dev/null +++ b/content/en/readings.md @@ -0,0 +1,8 @@ +--- +coverTitle: Reading +coverSubtitle: List of articles to read +coverDescription: Like a to-do list, but for articles to be read. +description: Pascal Achard, senior frontend developer. Reading. List of articles to read. +--- + + diff --git a/content/en/test.md b/content/en/test.md new file mode 100644 index 0000000..b23f77a --- /dev/null +++ b/content/en/test.md @@ -0,0 +1,8 @@ +--- +coverTitle: À lire +coverSubtitle: Liste d'articles à lire +coverDescription: ??? +description: Pascal Achard, développeur frontend senior. Test. Liste d'articles à lire. +--- + + diff --git a/content/fr/readings.md b/content/fr/readings.md new file mode 100644 index 0000000..43c29d2 --- /dev/null +++ b/content/fr/readings.md @@ -0,0 +1,9 @@ +--- +coverTitle: Lectures +coverSubtitle: Frontend, développement, design, etc. +coverDescription: Base de données d’articles collectés au fil du temps. +description: Pascal Achard, développeur frontend senior. Lecture. Liste d'articles à lire. +--- + + +## Articles diff --git a/content/fr/test.md b/content/fr/test.md new file mode 100644 index 0000000..b23f77a --- /dev/null +++ b/content/fr/test.md @@ -0,0 +1,8 @@ +--- +coverTitle: À lire +coverSubtitle: Liste d'articles à lire +coverDescription: ??? +description: Pascal Achard, développeur frontend senior. Test. Liste d'articles à lire. +--- + + diff --git a/locales/en.json b/locales/en.json index 16c6b16..417beca 100644 --- a/locales/en.json +++ b/locales/en.json @@ -3,6 +3,7 @@ "go": "Go", "goToPage": "Go to page", "languages": "Language", + "loadMore": "Load more", "no": "No", "yes": "Yes" }, @@ -18,6 +19,7 @@ "home": "Home page", "lab": "Lab page", "languageSelector": "Language selector", + "reading": "Reading page", "themeSelector": "Theme selector" }, "pages": { @@ -29,6 +31,28 @@ "scrobbles": "Scrobbles", "scrobblesHistory": "Listening history", "tracksPerPage": "{n} tracks per page" + }, + "readings": { + "articleList": "Article list", + "bdd": "Data base", + "filters": { + "pageSizes": "Articles by page", + "status": { + "all": "All", + "canceled": "Canceled", + "inProgress": "In Progress", + "read": "Read", + "toRead": "To read" + }, + "statusLabel": "Status" + }, + "sort": { + "createdTime": "Created Time", + "lastEditedTime": "Last edited time", + "name": "Name", + "score": "⭐️⭐️⭐️⭐️⭐️", + "sortLabel": "Sort by" + } } }, "theme": { diff --git a/locales/fr.json b/locales/fr.json index 2900ed8..a773ea0 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -3,6 +3,7 @@ "go": "Allez", "goToPage": "Aller à la page", "languages": "Langue", + "loadMore": "Charger la suite", "no": "Non", "yes": "Oui" }, @@ -18,6 +19,7 @@ "home": "Page d'accueil", "lab": "Page lab", "languageSelector": "Sélecteur de langue", + "reading": "Page lecture", "themeSelector": "Sélecteur de thème" }, "pages": { @@ -29,6 +31,28 @@ "scrobbles": "Scrobbles", "scrobblesHistory": "Historique d'écoute", "tracksPerPage": "{n} pistes par pages" + }, + "readings": { + "articleList": "Liste des articles", + "bdd": "Base de données", + "filters": { + "pageSizes": "Articles par page", + "status": { + "all": "Tous", + "canceled": "Annulés", + "inProgress": "En cours", + "read": "Lus", + "toRead": "À lire" + }, + "statusLabel": "Statut" + }, + "sort": { + "createdTime": "Date de création", + "lastEditedTime": "Date de dernière édition", + "name": "Nom", + "score": "⭐️⭐️⭐️⭐️⭐️", + "sortLabel": "Trier par" + } } }, "theme": { diff --git a/nuxt.config.ts b/nuxt.config.ts index 9f6af8e..b0ae0e1 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -136,10 +136,12 @@ export default defineNuxtConfig({ }, runtimeConfig: { + notionApiKey: process.env.NUXT_NOTION_API_PRIVATE_KEY, public: { pkg: JSON.stringify(pkg), siteUrl: process.env.NUXT_PUBLIC_SITE_URL || 'http://localhost:3000', lastFmApiKey: process.env.NUXT_PUBLIC_LASTFM_API_KEY, + notionDatabaseId: process.env.NUXT_NOTION_DATABASE_ID, }, }, diff --git a/package.json b/package.json index 872ff9b..6ba270a 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,10 @@ "dependencies": { "@fontsource/inter": "^5.0.16", "@fontsource/rubik": "^5.0.18", + "@notionhq/client": "^2.2.14", "@studio-freight/lenis": "^1.0.34", "@vueuse/nuxt": "^10.7.2", + "@vueuse/router": "^10.7.2", "gsap": "^3.12.5", "splitting": "^1.0.6" }, @@ -34,6 +36,7 @@ "@nuxtjs/i18n": "^8.0.1", "@nuxtjs/sitemap": "^5.1.0", "@nuxtjs/tailwindcss": "^6.11.2", + "@tailwindcss/forms": "^0.5.7", "@types/node": "^20.11.16", "@types/splitting": "^1.0.5", "@types/uuid": "^9.0.8", diff --git a/pages/index.vue b/pages/index.vue index a83a78d..0c52173 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -70,7 +70,7 @@ onUnmounted(() => {

🧪 -

+

{{ contentData?.coverTitle }}

@@ -162,15 +162,3 @@ function scrollListToTop() { - - diff --git a/pages/readings.vue b/pages/readings.vue new file mode 100644 index 0000000..5b8ce76 --- /dev/null +++ b/pages/readings.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/pages/test.vue b/pages/test.vue index 4f67305..0c41145 100644 --- a/pages/test.vue +++ b/pages/test.vue @@ -1,11 +1,7 @@