[코딩 자율학습 HTML + CSS + 자바스크립트] 1장 Hello, HTML + CSS + 자바스크립트 - 2

| | 조회 243

#HTML기초 #비주얼스튜디오코드 #웹개발 #프로그래밍기초 #코딩튜토리얼 #myip

[주요 목차]

목차1 🌐 HTML 문서 만들기

목차2 💻 개발 환경 설정

목차3 🗂️ 폴더 및 파일 생성

목차4 ✍️ HTML 기본 구조 작성

목차5 🔄 라이브 서버 실행


안녕하세요! 오늘의 블로그 포스트에서는 HTML 문서 만들기 과정과, 비주얼 스튜디오 코드(Visual Studio Code)를 활용한 웹 개발 환경 설정에 대해 알아보겠습니다. 웹 개발을 처음 시작하는 분들에게 유익한 정보가 될 것입니다. 이 튜토리얼을 따라 하시면, HTML 문서를 생성하고, 기본적인 웹 페이지를 테스트하는 방법을 배우실 수 있습니다. 그럼 시작해볼까요?


🌐 HTML 문서 만들기

HTML은 웹 페이지의 뼈대를 구성하는 언어입니다. 첫 번째 단계로, HTML 문서를 만드는 방법을 알아보겠습니다. 비주얼 스튜디오 코드를 열고, 새로운 파일을 생성한 후, 'index.html'이라는 이름으로 저장합니다. 이 파일은 브라우저에서 기본적으로 로드되는 파일이기 때문에, 웹 페이지의 시작 지점이 됩니다. HTML 문서는 <!DOCTYPE html>로 시작하며, 태그 안에 와 를 포함합니다. 에는 메타 정보와 제목이, 에는 실제 콘텐츠가 들어갑니다.

💻 개발 환경 설정

웹 개발을 시작하려면 적절한 개발 환경을 설정해야 합니다. 우리는 비주얼 스튜디오 코드를 사용하여 코딩을 진행할 것입니다. 이 소프트웨어는 다양한 확장 기능을 제공하여 개발을 더욱 효율적으로 만들어 줍니다. 크롬과 같은 브라우저를 사용하여 코드를 실행하고 테스트할 수 있습니다. 익스텐션 마켓플레이스에서 'Live Server'를 설치하여 실시간으로 변경 사항을 확인할 수 있습니다.

🗂️ 폴더 및 파일 생성

프로젝트를 시작할 때는 적절한 폴더 구조를 만드는 것이 중요합니다. 비주얼 스튜디오 코드에서 'Open Folder'를 클릭하여 작업할 폴더를 생성합니다. 이 폴더 안에 'index.html' 파일을 생성하면, 기본적인 프로젝트 구조가 완성됩니다. 폴더를 선택하고, 파일을 추가하면, 프로젝트의 기초가 마련됩니다.

✍️ HTML 기본 구조 작성

