
실행 가능한 모든 컴포넌트를 레이블 형태(아이콘)로 보여주고, 레이블을 클릭하면 그에 맞는 컴포넌트(=창)를 실행한다.
모듈을 어떻게 나눌까 고민했는데, 역시 메인 컴포넌트들을 각자의 .js 파일로 구현하고 바탕화면 역할을 하는 main.js에서 불러와서 사용하는 게 제일 직관적이라고 생각했다.
main.js에서 다른 파일에서 작성한 것들을 불러오려고 하니까 Cannot use import statement outside a module 에러가 났다. import를 사용할 스크립트는 최상단 html 파일에서 불러올 때 type="module" 을 사용해 모듈임을 명시해줘야 한다고 해서 다음과 같이 수정했다. 
index.html<head>
    <meta charset="UTF-8"/>
    ...
    <script src="./scripts/main.js" type="module" defer></script>
</head>
이제 main.js에서 import 구문을 사용할 수 있고, export하는 파일들은 따로 설정해줄 필요가 없다.
바탕화면 구조는
의 코드를 사용했다. 대강 아래와 같은 구조다.
index.html<body>
        <div id="desktop">
            <label for="windows-document-input" class="desktop-item">
                <div class="icon">
                    <img
                    	src="생략"
                        alt=""
                    />
                </div>
                <div class="text">Documents</div>
            </label>
          
          	...
          
          <div id="start-bar">
            <div id="start-button-items">
                <label
                    id="start-button"
                    class="windows-box-shadow"
                    for="start-button-input"
                ></label>
                <div id="items"></div>
            </div>
            <div id="time-options"></div>
        </div>
        ...
<body>태그 안에 <label>들을 배치했고 마지막에는 startbar가 있다.
(img src 부분은 링크가 너무 길어져서 생략)
컴포넌트들의 생성과 삭제, 이동을 담당
컴포넌트들을 생성, 삭제하고 이동하는 데 필요한 파일들을 import해오고 각 컴포넌트들의 아이콘(레이블)과 엘리먼트를 전역에서 관리한다.
또한 OPEN_EL_LIST를 두어 현재 열려 있는 창들을 관리한다.
별도의 인덱스 처리 없이 개별 컴포넌트를 담고 꺼내오기 위해 Set을 사용했다.
import { createDraggable } from './utility/drag-event.js';
import { clickCloseBtn, clickWindowEl } from './utility/click-event.js';
import { createClockEl, TIMERID } from './component/clock.js';
...
// Desktop Element: to append a new tab
const desktop = document.querySelector('#desktop');
// Get Desktop Items
const lifequoteLabel = document.querySelector('#life-quote');
const clockLabel = document.querySelector('#clock');
const timetableLabel = document.querySelector('#timetable');
const OPEN_EL_LIST = new Set();
// Elements will be created by click label
let clockEl = null;
let quoteEl = null;
let timetableEl = null;
컴포넌트를 생성하고 삭제하는 과정은 모든 컴포넌트가 제일 비슷하므로 대표로 시계 컴포넌트를 가져왔다.
// Desktop Element: to append a new tab
const desktop = document.querySelector('#desktop');
// Elements will be created by click label
let clockEl = null;
const clickClockLabel = () => {
    // Make sure only one window is open
    if (desktop.contains(clockEl)) return;
    clockEl = createClockEl();
    setAllListenerForWindowEl(clockEl);
    addWindowElToDesktop(clockEl); 	
};
clockLabel.addEventListener('click', clickClockLabel);
desktop.contains() 체크를 제일 먼저 수행한다. 이를 위해서 clockEl 요소를 let 전역변수로 빼줬다.clickClockLabel()을 실행할 수 있게 리스너를 달아준다.clockEl을 생성한 이후에 할 수 있는 작업들을 이어서 수행해준다.const setAllListenerForWindowEl = (elem) => {
    clickWindowEl(elem);
    clickCloseBtn(elem, TIMERID);
    createDraggable(elem);
};
const addWindowElToDesktop = (elem) => {
    desktop.append(elem);
    OPEN_EL_LIST.add(elem);
};
- 바탕화면 CSS, 구조
 
https://codepen.io/Mohiaish/details/yLqXZOw
- Windows 98 icon
 
https://win98icons.alexmeub.com/