Skip to content

Commit e8ef8cd

Browse files
authored
[UI] Box, Button : web-component 생성 및 스타일링 (#98)
* [task/96] Button : web-component HTML 구조 작성 * [task/97] Button : 스타일링 * [task/93] Box : web-component HTML 구조 작성 * [refactor] LoadMd : 문서를 웹컴포넌트 기준 분할 후 순차 삽입되도록 변경 * 기능 추가에 따른 디테일 수정
1 parent f5f1078 commit e8ef8cd

6 files changed

Lines changed: 106 additions & 21 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
class BoxComponent extends HTMLElement {
2+
static get observedAttributes() {
3+
return ['img-src', 'href', 'title', 'description'];
4+
}
5+
6+
constructor() {
7+
super();
8+
}
9+
10+
attributeChangedCallback() {
11+
this.render();
12+
}
13+
14+
connectedCallback() {
15+
this.render();
16+
}
17+
18+
render() {
19+
const imgSrc = this.getAttribute('imgsrc') || '';
20+
const href = this.getAttribute('href') || '/';
21+
const title = this.getAttribute('title') || '';
22+
const description = this.getAttribute('description') || '';
23+
24+
this.innerHTML = `
25+
<article id="box-component">
26+
<a href="${href}">
27+
<div>
28+
<div>
29+
<img src="${imgSrc}" />
30+
<p>${title}</p>
31+
</div>
32+
<div>${description}</div>
33+
</div>
34+
</a>
35+
</article>
36+
`;
37+
}
38+
}
39+
40+
customElements.define('box-component', BoxComponent);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class ButtonComponent extends HTMLElement {
2+
static get observedAttributes() {
3+
return ['href', 'title'];
4+
}
5+
6+
constructor() {
7+
super();
8+
}
9+
10+
attributeChangedCallback() {
11+
this.render();
12+
}
13+
14+
connectedCallback() {
15+
this.render();
16+
}
17+
18+
render() {
19+
const href = this.getAttribute('href') || '#';
20+
const title = this.getAttribute('title') || '';
21+
22+
this.innerHTML = `
23+
<button type="button" class="not-prose my-4">
24+
<a href="${href}" class="cursor-pointer py-2 px-4 rounded bg-[#086dd7] text-white!">
25+
${title}
26+
</a>
27+
</button>
28+
`;
29+
}
30+
}
31+
32+
customElements.define('button-component', ButtonComponent);

src/scripts/components/header-component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class HeaderComponent extends HTMLElement {
99
<div class="max-w-[1920px] mx-auto flex lg:gap-8 gap-2 h-full items-center justify-between">
1010
<div class="flex h-full items-center lg:gap-8 gap-2">
1111
<div>
12-
<a href="https://docker-ko.github.io" title="Docker korean translation home page">
12+
<a href="/" title="Docker korean translation home page">
1313
<img
1414
src="./imgs/logo/docker-logo-white.svg"
1515
alt="Docker Korea home page"

src/scripts/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
import './footer-component';
22
import './header-component';
3+
import './box-component';
4+
import './button-component'

src/scripts/load_md.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
import { marked } from 'marked';
22

3+
/**
4+
* mdText를 웹 컴포넌트 태그(<box-component>, <button-component>, </box-component>, </button-component>) 기준으로 분할하여
5+
* 마크다운은 파싱해서, 웹 컴포넌트는 그대로 contentElement에 삽입하는 함수
6+
*/
7+
async function renderMarkdownWithComponents(mdText: string, contentElement: HTMLElement) {
8+
const tokens = mdText.split(/(<\/?box-component[^>]*>|<\/?button-component[^>]*>)/gi).filter(Boolean);
9+
10+
for (const token of tokens) {
11+
// 웹 컴포넌트 태그인지 확인
12+
if (/^<\/?(box-component|button-component)[^>]*>$/.test(token)) {
13+
// 웹 컴포넌트 태그는 문자열 그대로 삽입
14+
contentElement.innerHTML += token;
15+
} else if (token.trim()) {
16+
// 마크다운 텍스트는 파싱해서 바로 innerHTML로 삽입
17+
const html = await marked.parse(token);
18+
contentElement.innerHTML += html;
19+
}
20+
}
21+
}
22+
323
async function loadMarkdown(page: string) {
424
try {
525
const response = await fetch(`/docs/${page}.md?cache=${Date.now()}`);
@@ -15,8 +35,9 @@ async function loadMarkdown(page: string) {
1535
);
1636
}
1737

18-
const htmlContent = marked.parse(mdText);
19-
document.getElementById('content')!.innerHTML = await htmlContent;
38+
const contentElement = document.getElementById('content')!;
39+
contentElement.innerHTML = '';
40+
await renderMarkdownWithComponents(mdText, contentElement);
2041
} catch (error) {
2142
document.getElementById('content')!.innerHTML = `
2243
<div id="not-found" class="w-full">

src/styles/content_style.css

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,27 +105,17 @@ h4 {
105105
#content a {
106106
color: #007bff;
107107
text-decoration: none;
108-
font-weight: 600;
109108
transition: color 0.2s ease-in-out;
110-
}
111-
112-
#content a:hover {
113-
color: #0056b3;
114-
text-decoration: underline;
115-
}
116-
117-
#content a:active {
118-
color: #004080;
119-
}
120109

121-
#content a:visited {
122-
color: #800080;
123-
}
110+
&:hover {
111+
color: #007bff;
112+
}
124113

125-
#content a.external-link::after {
126-
content: ' 🔗';
127-
font-size: 0.8em;
128-
opacity: 0.7;
114+
&.external-link::after {
115+
content: ' 🔗';
116+
font-size: 0.8em;
117+
opacity: 0.7;
118+
}
129119
}
130120

131121
#content .youtube-video {

0 commit comments

Comments
 (0)