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 (