From 8d1f550fcd1fc2f1e7d152a0451f533d9582ef0d Mon Sep 17 00:00:00 2001 From: Ferran Date: Wed, 28 Aug 2024 13:05:00 +0200 Subject: [PATCH] feat: type improvements --- package.json | 16 +- src/application/dto/article/articleDTO.ts | 5 +- src/application/dto/article/types.ts | 3 - .../createRelatedArticles.ts | 9 + .../utils/createRelatedArticles/index.ts | 1 + .../utils/generateExcerpt/generateExcerpt.ts | 8 +- .../getRelatedArticles/getRelatedArticles.ts | 7 +- .../dto/author/utils/getArticlesByAuthor.ts | 3 +- .../dto/city/utils/createDate/createDate.ts | 4 +- .../getArticlesByTag/getArticlesByTag.ts | 14 +- .../dto/tag/utils/groupBy/groupBy.ts | 4 +- src/pages/index.astro | 6 +- src/shared/application/dto/baseDTO.ts | 4 +- src/shared/application/types/index.ts | 5 + .../about/utils/renderPin/renderPin.ts | 4 +- .../articleDetails/ArticleDetails.astro | 1 + .../articleDetails/article-details.css | 8 +- .../components/articleCard/ArticleCard.astro | 2 +- .../components/articleCard/article-card.css | 2 +- .../LatestArticlesSlider.tsx | 2 +- .../RelatedArticleCard.astro | 2 +- .../related-article-card.css | 2 +- .../useSliderNavigation.ts | 4 +- yarn.lock | 389 ++++++++++-------- 24 files changed, 284 insertions(+), 221 deletions(-) create mode 100644 src/application/dto/article/utils/createRelatedArticles/createRelatedArticles.ts create mode 100644 src/application/dto/article/utils/createRelatedArticles/index.ts diff --git a/package.json b/package.json index 9d58512d1..256564c02 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,8 @@ "dependencies": { "@astrojs/check": "^0.9.3", "@astrojs/cloudflare": "^11.0.4", - "@astrojs/mdx": "^3.1.4", - "@astrojs/partytown": "^2.1.1", + "@astrojs/mdx": "^3.1.5", + "@astrojs/partytown": "^2.1.2", "@astrojs/react": "^3.6.2", "@astrojs/rss": "^4.0.7", "@astrojs/sitemap": "^3.1.6", @@ -57,8 +57,8 @@ "@fontsource/baskervville": "^5.0.21", "@hookform/resolvers": "^3.9.0", "@million/lint": "1.0.0-rc.82-beta.50", - "algoliasearch": "^5.1.1", - "astro": "^4.14.5", + "algoliasearch": "^5.2.1", + "astro": "^4.14.6", "clsx": "^2.1.1", "contentful": "^10.15.0", "firebase": "^10.13.0", @@ -83,21 +83,21 @@ "devDependencies": { "@astrojs/ts-plugin": "^1.10.1", "@biomejs/biome": "1.8.3", - "@commitlint/cli": "^19.4.0", - "@commitlint/config-conventional": "^19.2.2", + "@commitlint/cli": "^19.4.1", + "@commitlint/config-conventional": "^19.4.1", "@commitlint/format": "^19.3.0", "@testing-library/react": "^16.0.0", "@testing-library/react-hooks": "^8.0.1", "@types/add": "^2.0.3", "@types/markdown-it": "^14.1.2", - "@types/node": "^22.5.0", + "@types/node": "^22.5.1", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", "@types/three": "^0.167.2", "conventional-changelog-atom": "^5.0.0", "husky": "^9.1.5", "lint-staged": "^15.2.9", - "stylelint": "^16.8.2", + "stylelint": "^16.9.0", "stylelint-config-recommended": "^14.0.1", "stylelint-order": "^6.0.4", "vitest": "^2.0.5" diff --git a/src/application/dto/article/articleDTO.ts b/src/application/dto/article/articleDTO.ts index f564b08c6..db025ddf5 100644 --- a/src/application/dto/article/articleDTO.ts +++ b/src/application/dto/article/articleDTO.ts @@ -1,5 +1,6 @@ import type { ArticleDTO, RawArticle } from "@application/dto/article/types"; import { ArticleType } from "@application/dto/article/types"; +import { createRelatedArticles } from "@application/dto/article/utils/createRelatedArticles"; import { getRelatedArticles } from "@application/dto/article/utils/getRelatedArticles/getRelatedArticles.ts"; import { DEFAULT_DATE_FORMAT } from "@const/index.ts"; import { documentToHtmlString } from "@contentful/rich-text-html-renderer"; @@ -23,11 +24,11 @@ export const articleDTO: BaseDTO = { generateExcerpt({ parser: PARSER, content: documentToHtmlString(rawArticle.fields.content as unknown as Document), - }).excerpt; + }); const tags = createTags(rawArticle.fields.tags); const relatedArticles = rawArticle.fields.relatedArticles - ? articleDTO.render(rawArticle.fields.relatedArticles as unknown as RawArticle[]) + ? createRelatedArticles(rawArticle.fields.relatedArticles) : getRelatedArticles({ rawArticle, allRawArticles: raw }); const featuredImage = rawArticle.fields.featuredImage && createImage(rawArticle.fields.featuredImage); const content = documentToHtmlString(rawArticle.fields.content as unknown as Document, renderOptions(rawArticle)); diff --git a/src/application/dto/article/types.ts b/src/application/dto/article/types.ts index 2aea20c89..a1819d00d 100644 --- a/src/application/dto/article/types.ts +++ b/src/application/dto/article/types.ts @@ -7,9 +7,6 @@ import type { z } from "zod"; export interface RawArticle { contentTypeId: "article"; - sys: { - id: string; - }; fields: { title: EntryFieldTypes.Text; slug: EntryFieldTypes.Text; diff --git a/src/application/dto/article/utils/createRelatedArticles/createRelatedArticles.ts b/src/application/dto/article/utils/createRelatedArticles/createRelatedArticles.ts new file mode 100644 index 000000000..b3f8174c8 --- /dev/null +++ b/src/application/dto/article/utils/createRelatedArticles/createRelatedArticles.ts @@ -0,0 +1,9 @@ +import type { Reference } from "@shared/application/types"; +import type { Entry, EntrySkeletonType } from "contentful"; + +export function createRelatedArticles(relatedArticles: Array>): Reference<"articles">[] { + return relatedArticles.map((relatedArticle) => ({ + id: relatedArticle.fields.slug as unknown as string, + collection: "articles", + })); +} diff --git a/src/application/dto/article/utils/createRelatedArticles/index.ts b/src/application/dto/article/utils/createRelatedArticles/index.ts new file mode 100644 index 000000000..fb1af166e --- /dev/null +++ b/src/application/dto/article/utils/createRelatedArticles/index.ts @@ -0,0 +1 @@ +export * from "./createRelatedArticles"; diff --git a/src/application/dto/article/utils/generateExcerpt/generateExcerpt.ts b/src/application/dto/article/utils/generateExcerpt/generateExcerpt.ts index 1444d6c78..15259ce43 100644 --- a/src/application/dto/article/utils/generateExcerpt/generateExcerpt.ts +++ b/src/application/dto/article/utils/generateExcerpt/generateExcerpt.ts @@ -6,14 +6,10 @@ interface ExcerptParams { limit?: number; } -interface ExcerptReturnType { - excerpt: string; -} - const EXCERPT_LIMIT = 140; const HTML_TAG_REGEX = /<\/?[^>]+(>|$)/g; -export function generateExcerpt({ parser, content, limit = EXCERPT_LIMIT }: ExcerptParams): ExcerptReturnType { +export function generateExcerpt({ parser, content, limit = EXCERPT_LIMIT }: ExcerptParams) { const excerpt = parser .render(content) .split("\n") @@ -23,5 +19,5 @@ export function generateExcerpt({ parser, content, limit = EXCERPT_LIMIT }: Exce .substring(0, limit) .trim(); - return { excerpt: `${excerpt}...` }; + return `${excerpt}...`; } diff --git a/src/application/dto/article/utils/getRelatedArticles/getRelatedArticles.ts b/src/application/dto/article/utils/getRelatedArticles/getRelatedArticles.ts index 30ca134e3..160abd0b4 100644 --- a/src/application/dto/article/utils/getRelatedArticles/getRelatedArticles.ts +++ b/src/application/dto/article/utils/getRelatedArticles/getRelatedArticles.ts @@ -1,12 +1,13 @@ import type { RawArticle } from "@application/dto/article/types"; import { MAX_RELATED_ARTICLES } from "@const/index"; +import type { Reference } from "@shared/application/types"; -interface GetRelatedArticlesProps { +interface GetRelatedArticlesParams { rawArticle: RawArticle; allRawArticles: RawArticle[]; } -export function getRelatedArticles({ rawArticle, allRawArticles }: GetRelatedArticlesProps) { +export function getRelatedArticles({ rawArticle, allRawArticles }: GetRelatedArticlesParams): Reference<"articles">[] { const articleTagsSlugs = rawArticle.fields.tags.map((tag) => tag.fields.slug); return allRawArticles @@ -17,7 +18,7 @@ export function getRelatedArticles({ rawArticle, allRawArticles }: GetRelatedArt }) .slice(0, MAX_RELATED_ARTICLES) .map((relatedArticle) => ({ - id: relatedArticle.fields.slug, + id: String(relatedArticle.fields.slug), collection: "articles", })); } diff --git a/src/application/dto/author/utils/getArticlesByAuthor.ts b/src/application/dto/author/utils/getArticlesByAuthor.ts index 0be7af7f6..f70a39a68 100644 --- a/src/application/dto/author/utils/getArticlesByAuthor.ts +++ b/src/application/dto/author/utils/getArticlesByAuthor.ts @@ -1,7 +1,8 @@ import { getCollection } from "astro:content"; import type { RawAuthor } from "@application/dto/author/types.ts"; +import type { Reference } from "@shared/application/types"; -export async function getArticlesByAuthor(rawAuthor: RawAuthor) { +export async function getArticlesByAuthor(rawAuthor: RawAuthor): Promise[]> { const articles = await getCollection("articles"); return articles diff --git a/src/application/dto/city/utils/createDate/createDate.ts b/src/application/dto/city/utils/createDate/createDate.ts index 21b77c2a7..8979772d2 100644 --- a/src/application/dto/city/utils/createDate/createDate.ts +++ b/src/application/dto/city/utils/createDate/createDate.ts @@ -1,9 +1,9 @@ -interface ParseDatesProps { +interface ParseDatesParams { startDate: string; endDate?: string; } -export function createDate({ startDate, endDate }: ParseDatesProps) { +export function createDate({ startDate, endDate }: ParseDatesParams) { return { startDate: new Date(startDate).getFullYear(), endDate: endDate ? new Date(endDate).getFullYear() : "Present", diff --git a/src/application/dto/tag/utils/getArticlesByTag/getArticlesByTag.ts b/src/application/dto/tag/utils/getArticlesByTag/getArticlesByTag.ts index 58dc2168a..bff64749b 100644 --- a/src/application/dto/tag/utils/getArticlesByTag/getArticlesByTag.ts +++ b/src/application/dto/tag/utils/getArticlesByTag/getArticlesByTag.ts @@ -1,13 +1,17 @@ import type { CollectionEntry } from "astro:content"; import type { RawTag } from "@application/dto/tag/types.ts"; +import type { Reference } from "@shared/application/types"; -interface GetArticlesProps { +interface GetArticlesParams { rawTag: RawTag; articles: CollectionEntry<"articles">[]; } -export function getArticlesByTag({ rawTag, articles }: GetArticlesProps) { - return articles.filter((article) => - article.data.tags?.map((tag) => tag.slug).includes(rawTag.fields.slug as unknown as string), - ); +export function getArticlesByTag({ rawTag, articles }: GetArticlesParams): Reference<"articles">[] { + return articles + .filter(({ data: { tags } }) => tags?.some(({ slug }) => slug === String(rawTag.fields.slug))) + .map(({ data: { slug } }) => ({ + id: slug, + collection: "articles", + })); } diff --git a/src/application/dto/tag/utils/groupBy/groupBy.ts b/src/application/dto/tag/utils/groupBy/groupBy.ts index b274602f2..d9bb319b8 100644 --- a/src/application/dto/tag/utils/groupBy/groupBy.ts +++ b/src/application/dto/tag/utils/groupBy/groupBy.ts @@ -1,9 +1,9 @@ -interface GroupByProps { +interface GroupByParams { array: T[]; keyFn: (item: T) => K; } -export function groupBy({ array, keyFn }: GroupByProps): Record { +export function groupBy({ array, keyFn }: GroupByParams): Record { const grouped = array.reduce( (acc, currentItem) => { const key = keyFn(currentItem); diff --git a/src/pages/index.astro b/src/pages/index.astro index 13fe86dea..e977ca058 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -5,6 +5,7 @@ import MyWork from "@modules/home/components/myWork/MyWork.astro"; import Testimonials from "@modules/home/components/testimonials/Testimonials.astro"; import Welcome from "@modules/home/components/welcome/Welcome.astro"; +// todo: review classNames (-wraper or __wrapper, etc) (check grid names as well) // todo: check metadata all pages // todo: add small transitions & animations // - Latest articles (https://codepen.io/jh3y/pen/MWLyGxo) @@ -22,9 +23,7 @@ import Welcome from "@modules/home/components/welcome/Welcome.astro"; // todo: check imgBot and other bot implementations (configure them) // todo: add padding to overlapping items in cards(author, tags etc) // todo: add container queries -// todo: review classNames (-wraper or __wrapper, etc) -// -// + // other ideas: // todo: check notion // todo: reveal on scroll (Agafar idees gsap) @@ -33,7 +32,6 @@ import Welcome from "@modules/home/components/welcome/Welcome.astro"; // todo: add comments section // todo: content bar https://x.com/anatudor/status/1798615928420344018?t=m-9Hn_qO58wltQejaEMHNg&s=19 // todo: svg scroll offset driven animation in background -// todo: https://codepen.io/jh3y/pen/GReZEwK // todo: mess with line-heights (actually not using var(--base-line-height) and test (https://dev.to/carmenansio/creating-a-modular-typography-scale-with-css-2d29) // todo: mess with vertical rythm (https://notadesigner.io/p/vertical-rhythm) // todo: https://daverupert.com/2024/01/focus-visible-love/ diff --git a/src/shared/application/dto/baseDTO.ts b/src/shared/application/dto/baseDTO.ts index 26a077365..cafabe7d2 100644 --- a/src/shared/application/dto/baseDTO.ts +++ b/src/shared/application/dto/baseDTO.ts @@ -1,3 +1,3 @@ -export type BaseDTO = { - render: (raw: INPUT, configuration?: CONFIG) => RETURN_TYPE; +export type BaseDTO = { + render: (raw: INPUT, configuration?: CONFIGURATION) => OUTPUT; }; diff --git a/src/shared/application/types/index.ts b/src/shared/application/types/index.ts index 14f6af06e..cb90bf127 100644 --- a/src/shared/application/types/index.ts +++ b/src/shared/application/types/index.ts @@ -34,3 +34,8 @@ export interface ContenfulLocation { }; }; } + +export interface Reference { + id: string; + collection: T; +} diff --git a/src/ui/modules/about/utils/renderPin/renderPin.ts b/src/ui/modules/about/utils/renderPin/renderPin.ts index e2beb64ff..788aab728 100644 --- a/src/ui/modules/about/utils/renderPin/renderPin.ts +++ b/src/ui/modules/about/utils/renderPin/renderPin.ts @@ -2,11 +2,11 @@ import { Pin as pin } from "@assets/images/svg-components/pin"; import type { ReactGlobePoint } from "@modules/about/components/worldGlobe"; import { createRoot } from "react-dom/client"; -interface RenderPinProps { +interface RenderPinParams { markerData: ReactGlobePoint; } -export function renderPin({ markerData }: RenderPinProps): HTMLElement { +export function renderPin({ markerData }: RenderPinParams): HTMLElement { const markerWrapper = document.createElement("button"); markerWrapper.classList.add("marker__wrapper"); markerWrapper.classList.add(`--is-${markerData.label.toLowerCase()}`); diff --git a/src/ui/modules/article/components/articleDetails/ArticleDetails.astro b/src/ui/modules/article/components/articleDetails/ArticleDetails.astro index 2ff6c0631..957effe21 100644 --- a/src/ui/modules/article/components/articleDetails/ArticleDetails.astro +++ b/src/ui/modules/article/components/articleDetails/ArticleDetails.astro @@ -17,6 +17,7 @@ const { article } = Astro.props as ArticleDetailsProps; {article.data.publishDate} + {article.data.readingTime} minutes read { article.data.tags?.length && ( diff --git a/src/ui/modules/article/components/articleDetails/article-details.css b/src/ui/modules/article/components/articleDetails/article-details.css index db042dba9..cec522b44 100644 --- a/src/ui/modules/article/components/articleDetails/article-details.css +++ b/src/ui/modules/article/components/articleDetails/article-details.css @@ -1,9 +1,11 @@ .article__details { display: grid; + gap: 1rem 0; grid: 'Article-Date Article-Date Article-Date' min-content 'Article-Title Article-Title Article-Title' 1fr - 'Article-Tags Article-Tags Article-Author' min-content / 1fr 1fr; + 'Article-Author Article-Author Article-Reading-Time' min-content + 'Article-Tags Article-Tags Article-Tags' min-content / 1fr 1fr; margin: 2rem auto; max-width: var(--grid-small); width: 100%; @@ -25,6 +27,10 @@ } } +.article__reading-time{ + grid-area: Article-Reading-Time; +} + .article__tags__list { gap: 0 1rem; grid-area: Article-Tags; diff --git a/src/ui/modules/core/components/articleCard/ArticleCard.astro b/src/ui/modules/core/components/articleCard/ArticleCard.astro index 63d985f31..5b00e9f51 100644 --- a/src/ui/modules/core/components/articleCard/ArticleCard.astro +++ b/src/ui/modules/core/components/articleCard/ArticleCard.astro @@ -43,7 +43,7 @@ const origin = getLocation(Astro.url); by {article.data.author.name}
{article.data.readingTime} minutes read
{article.data.description}
{article.data.readingTime} min.
{relatedArticle.data.description}
{relatedArticle.data.readingTime} min.
{relatedArticle.data.readingTime} minutes read