diff --git a/src/components/ArticlesList/ArticlesList.tsx b/src/components/ArticlesList/ArticlesList.tsx index 8680091..92e9de4 100644 --- a/src/components/ArticlesList/ArticlesList.tsx +++ b/src/components/ArticlesList/ArticlesList.tsx @@ -1,100 +1,98 @@ import type { Component } from "solid-js"; import { createSignal, createEffect, For } from "solid-js"; import { search, selectedTags } from "@stores/searchStore"; +import SearchInput from "./SearchInput"; +import TagsList from "./TagsList"; import ArticleItem from "@components/ArticleItem"; import "./ArticlesList.scss"; -type UiStringsType = { "articles.empty": string }; +type UiStringsType = { "articles.empty": string; "input.search": string }; -type ArticleType = { +type ArticlesType = Array<{ id: string; title: string; + tags: string[]; pubDate: Date; -}; +}>; -type ArticlesType = Record; +type ArticlesBlockType = Record; type ArticlesListProps = { - data: { articles: ArticlesType; pageLang: string }; + articles: ArticlesBlockType; + tags: string[]; + pageLang: string; i18n: UiStringsType; }; const ArticlesList: Component = (props) => { - const [articles, setArticles] = createSignal(props.data.articles); + const [articles, setArticles] = createSignal(props.articles); - /** - * Sort articles by year in descending order - */ - const sortYears = (articles: ArticlesType) => { + const isEmpty = () => Object.keys(articles()).length === 0; + + const sortYears = (articles: ArticlesBlockType) => { return Object.keys(articles) .map(Number) .sort((a, b) => b - a); }; - const isEmpty = () => Object.keys(articles()).length === 0; - const getLength = () => Object.values(articles()).flat().length; + const searchArticles = ({ + params: { search, tags }, + }: { + params: { search: string; tags?: string[] }; + }) => { + const filter = (cb: (year: string) => ArticlesType) => { + return Object.fromEntries( + Object.keys(props.articles) + .map((year) => [year, cb(year)]) + .filter((articles) => articles[1].length !== 0) + ); + }; + + return filter((year) => { + let filtered = props.articles[year].filter((a) => + a.title.toLocaleLowerCase().includes(search) + ); + if (tags && tags.length > 0) { + filtered = filtered.filter((a) => tags.some((t) => a.tags.includes(t))); + } + return filtered; + }); + }; createEffect(() => { - // const filtered = Object.values(articles()).flat(1) - }); - - createEffect(() => { - let filtered = props.data.articles; - - /** - * Find articles by title - */ - if (search()) { - // filtered = findArticlesBySearch(search().trim(), filtered); - // setArticles(filtered); - console.log(search()); - } - - /** - * Find articles by selected tags - */ - if (selectedTags().length !== 0) { - // filtered = findArticlesByTags(selectedTags(), filtered); - // setArticles(filtered); - - return; - } - - /** - * Set filtered variable as default value - */ - if (!search() && selectedTags().length === 0) { - filtered = props.data.articles; - setArticles(filtered); - } + setArticles(searchArticles({ params: { search: search(), tags: selectedTags() } })); }); return ( -
- {!isEmpty() ? ( - - {(year) => ( -
-

{year}

- - {(a) => ( - - )} - -
- )} -
- ) : ( -
-

{props.i18n["articles.empty"]}

-
- )} -
+ <> + + +
+ {!isEmpty() ? ( + + {(year) => ( +
+

{year}

+ + {({ id, title, pubDate }) => ( + + )} + +
+ )} +
+ ) : ( +
+

{props.i18n["articles.empty"]}

+
+ )} +
+ ); }; diff --git a/src/components/SearchInput/SearchInput.scss b/src/components/ArticlesList/SearchInput/SearchInput.scss similarity index 100% rename from src/components/SearchInput/SearchInput.scss rename to src/components/ArticlesList/SearchInput/SearchInput.scss diff --git a/src/components/SearchInput/SearchInput.tsx b/src/components/ArticlesList/SearchInput/SearchInput.tsx similarity index 97% rename from src/components/SearchInput/SearchInput.tsx rename to src/components/ArticlesList/SearchInput/SearchInput.tsx index 247928c..ff1ac95 100644 --- a/src/components/SearchInput/SearchInput.tsx +++ b/src/components/ArticlesList/SearchInput/SearchInput.tsx @@ -21,7 +21,7 @@ const SearchInput: Component = (props) => { * Update state and set url param */ const onSearch: JSX.EventHandler = (e) => { - const value = e.currentTarget.value; + const value = e.currentTarget.value.trim().toLocaleLowerCase(); if (value.trim().length === 0) { resetSearch(); @@ -31,8 +31,6 @@ const SearchInput: Component = (props) => { const url = utils.setParamToUrl("search", value.trim()); history.replaceState(null, "", `${location.pathname}?${url}`); setSearch(value); - - // TODO: search articles }; /** diff --git a/src/components/SearchInput/index.ts b/src/components/ArticlesList/SearchInput/index.ts similarity index 100% rename from src/components/SearchInput/index.ts rename to src/components/ArticlesList/SearchInput/index.ts diff --git a/src/components/TagsList/TagsList.tsx b/src/components/ArticlesList/TagsList/TagsList.tsx similarity index 87% rename from src/components/TagsList/TagsList.tsx rename to src/components/ArticlesList/TagsList/TagsList.tsx index f3b7525..55a1c75 100644 --- a/src/components/TagsList/TagsList.tsx +++ b/src/components/ArticlesList/TagsList/TagsList.tsx @@ -6,7 +6,7 @@ import * as utils from "@utils/history"; type TagsListProps = { data: string[] }; const TagsList: Component = (props) => { - const isTagSelected = (tag: string) => selectedTags().includes(tag.toLocaleLowerCase()); + const isTagSelected = (tag: string) => selectedTags().includes(tag); /** * Reset signal state and `tags` property in history state @@ -21,6 +21,8 @@ const TagsList: Component = (props) => { const onSelect: JSX.EventHandler = (e) => { const tag = e.target.getAttribute("data-tag"); + if (!tag) return; + /** * Delete tag from selected tags if already selected * and update param in url @@ -68,10 +70,10 @@ const TagsList: Component = (props) => { const tags: string[] = []; for (const tag of props.data) { - const isTagExist = param.includes(tag.toLocaleLowerCase()); + const isTagExist = param.includes(tag); if (isTagExist) { - tags.push(tag.toLocaleLowerCase()); + tags.push(tag); } } @@ -83,12 +85,7 @@ const TagsList: Component = (props) => { ( - )} diff --git a/src/components/TagsList/index.ts b/src/components/ArticlesList/TagsList/index.ts similarity index 100% rename from src/components/TagsList/index.ts rename to src/components/ArticlesList/TagsList/index.ts diff --git a/src/templates/Articles.astro b/src/templates/Articles.astro index 787fb2a..a15e7a4 100644 --- a/src/templates/Articles.astro +++ b/src/templates/Articles.astro @@ -5,8 +5,6 @@ import * as utils from "@utils/index"; import PageLayout from "@layouts/default.astro"; import PageHeading from "@components/PageHeading.astro"; import ArticlesList from "@root/components/ArticlesList"; -import SearchInput from "@components/SearchInput"; -import TagsList from "@components/TagsList"; const t = useTranslation(Astro); const pageLang = getLanguageFromURL(Astro.url.pathname); @@ -24,12 +22,12 @@ const canonicalUrl = new URL(Astro.url.pathname, Astro.site); >
- -
diff --git a/src/utils/article.ts b/src/utils/article.ts index c451b20..b0fcd7c 100644 --- a/src/utils/article.ts +++ b/src/utils/article.ts @@ -49,7 +49,12 @@ export function formatToArticleBlocks(articles: CollectionEntry<"blog">[]) { articles.forEach((a) => { const year = a.data.pubDate.getFullYear(); if (!blocks[year]) blocks[year] = []; - blocks[year].push({ id: a.id, title: a.data.title, pubDate: a.data.pubDate }); + blocks[year].push({ + id: a.id, + title: a.data.title, + tags: a.data.tags, + pubDate: a.data.pubDate, + }); }); return blocks; }