快轉到主要內容
  1. 全部文章/

Hugo Blowfish 主題|程式碼區塊樣式與折疊

·2140 字·5 分鐘
目錄
Hugo Blowfish 主題客製化 - 本文屬於一個選集。
§ 3: 本文

前言
#

這個程式碼區塊是模仿 macOS 的視窗外觀(左上角的紅黃綠三個點),首先我參考了 Blog|自定義Hugo Blowfish主題 這篇文章,該作者是參考另一篇文章 Hugo Stack 主题装修笔记 Part 3 去修改,而這篇的作者則是從 hugo stack 主题美化 這篇文章發現的,原始的代碼來自於 linsnow.cnStack主题的自定义 (但這篇文章似乎進不去了),總之在文章開始前先感謝這4位作者的分享,讀者可以先去閱讀這幾篇文章。

我在上述的基礎上做了一點小更改,具體的外觀請見本文中的程式碼區塊,另外我在某個部落格看到折疊的樣式,忘記是哪個主題了,它預設只顯示上半部的內容,高度若是超過則需要點擊展開,我蠻喜歡的,於是請 Perplexity 幫我重現了這個樣式。

macOS 視窗樣式
#

編輯/assets/css路徑下的custom.css,添加:

/* 程式碼區塊容器樣式 */
.highlight {
  max-width: 100%;
  position: relative;
  border-radius: 10px;
  margin-left: -5px;
  margin-right: -10px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

/* 添加 macOS 風格的標題欄 */
.highlight::before {
  content: '';
  height: 30px;
  width: 100%;
  background-color: rgba(var(--color-neutral-50));
  display: block;
  position: relative;
}
    
/* 深色模式下的标题栏样式 */
.dark .highlight::before {
  background-color: rgba(var(--color-neutral-700));
}
/* 添加控制按钮 */
.highlight::after {
  content: '';
  position: absolute;
  top: 9px;
  left: 13px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background-color: #ff5f56;
  box-shadow: 20px 0 0 #ffbd2e, 40px 0 0 #27c93f;
  z-index: 1;
}
  
/* 程式碼内容區塊樣式 */
.highlight pre {
  margin: 0;
  padding: 1.5rem;
  width: auto;
}
.prose .chroma {
  border-radius: 0;
}

折疊功能
#

這邊提供兩個樣式,如果你不使用上面的 macOS 樣式的話,直接使用第一種,如果你也使用我上面提供的 macOS 視窗樣式,請使用第二種

不使用 macOS 視窗樣式時
#

編輯 custom.css
#

編輯/assets/css下的custom.css

/* 程式碼區塊容器 */
.highlight {
  position: relative;
  margin: 1.5rem 0;
}

/* 折疊狀態 */
.highlight.collapsible {
  max-height: 400px;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

/* 展開狀態 */
.highlight.expanded {
  max-height: none;
}

/* 漸層遮罩 */
.highlight.collapsible::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 80px;
  background: linear-gradient(to bottom, transparent, var(--color-background));
  pointer-events: none;
}

.highlight.expanded::after {
  display: none;
}

/* 展開按鈕 */
.code-expand-btn {
  display: block;
  width: 100%;
  padding: 0.5rem;
  margin-top: 0.5rem;
  background: var(--color-secondary);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-base);
  cursor: pointer;
  font-size: 0.875rem;
  text-align: center;
  transition: background 0.2s;
}

.code-expand-btn:hover {
  background: var(--color-secondary-hover);
}

新增 collapsible-code.js
#

/static/js下創建collapsible-code.js