HTML 문서의 기본 구조는 매우 간단합니다. 태그 안에 와 가 있으며, 각 섹션에 필요한 내용을 추가합니다. 에는 태그를 사용하여 페이지 제목을 설정하고, <body>에는 실제 웹 페이지에 표시될 요소들을 추가합니다. 비주얼 스튜디오 코드의 자동 완성 기능을 활용하면, 이러한 기본 구조를 빠르게 작성할 수 있습니다.</p> <p><img src="https://idc.myip.co.kr/board/images/2025/01/11/741608ffb1e4fa1467f7127834a80dbc.png" class="mt-10 mb-10" /></p> <h2>🔄 라이브 서버 실행</h2> <p>코드를 작성한 후에는 결과를 확인하는 것이 중요합니다. 'Live Server' 익스텐션을 사용하면, 실시간으로 변경 사항을 웹 브라우저에 반영할 수 있습니다. 비주얼 스튜디오 코드에서 'Go Live' 버튼을 클릭하면, 브라우저가 자동으로 열리고, 변경된 내용을 즉시 확인할 수 있습니다. 이는 개발 속도를 빠르게 하고, 오류를 즉시 수정할 수 있게 도와줍니다.</p> <h2>🌐 공식사이트</h2> <p><a href="https://code.visualstudio.com/">Visual Studio Code 공식 사이트</a></p> <h2>📚 추천자료</h2> <ul> <li><a href="https://developer.mozilla.org/ko/">MDN Web Docs</a></li> <li><a href="https://www.w3schools.com/html/">W3Schools HTML Tutorial</a></li> </ul> <h2>🔗 관련 링크</h2> <ul> <li><a href="https://www.codecademy.com/learn/learn-html">HTML 기초 강좌</a></li> <li><a href="https://www.howtogeek.com/658962/how-to-install-visual-studio-code-on-linux/">비주얼 스튜디오 코드 설치 가이드</a></li> </ul> <h2>❓ FAQ 섹션</h2> <ul> <li><strong>질문</strong>: HTML 문서를 어떻게 저장하나요?</li> <li><strong>답</strong>: 비주얼 스튜디오 코드에서 Ctrl+S를 눌러 저장할 수 있습니다.</li> </ul> </article> </div> </section> <!-- 액션 버튼 섹션: 목록, 글쓰기, 수정, 삭제 --> <footer class="flex flex-wrap justify-end gap-3 px-6 sm:px-10 py-6 border-t border-gray-100"> <div onclick="location.href='list.php?table=tip&category1=language&category2=htmlcss'" class="bg-gray-600 text-white px-6 py-2 rounded-md hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500 cursor-pointer text-sm"> 목록 </div> <div onclick="location.href='write.php?table=tip&category1=language&category2=htmlcss'" class="bg-green-600 text-white px-6 py-2 rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 cursor-pointer text-sm"> 글쓰기 </div> </footer> <!-- 광고 섹션: 한국 서버호스팅 --> <section class="mx-4 sm:mx-8 my-5 p-3 lg:p-4 bg-gradient-to-r from-slate-50 to-blue-50 border border-slate-200 rounded-xl"> <div class="flex items-center justify-between mb-2"> <div class="flex items-center gap-1.5"> <svg class="w-4 h-4 text-blue-600" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"/><rect width="20" height="8" x="2" y="14" rx="2" ry="2"/><line x1="6" x2="6.01" y1="6" y2="6"/><line x1="6" x2="6.01" y1="18" y2="18"/></svg> <span class="text-xs font-semibold text-slate-700">한국 서버호스팅</span> </div> <a href="/product.php?S_content=%EC%84%9C%EB%B2%84%ED%98%B8%EC%8A%A4%ED%8C%85" class="text-xs text-blue-600 hover:text-blue-800 font-medium"> 전체보기 → </a> </div> <div class="grid grid-cols-2 lg:grid-cols-4 gap-2"> <a href="/product/product_detail.php?id=123" class="block bg-white rounded-lg border border-slate-200 overflow-hidden hover:shadow-md hover:border-blue-300 transition-all duration-200 group"> <div class="w-full h-16 sm:h-20 overflow-hidden bg-slate-100"> <img src="/partner/2024/12/15/e3-1240v6.png" alt="Xeon E3-1240 v6 서버" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy"> </div> <div class="p-2"> <div class="flex items-center gap-1 mb-1"> <svg class="w-3 h-3 text-blue-500 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/></svg> <span class="text-[11px] font-bold text-slate-800 truncate">Xeon E3-1240 v6</span> </div> <p class="text-[10px] text-slate-500 leading-tight mb-1 line-clamp-1">4C/8T (4.1GHz) + 16GB + SSD 500GB</p> <div class="text-right"> <span class="text-xs font-bold text-blue-600 group-hover:text-blue-700">80,000원</span> <span class="text-[9px] text-slate-400">/월</span> </div> </div> </a> <a href="/product/product_detail.php?id=102" class="block bg-white rounded-lg border border-slate-200 overflow-hidden hover:shadow-md hover:border-blue-300 transition-all duration-200 group"> <div class="w-full h-16 sm:h-20 overflow-hidden bg-slate-100"> <img src="/partner/2024/12/15/i3_12100-001.png" alt="i3-12100 서버" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy"> </div> <div class="p-2"> <div class="flex items-center gap-1 mb-1"> <svg class="w-3 h-3 text-indigo-500 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/></svg> <span class="text-[11px] font-bold text-slate-800 truncate">i3-12100</span> </div> <p class="text-[10px] text-slate-500 leading-tight mb-1 line-clamp-1">4C/8T (4.3GHz) + GPU + 16GB + NVME 500GB</p> <div class="text-right"> <span class="text-xs font-bold text-blue-600 group-hover:text-blue-700">100,000원</span> <span class="text-[9px] text-slate-400">/월</span> </div> </div> </a> <a href="/product/product_detail.php?id=103" class="block bg-white rounded-lg border border-slate-200 overflow-hidden hover:shadow-md hover:border-blue-300 transition-all duration-200 group"> <div class="w-full h-16 sm:h-20 overflow-hidden bg-slate-100"> <img src="/partner/2024/12/15/i9_12900K-001.png" alt="i9-12900K 서버" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy"> </div> <div class="p-2"> <div class="flex items-center gap-1 mb-1"> <svg class="w-3 h-3 text-violet-500 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/></svg> <span class="text-[11px] font-bold text-slate-800 truncate">i9-12900K</span> </div> <p class="text-[10px] text-slate-500 leading-tight mb-1 line-clamp-1">16C/24T (5.2GHz) + GPU + 32GB + NVME 1TB</p> <div class="text-right"> <span class="text-xs font-bold text-blue-600 group-hover:text-blue-700">200,000원</span> <span class="text-[9px] text-slate-400">/월</span> </div> </div> </a> <a href="/product/product_detail.php?id=105" class="block bg-white rounded-lg border border-slate-200 overflow-hidden hover:shadow-md hover:border-blue-300 transition-all duration-200 group"> <div class="w-full h-16 sm:h-20 overflow-hidden bg-slate-100"> <img src="/partner/document/105/105_img_01.png" alt="RYZEN 9 9950X 서버" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy"> </div> <div class="p-2"> <div class="flex items-center gap-1 mb-1"> <svg class="w-3 h-3 text-red-500 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/></svg> <span class="text-[11px] font-bold text-slate-800 truncate">RYZEN 9 9950X</span> </div> <p class="text-[10px] text-slate-500 leading-tight mb-1 line-clamp-1">16C/32T (5.7GHz) + 32GB + NVME 1TB</p> <div class="text-right"> <span class="text-xs font-bold text-blue-600 group-hover:text-blue-700">300,000원</span> <span class="text-[9px] text-slate-400">/월</span> </div> </div> </a> </div> </section> <!-- 댓글 섹션 --> <section class="mt-6 border-t border-gray-200 pt-8 bg-gray-50 rounded-b-lg"> <h3 class="text-lg font-bold mb-4 px-4">댓글 0</h3> <!-- 댓글 목록 --> <div class="space-y-4 mb-6"> </div> <!-- 댓글 페이징 --> <!-- 댓글 작성 폼 --> <div class="border border-gray-200 rounded-lg p-4"> <textarea id="commentContent" class="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" rows="3" placeholder="댓글을 입력하세요"></textarea> <div class="mt-2 board-attach-zone" data-attach-zone="comment"> <label class="inline-flex items-center gap-2 px-3 py-1.5 bg-white border border-gray-300 rounded-md text-sm text-gray-700 hover:bg-gray-50 cursor-pointer"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg> <span>파일 첨부</span> <input type="file" multiple accept=".jpg,.jpeg,.png,.gif,.webp,.zip,image/jpeg,image/png,image/gif,image/webp,application/zip" class="hidden" data-attach-input> </label> <span class="ml-2 text-xs text-gray-500">jpg/png/gif/webp/zip · 최대 100MB · 10개</span> <div class="mt-2 grid grid-cols-2 sm:grid-cols-3 gap-2" data-attach-preview></div> </div> <div class="mt-2 flex justify-end"> <button onclick="submitComment()" class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">댓글 등록</button> </div> </div> </section> <section class="px-6 sm:px-10 py-8 border-t border-gray-200 board-review-wrap"> <section class="mt-8" data-review-root data-entity-type="board_tip" data-entity-ref="1234" data-lang="ko" data-is-logged-in="0" id="reviews"> <div class="bg-card dark:bg-slate-800 border border-border dark:border-slate-700 rounded-lg p-4 flex flex-wrap items-center justify-between gap-3"> <button type="button" data-action="entity-like" data-liked="0" aria-pressed="false" class="inline-flex items-center gap-2 rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-3 py-2 text-sm font-medium text-foreground dark:text-slate-200 transition-colors hover:bg-rose-50 dark:hover:bg-rose-900/20 hover:text-rose-600 dark:hover:text-rose-400 hover:border-rose-300 dark:hover:border-rose-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-400 "> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z"/></svg> <span>좋아요</span> <span data-entity-like-count class="font-semibold tabular-nums">0</span> </button> <div class="relative"> <button type="button" data-action="share-toggle" aria-haspopup="menu" aria-expanded="false" class="inline-flex items-center gap-2 rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-3 py-2 text-sm font-medium text-foreground dark:text-slate-200 transition-colors hover:bg-primary-50 dark:hover:bg-primary-900/20 hover:text-primary-600 dark:hover:text-primary-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg> <span>공유하기</span> </button> <ul data-share-menu role="menu" class="hidden absolute right-0 mt-2 w-48 rounded-md border border-border dark:border-slate-600 bg-card dark:bg-slate-800 py-1 shadow-lg z-30 text-sm"> <li role="none"><a role="menuitem" data-share="kakaotalk" href="javascript:void(0)" class="flex items-center gap-2 px-3 py-2 hover:bg-muted dark:hover:bg-slate-700"><span class="inline-block w-4 h-4 rounded-sm bg-yellow-400"></span> 카카오톡</a></li> <li role="none"><a role="menuitem" data-share="facebook" href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fmyip.co.kr%2Fboard%2Fread.php%3Fid%3D1234%26table%3Dtip" target="_blank" rel="noopener" class="flex items-center gap-2 px-3 py-2 hover:bg-muted dark:hover:bg-slate-700"><span class="inline-block w-4 h-4 rounded-sm bg-blue-600"></span> 페이스북</a></li> <li role="none"><a role="menuitem" data-share="x" href="https://x.com/intent/tweet?url=https%3A%2F%2Fmyip.co.kr%2Fboard%2Fread.php%3Fid%3D1234%26table%3Dtip&text=%5B%EC%BD%94%EB%94%A9%20%EC%9E%90%EC%9C%A8%ED%95%99%EC%8A%B5%20HTML%20%2B%20CSS%20%2B%20%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%5D%201%EC%9E%A5%20Hello%2C%20HTML%20%2B%20CSS%20%2B%20%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%20-%202%20-%20MyIP%20%EA%B2%8C%EC%8B%9C%ED%8C%90" target="_blank" rel="noopener" class="flex items-center gap-2 px-3 py-2 hover:bg-muted dark:hover:bg-slate-700"><span class="inline-block w-4 h-4 rounded-sm bg-slate-900 dark:bg-white dark:text-slate-900"></span> X (트위터)</a></li> <li role="none"><a role="menuitem" data-share="line" href="https://social-plugins.line.me/lineit/share?url=https%3A%2F%2Fmyip.co.kr%2Fboard%2Fread.php%3Fid%3D1234%26table%3Dtip" target="_blank" rel="noopener" class="flex items-center gap-2 px-3 py-2 hover:bg-muted dark:hover:bg-slate-700"><span class="inline-block w-4 h-4 rounded-sm bg-green-500"></span> LINE</a></li> <li role="none"><a role="menuitem" data-share="telegram" href="https://t.me/share/url?url=https%3A%2F%2Fmyip.co.kr%2Fboard%2Fread.php%3Fid%3D1234%26table%3Dtip&text=%5B%EC%BD%94%EB%94%A9%20%EC%9E%90%EC%9C%A8%ED%95%99%EC%8A%B5%20HTML%20%2B%20CSS%20%2B%20%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%5D%201%EC%9E%A5%20Hello%2C%20HTML%20%2B%20CSS%20%2B%20%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%20-%202%20-%20MyIP%20%EA%B2%8C%EC%8B%9C%ED%8C%90" target="_blank" rel="noopener" class="flex items-center gap-2 px-3 py-2 hover:bg-muted dark:hover:bg-slate-700"><span class="inline-block w-4 h-4 rounded-sm bg-sky-500"></span> 텔레그램</a></li> <li role="none"><a role="menuitem" data-share="email" href="mailto:?subject=%5B%EC%BD%94%EB%94%A9%20%EC%9E%90%EC%9C%A8%ED%95%99%EC%8A%B5%20HTML%20%2B%20CSS%20%2B%20%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%5D%201%EC%9E%A5%20Hello%2C%20HTML%20%2B%20CSS%20%2B%20%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%20-%202%20-%20MyIP%20%EA%B2%8C%EC%8B%9C%ED%8C%90&body=https%3A%2F%2Fmyip.co.kr%2Fboard%2Fread.php%3Fid%3D1234%26table%3Dtip" class="flex items-center gap-2 px-3 py-2 hover:bg-muted dark:hover:bg-slate-700"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg> 이메일</a></li> <li role="none"><button type="button" role="menuitem" data-share="copy_link" class="flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted dark:hover:bg-slate-700"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg> 링크 복사</button></li> </ul> </div> </div> <div class="mt-6 bg-card dark:bg-slate-800 border border-border dark:border-slate-700 rounded-lg p-6 shadow-sm"> <h2 class="flex items-center gap-2 text-xl font-semibold text-foreground dark:text-white mb-5"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-primary-600"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> <span>리뷰</span> </h2> <div class="flex flex-wrap items-start gap-6 md:gap-10"> <div class="flex-shrink-0 text-center md:text-left"> <div class="text-5xl font-bold tabular-nums text-foreground dark:text-white" data-agg-avg>0</div> <div class="mt-1 flex items-center justify-center md:justify-start gap-0.5" data-agg-stars> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-slate-300 dark:text-slate-600"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-slate-300 dark:text-slate-600"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-slate-300 dark:text-slate-600"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-slate-300 dark:text-slate-600"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-slate-300 dark:text-slate-600"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> </div> <div class="mt-2 text-sm text-muted-foreground dark:text-slate-400" data-agg-count> 0건의 리뷰 </div> </div> <div class="flex-1 min-w-0 space-y-1.5 w-full"> <div class="flex items-center gap-3 text-xs"> <span class="w-6 text-right tabular-nums text-slate-500 dark:text-slate-400">5★</span> <div class="flex-1 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="height: 8px;"> <div class="bg-amber-400 rounded-full transition-all" style="height: 8px; width: 0%;"></div> </div> <span class="w-8 text-right tabular-nums text-slate-500 dark:text-slate-400">0</span> </div> <div class="flex items-center gap-3 text-xs"> <span class="w-6 text-right tabular-nums text-slate-500 dark:text-slate-400">4★</span> <div class="flex-1 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="height: 8px;"> <div class="bg-amber-400 rounded-full transition-all" style="height: 8px; width: 0%;"></div> </div> <span class="w-8 text-right tabular-nums text-slate-500 dark:text-slate-400">0</span> </div> <div class="flex items-center gap-3 text-xs"> <span class="w-6 text-right tabular-nums text-slate-500 dark:text-slate-400">3★</span> <div class="flex-1 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="height: 8px;"> <div class="bg-amber-400 rounded-full transition-all" style="height: 8px; width: 0%;"></div> </div> <span class="w-8 text-right tabular-nums text-slate-500 dark:text-slate-400">0</span> </div> <div class="flex items-center gap-3 text-xs"> <span class="w-6 text-right tabular-nums text-slate-500 dark:text-slate-400">2★</span> <div class="flex-1 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="height: 8px;"> <div class="bg-amber-400 rounded-full transition-all" style="height: 8px; width: 0%;"></div> </div> <span class="w-8 text-right tabular-nums text-slate-500 dark:text-slate-400">0</span> </div> <div class="flex items-center gap-3 text-xs"> <span class="w-6 text-right tabular-nums text-slate-500 dark:text-slate-400">1★</span> <div class="flex-1 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="height: 8px;"> <div class="bg-amber-400 rounded-full transition-all" style="height: 8px; width: 0%;"></div> </div> <span class="w-8 text-right tabular-nums text-slate-500 dark:text-slate-400">0</span> </div> </div> </div> <div class="mt-5 pt-4 border-t border-border dark:border-slate-700"> <div class="flex flex-col md:flex-row md:items-start gap-3"> <div class="flex items-center gap-0.5 flex-shrink-0" data-inline-rating role="radiogroup" aria-label="별점"> <button type="button" data-inline-star="1" aria-label="1" class="p-1 text-slate-300 dark:text-slate-600 hover:text-amber-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-300 rounded"><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></button> <button type="button" data-inline-star="2" aria-label="2" class="p-1 text-slate-300 dark:text-slate-600 hover:text-amber-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-300 rounded"><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></button> <button type="button" data-inline-star="3" aria-label="3" class="p-1 text-slate-300 dark:text-slate-600 hover:text-amber-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-300 rounded"><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></button> <button type="button" data-inline-star="4" aria-label="4" class="p-1 text-slate-300 dark:text-slate-600 hover:text-amber-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-300 rounded"><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></button> <button type="button" data-inline-star="5" aria-label="5" class="p-1 text-slate-300 dark:text-slate-600 hover:text-amber-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-300 rounded"><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></button> <input type="hidden" data-inline-rating-input value="0"> </div> <textarea data-inline-body rows="2" maxlength="5000" placeholder="경험을 자세히 적어주세요 (10자 이상)" readonly aria-readonly="true" class="flex-1 min-w-0 rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-3 py-2 text-sm text-foreground dark:text-slate-200 placeholder:text-slate-400 dark:placeholder:text-slate-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400 resize-y cursor-pointer"></textarea> <button type="button" data-action="inline-submit" class="inline-flex items-center justify-center gap-1.5 rounded-md bg-primary-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-primary-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400 flex-shrink-0 md:self-stretch"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 1 1 3 3L7 19l-4 1 1-4Z"/></svg> <span>리뷰 작성하기</span> </button> </div> <div class="mt-2 flex items-center justify-between gap-2 text-xs"> <span data-inline-error class="hidden text-rose-600 dark:text-rose-400"></span> <span class="ml-auto text-muted-foreground dark:text-slate-400 tabular-nums"><span data-inline-counter>0</span>/5000</span> </div> </div> </div> <div data-login-modal role="dialog" aria-modal="true" aria-labelledby="login-modal-title" class="hidden fixed inset-0 z-50 items-center justify-center bg-black/50 p-4"> <div class="relative w-full max-w-sm bg-card dark:bg-slate-800 border border-border dark:border-slate-700 rounded-lg p-6 shadow-xl"> <button type="button" data-action="cancel-login" class="absolute top-3 right-3 inline-flex items-center justify-center w-8 h-8 rounded-md text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400" aria-label="닫기"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> </button> <h3 id="login-modal-title" class="text-lg font-semibold text-foreground dark:text-white mb-1 text-center">리뷰를 작성하려면 로그인이 필요합니다.</h3> <p class="text-sm text-muted-foreground dark:text-slate-400 mb-5 text-center">Google 계정으로 로그인하면 바로 리뷰를 남길 수 있습니다.</p> <div id="review-gsi-button" data-gsi-button-slot class="flex justify-center min-h-[44px]"></div> <p class="mt-4 text-xs text-center text-muted-foreground dark:text-slate-400"> <a href="/index.php?/login&return=https%3A%2F%2Fmyip.co.kr%2Fboard%2Fread.php%3Fid%3D1234%26table%3Dtip#reviews" class="text-primary-600 dark:text-primary-400 hover:underline">다른 방법으로 로그인</a> </p> </div> </div> <div class="mt-6 flex flex-wrap items-center gap-3 text-sm"> <label class="flex items-center gap-2"> <span class="text-muted-foreground dark:text-slate-400">정렬</span> <select data-sort class="rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400"> <option value="helpful">도움순</option> <option value="recent">최신순</option> <option value="rating_desc">높은 별점순</option> <option value="rating_asc">낮은 별점순</option> </select> </label> <label class="flex items-center gap-2"> <span class="text-muted-foreground dark:text-slate-400">언어</span> <select data-lang-filter class="rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-2 py-1.5 text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400"> <option value="">전체</option> <option value="ko">한국어</option> <option value="en">English</option> <option value="ja">日本語</option> <option value="zh">中文</option> <option value="es">Español</option> <option value="pt">Português</option> <option value="ru">Русский</option> <option value="vi">Tiếng Việt</option> <option value="id">Indonesia</option> <option value="tr">Türkçe</option> <option value="hi">हिन्दी</option> <option value="ar">العربية</option> </select> </label> </div> <div data-review-list class="mt-4 space-y-3"> <div class="bg-card dark:bg-slate-800 border border-dashed border-border dark:border-slate-600 rounded-lg p-8 text-center text-sm text-muted-foreground dark:text-slate-400"> 아직 작성된 리뷰가 없습니다. 첫 리뷰를 남겨주세요! </div> </div> <nav data-pager aria-label="reviews pagination" class="mt-6 flex flex-wrap items-center justify-center gap-1 text-sm"></nav> <div data-report-modal role="dialog" aria-modal="true" class="hidden fixed inset-0 z-50 items-center justify-center bg-black/50 p-4"> <div class="w-full max-w-md bg-card dark:bg-slate-800 border border-border dark:border-slate-700 rounded-lg p-6 shadow-xl"> <h3 class="text-lg font-semibold mb-4">리뷰 신고</h3> <label class="block text-sm font-medium mb-2">신고 사유</label> <select data-report-reason class="w-full mb-3 rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-3 py-2 text-sm"> <option value="spam">스팸/광고</option> <option value="offensive">욕설/혐오 표현</option> <option value="misleading">허위/오해 소지</option> <option value="self_promo">자기 홍보</option> <option value="copyright">저작권 침해</option> <option value="other">기타</option> </select> <textarea data-report-text rows="3" maxlength="2000" placeholder="추가 설명 (선택)" class="w-full mb-3 rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-3 py-2 text-sm"></textarea> <div class="flex items-center justify-end gap-2"> <button type="button" data-action="cancel-report" class="inline-flex items-center rounded-md border border-border dark:border-slate-600 bg-background dark:bg-slate-900 px-3 py-2 text-sm">취소</button> <button type="button" data-action="submit-report" class="inline-flex items-center rounded-md bg-rose-600 px-4 py-2 text-sm font-medium text-white hover:bg-rose-700">신고하기</button> </div> </div> </div> </section> </section> <style> /* 상단 헤더의 좋아요/공유 버튼과 중복 — 리뷰 모듈의 첫 번째 div(좋아요+공유 바) 숨김 */ .board-review-wrap [data-review-root] > div:first-of-type { display: none !important; } </style> </article> </main> </div> <!-- ========== END MAIN CONTENT ========== --> <!-- JavaScript for toggle menu --> <script> function toggleMenu(menuId) { const menu = document.getElementById(menuId); const icon = document.getElementById(menuId + 'Icon'); menu.classList.toggle('hidden'); icon.classList.toggle('rotate-180'); } // 좋아요 버튼 처리 함수 async function handleLike() { try { const response = await fetch(`read.php?id=1234&table=tip&action=like`, { method: 'GET' }); const data = await response.json(); if (data.success) { // 좋아요 버튼 상태 업데이트 const likeButton = document.getElementById('likeButton'); const likeCount = document.getElementById('likeCount'); // 버튼 스타일 변경 likeButton.classList.add('bg-pink-100', 'text-pink-600'); likeButton.classList.remove('bg-gray-100', 'hover:bg-gray-200'); // 아이콘 색상 변경 likeButton.querySelector('svg').classList.add('text-pink-600'); likeButton.querySelector('svg').classList.remove('text-gray-600'); // 카운트 텍스트 색상 변경 likeCount.classList.add('text-pink-600'); likeCount.classList.remove('text-gray-600'); // 카운트 업데이트 likeCount.textContent = data.likes; // 버튼 비활성화 likeButton.disabled = true; } else { alert(data.message || '이미 좋아요를 누르셨습니다.'); } } catch (error) { console.error('Error:', error); alert('좋아요 처리 중 오류가 발생했습니다.'); } } function showDeleteModal() { document.getElementById('deleteModal').classList.remove('hidden'); } function hideDeleteModal() { document.getElementById('deleteModal').classList.add('hidden'); } function confirmDelete() { window.location.href = `edit.php?mode=delete&id=1234&table=tip`; } // 모달 외부 클릭 시 닫기 document.addEventListener('click', function(event) { const modal = document.getElementById('deleteModal'); if (event.target === modal) { hideDeleteModal(); } }); // ───────────────────────────────────────────── // 댓글 / 답글 / 삭제 // - write.php 가 mode=comment | reply | delete_comment 처리 // - CSRF: Referer/Origin 검증 (same-origin fetch 면 자동 통과) // ───────────────────────────────────────────── const BOARD_POST_ID = 1234; const BOARD_TABLE = 'tip'; const BOARD_IS_LOGGED_IN = false; // 리뷰 모듈이 제공하는 Google Login 모달을 재사용 (window.wimShowLoginModal) // 모달 로드 전이거나 모듈 미포함 시에는 일반 로그인 페이지로 fallback. function _board_show_login_gate() { if (typeof window.wimShowLoginModal === 'function') { window.wimShowLoginModal(); return true; } return false; } function _board_require_login() { if (BOARD_IS_LOGGED_IN) return true; if (!_board_show_login_gate()) { alert('로그인이 필요합니다.'); window.location.href = '/index.php?/clientarea/'; } return false; } // 비로그인 시 댓글/답글 textarea 클릭 → 로그인 모달 (리뷰 textarea 와 동일 UX) (function attachCommentLoginGate() { if (BOARD_IS_LOGGED_IN) return; const gate = function (ta) { if (!ta) return; ta.setAttribute('readonly', ''); ta.setAttribute('aria-readonly', 'true'); ta.classList.add('cursor-pointer'); const openModal = function (e) { if (BOARD_IS_LOGGED_IN) return; e.preventDefault(); ta.blur(); if (!_board_show_login_gate()) { alert('로그인이 필요합니다.'); window.location.href = '/index.php?/clientarea/'; } }; ta.addEventListener('focus', openModal); ta.addEventListener('mousedown', openModal); ta.addEventListener('touchstart',openModal, { passive: false }); }; document.addEventListener('DOMContentLoaded', function () { gate(document.getElementById('commentContent')); // 답글 textarea — id 패턴 replyContent_<pid> document.querySelectorAll('textarea[id^="replyContent_"]').forEach(gate); }); })(); // ───────────────────────────────────────────── // ZIP 다운로드 게이트 — 비로그인 시 로그인 모달, 로그인 시 정상 다운로드 function boardZipDownload(ev, anchor) { if (BOARD_IS_LOGGED_IN) return true; // 정상 진행 ev.preventDefault(); if (typeof window.wimShowLoginModal === 'function') { window.wimShowLoginModal(); } else { alert('ZIP 첨부 파일은 로그인 사용자만 다운로드 가능합니다.'); window.location.href = '/index.php?/clientarea/'; } return false; } // ───────────────────────────────────────────── // 댓글/답글 첨부 파일 — 즉시 업로드 + 미리보기 + 토큰 회수 // - input[type=file] change → /board/comment_upload.php 로 업로드 // - 응답의 url 을 zone 의 hidden 토큰 목록에 추가 // - 댓글 등록 시 attachments[] 로 함께 전송 // ───────────────────────────────────────────── const BOARD_ATTACH_LIMIT = 10; const BOARD_ATTACH_MAX_BYTES = 100 * 1024 * 1024; const BOARD_ATTACH_ALLOWED_EXT = ['jpg','jpeg','png','gif','webp','zip']; function _boardAttachState(zone) { if (!zone._attachState) zone._attachState = { files: [] }; return zone._attachState; } function _boardAttachRenderPreview(zone) { const preview = zone.querySelector('[data-attach-preview]'); const state = _boardAttachState(zone); if (!preview) return; preview.innerHTML = ''; state.files.forEach(function (f, idx) { const item = document.createElement('div'); item.className = 'relative border border-gray-200 rounded-md p-2 bg-white text-xs'; if (f.kind === 'image') { const img = document.createElement('img'); img.src = f.url; img.alt = ''; img.loading = 'lazy'; img.className = 'w-full h-24 object-cover rounded'; item.appendChild(img); } else { item.innerHTML = '<div class="w-full h-24 flex items-center justify-center bg-gray-50 rounded text-gray-500"><span>ZIP</span></div>'; } const meta = document.createElement('div'); meta.className = 'mt-1 text-gray-600 truncate'; meta.title = f.original_name || f.filename; meta.textContent = (f.original_name || f.filename) + ' (' + (f.size/1024/1024).toFixed(2) + ' MB)'; item.appendChild(meta); const rm = document.createElement('button'); rm.type = 'button'; rm.className = 'absolute top-1 right-1 bg-white/90 hover:bg-red-50 text-red-600 border border-red-200 rounded-full w-6 h-6 leading-none text-base'; rm.textContent = '×'; rm.setAttribute('aria-label', '제거'); rm.addEventListener('click', function () { state.files.splice(idx, 1); _boardAttachRenderPreview(zone); }); item.appendChild(rm); preview.appendChild(item); }); } async function _boardAttachUpload(zone, file) { const fd = new FormData(); fd.append('file', file); fd.append('table', BOARD_TABLE); const res = await fetch('/board/comment_upload.php?table=' + encodeURIComponent(BOARD_TABLE), { method: 'POST', body: fd, credentials: 'same-origin' }); let data; try { data = await res.json(); } catch (e) { throw new Error('업로드 응답을 해석할 수 없습니다.'); } if (!res.ok || !data.success) { throw new Error(data && data.message ? data.message : '업로드 실패'); } return data; } function _boardAttachInit() { document.querySelectorAll('.board-attach-zone').forEach(function (zone) { if (zone._attachInited) return; zone._attachInited = true; const input = zone.querySelector('[data-attach-input]'); if (!input) return; input.addEventListener('change', async function (ev) { const state = _boardAttachState(zone); const files = Array.from(ev.target.files || []); for (const f of files) { if (!BOARD_IS_LOGGED_IN) { _board_show_login_gate() || (window.location.href = '/index.php?/clientarea/'); break; } if (state.files.length >= BOARD_ATTACH_LIMIT) { alert('첨부 파일은 최대 ' + BOARD_ATTACH_LIMIT + '개까지 가능합니다.'); break; } const ext = (f.name.split('.').pop() || '').toLowerCase(); if (BOARD_ATTACH_ALLOWED_EXT.indexOf(ext) === -1) { alert('허용되지 않는 파일 형식입니다: ' + f.name); continue; } if (f.size > BOARD_ATTACH_MAX_BYTES) { alert('파일 크기가 100MB를 초과합니다: ' + f.name); continue; } // placeholder 추가 (업로드 중 표시) const placeholder = { url: '', kind: ext === 'zip' ? 'archive' : 'image', size: f.size, original_name: f.name, filename: f.name, uploading: true }; state.files.push(placeholder); _boardAttachRenderPreview(zone); try { const data = await _boardAttachUpload(zone, f); Object.assign(placeholder, { url: data.url, kind: data.kind, filename: data.filename, original_name: data.original_name || f.name, mime: data.mime, size: data.size, uploading: false }); _boardAttachRenderPreview(zone); } catch (err) { const idx = state.files.indexOf(placeholder); if (idx >= 0) state.files.splice(idx, 1); _boardAttachRenderPreview(zone); alert((err && err.message) || '업로드 실패: ' + f.name); } } // 같은 파일 다시 선택 가능하도록 reset ev.target.value = ''; }); }); } document.addEventListener('DOMContentLoaded', _boardAttachInit); function _boardAttachAppendToBody(zone, body) { if (!zone) return; const state = _boardAttachState(zone); state.files.forEach(function (f) { if (f.url && !f.uploading) body.append('attachments[]', f.url); }); } function _boardAttachClear(zone) { if (!zone) return; zone._attachState = { files: [] }; _boardAttachRenderPreview(zone); } function _boardAttachHasUploading(zone) { if (!zone) return false; return _boardAttachState(zone).files.some(function (f) { return f.uploading; }); } async function submitComment() { if (!_board_require_login()) return; const textarea = document.getElementById('commentContent'); const zone = document.querySelector('[data-attach-zone="comment"]'); if (_boardAttachHasUploading(zone)) { alert('첨부 파일 업로드가 진행 중입니다. 잠시만 기다려주세요.'); return; } const content = (textarea.value || '').trim(); const hasAttach = zone && _boardAttachState(zone).files.length > 0; if (content === '' && !hasAttach) { alert('댓글 내용 또는 첨부 파일을 입력해주세요.'); textarea.focus(); return; } const btn = textarea.parentElement.querySelector('button[onclick="submitComment()"]') || document.querySelector('button[onclick="submitComment()"]'); if (btn) btn.disabled = true; try { const body = new URLSearchParams(); body.append('mode', 'comment'); body.append('table', BOARD_TABLE); body.append('parent', String(BOARD_POST_ID)); body.append('content', content); _boardAttachAppendToBody(zone, body); const res = await fetch('write.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, body: body.toString(), credentials: 'same-origin' }); const data = await res.json(); if (data.success) { window.location.reload(); } else { alert(data.message || '댓글 등록에 실패했습니다.'); if (btn) btn.disabled = false; } } catch (e) { console.error('submitComment error:', e); alert('댓글 처리 중 오류가 발생했습니다.'); if (btn) btn.disabled = false; } } function showReplyForm(commentId) { if (!_board_require_login()) return; const form = document.getElementById('replyForm_' + commentId); if (form) form.classList.remove('hidden'); } function hideReplyForm(commentId) { const form = document.getElementById('replyForm_' + commentId); if (form) form.classList.add('hidden'); } async function submitReply(commentId) { if (!_board_require_login()) return; const textarea = document.getElementById('replyContent_' + commentId); if (!textarea) return; const zone = document.querySelector('[data-attach-zone="reply-' + commentId + '"]'); if (_boardAttachHasUploading(zone)) { alert('첨부 파일 업로드가 진행 중입니다. 잠시만 기다려주세요.'); return; } const content = (textarea.value || '').trim(); const hasAttach = zone && _boardAttachState(zone).files.length > 0; if (content === '' && !hasAttach) { alert('답글 내용 또는 첨부 파일을 입력해주세요.'); textarea.focus(); return; } try { const body = new URLSearchParams(); body.append('mode', 'reply'); body.append('table', BOARD_TABLE); body.append('parent', String(BOARD_POST_ID)); body.append('comment_parent', String(commentId)); body.append('content', content); _boardAttachAppendToBody(zone, body); const res = await fetch('write.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, body: body.toString(), credentials: 'same-origin' }); const data = await res.json(); if (data.success) { window.location.reload(); } else { alert(data.message || '답글 등록에 실패했습니다.'); } } catch (e) { console.error('submitReply error:', e); alert('답글 처리 중 오류가 발생했습니다.'); } } async function likeComment(commentId) { if (!_board_require_login()) return; const btn = document.querySelector('button[data-comment-like-id="' + commentId + '"]'); if (!btn || btn.disabled) return; try { const url = 'read.php?action=comment_like' + '&id=' + encodeURIComponent(BOARD_POST_ID) + '&table=' + encodeURIComponent(BOARD_TABLE) + '&comment_id=' + encodeURIComponent(commentId); const res = await fetch(url, { method: 'GET', credentials: 'same-origin' }); const data = await res.json(); if (data.success) { const cnt = btn.querySelector('.comment-like-count'); if (cnt) cnt.textContent = String(data.likes); btn.disabled = true; btn.classList.remove('text-gray-500', 'hover:text-pink-600'); btn.classList.add('text-pink-600'); } else { alert(data.message || '처리에 실패했습니다.'); } } catch (e) { console.error('likeComment error:', e); alert('좋아요 처리 중 오류가 발생했습니다.'); } } async function reportComment(commentId) { if (!_board_require_login()) return; const btn = document.querySelector('button[data-comment-report-id="' + commentId + '"]'); if (!btn || btn.disabled) return; if (!confirm('이 댓글을 신고하시겠습니까?\n(스팸/욕설/허위정보 등 부적절한 댓글)')) return; try { const url = 'read.php?action=comment_report' + '&id=' + encodeURIComponent(BOARD_POST_ID) + '&table=' + encodeURIComponent(BOARD_TABLE) + '&comment_id=' + encodeURIComponent(commentId) + '&reason=other'; const res = await fetch(url, { method: 'GET', credentials: 'same-origin' }); const data = await res.json(); if (data.success) { btn.disabled = true; btn.textContent = '신고됨'; btn.classList.remove('text-gray-500', 'hover:text-red-600'); btn.classList.add('text-gray-400', 'cursor-not-allowed'); if (data.hidden) { alert('신고가 누적되어 댓글이 가려집니다.'); window.location.reload(); } else { alert(data.message || '신고가 접수되었습니다.'); } } else { alert(data.message || '신고 처리에 실패했습니다.'); } } catch (e) { console.error('reportComment error:', e); alert('신고 처리 중 오류가 발생했습니다.'); } } async function deleteComment(commentId) { if (!_board_require_login()) return; if (!confirm('정말 삭제하시겠습니까?')) return; try { const url = 'write.php?mode=delete_comment&id=' + encodeURIComponent(commentId) + '&table=' + encodeURIComponent(BOARD_TABLE); const res = await fetch(url, { method: 'GET', credentials: 'same-origin' }); const data = await res.json(); if (data.success) { window.location.reload(); } else { alert(data.message || '댓글 삭제에 실패했습니다.'); } } catch (e) { console.error('deleteComment error:', e); alert('댓글 삭제 중 오류가 발생했습니다.'); } } </script> <!-- JSON-LD 구조화 데이터: Article --> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"Article","headline":"[코딩 자율학습 HTML + CSS + 자바스크립트] 1장 Hello, HTML + CSS + 자바스크립트 - 2","description":"#HTML기초 #비주얼스튜디오코드 #웹개발 #프로그래밍기초 #코딩튜토리얼 #myip [주요 목차] 목차1 🌐 HTML 문서 만들기 목차2 💻 개발 환경 설정 목차3 🗂️ 폴더 및 파일 생성 목차4 ✍️ HTML 기본 구조 작성 목차5 🔄 라이브 서버 실행 안녕하세요! ","url":"https://myip.co.kr/board/read.php?id=1234\u0026table=tip","datePublished":"2025-01-11T19:49:11+09:00","author":{"@type":"Person","name":"익명"},"publisher":{"@type":"Organization","name":"MyIP IDC","logo":{"@type":"ImageObject","url":"https://myip.co.kr/templates/logo.png"}},"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":9},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0}],"mainEntityOfPage":{"@type":"WebPage","@id":"https://myip.co.kr/board/read.php?id=1234\u0026table=tip"},"image":"https://myip.co.kr/board/files/1234/67824ca70daa6.jpg","articleSection":"개발/프로그래밍","keywords":"HTML/CSS"} </script> <!-- JSON-LD 구조화 데이터: BreadcrumbList --> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"홈","item":"https://myip.co.kr/"},{"@type":"ListItem","position":2,"name":"게시판","item":"https://myip.co.kr/board/list.php?table=tip"},{"@type":"ListItem","position":3,"name":"개발/프로그래밍","item":"https://myip.co.kr/board/list.php?table=tip\u0026category1=language"},{"@type":"ListItem","position":4,"name":"HTML/CSS","item":"https://myip.co.kr/board/list.php?table=tip\u0026category1=language\u0026category2=htmlcss"}]} </script> <!-- JSON-LD 구조화 데이터: VideoObject --> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"VideoObject","name":"[코딩 자율학습 HTML + CSS + 자바스크립트] 1장 Hello, HTML + CSS + 자바스크립트 - 2","description":"#HTML기초 #비주얼스튜디오코드 #웹개발 #프로그래밍기초 #코딩튜토리얼 #myip [주요 목차] 목차1 🌐 HTML 문서 만들기 목차2 💻 개발 환경 설정 목차3 🗂️ 폴더 및 파일 생성 목차4 ✍️ HTML 기본 구조 작성 목차5 🔄 라이브 서버 실행 안녕하세요! ","thumbnailUrl":["https://i.ytimg.com/vi/w9AyFK1zve8/maxresdefault.jpg","https://i.ytimg.com/vi/w9AyFK1zve8/hqdefault.jpg"],"uploadDate":"2025-01-11T19:49:11+09:00","contentUrl":"https://www.youtube.com/watch?v=w9AyFK1zve8","embedUrl":"https://www.youtube.com/embed/w9AyFK1zve8"} </script> <!-- 공유하기 모달 --> <div id="shareModal" class="hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"> <div class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 p-5 border w-96 shadow-lg rounded-md bg-white"> <div class="mt-3"> <h3 class="text-lg font-medium text-gray-900 text-center mb-4">공유하기</h3> <div class="flex flex-col space-y-4"> <!-- 복사 완료 메시지 --> <div id="copyMessage" class="hidden text-center py-2 text-green-600 bg-green-50 rounded-md"> 링크가 복사되었습니다! </div> <!-- 링크 복사 버튼 --> <button onclick="copyLink()" class="flex items-center justify-center space-x-2 px-4 py-3 rounded-md bg-gray-100 hover:bg-gray-200 text-gray-800 transition-colors duration-200"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"/> </svg> <span>링크 복사하기</span> </button> </div> <div class="mt-4"> <button onclick="hideShareModal()" class="w-full px-4 py-2 bg-gray-100 text-gray-800 text-base font-medium rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-400"> 닫기 </button> </div> </div> </div> </div> <script src="https://developers.kakao.com/sdk/js/kakao.js"></script> <script> // 카카오톡 SDK 초기화 Kakao.init('YOUR_KAKAO_APP_KEY'); // 여기에 카카오 앱 키를 넣어주세요 // 공유하기 모달 표시 function showShareModal() { document.getElementById('shareModal').classList.remove('hidden'); } // 공유하기 모달 숨기기 function hideShareModal() { document.getElementById('shareModal').classList.add('hidden'); } // 카카오톡 공유하기 function shareKakao() { Kakao.Link.sendDefault({ objectType: 'feed', content: { title: '[코딩 자율학습 HTML + CSS + 자바스크립트] 1장 Hello, HTML + CSS + 자바스크립트 - 2', description: document.querySelector('.prose').textContent.substring(0, 100) + '...', imageUrl: '/board/files/1234/67824ca70daa6.jpg', link: { mobileWebUrl: window.location.href, webUrl: window.location.href } }, buttons: [ { title: '웹으로 보기', link: { mobileWebUrl: window.location.href, webUrl: window.location.href } } ] }); } // 링크 복사하기 function copyLink() { const dummy = document.createElement('input'); document.body.appendChild(dummy); dummy.value = window.location.href; dummy.select(); document.execCommand('copy'); document.body.removeChild(dummy); // 복사 완료 메시지 표시 const copyMessage = document.getElementById('copyMessage'); copyMessage.classList.remove('hidden'); // 2초 후 메시지 숨기기 setTimeout(() => { copyMessage.classList.add('hidden'); }, 2000); } // 모달 외부 클릭 시 닫기 window.onclick = function(event) { const modal = document.getElementById('shareModal'); if (event.target == modal) { hideShareModal(); } } </script> <script>window.__wimI18n = {"meta_title":"내 아이피 확인 · IP 주소 조회 (IPv4·IPv6 위치·통신사) | MyIP","meta_description":"내 아이피 즉시 확인 — 공인 IP 주소 조회, IP 위치 확인, IPv4·IPv6, ISP/통신사, WHOIS, 컴퓨터 IP 확인 방법(CMD ipconfig)까지 무료. WebRTC 누출 점검·블랙리스트(RBL) 체크 포함.","meta_keywords":"내 아이피, ip 주소 확인, 내 아이피 확인, ip 확인, ip 조회, ip 추적, ip 위치 확인, 공인 ip, 공인 ip 확인, ip 검색, ip 뜻, ip 주소 위치, 컴퓨터 ip 확인, ip 확인 cmd, whois ip 조회, 해외 ip 조회, ipv4, ipv6","image_alt_cta":"내 아이피 확인 — IP 주소 조회·IP 위치 확인이 가능한 MyIP IDC 서버호스팅·게임서버 안내","image_alt_info":"공인 IP와 사설 IP 차이 인포그래픽 — ISP·공유기·사설 IP 가정용 네트워크 구조","service_name":"내 아이피 확인 · IP 주소 조회","service_type":"IP Address Lookup Service","h1":"내 아이피 확인 — 내 IP 주소 즉시 조회","sub":"지금 인터넷에 연결된 내 기기의 공인 IP 주소(IPv4·IPv6), 위치, 통신사(ISP), 호스트명을 1초 만에 확인하세요. 별도 설치 없이 브라우저만으로.","hero_label":"내 공인 IP 주소","copy":"복사","copied":"복사됨!","hostname":"호스트명","proxy_warn":"프록시/VPN 경유로 접속한 것으로 보입니다.","loc_title":"위치 · 네트워크 정보","f_country":"국가","f_region":"지역(시/도)","f_city":"도시","f_postal":"우편번호","f_timezone":"시간대","f_isp":"ISP / 조직","f_asn":"ASN","f_latlng":"위도 / 경도","loc_missing":"※ 일부 위치 정보를 확인할 수 없습니다. (사설망/예약 IP이거나 데이터베이스 미수록)","precise_q":"더 정확한 위치가 필요하신가요?","precise_desc":"위 위치는 IP 기반 추정값입니다. GPS 기반 정밀 위치는 동의가 필요합니다.","precise_btn":"정확한 내 위치 보기","map_disclaimer":"※ GeoIP 기반 대략적 위치이며, 실제 위치와 다를 수 있습니다. 지도 데이터 © OpenStreetMap 기여자.","bi_title":"내 브라우저 · 연결 정보","bi_sub":"웹사이트가 접속만으로 알 수 있는 내 장치 정보입니다.","bi_os":"운영체제","bi_browser":"브라우저","bi_lang":"언어","bi_screen":"화면 해상도","bi_viewport":"브라우저 창","bi_dpr":"픽셀 비율","bi_cores":"CPU 코어","bi_mem":"메모리","bi_tz":"시간대","bi_cookie":"쿠키","bi_dnt":"Do Not Track","bi_touch":"터치 입력","bi_webdriver":"자동화 감지","webrtc_title":"WebRTC 누출 진단","webrtc_sub":"VPN/프록시 사용 시에도 WebRTC가 실제 IP를 노출하는지 검사합니다.","webrtc_checking":"검사 중…","webrtc_leak":"WebRTC를 통해 공인 IP가 노출됩니다. VPN 사용 중이라면 실제 IP가 새고 있을 수 있습니다.","webrtc_clean":"WebRTC로 노출되는 IP가 감지되지 않았습니다. (양호)","webrtc_local":"로컬 IP만 감지되었습니다. 공인 IP 누출은 없습니다.","webrtc_unsupported":"이 브라우저는 WebRTC를 지원하지 않습니다.","webrtc_b_local":"로컬","webrtc_b_public":"공인","lookup_title":"다른 IP / 도메인 조회","lookup_sub":"IP 주소나 도메인을 입력하면 위치·호스트명 정보를 조회합니다.","lookup_ph":"예: 8.8.8.8 또는 example.com","lookup_btn":"조회","lookup_dom":"조회 도메인","lookup_neterr":"네트워크 오류가 발생했습니다.","rbl_title":"메일 블랙리스트(RBL) 체크","rbl_sub":"메일 서버 IP가 주요 스팸 블랙리스트에 등재됐는지 확인합니다. (IPv4)","rbl_ph":"예: 203.0.113.10","rbl_btn":"체크","rbl_listed":"%s개 중 %d개 블랙리스트에 등재되어 있습니다.","rbl_clean":"주요 블랙리스트에 등재되어 있지 않습니다.","rbl_b_listed":"등재됨","rbl_b_error":"조회제한","rbl_b_clean":"정상","geo_unsupported":"이 브라우저는 위치 기능을 지원하지 않습니다.","geo_checking":"위치 확인 중…","geo_result":"정밀 위치","geo_acc":"오차 약","geo_denied":"위치 권한이 거부되었습니다. 브라우저 설정에서 허용해 주세요.","geo_unavail":"현재 위치를 확인할 수 없습니다.","geo_timeout":"위치 확인 시간이 초과되었습니다.","faq_title":"자주 묻는 질문","faq1_q":"내 공인 IP 주소는 어떻게 확인하나요?","faq1_a":"IP 주소 확인 페이지에 접속하면 현재 인터넷에 연결된 기기의 공인 IP 주소를 바로 확인할 수 있습니다. 별도 프로그램을 설치하지 않아도 브라우저에서 접속한 네트워크 기준의 IP 주소가 표시됩니다.","faq2_q":"공인 IP와 사설 IP는 무엇이 다른가요?","faq2_a":"공인 IP는 인터넷에서 내 네트워크를 식별하는 주소이고, 사설 IP는 공유기 내부에서 스마트폰, PC, 태블릿 같은 기기를 구분하는 주소입니다. IP 주소 확인 사이트에서 보이는 주소는 보통 공인 IP입니다.","faq3_q":"IP 주소 확인 사이트에 표시되는 IP가 내 컴퓨터 IP인가요?","faq3_a":"표시되는 IP는 정확히 말하면 내 컴퓨터 자체의 내부 주소가 아니라, 인터넷에 접속할 때 외부에 보이는 공인 IP 주소입니다. 공유기를 사용 중이라면 같은 와이파이에 연결된 기기들이 동일한 공인 IP로 보일 수 있습니다.","faq4_q":"IP 주소로 내 위치를 알 수 있나요?","faq4_a":"IP 주소로 국가, 지역, 통신사 정도는 추정할 수 있지만 집 주소나 정확한 현재 위치까지 알 수 있는 것은 아닙니다. IP 위치 정보는 통신사와 데이터베이스 기준으로 추정되기 때문에 실제 위치와 다를 수 있습니다.","faq5_q":"IP 주소가 계속 바뀌는 이유는 무엇인가요?","faq5_a":"가정용 인터넷이나 모바일 네트워크는 통신사가 동적 IP를 할당하는 경우가 많습니다. 공유기 재부팅, 인터넷 재연결, 모바일 데이터 전환, VPN 사용 등에 따라 표시되는 IP 주소가 달라질 수 있습니다.","faq6_q":"와이파이와 모바일 데이터에서 IP 주소가 다르게 보이는 이유는 무엇인가요?","faq6_a":"와이파이는 집, 회사, 카페 등 해당 네트워크의 인터넷 회선을 통해 접속하고, 모바일 데이터는 이동통신사의 네트워크를 통해 접속합니다. 사용하는 네트워크가 다르기 때문에 외부에 표시되는 공인 IP도 다르게 나타날 수 있습니다.","faq7_q":"VPN을 사용하면 IP 주소 확인 결과가 달라지나요?","faq7_a":"네. VPN을 사용하면 실제 인터넷 회선의 IP 대신 VPN 서버의 IP 주소가 외부에 표시됩니다. 그래서 IP 주소 확인 페이지에서 보이는 국가, 지역, 통신사 정보도 VPN 서버 기준으로 바뀔 수 있습니다.","faq8_q":"IP 주소만으로 개인정보가 유출될 수 있나요?","faq8_a":"IP 주소만으로 이름, 전화번호, 주민등록번호, 정확한 집 주소 같은 개인정보가 바로 노출되는 것은 아닙니다. 다만 IP 주소는 접속 기록 분석, 대략적인 위치 추정, 보안 점검 등에 사용될 수 있으므로 공개 게시판이나 로그 관리에서는 주의하는 것이 좋습니다.","faq9_q":"내 IP 주소를 변경하려면 어떻게 해야 하나요?","faq9_a":"일반적으로 공유기를 재부팅하거나 인터넷 연결을 다시 설정하면 동적 IP 환경에서는 IP가 바뀔 수 있습니다. 모바일에서는 비행기 모드를 켰다가 끄거나 모바일 데이터를 다시 연결하면 IP가 변경될 수 있습니다. 고정 IP를 사용 중이라면 통신사나 네트워크 관리자에게 문의해야 합니다.","faq10_q":"IPv4와 IPv6는 무엇이 다른가요?","faq10_a":"IPv4는 123.123.123.123처럼 숫자 네 묶음으로 된 기존 IP 주소 형식이고, IPv6는 더 많은 기기를 수용하기 위해 만들어진 새로운 주소 체계입니다. IP 주소 확인 페이지에서 IPv4 또는 IPv6가 표시되는 것은 사용 중인 인터넷 환경과 통신사 설정에 따라 달라집니다.","products_title":"추천 서버 상품","products_sub":"합리적인 가격의 서버호스팅·게임서버를 만나보세요.","price_unit":"원","bc_home":"홈","bc_tools":"도구","review_section_title":"리뷰","review_count_label":"{n}건의 리뷰","review_avg_rating":"평균 별점","review_write_btn":"리뷰 작성하기","review_edit_btn":"수정","review_delete_btn":"삭제","review_login_required":"리뷰를 작성하려면 로그인이 필요합니다.","review_form_title":"리뷰 작성","review_form_rating_label":"별점","review_form_title_label":"제목 (선택)","review_form_body_label":"본문","review_form_body_placeholder":"경험을 자세히 적어주세요 (10자 이상)","review_form_submit":"등록","review_form_cancel":"취소","review_form_min_chars":"최소 10자 이상 입력해주세요.","review_form_success":"리뷰가 등록되었습니다.","review_form_error":"등록에 실패했습니다.","review_form_already":"이미 리뷰를 작성하셨습니다.","review_sort_label":"정렬","review_sort_recent":"최신순","review_sort_helpful":"도움순","review_sort_rating_desc":"높은 별점순","review_sort_rating_asc":"낮은 별점순","review_lang_filter":"언어","review_lang_all":"전체","review_helpful_btn":"도움됨","review_report_btn":"신고","review_report_title":"리뷰 신고","review_report_reason":"신고 사유","review_reason_spam":"스팸/광고","review_reason_offensive":"욕설/혐오 표현","review_reason_misleading":"허위/오해 소지","review_reason_self_promo":"자기 홍보","review_reason_copyright":"저작권 침해","review_reason_other":"기타","review_report_text_placeholder":"추가 설명 (선택)","review_report_submit":"신고하기","review_report_success":"신고가 접수되었습니다.","review_load_more":"리뷰 더 보기","review_loading":"불러오는 중…","review_no_reviews":"아직 작성된 리뷰가 없습니다. 첫 리뷰를 남겨주세요!","review_time_just_now":"방금 전","review_time_minutes_ago":"{n}분 전","review_time_hours_ago":"{n}시간 전","review_time_days_ago":"{n}일 전","review_time_months_ago":"{n}달 전","review_time_years_ago":"{n}년 전","review_verified_badge":"인증","review_blinded_notice":"여러 사용자의 신고로 가려진 리뷰입니다.","like_btn":"좋아요","like_count_label":"좋아요 {n}","share_btn":"공유하기","share_kakaotalk":"카카오톡","share_facebook":"페이스북","share_x":"X (트위터)","share_line":"LINE","share_telegram":"텔레그램","share_email":"이메일","share_copy_link":"링크 복사","share_link_copied":"링크가 복사되었습니다.","toc_ip_meaning":"IP 뜻","toc_how_to":"내 아이피 확인","toc_location":"IP 위치 확인","toc_whois":"WHOIS","toc_tracking":"IP 추적","article_eyebrow":"내 아이피 확인 · IP 주소 가이드","article_h2_main":"내 아이피 확인 완벽 가이드","article_h2_sub":"IP 주소 조회·IP 위치 확인·IP 추적의 진실","article_intro":"내 아이피(공인 IP)부터 IPv4·IPv6, 공인 IP·사설 IP 차이, 운영체제별 IP 확인 방법(Windows CMD ipconfig·macOS·Linux), IP 위치 확인·WHOIS IP 조회·IP 추적의 한계까지 한 번에 정리했습니다.","article_meta_reviewed":"최종 검토일","article_meta_author":"작성·검토","article_meta_author_name":"MyIP IDC 기술팀","article_meta_refs":"참고","article_fig_caption":"ISP → 공유기 → 사설 IP 로 이어지는 일반적인 가정용 네트워크 구조 (공인 IP vs 사설 IP)","article_s1_h3":"IP 뜻 — IP 주소란 무엇인가? (IPv4·IPv6, 공인 IP·사설 IP)","article_s1_p1":"\u003Cstrong\u003EIP 주소\u003C/strong\u003E는 \u003Cem\u003E인터넷 프로토콜(Internet Protocol) 주소\u003C/em\u003E의 약자로, 인터넷에 연결된 모든 기기들이 서로를 식별하고 통신하기 위해 사용하는 고유한 숫자입니다. 컴퓨터가 사용하는 \u003Cstrong\u003E전화번호\u003C/strong\u003E라고 생각하면 이해하기 쉽습니다.","article_s1_p2":"IP 주소는 \u003Cstrong\u003EIPv4\u003C/strong\u003E와 \u003Cstrong\u003EIPv6\u003C/strong\u003E 2가지 종류가 있습니다. IPv4는 32비트 숫자로 구성되어 있으며, 예를 들어 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003E192.168.1.1\u003C/code\u003E 과 같은 형식을 가지고 있습니다. 반면에 IPv6는 128비트 숫자로 구성되어 있어 훨씬 더 많은 주소를 제공합니다.","article_s1_p3":"IP 주소는 인터넷 서비스 제공업체(\u003Cabbr title=\"Internet Service Provider\"\u003EISP\u003C/abbr\u003E)로부터 할당받으며, \u003Cstrong\u003E공인 IP\u003C/strong\u003E와 \u003Cstrong\u003E사설 IP\u003C/strong\u003E로 나뉩니다. 공인 IP는 인터넷에 직접 연결된 기기들이 사용하는 주소로, 전 세계적으로 유일합니다. 반면에 사설 IP는 로컬 네트워크 내에서만 유효하며, 보통 공유기를 사용하면 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003E192.168.0.10\u003C/code\u003E 과 같은 IP 주소를 사용하는 방식 입니다.","article_s1_p4":"\u003Cstrong\u003E공유기\u003C/strong\u003E란 ISP 에서 공인 IP(Public IP)를 1개 할당받아서, 가정이나 사무실 내부에 사설 IP 를 사용해서 여러 디바이스가 인터넷을 사용 할 수 있게 해주는 장치 입니다.","article_s2_h3":"내 아이피 확인 방법 — IP 주소 조회·IP 검색 사이트 활용","article_s2_p1":"내 아이피(공인 IP)를 확인하는 방법은 크게 두 가지입니다. 첫째, \u003Cstrong\u003EIP 검색 사이트\u003C/strong\u003E를 이용하면 가장 간단합니다. 둘째, 운영체제의 명령어(\u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-xs\"\u003Eipconfig\u003C/code\u003E, \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-xs\"\u003Eifconfig\u003C/code\u003E, \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-xs\"\u003Eip addr\u003C/code\u003E)로 직접 조회하는 방법이 있습니다.","article_s2_p2":"가장 빠른 방법은 IP 주소 확인 사이트 접속입니다. \u003Ca href=\"https://myip.co.kr/util/what-is-myip/\" class=\"text-primary-600 dark:text-primary-400 font-medium hover:underline\"\u003EMyIP.co.kr 내 아이피 확인\u003C/a\u003E 페이지를 열면, 현재 외부에 노출되는 공인 IP 주소(IPv4·IPv6), 위치(국가·도시), 통신사(ISP·ASN), 호스트명이 한 번에 표시됩니다. 이 방식은 \u003Cstrong\u003EWindows·macOS·Linux·iOS·Android 모든 OS에서 동일\u003C/strong\u003E하게 작동하며, 추가 설치 없이 브라우저만으로 몇 초 만에 결과를 얻을 수 있습니다.","article_s2_p3":"반면 \u003Cstrong\u003E명령 프롬프트(CMD)·터미널\u003C/strong\u003E로 컴퓨터 IP 확인을 하면 \u003Cem\u003E사설 IP\u003C/em\u003E(예: 192.168.x.x)가 함께 표시되어 네트워크 문제 해결에 유용합니다. 아래에서 운영체제별 IP 확인 방법을 자세히 안내합니다.","article_s3_h3":"Windows에서 컴퓨터 IP 확인 — CMD \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-base\"\u003Eipconfig\u003C/code\u003E 명령어","article_s3_p1":"Windows 에서 IP 주소를 확인하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 명령 프롬프트를 사용하는 것입니다. 명령 프롬프트를 열기 위해 시작 메뉴에서 \u003Ckbd class=\"rounded border border-border dark:border-slate-600 bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-xs\"\u003Ecmd\u003C/kbd\u003E 를 입력하고 엔터를 누릅니다. 그런 다음, cmd 명령 창에 아래 명령어를 입력하면 현재 네트워크에 연결된 모든 어댑터의 IP 정보를 확인할 수 있습니다.","article_s3_p2":"이 방법은 매우 유용합니다. 특히, 여러 네트워크 어댑터(예: 이더넷과 Wi-Fi)를 사용하는 경우 각 어댑터에 할당된 \u003Cstrong\u003E사설 IP 주소\u003C/strong\u003E를 쉽게 확인할 수 있습니다. 만약 \u003Cstrong\u003E공인 IP 주소\u003C/strong\u003E가 필요하다면, 앞서 언급한 웹사이트를 통해 확인하는 것이 더 간편합니다.","article_s3_p3":"또한, Windows 10 이상의 버전에서는 \u003Cem\u003E설정\u003C/em\u003E 앱을 통해서도 IP 주소를 확인할 수 있습니다. \u003Cem\u003E설정\u003C/em\u003E 앱을 열고 \u003Cem\u003E네트워크 및 인터넷\u003C/em\u003E 을 선택한 후, \u003Cem\u003E상태\u003C/em\u003E 탭에서 \u003Cem\u003E네트워크 및 공유 센터\u003C/em\u003E 를 클릭합니다. 여기서 사용 중인 네트워크를 클릭하면 IP 주소를 포함한 상세 정보를 볼 수 있습니다. 이 방법은 그래픽 인터페이스를 선호하는 사용자에게 특히 유용합니다.","article_s4_h3":"macOS에서 IP 주소 확인 — 시스템 설정·터미널 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-base\"\u003Eipconfig getifaddr\u003C/code\u003E","article_s4_li1":"상단 메뉴 바에서 \u003Cstrong\u003E애플 아이콘\u003C/strong\u003E 을 클릭하고, \u003Cem\u003E시스템 설정\u003C/em\u003E 을 선택합니다.","article_s4_li2":"설정 창에서 \u003Cem\u003E네트워크\u003C/em\u003E 를 선택합니다. 이곳에서 현재 연결된 네트워크 목록이 표시됩니다.","article_s4_li3":"사용 중인 네트워크를 선택한 후, \u003Cem\u003E고급\u003C/em\u003E 버튼을 클릭합니다. 여기서 IP 주소를 포함한 자세한 네트워크 정보를 확인할 수 있습니다.","article_s4_p_intro":"\u003Cstrong\u003E터미널에서 명령어로 IP 확인하기.\u003C/strong\u003E Wi-Fi 사용 중이면 대부분 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003Een0\u003C/code\u003E 입니다.","article_s4_p_wired":"유선랜을 사용하면","article_s5_h3":"Linux에서 IP 주소 확인 — \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-base\"\u003Eip addr\u003C/code\u003E·\u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-base\"\u003Ehostname -I\u003C/code\u003E","article_s5_p1":"대부분의 리눅스 배포판(Ubuntu, CentOS, Rocky, Debian 등)에서는 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003Eiproute2\u003C/code\u003E 패키지의 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003Eip\u003C/code\u003E 명령으로 IP 주소를 확인합니다. (구버전의 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003Eifconfig\u003C/code\u003E 은 net-tools 가 별도 설치된 경우에만 동작합니다.)","article_s6_h3":"IP 주소로 위치 확인 — IP 위치 확인은 어디까지 가능한가?","article_s6_p1":"\u003Cstrong\u003EIP 주소 위치\u003C/strong\u003E 정보는 IP 대역과 통신사 등록 정보, 그리고 \u003Cabbr title=\"MaxMind GeoLite2 / IP2Location 등\"\u003EGeoIP 데이터베이스\u003C/abbr\u003E를 종합해 추정합니다. 국가·시·도 단위는 보통 정확하지만, \u003Cstrong\u003E구·동·실제 주소\u003C/strong\u003E 단위로 좁히는 것은 일반 사용자에게는 불가능합니다.","article_s6_li1":"\u003Cstrong\u003E국가·시·도 (서울, 부산, 경기 등)\u003C/strong\u003E — GeoIP 정확도 ~99% (국가), ~75% (도시)","article_s6_li2":"\u003Cstrong\u003E통신사(ISP)·ASN\u003C/strong\u003E — KT, SK Broadband, LG U+ 등 회선 사업자 식별","article_s6_li3":"\u003Cstrong\u003E좌표·시간대\u003C/strong\u003E — IP 등록 기준 위·경도(실제 위치와 수 km~수십 km 오차 가능)","article_s6_li4":"\u003Cstrong\u003E회사·기관 IP\u003C/strong\u003E — 일부 기업/대학은 등록 정보가 공개되어 식별 가능","article_s6_p2":"\u003Cstrong\u003E정확한 GPS 위치\u003C/strong\u003E가 필요하면 페이지 상단의 \u003Cem\u003E\"내 정확한 위치 보기\"\u003C/em\u003E 버튼을 사용하세요. 브라우저의 \u003Ccode class=\"rounded bg-muted dark:bg-slate-900 px-1.5 py-0.5 font-mono text-sm\"\u003Enavigator.geolocation\u003C/code\u003E API 로 GPS·Wi-Fi·셀룰러 기반 위치를 제공합니다(사용자 권한 필수).","article_s7_h3":"WHOIS IP 조회·해외 IP 조회 — KISA·RIR 공식 채널","article_s7_p1":"\u003Cstrong\u003EWHOIS IP 조회\u003C/strong\u003E는 IP 대역의 공식 등록자(통신사·기관·국가)를 확인하는 방법입니다. 전 세계 IP 자원은 5개 RIR(Regional Internet Registry)이 관리하며, 각 지역별 WHOIS 서버에 질의합니다.","article_s7_li1":"\u003Cstrong\u003E국내 IP\u003C/strong\u003E — \u003Ca href=\"https://krnic.or.kr/\" target=\"_blank\" rel=\"noopener\" class=\"text-primary-600 dark:text-primary-400 hover:underline\"\u003EKISA KRNIC WHOIS\u003C/a\u003E (한국인터넷진흥원, Kisa IP 조회의 정식 채널)","article_s7_li2":"\u003Cstrong\u003E아시아·태평양\u003C/strong\u003E — \u003Ca href=\"https://wq.apnic.net/\" target=\"_blank\" rel=\"noopener\" class=\"text-primary-600 dark:text-primary-400 hover:underline\"\u003EAPNIC WHOIS\u003C/a\u003E (한·일·중·동남아·호주 등)","article_s7_li3":"\u003Cstrong\u003E북미\u003C/strong\u003E — \u003Ca href=\"https://search.arin.net/rdap/\" target=\"_blank\" rel=\"noopener\" class=\"text-primary-600 dark:text-primary-400 hover:underline\"\u003EARIN WHOIS\u003C/a\u003E (미국·캐나다)","article_s7_li4":"\u003Cstrong\u003E유럽·중동\u003C/strong\u003E — \u003Ca href=\"https://apps.db.ripe.net/db-web-ui/query\" target=\"_blank\" rel=\"noopener\" class=\"text-primary-600 dark:text-primary-400 hover:underline\"\u003ERIPE NCC WHOIS\u003C/a\u003E","article_s7_li5":"\u003Cstrong\u003E중남미\u003C/strong\u003E — \u003Ca href=\"https://rdap.lacnic.net/rdap\" target=\"_blank\" rel=\"noopener\" class=\"text-primary-600 dark:text-primary-400 hover:underline\"\u003ELACNIC RDAP\u003C/a\u003E · \u003Cstrong\u003E아프리카\u003C/strong\u003E — \u003Ca href=\"https://www.afrinic.net/whois\" target=\"_blank\" rel=\"noopener\" class=\"text-primary-600 dark:text-primary-400 hover:underline\"\u003EAFRINIC WHOIS\u003C/a\u003E","article_s7_p2":"이 페이지의 \u003Cstrong\u003E다른 IP 조회\u003C/strong\u003E 섹션에서 IP·도메인을 입력하면 위 채널 정보(국가·통신사·ASN)를 통합한 결과를 즉시 제공합니다. \u003Cstrong\u003E해외 IP 조회\u003C/strong\u003E도 동일한 방식으로 가능합니다.","article_s8_h3":"공인 IP 주소 변경 방법 — 공유기 재부팅·MAC 변경·VPN","article_s8_p1":"IP 주소를 변경해야 하는 상황은 종종 발생합니다. 예를 들어, 네트워크 문제를 해결하거나 특정 웹사이트에 대한 접근 제한을 우회할 때 IP 주소 변경이 필요할 수 있습니다. 저는 개인적으로 게임 서버를 운영하면서 여러 번 IP 주소를 변경해야 했습니다. 그 경험을 바탕으로 IP 주소 변경 방법을 설명드리겠습니다.","article_s8_p2":"먼저, 가장 일반적인 방법은 \u003Cstrong\u003E인터넷 서비스 제공업체(ISP)에게 요청\u003C/strong\u003E하는 것입니다. ISP는 공인 IP 주소를 할당하며, 이를 변경할 수 있는 권한을 가지고 있습니다. 하지만, 이 방법은 시간이 오래 걸릴 수 있으므로 급할 경우에는 다른 방법을 고려해야 합니다. 예를 들어, \u003Cstrong\u003E가정용 라우터의 전원을 껐다가 켜는 방법\u003C/strong\u003E이 있습니다. 이 방법은 종종 새로운 공인 IP 주소를 할당받게 해줍니다. 저도 이 방법으로 몇 번 문제를 해결한 적이 있습니다.","article_s8_li1":"라우터의 전원을 껐다가 켭니다.","article_s8_li2":"IP 주소를 확인하여 변경되었는지 확인합니다.","article_s8_li3":"변경되지 않았다면, 라우터의 \u003Cstrong\u003EMAC 주소\u003C/strong\u003E를 수동으로 변경해보세요. 일부 ISP는 MAC 주소에 따라 IP 주소를 할당하기도 합니다.","article_s8_p3":"또한, \u003Cstrong\u003EVPN\u003C/strong\u003E 을 사용하여 IP 주소를 변경할 수도 있습니다. VPN은 가상 사설망을 통해 다른 지역의 IP 주소를 제공하므로, 프라이버시 보호와 함께 다양한 지역의 콘텐츠에 접근할 수 있습니다.","article_s9_h3":"IP 추적·IP 위치추적의 진실과 오해 — 아이피 정밀 추적은 가능한가?","article_s9_p1":"IP 추적은 흔히 \u003Cem\u003E\"상대의 정확한 집 주소나 신원을 바로 알아낼 수 있다\"\u003C/em\u003E 라고 오해되지만, 실제로는 그렇지 않은 경우가 많습니다. IP 주소는 인터넷에 연결된 장치의 네트워크 정보일 뿐이며, 일반 사용자가 확인할 수 있는 정보는 대개 \u003Cstrong\u003E국가, 지역, 인터넷 서비스 제공업체(ISP)\u003C/strong\u003E 정도에 한정됩니다. 정확한 개인정보는 통신사나 사법기관의 협조 없이는 확인하기 어렵습니다.","article_s9_p2":"또한 \u003Cstrong\u003EVPN, 프록시, 공용 와이파이\u003C/strong\u003E 등을 사용하면 실제 위치와 다른 IP 가 표시될 수 있어 추적 정확도가 크게 떨어집니다.","article_s9_p3":"반대로 \u003Cem\u003E\"IP 추적은 완전히 불가능하다\"\u003C/em\u003E 는 주장도 사실이 아닙니다. 사이버 범죄 수사에서는 접속 기록, 서버 로그, 계정 정보 등을 종합 분석해 사용자를 특정하기도 합니다.","article_s9_p4":"즉, IP 추적은 일부 정보 확인에는 유용하지만, 영화처럼 단 몇 초 만에 모든 신상을 파악하는 수준은 아닙니다."};</script> <script src="/util/what-is-myip/js/review.js?v=20260528glogin"></script></div> <!-- End Page Content --> </div> </main> <!-- Footer --> <footer class="bg-gradient-to-b from-gray-800 to-gray-900 mt-20"> <div class="mx-auto max-w-7xl px-6 pb-8 pt-16 sm:pt-24 lg:px-8 lg:pt-32"> <div class="xl:grid xl:grid-cols-3 xl:gap-8"> <!-- 로고 및 연락처 --> <div class="space-y-8"> <div> <a href="/" class="flex items-center gap-3"> <div class="w-10 h-10 rounded-xl bg-gradient-to-br from-primary-500 to-primary-600 flex items-center justify-center"> <i data-lucide="server" class="w-5 h-5 text-white"></i> </div> <span class="text-xl font-bold text-white">MyIP</span> </a> </div> <div class="space-y-3"> <p class="text-xl font-bold text-white flex items-center gap-2"> <i data-lucide="phone" class="w-5 h-5 text-primary-400"></i> 고객지원센터 032-723-9999 </p> <p class="text-sm text-gray-400">평일 09:00 - 18:00 (주말/공휴일 휴무)</p> </div> <!-- 소셜 미디어 --> <div class="flex gap-x-4"> <a href="https://www.facebook.com/myipidc" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-lg bg-gray-700/50 hover:bg-primary-500/20 ring-1 ring-gray-600 flex items-center justify-center transition-colors group" aria-label="Facebook 페이지로 이동"> <span class="sr-only">Facebook</span> <svg class="h-5 w-5 text-gray-400 group-hover:text-primary-400 transition-colors" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"> <path fill-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clip-rule="evenodd" /> </svg> </a> <a href="https://www.instagram.com/myipidc" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-lg bg-gray-700/50 hover:bg-primary-500/20 ring-1 ring-gray-600 flex items-center justify-center transition-colors group" aria-label="Instagram 페이지로 이동"> <span class="sr-only">Instagram</span> <svg class="h-5 w-5 text-gray-400 group-hover:text-primary-400 transition-colors" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"> <path fill-rule="evenodd" d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z" clip-rule="evenodd" /> </svg> </a> <a href="https://twitter.com/myipidc" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-lg bg-gray-700/50 hover:bg-primary-500/20 ring-1 ring-gray-600 flex items-center justify-center transition-colors group" aria-label="X (트위터) 페이지로 이동"> <span class="sr-only">X</span> <svg class="h-5 w-5 text-gray-400 group-hover:text-primary-400 transition-colors" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"> <path d="M13.6823 10.6218L20.2391 3H18.6854L12.9921 9.61788L8.44486 3H3.2002L10.0765 13.0074L3.2002 21H4.75404L10.7663 14.0113L15.5685 21H20.8131L13.6819 10.6218H13.6823ZM11.5541 13.0956L10.8574 12.0991L5.31391 4.16971H7.70053L12.1742 10.5689L12.8709 11.5655L18.6861 19.8835H16.2995L11.5541 13.096V13.0956Z" /> </svg> </a> <a href="https://github.com/myipidc" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-lg bg-gray-700/50 hover:bg-primary-500/20 ring-1 ring-gray-600 flex items-center justify-center transition-colors group" aria-label="GitHub 페이지로 이동"> <span class="sr-only">GitHub</span> <svg class="h-5 w-5 text-gray-400 group-hover:text-primary-400 transition-colors" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" /> </svg> </a> <a href="https://www.youtube.com/@myipidc" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-lg bg-gray-700/50 hover:bg-primary-500/20 ring-1 ring-gray-600 flex items-center justify-center transition-colors group" aria-label="YouTube 채널로 이동"> <span class="sr-only">YouTube</span> <svg class="h-5 w-5 text-gray-400 group-hover:text-primary-400 transition-colors" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"> <path fill-rule="evenodd" d="M19.812 5.418c.861.23 1.538.907 1.768 1.768C21.998 8.746 22 12 22 12s0 3.255-.418 4.814a2.504 2.504 0 0 1-1.768 1.768c-1.56.419-7.814.419-7.814.419s-6.255 0-7.814-.419a2.505 2.505 0 0 1-1.768-1.768C2 15.255 2 12 2 12s0-3.255.417-4.814a2.507 2.507 0 0 1 1.768-1.768C5.744 5 11.998 5 11.998 5s6.255 0 7.814.418ZM15.194 12 10 15V9l5.194 3Z" clip-rule="evenodd" /> </svg> </a> </div> </div> <!-- 링크 섹션 --> <div class="mt-16 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0"> <div class="md:grid md:grid-cols-2 md:gap-8"> <div> <h3 class="text-sm font-semibold text-white flex items-center gap-2"> <i data-lucide="server" class="w-4 h-4 text-primary-400"></i> <a href="/product.php?S_content=서버호스팅" class="hover:text-primary-400 transition-colors">서버호스팅</a> </h3> <ul role="list" class="mt-6 space-y-4"> <li> <!-- /expert_create.php --> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="user-plus" class="w-4 h-4"></i> 판매자로 등록하기 </a> </li> <li> <!-- /expert_server.php --> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="package-plus" class="w-4 h-4"></i> 판매상품 등록하기 </a> </li> <li> <a href="/game_server_register.php" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="gamepad-2" class="w-4 h-4"></i> 게임서버 홍보하기 </a> </li> <li> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="cloud" class="w-4 h-4"></i> SaaS (Software as a Service) </a> </li> <li> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="settings" class="w-4 h-4"></i> 서버 관리 </a> </li> <li> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="code" class="w-4 h-4"></i> 소프트웨어 개발 </a> </li> </ul> </div> <div class="mt-10 md:mt-0"> <h3 class="text-sm font-semibold text-white flex items-center gap-2"> <i data-lucide="headphones" class="w-4 h-4 text-primary-400"></i> 고객지원 </h3> <ul role="list" class="mt-6 space-y-4"> <li> <a href="/index.php?/tickets/new/" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="message-square-plus" class="w-4 h-4"></i> 1:1 문의 </a> </li> <li> <a href="/index.php?/knowledgebase/" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="book-open" class="w-4 h-4"></i> 지식 데이터베이스 </a> </li> <li> <a href="/index.php?/userapi" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="code-2" class="w-4 h-4"></i> OpenAPI </a> </li> </ul> </div> </div> <div class="md:grid md:grid-cols-2 md:gap-8"> <div> <h3 class="text-sm font-semibold text-white flex items-center gap-2"> <i data-lucide="building-2" class="w-4 h-4 text-primary-400"></i> 회사소개 </h3> <ul role="list" class="mt-6 space-y-4"> <li> <a href="/map.php" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="map-pin" class="w-4 h-4"></i> 오시는길 </a> </li> <li> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="users" class="w-4 h-4"></i> 인재영입 </a> </li> <li> <a href="#" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="handshake" class="w-4 h-4"></i> 투자 및 제휴 </a> </li> </ul> </div> <div class="mt-10 md:mt-0"> <h3 class="text-sm font-semibold text-white flex items-center gap-2"> <i data-lucide="scale" class="w-4 h-4 text-primary-400"></i> 법적고지 </h3> <ul role="list" class="mt-6 space-y-4"> <li> <a href="/idctermsofuse.php" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="file-text" class="w-4 h-4"></i> 이용약관 </a> </li> <li> <a href="/idcprivacypolicy.php" class="text-sm text-gray-300 hover:text-primary-400 transition-colors flex items-center gap-2"> <i data-lucide="shield" class="w-4 h-4"></i> 개인정보처리방침 </a> </li> </ul> </div> </div> </div> </div> <!-- 결제 방식 지원 --> <div class="mt-16 border-t border-gray-700/50 pt-8"> <div class="flex flex-col items-center gap-4 lg:flex-row lg:justify-center lg:gap-6"> <h3 class="text-sm font-semibold text-white flex items-center gap-2 shrink-0"> <i data-lucide="credit-card" class="w-4 h-4 text-primary-400"></i> 결제 방식 지원 : </h3> <div class="flex flex-wrap items-center justify-center gap-3"> <img src="/templates/modernpanel2026/assets/payment/visa.svg" alt="Visa 신용카드 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/mastercard.svg" alt="MasterCard 마스터카드 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/unionpay.PNG" alt="UnionPay 银联 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/paypal.PNG" alt="PayPal 페이팔 글로벌 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/alipay.PNG" alt="Alipay 支付宝 알리페이 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/wechatpay.png" alt="WeChat Pay 微信支付 위챗페이 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/TossPay_Logo_Primary.png" alt="Toss Pay 토스페이 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/NAVER_login_Light_KR_green_icon_H48.png" alt="Naver Pay 네이버페이 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/assets/payment/kakaopay.PNG" alt="Kakao Pay 카카오페이 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> <img src="/templates/modernpanel2026/images/crypto-300x91.png" alt="Crypto 암호화폐 BTC ETH USDT 결제 지원" class="h-[41px] w-auto shrink-0 bg-white rounded-lg p-2 shadow-sm" loading="lazy" decoding="async"> </div> </div> </div> <!-- 하단 정보 --> <div class="mt-12 border-t border-gray-700/50 pt-8"> <div class="space-y-2"> <p class="text-sm text-gray-300">© 2002 - 2026 Piranha Systems, Inc. All rights reserved.</p> <p class="text-xs text-gray-500">주식회사 피란하시스템즈 대표이사 김영곤 / 통신판매업신고번호 : 2016-인천연수구-0264호 / 개인정보관리책임자 : 김안식 | <a href=https://myip.co.kr/>호스팅 제공자: MyIP.co.kr</a></p> <p class="text-xs text-gray-500">사업자등록번호 : 121-81-56339 | <b><a href=https://www.ftc.go.kr/bizCommPop.do?wrkr_no=1218156339 target=_blank>사업자정보확인</a></b> | 인천광역시 연수구 송도동 송도과학로 32, 송도테크노파크 IT센터 S동 25층</p> </div> </div> </div> </footer> <!-- End of Footer --> <!-- Lucide Icons 초기화 및 다크모드 토글 --> <script> document.addEventListener('DOMContentLoaded', function() { // Lucide Icons 초기화 if (typeof lucide !== 'undefined') { lucide.createIcons(); } // 다크모드 토글 기능 - 모든 테마 토글 버튼 선택 const themeToggleBtns = document.querySelectorAll('#theme-toggle-btn, #theme-toggle-btn-logged'); const themeIconsLight = document.querySelectorAll('#theme-icon-light, .theme-icon-light'); const themeIconsDark = document.querySelectorAll('#theme-icon-dark, .theme-icon-dark'); // 현재 테마 상태에 따라 모든 아이콘 업데이트 function updateThemeUI() { const isDark = document.documentElement.classList.contains('dark'); themeIconsLight.forEach(function(icon) { if (isDark) { icon.classList.remove('hidden'); } else { icon.classList.add('hidden'); } }); themeIconsDark.forEach(function(icon) { if (isDark) { icon.classList.add('hidden'); } else { icon.classList.remove('hidden'); } }); } // 테마 토글 함수 function toggleTheme() { const isDark = document.documentElement.classList.contains('dark'); if (isDark) { document.documentElement.classList.remove('dark'); localStorage.setItem('theme', 'light'); } else { document.documentElement.classList.add('dark'); localStorage.setItem('theme', 'dark'); } updateThemeUI(); } // 모든 테마 토글 버튼에 이벤트 리스너 추가 themeToggleBtns.forEach(function(btn) { btn.addEventListener('click', toggleTheme); }); // 초기 UI 상태 설정 updateThemeUI(); }); </script> </div> </body> </html>