λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
IT/Svelte

BH] Svelte νŠœν† λ¦¬μ–Ό - 2편 (Trello)

by Full~ day πŸ˜€ 2022. 2. 16.
728x90
λ°˜μ‘ν˜•

[BH] μ•ˆλ…•ν•˜μ„Έμš”.

 

1νŽΈμ—μ„œλŠ” 기본적인 μ…‹νŒ…μ„ ν–ˆμ–΄μš”.

Svelte νŠœν† λ¦¬μ–Ό 2νŽΈμ€ 메인화면 μž‘μ—…ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

λͺ©μ μ€ μ•„λž˜μ˜ μ΄λ―Έμ§€μž…λ‹ˆλ‹€.

메인화면

1. 폴더 ꡬ쑰

- src

  β”” assets

  β”” components

  β”” layout

  β”” pages

- App.svelte

- main.js

- store.js

 

2. 상단 헀더 μž‘μ—…

 

layout - TheHeader.svelte 생성

<script>
  import Icon from 'svelte-fa';
  import { faHome, faColumns, faPlus, faBell, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
  import { navigate } from 'svelte-routing';

  const goPage = (page) => {
    navigate(page, { replace: true });
  };
</script>
<header id="header">
  <div class="header-band"><Icon icon="{faColumns}" /> Trello</div>
  <div class="button-group">
    <button type="button" class="button" on:click="{() => goPage('/home')}"> <Icon icon="{faHome}" /> </button>
    <button type="button" class="button" on:click="{() => goPage('/boards')}"><span class="icon"><Icon icon="{faColumns}" /></span><span>Boards </span></button>
    <button type="button" class="button">Jump to....</button>
  </div>
  <div class="button-group">
    <button type="button" class="button"> <span class="icon"><span class="material-icons-outlined"> add </span> </span></button>
    <button type="button" class="button"><span class="material-icons-outlined"> error_outline </span></button>
    <button type="button" class="button"><span class="icon"><span class="material-icons-outlined"> notifications </span></span></button>
  </div>
</header>
<style lang="scss">
  #header {
    position: relative;
    width: 100%;
    height: 38px;
    background-color: #026aa7;
    display: flex;
    align-items: center;
    justify-content: space-between;
    &.custom-header-background {
      background-color: rgb(6 3 3 / 81%);
    }
    & .header-band {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: #fff;
      font-size: 22px;
    }
    .button-group {
      .button {
        width: auto;
        border-radius: 4px;
        font-size: 14px;
        margin: 0;
        background-color: rgba(255, 255, 255, 0.3);
        color: #fff;
        font-weight: bold;
        border: 0;
        outline: 0;
        &:hover,
        &:focus {
          background-color: rgba(255, 255, 255, 0.2);
          cursor: pointer;
        }
        &:active {
          background-color: rgba(255, 255, 255, 0.1);
        }
        & .icon {
          display: inline-block;
          width: 20px;
        }
      }
    }
  }
</style>

μž‘μ—…ν•˜λ©΄μ„œ λŠλ‚€ 건 vuejsλž‘ μƒλ‹Ήνžˆ λΉ„μŠ·ν•˜λ‹€λŠ”κ²ƒμ„ λŠκΌˆμ–΄μš”.

 

μ΄λ ‡κ²Œ TheHeader.svelte μž‘μ—…μ„ 마친 λ’€

TheHeader.svelte importν•©λ‹ˆλ‹€.

 

App.svelte

<script>  
  import Header from '@/layout/TheHeader.svelte';

</script>

<Header />

 

μ™Όμͺ½ 메뉴 생성 및 메인화면 μž‘μ—…

pages - boards.svelte 생성

<script>
  import Icon from "svelte-fa";
  import { faColumns, faListAlt, faHome } from "@fortawesome/free-solid-svg-icons";

  let component = Main;
  const menuItems = [
    { id: 1, name: "Board", icon: faColumns, isActive: true },
    { id: 2, name: "templates", icon: faListAlt, isActive: false },
    { id: 3, name: "Home", icon: faHome, isActive: false },
  ];

  const selectMenu = (menuItem) => {
    menuItems.forEach((x) => {
      x.isActive = false;
    });
    if (!menuItem.isActive) {
      menuItem.isActive = true;
    }
    menuItems = menuItems;
  };
