• 돌아가기
  • 아래로
  • 위로
  • 목록
  • 댓글
정보

Ghost 블로그에서 목차 만드는법.

달소 달소 328

0

0

 

안녕하세요. 달소입니다.

 

이번글은 Ghost 블로그에서 기본테마 Casper에 목차를 생성하는 방법입니다.

Ghost의 장점은 기본테마가 예쁘고 사용성이 높은것도 한몫하는데 여기에 공식 블로그에서 플러그인은 아니지만 추가 셋팅하는방법을 가이드해줘서 쉽게 적용했습니다.

 

목차 적용 전

휑함

image.png.jpg

목차 적용 후

헤딩값으로 작성된 항목에 대해서 좌측에 목차가 생성됩니다.

image.png.jpg

적용 방법

 

적용을 하기위해서는 사용하는 환경에 따라서 컨테이너나 서버의 content/theme/casper/로 이동한 뒤에 진행되는 작업들입니다.

 

전체 코드를 수정하려면 제 코드를 복붙하시면 됩니다.

vi default.hbs

 

<!DOCTYPE html>
<html lang="{{@site.locale}}"{{#match @custom.color_scheme "Dark"}} class="dark-mode"{{else match @custom.color_scheme "Auto"}} class="auto-color"{{/match}}>
<head>

    {{!-- Basic meta - advanced meta is output with {ghost_head} below --}}
    <title>{{meta_title}}</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="HandheldFriendly" content="True" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    {{!-- Theme assets - use the {asset} helper to reference styles & scripts,
    this will take care of caching and cache-busting automatically --}}
    <link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}" />
    
    {{!-- TOC styles --}}
    <link rel="stylesheet" href="<https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.css>">
    
    <style>
        .gh-toc {
            margin-top: 4vmin; /* Aligns the TOC with the beginning of content */
        }

        @media (min-width: 1300px) {
            .gh-toc {
                position: sticky; /* On larger screens, TOC will stay in the same spot on the page */
                top: 4vmin;
                grid-column: wide-start / main-start; /* Place the TOC to the left of the content */
            }
        }

        .gh-toc > .toc-list {
            position: relative;
            overflow: hidden;
        }

        .toc-list {
            list-style: none;
        }

        .gh-toc .is-active-link::before {
            background-color: var(--ghost-accent-color); /* Defines TOC accent color based on Accent color set in Ghost Admin */
        } 
    </style>

    {{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings,
    it should always be the last tag before the closing head tag --}}
    {{ghost_head}}

</head>
<body class="{{body_class}}{{#match @custom.title_font "=" "Elegant serif"}} has-serif-title{{/match}}{{#match @custom.body_font "=" "Modern sans-serif"}} has-sans-body{{/match}}{{#if @custom.show_publication_cover}} has-cover{{/if}}{{#is "home"}}{{#unless @custom.show_logo_in_navigation}} no-logo{{/unless}}{{/is}}">
<div class="viewport">

    <header id="gh-head" class="gh-head outer">
        <nav class="gh-head-inner inner">

            <div class="gh-head-brand">
                <a class="gh-head-logo{{#unless @site.logo}} no-image{{/unless}}" href="{{@site.url}}">
                    {{#if @site.logo}}
                        <img src="{{@site.logo}}" alt="{{@site.title}}" />
                    {{else}}
                        {{@site.title}}
                    {{/if}}
                </a>
                <a class="gh-burger" role="button">
                    <div class="gh-burger-box">
                        <div class="gh-burger-inner"></div>
                    </div>
                </a>
            </div>
            <div class="gh-head-menu">
                {{navigation}}
            </div>
            <div class="gh-head-actions">
                <div class="gh-social">
                    {{#if @site.facebook}}
                        <a class="gh-social-link gh-social-facebook" href="{{facebook_url @site.facebook}}" title="Facebook" target="_blank" rel="noopener">{{> "icons/facebook"}}</a>
                    {{/if}}
                    {{#if @site.twitter}}
                        <a class="gh-social-link gh-social-twitter" href="{{twitter_url @site.twitter}}" title="Twitter" target="_blank" rel="noopener">{{> "icons/twitter"}}</a>
                    {{/if}}
                </div>
                {{#if @site.members_enabled}}
                    {{#unless @member}}
                        <a class="gh-head-button" href="#/portal/signup" data-portal="signup">Subscribe</a>
                    {{else}}
                        <a class="gh-head-button" href="#/portal/account" data-portal="account">Account</a>
                    {{/unless}}
                {{/if}}
            </div>
        </nav>
    </header>

    <div class="site-content">
        {{!-- All other templates get inserted here, index.hbs, post.hbs, etc --}}
        {{{body}}}
    </div>

    {{!-- The global footer at the very bottom of the screen --}}
    <footer class="site-footer outer">
        <div class="inner">
            <section class="copyright"><a href="{{@site.url}}">{{@site.title}}</a> &copy; {{date format="YYYY"}}</section>
            <nav class="site-footer-nav">
                {{navigation type="secondary"}}
            </nav>
            <div><a href="https://ghost.org/" target="_blank" rel="noopener">Powered by Ghost</a></div>
        </div>
    </footer>

</div>
{{!-- /.viewport --}}

{{!-- Scripts - handle member signups, responsive videos, infinite scroll, floating headers, and galleries --}}
<script
    src="https://code.jquery.com/jquery-3.5.1.min.js"
    integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
    crossorigin="anonymous">
</script>
<script src="{{asset "built/casper.js"}}"></script>
<script>
$(document).ready(function () {
    // Mobile Menu Trigger
    $('.gh-burger').click(function () {
        $('body').toggleClass('gh-head-open');
    });
    // FitVids - Makes video embeds responsive
    $(".gh-content").fitVids();
});
</script>

{{!-- Tocbot script --}}
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.min.js"></script>

{{! Initialize Tocbot after you load the script }}
<script>
    tocbot.init({
        // Where to render the table of contents.
        tocSelector: '.gh-toc',
        // Where to grab the headings to build the table of contents.
        contentSelector: '.gh-content',
        // Which headings to grab inside of the contentSelector element.
        headingSelector: 'h1, h2, h3, h4',
    });
</script>

{{!-- Ghost outputs required functional scripts with this tag - it should always be the last thing before the closing body tag --}}
{{ghost_foot}}

</body>
</html>

 

vi post.hbs

 

{{!< default}}

{{!-- The tag above means: insert everything in this file
into the {body} tag of the default.hbs template --}}

{{#post}}
{{!-- Everything inside the #post block pulls data from the post --}}

<main id="site-main" class="site-main">
<article class="article {{post_class}} {{#match @custom.post_image_style "Full"}}image-full{{else match @custom.post_image_style "=" "Small"}}image-small{{/match}}">

    <header class="article-header gh-canvas">

        <div class="article-tag post-card-tags">
            {{#primary_tag}}
                <span class="post-card-primary-tag">
                    <a href="{{url}}">{{name}}</a>
                </span>
            {{/primary_tag}}
            {{#if featured}}
                <span class="post-card-featured">{{> "icons/fire"}} Featured</span>
            {{/if}}
        </div>

        <h1 class="article-title">{{title}}</h1>

        {{#if custom_excerpt}}
            <p class="article-excerpt">{{custom_excerpt}}</p>
        {{/if}}

        <div class="article-byline">
        <section class="article-byline-content">

            <ul class="author-list">
                {{#foreach authors}}
                <li class="author-list-item">
                    {{#if profile_image}}
                    <a href="{{url}}" class="author-avatar">
                        <img class="author-profile-image" src="{{img_url profile_image size="xs"}}" alt="{{name}}" />
                    </a>
                    {{else}}
                    <a href="{{url}}" class="author-avatar author-profile-image">{{> "icons/avatar"}}</a>
                    {{/if}}
                </li>
                {{/foreach}}
            </ul>

            <div class="article-byline-meta">
                <h4 class="author-name">{{authors}}</h4>
                <div class="byline-meta-content">
                    <time class="byline-meta-date" datetime="{{date format="YYYY-MM-DD"}}">{{date}}</time>
                    {{#if reading_time}}
                        <span class="byline-reading-time"><span class="bull">&bull;</span> {{reading_time}}</span>
                    {{/if}}
                </div>
            </div>

        </section>
        </div>

        {{#match @custom.post_image_style "!=" "Hidden"}}
        {{#if feature_image}}
            <figure class="article-image">
                {{!-- This is a responsive image, it loads different sizes depending on device
                https://medium.freecodecamp.org/a-guide-to-responsive-images-with-ready-to-use-templates-c400bd65c433 --}}
                <img
                    srcset="{{img_url feature_image size="s"}} 300w,
                            {{img_url feature_image size="m"}} 600w,
                            {{img_url feature_image size="l"}} 1000w,
                            {{img_url feature_image size="xl"}} 2000w"
                    sizes="(min-width: 1400px) 1400px, 92vw"
                    src="{{img_url feature_image size="xl"}}"
                    alt="{{#if feature_image_alt}}{{feature_image_alt}}{{else}}{{title}}{{/if}}"
                />
                {{#if feature_image_caption}}
                    <figcaption>{{feature_image_caption}}</figcaption>
                {{/if}}
            </figure>
        {{/if}}
        {{/match}}

    </header>

    <section class="gh-content gh-canvas">
        <div class="gh-toc"></div> {{! The TOC will be inserted here }}
        {{content}}
    </section>

    {{!--
    <section class="article-comments gh-canvas">
        If you want to embed comments, this is a good place to paste your code!
    </section>
    --}}

</article>
</main>

{{!-- A signup call to action is displayed here, unless viewed as a logged-in member --}}
{{#if @site.members_enabled}}
{{#unless @member}}
{{#if access}}
    <section class="footer-cta outer">
        <div class="inner">
            {{#if @custom.email_signup_text}}<h2 class="footer-cta-title">{{@custom.email_signup_text}}</h2>{{/if}}
            <a class="footer-cta-button" href="#/portal" data-portal>
                <div class="footer-cta-input">Enter your email</div>
                <span>Subscribe</span>
            </a>
            {{!-- ^ This looks like a form element, but it's just a link to Portal,
            making the form validation and submission much simpler. --}}
        </div>
    </section>
{{/if}}
{{/unless}}
{{/if}}

{{!-- Read more links, just above the footer --}}
{{#if @custom.show_recent_posts_footer}}
    {{!-- The {#get} helper below fetches some of the latest posts here
    so that people have something else to read when they finish this one.

    This query gets the latest 3 posts on the site, but adds a filter to
    exclude the post we're currently on from being included. --}}
    {{#get "posts" filter="id:-{{id}}" limit="3" as |more_posts|}}

        {{#if more_posts}}
            <aside class="read-more-wrap outer">
                <div class="read-more inner">
                    {{#foreach more_posts}}
                        {{> "post-card"}}
                    {{/foreach}}
                </div>
            </aside>
        {{/if}}

    {{/get}}
{{/if}}

{{/post}}

 

수정후에 컨테이너만 재시작한번 시켜주시면됩니다.

 

워드프레스였으면 플러그인한방이면 됐을텐데.. 소스를 수정해야하긴하지만

공식 지원인점과 깔끔한 UI/속도 부분은 Ghost의 큰 강점이 아닐까 싶습니다.

 

참조 : https://ghost.org/tutorials/adding-table-of-contents/ 

신고공유스크랩
0

댓글 쓰기 권한이 없습니다. 로그인

취소 댓글 등록

신고

"님의 댓글"

이 댓글을 신고하시겠습니까?

댓글 삭제

"님의 댓글"

삭제하시겠습니까?


목록

공유

facebooktwitterpinterestbandkakao story
번호 분류 제목 글쓴이 날짜 조회 추천
질문 적용 방법을 모르겠습니다?? 11 초보나스 2일 전08:05 230 +1
잡담 php가 벌써 8.36까지 나왔습니다. 5 달소 3일 전23:39 198 +2
질문 proxmox ssd 인식이 갑자기 안됩니다 고장인걸까요? 3 kmw_ 5일 전09:37 193 +1
454 정보
image
달소 15분 전08:21 11 0
453 정보
normal
행복구슬 24.04.07.13:38 1061 +5
452 정보
image
DarkAcid 24.03.30.09:32 320 +2
451 정보
image
달소 24.03.28.22:48 178 +1
450 정보
image
Razorbacks 24.03.28.18:06 163 +1
449 정보
image
툭툭이 24.03.28.11:14 863 +16
448 정보
image
서맹 24.03.10.15:34 324 +1
447 정보
normal
서맹 24.03.09.17:09 211 +1
446 정보
image
달소 24.03.09.05:27 59 0
445 정보
image
달소 24.03.08.16:02 200 +2
444 정보
normal
서맹 24.03.08.15:15 178 +1
443 정보
normal
SHISHAMO 24.03.03.16:08 482 +1
442 정보
image
똥쓰똥쓰 24.03.01.13:15 653 +3
441 정보
image
honey720 24.02.28.00:20 239 +6
440 정보
image
권씨아저씨 24.02.24.21:41 203 +1
439 정보
image
콜라 24.02.23.16:30 144 +1
438 정보
normal
very 24.02.23.13:54 155 0
437 정보
normal
KelvinKang 24.02.20.20:35 116 +1
436 정보
image
달소 24.02.19.22:51 291 +1
435 정보
image
빨간물약 24.02.19.13:28 642 +3