Skip to content

๐Ÿ‘Š๐Ÿผ Daily Mission โ€‹

HTML/CSS โ€‹

Day 1 ๋‚˜์˜ ํ•˜๋ฃจ ๋ฌธ์„œ ๋งŒ๋“ค๊ธฐ

day1mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ

Day 2 ํ”„๋กœํ•„ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ

day2mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


Day 3 ์„ค๋ฌธ์กฐ์‚ฌ ์–‘์‹ ๋ฐ ํšŒ์›๊ฐ€์ž… ํผ

day3mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


day3mission

day3mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


Day 4 ํ”„๋กœํ•„ ํŽ˜์ด์ง€, ์ฑ„ํŒ…๋ฐฉ, ๋ˆˆ์‚ฌ๋žŒ

day4mission
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


day4mission
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


day4mission
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


Day 5 ์ฑ„ํŒ…๋ฐฉ ๋””๋ฒจ๋กญ, ๋ฐ˜์‘ํ˜• ์›น, ๋ฐ˜์‘ํ˜• ์›น ๋””๋ฒจ๋กญ, ํด๋ก 

day5mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


day5mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


day5mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


day5mission

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ์ œ์ถœํ•œ ์ฝ”๋“œ๋ณด๊ธฐ


JavaScript โ€‹

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป StackBlitz Collections

day 6 ๋ณ€์ˆ˜์™€ ํƒ€์ž… ๊ฐœ๋…

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 1์ผ์ฐจ ๋ณด๋ฌผ ์ƒ์ž์—ด๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 1์ผ์ฐจ ๋™๋ฌผ ์ถœ๋ ฅํ•˜๊ธฐ

๐Ÿ’ก Node.js ํ™˜๊ฒฝ์—์„œ๋Š” .js ํŒŒ์ผ์„ ์‹คํ–‰ํ•  ๋•Œ ํ„ฐ๋ฏธ๋„์—์„œ node main.js์ฒ˜๋Ÿผ ๋ช…๋ น์–ด๋กœ ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ด๋ฒˆ์— ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

day 7 ํƒ€์ž… ๊ฐœ๋… ๋ฐ ๋ฉ”์„œ๋“œ ํ™œ์šฉ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 2์ผ์ฐจ ์˜ค๋ฅ˜ ์ˆ˜์ •ํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 2์ผ์ฐจ ์ฃผ์‚ฌ์œ„ ๋งŒ๋“ค๊ธฐ

js
// min ์ด์ƒ max ์ดํ•˜์˜ ์ •์ˆ˜๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๊ณต์‹
Math.floor(Math.random() * (max - min + 1)) + min;
day 8 ์กฐ๊ฑด๋ฌธ๊ณผ ๋ฐ˜๋ณต๋ฌธ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 3์ผ์ฐจ ์ˆ˜์—ด ๊ณ„์‚ฐํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 3์ผ์ฐจ ๋ฐฐ๋‹ฌ ์ฃผ๋ฌธํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 3์ผ์ฐจ ์œค๋…„ ๊ตฌํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 3์ผ์ฐจ ๋ณ„ ์ฐ๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 3์ผ์ฐจ ์†Œ์ˆ˜ ํŒ๋ณ„ํ•˜๊ธฐ

day 9 ๋ฐฐ์—ด ๊ธฐ์ดˆ ๋ฐ ๋ฐฐ์—ด ๋ฐ˜๋ณต๋ฌธ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 4์ผ์ฐจ ์ฃผ๊ฐ„ ๋…์„œ ์ด๋ฒคํŠธ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 4์ผ์ฐจ ์‹ ๊ทœ ๊ณ ๊ฐ ์„ ๋ณ„ํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 4์ผ์ฐจ ๋ด„ ์˜ท ๊ณ ๋ฅด๊ธฐ

day 10 ํ•จ์ˆ˜ ๊ธฐ์ดˆ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 5์ผ์ฐจ ์ฃผ์‚ฌ์œ„ ๋งŒ๋“ค๊ธฐ 2

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 5์ผ์ฐจ ์œค๋…„ ๊ตฌํ•˜๊ธฐ 2

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 5์ผ์ฐจ ์นดํŽ˜ ์ฃผ๋ฌธํ•˜๊ธฐ

day 11 ๊ฐ์ฒด ๊ธฐ์ดˆ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 6์ผ์ฐจ ๊ณ„์‚ฐ๊ธฐ ๋งŒ๋“ค๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 6์ผ์ฐจ ํ•  ์ผ ๋ชฉ๋ก ๊ด€๋ฆฌํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 6์ผ์ฐจ ํ ์ž๋ฃŒ๊ตฌ์กฐ ๋งŒ๋“ค๊ธฐ

day 12 ๋ฐฐ์—ด, ๊ฐ์ฒด ์‘์šฉ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 7์ผ์ฐจ ์ง์› ๊ด€๋ฆฌํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 7์ผ์ฐจ ๋งˆ์™• ๋ฌผ๋ฆฌ์น˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 7์ผ์ฐจ ์Šคํƒ ์ž๋ฃŒ๊ตฌ์กฐ ๋งŒ๋“ค๊ธฐ

day 13 ํ•จ์ˆ˜ ์‘์šฉ, ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 8์ผ์ฐจ ์˜ค๋ฅ˜ ํ•ด๊ฒฐํ•˜๊ธฐ 2

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 8์ผ์ฐจ ํ…œํ”Œ๋ฆฟ ๋งŒ๋“ค๊ธฐ

day 14 DOM ๊ธฐ์ดˆ, ์ด๋ฒคํŠธ ๊ฐ์ฒด

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 9์ผ์ฐจ ํ–„๋ฒ„๊ฑฐ ์ฃผ๋ฌธ์„œ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 9์ผ์ฐจ ๋กœ๋˜ ๋ฒˆํ˜ธ ์ƒ์„ฑ๊ธฐ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๊ตฌํ˜„

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 9์ผ์ฐจ ๋กœ๋˜ ๋‹น์ฒจ ๋ฒˆํ˜ธ ๋ฐ ๋กœ๋˜ ๋ฒˆํ˜ธ ์ž๋™ ์ƒ์„ฑ

day 15 ๋น„๋™๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 10์ผ์ฐจ ์ˆœ๊ฐ„ ํฌ์ฐฉ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 10์ผ์ฐจ ์ฝœ๋ฐฑ ํƒˆ์ถœ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 10์ผ์ฐจ ๋ฐ˜์‘ ์†๋„

day 16 ๋ฐ์ดํ„ฐ fetch

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 11์ผ์ฐจ ๊ฐ•์•„์ง€ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 11์ผ์ฐจ ์˜ค๋Š˜์˜ ๋‚ ์”จ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป JavaScript 11์ผ์ฐจ ์˜ค๋Š˜ ๋ญ ์ž…์ง€?

day 17 ๊ณ„์‚ฐ๊ธฐ | DAY 1_HTML๋กœ ๋ชฉ์—… ๋งŒ๋“ค๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๊ณ„์‚ฐ๊ธฐ GitHub

๐Ÿ“‹ ์ง„ํ–‰ ๋‚ด์šฉ ์š”์•ฝ โ€‹

  • ์ดˆ๊ธฐ ํ”„๋กœ์ ํŠธ ์…‹์—… ๋ฐ ํ™˜๊ฒฝ ๊ตฌ์„ฑ
    โ†’ npm init์œผ๋กœ ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™”, package.json ๋ฐ .gitignore ์ž‘์„ฑ
  • ๊ณ„์‚ฐ๊ธฐ UI ๋ชฉ์—… ๋ฐ ๋ ˆ์ด์•„์›ƒ ์ž‘์„ฑ
  • ๊ธฐ๋ณธ ์Šคํƒ€์ผ๋ง ๋ฐ ๋ฒ„ํŠผ ๊ทธ๋ฃน ๊ตฌ์„ฑ
  • README ์ž‘์„ฑ: ํ”„๋กœ์ ํŠธ ๊ฐ€์ด๋“œ & ๋„ค์ด๋ฐ ๊ทœ์น™ ์ •๋ฆฌ

