diff --git a/src/App.js b/src/App.js index 3fe644a..e64634f 100644 --- a/src/App.js +++ b/src/App.js @@ -2,9 +2,10 @@ import './App.css'; import React from 'react'; import { Route, Switch } from 'react-router-dom'; -import { AppHeader } from '@/features/layout/components'; +import { AppHeader } from '@/features/layout'; import { LandingPage } from '@/pages/landing'; import { PageNotFound } from '@/pages/page-not-found'; +import { ExploreMemes } from '@/pages/explore-memes'; import Templates from './components/Templates/Templates'; import MemeGenerator from './components/MemeGenerator/MemeGenerator'; import Personal from './components/PersonalPage/Personal'; @@ -27,7 +28,7 @@ function App() { - + diff --git a/src/components/dialog/dialog-body.jsx b/src/components/dialog/dialog-body.jsx index b4714e6..80981f2 100644 --- a/src/components/dialog/dialog-body.jsx +++ b/src/components/dialog/dialog-body.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { StyledDialogBody } from './dialog.style'; const DialogBody = ({ children, ...rest }) => { diff --git a/src/components/dialog/dialog-content.jsx b/src/components/dialog/dialog-content.jsx index d5014c5..022f27d 100644 --- a/src/components/dialog/dialog-content.jsx +++ b/src/components/dialog/dialog-content.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { StyledDialogContent } from './dialog.style'; const DialogContent = ({ children, ...rest }) => { diff --git a/src/components/dialog/dialog-footer-close-button.jsx b/src/components/dialog/dialog-footer-close-button.jsx index 763de7f..fc231ec 100644 --- a/src/components/dialog/dialog-footer-close-button.jsx +++ b/src/components/dialog/dialog-footer-close-button.jsx @@ -1,4 +1,4 @@ -import React, { forwardRef } from 'react'; +import { forwardRef } from 'react'; import { useDialogContext } from './dialog'; import { StyledDialogFooterCloseButton } from './dialog.style'; diff --git a/src/components/dialog/dialog-footer.jsx b/src/components/dialog/dialog-footer.jsx index 5d0d5f0..a24e3f4 100644 --- a/src/components/dialog/dialog-footer.jsx +++ b/src/components/dialog/dialog-footer.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { StyledDialogFooter } from './dialog.style'; const DialogFooter = ({ children, ...rest }) => { diff --git a/src/components/dialog/dialog-header.jsx b/src/components/dialog/dialog-header.jsx index c47652d..e1aaac8 100644 --- a/src/components/dialog/dialog-header.jsx +++ b/src/components/dialog/dialog-header.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { StyledDialogHeader } from './dialog.style'; const DialogHeader = ({ children, ...rest }) => { diff --git a/src/components/dialog/dialog-overlay.jsx b/src/components/dialog/dialog-overlay.jsx index 020d6bd..d8ab22e 100644 --- a/src/components/dialog/dialog-overlay.jsx +++ b/src/components/dialog/dialog-overlay.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { StyledDialogOverlay } from './dialog.style'; const DialogOverlay = ({ ...props }) => { diff --git a/src/components/dialog/dialog.jsx b/src/components/dialog/dialog.jsx index 690a3b7..c897fd7 100644 --- a/src/components/dialog/dialog.jsx +++ b/src/components/dialog/dialog.jsx @@ -1,4 +1,9 @@ -import React, { createContext, useCallback, useContext, useMemo } from 'react'; +import { + createContext, + useCallback, + useContext, + useMemo +} from 'react'; import { Portal } from '@/components/portal'; const DialogContext = createContext(null); diff --git a/src/components/dialog/dialog.style.js b/src/components/dialog/dialog.style.js index 7426b61..d98a23e 100644 --- a/src/components/dialog/dialog.style.js +++ b/src/components/dialog/dialog.style.js @@ -41,6 +41,7 @@ export const StyledDialogFooterCloseButton = styled.button` font-size: 1rem; cursor: pointer; padding: 8px 16px; + color: inherit; &:first-child { margin-left: auto; } diff --git a/src/components/input/input.jsx b/src/components/input/input.jsx index c59cfc9..58e7385 100644 --- a/src/components/input/input.jsx +++ b/src/components/input/input.jsx @@ -1,4 +1,4 @@ -import React, { forwardRef } from 'react'; +import { forwardRef } from 'react'; import { useInputProps } from './use-input-props'; import { StyledInput } from './input.style'; diff --git a/src/components/portal/portal.jsx b/src/components/portal/portal.jsx index 31147ab..0119942 100644 --- a/src/components/portal/portal.jsx +++ b/src/components/portal/portal.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { createPortal } from 'react-dom'; const Portal = ({ diff --git a/src/features/all-memes/.gitkeep b/src/features/all-memes/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/features/auth/components/login-dialog/login-dialog.jsx b/src/features/auth/components/login-dialog/login-dialog.jsx index 274aa01..1381abf 100644 --- a/src/features/auth/components/login-dialog/login-dialog.jsx +++ b/src/features/auth/components/login-dialog/login-dialog.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; // api import { nativeLogin } from '../../api'; // components diff --git a/src/features/auth/components/login-dialog/login-dialog.style.js b/src/features/auth/components/login-dialog/login-dialog.style.js index 80df7b8..b2f22b8 100644 --- a/src/features/auth/components/login-dialog/login-dialog.style.js +++ b/src/features/auth/components/login-dialog/login-dialog.style.js @@ -18,4 +18,5 @@ export const StyledButton = styled.button` cursor: pointer; padding: 8px 16px; margin-left: 16px; + color: inherit; `; diff --git a/src/features/auth/components/signup-dialog/signup-dialog.jsx b/src/features/auth/components/signup-dialog/signup-dialog.jsx index 216fd03..0f57994 100644 --- a/src/features/auth/components/signup-dialog/signup-dialog.jsx +++ b/src/features/auth/components/signup-dialog/signup-dialog.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; // apis import { nativeSignup } from '../../api'; // components diff --git a/src/features/auth/components/signup-dialog/signup-dialog.style.js b/src/features/auth/components/signup-dialog/signup-dialog.style.js index 69c6352..1e3a025 100644 --- a/src/features/auth/components/signup-dialog/signup-dialog.style.js +++ b/src/features/auth/components/signup-dialog/signup-dialog.style.js @@ -18,5 +18,6 @@ export const StyledButton = styled.button` cursor: pointer; padding: 8px 16px; margin-left: 16px; + color: inherit; `; diff --git a/src/features/auth/index.js b/src/features/auth/index.js new file mode 100644 index 0000000..0ef4643 --- /dev/null +++ b/src/features/auth/index.js @@ -0,0 +1,2 @@ +export * from './api'; +export * from './components'; diff --git a/src/features/layout/components/app-footer/app-footer.jsx b/src/features/layout/components/app-footer/app-footer.jsx index cccc6e8..f60c8a9 100644 --- a/src/features/layout/components/app-footer/app-footer.jsx +++ b/src/features/layout/components/app-footer/app-footer.jsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Link } from 'react-router-dom'; import { StyledWrapper, @@ -18,7 +17,8 @@ const AppFooter = () => { > - , + + Copyright © Simone Cheng, 2021 { + return db + .collection('completed_meme') + .where('isPublic', '==', true) + .orderBy('last_save_time', sort) + .limit(15) + .get() + .then((querySnapshot) => { + const docs = querySnapshot.docs + const lastKey = docs[docs.length - 1]; + const allPublicMemeImgData = docs.map((doc) => doc.data()); + return { + allPublicMemeImgData, + lastKey + }; + }); +} + +export const getAllPublicMemesNextPage = (lastKey, sort = defaultSort) => { + return db + .collection('completed_meme') + .where('isPublic', '==', true) + .orderBy('last_save_time', sort) + .startAfter(lastKey) + .limit(15) + .get() + .then((querySnapshot) => { + const docs = querySnapshot.docs + const lastKey = docs[docs.length - 1]; + const allPublicMemeImgData = docs.map((doc) => doc.data()); + return { + allPublicMemeImgData, + lastKey + }; + }); +} diff --git a/src/features/hot-memes/api/get-hot-memes.api.js b/src/features/meme-explorer/api/get-hot-memes.api.js similarity index 70% rename from src/features/hot-memes/api/get-hot-memes.api.js rename to src/features/meme-explorer/api/get-hot-memes.api.js index afd77f9..34cc86a 100644 --- a/src/features/hot-memes/api/get-hot-memes.api.js +++ b/src/features/meme-explorer/api/get-hot-memes.api.js @@ -8,10 +8,7 @@ export const getHotMemes = () => { .limit(6) .get() .then((querySnapshot) => { - const campaignMeme = []; - querySnapshot.forEach(doc => { - campaignMeme.push(doc.data()); - }) + const campaignMeme = querySnapshot.docs.map((doc) => doc.data()); return campaignMeme; }); } diff --git a/src/features/hot-memes/api/index.js b/src/features/meme-explorer/api/index.js similarity index 63% rename from src/features/hot-memes/api/index.js rename to src/features/meme-explorer/api/index.js index a370a1a..0b28895 100644 --- a/src/features/hot-memes/api/index.js +++ b/src/features/meme-explorer/api/index.js @@ -1,3 +1,3 @@ export * from './get-hot-memes.api'; export * from './count-click-time.api'; - +export * from './get-all-public-memes.api'; diff --git a/src/features/meme-explorer/components/all-public-memes/all-public-memes.jsx b/src/features/meme-explorer/components/all-public-memes/all-public-memes.jsx new file mode 100644 index 0000000..0796dc5 --- /dev/null +++ b/src/features/meme-explorer/components/all-public-memes/all-public-memes.jsx @@ -0,0 +1,87 @@ +import { useEffect, useState } from "react"; +import { useHistory } from "react-router-dom"; +// api +import { + getAllPublicMemes, + getAllPublicMemesNextPage, + countClickTime +} from "../../api"; +// styles +import { + StyledPublicMemeWrapper, + StyledPublicMemeImg, + StyledButton, + StyledAllPublicMemesWrapper, + StyledLoadingWrapper +} from "./all-public-memes.style"; +// utils +import { loading } from "@/utlis/loading"; + +const PublicMeme = (props) => { + const { img_url, img_name } = props; + const history = useHistory(); + + const handleClick = () => { + countClickTime(img_name); + history.push(`/meme/${img_name}`); + }; + + return ( + + + + ); + +}; + +const AllPublicMemes = () => { + const [allPublicMemeImg, setAllPublicMemeImg] = useState([]); + const [lastKey, setLastKey] = useState(); + + useEffect(() => { + window.scrollTo(0, 0); + }, []) + + useEffect(() => { + getAllPublicMemes('desc').then((res) => { + const { allPublicMemeImgData, lastKey } = res; + setAllPublicMemeImg(allPublicMemeImgData); + setLastKey(lastKey); + }); + }, []) + + if (allPublicMemeImg.length === 0) { + return ( + + {loading('spinningBubbles', '#056', 50, 50)} + + ); + } + + const getMoreMeme = () => { + if (!lastKey) return; + getAllPublicMemesNextPage(lastKey, 'desc') + .then((res) => { + const { allPublicMemeImgData, lastKey } = res; + setAllPublicMemeImg(allPublicMemeImg.concat(allPublicMemeImgData)); + setLastKey(lastKey); + }); + } + + return ( + <> + + {allPublicMemeImg.map((item) => ())} + + {lastKey ? ( + + 載入更多 + + ) : ( +
沒有囉!
+ )} + + ) +}; + +export default AllPublicMemes; diff --git a/src/features/meme-explorer/components/all-public-memes/all-public-memes.style.js b/src/features/meme-explorer/components/all-public-memes/all-public-memes.style.js new file mode 100644 index 0000000..01ee9bb --- /dev/null +++ b/src/features/meme-explorer/components/all-public-memes/all-public-memes.style.js @@ -0,0 +1,76 @@ +import styled from "styled-components"; + +export const StyledPublicMemeWrapper = styled.div` + box-shadow: 0 0 3px grey; + border-radius: 10px; + width: 250px; + height: 250px; + overflow: hidden; + cursor: pointer; + position: relative; + bottom: 0; + transition: bottom 0.3s linear; + &:hover{ + box-shadow: 0 0 10px 2px grey; + bottom: 10px; + } + @media screen and (max-width: 1024px) { + width: 200px; + height: 200px; + } + @media screen and (max-width: 768px) { + width: 250px; + height: 250px; + } + @media screen and (max-width: 660px) { + width: 200px; + height: 200px; + } + @media screen and (max-width: 524px) { + width: 250px; + height: 250px; + } +`; + +export const StyledPublicMemeImg = styled.img` + width: 100%; + height: 100%; + object-fit: cover; +`; + +export const StyledButton = styled.button` + border: none; + border-radius: 5px; + background-color: #056; + color: white; + padding: 10px 20px; + cursor: pointer; + font-size: 1rem; +`; + +export const StyledAllPublicMemesWrapper = styled.div` + display: grid; + grid-template-columns: repeat(3, 250px); + grid-gap: 45px; + margin-top: 45px; + padding-bottom: 45px; + @media screen and (max-width: 1024px) { + grid-template-columns: repeat(3, 200px); + } + @media screen and (max-width: 768px) { + grid-template-columns: repeat(2, 250px); + } + @media screen and (max-width: 660px) { + grid-template-columns: repeat(2, 200px); + } + @media screen and (max-width: 524px) { + grid-template-columns: repeat(1, 250px); + } +`; + +export const StyledLoadingWrapper = styled.div` + margin-top: 100px; + display: flex; + justify-content: center; + width: 100%; +` diff --git a/src/features/meme-explorer/components/all-public-memes/index.js b/src/features/meme-explorer/components/all-public-memes/index.js new file mode 100644 index 0000000..89ad071 --- /dev/null +++ b/src/features/meme-explorer/components/all-public-memes/index.js @@ -0,0 +1 @@ +export { default as AllPublicMemes } from './all-public-memes'; diff --git a/src/features/hot-memes/components/hot-memes.jsx b/src/features/meme-explorer/components/hot-memes/hot-memes.jsx similarity index 92% rename from src/features/hot-memes/components/hot-memes.jsx rename to src/features/meme-explorer/components/hot-memes/hot-memes.jsx index f527659..ac7f7aa 100644 --- a/src/features/hot-memes/components/hot-memes.jsx +++ b/src/features/meme-explorer/components/hot-memes/hot-memes.jsx @@ -1,7 +1,7 @@ -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { Link } from "react-router-dom"; // api -import { getHotMemes, countClickTime } from "../api"; +import { getHotMemes, countClickTime } from "../../api"; // styles import color from "@/components/Styled/colorTheme"; import { diff --git a/src/features/hot-memes/components/hot-memes.style.js b/src/features/meme-explorer/components/hot-memes/hot-memes.style.js similarity index 100% rename from src/features/hot-memes/components/hot-memes.style.js rename to src/features/meme-explorer/components/hot-memes/hot-memes.style.js diff --git a/src/features/hot-memes/components/index.js b/src/features/meme-explorer/components/hot-memes/index.js similarity index 100% rename from src/features/hot-memes/components/index.js rename to src/features/meme-explorer/components/hot-memes/index.js diff --git a/src/features/meme-explorer/components/index.js b/src/features/meme-explorer/components/index.js new file mode 100644 index 0000000..6e3113e --- /dev/null +++ b/src/features/meme-explorer/components/index.js @@ -0,0 +1,2 @@ +export * from './hot-memes'; +export * from './all-public-memes'; diff --git a/src/features/meme-explorer/index.js b/src/features/meme-explorer/index.js new file mode 100644 index 0000000..0ef4643 --- /dev/null +++ b/src/features/meme-explorer/index.js @@ -0,0 +1,2 @@ +export * from './api'; +export * from './components'; diff --git a/src/pages/explore-memes/explore-memes.page.jsx b/src/pages/explore-memes/explore-memes.page.jsx new file mode 100644 index 0000000..1fedd79 --- /dev/null +++ b/src/pages/explore-memes/explore-memes.page.jsx @@ -0,0 +1,12 @@ +import { AllPublicMemes } from '@/features/meme-explorer'; +import { StyledWrapper } from './explore-memes.style'; + +const ExploresMemes = () => { + return ( + + + + ); +}; + +export default ExploresMemes; diff --git a/src/pages/explore-memes/explore-memes.style.js b/src/pages/explore-memes/explore-memes.style.js new file mode 100644 index 0000000..6652779 --- /dev/null +++ b/src/pages/explore-memes/explore-memes.style.js @@ -0,0 +1,11 @@ +import styled from "styled-components"; + +export const StyledWrapper = styled.div` + padding-top: 100px; + padding-bottom: 50px; + background-color: #ffc349; + min-height: calc(100vh - 100px); + display: flex; + flex-direction: column; + align-items: center; +`; diff --git a/src/pages/explore-memes/index.js b/src/pages/explore-memes/index.js new file mode 100644 index 0000000..22c383a --- /dev/null +++ b/src/pages/explore-memes/index.js @@ -0,0 +1 @@ +export { default as ExploreMemes } from './explore-memes.page'; diff --git a/src/pages/landing/index.js b/src/pages/landing/index.js index 5ba2890..3735146 100644 --- a/src/pages/landing/index.js +++ b/src/pages/landing/index.js @@ -1 +1 @@ -export { default as LandingPage } from './landing'; +export { default as LandingPage } from './landing.page'; diff --git a/src/pages/landing/landing.jsx b/src/pages/landing/landing.page.jsx similarity index 96% rename from src/pages/landing/landing.jsx rename to src/pages/landing/landing.page.jsx index 2cd3a4f..421cf2c 100644 --- a/src/pages/landing/landing.jsx +++ b/src/pages/landing/landing.page.jsx @@ -24,8 +24,8 @@ import canvasStand from '@/image/day10-canvas-stand.png'; import colorTools from '@/image/gummy-color-tools.png'; import floppy from '@/image/day18-floppy.png'; // components -import { AppFooter } from '@/features/layout/components'; -import { HotMemes } from '@/features/hot-memes/components'; +import { AppFooter } from '@/features/layout'; +import { HotMemes } from '@/features/meme-explorer'; function PrimarySection() { return ( diff --git a/src/pages/landing/landing.style.js b/src/pages/landing/landing.style.js index a1d9cfc..25a95c3 100644 --- a/src/pages/landing/landing.style.js +++ b/src/pages/landing/landing.style.js @@ -1,12 +1,12 @@ import styled from 'styled-components'; -const Wrapper = styled.div` +export const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; `; -const StyledSloganDiv = styled.div` +export const StyledSloganDiv = styled.div` display: flex; justify-content: center; align-items: center; @@ -22,7 +22,7 @@ const StyledSloganDiv = styled.div` } `; -const SloganText = styled.div` +export const SloganText = styled.div` width: 300px; text-align: center; margin-left: 100px; @@ -32,7 +32,7 @@ const SloganText = styled.div` } `; -const StyledInfoDiv = styled.div` +export const StyledInfoDiv = styled.div` max-width: 1440px; margin: 0 auto; @media screen and (max-width: 768px) { @@ -40,7 +40,7 @@ const StyledInfoDiv = styled.div` } `; -const InfoText = styled.div` +export const InfoText = styled.div` display: flex; justify-content: center; align-items: center; @@ -53,18 +53,18 @@ const InfoText = styled.div` } `; -const InfoContent = styled.div` +export const InfoContent = styled.div` @media screen and (max-width: 768px) { margin-top: 20px; } `; -const InfoSubContent = styled.div` +export const InfoSubContent = styled.div` margin: 30px auto 0 auto; width: 80%; `; -const SloganImg = styled.img` +export const SloganImg = styled.img` height: 30rem; border-radius: 50px; animation: fadein 6s ease; @@ -80,7 +80,7 @@ const SloganImg = styled.img` } `; -const InfoImg = styled.img` +export const InfoImg = styled.img` width: 20rem; @media screen and (max-width: 1024px) { width: 15rem; @@ -90,7 +90,7 @@ const InfoImg = styled.img` } `; -const SloganTitle = styled.h1` +export const SloganTitle = styled.h1` width: 9em; border-right: 2px solid; overflow: hidden; @@ -108,7 +108,7 @@ const SloganTitle = styled.h1` } `; -const InfoTitle = styled.h1` +export const InfoTitle = styled.h1` margin-left: 50px; margin-top: 50px; @media screen and (max-width: 768px) { @@ -116,7 +116,7 @@ const InfoTitle = styled.h1` } `; -const HotMemesTitle = styled.h1` +export const HotMemesTitle = styled.h1` color: white; margin-left: 50px; @media screen and (max-width: 768px) { @@ -124,7 +124,7 @@ const HotMemesTitle = styled.h1` } `; -const SloganButton = styled.button` +export const SloganButton = styled.button` border: none; border-radius: 5px; background-color: ${props => props.color.color2.colorCode}; @@ -139,31 +139,13 @@ const SloganButton = styled.button` } `; -const SloganContent = styled.div` +export const SloganContent = styled.div` margin-top: 10px; font-size: 1rem; `; -const Strong = styled.strong` +export const Strong = styled.strong` font-size: 20px; border-bottom: 2px ${props => props.color.color2.colorCode} solid; margin-left: 5px; `; - -export { - Wrapper, - StyledSloganDiv, - SloganText, - StyledInfoDiv, - InfoText, - InfoContent, - InfoSubContent, - SloganImg, - InfoImg, - SloganTitle, - InfoTitle, - HotMemesTitle, - SloganButton, - SloganContent, - Strong -} diff --git a/src/pages/page-not-found/index.js b/src/pages/page-not-found/index.js index b462421..46c5d93 100644 --- a/src/pages/page-not-found/index.js +++ b/src/pages/page-not-found/index.js @@ -1 +1 @@ -export { default as PageNotFound } from './page-not-found'; +export { default as PageNotFound } from './page-not-found.page'; diff --git a/src/pages/page-not-found/page-not-found.jsx b/src/pages/page-not-found/page-not-found.page.jsx similarity index 97% rename from src/pages/page-not-found/page-not-found.jsx rename to src/pages/page-not-found/page-not-found.page.jsx index 8ac1c98..e05578a 100644 --- a/src/pages/page-not-found/page-not-found.jsx +++ b/src/pages/page-not-found/page-not-found.page.jsx @@ -24,7 +24,7 @@ function PageNotFound() { if (canvas === null) { dispatch(setCanvas('')); } - }, []) + }, [canvas, dispatch]) return (