From e7308edd410b54fca68624ac5860d7d1c3d6eba8 Mon Sep 17 00:00:00 2001 From: amirhouieh Date: Thu, 27 Apr 2023 12:35:06 +0200 Subject: [PATCH 1/7] add layout and its interactions --- .idea/.gitignore | 5 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/lpe-frontend.iml | 12 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 + src/components/FilterTags/FilterTags.tsx | 58 ++++++++ src/components/FilterTags/index.ts | 1 + src/components/Header/index.ts | 1 - src/components/HeaderTags/HeaderTags.tsx | 52 ------- src/components/HeaderTags/index.ts | 1 - .../{Header/Header.tsx => Hero/Hero.tsx} | 16 +-- src/components/Hero/index.ts | 1 + src/components/Navbar/Navbar.tsx | 29 ++-- src/components/Navbar/NavbarFiller.tsx | 5 + src/components/Search/Search.module.css | 8 -- src/components/Search/Search.tsx | 12 -- src/components/Search/index.ts | 1 - src/components/Searchbar/Search.module.css | 11 ++ src/components/Searchbar/Searchbar.tsx | 130 ++++++++++++++++++ .../Searchbar/SearchbarContainer.tsx | 58 ++++++++ src/components/Searchbar/index.ts | 1 + src/configs/copy.configs.ts | 20 +++ src/configs/ui.configs.ts | 3 + src/layouts/ArticleLayout/Article.layout.tsx | 20 +++ src/layouts/ArticleLayout/index.ts | 1 + src/layouts/DefaultLayout/Default.layout.tsx | 22 +++ src/layouts/DefaultLayout/index.ts | 1 + src/layouts/HeaderLayout/Header.layout.tsx | 17 --- src/layouts/HeaderLayout/index.ts | 1 - src/pages/_app.tsx | 32 +++-- src/pages/article/[:slug].tsx | 14 ++ src/pages/index.tsx | 16 +-- src/styles/globals.css | 107 -------------- src/types/ui.types.ts | 4 + src/utils/.placeholder | 0 src/utils/general.utils.ts | 1 + src/utils/ui.utils.ts | 59 ++++++++ 37 files changed, 496 insertions(+), 244 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/lpe-frontend.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 src/components/FilterTags/FilterTags.tsx create mode 100644 src/components/FilterTags/index.ts delete mode 100644 src/components/Header/index.ts delete mode 100644 src/components/HeaderTags/HeaderTags.tsx delete mode 100644 src/components/HeaderTags/index.ts rename src/components/{Header/Header.tsx => Hero/Hero.tsx} (77%) create mode 100644 src/components/Hero/index.ts create mode 100644 src/components/Navbar/NavbarFiller.tsx delete mode 100644 src/components/Search/Search.module.css delete mode 100644 src/components/Search/Search.tsx delete mode 100644 src/components/Search/index.ts create mode 100644 src/components/Searchbar/Search.module.css create mode 100644 src/components/Searchbar/Searchbar.tsx create mode 100644 src/components/Searchbar/SearchbarContainer.tsx create mode 100644 src/components/Searchbar/index.ts create mode 100644 src/configs/copy.configs.ts create mode 100644 src/configs/ui.configs.ts create mode 100644 src/layouts/ArticleLayout/Article.layout.tsx create mode 100644 src/layouts/ArticleLayout/index.ts create mode 100644 src/layouts/DefaultLayout/Default.layout.tsx create mode 100644 src/layouts/DefaultLayout/index.ts delete mode 100644 src/layouts/HeaderLayout/Header.layout.tsx delete mode 100644 src/layouts/HeaderLayout/index.ts create mode 100644 src/pages/article/[:slug].tsx create mode 100644 src/types/ui.types.ts delete mode 100644 src/utils/.placeholder create mode 100644 src/utils/general.utils.ts create mode 100644 src/utils/ui.utils.ts diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/lpe-frontend.iml b/.idea/lpe-frontend.iml new file mode 100644 index 0000000..0c8867d --- /dev/null +++ b/.idea/lpe-frontend.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c098ab5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/components/FilterTags/FilterTags.tsx b/src/components/FilterTags/FilterTags.tsx new file mode 100644 index 0000000..f64ed11 --- /dev/null +++ b/src/components/FilterTags/FilterTags.tsx @@ -0,0 +1,58 @@ +import { Tag } from '@acid-info/lsd-react' +import styled from '@emotion/styled' +import { useState } from 'react' +import { nope } from '@/utils/general.utils' + +type FilterTagsProps = { + tags: string[] + selectedTags: string[] + onTagClick?: (tag: string) => void +} + +export default function FilterTags(props: FilterTagsProps) { + const { tags = [], onTagClick = nope, selectedTags } = props + return ( + + + {tags.map((tag, index) => ( + onTagClick(tag)} + selected={selectedTags.includes(tag)} + variant={selectedTags.includes(tag) ? 'filled' : 'outlined'} + > + {tag} + + ))} + + + ) +} + +const Container = styled.div` + padding: 8px 0; +` + +const Tags = styled.div` + display: flex; + gap: 8px; + overflow-x: auto; + padding-right: 14px; + + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + + &::-webkit-scrollbar { + display: none; + } + + > *:first-child { + margin-left: 14px; + } + + > * { + white-space: nowrap; + } +` diff --git a/src/components/FilterTags/index.ts b/src/components/FilterTags/index.ts new file mode 100644 index 0000000..06b8e87 --- /dev/null +++ b/src/components/FilterTags/index.ts @@ -0,0 +1 @@ +export { default as FilterTags } from './HeaderTags' diff --git a/src/components/Header/index.ts b/src/components/Header/index.ts deleted file mode 100644 index 2d31985..0000000 --- a/src/components/Header/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Header } from './Header'; \ No newline at end of file diff --git a/src/components/HeaderTags/HeaderTags.tsx b/src/components/HeaderTags/HeaderTags.tsx deleted file mode 100644 index 3e3ad9c..0000000 --- a/src/components/HeaderTags/HeaderTags.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Tag } from "@acid-info/lsd-react"; -import styled from "@emotion/styled"; - -export default function Header() { - return ( - - - - Privacy - - - Security - - - Liberty - - - Censorship - - - Decentralization - - - Openness / inclusivity - - - Innovation - - - Interview - - - Podcast - - - Law - - - - ); -} - -const Container = styled.div` - padding: 16px 0 16px 16px; -`; - -const Tags = styled.div` - display: flex; - gap: 8px; - overflow-x: auto; - padding-right: 16px; -`; diff --git a/src/components/HeaderTags/index.ts b/src/components/HeaderTags/index.ts deleted file mode 100644 index f80bc45..0000000 --- a/src/components/HeaderTags/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as HeaderTags } from './HeaderTags'; \ No newline at end of file diff --git a/src/components/Header/Header.tsx b/src/components/Hero/Hero.tsx similarity index 77% rename from src/components/Header/Header.tsx rename to src/components/Hero/Hero.tsx index d257254..ffa0c3b 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Hero/Hero.tsx @@ -1,11 +1,11 @@ -import { Typography } from "@acid-info/lsd-react"; -import styled from "@emotion/styled"; +import { Typography } from '@acid-info/lsd-react' +import styled from '@emotion/styled' -export default function Header() { +export default function Hero() { return ( - LOGOS →{" "} + LOGOS →{' '} PRESS ENGINE @@ -14,17 +14,17 @@ export default function Header() { Blog with media written by Logos members - ); + ) } const Container = styled.div` padding: 16px 16px 8px 16px; -`; +` const Title = styled(Typography)` white-space: nowrap; -`; +` const Description = styled(Typography)` margin-top: 6px; -`; +` diff --git a/src/components/Hero/index.ts b/src/components/Hero/index.ts new file mode 100644 index 0000000..a3465b7 --- /dev/null +++ b/src/components/Hero/index.ts @@ -0,0 +1 @@ +export { default as Hero } from './Hero' diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 596940d..489c292 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -1,12 +1,12 @@ -import styled from "@emotion/styled"; -import { LogosIcon } from "../icons/LogosIcon"; -import { IconButton, Typography } from "@acid-info/lsd-react"; -import { MoonIcon } from "../icons/MoonIcon"; -import { SunIcon } from "../icons/SunIcon"; +import styled from '@emotion/styled' +import { LogosIcon } from '../icons/LogosIcon' +import { IconButton, Typography } from '@acid-info/lsd-react' +import { MoonIcon } from '../icons/MoonIcon' +import { SunIcon } from '../icons/SunIcon' interface NavbarProps { - isDark: boolean; - toggle: () => void; + isDark: boolean + toggle: () => void } export default function Navbar({ isDark, toggle }: NavbarProps) { @@ -22,22 +22,27 @@ export default function Navbar({ isDark, toggle }: NavbarProps) { - ); + ) } -const Container = styled.div` +const Container = styled.nav` display: flex; padding: 8px; align-items: center; justify-content: space-between; border-bottom: 1px solid rgb(var(--lsd-theme-primary)); -`; + position: fixed; + top: 0; + width: calc(100% - 16px); + background: rgb(var(--lsd-surface-primary)); + z-index: 100; +` const Icons = styled.div` display: flex; align-items: center; -`; +` const Selector = styled(IconButton)` border-left: none; -`; +` diff --git a/src/components/Navbar/NavbarFiller.tsx b/src/components/Navbar/NavbarFiller.tsx new file mode 100644 index 0000000..724707e --- /dev/null +++ b/src/components/Navbar/NavbarFiller.tsx @@ -0,0 +1,5 @@ +import styled from '@emotion/styled' + +export const NavbarFiller = styled.div` + height: var(--lpe-nav-rendered-height); +` diff --git a/src/components/Search/Search.module.css b/src/components/Search/Search.module.css deleted file mode 100644 index ba92798..0000000 --- a/src/components/Search/Search.module.css +++ /dev/null @@ -1,8 +0,0 @@ -.searchBox { - width: 100% !important; -} - -.searchBox > div { - border-left: none !important; - border-right: none !important; -} \ No newline at end of file diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx deleted file mode 100644 index 97763b6..0000000 --- a/src/components/Search/Search.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { Autocomplete } from "@acid-info/lsd-react"; -import styles from "./Search.module.css"; - -export default function Search() { - return ( - - ); -} diff --git a/src/components/Search/index.ts b/src/components/Search/index.ts deleted file mode 100644 index 5f65bc8..0000000 --- a/src/components/Search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Search } from './Search'; \ No newline at end of file diff --git a/src/components/Searchbar/Search.module.css b/src/components/Searchbar/Search.module.css new file mode 100644 index 0000000..71bfef8 --- /dev/null +++ b/src/components/Searchbar/Search.module.css @@ -0,0 +1,11 @@ +.searchBox { + width: 100% !important; +} + +.active::placeholder{ + /*opacity: 1 !important;*/ +} + +.searchBox > div { + border: none !important; +} diff --git a/src/components/Searchbar/Searchbar.tsx b/src/components/Searchbar/Searchbar.tsx new file mode 100644 index 0000000..1f03aaa --- /dev/null +++ b/src/components/Searchbar/Searchbar.tsx @@ -0,0 +1,130 @@ +import { Autocomplete } from '@acid-info/lsd-react' +import styles from './Search.module.css' +import { SearchbarContainer } from '@/components/Searchbar/SearchbarContainer' +import { copyConfigs } from '@/configs/copy.configs' +import { ESearchScope } from '@/types/ui.types' +import React, { useCallback, useEffect, useState } from 'react' +import FilterTags from '@/components/FilterTags/FilterTags' +import styled from '@emotion/styled' + +export type SearchbarProps = { + searchScope?: ESearchScope +} + +export default function Searchbar(props: SearchbarProps) { + const { searchScope = ESearchScope.GLOBAL } = props + + const [active, setActive] = useState(false) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(false) + + const [query, setQuery] = useState(undefined) + const [filterTags, setFilterTags] = useState([]) + + const performSearch = () => { + console.log('performing search', query, filterTags) + if (!validateSearch()) return + } + + useEffect(() => { + performSearch() + }, [filterTags]) + + const handleTagClick = (tag: string) => { + let newSelectedTags = [...filterTags] + if (newSelectedTags.includes(tag)) { + newSelectedTags = newSelectedTags.filter((t) => t !== tag) + } else { + newSelectedTags.push(tag) + } + setFilterTags(newSelectedTags) + } + + const handleEnter = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + performSearch() + } + } + + const validateSearch = () => { + return (query !== undefined && query.length > 0) || filterTags.length > 0 + } + + const isCollapsed = validateSearch() && !active + + const constructCollapseText = () => { + let txt = '' + if (query !== undefined && query.length > 0) { + txt += query + } + if (filterTags.length > 0) { + if (txt.length > 0) txt += ' . ' + txt += `${filterTags.map((t) => `[${t}]`).join(',')}` + } + return txt + } + + return ( + setActive(false)}> + setActive(true)} + inputProps={{ + onChange: (e) => setQuery(e.target.value), + onKeyUp: (e) => handleEnter(e), + className: isCollapsed ? styles.active : '', + }} + /> + + + + + setActive(true)} + > + {constructCollapseText()} + + + ) +} + +const TagsWrapper = styled.div` + transition: height 250ms ease-in-out; + overflow: hidden; + height: 0; + + &.active { + height: 45px; + } +` + +const Collapsed = styled.div` + background: rgb(var(--lsd-surface-primary)); + padding: 8px 14px; + width: calc(90% - 28px); + position: absolute; + z-index: auto; + + top: -100%; + left: 0; + + font-size: 14px; + + transition: top 250ms ease-in-out; + + &.enabled { + top: 0; + } +` diff --git a/src/components/Searchbar/SearchbarContainer.tsx b/src/components/Searchbar/SearchbarContainer.tsx new file mode 100644 index 0000000..2082909 --- /dev/null +++ b/src/components/Searchbar/SearchbarContainer.tsx @@ -0,0 +1,58 @@ +import styled from '@emotion/styled' +import { uiConfigs } from '@/configs/ui.configs' +import { useIsScrolling, useOutsideClick, useSticky } from '@/utils/ui.utils' +import { PropsWithChildren, useEffect } from 'react' +import { nope } from '@/utils/general.utils' + +type Props = PropsWithChildren<{ + onUnfocus?: () => void +}> + +export function SearchbarContainer({ children, onUnfocus = nope }: Props) { + const { sticky, stickyRef, height } = useSticky( + uiConfigs.navbarRenderedHeight, + ) + const { isOutside } = useOutsideClick(stickyRef) + const isScrolling = useIsScrolling() + + useEffect(() => { + if (isOutside && onUnfocus) { + onUnfocus() + } + if (isScrolling && onUnfocus) { + console.log('scrolling', isScrolling) + onUnfocus() + } + }, [isOutside, stickyRef, isScrolling]) + + return ( + <> + + {children} + +
+ + ) +} + +const SearchBarWrapper = styled.div` + display: block; + width: 100%; + background: rgb(var(--lsd-surface-primary)); + border-bottom: 1px solid rgb(var(--lsd-border-primary)); + border-top: 1px solid rgb(var(--lsd-border-primary)); + transition: all 0.2s ease-in-out; + position: relative; + + overflow: hidden; + + &.sticky { + position: fixed; + top: ${uiConfigs.navbarRenderedHeight - 1}px; + z-index: 100; + } +` diff --git a/src/components/Searchbar/index.ts b/src/components/Searchbar/index.ts new file mode 100644 index 0000000..6ece6a9 --- /dev/null +++ b/src/components/Searchbar/index.ts @@ -0,0 +1 @@ +export { default as Searchbar } from './Searchbar' diff --git a/src/configs/copy.configs.ts b/src/configs/copy.configs.ts new file mode 100644 index 0000000..9fe379c --- /dev/null +++ b/src/configs/copy.configs.ts @@ -0,0 +1,20 @@ +export const copyConfigs = { + search: { + searchbarPlaceholders: { + global: () => 'Search through the LPE posts...', + article: () => `Search through the article`, + }, + filterTags: [ + 'Privacy', + 'Security', + 'Liberty', + 'Censorship', + 'Decentralization', + 'Openness / inclusivity', + 'Innovation', + 'Interview', + 'Podcast', + 'Law', + ], + }, +} diff --git a/src/configs/ui.configs.ts b/src/configs/ui.configs.ts new file mode 100644 index 0000000..1036bc5 --- /dev/null +++ b/src/configs/ui.configs.ts @@ -0,0 +1,3 @@ +export const uiConfigs = { + navbarRenderedHeight: 45, +} diff --git a/src/layouts/ArticleLayout/Article.layout.tsx b/src/layouts/ArticleLayout/Article.layout.tsx new file mode 100644 index 0000000..0479971 --- /dev/null +++ b/src/layouts/ArticleLayout/Article.layout.tsx @@ -0,0 +1,20 @@ +import { Navbar } from '@/components/Navbar' +import useIsDarkState from '@/states/isDarkState/isDarkState' +import { PropsWithChildren } from 'react' +import { NavbarFiller } from '@/components/Navbar/NavbarFiller' +import { Searchbar } from '@/components/Searchbar' +import { ESearchScope } from '@/types/ui.types' + +export default function ArticleLayout(props: PropsWithChildren) { + const isDarkState = useIsDarkState() + return ( + <> +
+ + + +
+
{props.children}
+ + ) +} diff --git a/src/layouts/ArticleLayout/index.ts b/src/layouts/ArticleLayout/index.ts new file mode 100644 index 0000000..a30058d --- /dev/null +++ b/src/layouts/ArticleLayout/index.ts @@ -0,0 +1 @@ +export { default as ArticleLayout } from './Article.layout' diff --git a/src/layouts/DefaultLayout/Default.layout.tsx b/src/layouts/DefaultLayout/Default.layout.tsx new file mode 100644 index 0000000..7e1cf14 --- /dev/null +++ b/src/layouts/DefaultLayout/Default.layout.tsx @@ -0,0 +1,22 @@ +import { Navbar } from '@/components/Navbar' +import useIsDarkState from '@/states/isDarkState/isDarkState' +import { PropsWithChildren } from 'react' +import { Hero } from '@/components/Hero' +import { NavbarFiller } from '@/components/Navbar/NavbarFiller' +import { Searchbar } from '@/components/Searchbar' + +export default function DefaultLayout(props: PropsWithChildren) { + const isDarkState = useIsDarkState() + + return ( + <> +
+ + + + +
+
{props.children}
+ + ) +} diff --git a/src/layouts/DefaultLayout/index.ts b/src/layouts/DefaultLayout/index.ts new file mode 100644 index 0000000..c58a2b6 --- /dev/null +++ b/src/layouts/DefaultLayout/index.ts @@ -0,0 +1 @@ +export { default as DefaultLayout } from './Default.layout' diff --git a/src/layouts/HeaderLayout/Header.layout.tsx b/src/layouts/HeaderLayout/Header.layout.tsx deleted file mode 100644 index 3f9efb7..0000000 --- a/src/layouts/HeaderLayout/Header.layout.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Header } from "@/components/Header"; -import { HeaderTags } from "@/components/HeaderTags"; -import { Navbar } from "@/components/Navbar"; -import { Search } from "@/components/Search"; -import useIsDarkState from "@/states/isDarkState/isDarkState"; - -export default function HeaderLayout() { - const isDarkState = useIsDarkState(); - return ( - <> - -
- - - - ); -} diff --git a/src/layouts/HeaderLayout/index.ts b/src/layouts/HeaderLayout/index.ts deleted file mode 100644 index aababef..0000000 --- a/src/layouts/HeaderLayout/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as HeaderLayout } from './Header.layout'; \ No newline at end of file diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4e15ff0..1b6048e 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,17 +1,27 @@ -import useIsDarkState from "@/states/isDarkState/isDarkState"; -import { defaultThemes, ThemeProvider } from "@acid-info/lsd-react"; -import { css, Global } from "@emotion/react"; -import type { AppProps } from "next/app"; -import Head from "next/head"; +import useIsDarkState from '@/states/isDarkState/isDarkState' +import { defaultThemes, ThemeProvider } from '@acid-info/lsd-react' +import { css, Global } from '@emotion/react' +import type { AppProps } from 'next/app' +import Head from 'next/head' +import { uiConfigs } from '@/configs/ui.configs' +import { DefaultLayout } from '@/layouts/DefaultLayout' export default function App({ Component, pageProps }: AppProps) { - const isDark = useIsDarkState().get(); + const isDark = useIsDarkState().get() + + //TODO: fix this + //@ts-ignore + const getLayout = + Component.getLayout || ((page) => {page}) return ( - - + Acid + + {getLayout()} - ); + ) } diff --git a/src/pages/article/[:slug].tsx b/src/pages/article/[:slug].tsx new file mode 100644 index 0000000..ccb7c14 --- /dev/null +++ b/src/pages/article/[:slug].tsx @@ -0,0 +1,14 @@ +import { NextPage } from 'next' +import { ArticleLayout } from '@/layouts/ArticleLayout' + +type Props = NextPage<{}> + +const ArticlePage = (props: Props) => { + return
article
+} + +ArticlePage.getLayout = function getLayout(page) { + return {page} +} + +export default ArticlePage diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 42cab72..0a3fb38 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,23 +1,9 @@ import PostsDemo from '@/components/Post/PostsDemo' -import { HeaderLayout } from '@/layouts/HeaderLayout' -import Head from 'next/head' export default function Home() { return ( <> - - Logos Press Engine - - - - -
- - -
+ ) } diff --git a/src/styles/globals.css b/src/styles/globals.css index d4f491e..e69de29 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -1,107 +0,0 @@ -:root { - --max-width: 1100px; - --border-radius: 12px; - --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', - 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', - 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; - - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; - - --primary-glow: conic-gradient( - from 180deg at 50% 50%, - #16abff33 0deg, - #0885ff33 55deg, - #54d6ff33 120deg, - #0071ff33 160deg, - transparent 360deg - ); - --secondary-glow: radial-gradient( - rgba(255, 255, 255, 1), - rgba(255, 255, 255, 0) - ); - - --tile-start-rgb: 239, 245, 249; - --tile-end-rgb: 228, 232, 233; - --tile-border: conic-gradient( - #00000080, - #00000040, - #00000030, - #00000020, - #00000010, - #00000010, - #00000080 - ); - - --callout-rgb: 238, 240, 241; - --callout-border-rgb: 172, 175, 176; - --card-rgb: 180, 185, 188; - --card-border-rgb: 131, 134, 135; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - - --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); - --secondary-glow: linear-gradient( - to bottom right, - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0.3) - ); - - --tile-start-rgb: 2, 13, 46; - --tile-end-rgb: 2, 5, 19; - --tile-border: conic-gradient( - #ffffff80, - #ffffff40, - #ffffff30, - #ffffff20, - #ffffff10, - #ffffff10, - #ffffff80 - ); - - --callout-rgb: 20, 20, 20; - --callout-border-rgb: 108, 108, 108; - --card-rgb: 100, 100, 100; - --card-border-rgb: 200, 200, 200; - } -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); -} - -a { - color: inherit; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } -} diff --git a/src/types/ui.types.ts b/src/types/ui.types.ts new file mode 100644 index 0000000..6ef6e21 --- /dev/null +++ b/src/types/ui.types.ts @@ -0,0 +1,4 @@ +export enum ESearchScope { + GLOBAL = 'global', + ARTICLE = 'article', +} diff --git a/src/utils/.placeholder b/src/utils/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/general.utils.ts b/src/utils/general.utils.ts new file mode 100644 index 0000000..3b10ad8 --- /dev/null +++ b/src/utils/general.utils.ts @@ -0,0 +1 @@ +export const nope = (...args: any) => {} diff --git a/src/utils/ui.utils.ts b/src/utils/ui.utils.ts new file mode 100644 index 0000000..46be6a1 --- /dev/null +++ b/src/utils/ui.utils.ts @@ -0,0 +1,59 @@ +import { useEffect, useRef, useState } from 'react' + +export const useSticky = (dy: number = 0) => { + const stickyRef = useRef(null) + const [sticky, setSticky] = useState(false) + const [offset, setOffset] = useState(0) + const [height, setHeight] = useState(0) + + useEffect(() => { + if (!stickyRef.current) { + return + } + setOffset(stickyRef.current.offsetTop) + setHeight(stickyRef.current.clientHeight) + }, [stickyRef, setOffset]) + + useEffect(() => { + const handleScroll = () => { + if (!stickyRef.current) { + return + } + setSticky(window.scrollY > offset - dy) + } + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [dy, setSticky, stickyRef, offset]) + + return { stickyRef, sticky, height: sticky ? height : 0 } +} + +export const useOutsideClick = (ref) => { + const [isOutside, setIsOutside] = useState(false) + useEffect(() => { + function handleClickOutside(event) { + setIsOutside(ref.current && !ref.current.contains(event.target)) + } + document.addEventListener('mousedown', handleClickOutside) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, [ref]) + + return { isOutside } +} + +export const useIsScrolling = () => { + const [isScrolling, setIsScrolling] = useState(false) + useEffect(() => { + let timeout + function handleScroll() { + setIsScrolling(true) + clearTimeout(timeout) + timeout = setTimeout(() => setIsScrolling(false), 100) + } + window.addEventListener('scroll', handleScroll) + return () => window.removeEventListener('scroll', handleScroll) + }, [setIsScrolling]) + return isScrolling +} From 1afb84e6ee32520ddd753449192e8743bd062c22 Mon Sep 17 00:00:00 2001 From: amirhouieh Date: Thu, 27 Apr 2023 12:35:38 +0200 Subject: [PATCH 2/7] remove idea --- .gitignore | 1 + .idea/.gitignore | 5 ----- .idea/inspectionProfiles/Project_Default.xml | 6 ------ .idea/lpe-frontend.iml | 12 ------------ .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 6 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/lpe-frontend.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore index 8f322f0..1403e90 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index b58b603..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 03d9549..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/lpe-frontend.iml b/.idea/lpe-frontend.iml deleted file mode 100644 index 0c8867d..0000000 --- a/.idea/lpe-frontend.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index c098ab5..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 79c9e25a0768799d9697d946d3ac7fcabf1447c2 Mon Sep 17 00:00:00 2001 From: amirhouieh Date: Thu, 27 Apr 2023 12:36:12 +0200 Subject: [PATCH 3/7] add idea to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1403e90..fb30cbd 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ yarn-error.log* *.tsbuildinfo next-env.d.ts +.idea From 7b8447fe9884343d339e49e7057c35b352c1e1f7 Mon Sep 17 00:00:00 2001 From: amirhouieh Date: Thu, 27 Apr 2023 14:55:23 +0200 Subject: [PATCH 4/7] add search action buttons --- src/components/FilterTags/FilterTags.tsx | 1 - src/components/Searchbar/Search.module.css | 16 ++- src/components/Searchbar/Searchbar.tsx | 109 ++++++++++++------ .../Searchbar/SearchbarContainer.tsx | 2 +- 4 files changed, 87 insertions(+), 41 deletions(-) diff --git a/src/components/FilterTags/FilterTags.tsx b/src/components/FilterTags/FilterTags.tsx index f64ed11..053eb1e 100644 --- a/src/components/FilterTags/FilterTags.tsx +++ b/src/components/FilterTags/FilterTags.tsx @@ -20,7 +20,6 @@ export default function FilterTags(props: FilterTagsProps) { disabled={false} key={index} onClick={() => onTagClick(tag)} - selected={selectedTags.includes(tag)} variant={selectedTags.includes(tag) ? 'filled' : 'outlined'} > {tag} diff --git a/src/components/Searchbar/Search.module.css b/src/components/Searchbar/Search.module.css index 71bfef8..be32d44 100644 --- a/src/components/Searchbar/Search.module.css +++ b/src/components/Searchbar/Search.module.css @@ -2,10 +2,16 @@ width: 100% !important; } -.active::placeholder{ - /*opacity: 1 !important;*/ -} - -.searchBox > div { +.searchButton{ + border: none !important; +} + +/*if we use textfield*/ +/*.searchBox{*/ +/* border: none !important;*/ +/*}*/ + +/*if we use autocompete */ +.searchBox > div{ border: none !important; } diff --git a/src/components/Searchbar/Searchbar.tsx b/src/components/Searchbar/Searchbar.tsx index 1f03aaa..fdcdd22 100644 --- a/src/components/Searchbar/Searchbar.tsx +++ b/src/components/Searchbar/Searchbar.tsx @@ -1,4 +1,10 @@ -import { Autocomplete } from '@acid-info/lsd-react' +import { + TextField, + Autocomplete, + IconButton, + SearchIcon, + CloseIcon, +} from '@acid-info/lsd-react' import styles from './Search.module.css' import { SearchbarContainer } from '@/components/Searchbar/SearchbarContainer' import { copyConfigs } from '@/configs/copy.configs' @@ -21,14 +27,23 @@ export default function Searchbar(props: SearchbarProps) { const [query, setQuery] = useState(undefined) const [filterTags, setFilterTags] = useState([]) - const performSearch = () => { - console.log('performing search', query, filterTags) + const validateSearch = useCallback(() => { + return (query !== undefined && query.length > 0) || filterTags.length > 0 + }, [query, filterTags]) + + const performSearch = useCallback(() => { if (!validateSearch()) return - } + }, [validateSearch]) + + const performClear = useCallback(() => { + // TODO: clear input.value seems to be not working. When set to undefined, the input value is still there. + setQuery(undefined) + setFilterTags([]) + }, [setQuery, setFilterTags]) useEffect(() => { performSearch() - }, [filterTags]) + }, [filterTags, performSearch]) const handleTagClick = (tag: string) => { let newSelectedTags = [...filterTags] @@ -46,42 +61,52 @@ export default function Searchbar(props: SearchbarProps) { } } - const validateSearch = () => { - return (query !== undefined && query.length > 0) || filterTags.length > 0 - } - - const isCollapsed = validateSearch() && !active - const constructCollapseText = () => { let txt = '' if (query !== undefined && query.length > 0) { - txt += query + txt += `${query}` } if (filterTags.length > 0) { - if (txt.length > 0) txt += ' . ' - txt += `${filterTags.map((t) => `[${t}]`).join(',')}` + if (txt.length > 0) txt += ' . ' + txt += `${filterTags.map((t) => `[${t}]`).join(' ')}` } return txt } + const isCollapsed = validateSearch() && !active + return ( setActive(false)}> - setActive(true)} - inputProps={{ - onChange: (e) => setQuery(e.target.value), - onKeyUp: (e) => handleEnter(e), - className: isCollapsed ? styles.active : '', - }} - /> + + setActive(true)} + clearButton={false} + inputProps={{ + onChange: (e) => { + setQuery(e.target.value) + console.log(e.target.value) + }, + onKeyUp: (e) => handleEnter(e), + }} + /> +
+ + validateSearch() ? performClear() : performSearch() + } + > + {validateSearch() ? : } + +
+
- setActive(true)} - > - {constructCollapseText()} - + dangerouslySetInnerHTML={{ __html: constructCollapseText() }} + >
) } @@ -111,6 +134,8 @@ const TagsWrapper = styled.div` ` const Collapsed = styled.div` + display: flex; + align-items: baseline; background: rgb(var(--lsd-surface-primary)); padding: 8px 14px; width: calc(90% - 28px); @@ -127,4 +152,20 @@ const Collapsed = styled.div` &.enabled { top: 0; } + > * { + margin-right: 4px; + } + > *:not(:first-child) { + margin-left: 4px; + } + + b { + transform: translateY(-2px); + } +` +const SearchBox = styled.div` + display: flex; + align-items: center; + width: 100%; + height: 100%; ` diff --git a/src/components/Searchbar/SearchbarContainer.tsx b/src/components/Searchbar/SearchbarContainer.tsx index 2082909..755be2d 100644 --- a/src/components/Searchbar/SearchbarContainer.tsx +++ b/src/components/Searchbar/SearchbarContainer.tsx @@ -23,7 +23,7 @@ export function SearchbarContainer({ children, onUnfocus = nope }: Props) { console.log('scrolling', isScrolling) onUnfocus() } - }, [isOutside, stickyRef, isScrolling]) + }, [isOutside, stickyRef, isScrolling, onUnfocus]) return ( <> From 76559d9537e357585c2d361b35025150fcf924a9 Mon Sep 17 00:00:00 2001 From: amirhouieh Date: Thu, 27 Apr 2023 15:31:38 +0200 Subject: [PATCH 5/7] fix input in search bar --- src/components/Searchbar/Search.module.css | 8 +----- src/components/Searchbar/Searchbar.tsx | 30 ++++++++++------------ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/components/Searchbar/Search.module.css b/src/components/Searchbar/Search.module.css index be32d44..eadf012 100644 --- a/src/components/Searchbar/Search.module.css +++ b/src/components/Searchbar/Search.module.css @@ -6,12 +6,6 @@ border: none !important; } -/*if we use textfield*/ -/*.searchBox{*/ -/* border: none !important;*/ -/*}*/ - -/*if we use autocompete */ -.searchBox > div{ +.searchBox{ border: none !important; } diff --git a/src/components/Searchbar/Searchbar.tsx b/src/components/Searchbar/Searchbar.tsx index fdcdd22..9983b0a 100644 --- a/src/components/Searchbar/Searchbar.tsx +++ b/src/components/Searchbar/Searchbar.tsx @@ -24,11 +24,11 @@ export default function Searchbar(props: SearchbarProps) { const [loading, setLoading] = useState(false) const [error, setError] = useState(false) - const [query, setQuery] = useState(undefined) + const [query, setQuery] = useState('') const [filterTags, setFilterTags] = useState([]) const validateSearch = useCallback(() => { - return (query !== undefined && query.length > 0) || filterTags.length > 0 + return query.length > 0 || filterTags.length > 0 }, [query, filterTags]) const performSearch = useCallback(() => { @@ -37,7 +37,7 @@ export default function Searchbar(props: SearchbarProps) { const performClear = useCallback(() => { // TODO: clear input.value seems to be not working. When set to undefined, the input value is still there. - setQuery(undefined) + setQuery('') setFilterTags([]) }, [setQuery, setFilterTags]) @@ -75,25 +75,21 @@ export default function Searchbar(props: SearchbarProps) { const isCollapsed = validateSearch() && !active + const placeholder = + searchScope === ESearchScope.GLOBAL + ? copyConfigs.search.searchbarPlaceholders.global() + : copyConfigs.search.searchbarPlaceholders.article() + return ( setActive(false)}> - setActive(true)} - clearButton={false} - inputProps={{ - onChange: (e) => { - setQuery(e.target.value) - console.log(e.target.value) - }, - onKeyUp: (e) => handleEnter(e), + onChange={(e) => { + setQuery(e.target.value) }} />
@@ -118,7 +114,7 @@ export default function Searchbar(props: SearchbarProps) { className={isCollapsed ? 'enabled' : ''} onClick={() => setActive(true)} dangerouslySetInnerHTML={{ __html: constructCollapseText() }} - > + /> ) } From 316fc9d0d8f508dedac8d7606c73fd89cce61acf Mon Sep 17 00:00:00 2001 From: jinhojang6 Date: Tue, 25 Apr 2023 14:28:22 +0900 Subject: [PATCH 6/7] feat: implement post container component --- src/components/Post/PostsDemo.tsx | 79 ++++++++++++++----- src/components/Post/index.ts | 1 + .../PostContainer/PostContainer.tsx | 51 ++++++++++++ src/components/PostContainer/index.ts | 1 + 4 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 src/components/PostContainer/PostContainer.tsx create mode 100644 src/components/PostContainer/index.ts diff --git a/src/components/Post/PostsDemo.tsx b/src/components/Post/PostsDemo.tsx index f67cf9d..042fc0a 100644 --- a/src/components/Post/PostsDemo.tsx +++ b/src/components/Post/PostsDemo.tsx @@ -1,4 +1,5 @@ -import Post, { PostProps } from './Post' +import { PostContainer } from '../PostContainer' +import { PostProps } from './Post' const postsData: PostProps[] = [ { @@ -18,7 +19,7 @@ const postsData: PostProps[] = [ tags: ['Privacy', 'Security', 'Liberty'], }, { - aspectRatio: 'portrait', // different aspect ratio + aspectRatio: 'portrait', // different aspect ratio - portrait imageUrl: 'https://images.pexels.com/photos/4992820/pexels-photo-4992820.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2', date: new Date(), @@ -56,31 +57,67 @@ const postsData: PostProps[] = [ description: 'We built a pedal-powered generator and controller, which is practical to use as an energy source and exercise machine in a household -- and which you can integrate into a solar PV', }, + { + showImage: false, // without image + classType: 'article', + date: new Date(), + title: 'Satoshi breaks their silence: Inside the mind of the OG anon', + description: + "Bitcoin's creator reveals their feelings on privacy, CBDCs and their favorite NFT collection in an unprecedented interview with Acid.info", + author: 'Jason Freeman', + tags: ['Privacy', 'Security', 'Liberty'], + }, + { + aspectRatio: 'square', // square + imageUrl: + 'https://images.pexels.com/photos/6477673/pexels-photo-6477673.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2', + date: new Date(), + title: 'How to Build a Practical Household Bike Generator', + description: + 'We built a pedal-powered generator and controller, which is practical to use as an energy source and exercise machine in a household -- and which you can integrate into a solar PV', + author: 'Jason Freeman', + tags: ['Privacy', 'Security', 'Liberty'], + }, + { + // featured + imageUrl: + 'https://images.pexels.com/photos/6227715/pexels-photo-6227715.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2', + date: new Date(), + title: 'How to Build a Practical Household Bike Generator', + description: + 'We built a pedal-powered generator and controller, which is practical to use as an energy source and exercise machine in a household -- and which you can integrate into a solar PV', + author: 'Jason Freeman', + tags: ['Privacy', 'Security', 'Liberty'], + }, ] const PostsDemo = () => { return (
{/* For Demo purposes only. Use inline CSS and styled components temporarily */} -
- {postsData.map((post, index) => ( -
- -
- ))} -
+ + + + + +
) } diff --git a/src/components/Post/index.ts b/src/components/Post/index.ts index 1083f45..2d3d965 100644 --- a/src/components/Post/index.ts +++ b/src/components/Post/index.ts @@ -1,2 +1,3 @@ export { default as Post } from './Post' export { default as PostsDemo } from './PostsDemo' +export type { PostProps } from './Post' diff --git a/src/components/PostContainer/PostContainer.tsx b/src/components/PostContainer/PostContainer.tsx new file mode 100644 index 0000000..2923606 --- /dev/null +++ b/src/components/PostContainer/PostContainer.tsx @@ -0,0 +1,51 @@ +import { CommonProps } from '@acid-info/lsd-react/dist/utils/useCommonProps' +import styled from '@emotion/styled' +import { Post, PostProps } from '../Post' +import { Typography } from '@acid-info/lsd-react' + +export type PostContainerProps = CommonProps & + React.HTMLAttributes & { + title?: string + postsData: PostProps[] + } + +export default function PostContainer({ + title, + postsData, + ...props +}: PostContainerProps) { + return ( +
+ {title && ({title})} + + {postsData.map((post, index) => ( + + + + ))} + +
+ ) +} + +const Container = styled.div` + display: flex; + flex-direction: row; + padding: 16px; + gap: 24px; + + @media (max-width: 768px) { + // temporariy breakpoint + flex-direction: column; + } +` + +const PostWrapper = styled.div` + padding: 16px 0; + border-top: 1px solid rgb(var(--lsd-theme-primary)); + width: 100%; +` + +const Title = styled(Typography)` + padding: 0 16px; +` diff --git a/src/components/PostContainer/index.ts b/src/components/PostContainer/index.ts new file mode 100644 index 0000000..8ca9444 --- /dev/null +++ b/src/components/PostContainer/index.ts @@ -0,0 +1 @@ +export { default as PostContainer } from './PostContainer' From 7b01558f6ca6e9e85d16b6ceefb785ae445053d0 Mon Sep 17 00:00:00 2001 From: jinhojang6 Date: Fri, 28 Apr 2023 01:55:29 +0900 Subject: [PATCH 7/7] resolve merge conflicts --- src/components/FilterTags/FilterTags.tsx | 1 - src/components/FilterTags/index.ts | 2 +- src/components/Hero/Hero.tsx | 24 +++++++++++++++---- src/components/Navbar/Navbar.tsx | 20 ++++++++++++---- src/components/Post/Post.tsx | 2 +- .../PostContainer/PostContainer.tsx | 2 +- src/pages/_app.tsx | 21 ++++++++++++---- src/pages/article/[:slug].tsx | 3 ++- src/utils/ui.utils.ts | 17 ++++++++----- 9 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/components/FilterTags/FilterTags.tsx b/src/components/FilterTags/FilterTags.tsx index 053eb1e..962528d 100644 --- a/src/components/FilterTags/FilterTags.tsx +++ b/src/components/FilterTags/FilterTags.tsx @@ -1,6 +1,5 @@ import { Tag } from '@acid-info/lsd-react' import styled from '@emotion/styled' -import { useState } from 'react' import { nope } from '@/utils/general.utils' type FilterTagsProps = { diff --git a/src/components/FilterTags/index.ts b/src/components/FilterTags/index.ts index 06b8e87..4f7eb33 100644 --- a/src/components/FilterTags/index.ts +++ b/src/components/FilterTags/index.ts @@ -1 +1 @@ -export { default as FilterTags } from './HeaderTags' +export { default as FilterTags } from './FilterTags' diff --git a/src/components/Hero/Hero.tsx b/src/components/Hero/Hero.tsx index ffa0c3b..733e13d 100644 --- a/src/components/Hero/Hero.tsx +++ b/src/components/Hero/Hero.tsx @@ -4,12 +4,17 @@ import styled from '@emotion/styled' export default function Hero() { return ( - + LOGOS →{' '} - <Title genericFontFamily="serif" component="span" variant="h2"> + <Title + style={{ whiteSpace: 'nowrap' }} + genericFontFamily="serif" + component="span" + variant="h2" + > PRESS ENGINE - + Blog with media written by Logos members @@ -18,11 +23,22 @@ export default function Hero() { } const Container = styled.div` + display: flex; + flex-direction: column; + align-items: center; padding: 16px 16px 8px 16px; + + @media (max-width: 768px) { + align-items: flex-start; + } ` const Title = styled(Typography)` - white-space: nowrap; + // temporary breakpoint + @media (min-width: 1440px) { + padding-block: 16px; + font-size: 90px; + } ` const Description = styled(Typography)` diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 489c292..fefe2cd 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled' -import { LogosIcon } from '../icons/LogosIcon' import { IconButton, Typography } from '@acid-info/lsd-react' -import { MoonIcon } from '../icons/MoonIcon' -import { SunIcon } from '../icons/SunIcon' +import { LogosIcon } from '../Icons/LogosIcon' +import { SunIcon } from '../Icons/SunIcon' +import { MoonIcon } from '../Icons/MoonIcon' interface NavbarProps { isDark: boolean @@ -12,7 +12,9 @@ interface NavbarProps { export default function Navbar({ isDark, toggle }: NavbarProps) { return ( - + + + toggle()}> {isDark ? : } @@ -38,9 +40,19 @@ const Container = styled.nav` z-index: 100; ` +const LogosIconContainer = styled.div` + display: flex; + align-items: center; + margin-left: auto; + @media (max-width: 768px) { + margin-left: unset; + } +` + const Icons = styled.div` display: flex; align-items: center; + margin-left: auto; ` const Selector = styled(IconButton)` diff --git a/src/components/Post/Post.tsx b/src/components/Post/Post.tsx index 5ec3cc6..7ad990a 100644 --- a/src/components/Post/Post.tsx +++ b/src/components/Post/Post.tsx @@ -68,7 +68,7 @@ export default function Post({ {description} ), - [classType, description, size], + [classType, description], ) const _thumbnail = useMemo(() => { diff --git a/src/components/PostContainer/PostContainer.tsx b/src/components/PostContainer/PostContainer.tsx index 2923606..fbe4aac 100644 --- a/src/components/PostContainer/PostContainer.tsx +++ b/src/components/PostContainer/PostContainer.tsx @@ -34,8 +34,8 @@ const Container = styled.div` padding: 16px; gap: 24px; + // temporariy breakpoint @media (max-width: 768px) { - // temporariy breakpoint flex-direction: column; } ` diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 1b6048e..e2f0ab5 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -5,14 +5,27 @@ import type { AppProps } from 'next/app' import Head from 'next/head' import { uiConfigs } from '@/configs/ui.configs' import { DefaultLayout } from '@/layouts/DefaultLayout' +import { ReactNode } from 'react' +import { NextComponentType, NextPageContext } from 'next' -export default function App({ Component, pageProps }: AppProps) { +type NextLayoutComponentType

= NextComponentType< + NextPageContext, + any, + P +> & { + getLayout?: (page: ReactNode) => ReactNode +} + +type AppLayoutProps

= AppProps & { + Component: NextLayoutComponentType +} + +export default function App({ Component, pageProps }: AppLayoutProps) { const isDark = useIsDarkState().get() - //TODO: fix this - //@ts-ignore const getLayout = - Component.getLayout || ((page) => {page}) + Component.getLayout || + ((page: ReactNode) => {page}) return ( diff --git a/src/pages/article/[:slug].tsx b/src/pages/article/[:slug].tsx index ccb7c14..f820bd8 100644 --- a/src/pages/article/[:slug].tsx +++ b/src/pages/article/[:slug].tsx @@ -1,5 +1,6 @@ import { NextPage } from 'next' import { ArticleLayout } from '@/layouts/ArticleLayout' +import { ReactNode } from 'react' type Props = NextPage<{}> @@ -7,7 +8,7 @@ const ArticlePage = (props: Props) => { return

article
} -ArticlePage.getLayout = function getLayout(page) { +ArticlePage.getLayout = function getLayout(page: ReactNode) { return {page} } diff --git a/src/utils/ui.utils.ts b/src/utils/ui.utils.ts index 46be6a1..fcf9697 100644 --- a/src/utils/ui.utils.ts +++ b/src/utils/ui.utils.ts @@ -1,6 +1,6 @@ -import { useEffect, useRef, useState } from 'react' +import { RefObject, useEffect, useRef, useState } from 'react' -export const useSticky = (dy: number = 0) => { +export const useSticky = (dy: number = 0) => { const stickyRef = useRef(null) const [sticky, setSticky] = useState(false) const [offset, setOffset] = useState(0) @@ -28,13 +28,18 @@ export const useSticky = (dy: number = 0) => { return { stickyRef, sticky, height: sticky ? height : 0 } } -export const useOutsideClick = (ref) => { +export const useOutsideClick = ( + ref: RefObject, +) => { const [isOutside, setIsOutside] = useState(false) + useEffect(() => { - function handleClickOutside(event) { - setIsOutside(ref.current && !ref.current.contains(event.target)) + function handleClickOutside(event: any) { + const isOutside = !!(ref.current && !ref.current.contains(event.target)) + setIsOutside(isOutside) } document.addEventListener('mousedown', handleClickOutside) + return () => { document.removeEventListener('mousedown', handleClickOutside) } @@ -46,7 +51,7 @@ export const useOutsideClick = (ref) => { export const useIsScrolling = () => { const [isScrolling, setIsScrolling] = useState(false) useEffect(() => { - let timeout + let timeout: NodeJS.Timeout function handleScroll() { setIsScrolling(true) clearTimeout(timeout)