๐Ÿ”จ ๊ฐœ์„ ํ•  ์  โ€‹

๋ฏธ์…˜ ๊ฐ€์ด๋“œ์— ๋ช…ํ™•ํ•œ ํด๋ž˜์Šค๋ช… ๊ทœ์น™์ด ์—†์–ด, ๊ฐœ์ธ์ ์œผ๋กœ BEM ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋„ค์ด๋ฐ ๊ทœ์น™์„ ๋จผ์ € ์„ธ์›Œ ์ž‘์—…์„ ์ง„ํ–‰ํ–ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ดํ›„ DAY 2 ๋ฏธ์…˜์ง€๋ฅผ ํ™•์ธํ•ด๋ณด๋‹ˆ ํ•„์ˆ˜ ํด๋ž˜์Šค๋ช…์ด ์ถ”๊ฐ€๋กœ ์ง€์ •๋˜์–ด ์žˆ์–ด, ์ผ๋ถ€ ํด๋ž˜์Šค๋ช…์„ ์ˆ˜์ •ํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์ƒ๊ฒผ๋‹ค.

html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Calculator</title>
    <link rel="stylesheet" href="./src/style.css" />
  </head>
  <body>
    <main class="calculator">
      <h1 class="a11y-hidden">Calculator</h1>
      <div class="calc-container p-40">
        <!-- calculator window buttons -->
        <div class="calc__window-btns">
          <button
            class="calc__window-btn--close btn-xs"
            aria-label="ํ™”๋ฉด ๋‹ซ๊ธฐ"
            title="๋‹ซ๊ธฐ"
          ></button>
          <button
            class="calc__window-btn--min btn-xs"
            aria-label="ํ™”๋ฉด ์ตœ์†Œํ™”"
            title="์ตœ์†Œํ™”"
          ></button>
          <button
            class="calc__window-btn--max btn-xs"
            aria-label="ํ™”๋ฉด ์ตœ๋Œ€ํ™”"
            title="์ตœ๋Œ€ํ™”"
          ></button>
        </div>

        <!-- calculator display -->
        <div class="calc__display p-40"></div>

        <!-- calculator keypad -->
        <div class="calc__keypad p-40"></div>
      </div>
    </main>
  </body>
</html>
css
/* reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

button {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
}

/* color variables */
:root {
  --white: #ffffff;
  --black: #212121;
  --red: #ff5f57;
  --yellow: #ffbd2e;
  --green: #28c840;
}

/* calculator-layout */
.calculator {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.calc-container {
  width: 600px;
  height: 800px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  border: 4px solid #2d2f36;
}

/* calculator-inner */
.calc__window-btns {
  display: flex;
  gap: 8px;
}

.calc__window-btn--close {
  background-color: var(--red);
}
.calc__window-btn--min {
  background-color: var(--yellow);
}
.calc__window-btn--max {
  background-color: var(--green);
}

.calc__display {
  height: 120px;
  text-align: right;
  border: 4px solid #9000ff;
}

.calc__keypad {
  flex: 1;
  border: 4px solid #0085f9;
}

/* utils */
.a11y-hidden {
  position: absolute;
  overflow: hidden;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.btn-xs {
  width: 32px;
  height: 32px;
  border-radius: 50%;
}

.p-40 {
  padding: 40px;
}
day 18 ๊ณ„์‚ฐ๊ธฐ | DAY 2_HTML๋กœ ๋ชฉ์—… ๋งŒ๋“ค๊ธฐ, Flexbox๋กœ ์ •๋ ฌ ๋ฐ ๋ฐฐ์น˜ํ•˜๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๊ณ„์‚ฐ๊ธฐ GitHub

๐Ÿ“‹ ์ง„ํ–‰ ๋‚ด์šฉ ์š”์•ฝ โ€‹

  • ๊ณ„์‚ฐ๊ธฐ ๋ ˆ์ด์•„์›ƒ์— Flexbox ์ ์šฉํ•˜์—ฌ ์ •๋ ฌ ๋ฐ ๋ฐฐ์น˜ ๊ตฌํ˜„
  • ๋ฒ„ํŠผ ์ข…๋ฅ˜๋ณ„ ํด๋ž˜์Šค ์„ธ๋ถ„ํ™”
  • Pretendard ์›นํฐํŠธ ์ ์šฉ ๋ฐ UI ์Šคํƒ€์ผ๋ง ๋ฐ˜์˜
  • README ์ž‘์„ฑ: ๋ฐ๋ชจ url ๋ฐ ๋””์ž์ธ ์‹œ์•ˆ ๋ฐ˜์˜

๐Ÿ”จ ๊ฐœ์„ ํ•  ์  โ€‹

  • display์— ์ถœ๋ ฅ๋˜๋Š” ๊ธ€์ž๊ฐ€ ๋งŽ์•„์กŒ์„ ๋•Œ์˜ ํฐํŠธ ์‚ฌ์ด์ฆˆ ๋Œ€์‘์€ ์•„์ง ๋ฏธ๊ตฌํ˜„
html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Calculator</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/pretendard@1.3.8/dist/web/static/pretendard.css"
    />
    <link rel="stylesheet" href="./src/style.css" />
  </head>
  <body>
    <main class="calculator">
      <h1 class="a11y-hidden">๊ณ„์‚ฐ๊ธฐ</h1>
      <div class="calc-container">
        <!-- calculator window buttons -->
        <div class="calc__window-btns">
          <button
            type="button"
            class="calc__window-btn close"
            aria-label="ํ™”๋ฉด ๋‹ซ๊ธฐ"
            title="๋‹ซ๊ธฐ"
          ></button>
          <button
            type="button"
            class="calc__window-btn min"
            aria-label="ํ™”๋ฉด ์ตœ์†Œํ™”"
            title="์ตœ์†Œํ™”"
          ></button>
          <button
            type="button"
            class="calc__window-btn max"
            aria-label="ํ™”๋ฉด ์ตœ๋Œ€ํ™”"
            title="์ตœ๋Œ€ํ™”"
          ></button>
        </div>

        <!-- calculator display -->
        <!-- 
          - ์Šคํฌ๋ฆฐ๋ฆฌ๋” ์ž๋™ ์ฝ๊ธฐ: role="status" + aria-live="polite"
          - ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค ๊ฐ€๋Šฅ: tabindex="0"
          - input ๋Œ€์‹  div ์‚ฌ์šฉ (์ง์ ‘ ์ž…๋ ฅ ์—†์ด ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ๋งŒ ๋™์ž‘)
        -->
        <div
          class="calc__display"
          role="status"
          aria-live="polite"
          aria-label="๊ณ„์‚ฐ ๊ฒฐ๊ณผ"
          tabindex="0"
        >
          0
        </div>

        <!-- calculator buttons -->
        <div class="calc__buttons">
          <button type="button" class="button function clear" aria-label="์ดˆ๊ธฐํ™”" title="์ดˆ๊ธฐํ™”">
            <span class="button__inner">C</span>
          </button>
          <button type="button" class="button function" aria-label="๋ถ€ํ˜ธ ์ „ํ™˜" title="๋ถ€ํ˜ธ ์ „ํ™˜">
            <span class="button__inner">ยฑ</span>
          </button>
          <button type="button" class="button function" aria-label="ํผ์„ผํŠธ" title="ํผ์„ผํŠธ">
            <span class="button__inner">%</span>
          </button>
          <button type="button" class="button operator" aria-label="๋‚˜๋ˆ„๊ธฐ" title="๋‚˜๋ˆ„๊ธฐ">
            <span class="button__inner">/</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">7</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">8</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">9</span>
          </button>
          <button type="button" class="button operator" aria-label="๊ณฑํ•˜๊ธฐ" title="๊ณฑํ•˜๊ธฐ">
            <span class="button__inner">*</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">4</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">5</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">6</span>
          </button>
          <button type="button" class="button operator" aria-label="๋นผ๊ธฐ" title="๋นผ๊ธฐ">
            <span class="button__inner">-</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">1</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">2</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">3</span>
          </button>
          <button type="button" class="button operator" aria-label="๋”ํ•˜๊ธฐ" title="๋”ํ•˜๊ธฐ">
            <span class="button__inner">+</span>
          </button>
          <button type="button" class="button number zero">
            <span class="button__inner">0</span>
          </button>
          <button type="button" class="button decimal" aria-label="์†Œ์ˆ˜์ " title="์†Œ์ˆ˜์ ">
            <span class="button__inner">.</span>
          </button>
          <button type="button" class="button equal" aria-label="๊ณ„์‚ฐํ•˜๊ธฐ" title="๊ณ„์‚ฐํ•˜๊ธฐ">
            <span class="button__inner">=</span>
          </button>
        </div>
      </div>
      <div class="calc-shadow" aria-hidden="true"></div>
    </main>
    <script src="./src/script.js"></script>
  </body>
</html>
css
/* reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  font-family: "Pretendard", sans-serif;
  background-color: var(--black);
}

button {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
}

/* color variables */
:root {
  --white: #ffffff;
  --gray-100: #eeeeee;
  --gray-200: #dadada;
  --gray-300: #b8b8b8;
  --gray-400: #444444;
  --gray-600: #666666;
  --gray-700: #777777;
  --gray-800: #8c8c8c;
  --black: #222222;
  /* status color */
  --red: #ff5f57;
  --yellow: #ffbd2e;
  --green: #28c840;
}

/* calculator-layout */
.calculator {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.calc-container {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 20px;
  border-radius: 8px;
  border: 2px solid var(--white);
  background-color: var(--gray-100);
  z-index: 100;
}

.calc-shadow {
  position: absolute;
  bottom: 136px;
  width: 384px;
  height: 30px;
  background: var(--gray-300);
  border-radius: 0 0 12px 12px;
  background: linear-gradient(180deg, var(--gray-400) -20%, var(--gray-700) 90%);
}

/* calculator inner */
/* window buttons */
.calc__window-btns {
  display: flex;
  gap: 8px;
}

.calc__window-btn {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 16px;
  background-color: var(--gray-600);
  transition: all 0.2s ease;
}

.calc__window-btn.close:hover {
  background-color: var(--red);
  background-image: url(./images/ico_close.svg);
}

.calc__window-btn.min:hover {
  background-color: var(--yellow);
  background-image: url(./images/ico_min.svg);
}
.calc__window-btn.max:hover {
  background-color: var(--green);
  background-image: url(./images/ico_max.svg);
}

/* display */
.calc__display {
  width: 340px;
  height: 88px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding: 20px;
  font-size: 32px;
  border-radius: 8px;
  color: var(--gray-100);
  background-color: var(--black);
}

/* buttons */
.calc__buttons {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-radius: 8px;
  padding: 4px;
  background-color: var(--black);
}

.button {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  color: var(--gray-600);
  padding: 20px;
  border-radius: 4px;
  background-color: var(--gray-200);
  transition: all 0.2s ease;
}

.button__inner {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  font-size: 18px;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--gray-300) 20%, var(--gray-100) 60%);
}

.button.zero {
  flex-grow: 1;
}

.button:hover {
  background-color: var(--gray-300);
}

.button:active {
  transform: scale(0.9);
  background-color: var(--gray-800);
  box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.4);
}