document.addEventListener('DOMContentLoaded', function() {
  const codeBlocks = document.querySelectorAll('.highlight');
  
  codeBlocks.forEach(function(block) {
    // 檢查高度是否超過 400px
    if (block.scrollHeight > 400) {
      // 加上折疊樣式
      block.classList.add('collapsible');
      
      // 創建展開按鈕
      const btn = document.createElement('button');
      btn.className = 'code-expand-btn';
      btn.innerHTML = '<span class="expand-text">展開完整程式碼 ▼</span><span class="collapse-text" style="display:none;">折疊程式碼 ▲</span>';
      
      // 插入按鈕到程式碼區塊後面
      block.parentNode.insertBefore(btn, block.nextSibling);
      
      // 按鈕點擊事件
      btn.addEventListener('click', function() {
        const expandText = btn.querySelector('.expand-text');
        const collapseText = btn.querySelector('.collapse-text');
        
        if (block.classList.contains('collapsible')) {
          block.classList.remove('collapsible');
          block.classList.add('expanded');
          expandText.style.display = 'none';
          collapseText.style.display = 'inline';
        } else {
          block.classList.remove('expanded');
          block.classList.add('collapsible');
          expandText.style.display = 'inline';
          collapseText.style.display = 'none';
          block.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }
      });
    }
  });
});

使用 macOS 視窗樣式時
#

編輯 custom.css
#

先將創建 macOS 視窗樣式時新增的 CSS 樣式刪除,在這邊會合併。
編輯/assets/css下的custom.css

/* 程式碼區塊容器樣式 */
.highlight {
    max-width: 100%;
    position: relative;
    border-radius: 10px;
    margin-left: -5px;
    margin-right: -10px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    overflow: hidden;
}

/* 添加 macOS 風格標題欄 */
.highlight::before {
    content: '';
    height: 30px;
    width: 100%;
    background-color: rgba(var(--color-neutral-50));
    display: block;
    position: relative;
}

/* 深色模式下的標題欄樣式 */
.dark .highlight::before {
    background-color: rgba(var(--color-neutral-700));
}

/* 添加控制按钮 */
.highlight::after {
    content: '';
    position: absolute;
    top: 9px;
    left: 13px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background-color: #ff5f56;
    box-shadow: 20px 0 0 #ffbd2e, 40px 0 0 #27c93f;
    z-index: 1;
}

/* 程式碼區塊內容區域樣式 */
.highlight pre {
    margin: 0;
    padding: 1.5rem;
    width: auto;
}

.prose .chroma {
    border-radius: 0;
}

/* ===== 折疊功能樣式 ===== */

/* 折疊狀態 */
.highlight.collapsible {
    max-height: 430px; /* 400px 內容 + 30px 標題欄 */
    overflow: hidden;
    transition: max-height 0.3s ease;
}

/* 展開狀態 */
.highlight.expanded {
    max-height: none;
}

/* 漸層遮罩 - 使用獨立元素而非偽元素 */
.code-gradient {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 80px;
    background: linear-gradient(to bottom, transparent, var(--color-background));
    pointer-events: none;
    z-index: 2;
}

/* 深色模式的漸層 */
.dark .code-gradient {
    background: linear-gradient(to bottom, transparent, var(--color-charcoal-800));
}

/* 展開按鈕 */
.code-expand-btn {
    display: block;
    width: 100%;
    padding: 0.5rem;
    margin-top: 0.5rem;
    background: var(--color-secondary);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-base);
    cursor: pointer;
    font-size: 0.875rem;
    text-align: center;
    transition: background 0.2s;
}

.code-expand-btn:hover {
    background: var(--color-secondary-hover);
}

新增 collapsible-code.js
#

/static/js下創建collapsible-code.js

document.addEventListener('DOMContentLoaded', function() {
  const codeBlocks = document.querySelectorAll('.highlight');
  
  codeBlocks.forEach(function(block) {
    // 檢查高度是否超過 400px (不含標題欄的30px)
    const contentHeight = block.scrollHeight - 30;
    
    if (contentHeight > 400) {
      // 加上折疊樣式
      block.classList.add('collapsible');
      
      // 創建漸層遮罩
      const gradient = document.createElement('div');
      gradient.className = 'code-gradient';
      block.appendChild(gradient);
      
      // 創建展開按鈕
      const btn = document.createElement('button');
      btn.className = 'code-expand-btn';
      btn.innerHTML = '<span class="expand-text">Expand Code ▼</span><span class="collapse-text" style="display:none;">Collapse Code ▲</span>';
      
      // 插入按鈕到程式碼區塊後面
      block.parentNode.insertBefore(btn, block.nextSibling);
      
      // 按鈕點擊事件
      btn.addEventListener('click', function() {
        const expandText = btn.querySelector('.expand-text');
        const collapseText = btn.querySelector('.collapse-text');
        
        if (block.classList.contains('collapsible')) {
          block.classList.remove('collapsible');
          block.classList.add('expanded');
          gradient.style.display = 'none';
          expandText.style.display = 'none';
          collapseText.style.display = 'inline';
        } else {
          block.classList.remove('expanded');
          block.classList.add('collapsible');
          gradient.style.display = 'block';
          expandText.style.display = 'inline';
          collapseText.style.display = 'none';
          block.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }
      });
    }
  });
});

