JWen's Blog

Personal website of JWen 丁文亮的个人网站

Build a Blog with Hugo

2024-07-13


Hugo - getting started

  1. Install Hugo from Homebrew

    brew install hugo
    hugo version
    
  2. Create a site skeleton

    cd ~/Desktop
    hugo new site blog
    
  3. Get a theme met your taste

    cd blog
    git clone https://github.com/yihui/hugo-ivy themes/hugo-ivy
    

    To view the exampleSite (if it exists) of your selected theme

    hugo server --source themes/hugo-ivy/exampleSite --themesDir ../../
    
  4. View and configure the site

    • Copy the configuration file config.yaml (in my case) and the folder content from themes/hugo-ivy/exampleSite to the Hugo site directory (Ref1, Ref2)
      rm hugo.toml
      \cp -r themes/hugo-ivy/exampleSite/config.yaml themes/hugo-ivy/exampleSite/content ./
      
    • Nevigate the address http://localhost:1313/ in your browser after running1
      hugo server -D -F --navigateToChanged
      
    • Play with the config.yaml to see what would happen in your site
  5. Add new pages

    Play with the Markdown files in the content directory

  6. Publish the site using Github

    • Create a new repository in Github with name <user>.github.io (in my case, dwla.github.io)
    • Change the baseurl in config.yaml with value <user>.github.io
    • Create the entire static site in the public directory
      hugo
      
    • Deploy it to Github (in your case, change dwla to <user>)
      cd public
      git init
      git add .
      git commit -m "first commit"
      git branch -M main
      git remote add origin git@github.com:dwla/dwla.github.io.git
      git push -u origin main
      

