Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Atom #1

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Router } from "./router/Router";
import { UserProvider } from "./providers/UserProvider";

import "./styles.css";

export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
<UserProvider>
<Router />
</UserProvider>
);
}
13 changes: 13 additions & 0 deletions src/components/atoms/button/BaseButton.jsx
Original file line number Diff line number Diff line change
@@ -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;
}
`;
11 changes: 11 additions & 0 deletions src/components/atoms/button/PrimaryButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from "styled-components";
import { BaseButton } from "./BaseButton";

export const PrimaryButton = (props) => {
const { children } = props;
return <SButton>{children}</SButton>;
};

const SButton = styled(BaseButton)`
background-color: #40514e;
`;
11 changes: 11 additions & 0 deletions src/components/atoms/button/SecondaryButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from "styled-components";
import { BaseButton } from "./BaseButton";

export const SecondaryButton = (props) => {
const { children, onClick } = props;
return <SButton onClick={onClick}>{children}</SButton>;
};

const SButton = styled(BaseButton)`
background-color: #11999e;
`;
13 changes: 13 additions & 0 deletions src/components/atoms/card/Card.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styled from "styled-components";

export const Card = (props) => {
const { children } = props;
return <SCard>{children}</SCard>;
};

const SCard = styled.div`
background-color: #fff;
box-shadow: #ddd 0px 0px 4px 2px;
border-radius: 8px;
padding: 16px;
`;
13 changes: 13 additions & 0 deletions src/components/atoms/input/Input.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styled from "styled-components";

export const Input = (props) => {
const { placeholder = "" } = props;
return <SInput type="text" placeholder={placeholder} />;
};

const SInput = styled.input`
padding: 8px 16px;
border: solid #ddd 1px;
border-radius: 9999px;
outline: none;
`;
16 changes: 16 additions & 0 deletions src/components/atoms/layout/Footer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Link } from "react-router-dom";
import styled from "styled-components";

export const Footer = () => {
return <SFooter>&copy; 2021 test</SFooter>;
};

const SFooter = styled.footer`
background-color: #11999e;
color: #fff;
text-align: center;
padding: 8px 0;
position: fixed;
bottom: 0;
width: 100%;
`;
22 changes: 22 additions & 0 deletions src/components/atoms/layout/Header.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Link } from "react-router-dom";
import styled from "styled-components";

export const Header = () => {
return (
<SHeader>
<SLink to="/">HOME</SLink>
<SLink to="/users">USERS</SLink>
</SHeader>
);
};

const SHeader = styled.header`
background-color: #11999e;
color: fff;
text-align: center;
padding: 8px 0;
`;

const SLink = styled(Link)`
margin: 0 8px;
`;
26 changes: 26 additions & 0 deletions src/components/molecules/SearchInput.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<SContainer>
<Input placeholder="検索条件を入力" />
<SButtonWrapper>
<PrimaryButton>検索</PrimaryButton>
</SButtonWrapper>
</SContainer>
);
});

const SContainer = styled.div`
display: flex;
align-items: center;
`;

const SButtonWrapper = styled.div`
padding-left: 8px;
`;
40 changes: 40 additions & 0 deletions src/components/molecules/user/UserIconWithName.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<SContainer>
<SImage height={160} width={160} src={image} alt={name} />
<SName>{name}</SName>
{isAdmin && <SEdit>編集</SEdit>}
</SContainer>
);
});

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;
`;
38 changes: 38 additions & 0 deletions src/components/organisms/user/UserCard.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<Card>
<UserIconWithName image={user.image} name={user.name} />
<SDL>
<dt>メール</dt>
<dd>{user.email}</dd>
<dt>TEL</dt>
<dd>{user.phone}</dd>
<dt>会社名</dt>
<dd>{user.company.name}</dd>
<dt>WEB</dt>
<dd>{user.website}</dd>
</SDL>
</Card>
);
});

const SDL = styled.dl`
text-align: left;
margin-bottom: 0px;
dt {
float: left;
}
dd {
padding-left: 32px;
padding-bottom: 8px;
overflow-wrap: break-word;
}
`;
34 changes: 34 additions & 0 deletions src/components/pages/Top.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<SContainer>
<h2>Topページ</h2>
<SecondaryButton onClick={onClickAdmin}>管理者ユーザー</SecondaryButton>
<br />
<br />
<SecondaryButton onClick={onClickGeneral}>一般ユーザー</SecondaryButton>
</SContainer>
);
};

const SContainer = styled.div`
text-align: center;
`;
55 changes: 55 additions & 0 deletions src/components/pages/Users.jsx
Original file line number Diff line number Diff line change
@@ -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: "[email protected]",
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 (
<SContainer>
<h2>ユーザー一覧</h2>
<SearchInput />
<br />
<SecondaryButton onClick={onClickSwitch}>切り替え</SecondaryButton>
<SUserArea>
{users.map((user) => (
<UserCard key={user.id} user={user} />
))}
</SUserArea>
</SContainer>
);
};

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;
`;
13 changes: 13 additions & 0 deletions src/components/templates/DefaultLayout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Footer } from "../atoms/layout/Footer";
import { Header } from "../atoms/layout/Header";

export const DefaultLayout = (props) => {
const { children } = props;
return (
<>
<Header />
{children}
<Footer />
</>
);
};
11 changes: 11 additions & 0 deletions src/components/templates/HeaderOnly.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Header } from "../atoms/layout/Header";

export const HeaderOnly = (props) => {
const { children } = props;
return (
<>
<Header />
{children}
</>
);
};
14 changes: 14 additions & 0 deletions src/providers/UserProvider.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<UserContext.Provider value={{ userInfo, setUserInfo }}>
{children}
</UserContext.Provider>
);
};
24 changes: 24 additions & 0 deletions src/router/Router.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<BrowserRouter>
<Switch>
<Route exact path="/">
<DefaultLayout>
<Top />
</DefaultLayout>
</Route>
<Route path="/users">
<HeaderOnly>
<Users />
</HeaderOnly>
</Route>
</Switch>
</BrowserRouter>
);
};
9 changes: 5 additions & 4 deletions src/styles.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.App {
font-family: sans-serif;
text-align: center;
}
body {
background-color: #e4f9f5;
margin: 0;
min-height: 100vh;
}