</script>

<svelte:head>
  <title>Board | Svelte</title>
</svelte:head>

<div class="container">
  <div class="left__contents">
    <ul class="menu">
      {#each menuItems as menuItem}
        <li class="menu__button">
          <button type="button" class="button" class:isActive={menuItem.isActive} on:click={() => selectMenu(menuItem)}><Icon icon={menuItem.icon} /> {menuItem.name}</button>
        </li>
      {/each}
    </ul>
  </div>
  <div class="right__contents">
    
  </div>
</div>

<style lang="scss">
  .container {
    display: flex;
    justify-content: center;
    height: calc(100% - 38px);
    overflow-y: auto;
    .left__contents {
      margin: 40px 0 0 0;
      padding: 0 16px;
      width: 240px;
      & .menu {
        list-style: none;
        margin: 0;
        padding: 0;
        & .menu__button {
          margin-bottom: 4px;
          .button {
            width: 100%;
            height: 32px;
            border-radius: 4px;
            border: 0;
            outline: 0;
            background-color: transparent;
            margin: 0;
            text-align: left;
            transition: all 0.4s ease-in-out;
            font-size: 1.4rem;
            &:hover {
              background-color: rgba(9, 30, 66, 0.08);
              cursor: pointer;
            }
            &:active {
              background-color: rgba(9, 30, 66, 0.1);
            }
            &.isActive {
              background-color: #e4f0f6;
              color: #0079bf;
            }
          }
        }
      }
    }
    .right__contents {
      max-width: 825px;
      min-width: 288px;
      width: 100%;
      margin: 40px 16px 0;
    }
  }
</style>
<svelte:head>
  <title>Board | Svelte</title>
</svelte:head>
html title에 λ°”λ‘œ μž…λ ₯이 λ˜λ„λ‘ ν•  수 μžˆλŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.
{#each menuItems as menuItem}
    <li class="menu__button">
      <button type="button" class="button" class:isActive={menuItem.isActive} on:click={() => selectMenu(menuItem)}><Icon icon={menuItem.icon} /> {menuItem.name}</button>
    </li>
{/each}

for문은 μ΄λŸ°μ‹μœΌλ‘œ μ‚¬μš©ν•˜λ„€μš”.

 

 

λ©”μΈν”„λ‘œμ νŠΈ 별 λŒ€μ‰¬λ³΄λ“œ μž‘μ—…

page - main.svelte 생성

<script>
  import image_1 from "@/assets/images/image-1.jpg";
  import { navigate } from "svelte-routing";
  

  const items = [
    { id: 1, name: "project", favorite: true },
    { id: 2, name: "μŠ€ν„°λ””", favorite: false },
    { id: 3, name: "개발", favorite: false },
    { id: 4, name: "-", favorite: false },
  ];


  const goProject = (id) => {
    
    navigate(`b/${id}`, { replace: true });
  };
</script>

<div class="boards-page-board-section">
  <div class="boards-page-board-section-title boards-page-board-section-title--star"><span class="icon"><span class="material-icons-outlined">grade</span></span> Starred boards</div>
  <div class="boards-page-board-section-list">
    <div class="boards-page-board-section-item" style="background-image: url({image_1});">
      <div class="item-detail" on:click={() => goProject("project")}>
        <div class="detail-name">Project</div>
        <div class="detail-option">
          <div class="star-icon__contents">
            <span class="material-icons-outlined">grade</span>
          </div>
        </div>
      </div>
    </div>
    <div class="boards-page-board-section-item">
      <div class="item-detail" />
    </div>
  </div>
</div>
<div class="boards-page-board-section">
  <div class="boards-page-board-section-title"><span class="material-icons-outlined"> schedule </span> Recently viewed</div>
  <div class="boards-page-board-section-list">
    {#each items as item, i}
      <div class="boards-page-board-section-item" style="background-image: url({image_1});">
        <div class="item-detail" on:click={() => goProject(item.name)}>
          <div class="detail-name">{item.name}</div>
          <div class="detail-option">
            <div class="star-icon__contents">
              <span class="material-icons-outlined">grade</span>
            </div>
          </div>
        </div>
        <div class="item-tile-fade" on:click={goProject} />
      </div>
    {/each}
  </div>
</div>
<div class="boards-page-board-section">
  <div class="boards-page-board-section-title">YOUR WORKSPACES</div>
  <div class="boards-page-board-section-list">
    <div class="boards-page-board-section-item" style="background-image: url({image_1});">
      <div class="item-detail" on:click={() => goProject('project')}>
        <div class="detail-name">Project</div>
        <div class="detail-option">
          <div class="star-icon__contents">
            <span class="material-icons-outlined">grade</span>
          </div>
        </div>
      </div>
      <div class="item-tile-fade" on:click={goProject} />
    </div>
    <div class="boards-page-board-section-item">
      <div class="item-detail" />
    </div>
  </div>
</div>
<div class="boards-page-board-section">
  <div class="boards-page-board-section-title">GUEST WORKSPACES</div>
  <div class="boards-page-board-section-list">
    <div class="boards-page-board-section-item" style="background-image: url({image_1});">
      <div class="item-detail">
        <div class="detail-name">Project</div>
        <div class="detail-option">
          <div class="star-icon__contents">
            <span class="material-icons-outlined">grade</span>
          </div>
        </div>
      </div>
      <div class="item-tile-fade" />
    </div>
    <div class="boards-page-board-section-item">
      <div class="item-detail" />
    </div>
  </div>
</div>

<style lang="scss">
  .boards-page-board-section {
    width: 100%;
    padding: 0 0 20px;
    .boards-page-board-section-title {
      font-size: 1.6rem;
      font-weight: 700;
      &--star {
        & .icon {
          color: rgb(230, 226, 0);
        }
      }
    }
    .boards-page-board-section-list {
      display: flex;
      flex-wrap: wrap;
    }
    .boards-page-board-section-item {
      width: 23.5%;
      margin: 0 2% 2% 0;
      padding: 8px;
      position: relative;
      background-position: 50%;
      background-size: cover;
      &:hover {
        cursor: pointer;
      }
      .item-tile-fade {
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        background-color: #00000026;
        &:hover {
          & ~ .item-detail {
            & .detail-option {
              .star-icon__contents {
                width: 25px;
              }
            }
          }
        }
      }
      .item-detail {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        height: 80px;
        position: relative;
        z-index: 1;

        &:hover {
          & ~ .item-tile-fade {
            background-color: rgba(0, 0, 0, 0.322);
          }
          & .detail-option {
            .star-icon__contents {
              width: 25px;
            }
          }
        }
        .detail-name {
          font-size: 1.6rem;
          color: #fff;
          font-weight: 700;
        }
        .detail-option {
          width: 100%;
          height: 18px;
          .star-icon__contents {
            position: absolute;
            right: 0;
            line-height: 1%;
            color: #fff;
            font-size: 1.2rem;
            width: 0;
            transition: width 0.2s ease-in-out;
            overflow: hidden;
            &:hover {
              width: 25px;
              transform: scale(1.2);
            }
            .material-icons-outlined {
              font-size: 16px;
            }
          }
        }
      }
    }
  }
</style>

main.svelte μž‘μ—…μ„ 마친 λ’€

import ν•΄μ€λ‹ˆλ‹€.

 

boards.svelte

<script>
  ...
  import Main from "@/pages/main.svelte";
  let component = Main;
  ...
</script>

...
<div class="right__contents">
  <svelte:component this={component} />
</div>

svelte:componentλŠ” 동적 μ»΄ν¬λ„ŒνŠΈλ‘œ μ‚¬μš©ν•˜λ©΄ 될 것 κ°™μ•„μš”.

 

μ—¬κΈ°κΉŒμ§€ 메인화면 μž‘μ—…μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

 

κ°μ‚¬ν•©λ‹ˆλ‹€

728x90
λ°˜μ‘ν˜•
LIST

'IT > Svelte' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

BH] Svelte νŠœν† λ¦¬μ–Ό - 1편 (Trello)  (0) 2021.09.12
BH] Svelte νŠœν† λ¦¬μ–Ό - 1편 (Blog App)  (0) 2021.08.19