diff --git a/src/App.js b/src/App.js index dbc5c59..8d67433 100644 --- a/src/App.js +++ b/src/App.js @@ -1,10 +1,12 @@ +import { Router } from "./router/Router"; +import { UserProvider } from "./providers/UserProvider"; + import "./styles.css"; export default function App() { return ( -
-

Hello CodeSandbox

-

Start editing to see some magic happen!

-
+ + + ); } diff --git a/src/components/atoms/button/BaseButton.jsx b/src/components/atoms/button/BaseButton.jsx new file mode 100644 index 0000000..85defb9 --- /dev/null +++ b/src/components/atoms/button/BaseButton.jsx @@ -0,0 +1,13 @@ +import styled from "styled-components"; + +export const BaseButton = styled.button` + color: #fff; + padding: 6px 24px; + border: none; + border-radius: 9999px; + outline: none; + &:hover { + cursor: pointer; + opacity: 0.8; + } +`; diff --git a/src/components/atoms/button/PrimaryButton.jsx b/src/components/atoms/button/PrimaryButton.jsx new file mode 100644 index 0000000..aa1c214 --- /dev/null +++ b/src/components/atoms/button/PrimaryButton.jsx @@ -0,0 +1,11 @@ +import styled from "styled-components"; +import { BaseButton } from "./BaseButton"; + +export const PrimaryButton = (props) => { + const { children } = props; + return {children}; +}; + +const SButton = styled(BaseButton)` + background-color: #40514e; +`; diff --git a/src/components/atoms/button/SecondaryButton.jsx b/src/components/atoms/button/SecondaryButton.jsx new file mode 100644 index 0000000..9233cf1 --- /dev/null +++ b/src/components/atoms/button/SecondaryButton.jsx @@ -0,0 +1,11 @@ +import styled from "styled-components"; +import { BaseButton } from "./BaseButton"; + +export const SecondaryButton = (props) => { + const { children, onClick } = props; + return {children}; +}; + +const SButton = styled(BaseButton)` + background-color: #11999e; +`; diff --git a/src/components/atoms/card/Card.jsx b/src/components/atoms/card/Card.jsx new file mode 100644 index 0000000..f91b47e --- /dev/null +++ b/src/components/atoms/card/Card.jsx @@ -0,0 +1,13 @@ +import styled from "styled-components"; + +export const Card = (props) => { + const { children } = props; + return {children}; +}; + +const SCard = styled.div` + background-color: #fff; + box-shadow: #ddd 0px 0px 4px 2px; + border-radius: 8px; + padding: 16px; +`; diff --git a/src/components/atoms/input/Input.jsx b/src/components/atoms/input/Input.jsx new file mode 100644 index 0000000..95575ea --- /dev/null +++ b/src/components/atoms/input/Input.jsx @@ -0,0 +1,13 @@ +import styled from "styled-components"; + +export const Input = (props) => { + const { placeholder = "" } = props; + return ; +}; + +const SInput = styled.input` + padding: 8px 16px; + border: solid #ddd 1px; + border-radius: 9999px; + outline: none; +`; diff --git a/src/components/atoms/layout/Footer.jsx b/src/components/atoms/layout/Footer.jsx new file mode 100644 index 0000000..4effafa --- /dev/null +++ b/src/components/atoms/layout/Footer.jsx @@ -0,0 +1,16 @@ +import { Link } from "react-router-dom"; +import styled from "styled-components"; + +export const Footer = () => { + return © 2021 test; +}; + +const SFooter = styled.footer` + background-color: #11999e; + color: #fff; + text-align: center; + padding: 8px 0; + position: fixed; + bottom: 0; + width: 100%; +`; diff --git a/src/components/atoms/layout/Header.jsx b/src/components/atoms/layout/Header.jsx new file mode 100644 index 0000000..cea1848 --- /dev/null +++ b/src/components/atoms/layout/Header.jsx @@ -0,0 +1,22 @@ +import { Link } from "react-router-dom"; +import styled from "styled-components"; + +export const Header = () => { + return ( + + HOME + USERS + + ); +}; + +const SHeader = styled.header` + background-color: #11999e; + color: fff; + text-align: center; + padding: 8px 0; +`; + +const SLink = styled(Link)` + margin: 0 8px; +`; diff --git a/src/components/molecules/SearchInput.jsx b/src/components/molecules/SearchInput.jsx new file mode 100644 index 0000000..8af5a66 --- /dev/null +++ b/src/components/molecules/SearchInput.jsx @@ -0,0 +1,26 @@ +import styled from "styled-components"; +import { memo } from "react"; + +import { PrimaryButton } from "../atoms/button/PrimaryButton"; +import { Input } from "../atoms/input/Input"; + +export const SearchInput = memo(() => { + console.log("SearchInput"); + return ( + + + + 検索 + + + ); +}); + +const SContainer = styled.div` + display: flex; + align-items: center; +`; + +const SButtonWrapper = styled.div` + padding-left: 8px; +`; diff --git a/src/components/molecules/user/UserIconWithName.jsx b/src/components/molecules/user/UserIconWithName.jsx new file mode 100644 index 0000000..0026395 --- /dev/null +++ b/src/components/molecules/user/UserIconWithName.jsx @@ -0,0 +1,40 @@ +import { useContext, memo } from "react"; +import styled from "styled-components"; +import { UserContext } from "../../../providers/UserProvider"; + +export const UserIconWithName = memo((props) => { + console.log("UserIconWithName"); + + const { image, name } = props; + const { userInfo } = useContext(UserContext); + const isAdmin = userInfo ? userInfo.isAdmin : false; + + return ( + + + {name} + {isAdmin && 編集} + + ); +}); + +const SContainer = styled.div` + text-align: center; +`; + +const SImage = styled.img` + border-radius: 50%; +`; + +const SName = styled.p` + font-size: 18px; + font-weight: bold; + margin: 0; + color: #40514e; +`; + +const SEdit = styled.span` + text-decoration: underline; + color: #aaa; + cursor: pointer; +`; diff --git a/src/components/organisms/user/UserCard.jsx b/src/components/organisms/user/UserCard.jsx new file mode 100644 index 0000000..d36b05e --- /dev/null +++ b/src/components/organisms/user/UserCard.jsx @@ -0,0 +1,38 @@ +import styled from "styled-components"; +import { Card } from "../../atoms/card/Card"; +import { UserIconWithName } from "../../molecules/user/UserIconWithName"; +import { memo } from "react"; + +export const UserCard = memo((props) => { + console.log("UserCard"); + + const { user } = props; + return ( + + + +
メール
+
{user.email}
+
TEL
+
{user.phone}
+
会社名
+
{user.company.name}
+
WEB
+
{user.website}
+
+
+ ); +}); + +const SDL = styled.dl` + text-align: left; + margin-bottom: 0px; + dt { + float: left; + } + dd { + padding-left: 32px; + padding-bottom: 8px; + overflow-wrap: break-word; + } +`; diff --git a/src/components/pages/Top.jsx b/src/components/pages/Top.jsx new file mode 100644 index 0000000..0d8325d --- /dev/null +++ b/src/components/pages/Top.jsx @@ -0,0 +1,34 @@ +import styled from "styled-components"; +import { SecondaryButton } from "../atoms/button/SecondaryButton"; +import { useHistory } from "react-router-dom"; +import { useContext } from "react"; +import { UserContext } from "../../providers/UserProvider"; + +export const Top = () => { + const history = useHistory(); + const { setUserInfo } = useContext(UserContext); + + const onClickAdmin = () => { + setUserInfo({ isAdmin: true }); + history.push("/users"); + }; + + const onClickGeneral = () => { + setUserInfo({ isAdmin: false }); + history.push("/users"); + }; + + return ( + +

Topページ

+ 管理者ユーザー +
+
+ 一般ユーザー +
+ ); +}; + +const SContainer = styled.div` + text-align: center; +`; diff --git a/src/components/pages/Users.jsx b/src/components/pages/Users.jsx new file mode 100644 index 0000000..518d4e1 --- /dev/null +++ b/src/components/pages/Users.jsx @@ -0,0 +1,55 @@ +import { useContext } from "react"; +import styled from "styled-components"; +import { UserContext } from "../../providers/UserProvider"; +import { SecondaryButton } from "../atoms/button/SecondaryButton"; + +import { SearchInput } from "../molecules/SearchInput"; +import { UserCard } from "../organisms/user/UserCard"; + +const users = [...Array(10).keys()].map((val) => { + return { + id: val, + name: `まさお${val}`, + image: "https://source.unsplash.com/OzAeZPNsLXk", + email: "test@example.com", + phone: "020-0000-1111", + company: { + name: "テスト会社" + }, + website: "https://google.com" + }; +}); + +export const Users = () => { + const { userInfo, setUserInfo } = useContext(UserContext); + const onClickSwitch = () => setUserInfo({ isAdmin: !userInfo.isAdmin }); + + return ( + +

ユーザー一覧

+ +
+ 切り替え + + {users.map((user) => ( + + ))} + +
+ ); +}; + +const SContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + padding: 24px; +`; + +const SUserArea = styled.div` + padding-top: 40px; + width: 100%; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + grid-gap: 20px; +`; diff --git a/src/components/templates/DefaultLayout.jsx b/src/components/templates/DefaultLayout.jsx new file mode 100644 index 0000000..5197113 --- /dev/null +++ b/src/components/templates/DefaultLayout.jsx @@ -0,0 +1,13 @@ +import { Footer } from "../atoms/layout/Footer"; +import { Header } from "../atoms/layout/Header"; + +export const DefaultLayout = (props) => { + const { children } = props; + return ( + <> +
+ {children} +