From bea7c0f9c6bad234b1cf4cf855fbf1c0a6e0737d Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Fri, 20 Jun 2025 17:01:26 +0900 Subject: [PATCH 01/20] =?UTF-8?q?=EC=95=88=20=EC=93=B0=EB=8A=94=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../the-basics/what-is-docker-compose.md | 6 ++--- src/scripts/breadcrumb.ts | 4 ++-- src/styles/content_style.css | 1 + src/styles/style.css | 24 ------------------- 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/public/docs/get-started/docker-concepts/the-basics/what-is-docker-compose.md b/public/docs/get-started/docker-concepts/the-basics/what-is-docker-compose.md index 4911745..fe04a51 100644 --- a/public/docs/get-started/docker-concepts/the-basics/what-is-docker-compose.md +++ b/public/docs/get-started/docker-concepts/the-basics/what-is-docker-compose.md @@ -20,7 +20,7 @@ Docker Compose를 사용하면, 모든 컨테이너와 그 구성들을 단일 Y Compose는 선언적 도구라는 것을 이해하는 것이 중요합니다. 여러분들은 단순히 정의하고 실행하면 됩니다. 모든 것을 처음부터 다시 만들 필요는 없습니다. 변경 사항을 있는 경우, `docker compose up` 명령을 다시 실행하면 Compose가 파일의 변경 사항을 조정하고 지능적으로 적용합니다. -> ### Dockerfile vs Compose file +> **Dockerfile vs Compose file** > > Dockerfile은 컨테이너 이미지를 빌드하는 지침을 제공하고, Compose 파일은 실행 중인 컨테이너를 정의합니다. 꽤 자주, Compose 파일은 특정 서비스에 사용할 이미지를 빌드하기 위해 Dockerfile을 참조합니다. @@ -96,7 +96,7 @@ Docker Compose를 사용하여 이 애플리케이션을 시작했기 때문에 ✔ Network todo-list-app_default Removed 0.1s ``` - > ### Volume persistence(볼륨 유지) + > **Volume persistence(볼륨 유지)** > > 기본적으로 볼륨은 Compose 스택을 종료할 때 자동으로 제거되지 않습니다. 스택을 다시 시작할 때 데이터를 다시 원할 수 있기 때문입니다. > @@ -108,7 +108,7 @@ Docker Compose를 사용하여 이 애플리케이션을 시작했기 때문에 2. 또는 Docker Desktop GUI를 사용하여 애플리케이션 스택을 선택하고 **Delete** 버튼을 선택하여 컨테이너를 제거할 수 있습니다. - > ### Using the GUI for Compose stacks(GUI를 사용한 Compose 스택) + > **Using the GUI for Compose stacks(GUI를 사용한 Compose 스택)** > > GUI에서 Compose 앱의 컨테이너를 제거하면 컨테이너만 제거됩니다. 네트워크와 볼륨을 제거하려면 수동으로 제거해야 합니다. diff --git a/src/scripts/breadcrumb.ts b/src/scripts/breadcrumb.ts index 2c2bb7f..f4641da 100644 --- a/src/scripts/breadcrumb.ts +++ b/src/scripts/breadcrumb.ts @@ -35,12 +35,12 @@ function generateBreadcrumbItems(): BreadcrumbItem[] { const hash = window.location.hash.slice(1); // # 제거 if (!hash || hash === '/') { - return [{ name: '홈', path: '#/', linkable: true }]; + return [{ name: '홈', path: '/', linkable: true }]; } const pathSegments = hash.split('/').filter((segment) => segment !== ''); const breadcrumbItems: BreadcrumbItem[] = [ - { name: '홈', path: '#/', linkable: true }, + { name: '홈', path: '/', linkable: true }, ]; let currentPath = ''; diff --git a/src/styles/content_style.css b/src/styles/content_style.css index 57f4f13..b7beeed 100644 --- a/src/styles/content_style.css +++ b/src/styles/content_style.css @@ -37,6 +37,7 @@ h4 { #content ol { margin-left: 1.5rem; padding-left: 1rem; + color: #222; } #content ul { diff --git a/src/styles/style.css b/src/styles/style.css index 7dbce66..8f3e27e 100644 --- a/src/styles/style.css +++ b/src/styles/style.css @@ -1,29 +1,5 @@ @import 'tailwindcss'; -@layer base { - /* 전역 스타일 */ - body { - @apply bg-white text-black; - } - - /* Table 관련 기본 스타일 */ - card-component { - @apply block; - } - table { - @apply w-3/4 table-auto; - } - - th, - td { - @apply px-4 py-2 text-justify; - } - - thead { - @apply bg-gray-200; - } -} - /* 카드 컴포넌트 스타일 */ @layer components { .card { From a88022e294dc3226840e752f640c5361281453dc Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Fri, 20 Jun 2025 21:45:23 +0900 Subject: [PATCH 02/20] =?UTF-8?q?[fix]=20ObserverAPI=20=EB=AF=BC=EA=B0=90?= =?UTF-8?q?=EB=8F=84=20=EC=84=B8=EB=B6=80=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/table-contents.ts | 40 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/scripts/table-contents.ts b/src/scripts/table-contents.ts index f355776..4067fc1 100644 --- a/src/scripts/table-contents.ts +++ b/src/scripts/table-contents.ts @@ -1,21 +1,27 @@ const createObserver = (headingMap: Record) => { - return new IntersectionObserver((entries) => { - const visibleEntry = entries - .filter((entry) => entry.isIntersecting) - .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0]; - - if (visibleEntry) { - const id = (visibleEntry.target as HTMLElement).id; - - Object.entries(headingMap).forEach(([headingId, li]) => { - if (headingId === id) { - li.classList.add('border-l-2', 'border-blue-500'); - } else { - li.classList.remove('border-l-2', 'border-blue-500'); - } - }); + return new IntersectionObserver( + (entries) => { + const visibleEntry = entries + .filter((entry) => entry.isIntersecting) + .sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0]; + + if (visibleEntry) { + const id = (visibleEntry.target as HTMLElement).id; + + Object.entries(headingMap).forEach(([headingId, li]) => { + if (headingId === id) { + li.classList.add('border-l-2', 'border-blue-500'); + } else { + li.classList.remove('border-l-2', 'border-blue-500'); + } + }); + } + }, + { + rootMargin: '-60px 0px -60% 0px', + threshold: 0.8, } - }); + ); }; export const initializeTableContents = () => { @@ -30,7 +36,7 @@ export const initializeTableContents = () => { const tocTitle = document.createElement('p'); const tocList = document.createElement('ul'); - tocTitle.classList.add('text-black', 'font-light', 'text-lg', 'pb-5'); + tocTitle.classList.add('text-black', 'font-normal', 'text-lg', 'pb-5'); tocTitle.textContent = 'Table of contents'; const headingMap: Record = {}; From d29d6eab7ce4ba87c8a8ae6749bf08a6c57e0407 Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 00:38:56 +0900 Subject: [PATCH 03/20] =?UTF-8?q?[fix]=20=EC=97=86=EB=8A=94=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B8=EB=93=A4=EB=A7=81=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/load_md.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/scripts/load_md.ts b/src/scripts/load_md.ts index a8689d6..858a731 100644 --- a/src/scripts/load_md.ts +++ b/src/scripts/load_md.ts @@ -74,13 +74,24 @@ export async function renderMarkdownWithComponents( async function loadMarkdown(page: string) { try { - const response = await fetch(`/docs/${page}.md?cache=${Date.now()}`); + const response = await fetch(`/docs/${page}.md`); + + // HTTP 상태코드 확인 if (!response.ok) throw new Error(`❌ 페이지를 찾을 수 없습니다: ${page}`); + const mdText = await response.text(); + // Content-Type 확인 (개발 서버가 HTML을 반환하는 경우 대비) + const contentType = response.headers.get('content-type'); + if (contentType && contentType.includes('text/html')) { + throw new Error(`❌ 요청된 경로가 HTML을 반환합니다: ${page}`); + } + + // 응답 내용이 HTML인지 확인 if ( mdText.trim().startsWith('') || - mdText.includes('') + mdText.includes('') || + mdText.includes('') ) { throw new Error( `❌ 요청된 경로가 Markdown이 아닌 HTML을 반환합니다: ${page}` From e10b6fa4e045517f6675e8517459b90543eda817 Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 00:45:35 +0900 Subject: [PATCH 04/20] =?UTF-8?q?=ED=99=95=EC=9E=A5=EC=84=B1=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=B4=20breadcrumb=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20&=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/breadcrumb.json | 319 ++++++++++++++++++++------------------ src/scripts/breadcrumb.ts | 63 +++++--- 2 files changed, 210 insertions(+), 172 deletions(-) diff --git a/src/data/breadcrumb.json b/src/data/breadcrumb.json index 9a98a1c..1d2cbdd 100644 --- a/src/data/breadcrumb.json +++ b/src/data/breadcrumb.json @@ -1,156 +1,171 @@ { - "segments": { - "get-started": { - "name": "시작하기", - "linkable": true - }, - "get-docker": { - "name": "Docker 설치", - "linkable": true - }, - "docker-overview": { - "name": "Docker 개요", - "linkable": true - }, - "introduction": { - "name": "소개", - "linkable": true - }, - "build-and-push-first-image": { - "name": "첫 번째 이미지 빌드 및 푸시", - "linkable": true - }, - "develop-with-containers": { - "name": "컨테이너로 개발", - "linkable": true - }, - "get-docker-desktop": { - "name": "Docker Desktop 설치", - "linkable": true - }, - "whats-next": { - "name": "다음 단계", - "linkable": true - }, - "docker-concepts": { - "name": "Docker 개념", - "linkable": false - }, - "the-basics": { - "name": "기본 사항", - "linkable": false - }, - "what-is-a-container": { - "name": "컨테이너란?", - "linkable": true - }, - "what-is-a-registry": { - "name": "레지스트리란?", - "linkable": true - }, - "what-is-an-image": { - "name": "이미지란?", - "linkable": true - }, - "what-is-docker-compose": { - "name": "Docker Compose란?", - "linkable": true - }, - "building-images": { - "name": "이미지 빌드", - "linkable": false - }, - "understanding-image-layers": { - "name": "이미지 레이어 이해", - "linkable": true - }, - "writing-a-dockerfile": { - "name": "Dockerfile 작성", - "linkable": true - }, - "build-tag-and-publish-an-image": { - "name": "이미지 빌드, 태그, 게시", - "linkable": true - }, - "using-the-build-cache": { - "name": "빌드 캐시 사용", - "linkable": true - }, - "multi-stage-builds": { - "name": "멀티 스테이지 빌드", - "linkable": true - }, - "running-containers": { - "name": "컨테이너 실행", - "linkable": false - }, - "multi-container-applications": { - "name": "멀티 컨테이너 애플리케이션", - "linkable": true - }, - "overriding-container-defaults": { - "name": "컨테이너 기본값 재정의", - "linkable": true - }, - "persisting-container-data": { - "name": "컨테이너 데이터 유지", - "linkable": true - }, - "publishing-ports": { - "name": "포트 게시", - "linkable": true - }, - "sharing-local-files": { - "name": "로컬 파일 공유", - "linkable": true - }, - "docker-workshop": { - "name": "Docker 워크샵", - "linkable": true - }, - "resources": { - "name": "리소스", - "linkable": true - }, - "workshop": { - "name": "워크샵", - "linkable": false - }, - "02_our_app": { - "name": "애플리케이션 컨테이너화", - "linkable": true - }, - "03_updating_app": { - "name": "애플리케이션 업데이트", - "linkable": true - }, - "04_sharing_app": { - "name": "애플리케이션 공유", - "linkable": true - }, - "05_persisting_data": { - "name": "데이터베이스 유지", - "linkable": true - }, - "06_bind_mounts": { - "name": "바인드 마운트 사용", - "linkable": true - }, - "07_multi_container": { - "name": "멀티 컨테이너 애플리케이션", - "linkable": true - }, - "08_using_compose": { - "name": "Docker Compose 사용", - "linkable": true - }, - "09_image_best": { - "name": "이미지 빌드 모범 사례", - "linkable": true - }, - "10_what_next": { - "name": "Docker 워크숍 이후 단계", - "linkable": true + "get-started": { + "name": "시작하기", + "linkable": true, + "children": { + "get-docker": { + "name": "Docker 설치", + "linkable": true + }, + "docker-overview": { + "name": "Docker 개요", + "linkable": true + }, + "introduction": { + "name": "소개", + "linkable": true + }, + "build-and-push-first-image": { + "name": "첫 번째 이미지 빌드 및 푸시", + "linkable": true + }, + "develop-with-containers": { + "name": "컨테이너로 개발", + "linkable": true + }, + "get-docker-desktop": { + "name": "Docker Desktop 설치", + "linkable": true + }, + "whats-next": { + "name": "다음 단계", + "linkable": true + }, + "docker-concepts": { + "name": "Docker 개념", + "linkable": false + }, + "the-basics": { + "name": "기본 사항", + "linkable": false + }, + "what-is-a-container": { + "name": "컨테이너란?", + "linkable": true + }, + "what-is-a-registry": { + "name": "레지스트리란?", + "linkable": true + }, + "what-is-an-image": { + "name": "이미지란?", + "linkable": true + }, + "what-is-docker-compose": { + "name": "Docker Compose란?", + "linkable": true + }, + "building-images": { + "name": "이미지 빌드", + "linkable": false + }, + "understanding-image-layers": { + "name": "이미지 레이어 이해", + "linkable": true + }, + "writing-a-dockerfile": { + "name": "Dockerfile 작성", + "linkable": true + }, + "build-tag-and-publish-an-image": { + "name": "이미지 빌드, 태그, 게시", + "linkable": true + }, + "using-the-build-cache": { + "name": "빌드 캐시 사용", + "linkable": true + }, + "multi-stage-builds": { + "name": "멀티 스테이지 빌드", + "linkable": true + }, + "running-containers": { + "name": "컨테이너 실행", + "linkable": false + }, + "multi-container-applications": { + "name": "멀티 컨테이너 애플리케이션", + "linkable": true + }, + "overriding-container-defaults": { + "name": "컨테이너 기본값 재정의", + "linkable": true + }, + "persisting-container-data": { + "name": "컨테이너 데이터 유지", + "linkable": true + }, + "publishing-ports": { + "name": "포트 게시", + "linkable": true + }, + "sharing-local-files": { + "name": "로컬 파일 공유", + "linkable": true + }, + "docker-workshop": { + "name": "Docker 워크샵", + "linkable": true + }, + "resources": { + "name": "리소스", + "linkable": true + }, + "workshop": { + "name": "워크샵", + "linkable": false + }, + "02_our_app": { + "name": "애플리케이션 컨테이너화", + "linkable": true + }, + "03_updating_app": { + "name": "애플리케이션 업데이트", + "linkable": true + }, + "04_sharing_app": { + "name": "애플리케이션 공유", + "linkable": true + }, + "05_persisting_data": { + "name": "데이터베이스 유지", + "linkable": true + }, + "06_bind_mounts": { + "name": "바인드 마운트 사용", + "linkable": true + }, + "07_multi_container": { + "name": "멀티 컨테이너 애플리케이션", + "linkable": true + }, + "08_using_compose": { + "name": "Docker Compose 사용", + "linkable": true + }, + "09_image_best": { + "name": "이미지 빌드 모범 사례", + "linkable": true + }, + "10_what_next": { + "name": "Docker 워크숍 이후 단계", + "linkable": true + } } + }, + "guides": { + "name": "가이드", + "linkable": true, + "children": {} + }, + "reference": { + "name": "참조", + "linkable": true, + "children": {} + }, + "manuals": { + "name": "매뉴얼", + "linkable": true, + "children": {} } } diff --git a/src/scripts/breadcrumb.ts b/src/scripts/breadcrumb.ts index f4641da..61de1d8 100644 --- a/src/scripts/breadcrumb.ts +++ b/src/scripts/breadcrumb.ts @@ -1,31 +1,62 @@ import translations from '../data/breadcrumb.json'; +/** + * Breadcrumb 아이템의 세그먼트 데이터 구조 + * - name: 세그먼트 이름 + * - linkable: 링크 가능 여부 + * - children: 하위 세그먼트들 (선택적) + */ interface SegmentData { name: string; linkable: boolean; + children?: Record<string, SegmentData>; } - -interface BreadcrumbItem extends SegmentData { +/** + * Breadcrumb 아이템 구조 + */ +interface BreadcrumbItem { + name: string; path: string; + linkable: boolean; } +/** + * 최상위 레벨의 키-값 구조 + */ interface TranslationData { - segments: Record<string, SegmentData>; + [key: string]: SegmentData; } /** * 경로 세그먼트를 번역하고 링크 가능 여부를 확인합니다. - * @param segment 번역할 세그먼트 - * @returns 세그먼트 데이터 또는 기본값 + * 계층적 구조를 고려하여 현재 경로에서 세그먼트를 찾습니다. + * @param segments 전체 경로 세그먼트 배열 + * @param currentIndex 현재 처리 중인 세그먼트의 인덱스(깊이를 알기 위함) + * @returns 해당 세그먼트 데이터 또는 기본값 */ -function getSegmentData(segment: string): SegmentData { +function getSegmentData(segments: string[], currentIndex: number): SegmentData { const translationData = translations as TranslationData; - return ( - translationData.segments[segment] || { - name: segment, + let current = translationData[segments[0]]; + + if (!current) { + return { + name: segments[currentIndex], linkable: false, + }; + } + + for (let i = 1; i <= currentIndex; i++) { + if (current.children && current.children[segments[i]]) { + current = current.children[segments[i]]; + } else { + return { + name: segments[currentIndex], + linkable: false, + }; } - ); + } + + return current; } /** @@ -45,11 +76,10 @@ function generateBreadcrumbItems(): BreadcrumbItem[] { let currentPath = ''; - pathSegments.forEach((segment) => { + pathSegments.forEach((segment, index) => { currentPath += `/${segment}`; - // 세그먼트 데이터 가져오기 (이름과 링크 가능 여부) - const segmentData = getSegmentData(segment); + const segmentData = getSegmentData(pathSegments, index); breadcrumbItems.push({ name: segmentData.name, @@ -70,21 +100,17 @@ function createBreadcrumbElement(items: BreadcrumbItem[]): HTMLElement { breadcrumbNav.className = 'pb-3 flex min-w-0 items-center gap-2 text-gray-400 dark:text-gray-300'; - // HTML 문자열로 breadcrumb 구조 생성 const breadcrumbHTML = items .map((item, index) => { const isLast = index === items.length - 1; if (isLast) { - // 현재 페이지는 span으로 표시 return `<span class="truncate">${item.name}</span>`; } if (!item.linkable) { - // linkable이 false인 경우 span으로 표시 (링크 없음) return `<span class="truncate text-blue-500">${item.name}</span> / `; } else { - // 링크 가능한 이전 페이지들은 링크로 표시 + 구분자 return `<a href="${item.path}" class="link truncate">${item.name}</a> / `; } }) @@ -110,13 +136,10 @@ function removePreviousBreadcrumb(): void { export function initializeBreadcrumb(): void { const contentDiv = document.getElementById('content')!; - // 기존 breadcrumb 제거 removePreviousBreadcrumb(); - // 새 breadcrumb 생성 const breadcrumbItems = generateBreadcrumbItems(); const breadcrumbElement = createBreadcrumbElement(breadcrumbItems); - // div#content의 첫 번째 자식으로 추가 contentDiv.insertBefore(breadcrumbElement, contentDiv.firstChild); } From 8586a124520d9982d1bd73753e0d27d94b002eae Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 00:54:17 +0900 Subject: [PATCH 05/20] =?UTF-8?q?=EB=8F=84=EC=BB=A4=20=EB=A1=9C=EA=B3=A0?= =?UTF-8?q?=20svg=20=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0=20&=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EB=A1=9C=EA=B3=A0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/imgs/logo/docker-logo-blue.svg | 21 --------------------- public/imgs/logo/docker-logo-white.svg | 21 --------------------- public/imgs/logo/docker-mark-blue.svg | 12 ------------ public/imgs/logo/docker-mark-white.svg | 12 ------------ src/scripts/components/header-component.ts | 9 +++------ 5 files changed, 3 insertions(+), 72 deletions(-) delete mode 100644 public/imgs/logo/docker-logo-blue.svg delete mode 100644 public/imgs/logo/docker-logo-white.svg delete mode 100644 public/imgs/logo/docker-mark-blue.svg delete mode 100644 public/imgs/logo/docker-mark-white.svg diff --git a/public/imgs/logo/docker-logo-blue.svg b/public/imgs/logo/docker-logo-blue.svg deleted file mode 100644 index 4518f0b..0000000 --- a/public/imgs/logo/docker-logo-blue.svg +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2333.95 530.79"> - <defs> - <style> - .cls-1 { - fill: #1d63ed; - stroke-width: 0px; - } - </style> - </defs> - <path class="cls-1" d="M661.56,218.08c-16.49-11.1-59.81-15.84-91.3-7.35-1.69-31.37-17.88-57.81-47.47-80.88l-10.95-7.35-7.3,11.03c-14.35,21.78-20.4,50.81-18.26,77.2,1.69,16.26,7.34,34.53,18.26,47.79-40.99,23.78-78.78,18.38-246.12,18.38H.06c-.75,37.79,5.32,110.47,51.54,169.64,5.11,6.54,10.7,12.86,16.78,18.95,37.58,37.63,94.36,65.23,179.26,65.3,129.53.12,240.5-69.9,308.01-239.18,22.21.36,80.85,3.98,109.55-51.47.7-.93,7.3-14.7,7.3-14.7l-10.94-7.35ZM168.67,183.53h-72.65v72.65h72.65v-72.65ZM262.52,183.53h-72.65v72.65h72.65v-72.65ZM356.38,183.53h-72.65v72.65h72.65v-72.65ZM450.24,183.53h-72.65v72.65h72.65v-72.65ZM74.81,183.53H2.16v72.65h72.65v-72.65ZM168.67,91.77h-72.65v72.65h72.65v-72.65ZM262.52,91.77h-72.65v72.65h72.65v-72.65ZM356.38,91.77h-72.65v72.65h72.65v-72.65ZM356.38,0h-72.65v72.65h72.65V0Z"/> - <g> - <path class="cls-1" d="M2329.44,419.3c0,18.94-14.87,33.81-34.21,33.81s-34.42-14.87-34.42-33.81,15.27-33.4,34.42-33.4,34.21,14.87,34.21,33.4ZM2269.37,419.3c0,14.87,11,26.68,26.07,26.68s25.46-11.81,25.46-26.47-10.8-26.89-25.65-26.89-25.87,12.02-25.87,26.68ZM2289.95,436.82h-7.74v-33.4c3.04-.61,7.33-1.02,12.82-1.02,6.32,0,9.16,1.02,11.61,2.45,1.84,1.42,3.26,4.07,3.26,7.33,0,3.67-2.85,6.52-6.91,7.74v.41c3.24,1.21,5.08,3.66,6.1,8.14,1.01,5.09,1.62,7.13,2.45,8.35h-8.35c-1.02-1.22-1.64-4.27-2.65-8.15-.61-3.66-2.65-5.29-6.93-5.29h-3.66v13.45ZM2290.14,417.88h3.66c4.28,0,7.74-1.42,7.74-4.88,0-3.06-2.23-5.11-7.13-5.11-2.03,0-3.46.21-4.27.43v9.56Z"/> - <path class="cls-1" d="M1017.16,81.28c-4.79-4.68-10.54-7.06-17.43-7.06s-12.81,2.38-17.42,7.06c-4.62,4.68-6.88,10.68-6.88,17.83v119.4c-23.7-19.59-51.05-29.47-82.16-29.47-36.16,0-67.08,13.06-92.7,39.27-25.62,26.12-38.34,57.72-38.34,94.78s12.81,68.57,38.34,94.78c25.62,26.12,56.46,39.27,92.7,39.27s66.74-13.06,92.7-39.27c25.62-25.86,38.34-57.45,38.34-94.78V99.11c0-7.15-2.35-13.15-7.15-17.83ZM968.98,355.39v.18c-4.27,10.15-10.11,19.06-17.51,26.65-7.4,7.68-16.12,13.68-26.05,18.18-10.02,4.5-20.65,6.71-32.06,6.71s-22.3-2.21-32.32-6.71c-10.02-4.5-18.65-10.5-25.96-18.09-7.32-7.59-13.15-16.5-17.42-26.65-4.27-10.24-6.45-21.09-6.45-32.57s2.18-22.33,6.45-32.57c4.27-10.24,10.11-19.06,17.42-26.65,7.32-7.59,16.03-13.59,25.96-18.09,10.02-4.5,20.74-6.71,32.32-6.71s22.04,2.21,32.06,6.71c10.02,4.5,18.65,10.5,26.05,18.18,7.4,7.68,13.24,16.59,17.51,26.65,4.27,10.15,6.45,20.92,6.45,32.39s-2.18,22.33-6.45,32.39Z"/> - <path class="cls-1" d="M2099.77,271.64c-6.36-15.89-16.05-30.27-28.76-43.16l-.17-.09c-25.88-26.12-56.82-39.27-92.7-39.27s-67.09,13.06-92.71,39.27c-25.62,26.12-38.33,57.72-38.33,94.78s12.81,68.57,38.33,94.78c25.62,26.12,56.47,39.27,92.71,39.27,32.92,0,61.41-10.85,85.64-32.56,4.69-4.94,7.06-10.94,7.06-17.92s-2.26-13.15-6.89-17.83c-4.61-4.68-10.45-7.06-17.42-7.06-6.09.18-11.5,2.21-16.11,6.27-7.32,6.35-15.25,11.21-23.87,14.39-8.63,3.18-18.04,4.77-28.31,4.77-9.07,0-17.78-1.41-26.05-4.32-8.29-2.91-16.03-6.89-22.92-12.09-6.98-5.21-12.98-11.38-18.12-18.71-5.14-7.24-9.06-15.27-11.67-24.09h185.32c6.87,0,12.62-2.38,17.42-7.06,4.8-4.68,7.15-10.68,7.15-17.83,0-18.53-3.24-35.74-9.58-51.54ZM1899.29,298.29c2.53-8.74,6.36-16.77,11.5-24.09,5.15-7.24,11.24-13.5,18.21-18.71,7.06-5.21,14.72-9.18,23.17-12.09,8.44-2.91,17.06-4.32,25.97-4.32s17.51,1.41,25.86,4.32c8.37,2.91,16.05,6.88,22.92,12.09,6.98,5.21,13.07,11.38,18.21,18.71,5.22,7.24,9.16,15.27,11.86,24.09h-157.71Z"/> - <path class="cls-1" d="M2327.51,205.89c-4.36-4.32-9.85-7.68-16.47-10.15-6.62-2.47-13.85-4.15-21.78-5.12-7.84-.97-15.25-1.41-22.12-1.41-15.61,0-30.24,2.56-44,7.68-13.77,5.12-26.49,12.44-38.17,21.97v-4.76c0-6.88-2.35-12.71-7.15-17.56-4.78-4.85-10.45-7.32-17.15-7.32s-12.64,2.47-17.42,7.32c-4.8,4.85-7.15,10.77-7.15,17.56v218.25c0,6.88,2.35,12.71,7.15,17.56,4.78,4.85,10.53,7.32,17.42,7.32s12.45-2.47,17.15-7.32c4.8-4.85,7.15-10.77,7.15-17.56v-109.17c0-11.65,2.18-22.59,6.45-32.83,4.27-10.24,10.11-19.06,17.51-26.65,7.42-7.59,16.13-13.59,26.05-17.92,10.02-4.41,20.66-6.62,32.08-6.62s22.2,2.03,32.06,6c3.91,1.77,7.32,2.65,10.28,2.65,3.4,0,6.62-.62,9.58-1.94,2.96-1.32,5.58-3.09,7.76-5.38,2.18-2.29,3.91-4.94,5.22-8.03,1.31-3,2.01-6.27,2.01-9.8,0-6.88-2.18-12.44-6.53-16.77h.08Z"/> - <path class="cls-1" d="M1304.49,271.73c-6.36-15.8-15.86-30.27-28.66-43.33-25.87-26.12-56.8-39.27-92.7-39.27s-67.08,13.06-92.7,39.27c-25.62,26.12-38.33,57.72-38.33,94.78s12.81,68.57,38.33,94.78c25.62,26.12,56.46,39.27,92.7,39.27s66.74-13.06,92.7-39.27c25.62-25.86,38.34-57.45,38.34-94.78-.18-18.53-3.4-35.65-9.67-51.45ZM1258.84,355.39v.18c-4.27,10.15-10.11,19.06-17.51,26.65-7.4,7.68-16.12,13.68-26.05,18.18-9.93,4.5-20.65,6.71-32.06,6.71s-22.3-2.21-32.32-6.71c-10.02-4.5-18.65-10.5-25.96-18.09-7.32-7.59-13.15-16.5-17.42-26.65-4.27-10.24-6.45-21.09-6.45-32.57s2.18-22.33,6.45-32.57c4.27-10.24,10.11-19.06,17.42-26.65,7.32-7.59,16.03-13.59,25.96-18.09,10.02-4.5,20.74-6.71,32.32-6.71s22.04,2.21,32.06,6.71c10.02,4.5,18.65,10.5,26.05,18.18,7.4,7.68,13.24,16.59,17.51,26.65,4.27,10.15,6.45,20.92,6.45,32.39s-2.18,22.33-6.45,32.39Z"/> - <path class="cls-1" d="M1828.62,214.01c0-3.35-.7-6.53-2-9.53-1.31-3-3.05-5.73-5.23-8.03-2.18-2.29-4.79-4.15-7.75-5.38-2.96-1.23-6.18-1.94-9.58-1.94-4.88,0-9.24,1.24-13.07,3.8l-139.92,93.11V99.29c0-7.06-2.35-12.97-7.14-17.83-4.79-4.85-10.45-7.32-17.16-7.32s-12.63,2.47-17.43,7.32c-4.79,4.85-7.14,10.77-7.14,17.83v332.71c0,6.88,2.35,12.8,7.14,17.74,4.79,4.94,10.54,7.41,17.43,7.41s12.46-2.47,17.16-7.41c4.79-4.94,7.14-10.86,7.14-17.74v-86.4l28.58-19.15,108.12,124.17c4.36,4.32,9.85,6.44,16.38,6.44,3.4,0,6.62-.62,9.58-1.94,2.96-1.24,5.58-3.09,7.75-5.38,2.18-2.29,3.92-4.94,5.23-8.03,1.31-3,2-6.27,2-9.53,0-6.53-2.26-12.36-6.8-17.47l-100.63-115.87,98.01-65.13c6.27-4.32,9.32-10.94,9.32-19.86v.18Z"/> - <path class="cls-1" d="M1414.36,263.7c7.49-7.59,16.21-13.59,26.23-17.92,10.02-4.41,20.65-6.62,32.06-6.62,10.28,0,19.78,1.77,28.58,5.29,8.71,3.53,17.08,8.74,25,15.53,4.7,3.79,10.02,5.73,15.94,5.73,7.06,0,12.81-2.38,17.43-7.15,4.62-4.77,6.88-10.77,6.88-17.92s-2.79-13.77-8.45-18.88c-24.05-21.71-52.53-32.57-85.38-32.57-36.16,0-67.08,13.06-92.7,39.27-25.62,26.12-38.33,57.72-38.33,94.78s12.81,68.57,38.33,94.78c25.62,26.12,56.46,39.27,92.7,39.27,32.76,0,61.25-10.85,85.38-32.57,5.14-5.29,7.76-11.38,7.76-18.44s-2.27-13.15-6.88-17.83c-4.62-4.68-10.45-7.06-17.42-7.06-5.92.18-11.07,1.94-15.42,5.29-7.84,6.88-16.03,12-24.83,15.44-8.71,3.44-18.21,5.12-28.58,5.12-11.41,0-22.04-2.21-32.06-6.62-10.02-4.41-18.73-10.41-26.23-17.91-7.49-7.5-13.42-16.5-17.69-26.65-4.27-10.24-6.45-21.18-6.45-32.83s2.18-22.59,6.45-32.83c4.27-10.24,10.19-19.06,17.69-26.65v-.09Z"/> - </g> -</svg> \ No newline at end of file diff --git a/public/imgs/logo/docker-logo-white.svg b/public/imgs/logo/docker-logo-white.svg deleted file mode 100644 index b1f9dff..0000000 --- a/public/imgs/logo/docker-logo-white.svg +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2333.95 530.79"> - <defs> - <style> - .cls-1 { - fill: #fff; - stroke-width: 0px; - } - </style> - </defs> - <path class="cls-1" d="M661.56,218.08c-16.49-11.1-59.81-15.84-91.3-7.35-1.69-31.37-17.88-57.81-47.47-80.88l-10.95-7.35-7.3,11.03c-14.35,21.78-20.4,50.81-18.26,77.2,1.69,16.26,7.34,34.53,18.26,47.79-40.99,23.78-78.78,18.38-246.12,18.38H.06c-.75,37.79,5.32,110.47,51.54,169.64,5.11,6.54,10.7,12.86,16.78,18.95,37.58,37.63,94.36,65.23,179.26,65.3,129.53.12,240.5-69.9,308.01-239.18,22.21.36,80.85,3.98,109.55-51.47.7-.93,7.3-14.7,7.3-14.7l-10.94-7.35ZM168.67,183.53h-72.65v72.65h72.65v-72.65ZM262.52,183.53h-72.65v72.65h72.65v-72.65ZM356.38,183.53h-72.65v72.65h72.65v-72.65ZM450.24,183.53h-72.65v72.65h72.65v-72.65ZM74.81,183.53H2.16v72.65h72.65v-72.65ZM168.67,91.77h-72.65v72.65h72.65v-72.65ZM262.52,91.77h-72.65v72.65h72.65v-72.65ZM356.38,91.77h-72.65v72.65h72.65v-72.65ZM356.38,0h-72.65v72.65h72.65V0Z"/> - <g> - <path class="cls-1" d="M2329.44,419.3c0,18.94-14.87,33.81-34.21,33.81s-34.42-14.87-34.42-33.81,15.27-33.4,34.42-33.4,34.21,14.87,34.21,33.4ZM2269.37,419.3c0,14.87,11,26.68,26.07,26.68s25.46-11.81,25.46-26.47-10.8-26.89-25.65-26.89-25.87,12.02-25.87,26.68ZM2289.95,436.82h-7.74v-33.4c3.04-.61,7.33-1.02,12.82-1.02,6.32,0,9.16,1.02,11.61,2.45,1.84,1.42,3.26,4.07,3.26,7.33,0,3.67-2.85,6.52-6.91,7.74v.41c3.24,1.21,5.08,3.66,6.1,8.14,1.01,5.09,1.62,7.13,2.45,8.35h-8.35c-1.02-1.22-1.64-4.27-2.65-8.15-.61-3.66-2.65-5.29-6.93-5.29h-3.66v13.45ZM2290.14,417.88h3.66c4.28,0,7.74-1.42,7.74-4.88,0-3.06-2.23-5.11-7.13-5.11-2.03,0-3.46.21-4.27.43v9.56Z"/> - <path class="cls-1" d="M1017.16,81.28c-4.79-4.68-10.54-7.06-17.43-7.06s-12.81,2.38-17.42,7.06c-4.62,4.68-6.88,10.68-6.88,17.83v119.4c-23.7-19.59-51.05-29.47-82.16-29.47-36.16,0-67.08,13.06-92.7,39.27-25.62,26.12-38.34,57.72-38.34,94.78s12.81,68.57,38.34,94.78c25.62,26.12,56.46,39.27,92.7,39.27s66.74-13.06,92.7-39.27c25.62-25.86,38.34-57.45,38.34-94.78V99.11c0-7.15-2.35-13.15-7.15-17.83ZM968.98,355.39v.18c-4.27,10.15-10.11,19.06-17.51,26.65-7.4,7.68-16.12,13.68-26.05,18.18-10.02,4.5-20.65,6.71-32.06,6.71s-22.3-2.21-32.32-6.71c-10.02-4.5-18.65-10.5-25.96-18.09-7.32-7.59-13.15-16.5-17.42-26.65-4.27-10.24-6.45-21.09-6.45-32.57s2.18-22.33,6.45-32.57c4.27-10.24,10.11-19.06,17.42-26.65,7.32-7.59,16.03-13.59,25.96-18.09,10.02-4.5,20.74-6.71,32.32-6.71s22.04,2.21,32.06,6.71c10.02,4.5,18.65,10.5,26.05,18.18,7.4,7.68,13.24,16.59,17.51,26.65,4.27,10.15,6.45,20.92,6.45,32.39s-2.18,22.33-6.45,32.39Z"/> - <path class="cls-1" d="M2099.77,271.64c-6.36-15.89-16.05-30.27-28.76-43.16l-.17-.09c-25.88-26.12-56.82-39.27-92.7-39.27s-67.09,13.06-92.71,39.27c-25.62,26.12-38.33,57.72-38.33,94.78s12.81,68.57,38.33,94.78c25.62,26.12,56.47,39.27,92.71,39.27,32.92,0,61.41-10.85,85.64-32.56,4.69-4.94,7.06-10.94,7.06-17.92s-2.26-13.15-6.89-17.83c-4.61-4.68-10.45-7.06-17.42-7.06-6.09.18-11.5,2.21-16.11,6.27-7.32,6.35-15.25,11.21-23.87,14.39-8.63,3.18-18.04,4.77-28.31,4.77-9.07,0-17.78-1.41-26.05-4.32-8.29-2.91-16.03-6.89-22.92-12.09-6.98-5.21-12.98-11.38-18.12-18.71-5.14-7.24-9.06-15.27-11.67-24.09h185.32c6.87,0,12.62-2.38,17.42-7.06,4.8-4.68,7.15-10.68,7.15-17.83,0-18.53-3.24-35.74-9.58-51.54ZM1899.29,298.29c2.53-8.74,6.36-16.77,11.5-24.09,5.15-7.24,11.24-13.5,18.21-18.71,7.06-5.21,14.72-9.18,23.17-12.09,8.44-2.91,17.06-4.32,25.97-4.32s17.51,1.41,25.86,4.32c8.37,2.91,16.05,6.88,22.92,12.09,6.98,5.21,13.07,11.38,18.21,18.71,5.22,7.24,9.16,15.27,11.86,24.09h-157.71Z"/> - <path class="cls-1" d="M2327.51,205.89c-4.36-4.32-9.85-7.68-16.47-10.15-6.62-2.47-13.85-4.15-21.78-5.12-7.84-.97-15.25-1.41-22.12-1.41-15.61,0-30.24,2.56-44,7.68-13.77,5.12-26.49,12.44-38.17,21.97v-4.76c0-6.88-2.35-12.71-7.15-17.56-4.78-4.85-10.45-7.32-17.15-7.32s-12.64,2.47-17.42,7.32c-4.8,4.85-7.15,10.77-7.15,17.56v218.25c0,6.88,2.35,12.71,7.15,17.56,4.78,4.85,10.53,7.32,17.42,7.32s12.45-2.47,17.15-7.32c4.8-4.85,7.15-10.77,7.15-17.56v-109.17c0-11.65,2.18-22.59,6.45-32.83,4.27-10.24,10.11-19.06,17.51-26.65,7.42-7.59,16.13-13.59,26.05-17.92,10.02-4.41,20.66-6.62,32.08-6.62s22.2,2.03,32.06,6c3.91,1.77,7.32,2.65,10.28,2.65,3.4,0,6.62-.62,9.58-1.94,2.96-1.32,5.58-3.09,7.76-5.38,2.18-2.29,3.91-4.94,5.22-8.03,1.31-3,2.01-6.27,2.01-9.8,0-6.88-2.18-12.44-6.53-16.77h.08Z"/> - <path class="cls-1" d="M1304.49,271.73c-6.36-15.8-15.86-30.27-28.66-43.33-25.87-26.12-56.8-39.27-92.7-39.27s-67.08,13.06-92.7,39.27c-25.62,26.12-38.33,57.72-38.33,94.78s12.81,68.57,38.33,94.78c25.62,26.12,56.46,39.27,92.7,39.27s66.74-13.06,92.7-39.27c25.62-25.86,38.34-57.45,38.34-94.78-.18-18.53-3.4-35.65-9.67-51.45ZM1258.84,355.39v.18c-4.27,10.15-10.11,19.06-17.51,26.65-7.4,7.68-16.12,13.68-26.05,18.18-9.93,4.5-20.65,6.71-32.06,6.71s-22.3-2.21-32.32-6.71c-10.02-4.5-18.65-10.5-25.96-18.09-7.32-7.59-13.15-16.5-17.42-26.65-4.27-10.24-6.45-21.09-6.45-32.57s2.18-22.33,6.45-32.57c4.27-10.24,10.11-19.06,17.42-26.65,7.32-7.59,16.03-13.59,25.96-18.09,10.02-4.5,20.74-6.71,32.32-6.71s22.04,2.21,32.06,6.71c10.02,4.5,18.65,10.5,26.05,18.18,7.4,7.68,13.24,16.59,17.51,26.65,4.27,10.15,6.45,20.92,6.45,32.39s-2.18,22.33-6.45,32.39Z"/> - <path class="cls-1" d="M1828.62,214.01c0-3.35-.7-6.53-2-9.53-1.31-3-3.05-5.73-5.23-8.03-2.18-2.29-4.79-4.15-7.75-5.38-2.96-1.23-6.18-1.94-9.58-1.94-4.88,0-9.24,1.24-13.07,3.8l-139.92,93.11V99.29c0-7.06-2.35-12.97-7.14-17.83-4.79-4.85-10.45-7.32-17.16-7.32s-12.63,2.47-17.43,7.32c-4.79,4.85-7.14,10.77-7.14,17.83v332.71c0,6.88,2.35,12.8,7.14,17.74,4.79,4.94,10.54,7.41,17.43,7.41s12.46-2.47,17.16-7.41c4.79-4.94,7.14-10.86,7.14-17.74v-86.4l28.58-19.15,108.12,124.17c4.36,4.32,9.85,6.44,16.38,6.44,3.4,0,6.62-.62,9.58-1.94,2.96-1.24,5.58-3.09,7.75-5.38,2.18-2.29,3.92-4.94,5.23-8.03,1.31-3,2-6.27,2-9.53,0-6.53-2.26-12.36-6.8-17.47l-100.63-115.87,98.01-65.13c6.27-4.32,9.32-10.94,9.32-19.86v.18Z"/> - <path class="cls-1" d="M1414.36,263.7c7.49-7.59,16.21-13.59,26.23-17.92,10.02-4.41,20.65-6.62,32.06-6.62,10.28,0,19.78,1.77,28.58,5.29,8.71,3.53,17.08,8.74,25,15.53,4.7,3.79,10.02,5.73,15.94,5.73,7.06,0,12.81-2.38,17.43-7.15,4.62-4.77,6.88-10.77,6.88-17.92s-2.79-13.77-8.45-18.88c-24.05-21.71-52.53-32.57-85.38-32.57-36.16,0-67.08,13.06-92.7,39.27-25.62,26.12-38.33,57.72-38.33,94.78s12.81,68.57,38.33,94.78c25.62,26.12,56.46,39.27,92.7,39.27,32.76,0,61.25-10.85,85.38-32.57,5.14-5.29,7.76-11.38,7.76-18.44s-2.27-13.15-6.88-17.83c-4.62-4.68-10.45-7.06-17.42-7.06-5.92.18-11.07,1.94-15.42,5.29-7.84,6.88-16.03,12-24.83,15.44-8.71,3.44-18.21,5.12-28.58,5.12-11.41,0-22.04-2.21-32.06-6.62-10.02-4.41-18.73-10.41-26.23-17.91-7.49-7.5-13.42-16.5-17.69-26.65-4.27-10.24-6.45-21.18-6.45-32.83s2.18-22.59,6.45-32.83c4.27-10.24,10.19-19.06,17.69-26.65v-.09Z"/> - </g> -</svg> \ No newline at end of file diff --git a/public/imgs/logo/docker-mark-blue.svg b/public/imgs/logo/docker-mark-blue.svg deleted file mode 100644 index eba6cc4..0000000 --- a/public/imgs/logo/docker-mark-blue.svg +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 756.26 596.9"> - <defs> - <style> - .cls-1 { - fill: #1d63ed; - stroke-width: 0px; - } - </style> - </defs> - <path class="cls-1" d="M743.96,245.25c-18.54-12.48-67.26-17.81-102.68-8.27-1.91-35.28-20.1-65.01-53.38-90.95l-12.32-8.27-8.21,12.4c-16.14,24.5-22.94,57.14-20.53,86.81,1.9,18.28,8.26,38.83,20.53,53.74-46.1,26.74-88.59,20.67-276.77,20.67H.06c-.85,42.49,5.98,124.23,57.96,190.77,5.74,7.35,12.04,14.46,18.87,21.31,42.26,42.32,106.11,73.35,201.59,73.44,145.66.13,270.46-78.6,346.37-268.97,24.98.41,90.92,4.48,123.19-57.88.79-1.05,8.21-16.54,8.21-16.54l-12.3-8.27ZM189.67,206.39h-81.7v81.7h81.7v-81.7ZM295.22,206.39h-81.7v81.7h81.7v-81.7ZM400.77,206.39h-81.7v81.7h81.7v-81.7ZM506.32,206.39h-81.7v81.7h81.7v-81.7ZM84.12,206.39H2.42v81.7h81.7v-81.7ZM189.67,103.2h-81.7v81.7h81.7v-81.7ZM295.22,103.2h-81.7v81.7h81.7v-81.7ZM400.77,103.2h-81.7v81.7h81.7v-81.7ZM400.77,0h-81.7v81.7h81.7V0Z"/> -</svg> \ No newline at end of file diff --git a/public/imgs/logo/docker-mark-white.svg b/public/imgs/logo/docker-mark-white.svg deleted file mode 100644 index fc59e9d..0000000 --- a/public/imgs/logo/docker-mark-white.svg +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 756.26 596.9"> - <defs> - <style> - .cls-1 { - fill: #fff; - stroke-width: 0px; - } - </style> - </defs> - <path class="cls-1" d="M743.96,245.25c-18.54-12.48-67.26-17.81-102.68-8.27-1.91-35.28-20.1-65.01-53.38-90.95l-12.32-8.27-8.21,12.4c-16.14,24.5-22.94,57.14-20.53,86.81,1.9,18.28,8.26,38.83,20.53,53.74-46.1,26.74-88.59,20.67-276.77,20.67H.06c-.85,42.49,5.98,124.23,57.96,190.77,5.74,7.35,12.04,14.46,18.87,21.31,42.26,42.32,106.11,73.35,201.59,73.44,145.66.13,270.46-78.6,346.37-268.97,24.98.41,90.92,4.48,123.19-57.88.79-1.05,8.21-16.54,8.21-16.54l-12.3-8.27ZM189.67,206.39h-81.7v81.7h81.7v-81.7ZM295.22,206.39h-81.7v81.7h81.7v-81.7ZM400.77,206.39h-81.7v81.7h81.7v-81.7ZM506.32,206.39h-81.7v81.7h81.7v-81.7ZM84.12,206.39H2.42v81.7h81.7v-81.7ZM189.67,103.2h-81.7v81.7h81.7v-81.7ZM295.22,103.2h-81.7v81.7h81.7v-81.7ZM400.77,103.2h-81.7v81.7h81.7v-81.7ZM400.77,0h-81.7v81.7h81.7V0Z"/> -</svg> \ No newline at end of file diff --git a/src/scripts/components/header-component.ts b/src/scripts/components/header-component.ts index 1252b9a..b8b66ea 100644 --- a/src/scripts/components/header-component.ts +++ b/src/scripts/components/header-component.ts @@ -29,12 +29,9 @@ class HeaderComponent extends HTMLElement { <div class="flex h-full items-center lg:gap-8 gap-2"> <div> <a href="/" title="Docker korean translation home page"> - <img - src="./imgs/logo/docker-logo-white.svg" - alt="Docker Korea home page" - width="120" - height="24" - /> + <p class="w-full text-5xl font-bold text-white"> + Docker <span class="text-red-500">K</span><span class="text-blue-800">O</span> + </p> </a> </div> <nav class="mt-1 hidden md:block"> From 6d2c0be334b2e788a8095064e4a0dd9379dc8679 Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 03:05:58 +0900 Subject: [PATCH 06/20] =?UTF-8?q?Header(=EC=8A=A4=ED=83=80=EC=9D=BC=20?= =?UTF-8?q?=EC=84=B8=EB=B6=80=20=EC=88=98=EC=A0=95),=20Nav=20=EC=9B=B9=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/components/header-component.ts | 2 +- src/scripts/components/nav-component.ts | 0 src/scripts/main.ts | 1 - src/styles/not_found.css | 44 ---------------------- 4 files changed, 1 insertion(+), 46 deletions(-) create mode 100644 src/scripts/components/nav-component.ts delete mode 100644 src/styles/not_found.css diff --git a/src/scripts/components/header-component.ts b/src/scripts/components/header-component.ts index b8b66ea..fbd728e 100644 --- a/src/scripts/components/header-component.ts +++ b/src/scripts/components/header-component.ts @@ -24,7 +24,7 @@ class HeaderComponent extends HTMLElement { connectedCallback() { this.innerHTML = ` - <header class="w-full sticky top-0 z-20 h-16 px-6 text-white bg-[#086dd7]"> + <header class="w-full sticky top-0 z-20 h-18 px-6 text-white bg-[#086dd7]"> <div class="max-w-[1920px] mx-auto flex lg:gap-8 gap-2 h-full items-center justify-between"> <div class="flex h-full items-center lg:gap-8 gap-2"> <div> diff --git a/src/scripts/components/nav-component.ts b/src/scripts/components/nav-component.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/scripts/main.ts b/src/scripts/main.ts index 026ea25..a296334 100644 --- a/src/scripts/main.ts +++ b/src/scripts/main.ts @@ -1,6 +1,5 @@ import './components/index'; import '../styles/content_style.css'; -import '../styles/not_found.css'; import '../styles/style.css'; import './load_md'; import './components/card-component'; diff --git a/src/styles/not_found.css b/src/styles/not_found.css deleted file mode 100644 index 718232e..0000000 --- a/src/styles/not_found.css +++ /dev/null @@ -1,44 +0,0 @@ -.not-found { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - - text-align: center; - padding: 20px; - max-width: 600px; - background: #fff; - border: 1px solid #ddd; - border-radius: 8px; - box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); -} - -.not-found h2 { - color: #d9534f; - font-size: 24px; - margin-bottom: 10px; -} - -.not-found p { - font-size: 16px; - color: #555; -} - -.not-found .back-home { - display: inline-block; - margin-top: 10px; - padding: 8px 15px; - background: #007bff; - color: white; - text-decoration: none; - border-radius: 4px; -} - -.not-found .back-home:hover { - background: #0056b3; -} From 1b69a37f747baafd3a7bd2fa49c286422cabe1ad Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 03:11:18 +0900 Subject: [PATCH 07/20] =?UTF-8?q?[fix]=20404=20=EA=B2=BD=EC=9A=B0=EC=9D=98?= =?UTF-8?q?=20=EA=B8=B0=EB=B3=B8=20html=20=EA=B5=AC=EC=A1=B0=20=EC=84=B8?= =?UTF-8?q?=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/load_md.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/load_md.ts b/src/scripts/load_md.ts index 858a731..9f97a97 100644 --- a/src/scripts/load_md.ts +++ b/src/scripts/load_md.ts @@ -104,8 +104,8 @@ async function loadMarkdown(page: string) { } catch { document.getElementById('content')!.innerHTML = ` <div id="not-found" class="w-full"> - <p>페이지를 찾을 수 없습니다.</p> - <a href="#/home" class="back-home">홈으로 돌아가기</a> + <p>열심히 문서를 업데이트하고 있습니다💦. 더 풍부한 한국어 번역 자료를 제공하기 위해 웹사이트 발전에 기여하고 싶다면 <a href="https://github.com/docker-ko/docker-ko.github.io">깃허브 레포지토리 주소</a>를 클릭하세요!</p> + <button-component href="#/home" title="홈으로 돌아가기" /> </div> `; } From 2f637dd4ff31b42f4c1f053244c23629851e7ec7 Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 03:11:32 +0900 Subject: [PATCH 08/20] =?UTF-8?q?[=EB=B2=88=EC=97=AD]=20Guides=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=B4=88=EC=95=88=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/docs/guides.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 public/docs/guides.md diff --git a/public/docs/guides.md b/public/docs/guides.md new file mode 100644 index 0000000..bbee4db --- /dev/null +++ b/public/docs/guides.md @@ -0,0 +1,7 @@ +# Docker guides + +Docker를 사용하여 개발 워크플로를 최적화하는 방법과 특정 언어, 프레임워크 또는 기술과 함께 사용하는 방법을 알아보려면 가이드 모음을 살펴보세요. + +원하는 가이드를 찾을 수 없나요? [docker/docs](https://github.com/docker/docs/issues/new/choose) 저장소에 이슈를 등록하여 알려주세요. + +추천 가이드 \ No newline at end of file From 10b38e7af8f12952be4356a0a78089b308133ce6 Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 14:26:58 +0900 Subject: [PATCH 09/20] =?UTF-8?q?SPA=EB=A5=BC=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EA=B3=A8=EA=B2=A9=EB=A7=8C=20=EB=82=A8=EA=B8=B0=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 594 +---------------------------------------------------- 1 file changed, 5 insertions(+), 589 deletions(-) diff --git a/index.html b/index.html index dc418ce..97f9ef6 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,6 @@ }}); </script> <script type="module" src="./src/scripts/main.ts" defer></script> - <!-- Application Insights 스크립트는 main.ts에서 운영 환경에서만 동적으로 삽입됩니다. --> <link rel="icon" type="image/svg+xml" @@ -33,597 +32,14 @@ <!-- 최상단 헤더 --> <header-component></header-component> - <main class="flex h-full w-full"> + <main class="flex h-full w-full" id="main"> <!-- nav: 목차 나타내는 왼쪽 부분 사이드 --> <nav id="sidebar" style="scroll-behavior: smooth" - class="dark:bg-gray-dark-100 fixed top-0 z-40 hidden h-screen w-full flex-none overflow-x-hidden overflow-y-auto bg-[#f9f9fa] md:sticky md:top-12 md:z-auto md:block md:h-[calc(100vh-64px)] md:w-[320px]" + class="dark:bg-gray-dark-100 fixed top-0 z-40 hidden h-full w-full flex-none overflow-x-hidden overflow-y-auto bg-[#f9f9fa] md:sticky md:top-12 md:z-auto md:block md:h-[calc(100vh-64px)] md:w-[320px]" > - <div class="dark:bg-gray-dark-100 z-50 w-full p-4 md:block"> - <div - id="nav__content" - class="flex flex-col font-light text-black md:text-base" - > - <ul> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/get-docker" - >Get Docker</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-overview" - >What is Docker?</a - > - </li> - <li> - <div - class="flex w-full items-center justify-between rounded px-2" - id="section__wrapper" - > - <div class="w-full truncate py-2"> - <a - class="block select-none hover:text-blue-500 hover:dark:text-blue-500" - href="#/get-started/introduction" - >Introduction</a - > - </div> - <button - class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" - aria-label="Toggle section" - aria-expanded="false" - > - <span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z" - /> - </svg> - </span> - <span class="hidden"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z" - /> - </svg> - </span> - </button> - </div> - <ul class="ml-3 hidden"> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/introduction/get-docker-desktop" - title="Get Docker Desktop" - >Get Docker Desktop - </a> - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/introduction/develop-with-containers" - title="Develop with containers" - >Develop with containers - </a> - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/introduction/build-and-push-first-image" - title="Build and push your first image" - >Build and push your first image - </a> - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/introduction/whats-next" - title="What's next" - >What's next - </a> - </li> - </ul> - </li> - <li> - <div - class="flex w-full items-center justify-between rounded px-2" - id="section__wrapper" - > - <div class="w-full truncate py-2"> - <button - class="w-full text-left select-none hover:text-blue-500 hover:dark:text-blue-500" - > - Docker concepts - </button> - </div> - <button - class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" - aria-label="Toggle section" - aria-expanded="false" - > - <span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z" - /> - </svg> - </span> - <span class="hidden"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z" - /> - </svg> - </span> - </button> - </div> - <ul class="ml-3 hidden"> - <li> - <div - class="flex w-full items-center justify-between rounded px-2" - id="section__wrapper" - > - <div class="w-full truncate py-2"> - <button - class="w-full text-left select-none hover:text-blue-500 hover:dark:text-blue-500" - > - The basics - </button> - </div> - <button - class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" - aria-label="Toggle section" - aria-expanded="false" - > - <span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z" - /> - </svg> - </span> - <span class="hidden"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z" - /> - </svg> - </span> - </button> - </div> - <ul class="ml-3 hidden"> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/the-basics/what-is-a-container" - title="What is a container?" - >What is a container?</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/the-basics/what-is-an-image" - title="What is an image?" - >What is an image?</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/the-basics/what-is-a-registry" - title="What is a registry?" - >What is a registry?</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/the-basics/what-is-docker-compose" - title="What is Docker Compose?" - >What is Docker Compose?</a - > - </li> - </ul> - </li> - - <li> - <div - class="flex w-full items-center justify-between rounded px-2" - id="section__wrapper" - > - <div class="w-full truncate py-2"> - <button - class="w-full text-left select-none hover:text-blue-500 hover:dark:text-blue-500" - > - Building images - </button> - </div> - <button - class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" - aria-label="Toggle section" - aria-expanded="false" - > - <span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z" - /> - </svg> - </span> - <span class="hidden"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z" - /> - </svg> - </span> - </button> - </div> - <ul class="ml-3 hidden"> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/building-images/understanding-image-layers" - title="Understanding the image layers" - >Understanding the image layers</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/building-images/writing-a-dockerfile" - title="Writing a Dockerfile" - >Writing a Dockerfile</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/building-images/build-tag-and-publish-an-image" - title="Build, tag, and publish an image" - >Build, tag, and publish an image</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/building-images/using-the-build-cache" - title="Using the build cache" - >Using the build cache</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/building-images/multi-stage-builds" - title="Multi-stage builds" - >Multi-stage builds</a - > - </li> - </ul> - </li> - - <li> - <div - class="flex w-full items-center justify-between rounded px-2" - id="section__wrapper" - > - <div class="w-full truncate py-2"> - <button - class="w-full text-left select-none hover:text-blue-500 hover:dark:text-blue-500" - > - Running containers - </button> - </div> - <button - class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" - aria-label="Toggle section" - aria-expanded="false" - > - <span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z" - /> - </svg> - </span> - <span class="hidden"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z" - /> - </svg> - </span> - </button> - </div> - <ul class="ml-3 hidden"> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/running-containers/publishing-ports" - title="Publishing and exposing ports" - >Publishing and exposing ports</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/running-containers/overriding-container-defaults" - title="Overriding container defaults" - >Overriding container defaults</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/running-containers/persisting-container-data" - title="Persisting container data" - >Persisting container data</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/running-containers/sharing-local-files" - title="Sharing local files with containers" - >Sharing local files with containers</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/docker-concepts/running-containers/multi-container-applications" - title="Multi-container applications" - >Multi-container applications</a - > - </li> - </ul> - </li> - </ul> - </li> - <li> - <div - class="flex w-full items-center justify-between rounded px-2" - id="section__wrapper" - > - <div class="w-full truncate py-2"> - <a - class="block select-none hover:text-blue-500 hover:dark:text-blue-500" - href="#/get-started/docker-workshop" - >Docker workshop</a - > - </div> - <button - class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" - aria-label="Toggle section" - aria-expanded="false" - > - <span> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z" - /> - </svg> - </span> - <span class="hidden"> - <svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 512 512" - width="12" - height="12" - > - <path - d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z" - /> - </svg> - </span> - </button> - </div> - <ul class="ml-3 hidden"> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/02_our_app" - title="Part 1: Containerize an application" - >Part 1: Containerize an application</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/03_updating_app" - title="Part 2: Update the application" - >Part 2: Update the application</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/04_sharing_app" - title="Part 3: Share the application" - >Part 3: Share the application</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/05_persisting_data" - title="Part 4: Persist the DB" - >Part 4: Persist the DB</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/06_bind_mounts" - title="Part 5: Use bind mounts" - >Part 5: Use bind mounts</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/07_multi_container" - title="Part 6: Multi-container apps" - >Part 6: Multi-container apps</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/08_using_compose" - title="Part 7: Use Docker Compose" - >Part 7: Use Docker Compose</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/09_image_best" - title="Part 8: Image-building best practices" - >Part 8: Image-building best practices</a - > - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/workshop/10_what_next" - title="Part 9: What next" - >Part 9: What next</a - > - </li> - </ul> - </li> - <li - class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500" - > - <a - class="block w-full truncate py-2" - href="#/get-started/resources" - >Educational resources</a - > - </li> - </ul> - </div> - </div> + <nav-component></nav-component> </nav> <!-- content: (마크다운 파일) 표시 공간 : 중간 부분 --> @@ -635,9 +51,9 @@ <!-- aside: 오른쪽 부분 사이드 --> <aside id="aside-toc" - class="sticky top-12 h-full min-w-70 overflow-y-auto px-2 py-4 lg:block" + class="sticky top-12 h-full overflow-y-auto px-2 py-5 hidden lg:block min-w-60" > - <div id="toc" class="text-[14px] text-black font-bold"></div> + <div id="toc" class="text-[14px] text-black font-bold w-full"></div> </aside> </main> From e1915bbf5fabc6d1f7d61129f992787034fe8ddb Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 14:27:25 +0900 Subject: [PATCH 10/20] =?UTF-8?q?=EC=9E=98=EB=AA=BB=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=EB=90=9C=20Content=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/content_style.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/styles/content_style.css b/src/styles/content_style.css index b7beeed..1a474e7 100644 --- a/src/styles/content_style.css +++ b/src/styles/content_style.css @@ -1,7 +1,7 @@ #content h1, -h2, -h3, -h4 { +#content h2, +#content h3, +#content h4 { font-weight: 500; margin-bottom: 1rem; margin-top: 2rem; From b24ff88739b94dd8af832835177b17380d6c78b4 Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 14:28:19 +0900 Subject: [PATCH 11/20] =?UTF-8?q?Nav=20=EC=9B=B9=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/components/index.ts | 1 + src/scripts/components/nav-component.ts | 294 ++++++++++++++++++++++++ src/scripts/main.ts | 2 - 3 files changed, 295 insertions(+), 2 deletions(-) diff --git a/src/scripts/components/index.ts b/src/scripts/components/index.ts index 2631c12..8ec9ec9 100644 --- a/src/scripts/components/index.ts +++ b/src/scripts/components/index.ts @@ -2,3 +2,4 @@ import './footer-component'; import './header-component'; import './card-component'; import './button-component'; +import './nav-component'; diff --git a/src/scripts/components/nav-component.ts b/src/scripts/components/nav-component.ts index e69de29..6da35c8 100644 --- a/src/scripts/components/nav-component.ts +++ b/src/scripts/components/nav-component.ts @@ -0,0 +1,294 @@ +interface NavItem { + name: string; + docs_path?: string; + href_path: string; + children?: Record<string, NavItem>; +} + +interface GetStartedData { + [key: string]: NavItem; +} + +interface GuidesData { + [key: string]: string[]; +} + +export default class NavComponent extends HTMLElement { + private currentRoute: string = ''; + + constructor() { + super(); + } + + connectedCallback() { + this.render(); + this.setupEventListeners(); // 이벤트 리스너 설정 + } + + private getCurrentRoute(): string { + const hash = window.location.hash.slice(2); // #/ 제거 + return hash.split('/')[0] || 'get-started'; + } + + private async loadNavData(): Promise<GetStartedData | GuidesData> { + this.currentRoute = this.getCurrentRoute(); + + try { + const response = await fetch(`/src/data/nav/${this.currentRoute}.json`); + if (!response.ok) { + throw new Error( + `Failed to load navigation data for ${this.currentRoute}` + ); + } + return await response.json(); + } catch (error) { + console.error('Error loading navigation data:', error); + // 기본값으로 get-started 데이터 반환 + const fallbackResponse = await fetch('/src/data/nav/get-started.json'); + return await fallbackResponse.json(); + } + } + + private isGetStartedData( + data: GetStartedData | GuidesData + ): data is GetStartedData { + return ( + this.currentRoute === 'get-started' || + (Object.values(data)[0] && + typeof Object.values(data)[0] === 'object' && + !Array.isArray(Object.values(data)[0])) + ); + } + + private generateGetStartedNav(data: GetStartedData): string { + return Object.entries(data) + .map(([, item]) => { + if (item.children) { + return this.generateSectionWithChildren(item); + } else { + return ` + <li class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500"> + <a class="block w-full truncate py-2" href="${item.href_path}"> + ${item.name} + </a> + </li> + `; + } + }) + .join(''); + } + + private generateSectionWithChildren(item: NavItem): string { + const childrenHtml = item.children + ? Object.entries(item.children) + .map(([, childItem]) => { + if (childItem.children) { + // 3단계 중첩 (예: docker-concepts/the-basics/what-is-a-container) + return this.generateNestedSection(childItem); + } else { + return ` + <li class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500"> + <a class="block w-full truncate py-2" + href="${childItem.href_path}" + title="${childItem.name}"> + ${childItem.name} + </a> + </li> + `; + } + }) + .join('') + : ''; + + return ` + <li class="w-70"> + <div class="flex w-full items-center justify-between rounded px-2" id="section__wrapper"> + <div class="w-full truncate py-2"> + ${ + item.href_path + ? `<a class="block select-none hover:text-blue-500 hover:dark:text-blue-500" + href="${item.href_path}"> + ${item.name} + </a>` + : `<span class="block select-none text-gray-700 dark:text-gray-300"> + ${item.name} + </span>` + } + </div> + <button class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" aria-label="Toggle section" aria-expanded="false"> + <span> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"> + <path d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"/> + </svg> + </span> + <span class="hidden"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"> + <path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/> + </svg> + </span> + </button> + </div> + <ul class="ml-3 hidden"> + ${childrenHtml} + </ul> + </li> + `; + } + + private generateNestedSection(item: NavItem): string { + const childrenHtml = item.children + ? Object.entries(item.children) + .map( + ([, childItem]) => ` + <li class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500"> + <a class="block w-full truncate py-2" + href="${childItem.href_path}" + title="${childItem.name}"> + ${childItem.name} + </a> + </li> + ` + ) + .join('') + : ''; + + return ` + <li> + <div class="flex w-full items-center justify-between rounded px-2" id="section__wrapper"> + <div class="w-full truncate py-2"> + ${ + item.href_path + ? `<a class="block select-none hover:text-blue-500 hover:dark:text-blue-500" + href="${item.href_path}"> + ${item.name} + </a>` + : `<span class="block select-none text-gray-700 dark:text-gray-300"> + ${item.name} + </span>` + } + </div> + <button class="inline-flex h-7 w-7 items-center justify-center rounded hover:cursor-pointer hover:bg-gray-400 hover:dark:bg-gray-400" + aria-label="Toggle section" + aria-expanded="false"> + <span> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"> + <path d="M233.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L256 173.3 86.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"/> + </svg> + </span> + <span class="hidden"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"> + <path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 129.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/> + </svg> + </span> + </button> + </div> + <ul class="ml-3 hidden"> + ${childrenHtml} + </ul> + </li> + `; + } + + private generateGuidesNav(data: GuidesData): string { + return Object.entries(data) + .map( + ([category, items]) => ` + <li class="mb-2"> + <h3 class="mb-2 text-lg font-bold text-gray-700 dark:text-gray-300 uppercase tracking-wide"> + ${category} + </h3> + <ul class="ml-0"> + ${items + .map( + (item) => ` + <li class="rounded px-2 hover:text-blue-500 hover:dark:text-blue-500"> + <div class="flex items-center py-2"> + <input type="checkbox" class="mr-2 rounded cursor-pointer" id="${category.toLowerCase()}-${item.toLowerCase().replace(/\s+/g, '-').replace(/[#+]/g, '')}"> + <label class="block w-full truncate cursor-pointer" for="${category.toLowerCase()}-${item.toLowerCase().replace(/\s+/g, '-').replace(/[#+]/g, '')}"> + ${item} + </label> + </div> + </li> + ` + ) + .join('')} + </ul> + </li> + ` + ) + .join(''); + } + + private setupEventListeners(): void { + // 토글 버튼 이벤트 리스너 설정 + this.addEventListener('click', (event) => { + const button = (event.target as Element).closest('button'); + if (button && button.getAttribute('aria-label') === 'Toggle section') { + this.toggleSection(button as HTMLButtonElement); + } + }); + + // 라우트 변경 감지 + window.addEventListener('hashchange', () => { + const newRoute = this.getCurrentRoute(); + if (newRoute !== this.currentRoute) { + this.render(); + } + }); + } + + private toggleSection(button: HTMLButtonElement): void { + const contentWrapperDiv = button.closest( + '#section__wrapper' + ) as HTMLDivElement; + const ulElement = contentWrapperDiv?.parentElement?.querySelector( + 'ul.ml-3' + ) as HTMLUListElement; + + if (ulElement) { + ulElement.classList.toggle('hidden'); + } + + // 아이콘 토글 + const spans = button.querySelectorAll('span'); + spans.forEach((span) => { + span.classList.toggle('hidden'); + }); + + // aria-expanded 상태 변경 + const isExpanded = button.getAttribute('aria-expanded') === 'true'; + button.setAttribute('aria-expanded', (!isExpanded).toString()); + } + + async render(): Promise<void> { + try { + const navData = await this.loadNavData(); + let navContent = ''; + + if (this.isGetStartedData(navData)) { + navContent = this.generateGetStartedNav(navData); + } else { + navContent = this.generateGuidesNav(navData); + } + + this.innerHTML = ` + <div class="dark:bg-gray-dark-100 z-50 w-full p-4 md:block h-full"> + <div id="nav__content" class="flex flex-col font-light text-black md:text-base"> + <ul> + ${navContent} + </ul> + </div> + </div> + `; + } catch { + this.innerHTML = ` + <div class="dark:bg-gray-dark-100 z-50 w-full p-4 md:block"> + <div class="text-black">네비게이션을 로드할 수 없습니다. 새로고침을 해보세요.</div> + </div> + `; + } + } +} + +// 웹 컴포넌트 등록 +customElements.define('nav-component', NavComponent); diff --git a/src/scripts/main.ts b/src/scripts/main.ts index a296334..0cc543d 100644 --- a/src/scripts/main.ts +++ b/src/scripts/main.ts @@ -4,14 +4,12 @@ import '../styles/style.css'; import './load_md'; import './components/card-component'; import { initializeMarkdownLoader } from './load_md'; -import { initializeNavFn } from './nav'; import { initializeTableContents } from './table-contents'; import { initializeBreadcrumb } from './breadcrumb'; document.addEventListener('DOMContentLoaded', async () => { try { await initializeMarkdownLoader(); - initializeNavFn(); initializeTableContents(); initializeBreadcrumb(); } catch (error) { From 8aaf8c67a514f05d68b5492cb2aa996d83a1ccab Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 14:29:44 +0900 Subject: [PATCH 12/20] =?UTF-8?q?Breadcrumb=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/breadcrumb.json | 266 ++++++++++++++++++++------------------ src/scripts/breadcrumb.ts | 34 +++-- 2 files changed, 153 insertions(+), 147 deletions(-) diff --git a/src/data/breadcrumb.json b/src/data/breadcrumb.json index 1d2cbdd..7be7f23 100644 --- a/src/data/breadcrumb.json +++ b/src/data/breadcrumb.json @@ -13,142 +13,150 @@ }, "introduction": { "name": "소개", - "linkable": true - }, - "build-and-push-first-image": { - "name": "첫 번째 이미지 빌드 및 푸시", - "linkable": true - }, - "develop-with-containers": { - "name": "컨테이너로 개발", - "linkable": true - }, - "get-docker-desktop": { - "name": "Docker Desktop 설치", - "linkable": true - }, - "whats-next": { - "name": "다음 단계", - "linkable": true + "linkable": true, + "children": { + "get-docker-desktop": { + "name": "Docker Desktop 설치", + "linkable": true + }, + "develop-with-containers": { + "name": "컨테이너로 개발", + "linkable": true + }, + "build-and-push-first-image": { + "name": "첫 번째 이미지 빌드 및 푸시", + "linkable": true + }, + "whats-next": { + "name": "다음 단계", + "linkable": true + } + } }, "docker-concepts": { "name": "Docker 개념", - "linkable": false - }, - "the-basics": { - "name": "기본 사항", - "linkable": false - }, - "what-is-a-container": { - "name": "컨테이너란?", - "linkable": true - }, - "what-is-a-registry": { - "name": "레지스트리란?", - "linkable": true - }, - "what-is-an-image": { - "name": "이미지란?", - "linkable": true - }, - "what-is-docker-compose": { - "name": "Docker Compose란?", - "linkable": true - }, - "building-images": { - "name": "이미지 빌드", - "linkable": false - }, - "understanding-image-layers": { - "name": "이미지 레이어 이해", - "linkable": true - }, - "writing-a-dockerfile": { - "name": "Dockerfile 작성", - "linkable": true - }, - "build-tag-and-publish-an-image": { - "name": "이미지 빌드, 태그, 게시", - "linkable": true - }, - "using-the-build-cache": { - "name": "빌드 캐시 사용", - "linkable": true - }, - "multi-stage-builds": { - "name": "멀티 스테이지 빌드", - "linkable": true - }, - "running-containers": { - "name": "컨테이너 실행", - "linkable": false - }, - "multi-container-applications": { - "name": "멀티 컨테이너 애플리케이션", - "linkable": true - }, - "overriding-container-defaults": { - "name": "컨테이너 기본값 재정의", - "linkable": true - }, - "persisting-container-data": { - "name": "컨테이너 데이터 유지", - "linkable": true - }, - "publishing-ports": { - "name": "포트 게시", - "linkable": true - }, - "sharing-local-files": { - "name": "로컬 파일 공유", - "linkable": true - }, - "docker-workshop": { - "name": "Docker 워크샵", - "linkable": true - }, - "resources": { - "name": "리소스", - "linkable": true + "linkable": false, + "children": { + "the-basics": { + "name": "기본 사항", + "linkable": false, + "children": { + "what-is-a-container": { + "name": "컨테이너란?", + "linkable": true + }, + "what-is-an-image": { + "name": "이미지란?", + "linkable": true + }, + "what-is-a-registry": { + "name": "레지스트리란?", + "linkable": true + }, + "what-is-docker-compose": { + "name": "Docker Compose란?", + "linkable": true + } + } + }, + "building-images": { + "name": "이미지 빌드", + "linkable": false, + "children": { + "understanding-image-layers": { + "name": "이미지 레이어 이해", + "linkable": true + }, + "writing-a-dockerfile": { + "name": "Dockerfile 작성", + "linkable": true + }, + "build-tag-and-publish-an-image": { + "name": "이미지 빌드, 태그, 게시", + "linkable": true + }, + "using-the-build-cache": { + "name": "빌드 캐시 사용", + "linkable": true + }, + "multi-stage-builds": { + "name": "멀티 스테이지 빌드", + "linkable": true + } + } + }, + "running-containers": { + "name": "컨테이너 실행", + "linkable": false, + "children": { + "publishing-ports": { + "name": "포트 게시", + "linkable": true + }, + "overriding-container-defaults": { + "name": "컨테이너 기본값 재정의", + "linkable": true + }, + "persisting-container-data": { + "name": "컨테이너 데이터 유지", + "linkable": true + }, + "sharing-local-files": { + "name": "로컬 파일 공유", + "linkable": true + }, + "multi-container-applications": { + "name": "멀티 컨테이너 애플리케이션", + "linkable": true + } + } + } + } }, "workshop": { "name": "워크샵", - "linkable": false - }, - "02_our_app": { - "name": "애플리케이션 컨테이너화", - "linkable": true + "linkable": false, + "children": { + "02_our_app": { + "name": "애플리케이션 컨테이너화", + "linkable": true + }, + "03_updating_app": { + "name": "애플리케이션 업데이트", + "linkable": true + }, + "04_sharing_app": { + "name": "애플리케이션 공유", + "linkable": true + }, + "05_persisting_data": { + "name": "데이터베이스 유지", + "linkable": true + }, + "06_bind_mounts": { + "name": "바인드 마운트 사용", + "linkable": true + }, + "07_multi_container": { + "name": "멀티 컨테이너 애플리케이션", + "linkable": true + }, + "08_using_compose": { + "name": "Docker Compose 사용", + "linkable": true + }, + "09_image_best": { + "name": "이미지 빌드 모범 사례", + "linkable": true + }, + "10_what_next": { + "name": "Docker 워크숍 이후 단계", + "linkable": true + } + } }, - "03_updating_app": { - "name": "애플리케이션 업데이트", - "linkable": true - }, - "04_sharing_app": { - "name": "애플리케이션 공유", - "linkable": true - }, - "05_persisting_data": { - "name": "데이터베이스 유지", - "linkable": true - }, - "06_bind_mounts": { - "name": "바인드 마운트 사용", - "linkable": true - }, - "07_multi_container": { - "name": "멀티 컨테이너 애플리케이션", - "linkable": true - }, - "08_using_compose": { - "name": "Docker Compose 사용", - "linkable": true - }, - "09_image_best": { - "name": "이미지 빌드 모범 사례", - "linkable": true - }, - "10_what_next": { - "name": "Docker 워크숍 이후 단계", + "resources": { + "name": "리소스", "linkable": true } } diff --git a/src/scripts/breadcrumb.ts b/src/scripts/breadcrumb.ts index 61de1d8..b098813 100644 --- a/src/scripts/breadcrumb.ts +++ b/src/scripts/breadcrumb.ts @@ -32,27 +32,24 @@ interface TranslationData { * 계층적 구조를 고려하여 현재 경로에서 세그먼트를 찾습니다. * @param segments 전체 경로 세그먼트 배열 * @param currentIndex 현재 처리 중인 세그먼트의 인덱스(깊이를 알기 위함) - * @returns 해당 세그먼트 데이터 또는 기본값 + * @returns 해당 세그먼트 데이터 또는 null (데이터가 없는 경우) */ -function getSegmentData(segments: string[], currentIndex: number): SegmentData { +function getSegmentData( + segments: string[], + currentIndex: number +): SegmentData | null { const translationData = translations as TranslationData; let current = translationData[segments[0]]; if (!current) { - return { - name: segments[currentIndex], - linkable: false, - }; + return null; } for (let i = 1; i <= currentIndex; i++) { if (current.children && current.children[segments[i]]) { current = current.children[segments[i]]; } else { - return { - name: segments[currentIndex], - linkable: false, - }; + return null; } } @@ -75,17 +72,18 @@ function generateBreadcrumbItems(): BreadcrumbItem[] { ]; let currentPath = ''; - pathSegments.forEach((segment, index) => { - currentPath += `/${segment}`; - const segmentData = getSegmentData(pathSegments, index); + currentPath += `/${segment}`; - breadcrumbItems.push({ - name: segmentData.name, - path: `#${currentPath}`, - linkable: segmentData.linkable, - }); + // translations 데이터에 없는 세그먼트는 breadcrumb에 추가하지 않음 + if (segmentData) { + breadcrumbItems.push({ + name: segmentData.name, + path: `#${currentPath}`, + linkable: segmentData.linkable, + }); + } }); return breadcrumbItems; From 25d50bbfc704200b8f9fec26e040ed5fb6decc16 Mon Sep 17 00:00:00 2001 From: ThisTimeNull <krsy0411@naver.com> Date: Sat, 21 Jun 2025 14:30:44 +0900 Subject: [PATCH 13/20] =?UTF-8?q?=EB=A7=88=ED=81=AC=EB=8B=A4=EC=9A=B4=20?= =?UTF-8?q?=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EA=B0=80=20=EC=9E=98=EB=AA=BB=20=EC=B2=98=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=EC=9E=88=EB=8D=98=20=EC=A1=B0=EA=B1=B4=EB=AC=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/load_md.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/scripts/load_md.ts b/src/scripts/load_md.ts index 9f97a97..a593219 100644 --- a/src/scripts/load_md.ts +++ b/src/scripts/load_md.ts @@ -55,6 +55,7 @@ export async function renderMarkdownWithComponents( /(<card-component[\s\S]*?<\/card-component>|<card-component[\s\S]*?\/>|<button-component[\s\S]*?<\/button-component>|<button-component[\s\S]*?\/>)/gi ) .filter(Boolean); + for (const innerToken of innerTokens) { if ( /^<\/?(card-component|button-component)[^>]*?>.*?<\/(card-component|button-component)>$/.test( @@ -75,10 +76,12 @@ export async function renderMarkdownWithComponents( async function loadMarkdown(page: string) { try { const response = await fetch(`/docs/${page}.md`); - + // HTTP 상태코드 확인 - if (!response.ok) throw new Error(`❌ 페이지를 찾을 수 없습니다: ${page}`); - + if (!response.ok) { + throw new Error(`❌ 페이지를 찾을 수 없습니다: ${page}`); + } + const mdText = await response.text(); // Content-Type 확인 (개발 서버가 HTML을 반환하는 경우 대비) @@ -87,11 +90,12 @@ async function loadMarkdown(page: string) { throw new Error(`❌ 요청된 경로가 HTML을 반환합니다: ${page}`); } - // 응답 내용이 HTML인지 확인 + // 응답 내용이 HTML인지 확인 (더 정확한 검사) + const trimmedText = mdText.trim(); if ( - mdText.trim().startsWith('<!DOCTYPE html>') || - mdText.includes('<html>') || - mdText.includes('<title>') + trimmedText.startsWith('<!DOCTYPE html>') || + trimmedText.startsWith('<html>') || + (trimmedText.startsWith('<title>') && trimmedText.includes('')) ) { throw new Error( `❌ 요청된 경로가 Markdown이 아닌 HTML을 반환합니다: ${page}` From c173f314fec4a412a4105d6761416ed7a975a718 Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 14:31:37 +0900 Subject: [PATCH 14/20] =?UTF-8?q?nav=20=EC=9B=B9=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20=EC=82=AC=EC=9A=A9=ED=95=A0=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=B3=84=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/nav/get-started.json | 186 ++++++++++++++++++++++++++++++++++ src/data/nav/guides.json | 28 +++++ 2 files changed, 214 insertions(+) create mode 100644 src/data/nav/get-started.json create mode 100644 src/data/nav/guides.json diff --git a/src/data/nav/get-started.json b/src/data/nav/get-started.json new file mode 100644 index 0000000..e6d04c1 --- /dev/null +++ b/src/data/nav/get-started.json @@ -0,0 +1,186 @@ +{ + "get-docker": { + "name": "Get Docker", + "docs_path": "/docs/get-started/get-docker", + "href_path": "#/get-started/get-docker" + }, + "docker-overview": { + "name": "What is Docker?", + "docs_path": "/docs/get-started/docker-overview", + "href_path": "#/get-started/docker-overview" + }, + "introduction": { + "name": "Introduction", + "docs_path": "/docs/get-started/introduction", + "href_path": "#/get-started/introduction", + "children": { + "get-docker-desktop": { + "name": "Get Docker Desktop", + "docs_path": "/docs/get-started/introduction/get-docker-desktop", + "href_path": "#/get-started/introduction/get-docker-desktop" + }, + "develop-with-containers": { + "name": "Develop with containers", + "docs_path": "/docs/get-started/introduction/develop-with-containers", + "href_path": "#/get-started/introduction/develop-with-containers" + }, + "build-and-push-first-image": { + "name": "Build and push your first image", + "docs_path": "/docs/get-started/introduction/build-and-push-first-image", + "href_path": "#/get-started/introduction/build-and-push-first-image" + }, + "whats-next": { + "name": "What's next", + "docs_path": "/docs/get-started/introduction/whats-next", + "href_path": "#/get-started/introduction/whats-next" + } + } + }, + "docker-concepts": { + "name": "Docker concepts", + "children": { + "the-basics": { + "name": "The basics", + "children": { + "what-is-a-container": { + "name": "What is a container?", + "docs_path": "/docs/get-started/docker-concepts/the-basics/what-is-a-container", + "href_path": "#/get-started/docker-concepts/the-basics/what-is-a-container" + }, + "what-is-an-image": { + "name": "What is an image?", + "docs_path": "/docs/get-started/docker-concepts/the-basics/what-is-an-image", + "href_path": "#/get-started/docker-concepts/the-basics/what-is-an-image" + }, + "what-is-a-registry": { + "name": "What is a registry?", + "docs_path": "/docs/get-started/docker-concepts/the-basics/what-is-a-registry", + "href_path": "#/get-started/docker-concepts/the-basics/what-is-a-registry" + }, + "what-is-docker-compose": { + "name": "What is Docker Compose?", + "docs_path": "/docs/get-started/docker-concepts/the-basics/what-is-docker-compose", + "href_path": "#/get-started/docker-concepts/the-basics/what-is-docker-compose" + } + } + }, + "building-images": { + "name": "Building images", + "children": { + "understanding-image-layers": { + "name": "Understanding the image layers", + "docs_path": "/docs/get-started/docker-concepts/building-images/understanding-image-layers", + "href_path": "#/get-started/docker-concepts/building-images/understanding-image-layers" + }, + "writing-a-dockerfile": { + "name": "Writing a Dockerfile", + "docs_path": "/docs/get-started/docker-concepts/building-images/writing-a-dockerfile", + "href_path": "#/get-started/docker-concepts/building-images/writing-a-dockerfile" + }, + "build-tag-and-publish-an-image": { + "name": "Build, tag, and publish an image", + "docs_path": "/docs/get-started/docker-concepts/building-images/build-tag-and-publish-an-image", + "href_path": "#/get-started/docker-concepts/building-images/build-tag-and-publish-an-image" + }, + "using-the-build-cache": { + "name": "Using the build cache", + "docs_path": "/docs/get-started/docker-concepts/building-images/using-the-build-cache", + "href_path": "#/get-started/docker-concepts/building-images/using-the-build-cache" + }, + "multi-stage-builds": { + "name": "Multi-stage builds", + "docs_path": "/docs/get-started/docker-concepts/building-images/multi-stage-builds", + "href_path": "#/get-started/docker-concepts/building-images/multi-stage-builds" + } + } + }, + "running-containers": { + "name": "Running containers", + "children": { + "publishing-ports": { + "name": "Publishing and exposing ports", + "docs_path": "/docs/get-started/docker-concepts/running-containers/publishing-ports", + "href_path": "#/get-started/docker-concepts/running-containers/publishing-ports" + }, + "overriding-container-defaults": { + "name": "Overriding container defaults", + "docs_path": "/docs/get-started/docker-concepts/running-containers/overriding-container-defaults", + "href_path": "#/get-started/docker-concepts/running-containers/overriding-container-defaults" + }, + "persisting-container-data": { + "name": "Persisting container data", + "docs_path": "/docs/get-started/docker-concepts/running-containers/persisting-container-data", + "href_path": "#/get-started/docker-concepts/running-containers/persisting-container-data" + }, + "sharing-local-files": { + "name": "Sharing local files with containers", + "docs_path": "/docs/get-started/docker-concepts/running-containers/sharing-local-files", + "href_path": "#/get-started/docker-concepts/running-containers/sharing-local-files" + }, + "multi-container-applications": { + "name": "Multi-container applications", + "docs_path": "/docs/get-started/docker-concepts/running-containers/multi-container-applications", + "href_path": "#/get-started/docker-concepts/running-containers/multi-container-applications" + } + } + } + } + }, + "workshop": { + "name": "Docker workshop", + "docs_path": "/docs/get-started/workshop", + "href_path": "#/get-started/docker-workshop", + "children": { + "02_our_app": { + "name": "Part 1: Containerize an application", + "docs_path": "/docs/get-started/workshop/02_our_app", + "href_path": "#/get-started/workshop/02_our_app" + }, + "03_updating_app": { + "name": "Part 2: Update the application", + "docs_path": "/docs/get-started/workshop/03_updating_app", + "href_path": "#/get-started/workshop/03_updating_app" + }, + "04_sharing_app": { + "name": "Part 3: Share the application", + "docs_path": "/docs/get-started/workshop/04_sharing_app", + "href_path": "#/get-started/workshop/04_sharing_app" + }, + "05_persisting_data": { + "name": "Part 4: Persist the DB", + "docs_path": "/docs/get-started/workshop/05_persisting_data", + "href_path": "#/get-started/workshop/05_persisting_data" + }, + "06_bind_mounts": { + "name": "Part 5: Use bind mounts", + "docs_path": "/docs/get-started/workshop/06_bind_mounts", + "href_path": "#/get-started/workshop/06_bind_mounts" + }, + "07_multi_container": { + "name": "Part 6: Multi-container apps", + "docs_path": "/docs/get-started/workshop/07_multi_container", + "href_path": "#/get-started/workshop/07_multi_container" + }, + "08_using_compose": { + "name": "Part 7: Use Docker Compose", + "docs_path": "/docs/get-started/workshop/08_using_compose", + "href_path": "#/get-started/workshop/08_using_compose" + }, + "09_image_best": { + "name": "Part 8: Image-building best practices", + "docs_path": "/docs/get-started/workshop/09_image_best", + "href_path": "#/get-started/workshop/09_image_best" + }, + "10_what_next": { + "name": "Part 9: What next?", + "docs_path": "/docs/get-started/workshop/10_what_next", + "href_path": "#/get-started/workshop/10_what_next" + } + } + }, + "resources": { + "name": "Educational resources", + "docs_path": "/docs/get-started/resources", + "href_path": "#/get-started/resources" + } +} diff --git a/src/data/nav/guides.json b/src/data/nav/guides.json new file mode 100644 index 0000000..5e6c232 --- /dev/null +++ b/src/data/nav/guides.json @@ -0,0 +1,28 @@ +{ + "Tags": [ + "Administration", + "AI", + "App development", + "Cloud services", + "Data science", + "Databases", + "Deployment", + "DevOps", + "Distributed systems", + "Frameworks", + "Networking", + "Product demo" + ], + "Languages": [ + "C#", + "C++", + "Go", + "Java", + "JavaScript", + "PHP", + "Python", + "R", + "Ruby", + "Rust" + ] +} From 101a52f68855f3fe7215ead911119f0226d338a3 Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 14:32:11 +0900 Subject: [PATCH 15/20] =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=97=90=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/nav.test.ts | 10 +++++----- tests/table-contents.test.ts | 13 ------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/tests/nav.test.ts b/tests/nav.test.ts index 821223e..e96a661 100644 --- a/tests/nav.test.ts +++ b/tests/nav.test.ts @@ -21,12 +21,12 @@ beforeAll(async () => { diff --git a/tests/table-contents.test.ts b/tests/table-contents.test.ts index 30bfde9..5f08922 100644 --- a/tests/table-contents.test.ts +++ b/tests/table-contents.test.ts @@ -101,19 +101,6 @@ describe('initializeTableContents', () => { // Assert expect(tocTitle?.textContent).toBe('Table of contents'); }); - - it('Table of contents 제목 요소가 올바른 CSS 클래스를 가지는지 확인', async () => { - // Arrange & Act - // contentElement에 이미 testMarkdownContent가 설정됨 - initializeTableContents(); - const tocTitle = tocElement.querySelector('p'); - const expectedClasses = ['text-black', 'font-light', 'text-lg', 'pb-5']; - - // Assert - expectedClasses.forEach((className) => { - expect(tocTitle?.classList.contains(className)).toBe(true); - }); - }); }); describe('헤딩 요소들의 button 생성 확인', () => { From 8a150aac7d57c987c8e3c6a3bc801bff7c408b86 Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 15:57:52 +0900 Subject: [PATCH 16/20] =?UTF-8?q?unique=20id=EA=B0=80=20=EC=95=84=EB=8B=88?= =?UTF-8?q?=EB=AF=80=EB=A1=9C,=20section=5F=5Fwrapper=EB=A5=BC=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=AA=85=EC=9C=BC=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/components/nav-component.ts | 6 +-- src/scripts/nav.ts | 49 ------------------------- 2 files changed, 3 insertions(+), 52 deletions(-) delete mode 100644 src/scripts/nav.ts diff --git a/src/scripts/components/nav-component.ts b/src/scripts/components/nav-component.ts index 6da35c8..5245324 100644 --- a/src/scripts/components/nav-component.ts +++ b/src/scripts/components/nav-component.ts @@ -102,7 +102,7 @@ export default class NavComponent extends HTMLElement { return `
  • -
    +
    ${ item.href_path @@ -154,7 +154,7 @@ export default class NavComponent extends HTMLElement { return `
  • -
    +
    ${ item.href_path @@ -239,7 +239,7 @@ export default class NavComponent extends HTMLElement { private toggleSection(button: HTMLButtonElement): void { const contentWrapperDiv = button.closest( - '#section__wrapper' + '.section__wrapper' ) as HTMLDivElement; const ulElement = contentWrapperDiv?.parentElement?.querySelector( 'ul.ml-3' diff --git a/src/scripts/nav.ts b/src/scripts/nav.ts deleted file mode 100644 index 9f7c5a9..0000000 --- a/src/scripts/nav.ts +++ /dev/null @@ -1,49 +0,0 @@ -function toggleULElementVisibility(button: HTMLButtonElement) { - const contentWrapperDiv = button.closest( - '#section__wrapper' - ) as HTMLDivElement; - const ulElement = contentWrapperDiv?.parentElement?.querySelector( - 'ul.ml-3' - ) as HTMLUListElement; - - if (ulElement) { - ulElement.classList.toggle('hidden'); - } -} - -function toggleSpanVisibility(button: HTMLButtonElement) { - const spans = button.querySelectorAll('span'); - - // button태그의 자식 태그 중 span태그가 있는지 확인 - if (spans.length > 0) { - spans.forEach((span) => { - span.classList.toggle('hidden'); - }); - } else { - // 자식 태그 중 span태그가 없다면, 부모의 형제 요소의 span태그를 토글 - const siblingButton = button.parentElement - ?.nextElementSibling as HTMLButtonElement; - if (siblingButton) { - const siblingSpans = siblingButton.querySelectorAll('span'); - siblingSpans.forEach((span) => { - span.classList.toggle('hidden'); - }); - } - } -} - -export function initializeNavFn() { - const buttons = document.querySelectorAll( - 'div#nav__get-started div > button, div#nav__content li > div > button' - ); - buttons.forEach((button) => { - button.addEventListener('click', () => - // Ul 요소의 Visibility를 결정 - toggleULElementVisibility(button as HTMLButtonElement) - ); - button.addEventListener('click', () => - // button 내 span의 Visibility를 결정 : svg icon 변경 - toggleSpanVisibility(button as HTMLButtonElement) - ); - }); -} From 6bc8a3d34512b52db56ea9bcca073d71e3d208b7 Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 15:58:05 +0900 Subject: [PATCH 17/20] =?UTF-8?q?nav=20=EC=9B=B9=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20=EB=A7=9E=EC=B6=B0=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/nav.test.ts | 217 +++++++++++++++++----------------------------- 1 file changed, 81 insertions(+), 136 deletions(-) diff --git a/tests/nav.test.ts b/tests/nav.test.ts index e96a661..ce95c0f 100644 --- a/tests/nav.test.ts +++ b/tests/nav.test.ts @@ -1,78 +1,17 @@ import { describe, it, expect, beforeEach, beforeAll, vi } from 'vitest'; import { JSDOM } from 'jsdom'; -import { initializeNavFn } from '../src/scripts/nav'; +import NavComponent from '../src/scripts/components/nav-component'; let dom: JSDOM; let document: Document; +let navComponent: NavComponent; beforeAll(async () => { dom = new JSDOM(` - - + `); @@ -82,112 +21,118 @@ beforeAll(async () => { (global as any).window = dom.window; (global as any).document = dom.window.document; (global as any).HTMLElement = dom.window.HTMLElement; - /* eslint-enable @typescript-eslint/no-explicit-any */ + (global as any).customElements = { + define: vi.fn(), + get: vi.fn(), + whenDefined: vi.fn() + }; + + // fetch 모킹 + (global as any).fetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({ + "get-started": { + name: "Get started", + href_path: "#/get-started", + children: { + "introduction": { + name: "Introduction", + href_path: "#/get-started/introduction", + children: { + "get-docker-desktop": { + name: "Get Docker Desktop", + href_path: "#/get-started/introduction/get-docker-desktop" + } + } + } + } + } + }) + }); }); beforeEach(() => { - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - document = (global as any).document; - - // 각 테스트 전에 hidden 클래스 초기화 - const spans = document.querySelectorAll('span'); - spans.forEach((span, index) => { - if (index % 2 === 0) { - span.classList.remove('hidden'); // 짝수 인덱스: 보이게 - } else { - span.classList.add('hidden'); // 홀수 인덱스: 숨기게 - } - }); + document = global.document; - // ul.ml-3 요소의 hidden 클래스 제거 - const ulElement = document.querySelector('ul.ml-3'); - ulElement?.classList.remove('hidden'); + // 새로운 nav-component 인스턴스 생성 + navComponent = new NavComponent(); + document.body.innerHTML = ''; + document.body.appendChild(navComponent); }); -describe('네비게이션 초기화 확인', () => { - it('네비게이션 버튼들이 올바르게 선택되는지 확인', () => { - // Arrange & Act - initializeNavFn(); - const buttons = document.querySelectorAll( - 'div#nav__get-started div > button, div#nav__content li > div > button' - ); - +describe('NavComponent 초기화 확인', () => { + it('NavComponent가 올바르게 렌더링되는지 확인', async () => { + // Act + await navComponent.render(); + // Assert - expect(buttons.length).toBe(4); // 실제 DOM에서 선택되는 버튼 개수에 맞춤 + expect(navComponent.innerHTML).toContain('nav__content'); + expect(navComponent.innerHTML).toContain('Get started'); }); - it('버튼에 이벤트 리스너가 추가되는지 확인', () => { - // Arrange - const button = document.getElementById( - 'test-button-1' - ) as HTMLButtonElement; - const clickSpy = vi.fn(); - button.addEventListener = vi.fn().mockImplementation((event, handler) => { - if (event === 'click') { - clickSpy.mockImplementation(handler); - } - }); - + it('toggle 버튼이 올바르게 렌더링되는지 확인', async () => { // Act - initializeNavFn(); + await navComponent.render(); + const buttons = navComponent.querySelectorAll('button[aria-label="Toggle section"]'); // Assert - expect(button.addEventListener).toHaveBeenCalledWith( - 'click', - expect.any(Function) - ); + expect(buttons.length).toBeGreaterThan(0); }); }); -describe('UL 요소 토글 기능 확인', () => { - it('버튼 클릭 시 UL 요소의 hidden 클래스가 토글되는지 확인', () => { +describe('NavComponent 토글 기능 확인', () => { + it('버튼 클릭 시 UL 요소의 hidden 클래스가 토글되는지 확인', async () => { // Arrange - initializeNavFn(); - const button = document.getElementById( - 'test-button-2' - ) as HTMLButtonElement; - const ulElement = document.querySelector('ul.ml-3') as HTMLUListElement; + await navComponent.render(); + const button = navComponent.querySelector('button[aria-label="Toggle section"]') as HTMLButtonElement; + const ulElement = button?.closest('li')?.querySelector('ul.ml-3') as HTMLUListElement; // Act - button.click(); + if (button) { + button.click(); + } // Assert - expect(ulElement.classList.contains('hidden')).toBe(true); + expect(ulElement?.classList.contains('hidden')).toBe(false); }); }); -describe('Span 요소 토글 기능 확인', () => { - it('버튼 클릭 시 span 요소들의 hidden 클래스가 토글되는지 확인(하위 카테고리가 더 이상 없는 경우)', () => { +describe('NavComponent Span 요소 토글 기능 확인', () => { + it('버튼 클릭 시 span 요소들의 hidden 클래스가 토글되는지 확인', async () => { // Arrange - initializeNavFn(); - const button = document.getElementById( - 'test-button-1' - ) as HTMLButtonElement; - const spans = button.querySelectorAll('span'); + await navComponent.render(); + const button = navComponent.querySelector('button[aria-label="Toggle section"]') as HTMLButtonElement; + const spans = button?.querySelectorAll('span'); + + // 초기 상태 확인 + const initialFirstHidden = spans?.[0].classList.contains('hidden'); + const initialSecondHidden = spans?.[1].classList.contains('hidden'); // Act - button.click(); + if (button) { + button.click(); + } // Assert - expect(spans[0].classList.contains('hidden')).toBe(true); - expect(spans[1].classList.contains('hidden')).toBe(false); + expect(spans?.[0].classList.contains('hidden')).toBe(!initialFirstHidden); + expect(spans?.[1].classList.contains('hidden')).toBe(!initialSecondHidden); }); - it('버튼 클릭 시 형제 요소의 span 요소들의 클래스가 토글되는지 확인(하위 카테고리가 더 있는 경우)', () => { + it('aria-expanded 속성이 올바르게 토글되는지 확인', async () => { // Arrange - initializeNavFn(); - const buttonWithoutSpan = document.getElementById( - 'docker-concepts-button' - ) as HTMLButtonElement; - const siblingButton = buttonWithoutSpan.parentElement - ?.nextElementSibling as HTMLButtonElement; - const siblingSpans = siblingButton?.querySelectorAll('span'); + await navComponent.render(); + const button = navComponent.querySelector('button[aria-label="Toggle section"]') as HTMLButtonElement; + + // 초기 상태 확인 + const initialExpanded = button?.getAttribute('aria-expanded') === 'true'; // Act - buttonWithoutSpan.click(); + if (button) { + button.click(); + } // Assert - expect(siblingSpans?.[0].classList.contains('hidden')).toBe(false); - expect(siblingSpans?.[1].classList.contains('hidden')).toBe(true); + const finalExpanded = button?.getAttribute('aria-expanded') === 'true'; + expect(finalExpanded).toBe(!initialExpanded); }); }); From e81ed8fd5fd89f8d5d5978f84b4eb51d5847116c Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 16:03:38 +0900 Subject: [PATCH 18/20] =?UTF-8?q?ESLint=20=EB=B0=8F=20Prettier=20=EA=B7=9C?= =?UTF-8?q?=EC=B9=99=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/nav.test.ts | 58 +++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/tests/nav.test.ts b/tests/nav.test.ts index ce95c0f..58f0810 100644 --- a/tests/nav.test.ts +++ b/tests/nav.test.ts @@ -24,30 +24,30 @@ beforeAll(async () => { (global as any).customElements = { define: vi.fn(), get: vi.fn(), - whenDefined: vi.fn() + whenDefined: vi.fn(), }; - + // fetch 모킹 (global as any).fetch = vi.fn().mockResolvedValue({ ok: true, json: async () => ({ - "get-started": { - name: "Get started", - href_path: "#/get-started", + 'get-started': { + name: 'Get started', + href_path: '#/get-started', children: { - "introduction": { - name: "Introduction", - href_path: "#/get-started/introduction", + introduction: { + name: 'Introduction', + href_path: '#/get-started/introduction', children: { - "get-docker-desktop": { - name: "Get Docker Desktop", - href_path: "#/get-started/introduction/get-docker-desktop" - } - } - } - } - } - }) + 'get-docker-desktop': { + name: 'Get Docker Desktop', + href_path: '#/get-started/introduction/get-docker-desktop', + }, + }, + }, + }, + }, + }), }); }); @@ -64,7 +64,7 @@ describe('NavComponent 초기화 확인', () => { it('NavComponent가 올바르게 렌더링되는지 확인', async () => { // Act await navComponent.render(); - + // Assert expect(navComponent.innerHTML).toContain('nav__content'); expect(navComponent.innerHTML).toContain('Get started'); @@ -73,7 +73,9 @@ describe('NavComponent 초기화 확인', () => { it('toggle 버튼이 올바르게 렌더링되는지 확인', async () => { // Act await navComponent.render(); - const buttons = navComponent.querySelectorAll('button[aria-label="Toggle section"]'); + const buttons = navComponent.querySelectorAll( + 'button[aria-label="Toggle section"]' + ); // Assert expect(buttons.length).toBeGreaterThan(0); @@ -84,8 +86,12 @@ describe('NavComponent 토글 기능 확인', () => { it('버튼 클릭 시 UL 요소의 hidden 클래스가 토글되는지 확인', async () => { // Arrange await navComponent.render(); - const button = navComponent.querySelector('button[aria-label="Toggle section"]') as HTMLButtonElement; - const ulElement = button?.closest('li')?.querySelector('ul.ml-3') as HTMLUListElement; + const button = navComponent.querySelector( + 'button[aria-label="Toggle section"]' + ) as HTMLButtonElement; + const ulElement = button + ?.closest('li') + ?.querySelector('ul.ml-3') as HTMLUListElement; // Act if (button) { @@ -101,7 +107,9 @@ describe('NavComponent Span 요소 토글 기능 확인', () => { it('버튼 클릭 시 span 요소들의 hidden 클래스가 토글되는지 확인', async () => { // Arrange await navComponent.render(); - const button = navComponent.querySelector('button[aria-label="Toggle section"]') as HTMLButtonElement; + const button = navComponent.querySelector( + 'button[aria-label="Toggle section"]' + ) as HTMLButtonElement; const spans = button?.querySelectorAll('span'); // 초기 상태 확인 @@ -121,8 +129,10 @@ describe('NavComponent Span 요소 토글 기능 확인', () => { it('aria-expanded 속성이 올바르게 토글되는지 확인', async () => { // Arrange await navComponent.render(); - const button = navComponent.querySelector('button[aria-label="Toggle section"]') as HTMLButtonElement; - + const button = navComponent.querySelector( + 'button[aria-label="Toggle section"]' + ) as HTMLButtonElement; + // 초기 상태 확인 const initialExpanded = button?.getAttribute('aria-expanded') === 'true'; From 5fcafb0000171c61aca2f793d1299695faa35ab6 Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 16:05:52 +0900 Subject: [PATCH 19/20] =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EB=86=92=EC=9D=B4=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/components/header-component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/components/header-component.ts b/src/scripts/components/header-component.ts index fbd728e..b8b66ea 100644 --- a/src/scripts/components/header-component.ts +++ b/src/scripts/components/header-component.ts @@ -24,7 +24,7 @@ class HeaderComponent extends HTMLElement { connectedCallback() { this.innerHTML = ` -
    +
    From b1e427d9171811153ef4ce862378c4a50ae6beeb Mon Sep 17 00:00:00 2001 From: ThisTimeNull Date: Sat, 21 Jun 2025 16:14:04 +0900 Subject: [PATCH 20/20] =?UTF-8?q?nav=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=94=94=ED=85=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripts/components/nav-component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/components/nav-component.ts b/src/scripts/components/nav-component.ts index 5245324..9523371 100644 --- a/src/scripts/components/nav-component.ts +++ b/src/scripts/components/nav-component.ts @@ -101,7 +101,7 @@ export default class NavComponent extends HTMLElement { : ''; return ` -
  • +
  • ${ @@ -110,7 +110,7 @@ export default class NavComponent extends HTMLElement { href="${item.href_path}"> ${item.name} ` - : ` + : ` ${item.name} ` } @@ -162,7 +162,7 @@ export default class NavComponent extends HTMLElement { href="${item.href_path}"> ${item.name} ` - : ` + : ` ${item.name} ` }