/* utils */
.a11y-hidden {
  position: absolute;
  overflow: hidden;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
day 19 ๊ณ„์‚ฐ๊ธฐ | DAY 3_๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋””์Šคํ”Œ๋ ˆ์ด์— ํ‘œ์‹œ๋˜๋„๋ก ๋งŒ๋“ค๊ธฐ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๊ณ„์‚ฐ๊ธฐ GitHub

๐Ÿ“‹ ์ง„ํ–‰ ๋‚ด์šฉ ์š”์•ฝ โ€‹

  • ๊ฐ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ console์— ๊ฐ ๋ฒ„ํŠผ์˜ value ์ถœ๋ ฅ
  • ์ˆซ์ž ๋””์Šคํ”Œ๋ ˆ์ด์— ํ‘œ์‹œ
  • ์†Œ์ˆ˜์  ์ค‘๋ณต ์ž…๋ ฅ ๋ฐฉ์ง€ ๋กœ์ง ๊ตฌํ˜„
  • Clear ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • ์ฝ˜์†”์— ์ž…๋ ฅ ํ๋ฆ„ ์‹œ๊ฐ์ ์œผ๋กœ ๋””๋ฒ„๊น…

๐Ÿ”จ ๊ฐœ์„ ํ•  ์  โ€‹

  • btnClick ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์กฐ๊ฑด๋ฌธ์ด ๋งŽ์•„ ๋ณต์žกํ•˜๊ณ , console.log(clickedBtnText)๊ฐ€ ์ค‘๋ณต๋˜์–ด ์žˆ์–ด์„œ ๋ฒ„ํŠผ ํƒ€์ž…๋ณ„ ๋™์ž‘์„ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜๊ฑฐ๋‚˜, switch๋ฌธ ๋“ฑ์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง ์ง„ํ–‰ ์˜ˆ์ •
  • ์ฝ˜์†”์— ๋ชจ๋“  clickedBtnText๋ฅผ ์ถœ๋ ฅํ•˜์ง€๋งŒ, ์‹ค์ œ ๋™์ž‘์ƒ ํ•„์š” ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด ๋ฏธ์…˜ ์™„๋ฃŒ ํ›„ ๊ฐœ์„  ์˜ˆ์ •
  • ๋””์Šคํ”Œ๋ ˆ์ด ๊ธ€์ž ์ˆ˜์— ๋”ฐ๋ฅธ ๊ธ€์ž ํฌ๊ธฐ ์กฐ์ ˆ์€ ์•„์ง ๊ตฌํ˜„ ์ „
  • ์—ฐ์‚ฐ์ž, ๊ธฐ๋Šฅ, ๊ฒฐ๊ณผ ๋ฒ„ํŠผ์— ๋Œ€ํ•œ ๋™์ž‘ ๊ตฌํ˜„์€ ๋ฏธ๊ตฌํ˜„ ์ƒํƒœ (day 4)

๐Ÿงฉ forEach()๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ  (feat.map() ๋ฉ”์„œ๋“œ) โ€‹

js
// ์ œ์ถœ ์ฝ”๋“œ

// ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋“ฑ๋ก
calcButtons.forEach((button) => {
  button.addEventListener("click", btnClick);
});

// ๐Ÿ” ๋””๋ฒ„๊น…์šฉ ์ถœ๋ ฅ
console.log(calcButtons);
// ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ(.button)์„ ๋ชจ๋‘ ์„ ํƒํ•˜๋ฉด NodeList๊ฐ€ ๋ฐ˜ํ™˜๋จ
// NodeList๋Š” ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์ง€๋งŒ, forEach() ๋ฉ”์„œ๋“œ๋กœ ์ˆœํšŒ ๊ฐ€๋Šฅ
  • ๋ชจ๋“  ๋ฒ„ํŠผ์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด forEach()๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
  • ์ „์—ญ์—์„œ const calcButtons = document.querySelectorAll(".button");๋ฅผ ํ†ตํ•ด ๋ฒ„ํŠผ๋“ค์„ ๊ฐ€์ ธ์˜ค๊ณ , ์ฝ˜์†”์— ์ถœ๋ ฅํ•ด๋ณด๋ฉด NodeList๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค. NodeList๋Š” ๋ฐฐ์—ด๊ณผ ๋น„์Šทํ•œ ๊ตฌ์กฐ์˜ ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์ด๋ฉฐ, forEach() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿงฉ map()

  • map()์€ ์›๋ณธ ๋ฐฐ์—ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์— ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌํ„ด๊ฐ’์ด ํ•„์š”์—†๋Š” ๊ฒฝ์šฐ์—๋Š” map()๋ณด๋‹ค๋Š” forEach()๊ฐ€ ์ ํ•ฉํ•˜๋‹ค.
  • ํ˜„ ๊ณ„์‚ฐ๊ธฐ์—์„œ๋Š” ๊ฐ ๋ฒ„ํŠผ์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ์ž‘์—…์ด๋ฏ€๋กœ forEach()๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๐Ÿงฉ NodeList?

  • NodeList๋Š” ๋ฐฐ์—ด๊ณผ ๋น„์Šทํ•œ ๊ตฌ์กฐ์˜ ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์ด๋ฉฐ, ์ธ๋ฑ์Šค๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ณ , length ์†์„ฑ๋„ ์กด์žฌํ•˜์ง€๋งŒ, ์ง„์งœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฐฐ์—ด์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— push(), pop() ๋“ฑ์˜ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
  • ํ•˜์ง€๋งŒ, NodeList๋Š” forEach() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” iterable ๊ฐ์ฒด์ด๋‹ค. ๋ฐฐ์—ด์ฒ˜๋Ÿผ ์š”์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ๊ฐ ๋ฒ„ํŠผ์— ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿงฉ iterable ๊ฐ์ฒด?

  • ๐Ÿ“Ž iterable object
  • ์ดํ„ฐ๋Ÿฌ๋ธ” ๊ฐ์ฒด๋ž€? for...of, spread, Array.from() ๋“ฑ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋กœ์„œ, ๋‚ด๋ถ€์— Symbol.iterator() ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.
  • ๋ฐฐ์—ด, ๋ฌธ์ž์—ด, NodeList, Set, Map ๋“ฑ์€ ๋ชจ๋‘ iterable์ด๊ณ  ์ผ๋ฐ˜ ๊ฐ์ฒด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ iterable์ด ์•„๋‹ˆ๋‹ค.
  • ์ด๋•Œ ์‚ฌ์šฉ๋˜๋Š” Symbol.iterator๋Š” ์‹ฌ๋ณผ(Symbol) ํƒ€์ž…์˜ ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ทธ๋™์•ˆ ๋งค๋ฒˆ ์ง€๋‚˜์ณค๋˜ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž… ์ค‘ '์‹ฌ๋ณผ(Symbol)'์— ๋Œ€ํ•ด ์ œ๋Œ€๋กœ ์ดํ•ดํ•  ํ•„์š”์„ฑ์„ ๋А๊ผˆ๋‹ค.. ๐Ÿ”ซ

reference โ€‹


html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Calculator</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/pretendard@1.3.8/dist/web/static/pretendard.css"
    />
    <link rel="stylesheet" href="./src/style.css" />
  </head>
  <body>
    <main class="calculator">
      <h1 class="a11y-hidden">๊ณ„์‚ฐ๊ธฐ</h1>
      <div class="calc-container">
        <!-- calculator window buttons -->
        <div class="calc__window-btns">
          <button
            type="button"
            class="calc__window-btn close"
            aria-label="ํ™”๋ฉด ๋‹ซ๊ธฐ"
            title="๋‹ซ๊ธฐ"
          ></button>
          <button
            type="button"
            class="calc__window-btn min"
            aria-label="ํ™”๋ฉด ์ตœ์†Œํ™”"
            title="์ตœ์†Œํ™”"
          ></button>
          <button
            type="button"
            class="calc__window-btn max"
            aria-label="ํ™”๋ฉด ์ตœ๋Œ€ํ™”"
            title="์ตœ๋Œ€ํ™”"
          ></button>
        </div>

        <!-- calculator display -->
        <!-- 
          - ์Šคํฌ๋ฆฐ๋ฆฌ๋” ์ž๋™ ์ฝ๊ธฐ: role="status" + aria-live="polite"
          - ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค ๊ฐ€๋Šฅ: tabindex="0"
          - input ๋Œ€์‹  div ์‚ฌ์šฉ (์ง์ ‘ ์ž…๋ ฅ ์—†์ด ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ๋งŒ ๋™์ž‘)
        -->
        <div
          class="calc__display"
          role="status"
          aria-live="polite"
          aria-label="๊ณ„์‚ฐ ๊ฒฐ๊ณผ"
          tabindex="0"
        >
          0
        </div>

        <!-- calculator buttons -->
        <div class="calc__buttons">
          <button type="button" class="button function clear" aria-label="์ดˆ๊ธฐํ™”" title="์ดˆ๊ธฐํ™”">
            <span class="button__inner">C</span>
          </button>
          <button type="button" class="button function" aria-label="๋ถ€ํ˜ธ ์ „ํ™˜" title="๋ถ€ํ˜ธ ์ „ํ™˜">
            <span class="button__inner">ยฑ</span>
          </button>
          <button type="button" class="button function" aria-label="ํผ์„ผํŠธ" title="ํผ์„ผํŠธ">
            <span class="button__inner">%</span>
          </button>
          <button type="button" class="button operator" aria-label="๋‚˜๋ˆ„๊ธฐ" title="๋‚˜๋ˆ„๊ธฐ">
            <span class="button__inner">/</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">7</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">8</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">9</span>
          </button>
          <button type="button" class="button operator" aria-label="๊ณฑํ•˜๊ธฐ" title="๊ณฑํ•˜๊ธฐ">
            <span class="button__inner">*</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">4</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">5</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">6</span>
          </button>
          <button type="button" class="button operator" aria-label="๋นผ๊ธฐ" title="๋นผ๊ธฐ">
            <span class="button__inner">-</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">1</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">2</span>
          </button>
          <button type="button" class="button number">
            <span class="button__inner">3</span>
          </button>
          <button type="button" class="button operator" aria-label="๋”ํ•˜๊ธฐ" title="๋”ํ•˜๊ธฐ">
            <span class="button__inner">+</span>
          </button>
          <button type="button" class="button number zero">
            <span class="button__inner">0</span>
          </button>
          <button type="button" class="button decimal" aria-label="์†Œ์ˆ˜์ " title="์†Œ์ˆ˜์ ">
            <span class="button__inner">.</span>
          </button>
          <button type="button" class="button equal" aria-label="๊ณ„์‚ฐํ•˜๊ธฐ" title="๊ณ„์‚ฐํ•˜๊ธฐ">
            <span class="button__inner">=</span>
          </button>
        </div>
      </div>
      <div class="calc-shadow" aria-hidden="true"></div>
    </main>
    <script src="./src/script.js"></script>
  </body>
</html>
css
/* reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  font-family: "Pretendard", sans-serif;
  background-color: var(--black);
}

button {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
}

/* color variables */
:root {
  --white: #ffffff;
  --gray-100: #eeeeee;
  --gray-200: #dadada;
  --gray-300: #b8b8b8;
  --gray-400: #444444;
  --gray-600: #666666;
  --gray-700: #777777;
  --gray-800: #8c8c8c;
  --black: #222222;
  /* status color */
  --red: #ff5f57;
  --yellow: #ffbd2e;
  --green: #28c840;
}

/* calculator-layout */
.calculator {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.calc-container {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 20px;
  border-radius: 8px;
  border: 2px solid var(--white);
  background-color: var(--gray-100);
  z-index: 100;
}

.calc-shadow {
  position: absolute;
  bottom: 136px;
  width: 384px;
  height: 30px;
  background: var(--gray-300);
  border-radius: 0 0 12px 12px;
  background: linear-gradient(180deg, var(--gray-400) -20%, var(--gray-700) 90%);
}

/* calculator inner */
/* window buttons */
.calc__window-btns {
  display: flex;
  gap: 8px;
}

.calc__window-btn {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 16px;
  background-color: var(--gray-600);
  transition: all 0.2s ease;
}

.calc__window-btn.close:hover {
  background-color: var(--red);
  background-image: url(./images/ico_close.svg);
}

.calc__window-btn.min:hover {
  background-color: var(--yellow);
  background-image: url(./images/ico_min.svg);
}
.calc__window-btn.max:hover {
  background-color: var(--green);
  background-image: url(./images/ico_max.svg);
}

/* display */
.calc__display {
  width: 340px;
  height: 88px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding: 20px;
  font-size: 32px;
  border-radius: 8px;
  color: var(--gray-100);
  background-color: var(--black);
}

/* buttons */
.calc__buttons {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-radius: 8px;
  padding: 4px;
  background-color: var(--black);
}

.button {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  color: var(--gray-600);
  padding: 20px;
  border-radius: 4px;
  background-color: var(--gray-200);
  transition: all 0.2s ease;
}

.button__inner {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  font-size: 18px;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--gray-300) 20%, var(--gray-100) 60%);
}

