ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์ผ์ • ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌํ•˜๊ธฐ – ์ด๋ฒคํŠธ ์ถ”๊ฐ€ ๋ฐ ์ €์žฅ ๊ตฌ์กฐ ์„ค๊ณ„


์ด๋ฒˆ ํŽธ์—์„œ๋Š” ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ์— ๊ผญ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ธ
“์ผ์ •(Event)”์„ ๋“ฑ๋กํ•˜๊ณ , ์ €์žฅํ•˜๋ฉฐ, ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ๋‹ฌ๋ ฅ์„ ๋„˜๊ธฐ๊ณ , ๋‚ ์งœ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์œผ๋‹ˆ,
๊ฐ ๋‚ ์งœ์— ์ผ์ •์„ ์ถ”๊ฐ€ํ•˜๊ณ  ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์•ผ๊ฒ ์ฃ ?


๐ŸŽฏ ๋ชฉํ‘œ

  • ์ผ์ •(Event) ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜ ๋ฐ ์ €์žฅ ๋ฐฉ์‹ ์„ค๊ณ„
  • ๋‚ ์งœ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์ผ์ •์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„
  • ๊ฐ ๋‚ ์งœ๋ณ„๋กœ ๋“ฑ๋ก๋œ ์ผ์ •์ด ์บ˜๋ฆฐ๋”์— ํ‘œ์‹œ๋˜๋„๋ก ์ฒ˜๋ฆฌ

๐Ÿง  ๋ฐ์ดํ„ฐ ์„ค๊ณ„

โœ… CalendarEvent ํƒ€์ž… ๋‹ค์‹œ ํ™•์ธ

// src/types.ts
export interface CalendarEvent {
  id: string;
  title: string;
  date: string; // YYYY-MM-DD (ISO ํ˜•์‹)
}

โœ… ์ƒํƒœ์— ์ด๋ฒคํŠธ ์ €์žฅ์†Œ ์ถ”๊ฐ€

๋ฐ˜์‘ํ˜•
export interface CalendarState {
  year: number;
  month: number;
  selectedDate?: Date;
  events: CalendarEvent[]; // ๐Ÿ’ก ์ถ”๊ฐ€๋จ
}

๐Ÿ“ฆ 1. ๊ฐ„๋‹จํ•œ ์ผ์ • ์ถ”๊ฐ€ UI ๊ตฌ์„ฑ

โœ… prompt()๋ฅผ ํ™œ์šฉํ•œ ์ž…๋ ฅ ๋ฐฉ์‹ (๊ฐ„๋‹จ MVP์šฉ)

// src/components/Calendar.ts
function handleAddEvent(date: Date, state: CalendarState): void {
  const title = prompt(`${date.toDateString()} ์ผ์ • ์ œ๋ชฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”:`);
  if (!title) return;

  const newEvent: CalendarEvent = {
    id: crypto.randomUUID(),
    title,
    date: date.toISOString().split("T")[0],
  };

  state.events.push(newEvent);
}

๐Ÿงฉ 2. ๋‚ ์งœ ํด๋ฆญ ์‹œ ์ผ์ • ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ์—ฐ๊ฒฐ

โœ… ๋‚ ์งœ ์…€ ํด๋ฆญ ์ด๋ฒคํŠธ์—์„œ ์ถ”๊ฐ€ ์‹คํ–‰

// src/components/Calendar.ts
import { handleAddEvent } from "./EventUtils";

export function attachCalendarEvents(
  target: HTMLElement,
  state: CalendarState,
  rerender: () => void
) {
  const cells = target.querySelectorAll(".calendar-cell:not(.header)");

  cells.forEach((cell) => {
    cell.addEventListener("click", () => {
      const dateStr = cell.getAttribute("data-date");
      if (dateStr) {
        const date = new Date(dateStr);
        state.selectedDate = date;
        handleAddEvent(date, state); // ์ผ์ • ์ถ”๊ฐ€
        rerender();
      }
    });
  });

  // ... ์ƒ๋žต๋œ ์›” ์ „ํ™˜ ์ฝ”๋“œ ์œ ์ง€
}

๐Ÿ–ผ๏ธ 3. ๋‚ ์งœ ์…€์— ์ผ์ • ํ‘œ์‹œ

โœ… renderCalendar ๋‚ด๋ถ€์— ์ผ์ • ๋ Œ๋”๋ง ์ถ”๊ฐ€

// ๊ฐ ๋‚ ์งœ ์…€ ์•ˆ์—์„œ ์ผ์ • ๋ Œ๋”๋ง
const eventsForDate = state.events.filter(
  (e) => e.date === date?.toISOString().split("T")[0]
);
const eventHTML = eventsForDate
  .map((e) => `<div class="event">${e.title}</div>`)
  .join("");

