📑

oopy에 사이드 메뉴 추가하기

태그
작성일
1/12/2021, 3:27:37 AM
마지막 수정일
2/13/2021, 10:52:00 AM
OOPY에서 속성 값을 html에서 불러올수 있게 추가해주신 덕분에 이제 페이지 yaml 설정으로 페이지별로 보여줄지 여부를 간단하게 선택 가능합니다!!!

TOC가 필요해!

평소 귀차니즘으로 블로그 만들기를 멀리하다 몇일전부터 열심히 블로깅을 시작했습니다.
제 글은 대부분 기술 소개 및 헨즈온을 주로 작성 하다보니 내용이 매우 긴편입니다.
그래서 TOC가 있으면 독자 분들이 쉽고 빠르게 원하는 부분을 바로 읽을수 있어 항상 넣으려고 했습니다.
그런데 노션의 TOC는 위치가 고정 되있어서 읽는 중간에 TOC를 보려면 항상 맨 위로 가야 하는 불편함이 있습니다. 이를 해결하고자 글 읽는 중간에라도 언제든지 TOC를 볼수 있는 사이드 TOC 메뉴를 만들어 보았습니다.
지금 이 페이지 옆에 보면 오른쪽 같은 바를 볼수 있으실 겁니다. 마우스를 오버해보면 아래의 제목들이 TOC로 볼수 있구 클릭 하시면 바로 원하는 위치로 넘어 갈 수 있습니다

어떻게 만들었나요?

제목에 해당하는 css class를 추출 하여 제목 구조와 블록ID(바로가기에 사용)를 추출했습니다. 그리고 DOM을 js에서 직접 한땀한땀 만들고 TailwindCss 로 디자인을 입혔습니다.

어떻게 쓰나요?

블로그에 전체에 적용시

블로그 전체에 적용하신다면 글 하단의 소스코드를 html편집 페이지에서 추가해 주시면 됩니다. (소스코드의 head,body를 각각 넣어주시면 됩니다)
이렇게 적용 하시면 됩니다.

블로그 전체 적용후 특정 페이지에서는 끄고 싶을 경우 (2020-01-18 추가)

페이지 첫 코드블럭에 다음과 같이 추가하시면 됩니다. 참고로 제목 블럭 자체가 없는 페이지에서는 별도 설정을 안해도 사이드 메뉴가 뜨지 않습니다. 이 페이지가 실제로 적용된 페이지 입니다.
side-toc: false
YAML

블로그 전체 적용 없이 특정 페이지에만 적용 하고 싶으실 경우

만약 특정 페이지에만 적용 하시고 싶으시다면 아래 코드 블럭을 적용을 원하시는 페이지 젤 앞에 두시면 됩니다.

소스 코드

<head> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <style> #oopy-sidenav{ z-index: 9999999999999999999; width: 20rem; top: 5rem; left: auto; right: -18rem; transition-duration: 300ms; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } #oopy-sidenav:hover{ z-index: 9999999999999999999; transition-duration: 300ms; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); right: 0rem; bottom: auto; } .oopy-side-link{ display: block; padding-right: .5rem; } .oopy-side-link:hover{ --tw-bg-opacity: 1; background-color: rgba(229, 231, 235, var(--tw-bg-opacity)); } .oopy-side-link:focus{ font-weight: bold; } </style> </head> <body> <div id="oopy-sidenav" class="bg-gray-100 overflow-auto rounded-l-lg fixed"> <div id="oopy-sidenav-content" class="flex"> <div class="flex flex-col"> <div class="px-2 bold"> = </div> </div> <div id="oopy-sidenav-root"></div> </div> </div> <script> function getHeadersData ( items ){ const headersClassNames = [ "notion-header-block", "notion-sub_header-block", "notion-sub_sub_header-block" ]; const headersLevel = { "notion-header-block":1, "notion-sub_header-block":2, "notion-sub_sub_header-block":3 }; const headers = []; items.forEach(function(item){ item.className.split(" ").forEach(function(name){ if (headersClassNames.includes(name)) { const data = { "level":headersLevel[name], "text":item.innerText, "block_id": item.attributes["data-block-id"].value } headers.push(data); } }) }); return headers } function getContents(){ const app = document.getElementsByClassName("notion-page-content"); const contents = app[0].childNodes return contents } function createHeader (data) { const el = document.createElement("a"); const defaultClass = "oopy-side-link " const textNode = document.createTextNode(data.text); el.className = defaultClass + "pl-" + data.level*2; el.href = "#" + data.block_id; el.appendChild(textNode) return el } function createSideRootEL () { const sideNavEL = document.createElement("div"); const sideRootClass = "overflow-auto py-3"; // root 클래스 확장시 활용 sideNavEL.className = sideRootClass; sideNavEL.id = "oopy-sidenav-root"; return sideNavEL } function createSideNavEL (headers){ const root = createSideRootEL(); headers.forEach(function(data){ const el = createHeader(data); root.appendChild(el); }); return root } function replaceSideNav(el){ const parent = document.getElementById("oopy-sidenav-content"); const target = document.getElementById("oopy-sidenav-root"); parent.replaceChild(el,target); } function hideSideNav (){ document.getElementById("oopy-sidenav").className = "hidden" } function ready() { console.log('DOM이 준비되었습니다!'); const contents = getContents(); // console.log(contents); const headers = getHeadersData(contents); // console.log(headers); if (headers.length > 0){ const side = createSideNavEL(headers); replaceSideNav(side); } else { hideSideNav(); } } if (__OOPY__.yaml && __OOPY__.yaml["side-toc"] == false) { hideSideNav(); } else { ready(); } </script> </body>
HTML