0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

styled-componentsとAtomic Design @yukilulu0229

Posted at

インストール

npm install styled-components

atom

atom/button/PrimaryButton.jsx
import React from 'react';
import styled from "styled-components";
import BaseButton from "./BaseButton.jsx";

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

const SButton = styled.button`
    background-color: #40514e;
    color: #fff;
    padding: 6px 24px;
    border: none;
    outline: none;
    border-radius: 9999px;
    &:hover {
        cursor: pointer;
        opacity: 0.8;
    }
`

export default PrimaryButton;

ボタン名をpropsで受け取る

AtomicDesign.jsx
import React from 'react';
import PrimaryButton from "./atom/button/PrimaryButton.jsx";
import SecondaryButton from "./atom/button/SecondaryButton.jsx";
import SearchInput from "./molecules/SearchInput.jsx";

const AtomicDesign = () => {
  return (
    <div>
      <p>AtomicDesign</p>

      <PrimaryButton>テスト</PrimaryButton>
      <SecondaryButton>検索</SecondaryButton>
    </div>
  );
};

export default AtomicDesign;

ボタン名をpropsで渡す

共通の部分を抜き出す

atom/button/BaseButton.jsx
import styled from "styled-components";

const BaseButton = styled.button`
    color: #fff;
    padding: 6px 24px;
    border: none;
    outline: none;
    border-radius: 9999px;
    &:hover {
        cursor: pointer;
        opacity: 0.8;
    }
`

export default BaseButton;

共通部分

atom/button/PrimaryButton.jsx

import React from 'react';
import styled from "styled-components";
import BaseButton from "./BaseButton.jsx";

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

const SButton = styled(BaseButton)`
    background-color: #40514e;
`

export default PrimaryButton;

styled(BaseButton)を使い
共通部分を呼び出す
BaseButtonが上書きされる

molecules

molecules/SearchInput.jsx

import React from 'react';
import PrimaryButton from "../atom/button/PrimaryButton.jsx";
import Input from "../atom/input/Input.jsx";
import styled from "styled-components";

const 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;
`

export default SearchInput;

atomを読み込んで組み合わせる

Input.jsx

import React from 'react';
import styled from "styled-components";

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

const SInput = styled.input`
    padding: 8px 16px;
    border: solid 1px #ddd;
    border-radius: 9999px;
    outline: none;
`

export default Input;

placeholderでpropsを受け取る

PrimaryButton.jsx

import React from 'react';
import styled from "styled-components";
import BaseButton from "./BaseButton.jsx";

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

const SButton = styled(BaseButton)`
    background-color: #40514e;
`

export default PrimaryButton;

organisms

上位でもatom(Card)で囲む場合もある? ここはルールがよくわからな

AtomicDesigh.jsx

import React from 'react';
import PrimaryButton from "./atom/button/PrimaryButton.jsx";
import SecondaryButton from "./atom/button/SecondaryButton.jsx";
import SearchInput from "./molecules/SearchInput.jsx";
import UserCard from "./organisms/user/UserCard.jsx";

const AtomicDesign = () => {
  const user = {
    name: "yukilulu0229",
    image: "https://picsum.photos/160",
    email: "apple@fluits.com",
    tel: "01-2345-6789",
    company: {
      name: "company web"
    },
    website: "xxx.com"

  }
  return (
    <div>
      <UserCard user={user} />
    </div>
  );
};

export default AtomicDesign;

user情報を渡す

organisms/user/UserCard.jsx

import React from 'react';
import styled from "styled-components";
import Card from "../../atom/card/Card.jsx";
import UserIconWithName from "../../molecules/user/UserIconWithName.jsx";

const UserCard = (props) => {
  const {user} = props
  return (
    <Card>
      <UserIconWithName image={user.image} name={user.name} />

      <SDl>
        <dt>メール</dt>
        <dd>{user.email}</dd>

        <dt>tel</dt>
        <dd>{user.tel}</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: 0;
    
    dt {
        float: left;
    }
    
    dd {
        padding-left: 32px;
        padding-bottom: 8px;
        overflow-wrap: break-word;
    }
    
`

export default UserCard;

user情報を受け取る
UserIconWithNameにpropsを渡す
Cardの中をchildrenで渡す

molecules/user/UserIconWithName.jsx

import React from 'react';
import styled from "styled-components";