引入 JavaScript
#

複製/themes/blowfish/layouts/_default/single.html/layouts/_default/single.html並編輯,找到下面這段:

{{/* Body */}}
<section class="flex flex-col max-w-full mt-0 prose dark:prose-invert lg:flex-row">
  <!-- 內容省略 -->
</section>

並在</section>下面一行插入:

<script src="{{ "js/collapsible-code.js" | relURL }}"></script>

如後續更新 Blowfish 主題版本,若發現文章頁面版型出現問題,請複製新的single.html,並重新編輯。

折疊按鈕多語言設定
#

如果網站有多語言設定,要將展開(折疊)按鈕顯示為不同語言,可按照下方步驟更改。

編輯 JavaScript
#

更改collapsible-code.js為:

document.addEventListener('DOMContentLoaded', function() {
  const codeBlocks = document.querySelectorAll('.highlight');
  
  // 從 HTML 讀取翻譯文字,預設為英文
  const expandText = document.documentElement.dataset.expandText || 'Expand Code ▼';
  const collapseText = document.documentElement.dataset.collapseText || 'Collapse Code ▲';
  
  codeBlocks.forEach(function(block) {
    const contentHeight = block.scrollHeight - 30;
    
    if (contentHeight > 400) {
      block.classList.add('collapsible');
      
      const gradient = document.createElement('div');
      gradient.className = 'code-gradient';
      block.appendChild(gradient);
      
      const btn = document.createElement('button');
      btn.className = 'code-expand-btn';
      btn.innerHTML = '<span class="expand-text">' + expandText + '</span><span class="collapse-text" style="display:none;">' + collapseText + '</span>';
      
      block.parentNode.insertBefore(btn, block.nextSibling);
      
      btn.addEventListener('click', function() {
        const expandSpan = btn.querySelector('.expand-text');
        const collapseSpan = btn.querySelector('.collapse-text');
        
        if (block.classList.contains('collapsible')) {
          block.classList.remove('collapsible');
          block.classList.add('expanded');
          gradient.style.display = 'none';
          expandSpan.style.display = 'none';
          collapseSpan.style.display = 'inline';
        } else {
          block.classList.remove('expanded');
          block.classList.add('collapsible');
          gradient.style.display = 'block';
          expandSpan.style.display = 'inline';
          collapseSpan.style.display = 'none';
          block.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }
      });
    }
  });
});

引入 JavaScript
#

一樣編輯single.html,在剛剛加入:

<script src="{{ "js/collapsible-code.js" | relURL }}"></script>

的上面一行加入:

<script>
  document.documentElement.dataset.expandText = "{{ i18n "shortcode.collapsible-code.expand" }}";
  document.documentElement.dataset.collapseText = "{{ i18n "shortcode.collapsible-code.collapse" }}";
</script>

編輯 i18n 設定檔
#

這邊以繁中為例,我的檔名為zh-TW.yaml
在檔案中找到加入:

shortcode:
  collapsible-code:
    expand: "展開完整程式碼 ▼"
    collapse: "折疊程式碼 ▲"

按照上方的步驟編輯後,你就可以得到「macOS 視窗樣式」並且「限制高度、可折疊」的程式碼區塊。

透過郵件回覆
YoZ 柚子
作者
YoZ 柚子
韓國實用音樂系留學生/FOSS Nerd/ISTJ/襯衫、墨鏡愛好者
Hugo Blowfish 主題客製化 - 本文屬於一個選集。
§ 3: 本文

相關文章