Useful shortcodes excluded in hugo-ivy

  1. Add “copy to clipboard” buttons to code blocks (Ref1, Ref2)

    • Store this script in themes/hugo-ivy/static/js/clipboard.js
      const svgCopy =
            '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path><path fill-rule="evenodd" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path></svg>';
      const svgCheck =
            '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" fill="rgb(63, 185, 80)" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>';
      
      const addCopyButtons = (clipboard) => {
          // 1. Look for pre > code elements in the DOM
          document.querySelectorAll("pre > code").forEach((codeBlock) => {
              // 2. Create a button that will trigger a copy operation
              const button = document.createElement("button");
              button.className = "clipboard-button";
              button.type = "button";
              button.innerHTML = svgCopy;
              button.addEventListener("click", () => {
                  clipboard.writeText(codeBlock.innerText).then(
                      () => {
                          button.blur();
                          button.innerHTML = svgCheck;
                          setTimeout(() => (button.innerHTML = svgCopy), 2000);
                      },
                      (error) => (button.innerHTML = "Error")
                  );
              });
              // 3. Append the button directly before the pre tag
              const pre = codeBlock.parentNode;
              pre.parentNode.insertBefore(button, pre);
          });
      };
      
      if (navigator && navigator.clipboard) {
          addCopyButtons(navigator.clipboard);
      } else {
          const script = document.createElement("script");
          script.src =
              "https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.7.0/clipboard-polyfill.promise.js";
          script.integrity = "sha256-waClS2re9NUbXRsryKoof+F9qc1gjjIhc2eT7ZbIv94=";
          script.crossOrigin = "anonymous";
          script.onload = () => addCopyButtons(clipboard);
          document.body.appendChild(script);
      }
      
    • Store this script in themes/hugo-ivy/static/css/clipboard.css
      .clipboard-button {
          position: absolute;
          right: 0;
          /* padding: 2px 7px 5px 7px; */
          padding: 2px 5px 2px 5px;
          margin: 5px;
          /* color: #767676; */
          color: white;
          border-color: #767676;
          background-color: #ededed;
          border: 1px solid;
          border-radius: 6px;
          font-size: 0.8em;
          z-index: 1;
          opacity: 0;
          transition: 0.1s;
      }
      .clipboard-button > svg {
          fill: #767676;
      }
      .clipboard-button:hover {
          cursor: pointer;
          border-color: #696969;
          background-color: #e0e0e0;
      }
      .clipboard-button:hover > svg {
          fill: #696969;
      }
      .clipboard-button:focus {
          outline: 0;
      }
      .highlight {
          position: relative;
      }
      .highlight:hover > .clipboard-button {
          opacity: 1;
          transition: 0.2s;
      }
      
    • Add this script to themes/hugo-ivy/layouts/partials/head_custom.html
      {{ if (findRE "<pre" .Content 1) }}
          <link rel="stylesheet" href="/css/clipboard.css">
      {{ end }}
      
    • Add this script to themes/hugo-ivy/layouts/partials/head_custom.html
      {{ if (findRE "<pre" .Content 1) }}
          <script src="/js/clipboard.js"></script>
      {{ end }}
      
  2. Display nice notice (Ref1, Ref2)

    • Store this script in layouts/shortcodes/notice.html

      {{- $noticeType := .Get 0 -}}
      
      {{- $raw := (markdownify .Inner | chomp) -}}
      
      {{- $block := findRE "(?is)^<(?:address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h(?:1|2|3|4|5|6)|header|hgroup|hr|li|main|nav|noscript|ol|output|p|pre|section|table|tfoot|ul|video)\\b" $raw 1 -}}
      {{ $icon := (replace (index $.Site.Data.SVG $noticeType) "icon" "icon notice-icon") }}
      <div class="notice {{ $noticeType }}" {{ if len .Params | eq 2 }} id="{{ .Get 1 }}" {{ end }}>
          <div class="notice-title">{{ $icon | safeHTML }}</div>
          {{- if or $block (not $raw) }}{{ $raw }}{{ else }}<p>{{ $raw }}</p>{{ end -}}
      </div>
      
    • Store this script in static/css/notice.css

      .notice {
          position: relative;
          padding: 1em 1em 1em 2.5em;
          margin: 1em 0;
          /* border-radius: 4px; */
      }
      .notice p:last-child {
          margin: 0;
      }
      .notice .notice-title {
          position: absolute;
          left: 0.8em;
      }
      .notice .notice-title .notice-icon {
          width: 1.2em;
          height: 1.2em;
      }
      .notice.notice-warning {
          background: hsla(0, 65%, 65%, 0.15);
          border-left: 5px solid hsl(0, 65%, 65%);
      }
      .notice.notice-warning .notice-title {
          fill: hsl(0, 65%, 65%);
      }
      .notice.notice-info {
          background: hsla(30, 80%, 70%, 0.15);
          border-left: 5px solid hsl(30, 80%, 70%);
      }
      .notice.notice-info .notice-title {
          fill: hsl(30, 80%, 70%);
      }
      .notice.notice-note {
          background: hsla(200, 65%, 65%, 0.15);
          border-left: 5px solid hsl(200, 65%, 65%);
      }
      .notice.notice-note .notice-title {
          fill: hsl(200, 65%, 65%);
      }
      .notice.notice-tip {
          background: hsla(140, 65%, 65%, 0.15);
          border-left: 5px solid hsl(140, 65%, 65%);
      }
      .notice.notice-tip .notice-title {
          fill: hsl(140, 65%, 65%);
      }
      
    • Store this script in data/SVG.toml

      # Notice Icon
      notice-warning = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 576 512"><path d="M570 440c18 32-5 72-42 72H48c-37 0-60-40-42-72L246 24c19-32 65-32 84 0l240 416zm-282-86a46 46 0 100 92 46 46 0 000-92zm-44-165l8 136c0 6 5 11 12 11h48c7 0 12-5 12-11l8-136c0-7-5-13-12-13h-64c-7 0-12 6-12 13z"/></svg>'
      notice-info = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 512 512"><path d="M256 8a248 248 0 100 496 248 248 0 000-496zm0 110a42 42 0 110 84 42 42 0 010-84zm56 254c0 7-5 12-12 12h-88c-7 0-12-5-12-12v-24c0-7 5-12 12-12h12v-64h-12c-7 0-12-5-12-12v-24c0-7 5-12 12-12h64c7 0 12 5 12 12v100h12c7 0 12 5 12 12v24z"/></svg>'
      notice-note = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 512 512"><path d="M504 256a248 248 0 11-496 0 248 248 0 01496 0zm-248 50a46 46 0 100 92 46 46 0 000-92zm-44-165l8 136c0 6 5 11 12 11h48c7 0 12-5 12-11l8-136c0-7-5-13-12-13h-64c-7 0-12 6-12 13z"/></svg>'
      notice-tip = '<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 512 512"><path d="M504 256a248 248 0 11-496 0 248 248 0 01496 0zM227 387l184-184c7-6 7-16 0-22l-22-23c-7-6-17-6-23 0L216 308l-70-70c-6-6-16-6-23 0l-22 23c-7 6-7 16 0 22l104 104c6 7 16 7 22 0z"/></svg>'
      
    • Example in the .md file

      {{< notice notice-warning >}}
          Perhaps the most valuable result of all education is the ability to make yourself do the thing you have to do, when it ought to be done, whether you like it or not. It is the first lesson that ought to be learned and however early a man's training begins, it is probably the last lesson that he learns thoroughly. --- Thomas Henry Huxley
      {{< /notice >}}
      

      “Perhaps the most valuable result of all education is the ability to make yourself do the thing you have to do, when it ought to be done, whether you like it or not. It is the first lesson that ought to be learned and however early a man’s training begins, it is probably the last lesson that he learns thoroughly.” — Thomas Henry Huxley

      “Perhaps the most valuable result of all education is the ability to make yourself do the thing you have to do, when it ought to be done, whether you like it or not. It is the first lesson that ought to be learned and however early a man’s training begins, it is probably the last lesson that he learns thoroughly.” — Thomas Henry Huxley

      “Perhaps the most valuable result of all education is the ability to make yourself do the thing you have to do, when it ought to be done, whether you like it or not. It is the first lesson that ought to be learned and however early a man’s training begins, it is probably the last lesson that he learns thoroughly.” — Thomas Henry Huxley

      “Perhaps the most valuable result of all education is the ability to make yourself do the thing you have to do, when it ought to be done, whether you like it or not. It is the first lesson that ought to be learned and however early a man’s training begins, it is probably the last lesson that he learns thoroughly.” — Thomas Henry Huxley


  1. Damn, took me 3 hours to find the -F flag (Ref1, Ref2↩︎