From dad93f608eed5e8811b8570ce759b85f20eb8345 Mon Sep 17 00:00:00 2001 From: Panto! Date: Fri, 11 Aug 2023 13:30:24 -0300 Subject: [PATCH] feat: add multi-authors support (#28) * feat: add multi-authors support * i have dumb (forgot to remove dev things before commiting) * feat: add multi-author support to news page * fix: static video link --- package-lock.json | 11 ++++ package.json | 3 +- .../NewsAuthor/NewsAuthor.module.css | 27 ++++++++ .../NewsSection/NewsAuthor/index.tsx | 27 ++++++++ .../NewsSection/NewsEntry/index.tsx | 34 +++++++--- src/components/NewsSection/index.tsx | 2 +- src/hooks/useNews.ts | 6 +- src/hooks/useNewsArticle.ts | 12 +++- src/hooks/useNewsAuthor.ts | 21 +++++++ src/routes/NewsPage/NewsPage.module.css | 39 ++++-------- src/routes/NewsPage/index.tsx | 63 ++++++++++--------- src/utils/consts.ts | 1 + 12 files changed, 177 insertions(+), 69 deletions(-) create mode 100644 src/components/NewsSection/NewsAuthor/NewsAuthor.module.css create mode 100644 src/components/NewsSection/NewsAuthor/index.tsx create mode 100644 src/hooks/useNewsAuthor.ts create mode 100644 src/utils/consts.ts diff --git a/package-lock.json b/package-lock.json index fd650ea..8090155 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "date-fns": "^2.30.0", "dompurify": "^3.0.5", "gray-matter": "^4.0.3", + "js-video-url-parser": "^0.5.1", "lodash": "^4.17.21", "marked": "^5.1.1", "react": "^18.2.0", @@ -5459,6 +5460,11 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/js-video-url-parser": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/js-video-url-parser/-/js-video-url-parser-0.5.1.tgz", + "integrity": "sha512-/vwqT67k0AyIGMHAvSOt+n4JfrZWF7cPKgKswDO35yr27GfW4HtjpQVlTx6JLF45QuPm8mkzFHkZgFVnFm4x/w==" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -11558,6 +11564,11 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "js-video-url-parser": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/js-video-url-parser/-/js-video-url-parser-0.5.1.tgz", + "integrity": "sha512-/vwqT67k0AyIGMHAvSOt+n4JfrZWF7cPKgKswDO35yr27GfW4HtjpQVlTx6JLF45QuPm8mkzFHkZgFVnFm4x/w==" + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", diff --git a/package.json b/package.json index 9716c5e..e91d09c 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "date-fns": "^2.30.0", "dompurify": "^3.0.5", "gray-matter": "^4.0.3", + "js-video-url-parser": "^0.5.1", "lodash": "^4.17.21", "marked": "^5.1.1", "react": "^18.2.0", @@ -62,4 +63,4 @@ "vite-plugin-top-level-await": "^1.3.1", "zustand": "^4.3.9" } -} \ No newline at end of file +} diff --git a/src/components/NewsSection/NewsAuthor/NewsAuthor.module.css b/src/components/NewsSection/NewsAuthor/NewsAuthor.module.css new file mode 100644 index 0000000..68bfed7 --- /dev/null +++ b/src/components/NewsSection/NewsAuthor/NewsAuthor.module.css @@ -0,0 +1,27 @@ + +.author { + display: flex; + gap: 10px; + align-items: center; +} + +.author .avatar { + height: 48px; + aspect-ratio: 1; + border-radius: 50%; + overflow: hidden; +} + +.author .authorInformation { + color: #5A5A5A; +} + +.author .authorInformation .authorName { + font-size: 16px; + font-weight: 600; +} + +.author .authorInformation .authorRole { + font-size: 12px; + font-weight: 400; +} diff --git a/src/components/NewsSection/NewsAuthor/index.tsx b/src/components/NewsSection/NewsAuthor/index.tsx new file mode 100644 index 0000000..65d9189 --- /dev/null +++ b/src/components/NewsSection/NewsAuthor/index.tsx @@ -0,0 +1,27 @@ +import styles from "./NewsAuthor.module.css"; +import UnknownUserIcon from "@app/assets/Icons/UnknownUser.svg"; +import { AuthorData } from "@app/hooks/useNewsAuthor"; +import { newsBaseURL } from "@app/utils/consts"; +import { Img } from "react-image"; + +interface Props { + author: AuthorData +} + +const NewsAuthor: React.FC = ({author}: Props) => { + return
+
+ {`${author.displayName}'s +
+
+
{author.displayName}
+
{author.role}
+
+
; +}; + +export default NewsAuthor; \ No newline at end of file diff --git a/src/components/NewsSection/NewsEntry/index.tsx b/src/components/NewsSection/NewsEntry/index.tsx index 2be6023..8dd9945 100644 --- a/src/components/NewsSection/NewsEntry/index.tsx +++ b/src/components/NewsSection/NewsEntry/index.tsx @@ -6,15 +6,23 @@ import { Img } from "react-image"; import UnknownUserIcon from "@app/assets/Icons/UnknownUser.svg"; import { TimeIcon } from "@app/assets/Icons"; import { intlFormatDistance } from "date-fns"; +import { newsBaseURL } from "@app/utils/consts"; +import { useNewsAuthorSettings } from "@app/hooks/useNewsAuthor"; +import { useQueries } from "@tanstack/react-query"; interface Props { article: ArticleData; } const NewsEntry: React.FC = ({ article }: Props) => { + + const authors = useQueries({ + queries: article?.authors?.map(authorId => useNewsAuthorSettings(authorId)) || [] + }); + return
- +
@@ -31,14 +39,24 @@ const NewsEntry: React.FC = ({ article }: Props) => { {article.title}
- {`${article.author}'s + { + authors + .filter(({data}) => data?.avatar) + .map(({data}) => ({`${data?.displayName}'s)) + }
- By: {article.author} + By: { + authors + .map(({data}) => data?.displayName) + .filter(authorName => authorName) + .join(", ") + }
diff --git a/src/components/NewsSection/index.tsx b/src/components/NewsSection/index.tsx index 421e0b2..b075091 100644 --- a/src/components/NewsSection/index.tsx +++ b/src/components/NewsSection/index.tsx @@ -25,7 +25,7 @@ const NewsSection: React.FC = ({ categoryFilter, startingEntries }: Props
{ - Array.from(data.articles).filter(i => { + data.articles.filter(i => { // Filter out everything that doesn't meet the filter if (!categoryFilter) return true; return i.category === categoryFilter; diff --git a/src/hooks/useNews.ts b/src/hooks/useNews.ts index 1defd0b..31f4af0 100644 --- a/src/hooks/useNews.ts +++ b/src/hooks/useNews.ts @@ -1,3 +1,4 @@ +import { newsBaseURL } from "@app/utils/consts"; import { useQuery } from "@tanstack/react-query"; export interface ArticleData { @@ -5,8 +6,7 @@ export interface ArticleData { type: string, title: string, thumb: string, - author: string, - avatar: string, + authors: string[], release: string, category: string } @@ -19,7 +19,7 @@ export const useNews = () => { return useQuery({ queryKey: ["NewsIndex"], queryFn: async (): Promise => await fetch( - "https://raw.githubusercontent.com/YARC-Official/News/master/index.json") + `${newsBaseURL}/index.json`) .then(res => res.json()) }); }; \ No newline at end of file diff --git a/src/hooks/useNewsArticle.ts b/src/hooks/useNewsArticle.ts index 48189bd..de41915 100644 --- a/src/hooks/useNewsArticle.ts +++ b/src/hooks/useNewsArticle.ts @@ -1,11 +1,21 @@ +import { newsBaseURL } from "@app/utils/consts"; import { useQuery } from "@tanstack/react-query"; +export interface Article { + type: string, + title: string, + banner?: string, + authors: string[], + release?: string, + video?: string +} + export const useNewsArticle = (md: string) => { return useQuery({ queryKey: ["NewsArticle", md], cacheTime: 60 * 60 * 1000, queryFn: async () => await fetch( - `https://raw.githubusercontent.com/YARC-Official/News/master/articles/${md}.md`) + `${newsBaseURL}/articles/${md}.md`) .then(res => res.text()) }); }; \ No newline at end of file diff --git a/src/hooks/useNewsAuthor.ts b/src/hooks/useNewsAuthor.ts new file mode 100644 index 0000000..4685e85 --- /dev/null +++ b/src/hooks/useNewsAuthor.ts @@ -0,0 +1,21 @@ +import { newsBaseURL } from "@app/utils/consts"; +import { useQuery } from "@tanstack/react-query"; + +export interface AuthorData { + displayName: string, + avatar?: string, + role?: string, +} + +export const useNewsAuthorSettings = (authorId: string) => { + return { + queryKey: ["NewsAuthor", authorId], + queryFn: async (): Promise => await fetch( + `${newsBaseURL}/authors/${authorId}.json`) + .then(res => res.json()) + }; +}; + +export const useNewsAuthor = (authorId: string) => { + return useQuery(useNewsAuthorSettings(authorId)); +}; \ No newline at end of file diff --git a/src/routes/NewsPage/NewsPage.module.css b/src/routes/NewsPage/NewsPage.module.css index 89d29fa..344ea91 100644 --- a/src/routes/NewsPage/NewsPage.module.css +++ b/src/routes/NewsPage/NewsPage.module.css @@ -56,35 +56,16 @@ } .info { - display: flex; - align-items: center; + display: grid; + grid-template-columns: auto auto; + gap: 25px; } -.author { +.authors { display: flex; - gap: 10px; - align-items: center; -} - -.author .avatar { - height: 48px; - aspect-ratio: 1; - border-radius: 50%; - overflow: hidden; -} - -.author .authorInformation { - color: #5A5A5A; -} - -.author .authorInformation .authorName { - font-size: 16px; - font-weight: 600; -} - -.author .authorInformation .authorRole { - font-size: 12px; - font-weight: 400; + max-width: 90%; + gap: 25px; + flex-wrap: wrap; } .releaseDate { @@ -95,6 +76,8 @@ display: flex; align-items: center; gap: 10px; + flex-shrink: 0; + height: 48px; } .video_container { @@ -106,6 +89,8 @@ .video { border: none; border-radius: 8px; - aspect-ratio: calc(16 / 9); + aspect-ratio: 16 / 9; height: 50vh; + width: fit-content; + margin: 20px auto 10px; } \ No newline at end of file diff --git a/src/routes/NewsPage/index.tsx b/src/routes/NewsPage/index.tsx index b9ca679..fd5168f 100644 --- a/src/routes/NewsPage/index.tsx +++ b/src/routes/NewsPage/index.tsx @@ -1,4 +1,4 @@ -import { useNewsArticle } from "@app/hooks/useNewsArticle"; +import { Article, useNewsArticle } from "@app/hooks/useNewsArticle"; import { useNavigate, useParams } from "react-router-dom"; import matter from "gray-matter"; import { marked } from "marked"; @@ -7,9 +7,13 @@ import styles from "./NewsPage.module.css"; import NewsBadge from "@app/components/NewsSection/NewsBadge"; import { CSSProperties } from "react"; import { BackIcon, TimeIcon } from "@app/assets/Icons"; -import { Img } from "react-image"; -import UnknownUserIcon from "@app/assets/Icons/UnknownUser.svg"; import { intlFormatDistance } from "date-fns"; +import { newsBaseURL } from "@app/utils/consts"; +import { useQueries } from "@tanstack/react-query"; +import { useNewsAuthorSettings } from "@app/hooks/useNewsAuthor"; +import NewsAuthor from "@app/components/NewsSection/NewsAuthor"; +import urlParser from "js-video-url-parser/lib/base"; +import "js-video-url-parser/lib/provider/youtube"; function NewsPage() { const { md } = useParams(); @@ -23,21 +27,18 @@ function NewsPage() { if (error) return `An error has occurred: ${error}`; if (isSuccess) { - const { data: articleData, content } = matter(data); + const article = matter(data); + const articleData = article.data as Article; + const content = article.content; - let videoElem = <>; - if ("video" in articleData) { - videoElem =
-