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}
+
+ >
+ );
+};
diff --git a/src/components/templates/HeaderOnly.jsx b/src/components/templates/HeaderOnly.jsx
new file mode 100644
index 0000000..5db10cb
--- /dev/null
+++ b/src/components/templates/HeaderOnly.jsx
@@ -0,0 +1,11 @@
+import { Header } from "../atoms/layout/Header";
+
+export const HeaderOnly = (props) => {
+ const { children } = props;
+ return (
+ <>
+
+ {children}
+ >
+ );
+};
diff --git a/src/providers/UserProvider.jsx b/src/providers/UserProvider.jsx
new file mode 100644
index 0000000..7786472
--- /dev/null
+++ b/src/providers/UserProvider.jsx
@@ -0,0 +1,14 @@
+import { createContext, useState } from "react";
+
+export const UserContext = createContext({});
+
+export const UserProvider = (props) => {
+ const { children } = props;
+ const [userInfo, setUserInfo] = useState(null);
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/router/Router.jsx b/src/router/Router.jsx
new file mode 100644
index 0000000..b820bae
--- /dev/null
+++ b/src/router/Router.jsx
@@ -0,0 +1,24 @@
+import { BrowserRouter, Switch, Route } from "react-router-dom";
+import { Top } from "../components/pages/Top";
+import { Users } from "../components/pages/Users";
+import { DefaultLayout } from "../components/templates/DefaultLayout";
+import { HeaderOnly } from "../components/templates/HeaderOnly";
+
+export const Router = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/styles.css b/src/styles.css
index 59b0604..e9bb231 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,4 +1,5 @@
-.App {
- font-family: sans-serif;
- text-align: center;
-}
+body {
+ background-color: #e4f9f5;
+ margin: 0;
+ min-height: 100vh;
+}