From 622a98b5f42c5ddf19adfded7df7a1c7176a3c1e Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Wed, 20 Apr 2022 12:15:43 +0300 Subject: [PATCH] feat: add lazy loading to app pages, pull out tw theme to a module, add filters to getFeed api --- functions/graphql/nexus-typegen.ts | 2 + functions/graphql/schema.graphql | 2 +- functions/graphql/types/post.js | 8 +++- package-lock.json | 30 ++++++++++++ package.json | 1 + src/App.tsx | 31 +++++++----- src/Components/LoadingPage/LoadingPage.jsx | 14 ++++++ .../Components/TrendingCard/TrendingCard.tsx | 2 +- .../Posts/pages/FeedPage/FeedPage.tsx | 17 +++++-- .../Posts/pages/FeedPage/feed.graphql | 4 +- .../Components/PageContent/PageContent.tsx | 5 +- .../PageContent/QuestionPageContent.tsx | 39 +++++++++++++++ .../pages/PostDetailsPage/PostDetailsPage.tsx | 6 ++- .../pages/ExplorePage/Header/Header.tsx | 2 +- src/graphql/index.tsx | 14 ++++-- src/mocks/data/posts.ts | 6 ++- src/utils/apollo.ts | 2 +- src/utils/theme/colors.js | 47 ++++++++++++++++++ src/utils/theme/index.js | 11 +++++ src/utils/theme/index.ts | 6 --- src/utils/theme/media_queries.js | 9 +++- tailwind.config.js | 48 ++----------------- 22 files changed, 221 insertions(+), 85 deletions(-) create mode 100644 src/Components/LoadingPage/LoadingPage.jsx create mode 100644 src/features/Posts/pages/PostDetailsPage/Components/PageContent/QuestionPageContent.tsx create mode 100644 src/utils/theme/colors.js create mode 100644 src/utils/theme/index.js delete mode 100644 src/utils/theme/index.ts diff --git a/functions/graphql/nexus-typegen.ts b/functions/graphql/nexus-typegen.ts index 69aeb90..8bfff43 100644 --- a/functions/graphql/nexus-typegen.ts +++ b/functions/graphql/nexus-typegen.ts @@ -443,7 +443,9 @@ export interface NexusGenArgTypes { id: number; // Int! } getFeed: { // args + category: string | null; // String skip?: number | null; // Int + sortBy: string | null; // String take: number | null; // Int } getLnurlDetailsForProject: { // args diff --git a/functions/graphql/schema.graphql b/functions/graphql/schema.graphql index 35785cb..92330d5 100644 --- a/functions/graphql/schema.graphql +++ b/functions/graphql/schema.graphql @@ -102,7 +102,7 @@ type Query { allCategories: [Category!]! allProjects(skip: Int = 0, take: Int = 50): [Project!]! getCategory(id: Int!): Category! - getFeed(skip: Int = 0, take: Int = 10): [Post!]! + getFeed(category: String = "all", skip: Int = 0, sortBy: String = "all", take: Int = 10): [Post!]! getLnurlDetailsForProject(project_id: Int!): LnurlDetails! getPostById(id: Int!, type: POST_TYPE!): Post! getProject(id: Int!): Project! diff --git a/functions/graphql/types/post.js b/functions/graphql/types/post.js index 6aae735..cc41d4b 100644 --- a/functions/graphql/types/post.js +++ b/functions/graphql/types/post.js @@ -125,7 +125,13 @@ const getFeed = extendType({ t.nonNull.list.nonNull.field('getFeed', { type: "Post", args: { - ...paginationArgs({ take: 10 }) + ...paginationArgs({ take: 10 }), + sortBy: stringArg({ + default: "all" + }), + category: stringArg({ + default: "all" + }) }, resolve(_, { take, skip }) { const feed = [] diff --git a/package-lock.json b/package-lock.json index 9108dd3..3330d1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,6 +51,7 @@ "react-responsive-carousel": "^3.2.22", "react-router-dom": "^6.2.2", "react-scripts": "4.0.3", + "react-topbar-progress-indicator": "^4.1.1", "typescript": "^4.4.4", "web-vitals": "^1.1.2", "webln": "^0.2.2" @@ -53156,6 +53157,17 @@ "react": "^16.8.0 || ^17.0.0" } }, + "node_modules/react-topbar-progress-indicator": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/react-topbar-progress-indicator/-/react-topbar-progress-indicator-4.1.1.tgz", + "integrity": "sha512-Oy3ENNKfymt16zoz5SYy/WOepMurB0oeZEyvuHm8JZ3jrTCe1oAUD7fG6HhYt5sg8Wcg5gdkzSWItaFF6c6VhA==", + "dependencies": { + "topbar": "^0.1.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -57847,6 +57859,11 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/topbar": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/topbar/-/topbar-0.1.4.tgz", + "integrity": "sha512-P3n4WnN4GFd2mQXDo30rQmsAGe4V1bVkggtTreSbNyL50Fyc+eVkW5oatSLeGQmJoan2TLIgoXUZypN+6nw4MQ==" + }, "node_modules/tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -101774,6 +101791,14 @@ "use-latest": "^1.0.0" } }, + "react-topbar-progress-indicator": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/react-topbar-progress-indicator/-/react-topbar-progress-indicator-4.1.1.tgz", + "integrity": "sha512-Oy3ENNKfymt16zoz5SYy/WOepMurB0oeZEyvuHm8JZ3jrTCe1oAUD7fG6HhYt5sg8Wcg5gdkzSWItaFF6c6VhA==", + "requires": { + "topbar": "^0.1.3" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -105463,6 +105488,11 @@ "ieee754": "^1.2.1" } }, + "topbar": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/topbar/-/topbar-0.1.4.tgz", + "integrity": "sha512-P3n4WnN4GFd2mQXDo30rQmsAGe4V1bVkggtTreSbNyL50Fyc+eVkW5oatSLeGQmJoan2TLIgoXUZypN+6nw4MQ==" + }, "tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", diff --git a/package.json b/package.json index 03dc6de..6d66003 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "react-responsive-carousel": "^3.2.22", "react-router-dom": "^6.2.2", "react-scripts": "4.0.3", + "react-topbar-progress-indicator": "^4.1.1", "typescript": "^4.4.4", "web-vitals": "^1.1.2", "webln": "^0.2.2" diff --git a/src/App.tsx b/src/App.tsx index 7acbea1..4d1125f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,15 +1,18 @@ -import { useEffect } from "react"; +import React, { Suspense, useEffect } from "react"; import Navbar from "src/Components/Navbar/Navbar"; -import ExplorePage from "src/features/Projects/pages/ExplorePage"; import ModalsContainer from "src/Components/Modals/ModalsContainer/ModalsContainer"; import { useAppSelector } from './utils/hooks'; import { Wallet_Service } from "./services"; import { Route, Routes } from "react-router-dom"; -import CategoryPage from "src/features/Projects/pages/CategoryPage/CategoryPage"; import { useWrapperSetup } from "./utils/Wrapper"; -import HottestPage from "src/features/Projects/pages/HottestPage/HottestPage"; -import FeedPage from "./features/Posts/pages/FeedPage/FeedPage"; -import PostDetailsPage from "./features/Posts/pages/PostDetailsPage/PostDetailsPage"; +import LoadingPage from "./Components/LoadingPage/LoadingPage"; + +// Pages +const FeedPage = React.lazy(() => import("./features/Posts/pages/FeedPage/FeedPage")) +const HottestPage = React.lazy(() => import("src/features/Projects/pages/HottestPage/HottestPage")) +const PostDetailsPage = React.lazy(() => import("./features/Posts/pages/PostDetailsPage/PostDetailsPage")) +const CategoryPage = React.lazy(() => import("src/features/Projects/pages/CategoryPage/CategoryPage")) +const ExplorePage = React.lazy(() => import("src/features/Projects/pages/ExplorePage")) function App() { const { isWalletConnected } = useAppSelector(state => ({ @@ -38,13 +41,15 @@ function App() { return
- - } /> - } /> - } /> - } /> - } /> - + }> + + } /> + } /> + } /> + } /> + } /> + +
; } diff --git a/src/Components/LoadingPage/LoadingPage.jsx b/src/Components/LoadingPage/LoadingPage.jsx new file mode 100644 index 0000000..0d39b37 --- /dev/null +++ b/src/Components/LoadingPage/LoadingPage.jsx @@ -0,0 +1,14 @@ +import TopBarProgress from "react-topbar-progress-indicator"; +import THEME from "src/utils/theme"; + +TopBarProgress.config({ + barColors: { + 0: THEME.colors.primary[400], + ".5": THEME.colors.primary[500], + "1.0": THEME.colors.primary[700], + }, +}); + +export default function LoadingPage() { + return ; +} diff --git a/src/features/Posts/Components/TrendingCard/TrendingCard.tsx b/src/features/Posts/Components/TrendingCard/TrendingCard.tsx index 913f578..be83a81 100644 --- a/src/features/Posts/Components/TrendingCard/TrendingCard.tsx +++ b/src/features/Posts/Components/TrendingCard/TrendingCard.tsx @@ -24,7 +24,7 @@ export default function TrendingCard() { ) : trendingPosts.data?.getTrendingPosts.map(post => { - return + return
  • {post.title}

    diff --git a/src/features/Posts/pages/FeedPage/FeedPage.tsx b/src/features/Posts/pages/FeedPage/FeedPage.tsx index f35e79c..ffd33b3 100644 --- a/src/features/Posts/pages/FeedPage/FeedPage.tsx +++ b/src/features/Posts/pages/FeedPage/FeedPage.tsx @@ -1,4 +1,5 @@ +import { useReducer, useState } from 'react' import { useFeedQuery } from 'src/graphql' import { useAppSelector, useInfiniteQuery } from 'src/utils/hooks' import PostsList from '../../Components/PostsList/PostsList' @@ -10,10 +11,16 @@ import styles from './styles.module.css' export default function FeedPage() { + const [sortByFilter, setSortByFilter] = useState('all') + const [categoryFilter, setCategoryFilter] = useState('all') + + const feedQuery = useFeedQuery({ variables: { take: 10, - skip: 0 + skip: 0, + sortBy: sortByFilter, + category: categoryFilter }, }) const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed') @@ -32,9 +39,13 @@ export default function FeedPage() { maxHeight: `calc(100vh - ${navHeight}px - 16px)`, overflowY: "scroll", }}> - +
    - + - // if (isQuestion(post)) - // return + if (isQuestion(post)) + return return null diff --git a/src/features/Posts/pages/PostDetailsPage/Components/PageContent/QuestionPageContent.tsx b/src/features/Posts/pages/PostDetailsPage/Components/PageContent/QuestionPageContent.tsx new file mode 100644 index 0000000..0ee7d7c --- /dev/null +++ b/src/features/Posts/pages/PostDetailsPage/Components/PageContent/QuestionPageContent.tsx @@ -0,0 +1,39 @@ +import Header from "src/features/Posts/Components/PostCard/Header/Header" +import { Question } from "src/features/Posts/types" +import { marked } from 'marked'; +import styles from './styles.module.css' +import Badge from "src/Components/Badge/Badge"; +import { BiComment } from "react-icons/bi"; +import { RiFlashlightLine } from "react-icons/ri"; + + +interface Props { + question: Question +} + +export default function QuestionPageContent({ question }: Props) { + return ( +
    +
    +
    +

    {question.title}

    +
    + {question.tags.map(tag => + {tag.title} + )} +
    +
    +
    + {question.votes_count} votes +
    +
    + 32 Comments +
    +
    +
    + +
    +
    +
    + ) +} diff --git a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx index 1e2c90b..21d6529 100644 --- a/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx +++ b/src/features/Posts/pages/PostDetailsPage/PostDetailsPage.tsx @@ -1,5 +1,6 @@ import { useParams } from 'react-router-dom' +import LoadingPage from 'src/Components/LoadingPage/LoadingPage' import { usePostDetailsQuery } from 'src/graphql' import { useAppSelector, } from 'src/utils/hooks' import TrendingCard from '../../Components/TrendingCard/TrendingCard' @@ -17,7 +18,8 @@ export default function PostDetailsPage() { id: Number(id!), type: type as any }, - skip: isNaN(Number(id)) + skip: isNaN(Number(id)), + }) const { navHeight } = useAppSelector((state) => ({ @@ -25,7 +27,7 @@ export default function PostDetailsPage() { })); if (postDetailsQuery.loading) - return

    Loading

    + return const post = postDetailsQuery.data?.getPostById; diff --git a/src/features/Projects/pages/ExplorePage/Header/Header.tsx b/src/features/Projects/pages/ExplorePage/Header/Header.tsx index 5196565..7c37de7 100644 --- a/src/features/Projects/pages/ExplorePage/Header/Header.tsx +++ b/src/features/Projects/pages/ExplorePage/Header/Header.tsx @@ -2,7 +2,7 @@ import { useMediaQuery } from "@react-hookz/web"; import Carousel from "react-multi-carousel"; import Assets from "src/assets"; import Button from "src/Components/Button/Button"; -import { THEME } from "src/utils/theme"; +import THEME from "src/utils/theme"; import { MEDIA_QUERIES } from "src/utils/theme/media_queries"; import CustomDot from "./CustomDot/CustomDot"; import styles from './styles.module.css' diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index 0b91205..ccfeb7c 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -160,7 +160,9 @@ export type QueryGetCategoryArgs = { export type QueryGetFeedArgs = { + category?: InputMaybe; skip?: InputMaybe; + sortBy?: InputMaybe; take?: InputMaybe; }; @@ -278,8 +280,10 @@ export type TrendingPostsQueryVariables = Exact<{ [key: string]: never; }>; export type TrendingPostsQuery = { __typename?: 'Query', getTrendingPosts: Array<{ __typename?: 'Bounty', id: number, title: string, author: { __typename?: 'User', id: number, image: string } } | { __typename?: 'Question', id: number, title: string, author: { __typename?: 'User', id: number, image: string } } | { __typename?: 'Story', id: number, title: string, author: { __typename?: 'User', id: number, image: string } }> }; export type FeedQueryVariables = Exact<{ - skip: InputMaybe; take: InputMaybe; + skip: InputMaybe; + sortBy: InputMaybe; + category: InputMaybe; }>; @@ -475,8 +479,8 @@ export type TrendingPostsQueryHookResult = ReturnType; export type TrendingPostsQueryResult = Apollo.QueryResult; export const FeedDocument = gql` - query Feed($skip: Int, $take: Int) { - getFeed(skip: $skip, take: $take) { + query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) { + getFeed(take: $take, skip: $skip, sortBy: $sortBy, category: $category) { ... on Story { id title @@ -561,8 +565,10 @@ export const FeedDocument = gql` * @example * const { data, loading, error } = useFeedQuery({ * variables: { - * skip: // value for 'skip' * take: // value for 'take' + * skip: // value for 'skip' + * sortBy: // value for 'sortBy' + * category: // value for 'category' * }, * }); */ diff --git a/src/mocks/data/posts.ts b/src/mocks/data/posts.ts index 512e5e7..801ecd1 100644 --- a/src/mocks/data/posts.ts +++ b/src/mocks/data/posts.ts @@ -153,5 +153,9 @@ const feedRandomer = new Chance('feed') export const feed: Post[] = Array(30).fill(0).map((_, idx) => { const post = feedRandomer.pickone([posts.bounties[0], posts.questions[0], posts.stories[0]]) - return { ...post, id: idx + 1, title: `${post.type} Title ${idx + 1}` } + return { + ...post, id: idx + 1, title: feedRandomer.sentence({ + words: feedRandomer.integer({ min: 4, max: 7 }) + }) + } }) diff --git a/src/utils/apollo.ts b/src/utils/apollo.ts index 9cd5c6a..fd7e395 100644 --- a/src/utils/apollo.ts +++ b/src/utils/apollo.ts @@ -50,7 +50,7 @@ export const apolloClient = new ApolloClient({ typePolicies: { Query: { fields: { - getFeed: offsetLimitPagination() + getFeed: offsetLimitPagination(['sortBy', 'category']) }, }, }, diff --git a/src/utils/theme/colors.js b/src/utils/theme/colors.js new file mode 100644 index 0000000..fbdbf12 --- /dev/null +++ b/src/utils/theme/colors.js @@ -0,0 +1,47 @@ +const colors = { + gray: { + 25: "#FCFCFD", + 50: "#F9FAFB", + 100: "#F2F4F7", + 200: "#E4E7EC", + 300: "#D0D5DD", + 400: "#98A2B3", + 500: "#667085", + 600: "#475467", + 700: "#344054", + 800: "#1D2939", + 900: "#101828", + }, + primary: { + 25: "#FAF8FF", + 50: "#F5F2FF", + 100: "#E6DFFF", + 200: "#B3A0FF", + 300: "#B3A0FF", + 400: "#9E88FF", + 500: "#7B61FF", + 600: "#5C46DB", + 700: "#4230B7", + 800: "#2C1E93", + 900: "#1C127A", + }, + sucess: { + 300: "#6CE9A6", + 400: "#32D583", + 500: "#12B76A", + 600: "#039855", + 700: "#027A48", + }, + warning: { + 25: "#FFFCF5", + 50: "#FFFAEB", + 100: "#FEF0C7", + 200: "#FEDF89", + }, + + // Custom Colors + thunder: "#ffd400", + fire: "#ff6a00", +} + +module.exports = { colors }; \ No newline at end of file diff --git a/src/utils/theme/index.js b/src/utils/theme/index.js new file mode 100644 index 0000000..45c08f9 --- /dev/null +++ b/src/utils/theme/index.js @@ -0,0 +1,11 @@ + +const { colors } = require('./colors') +const { MEDIA_QUERIES, screens } = require('./media_queries') + +const THEME = { + colors, + screens, + MEDIA_QUERIES +} + +module.exports = THEME diff --git a/src/utils/theme/index.ts b/src/utils/theme/index.ts deleted file mode 100644 index 2bc2db3..0000000 --- a/src/utils/theme/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * as THEME from './media_queries' - -const THEME = {} - - -export default THEME; \ No newline at end of file diff --git a/src/utils/theme/media_queries.js b/src/utils/theme/media_queries.js index e41f09d..ca2c678 100644 --- a/src/utils/theme/media_queries.js +++ b/src/utils/theme/media_queries.js @@ -1,4 +1,4 @@ -export const screens = { +const screens = { sm: 640, md: 768, lg: 1024, @@ -6,9 +6,14 @@ export const screens = { '2xl': 1536, } -export const MEDIA_QUERIES = { +const MEDIA_QUERIES = { isSmall: `only screen and (min-width : ${screens.sm}px)`, isMedium: `only screen and (min-width : ${screens.md}px)`, isLarge: `only screen and (min-width : ${screens.lg}px)`, isXLarge: `only screen and (min-width : ${screens["2xl"]}px))`, +} + +module.exports = { + screens, + MEDIA_QUERIES } \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index 593fd99..731c3ce 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,3 +1,5 @@ +const THEME = require('./src/utils/theme') + module.exports = { mode: "jit", purge: [ @@ -10,51 +12,7 @@ module.exports = { darkMode: false, // or 'media' or 'class' theme: { extend: { - colors: { - gray: { - 25: "#FCFCFD", - 50: "#F9FAFB", - 100: "#F2F4F7", - 200: "#E4E7EC", - 300: "#D0D5DD", - 400: "#98A2B3", - 500: "#667085", - 600: "#475467", - 700: "#344054", - 800: "#1D2939", - 900: "#101828", - }, - primary: { - 25: "#FAF8FF", - 50: "#F5F2FF", - 100: "#E6DFFF", - 200: "#B3A0FF", - 300: "#B3A0FF", - 400: "#9E88FF", - 500: "#7B61FF", - 600: "#5C46DB", - 700: "#4230B7", - 800: "#2C1E93", - 900: "#1C127A", - }, - sucess: { - 300: "#6CE9A6", - 400: "#32D583", - 500: "#12B76A", - 600: "#039855", - 700: "#027A48", - }, - warning: { - 25: "#FFFCF5", - 50: "#FFFAEB", - 100: "#FEF0C7", - 200: "#FEDF89", - }, - - // Custom Colors - thunder: "#ffd400", - fire: "#ff6a00", - }, + colors: THEME.colors, boxShadow: { xs: "0px 1px 2px rgba(16, 24, 40, 0.05)", sm: