실행 가능한 모든 컴포넌트를 레이블 형태(아이콘)로 보여주고, 레이블을 클릭하면 그에 맞는 컴포넌트(=창)를 실행한다.
모듈을 어떻게 나눌까 고민했는데, 역시 메인 컴포넌트들을 각자의 .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/