데모페이지 : https://ohikmyeong.github.io/wds-library/mine/
WDS 강의 영상 : https://www.youtube.com/watch?v=vTsVl66q9jo
IntroJS : https://introjs.com
HTML
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
32
33
34
35
36
37
38
39
40
41
42
|
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mine</title>
<link rel="stylesheet" type="text/css" href="./css/main.css"/>
<script src="./js/main.js" type="module"></script>
</head>
<body>
<h1 id="pageTitle">Houses For Sale</h1>
<button id="btn-live-demo">Live Demo</button>
<div id="wrap-card">
<template>
<section class="card">
<img src="https://source.unsplash.com/178j8tJrNlc" alt=""/>
<article class="card-txt">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Magnam tempore nostrum autem vel esse libero!</article>
<article class="card-btns">
<button class="card-btn blue">Details</button>
<button class="card-btn">Contact Seller</button>
</article>
</section><!-- card -->
</template>
</div><!-- wrap-card -->
<!-- modal -->
<div id="highlighter-box" class="off"></div><!-- highlighter -->
<div id="modal" class="off">
<button id="btn-modal-close">X</button>
<h3 id="modal-head">modal title</h3>
<section id="modal-body">modal content</section>
<ul id="modal-pager"></ul>
<section id="modal-foot">
<button id="btn-modal-back" class="off">Back</button>
<button id="btn-modal-next">Next</button>
</section><!-- modal-foot -->
</div><!-- modal -->
</body>
</html>
|
cs |
modal.css
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
@charset "utf-8";
/* 툴팁 */
#modal{
position:absolute;
top:0;left:0;
min-width:300px; max-width:90%;
border:1px solid #ccc; border-radius:8px;
background:#fff;
box-shadow:0 0 5px rgba(0,0,0,.1);
transition:opacity .5s;
}
/* off */
#modal.off{
opacity:0;
pointer-events:none;
}
#btn-modal-close{
display:block;
position:absolute;
top:0;right:0;
width:35px;aspect-ratio:1/1;
background:transparent;border:none;
font-weight:bold; color:#999;
}
#modal-head{
padding:1em; padding-bottom:.5em;
text-align:center; font-size:1.3rem;
text-transform:uppercase; letter-spacing:-.01em;
}
#modal-body{
position:relative;
padding:0 1.5rem;
}
/* pager */
#modal-pager{
display:flex; flex-flow:row nowrap;
justify-content:center; align-items:center;
gap:3px;
margin-top:1rem;}
#modal-pager li{
width:20px; height:5px;
background:#ddd;
border-radius:2px;
}
#modal-pager li.on{
background:var(--blue); box-shadow:
0 0 2px 1px #fff,
0 0 10px 1px var(--blue-op-2);
transition:box-shadow .2s .5s;}
/* footer */
#modal-foot{
display:flex;flex-wrap:row nowrap;
justify-content:space-between; align-items:center;
position:relative;
margin-top:1rem;
border-top:1px solid #ddd;}
#btn-modal-back,
#btn-modal-next{
padding:1em 2em;
background:transparent;
border:none;
color:#777; font-weight:500; font-size:12px;
user-select:none;}
/* hover */
#btn-modal-back:hover,
#btn-modal-next:hover{background:#f9f9f9;}
/* focus */
#btn-modal-back:focus,
#btn-modal-next:focus{background:#eee;color:var(--blue);}
/* off */
#modal-foot button.off{
pointer-events:none; color:#ccc;}
#btn-modal-back{border-right:1px solid #fafafc;}
#btn-modal-next{border-left:1px solid #fafafc;}
/* 하이라이터 */
#highlighter-box{
position:absolute;
top:0;left:0;
border:3px solid #000;
box-shadow:0 0 0 200vmax rgba(0,0,0,.5);
cursor:pointer;
transition:opacity .5s;
}
#highlighter-box.off{
opacity:0;
pointer-events:none;user-select:none;
}
|
cs |
main.js
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import { CardMaker, fake_card_data_maker } from "./cardMaker.js";
import { ModalMaker } from "./modalMaker.js";
const cardData = fake_card_data_maker(10);
const modalData = [
{
title : "Hello World",
body : "<p>This the first Tutorial of Blah Blah...</p><p>잘 따라 와보셈</p>",
},
{
title : "Title(2)",
body : "집중 되니???",
focus : true
},
{
title : "Title(3)",
body : "했다가 안 했다가 할 수도 있습니다.",
focus : true
},
{
title : "조금만 더 견뎌봐요",
body : "피카츄 라이츄 파이리 꼬부기",
},
{
title : "존버",
body : "버터플 야도란 피존투 또가스",
focus : true
},
{
title : "Title(4)",
body : "짠짠 마지막 포커스",
focus : true
},
{
title : "끝!",
body : "수고했졍",
},
];
new CardMaker(cardData);
const modalMaker = new ModalMaker(modalData);
const $btnDemo = document.getElementById('btn-live-demo');
modalMaker.init();
$btnDemo.addEventListener('click',()=>{
modalMaker.reset_idx();
modalMaker.reset_ftr_btn();
modalMaker.display_modal();
});
|
cs |
fn.js
1
2
3
4
5
6
7
|
export function domMaker(domName,...clssList){
const $dom = document.createElement(domName);
for(const clssName of clssList){
$dom.classList.add(clssName);
}//for
return $dom;
}//domMaker
|
cs |
CardMaker.js
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
import { domMaker } from "./fn.js";
export function fake_card_data_maker(limit){
const url = "https://source.unsplash.com/";
const ImgID = ["1ddol8rgUH8","178j8tJrNlc", "eWqOgJ-lfiI","1sCXwVoqKAw","B0aCvAVSX8E","L7EwHkq1B2s","TiVPTYCG_3E","CnXVHyO1GGA","IYfp2Ixe9nM","yFV39g6AZ5o"];
const TXT = "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Magnam tempore nostrum autem vel esse libero! 어쩌고 저쩌고 얄리얄리 얄랑셩 얄라".split(' ');
const result = [];
for(let i=0; i<limit; i++){
const obj = {};
const randomImg = ImgID[Math.floor(Math.random() * ImgID.length)];
const IMG = `${url}${randomImg}`;
obj.img = IMG;
const start = Math.round(Math.random() * 3);
const final = Math.round(Math.random() * TXT.length) + 3;
obj.txt = TXT.slice(start,final).join(' ');
result.push(obj);
}//for
return result;
}//fake_card_data_maker
export class CardMaker{
constructor(data){
this.data = data;
this.$wrap = document.getElementById('wrap-card');
this.init();
}//constructor
init(){
const $frag = document.createDocumentFragment();
this.data.forEach((data,idx) => {
const $card = this.make_card(data);
if([2,5,6,9].includes(idx)){
$card.dataset.focus = "focus";
}//if
$frag.appendChild($card);
});
this.$wrap.appendChild($frag);
}//init
make_card(data){
const {img,txt} = data;
const $card = domMaker('SECTION','card');
const $img = new Image();
$img.src = img;
const $txt = domMaker('ARTICLE','card-txt');
$txt.textContent = txt;
const $btns = domMaker('ARTICLE','card-btns');
const btn1 = domMaker('BUTTON','card-btn','blue');
btn1.textContent = "Details";
const btn2 = domMaker('BUTTON','card-btn');
btn2.textContent = "Contact Seller";
$btns.appendChild(btn1);
$btns.appendChild(btn2);
$card.appendChild($img);
$card.appendChild($txt);
$card.appendChild($btns);
return $card;
}//make_card
}//CardMaker
|
cs |
ModalMaker.js
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
|
import { Highlighter } from "./Highlighter.js";
export class ModalMaker{
constructor(data){
this.HIGH = new Highlighter();
this.data = data;
this.$$focus = this.make_focus_list();
this.$modal = document.getElementById('modal');
this.idx = 0;
}//constructor
reset_idx(){this.idx = 0;}
init(){
//pager 만들기
this.add_pager();
//하단 버튼 준비
this.set_click_ftr_modal();
//닫을 준비
this.add_close_event();
//모달 행동 총괄
this.display_modal();
//resize시 이벤트 추가
this.add_on_resize();
}//init
display_modal(){
//pager에 on 표시
this.on_pager();
//모달 내용 바꾸기
this.change_content();
//모달 위치 조정
this.set_pos_modal();
//하이라이트 박스 조정
this.HIGH.set_pos(this.$$focus[this.idx]);
//해당 위치로 스크롤
this.scroll_to_focus();
//보이고,
if(this.$modal.classList.contains('off')) this.show_modal(true);
}//display_modal
/* focus list 만들기 */
make_focus_list(){
const $$focus = Array.from(document.querySelectorAll('[data-focus="focus"]'));
const result = [];
for(let i=0; i<this.data.length; i++){
const {focus} = this.data[i];
if(focus){
result.push($$focus.shift());
}else{
result.push(null);
}//if else
}//for
return result;
}//make_focus_list
/* pager 만들기 */
add_pager(){
const $pager = document.getElementById('modal-pager');
const $frag = document.createDocumentFragment();
for(let i=0; i<this.data.length; i++){
const $li = document.createElement('LI');
$frag.appendChild($li);
}//for
$pager.appendChild($frag);
}//add_pager
on_pager(){
const $$li = document.getElementById('modal-pager').children;
const target = $$li[this.idx];
const $$sib = Array.prototype.filter.call($$li, $li => $li !== target);
target.classList.add('on');
$$sib.forEach($sib => $sib.classList.remove('on'));
}//on_pager
/* 하단 버튼 준비 */
set_click_ftr_modal(){
const $ftr = document.getElementById('modal-foot');
$ftr.addEventListener('click',this.on_click_ftr_modal);
}//set_click_ftr_modal
/* Back, Next 버튼 누를 때 */
on_click_ftr_modal = e =>{
if(e.target.tagName !== "BUTTON") return;
const btnType = e.target.id.match(/btn\-modal\-(\w*)/)[1];
const $back = document.getElementById('btn-modal-back');
const $next = document.getElementById('btn-modal-next');
if(btnType == "next"){
/* NEXT */
this.idx++;
$back.classList.remove('off');
if(this.idx >= this.data.length - 1){
this.idx = this.data.length - 1;
$next.classList.add('off');
}//if
$next.blur();
}else{
/* PREV */
this.idx--;
$next.classList.remove('off');
if(this.idx <= 0){
this.reset_idx();
this.reset_ftr_btn();
}//if
$back.blur();
}//if else
this.display_modal();
}//on_click_ftr_modal
reset_ftr_btn(){
const $back = document.getElementById('btn-modal-back');
const $next = document.getElementById('btn-modal-next');
$back.classList.add('off');
$next.classList.remove('off');
}//reset_ftr_btn
/* 모달 내용 바꾸기 */
change_content(){
const data = this.data[this.idx];
const {title,body} = data;
const $head = document.getElementById('modal-head');
const $body = document.getElementById('modal-body');
$head.textContent = title;
$body.innerHTML = body;
}//change_content
/* 모달 위치 지정*/
set_pos_modal(){
const $focus = this.$$focus[this.idx];
const winHeiHalf = window.innerHeight / 2;
const winWidHalf = window.innerWidth / 2;
const mdHei = this.$modal.offsetHeight;
const mdWid = this.$modal.offsetWidth;
if(!$focus){
const scY = window.scrollY;
const TOP = scY + (winHeiHalf - mdHei / 2);
const LEFT = winWidHalf - mdWid / 2;
this.$modal.style.top = `${TOP}px`;
this.$modal.style.left = `${LEFT}px`;
}else{
const dom = $focus.getBoundingClientRect();
const focusTop = dom.top + (dom.height / 2) - (mdHei / 2);
const focusLeft = dom.left;
const TOP = focusTop + 10;
const LEFT_LEFT = focusLeft - mdWid - 20
const LEFT_RIGHT = focusLeft + dom.width + 20;
let LEFT = focusLeft > winWidHalf ? LEFT_LEFT : LEFT_RIGHT ;
const is_full_wid = Math.ceil($focus.getBoundingClientRect().width + (16 * 4.5));
if(window.innerWidth <= is_full_wid){LEFT = winWidHalf - mdWid / 2;}
this.$modal.style.top = `${TOP + window.scrollY}px`;
this.$modal.style.left = `${LEFT}px`;
}//else
}//set_pos_modal
/* 모달 보이기 */
show_modal(bool){
this.$modal.classList.toggle('off',!bool);
this.HIGH.show_box(bool);
}//show_modal
/* 모달 X 버튼 */
add_close_event(){
const $close = document.getElementById('btn-modal-close');
$close.addEventListener('click',()=>{
this.show_modal(false);
});
}//add_close_event
/* 그 위치로 스크롤 */
scroll_to_focus(){
const $focus = this.$$focus[this.idx];
if(!$focus) return;
window.scroll({
top : $focus.getBoundingClientRect().top + window.scrollY - 30,
behavior : 'smooth'
});
}//scroll_to_focus
/* resize시 이벤트 추가 */
add_on_resize(){
window.addEventListener('resize',()=>{
this.set_pos_modal();
this.HIGH.set_pos(this.$$focus[this.idx]);
});
}//add_on_resize
}//ModalMaker
|
cs |
Highlighter.js
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
32
33
34
35
|
export class Highlighter{
constructor(){
this.$box = document.getElementById('highlighter-box');
}//constructor
show_box(bool){
this.$box.classList.toggle('off',!bool);
}//show_box
set_pos($focus){
if(!$focus){
this.reset_box();
return;
}else{
this.change_box($focus);
};
}//set_pos
reset_box(){
const TOP = (window.innerHeight / 2) + window.scrollY;
const LEFT = (window.innerWidth / 2);
this.$box.style.left = `${LEFT}px`;
this.$box.style.top = `${TOP}px`;
this.$box.style.width = '1px';
this.$box.style.height = '1px';
}//reset_box
change_box($focus){
const {left,top,width,height} = $focus.getBoundingClientRect();
this.$box.style.left = `${left - 10}px`;
this.$box.style.top = `${window.scrollY + top - 10}px`;
this.$box.style.width = `${width + 20}px`;
this.$box.style.height = `${height + 20}px`;
}//change_box
}//Highlighter
|
cs |
'CSS&JS > 👀Study and Copy' 카테고리의 다른 글
[Nomad Coders] 바닐라 JS로 그림판 만들기 - 2021ver (0) | 2022.08.26 |
---|---|
WDS-Snake Game (0) | 2022.08.22 |
[WDS] Flip Card Time Turner (0) | 2022.08.17 |
WDS,OT - Magic CSS Indicator (0) | 2022.08.09 |
WDS- Sortable Drag & Drop List (0) | 2022.08.09 |