const UserIconWithName = (props) => {
  const {image, name} = props
  return (
    <SContainer>
      <SImage src={image} alt="プロフィール" />
      <SName>{name}</SName>
    </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: #303030;
`
export default UserIconWithName;


imageとnameのpropsを受け取る

atom/card/Card.jsx
import React from 'react';
import styled from "styled-components";

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

const SCard = styled.div`
    background-color: #d7d1d1;
    box-shadow: #ddd 0 0 4px 2px;
    border-radius: 8px;
    padding: 16px;
`

export default Card;

UserCardからchildrenを受け取る

templates

atomicDesign.jsx
import React from 'react';
import DefaultLayout from "./templates/DefaultLayout.jsx";

const AtomicDesign = () => {
  return (
    <DefaultLayout>
      <p>AtomicDesign</p>
    </DefaultLayout>
  );
};

export default AtomicDesign;

DefaultLayoutにchildrenを渡す

templates/DefaultLayout.jsx
import React from 'react';
import Footer from "../atoms/layout/Footer.jsx";
import Header from "../atoms/layout/Header.jsx";
import styled from "styled-components";


const DefaultLayout = (props) => {
  const {children} = props
  return (
    <>
      <SDefaultLayout>
        <Header />
        {children}
        <Footer />
      </SDefaultLayout>
    </>
  );
};


const SDefaultLayout = styled.div`
    min-height: 100vh;
`
export default DefaultLayout;

HeaderとFooterを読み込む
atomicDesignで渡されたchildrenを受け取る
そしてHeaderとFooterにchildrenを入れている

atom/Layout/Header.jsx
import React from 'react';
import {Link} from "react-router-dom";
import styled from "styled-components";

const Header = () => {
  return (
    <SHeader>
      <SLink to="/AtomicDesign">AtomicDesign</SLink>
      <SLink to="/AtomicDesign">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;
    color: #fff;
`

export default Header;

これがatomsの中でよいのかは疑問が残っている

atoms/layout/footer.jsx
import React from 'react';
import {Link} from "react-router-dom";
import styled from "styled-components";

const Footer = () => {
  return (
    <SFooter>
      <p>&copy; company web</p>
    </SFooter>
  );
};

const SFooter = styled.footer`
    background-color: #11999e;
    color: #fff;
    text-align: center;
    padding: 8px 0;
    position: fixed;
    bottom: 0;
    width: 100%;
`
export default Footer;

これがatomsの中でよいのかは疑問が残っている

pages

今回の話はUsersのほう(Usersは共通の部品がないのでtemplateを使っていない)

router/Router.jsx
import React from 'react';
import { Route, Routes } from "react-router-dom";
import Home from "../components/Home.jsx";
import Page2 from "../components/Page2.jsx";
import Page3 from "../components/Page3.jsx";
import Top from "../components/pages/Top.jsx";
import Users from "../components/pages/Users.jsx";
import DefaultLayout from "../components/templates/DefaultLayout.jsx";
import Page404 from "../Page404.jsx";
import { page2Routes } from "./Page2Routes.jsx";
import { page3Routes } from "./Page3Routes.jsx";

const Router = () => {
  return (
    <>
      <Routes path="/AtomicDesign/*" >
        <Route path="/" element={<DefaultLayout />} >
          <Route index={true} element={<Top/>} />
        </Route>
        <Route path="Users/*" element={<Users />} />
      </Routes>

    </>
  );
};

export default Router;

routerの設定でlayoutを選択している

pages/Users.jsx
import React from 'react';
import styled from "styled-components";
import Header from "../atoms/layout/Header.jsx";
import SearchInput from "../molecules/SearchInput.jsx";
import UserCard from "../organisms/user/UserCard.jsx";

const Users = () => {
  const users = [...Array(10).keys()].map((value) => {
    return {
      id: value,
      name: `yukilulu0229 + ${value}`,
      image: "https://picsum.photos/160",
      email: "apple@fluits.com",
      tel: "01-2345-6789",
      company: {
        name: "company web"
      },
      website: "xxx.com"
    }
  })
  return (
    <>
      <SContainer>

        <Header />

        <h2>User Page</h2>

        <SearchInput />


        <SUserArea>
          {users.map((user) => (
            <UserCard  key={user.id} user={user} />
          ))}
          </SUserArea>
      </SContainer>
    </>
  );
};

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

const SUserArea = styled.div`
    padding-top: 40px;
    width: calc(100% - 48px);
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    grid-gap: 20px;
`

export default Users;



0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?