.button.zero {
  flex-grow: 1;
}

.button:hover {
  background-color: var(--gray-300);
}

.button:active {
  transform: scale(0.9);
  background-color: var(--gray-800);
  box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.4);
}

/* utils */
.a11y-hidden {
  position: absolute;
  overflow: hidden;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
js
// ๊ณ„์‚ฐ๊ธฐ DOM ์š”์†Œ (์ „์—ญ)
const calcButtons = document.querySelectorAll(".button"); // ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ๋“ค
const calcDisplay = document.querySelector(".calc__display"); // ๊ณ„์‚ฐ๊ธฐ ํ™”๋ฉด

// ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์‹คํ–‰
const btnClick = (event) => {
  // ํด๋ฆญ๋œ ๋ฒ„ํŠผ ๊ด€๋ จ ๋ณ€์ˆ˜ (์ง€์—ญ)
  const clickedBtn = event.currentTarget; // ํด๋ฆญ๋œ ๋ฒ„ํŠผ ์š”์†Œ
  const clickedBtnText = clickedBtn.querySelector(".button__inner").textContent; // ๋ฒ„ํŠผ ์•ˆ์˜ ํ…์ŠคํŠธ

  // ๋ฒ„ํŠผ ์ข…๋ฅ˜ ํ™•์ธ
  const isNumber = clickedBtn.classList.contains("number"); // ์ˆซ์ž ๋ฒ„ํŠผ ์—ฌ๋ถ€ ํ™•์ธ
  const isDecimal = clickedBtn.classList.contains("decimal"); // ์†Œ์ˆ˜์  ๋ฒ„ํŠผ ์—ฌ๋ถ€ ํ™•์ธ
  const isClear = clickedBtn.classList.contains("clear"); // ์ดˆ๊ธฐํ™”(C) ๋ฒ„ํŠผ ์—ฌ๋ถ€ ํ™•์ธ
  const isFunction = clickedBtn.classList.contains("function"); // ๊ธฐ๋Šฅ ๋ฒ„ํŠผ ์—ฌ๋ถ€ ํ™•์ธ
  const isOperator = clickedBtn.classList.contains("operator"); // ์—ฐ์‚ฐ์ž ๋ฒ„ํŠผ ์—ฌ๋ถ€ ํ™•์ธ
  const isEqual = clickedBtn.classList.contains("equal"); // ๊ฒฐ๊ณผ ๋ฒ„ํŠผ ์—ฌ๋ถ€

  // ํ˜„์žฌ display ํ™”๋ฉด(๊ณต๋ฐฑ ์ œ๊ฑฐ๋œ ๋ฌธ์ž์—ด)
  const currentDisplay = calcDisplay.textContent.trim();

  // ์ดˆ๊ธฐํ™”(C) ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ: ๋””์Šคํ”Œ๋ ˆ์ด 0์œผ๋กœ ์ดˆ๊ธฐํ™”
  if (isClear) {
    console.log(clickedBtnText);
    calcDisplay.textContent = 0;
    return; // ์ข…๋ฃŒ
  }

  // ๊ฒฐ๊ณผ ๋ฒ„ํŠผ
  if (isEqual) {
    console.log(clickedBtnText);
    return;
  }

  // ์—ฐ์‚ฐ์ž ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ: ์ฝ˜์†” ์ถœ๋ ฅ
  if (isOperator) {
    console.log(clickedBtnText);
    return;
  }

  // ๊ธฐ๋Šฅ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ: ์ฝ˜์†” ์ถœ๋ ฅ
  if (isFunction) {
    console.log(clickedBtnText);
    return;
  }

  // ์†Œ์ˆ˜์  ์ค‘๋ณต ์ž…๋ ฅ ๋ฐฉ์ง€: ๋””์Šคํ”Œ๋ ˆ์ด์— ์†Œ์ˆ˜์ ์ด ์—†๋‹ค๋ฉด ์ถ”๊ฐ€
  if (isDecimal) {
    console.log(clickedBtnText);
    if (!currentDisplay.includes(".")) {
      calcDisplay.textContent = currentDisplay + clickedBtnText;
    }
    return; // ์ด๋ฏธ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด ๋ฆฌํ„ด(๋ฌด์‹œ)
  }

  // ์ˆซ์ž ํด๋ฆญ ์‹œ: ํ˜„์žฌ ํ™”๋ฉด์ด 0์ด๋ฉด ํด๋ฆญ๋œ ๋ฒ„ํŠผ์˜ ๊ฐ’์œผ๋กœ ๋Œ€์ฒด, ์•„๋‹ˆ๋ฉด ์ด์–ด ๋ถ™์ด๊ธฐ
  if (isNumber) {
    console.log(clickedBtnText);
    if (currentDisplay === "0") {
      calcDisplay.textContent = clickedBtnText;
    } else {
      calcDisplay.textContent += clickedBtnText;
    }
  }
};

// ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋“ฑ๋ก
calcButtons.forEach((button) => {
  button.addEventListener("click", btnClick);
});

// ๐Ÿ” ๋””๋ฒ„๊น…์šฉ ์ถœ๋ ฅ
// console.log(calcButtons);
// ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ(.button)์„ ๋ชจ๋‘ ์„ ํƒํ•˜๋ฉด NodeList๊ฐ€ ๋ฐ˜ํ™˜๋จ
// NodeList๋Š” ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์ง€๋งŒ, forEach() ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์–ด์„œ ์ˆœํšŒ ๊ฐ€๋Šฅ
day 20 ๊ณ„์‚ฐ๊ธฐ | DAY 4_๊ณ„์‚ฐ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ & DAY 5_๋ฐฐํฌ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ๊ณ„์‚ฐ๊ธฐ GitHub

๐Ÿ“‹ ์ง„ํ–‰ ๋‚ด์šฉ ์š”์•ฝ โ€‹

  • btnClick ํ•จ์ˆ˜์— ๋ณต์žกํ•œ ์กฐ๊ฑด๋ฌธ์„ ๊ฐ ๋ฒ„ํŠผ๋งˆ๋‹ค ๊ธฐ๋Šฅ๋ณ„๋กœ ํ•จ์ˆ˜ ๋ถ„๋ฆฌ
  • ๊ฐ ๋ฒ„ํŠผ์— data-set ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด ๋ฒ„ํŠผ ์•ˆ์˜ ํ…์ŠคํŠธ๋ฅผ ์ง์ ‘ ์ฝ์ง€ ์•Š๊ณ  ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋„๋ก ๊ฐœ์„ 
  • firstOperand, secondOperand, operator ์ „์—ญ ๋ณ€์ˆ˜ ์ถ”๊ฐ€ ๋ฐ ์ƒํƒœ ์ €์žฅ
  • = ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ ์ถœ๋ ฅ ๋ฐ ์—ฐ์† ๊ณ„์‚ฐ ๊ตฌํ˜„
  • %, ยฑ, C ๊ธฐ๋Šฅ ๋ฒ„ํŠผ ๊ตฌํ˜„
  • 0์œผ๋กœ ๋‚˜๋ˆ„๋Š” ์ƒํ™ฉ์—์„œ "์ •์˜๋˜์ง€ ์•Š์Œ" ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ๋ฐ ์ƒํƒœ ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•ด checkNaN() ์ถ”๊ฐ€
  • ํ™”๋ฉด์— ์ˆซ์ž๊ฐ€ ๊ธธ์–ด์ง€๋ฉด ํฐํŠธ ํฌ๊ธฐ๊ฐ€ ์ค„์–ด๋“ค๋„๋ก adjustDisplayFontSize() ํ•จ์ˆ˜ ์ถ”๊ฐ€

๐ŸŒ ๋ฐฐํฌ ๊ณผ์ • โ€‹

  • Vercel์„ ์ด์šฉํ•ด ๊ณ„์‚ฐ๊ธฐ ํ”„๋กœ์ ํŠธ ๋ฐฐํฌ
    • .dev ๋„๋ฉ”์ธ์€ HTTPS๊ฐ€ ํ•„์ˆ˜๋ผ Cloudflare๋ฅผ ์ด์šฉํ•ด ๋ณด์•ˆ ์ธ์ฆ ์ฒ˜๋ฆฌ
    • ๊ฐ€๋น„์•„์—์„œ ๋„๋ฉ”์ธ ๊ตฌ์ž… โ†’ Cloudflare์— ๋“ฑ๋ก ํ›„ DNS ์„ค์ • (CNAME, A ๋ ˆ์ฝ”๋“œ)
    • Vercel ํ”„๋กœ์ ํŠธ ์„ค์ •์—์„œ Custom Domain ์—ฐ๊ฒฐ ์™„๋ฃŒ
    • ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์ •๋ฆฌ๋ฅผ ์œ„ํ•ด calculator ๋ ˆํฌ๋ฅผ hyebin-dev monorepo๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜(?)

๐Ÿ”จ ๊ฐœ์„ ํ•  ์  โ€‹

  • ์ „์—ญ ๋ณ€์ˆ˜ firstOperand, operator ๊ฐ™์€ ์ƒํƒœ๋“ค์„ ํ•˜๋‚˜์˜ state ๊ฐ์ฒด๋กœ ๋ฌถ์–ด์„œ ๊ด€๋ฆฌํ•  ์˜ˆ์ • โ†’ ์‹ค์‹œ๊ฐ„ ์„ธ์…˜์—์„œ ์•„์ด๋””์–ด๋ฅผ ์–ป์—ˆ๊ณ , ๊ตฌ์กฐ๊ฐ€ ํ›จ์”ฌ ๊น”๋”ํ•ด์งˆ ๊ฒƒ ๊ฐ™์•„์„œ ๊ผญ ์ ์šฉํ•ด๋ณด๊ณ  ์‹ถ๋‹ค.

    js
    // ์˜ˆ์‹œ
    const defaultState = {
      firstOperand: null,
      secondOperand: null,
      operator: null,
      shouldResetDisplay: false,
    };
    
    const state = { ...defaultState };
    
    Object.assign(state, defaultState);
  • calcDisplay.textContent๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋ฐ˜๋ณต๋ผ์„œ, getDisplay(), setDisplay() ๊ฐ™์€ ํ•จ์ˆ˜๋กœ display ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๋”ฐ๋กœ ๋นผ์„œ ๊ด€๋ฆฌํ•˜๊ณ  ์ค‘๋ณต์„ ์ค„์ด๋ ค ํ•œ๋‹ค.

  • ์ง€๊ธˆ์€ ํ•œ ํŒŒ์ผ ์•ˆ์— ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์„ž์—ฌ ์žˆ์–ด์„œ, ๊ธฐ๋Šฅ๋ณ„๋กœ JS ํŒŒ์ผ์„ ๋‚˜๋ˆ ๋ณด๋ ค ํ•œ๋‹ค. (์œ ํ‹ธ, ๊ธฐ๋Šฅ, ๊ณ„์‚ฐ, ์ด๋ฒคํŠธ ๋“ฑ)


html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Calculator</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/pretendard@1.3.8/dist/web/static/pretendard.css"
    />
    <link rel="stylesheet" href="./src/style.css" />
  </head>
  <body>
    <main class="calculator">
      <h1 class="a11y-hidden">๊ณ„์‚ฐ๊ธฐ</h1>
      <div class="calc-container">
        <!-- calculator window buttons -->
        <div class="calc__window-btns">
          <button
            type="button"
            class="calc__window-btn close"
            aria-label="ํ™”๋ฉด ๋‹ซ๊ธฐ"
            title="๋‹ซ๊ธฐ"
          ></button>
          <button
            type="button"
            class="calc__window-btn min"
            aria-label="ํ™”๋ฉด ์ตœ์†Œํ™”"
            title="์ตœ์†Œํ™”"
          ></button>
          <button
            type="button"
            class="calc__window-btn max"
            aria-label="ํ™”๋ฉด ์ตœ๋Œ€ํ™”"
            title="์ตœ๋Œ€ํ™”"
          ></button>
        </div>

        <!-- calculator display -->
        <!-- 
          - ์Šคํฌ๋ฆฐ๋ฆฌ๋” ์ž๋™ ์ฝ๊ธฐ: role="status" + aria-live="polite"
          - ํ‚ค๋ณด๋“œ ํฌ์ปค์Šค ๊ฐ€๋Šฅ: tabindex="0"
          - input ๋Œ€์‹  div ์‚ฌ์šฉ (์ง์ ‘ ์ž…๋ ฅ ์—†์ด ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ๋งŒ ๋™์ž‘)
        -->
        <div
          class="calc__display"
          role="status"
          aria-live="polite"
          aria-label="๊ณ„์‚ฐ ๊ฒฐ๊ณผ"
          tabindex="0"
        >
          0
        </div>

        <!-- calculator buttons -->
        <div class="calc__buttons">
          <button
            type="button"
            class="button function clear"
            data-set="C"
            aria-label="์ดˆ๊ธฐํ™”"
            title="์ดˆ๊ธฐํ™”"
          >
            <span class="button__inner">C</span>
          </button>
          <button
            type="button"
            class="button function"
            data-set="ยฑ"
            aria-label="๋ถ€ํ˜ธ ์ „ํ™˜"
            title="๋ถ€ํ˜ธ ์ „ํ™˜"
          >
            <span class="button__inner">ยฑ</span>
          </button>
          <button
            type="button"
            class="button function"
            data-set="%"
            aria-label="ํผ์„ผํŠธ"
            title="ํผ์„ผํŠธ"
          >
            <span class="button__inner">%</span>
          </button>
          <button
            type="button"
            class="button operator"
            data-set="/"
            aria-label="๋‚˜๋ˆ„๊ธฐ"
            title="๋‚˜๋ˆ„๊ธฐ"
          >
            <span class="button__inner">/</span>
          </button>
          <button type="button" class="button number" data-set="7">
            <span class="button__inner">7</span>
          </button>
          <button type="button" class="button number" data-set="8">
            <span class="button__inner">8</span>
          </button>
          <button type="button" class="button number" data-set="9">
            <span class="button__inner">9</span>
          </button>
          <button
            type="button"
            class="button operator"
            data-set="*"
            aria-label="๊ณฑํ•˜๊ธฐ"
            title="๊ณฑํ•˜๊ธฐ"
          >
            <span class="button__inner">*</span>
          </button>
          <button type="button" class="button number" data-set="4">
            <span class="button__inner">4</span>
          </button>
          <button type="button" class="button number" data-set="5">
            <span class="button__inner">5</span>
          </button>
          <button type="button" class="button number" data-set="6">
            <span class="button__inner">6</span>
          </button>
          <button type="button" class="button operator" data-set="-" aria-label="๋นผ๊ธฐ" title="๋นผ๊ธฐ">
            <span class="button__inner">-</span>
          </button>
          <button type="button" class="button number" data-set="1">
            <span class="button__inner">1</span>
          </button>
          <button type="button" class="button number" data-set="2">
            <span class="button__inner">2</span>
          </button>
          <button type="button" class="button number" data-set="3">
            <span class="button__inner">3</span>
          </button>
          <button
            type="button"
            class="button operator"
            data-set="+"
            aria-label="๋”ํ•˜๊ธฐ"
            title="๋”ํ•˜๊ธฐ"
          >
            <span class="button__inner">+</span>
          </button>
          <button type="button" class="button number zero" data-set="0">
            <span class="button__inner">0</span>
          </button>
          <button
            type="button"
            class="button decimal"
            data-set="."
            aria-label="์†Œ์ˆ˜์ "
            title="์†Œ์ˆ˜์ "
          >
            <span class="button__inner">.</span>
          </button>
          <button
            type="button"
            class="button equal"
            data-set="="
            aria-label="๊ณ„์‚ฐํ•˜๊ธฐ"
            title="๊ณ„์‚ฐํ•˜๊ธฐ"
          >
            <span class="button__inner">=</span>
          </button>
        </div>
      </div>
      <div class="calc-shadow" aria-hidden="true"></div>
    </main>
    <script src="./src/script.js"></script>
  </body>
</html>
css
/* reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  font-family: "Pretendard", sans-serif;
  background-color: var(--black);
}

button {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
}

/* color variables */
:root {
  --white: #ffffff;
  --gray-100: #eeeeee;
  --gray-200: #dadada;
  --gray-300: #b8b8b8;
  --gray-400: #444444;
  --gray-600: #666666;
  --gray-700: #777777;
  --gray-800: #8c8c8c;
  --black: #222222;
  /* status color */
  --red: #ff5f57;
  --yellow: #ffbd2e;
  --green: #28c840;
}

/* calculator-layout */
.calculator {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.calc-container {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 20px;
  border-radius: 8px;
  border: 2px solid var(--white);
  background-color: var(--gray-100);
  z-index: 100;
}

.calc-shadow {
  position: absolute;
  bottom: 136px;
  width: 384px;
  height: 30px;
  background: var(--gray-300);
  border-radius: 0 0 12px 12px;
  background: linear-gradient(180deg, var(--gray-400) -20%, var(--gray-700) 90%);
}

/* calculator inner */
/* window buttons */
.calc__window-btns {
  display: flex;
  gap: 8px;
}

.calc__window-btn {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-position: center;
  background-repeat: no-repeat;
  background-size: 16px;
  background-color: var(--gray-600);
  transition: all 0.2s ease;
}

.calc__window-btn.close:hover {
  background-color: var(--red);
  background-image: url(./images/ico_close.svg);
}

.calc__window-btn.min:hover {
  background-color: var(--yellow);
  background-image: url(./images/ico_min.svg);
}
.calc__window-btn.max:hover {
  background-color: var(--green);
  background-image: url(./images/ico_max.svg);
}

/* display */
.calc__display {
  width: 340px;
  height: 88px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding: 20px;
  font-size: 32px;
  border-radius: 8px;
  color: var(--gray-100);
  background-color: var(--black);
  transition: font-size 0.2s ease;
}

/* buttons */
.calc__buttons {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  border-radius: 8px;
  padding: 4px;
  background-color: var(--black);
}

.button {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  color: var(--gray-600);
  padding: 20px;
  border-radius: 4px;
  background-color: var(--gray-200);
  transition: all 0.2s ease;
}

.button__inner {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  font-size: 18px;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--gray-300) 20%, var(--gray-100) 60%);
}