return `<div class="calendar-cell${inMonth ? "" : " out"}${isSelected ? " selected" : ""}" data-date="${dateStr}">
  ${day}
  ${eventHTML}
</div>`;

๐ŸŽจ 4. CSS ์Šคํƒ€์ผ ์ถ”๊ฐ€

.event {
  font-size: 0.75rem;
  background-color: #f2f2f2;
  margin-top: 4px;
  padding: 2px 4px;
  border-radius: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

๐Ÿš€ 5. index.ts ์—…๋ฐ์ดํŠธ

โœ… ์ดˆ๊ธฐ ์ƒํƒœ ์ •์˜์— events ํฌํ•จ

const state: CalendarState = {
  year: new Date().getFullYear(),
  month: new Date().getMonth(),
  events: [],
};

โœ… ๊ฒฐ๊ณผ ํ™•์ธ

npm run dev
  • ๋‚ ์งœ ํด๋ฆญ → prompt ์ฐฝ์— ์ผ์ • ์ž…๋ ฅ
  • ์ž…๋ ฅ ์™„๋ฃŒ ์‹œ ํ•ด๋‹น ๋‚ ์งœ์— ์ผ์ •์ด ํ‘œ์‹œ๋จ
  • ์ผ์ • ๋ฐ์ดํ„ฐ๋Š” ํ˜„์žฌ ์ƒํƒœ(state.events)์— ์ €์žฅ๋จ (ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ์‚ฌ๋ผ์ง)

๐Ÿ”„ ํ™•์žฅ ์•„์ด๋””์–ด

๊ธฐ๋Šฅ ์„ค๋ช…

โœ… ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ ์ƒˆ๋กœ๊ณ ์นจ ํ›„์—๋„ ์ผ์ • ์œ ์ง€
โœ… ์ผ์ • ์ˆ˜์ •/์‚ญ์ œ ์ผ์ • ํ•ญ๋ชฉ ํด๋ฆญ ์‹œ ์ˆ˜์ •/์‚ญ์ œ ๊ธฐ๋Šฅ ์ œ๊ณต
โœ… ์ผ์ • ์นดํ…Œ๊ณ ๋ฆฌ "์—…๋ฌด", "๊ฐœ์ธ" ๋“ฑ์˜ ๋ถ„๋ฅ˜ ์ถ”๊ฐ€
โœ… ๋ชจ๋‹ฌ ์ž…๋ ฅ์ฐฝ prompt ๋Œ€์‹  UI ๊ธฐ๋ฐ˜ ์ž…๋ ฅ ํผ ์ œ๊ณต

๐Ÿ“š ์ฐธ๊ณ ์ž๋ฃŒ


 

๋‹ค์Œ ํŽธ ์˜ˆ๊ณ :
๐Ÿ“˜ 7ํŽธ – ์ผ์ • ์ €์žฅ์†Œ ๊ฐœ์„ ํ•˜๊ธฐ: LocalStorage ๋˜๋Š” JSON ํŒŒ์ผ ์—ฐ๋™
ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ์—๋„ ์ผ์ •์ด ์œ ์ง€๋˜๋„๋ก ๋ฐ์ดํ„ฐ ์˜์†ํ™”(Storage) ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค! ๐Ÿง 
ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ์™„์„ฑ๋„๊ฐ€ ํ•œ ๋‹จ๊ณ„ ๋†’์•„์ง‘๋‹ˆ๋‹ค!

'study > ts' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์ผ์ • ๋ฐ์ดํ„ฐ ์˜๊ตฌ ์ €์žฅ โ€“ LocalStorage ์—ฐ๋™์œผ๋กœ ์ƒˆ๋กœ๊ณ ์นจ์—๋„ ์œ ์ง€ํ•˜๊ธฐ  (0) 2025.03.26
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ โ€“ ๋‚ ์งœ ์„ ํƒ๊ณผ ์›” ์ด๋™ ๊ธฐ๋Šฅ ๊ตฌํ˜„  (0) 2025.03.25
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌ์กฐ ์„ค๊ณ„ โ€“ ๋‚ ์งœ ๋ Œ๋”๋ง์„ ์œ„ํ•œ UI ๊ธฐ๋ณธ ๊ตฌ์„ฑ  (0) 2025.03.24
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - Webpack ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ธฐ โ€“ ๋ฒˆ๋“ค๋ง ๊ฐœ๋…๊ณผ ์„ค์ • ํŒŒ์ผ ์™„์ „ ๋ถ„์„  (0) 2025.03.24
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - TypeScript ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ธฐ โ€“ ํƒ€์ž… ์‹œ์Šคํ…œ๊ณผ ์บ˜๋ฆฐ๋” ๋ฐ์ดํ„ฐ ๋ชจ๋ธ๋ง  (0) 2025.03.23
โ€ป ์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค.
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/07   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ
๋ฐ˜์‘ํ˜•