.button.zero {
  flex-grow: 1;
}

.button:hover {
  background-color: var(--gray-300);
}

.button:active {
  transform: scale(0.9);
  background-color: var(--gray-800);
  box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.4);
}

/* utils */
.a11y-hidden {
  position: absolute;
  overflow: hidden;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
js
// DOM ์š”์†Œ (์ „์—ญ)
const calcButtons = document.querySelectorAll(".button"); // ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ๋“ค
const calcDisplay = document.querySelector(".calc__display"); // ๊ณ„์‚ฐ๊ธฐ ํ™”๋ฉด

// ๊ณ„์‚ฐ๊ธฐ ์ƒํƒœ ๋ณ€์ˆ˜ (์ „์—ญ)
let firstOperand = null; // ์ฒซ ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž
let secondOperand = null; // ๋‘ ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž
let operator = null; // ์—ฐ์‚ฐ์ž
let shouldResetDisplay = false; // ์ƒˆ ์ˆซ์ž ์ž…๋ ฅ ์‹œ, ๋””์Šคํ”Œ๋ ˆ์ด ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€

// ์—๋Ÿฌ
const isNotDefined = "์ •์˜๋˜์ง€ ์•Š์Œ";

// isNotDefined ์ฒดํฌ ํ•จ์ˆ˜
const checkNaN = () => {
  calcDisplay.textContent = isNotDefined;
  firstOperand = null;
  secondOperand = null;
  operator = null;
  shouldResetDisplay = true;
};

// display์˜ ๊ธ€์ž ์ˆ˜์— ๋”ฐ๋ผ ํฐํŠธ ํฌ๊ธฐ ์ค„์ด๋Š” ํ•จ์ˆ˜ (๋‹จ, ์ž…๋ ฅ ์ œํ•œ์€ ์—†์Œ)
const adjustDisplayFontSize = () => {
  const displayTextLength = calcDisplay.textContent.length;

  if (displayTextLength <= 14) {
    calcDisplay.style.fontSize = "";
  } else if (displayTextLength <= 20) {
    calcDisplay.style.fontSize = "22px";
  } else if (displayTextLength <= 26) {
    calcDisplay.style.fontSize = "18px";
  } else {
    calcDisplay.style.fontSize = "12px";
  }
};

// ์ดˆ๊ธฐํ™”(C) ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ: ๊ณ„์‚ฐ๊ธฐ ์ƒํƒœ ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™”
const clickClear = () => {
  firstOperand = null;
  secondOperand = null;
  operator = null;
  shouldResetDisplay = false;
  calcDisplay.textContent = "0";
  adjustDisplayFontSize();
};

// ์ˆซ์ž ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
const clickNumber = (number) => {
  const currentDisplay = calcDisplay.textContent.trim();

  // ์—ฐ์‚ฐ์ž ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ์ดํ›„๊ฑฐ๋‚˜(true), ํ˜„์žฌ ๋””์Šคํ”Œ๋ ˆ์ด๊ฐ€ "0"์ด๋ฉด ์ƒˆ ์ˆซ์ž๋กœ ๋ฐ˜์˜
  if (shouldResetDisplay || currentDisplay === "0") {
    calcDisplay.textContent = number;
    shouldResetDisplay = false;
  } else {
    // ์ด์–ด์„œ ์ˆซ์ž ์ž…๋ ฅ
    calcDisplay.textContent += number;
  }

  adjustDisplayFontSize();
};

// ์†Œ์ˆ˜์  ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
const clickDecimal = () => {
  const currentDisplay = calcDisplay.textContent.trim();

  if (currentDisplay === isNotDefined) {
    clickClear();
  }

  if (shouldResetDisplay) {
    // ์—ฐ์‚ฐ์ž ๋‹ค์Œ, ์ƒˆ ์ˆซ์ž๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ "0."๋ถ€ํ„ฐ ์‹œ์ž‘
    calcDisplay.textContent = "0.";
    shouldResetDisplay = false;
  } else if (!currentDisplay.includes(".")) {
    // ์†Œ์ˆ˜์  ์—†์œผ๋ฉด ์ถ”๊ฐ€
    calcDisplay.textContent += ".";
  }

  adjustDisplayFontSize();
};

// ์—ฐ์‚ฐ์ž ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
const clickOperator = (value) => {
  let currentDisplay = calcDisplay.textContent.trim();

  // ํ™”๋ฉด์— "์ •์˜๋˜์ง€ ์•Š์Œ"์ด๋ฉด clickClear() ํ˜ธ์ถœ ํ›„ 0๋ถ€ํ„ฐ ์‹œ์ž‘
  if (currentDisplay === isNotDefined) {
    clickClear();
    currentDisplay = "0";
  }

  if (firstOperand === null) {
    firstOperand = currentDisplay; // ์ฒซ ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž๊ฐ€ null์ด๋ฉด ํ˜„์žฌ ๊ฐ’์„ ์ €์žฅ
  } else if (operator && !shouldResetDisplay) {
    secondOperand = currentDisplay; // ๊ธฐ์กด ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ๊ณ , ์ƒˆ ์ˆซ์ž ์ž…๋ ฅ์ด ์žˆ๋‹ค๋ฉด ๊ณ„์‚ฐ ์ง„ํ–‰

    const result = calculate(firstOperand, operator, secondOperand);

    if (result === isNotDefined) {
      checkNaN();
      return;
    }

    calcDisplay.textContent = String(result); // ํ™”๋ฉด ์ถœ๋ ฅ ์‹œ ์ˆซ์ž -> ๋ฌธ์ž์—ด๋กœ ๋ณ€๊ฒฝ
    firstOperand = result; // ๊ณ„์‚ฐ ๊ฒฐ๊ณผ ๋‹ค์Œ ๊ณ„์‚ฐ์˜ ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž๋กœ ์ €์žฅ
  }

  operator = value; // ํด๋ฆญํ•œ ์—ฐ์‚ฐ๊ธฐํ˜ธ ์ €์žฅ
  shouldResetDisplay = true; // ์ƒˆ๋กœ์šด ์ˆซ์ž ์ž…๋ ฅ -> display ์ดˆ๊ธฐํ™” ์ƒํƒœ ๋ณ€๊ฒฝ

  console.log(`firstOperand: ${firstOperand}, operator: ${operator}`);
};

// = ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
const clickEqual = () => {
  // ์ฒซ ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž์™€ ์—ฐ์‚ฐ์ž๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด
  if (firstOperand !== null && operator !== null) {
    secondOperand = calcDisplay.textContent.trim(); // ํ˜„์žฌ ๊ฐ’์„ ๋„ฃ๊ณ  calculate() ์‹คํ–‰

    const result = calculate(firstOperand, operator, secondOperand);

    // NaN ์—๋Ÿฌ ํ™•์ธ
    if (result === isNotDefined) {
      checkNaN();
      return;
    }

    calcDisplay.textContent = String(result); // ํ™”๋ฉด ์ถœ๋ ฅ ์‹œ ์ˆซ์ž -> ๋ฌธ์ž์—ด๋กœ ๋ณ€๊ฒฝ
    adjustDisplayFontSize();

    // ์ฒซ ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž์— ๋‹ค์Œ ๊ณ„์‚ฐ์„ ์ด์–ด๊ฐ€๋„๋ก ๊ฒฐ๊ณผ ์ €์žฅ
    firstOperand = result;
    secondOperand = null;
    shouldResetDisplay = true;
  }
};

// function ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
const clickFunction = (funcValue) => {
  const currentDisplay = calcDisplay.textContent.trim();
  let result;

  switch (funcValue) {
    case "C": // ๋ณ„๋„ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜(clickClear) ํ˜ธ์ถœ
      return clickClear();
    case "ยฑ": // ํ˜„์žฌ ์ˆซ์ž์˜ ๋ถ€ํ˜ธ ์ „ํ™˜
      result = parseFloat(currentDisplay) * -1;
      break;
    case "%":
      const currentNum = parseFloat(currentDisplay);

      // ์ฒซ ๋ฒˆ์งธ ํ”ผ์—ฐ์‚ฐ์ž์™€ ์—ฐ์‚ฐ์ž๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด, ์ฆ‰ ํ”ผ์—ฐ์‚ฐ์ž์™€ ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ์œผ๋ฉด
      if (firstOperand !== null && operator !== null) {
        const firstNum = parseFloat(firstOperand);

        switch (operator) {
          case "+":
            result = (firstNum * currentNum) / 100;
            break;
          case "-":
            result = (firstNum * currentNum) / 100;
            break;
          case "*":
            result = currentNum / 100;
            break;
          case "/":
            result = currentNum / 100;
            break;
        }

        secondOperand = result;
        calcDisplay.textContent = String(result);
        adjustDisplayFontSize();

        return;
      } else {
        // ์—ฐ์‚ฐ์ž ์—†๋Š” ๊ฒฝ์šฐ
        result = currentNum / 100;
        secondOperand = result;
        calcDisplay.textContent = String(result);
        return;
      }
    default:
      return; // ์ •์˜๋˜์ง€ ์•Š์€ ๊ธฐ๋Šฅ ๊ณ ๋ ค
  }

  calcDisplay.textContent = String(result);
  adjustDisplayFontSize();
};

// calculate ํ•จ์ˆ˜: ์—ฐ์‚ฐ์ž์— ๋”ฐ๋ผ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
const calculate = (firstOperand, operator, secondOperand) => {
  // ๋ฌธ์ž์—ด์„ ๋ถ€๋™์†Œ์ˆ˜์  ์ˆซ์ž๋กœ ๋ณ€ํ™˜
  const firstNum = parseFloat(firstOperand);
  const secondNum = parseFloat(secondOperand);

  // ํ”ผ ์—ฐ์‚ฐ์ž๋“ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ NaN๋ฉด "์ •์˜๋˜์ง€ ์•Š์Œ ์ฒ˜๋ฆฌ"
  if (isNaN(firstNum) || isNaN(secondNum)) return isNotDefined;

  // ์—ฐ์‚ฐ ์กฐ๊ฑด๋ฌธ
  switch (operator) {
    case "+":
      return firstNum + secondNum;
    case "-":
      return firstNum - secondNum;
    case "*":
      return firstNum * secondNum;
    case "/":
      if (secondNum !== 0) {
        return firstNum / secondNum;
      } else {
        // secondNum์ด 0์ด๋ฉด '์ •์˜๋˜์ง€ ์•Š์Œ' ์ถœ๋ ฅ (๋ ˆํผ๋Ÿฐ์Šค: ๋งฅ๋ถ ๊ณ„์‚ฐ๊ธฐ)
        // ์ดํ›„ ์—ฐ์‚ฐ์ž, ์ˆซ์ž ์ž…๋ ฅ ์‹œ Nan ๋ฐ˜ํ™˜ ์ด์Šˆ๋กœ ๊ฐœ์„ 
        return isNotDefined;
      }
    default:
      return secondNum; // ์ •์˜๋˜์ง€ ์•Š์€ ์—ฐ์‚ฐ์ž ๊ณ ๋ ค
  }
};

// ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
const btnClick = (event) => {
  // ํด๋ฆญ๋œ ๋ฒ„ํŠผ ์š”์†Œ ๋ฐ ๊ฐ’
  const clickedBtn = event.currentTarget; // ํด๋ฆญํ•œ ๋ฒ„ํŠผ
  const clickedBtnValue = clickedBtn.dataset.set; // ๋ฒ„ํŠผ์— ์„ค์ •๋œ ๋ฐ์ดํ„ฐ ๊ฐ’ (html data-set)

  // ๋ฒ„ํŠผ ํด๋ž˜์Šค์— ๋”ฐ๋ผ ํ•จ์ˆ˜ ํ˜ธ์ถœ
  if (clickedBtn.classList.contains("clear")) return clickClear();
  if (clickedBtn.classList.contains("number")) return clickNumber(clickedBtnValue);
  if (clickedBtn.classList.contains("decimal")) return clickDecimal();
  if (clickedBtn.classList.contains("operator")) return clickOperator(clickedBtnValue);
  if (clickedBtn.classList.contains("equal")) return clickEqual();
  if (clickedBtn.classList.contains("function")) return clickFunction(clickedBtnValue);
};

// ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋“ฑ๋ก
calcButtons.forEach((button) => {
  button.addEventListener("click", btnClick);
});

// ๐Ÿ” ๋””๋ฒ„๊น…์šฉ ์ถœ๋ ฅ
// console.log(calcButtons);
// ๊ณ„์‚ฐ๊ธฐ ๋ฒ„ํŠผ(.button)์„ ๋ชจ๋‘ ์„ ํƒํ•˜๋ฉด NodeList๊ฐ€ ๋ฐ˜ํ™˜๋จ
// NodeList๋Š” ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด์ง€๋งŒ, forEach() ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์–ด์„œ ์ˆœํšŒ ๊ฐ€๋Šฅ

Git & GitHub โ€‹

Day 21 Git & GitHub 1

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป Commits on Jul 31, 2025

Day 22 Git & GitHub 2

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป Commits on Aug 01, 2025

Day 23 Git & GitHub 3
  • ๋ ˆํฌ์ง€ํ† ๋ฆฌ url ์ œ์ถœ

Git & GitHub ๋ธ”๋กœ๊ทธ ์ •๋ฆฌ

React โ€‹

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป StackBlitz Collections

Day 24 React๋ฅผ ์œ„ํ•œ Node.js, nvm, npm, npx

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป React 1์ผ์ฐจ package.json ์ˆ˜์ •ํ•˜๊ธฐ

Day 25

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป React 2์ผ์ฐจ

Day 26

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป React 3์ผ์ฐจ