Fluid 主题修改记录

这是 Fluid v1.9.7 修改内容的记录。下面的修改涉及到了图标,需要在 _config.fluid.yml 引入如下 CSS。

custom_css:
  - //at.alicdn.com/t/c/font_2976433_etozsfezlbk.css

1.1 代码块增强

v1.9.7 版本已实现代码块显示编程语言和复制代码按钮,但缺少代码块折叠功能。在参考网上的资料和 ChatGPT 后,实现了该功能。

1、_config.fluid.yml 文件修改

增加以下代码

code:
  # 设置为 false
  copy_btn: false

  # 设置为 false
  language:
    enable: false
    default: "TEXT"

# ...

# 增加的代码
SeeYue_Mod:
  # 代码块增强
  code_enhance:
    enable: true
    # 代码块折叠
    fold:
      enable: true
      # 最大显示行数
      lines: 20
    # 是否显示代码块编程语言
    lang: true
    # 是否显示代码块复制按钮
    copy: true

2、scripts.ejs 文件修改

scripts.ejs 位于 themes\fluid\layout_partials\ 路径,添加以下代码。

<!-- 代码增强 -->
<%- partial('_partials/plugins/code-enhance.ejs') %>

code-enhance.ejs 放在 themes\fluid\layout_partials\plugins\ 路径,其代码如下。

<!-- 不要格式化 -->
<% if ((theme.SeeYue_Mod.code_enhance.enable && theme.code.highlight.line_number)) { %>
  <script>
    // 是否开启代码折叠
    var enableCodeCollapse = <%- theme.SeeYue_Mod.code_enhance.fold.enable %>;
    // 代码块最大显示行数
    var maxDisplayLines = <%- theme.SeeYue_Mod.code_enhance.fold.lines %>;
    // 是否开启代码复制
    var enableCodeCopy = <%- theme.SeeYue_Mod.code_enhance.copy %>;
    // 是否显示编程语言
    var enableCodeLanguage = <%- theme.SeeYue_Mod.code_enhance.lang %>;
    // 代码语言标准形式
      var codeLang = {
        abap: "ABAP",
        apl: "APL",
        asciiarmor: "ASCII Armor",
        asn1: "ASN.1",
        asp: "ASP",
        assembly: "Assembly",
        bash: "Bash",
        basic: "BASIC",
        c: "C",
        csharp: "C#",
        cpp: "C++",
        cassandra: "Cassandra",
        ceylon: "Ceylon",
        clike: "C-like",
        clojure: "Clojure",
        cmake: "CMake",
        cobol: "COBOL",
        coffeescript: "CoffeeScript",
        commonlisp: "Common Lisp",
        cql: "CQL",
        crystal: "Crystal",
        css: "CSS",
        cypher: "Cypher",
        cython: "Cython",
        d: "D",
        dart: "Dart",
        diff: "Diff",
        django: "Django",
        dockerfile: "Dockerfile",
        dtd: "DTD",
        dylan: "Dylan",
        ejs: "EJS",
        elixir: "Elixir",
        elm: "Elm",
        embeddedjs: "EmbeddedJS",
        erb: "ERB",
        erlang: "Erlang",
        fsharp: "F#",
        flow: "Flow",
        forth: "Forth",
        fortran: "Fortran",
        gas: "Gas",
        gfm: "GFM",
        gherkin: "Gherkin",
        glsl: "GLSL",
        go: "Go",
        groovy: "Groovy",
        handlebars: "Handlebars",
        haskell: "Haskell",
        haxe: "Haxe",
        hive: "Hive",
        htaccess: "htaccess",
        html: "HTML",
        http: "HTTP",
        hxml: "HXML",
        idl: "IDL",
        ini: "INI",
        jade: "Jade",
        java: "Java",
        javascript: "JavaScript",
        jinja2: "Jinja2",
        js: "JavaScript",
        json: "JSON",
        jsp: "JSP",
        jsx: "JSX",
        julia: "Julia",
        kotlin: "Kotlin",
        latex: "LaTeX",
        less: "Less",
        lisp: "Lisp",
        livescript: "LiveScript",
        lua: "Lua",
        makefile: "Makefile",
        mariadb: "MariaDB",
        markdown: "Markdown",
        mathematica: "Mathematica",
        matlab: "MATLAB",
        mbox: "Mbox",
        mermaid: "Mermaid",
        mssql: "MSSQL",
        mysql: "MySQL",
        nginx: "Nginx",
        nim: "Nim",
        nsis: "NSIS",
        objc: "Objective-C",
        ocaml: "OCaml",
        octave: "Octave",
        oz: "Oz",
        pascal: "Pascal",
        pegjs: "PEG.js",
        perl: "Perl",
        perl6: "Perl6",
        pgp: "PGP",
        php: "PHP",
        phphtml: "PHP+HTML",
        plsql: "PL/SQL",
        postgresql: "PostgreSQL",
        powershell: "PowerShell",
        properties: "Properties",
        protobuf: "Protocol Buffers",
        pseudocode: "Pseudocode",
        pug: "Pug",
        python: "Python",
        q: "Q",
        r: "R",
        react: "React",
        restructuredtext: "reStructuredText",
        rst: "RST",
        ruby: "Ruby",
        rust: "Rust",
        sas: "SAS",
        scala: "Scala",
        scheme: "Scheme",
        scss: "SCSS",
        sequence: "Sequence",
        sh: "Shell",
        shell: "Shell",
        smalltalk: "Smalltalk",
        solidity: "Solidity",
        sparql: "SPARQL",
        spreadsheet: "Spreadsheet",
        sql: "SQL",
        sqlite: "SQLite",
        squirrel: "Squirrel",
        stata: "Stata",
        stylus: "Stylus",
        svelte: "Svelte",
        swift: "Swift",
        systemverilog: "SystemVerilog",
        tcl: "Tcl",
        tex: "TeX",
        tiddlywiki: "TiddlyWiki",
        tikiwiki: "Tiki Wiki",
        toml: "TOML",
        ts: "TypeScript",
        tsx: "TSX",
        turtle: "Turtle",
        twig: "Twig",
        typescript: "TypeScript",
        v: "V",
        vb: "VB",
        vbscript: "VBScript",
        velocity: "Velocity",
        verilog: "Verilog",
        vhdl: "VHDL",
        visualbasic: "Visual Basic",
        vue: "Vue",
        webidl: "Web IDL",
        wiki: "Wiki",
        xaml: "XAML",
        xml: "XML",
        xmldtd: "XML DTD",
        xquery: "XQuery",
        yacas: "Yacas",
        yaml: "YAML",
        yara: "YARA",
      };

      // 代码语言格式化
      function getLanguage(lang) {
        var lang_lower = lang.toLowerCase();
        return lang_lower in codeLang ? codeLang[lang_lower] : lang;
      }
      // 获取唯一 ID
      function getUuiD() {
        return Math.random().toString(36).substring(2, 8) + Date.now().toString(36);
      }
      // 文本复制
      function copyText(text) {
        navigator.clipboard.writeText(text).then(function () {
          console.log('代码复制成功');
        }).catch(function (err) {
          console.error('代码复制失败', err);
        });
      }
      // 复制按钮
      function addCopyButton(wrapper) {
        if (!enableCodeCopy) {
          return;
        }
      // 创建复制按钮
      var copyBtn = document.createElement('i');
      copyBtn.className = 'iconfont icon-clipboard copy-btn';
      copyBtn.addEventListener('click', function () {
        // 获取代码块内容
        var codeContent = wrapper.querySelector('.code pre');
        copyText(codeContent.innerText);
        // 先隐藏原本的复制按钮
        copyBtn.style.display = 'none';
        // 插入一个检查图标作为成功提示
        var successIcon = document.createElement('i');
        successIcon.className = 'iconfont icon-check copy-btn';
        wrapper.prepend(successIcon);
        setTimeout(function () {
          successIcon.remove();
          copyBtn.style.display = 'block';
        }, 1000);
      });
      // 创建 span 元素
      var spanElement = document.createElement('span');
      spanElement.innerText = '请在展开状态复制';
      spanElement.classList.add('copy-tip');
      spanElement.style.opacity = '0';
      copyBtn.addEventListener('mouseenter', function () {
        if (wrapper.querySelector('.code').offsetHeight === 0) {
          $(spanElement).animate({ opacity: 1 }, 300);
        }
      });
      copyBtn.addEventListener('mouseleave', function () {
        if (wrapper.querySelector('.code').offsetHeight === 0) {
          $(spanElement).animate({ opacity: 0 }, 300);
        }
      });
      wrapper.prepend(spanElement);
      wrapper.prepend(copyBtn);
    }

    // 代码折叠
    function addCodeCollapse(wrapper) {
      var lang = wrapper.classList[1];
      var id = `collapse-${getUuiD()}`;
      // 是否显示折叠按钮
      var btn = enableCodeCollapse ? `<i class="iconfont icon-regular-down" type="button" data-toggle="collapse" data-target="#${id}"></i>` : '';
      // 是否显示编程语言标签
      var span = enableCodeLanguage ? `<span class="code-lang">${getLanguage(lang)}</span>` : '';
      // 判断是否是大型代码块且开启了折叠
      var isLargeCode = wrapper.innerText.split('\n').length > (maxDisplayLines + 1);
      // 设置默认的折叠样式
      var defaultCollapseClass = isLargeCode && enableCodeCollapse ? 'collapse' : 'collapse show';
      // 创建包含折叠内容的 div
      var div = `<div class="${defaultCollapseClass}" id="${id}">${wrapper.innerHTML}</div>`;
      wrapper.innerHTML = btn + span + div;
      // 如果是大型代码块且开启了折叠
      if (isLargeCode && enableCodeCollapse) {
        // 获取折叠按钮
        var collapseButton = wrapper.querySelector(".icon-regular-down");
        // 添加旋转效果
        collapseButton.classList.add('rotate');
        // 点击折叠按钮时,移除旋转效果
        collapseButton.addEventListener('click', function () {
          var icon = $(this);
          icon.removeClass('rotate');
        });
      }
    }
    function codeEnhanced() {
      // 获取所有代码块的容器
      var wrappers = $("figure.highlight");
      for (var i = 0; i < wrappers.length; i++) {
        var wrapper = wrappers[i];
        // 调用折叠函数
        addCodeCollapse(wrapper);
        // 添加复制按钮
        addCopyButton(wrapper);
      }
    }
    // 页面加载完成后执行主逻辑
    $(document).ready(codeEnhanced);
  </script>
<% } %>
<% if ((theme.SeeYue_Mod.code_enhance.enable && !theme.code.highlight.line_number)) { %>
  <script>
    // 是否开启代码折叠
    var enableCodeCollapse = <%- theme.SeeYue_Mod.code_enhance.fold.enable %>;
    // 代码块最大显示行数
    var maxDisplayLines = <%- theme.SeeYue_Mod.code_enhance.fold.lines %>;
    // 是否开启代码复制
    var enableCodeCopy = <%- theme.SeeYue_Mod.code_enhance.copy %>;
    // 是否显示编程语言
    var enableCodeLanguage = <%- theme.SeeYue_Mod.code_enhance.lang %>;
    // 代码语言标准形式
    var codeLang = {
      abap: "ABAP",
      apl: "APL",
      asciiarmor: "ASCII Armor",
      asn1: "ASN.1",
      asp: "ASP",
      assembly: "Assembly",
      bash: "Bash",
      basic: "BASIC",
      c: "C",
      csharp: "C#",
      cpp: "C++",
      cassandra: "Cassandra",
      ceylon: "Ceylon",
      clike: "C-like",
      clojure: "Clojure",
      cmake: "CMake",
      cobol: "COBOL",
      coffeescript: "CoffeeScript",
      commonlisp: "Common Lisp",
      cql: "CQL",
      crystal: "Crystal",
      css: "CSS",
      cypher: "Cypher",
      cython: "Cython",
      d: "D",
      dart: "Dart",
      diff: "Diff",
      django: "Django",
      dockerfile: "Dockerfile",
      dtd: "DTD",
      dylan: "Dylan",
      ejs: "EJS",
      elixir: "Elixir",
      elm: "Elm",
      embeddedjs: "EmbeddedJS",
      erb: "ERB",
      erlang: "Erlang",
      fsharp: "F#",
      flow: "Flow",
      forth: "Forth",
      fortran: "Fortran",
      gas: "Gas",
      gfm: "GFM",
      gherkin: "Gherkin",
      glsl: "GLSL",
      go: "Go",
      groovy: "Groovy",
      handlebars: "Handlebars",
      haskell: "Haskell",
      haxe: "Haxe",
      hive: "Hive",
      htaccess: "htaccess",
      html: "HTML",
      http: "HTTP",
      hxml: "HXML",
      idl: "IDL",
      ini: "INI",
      jade: "Jade",
      java: "Java",
      javascript: "JavaScript",
      jinja2: "Jinja2",
      js: "JavaScript",
      json: "JSON",
      jsp: "JSP",
      jsx: "JSX",
      julia: "Julia",
      kotlin: "Kotlin",
      latex: "LaTeX",
      less: "Less",
      lisp: "Lisp",
      livescript: "LiveScript",
      lua: "Lua",
      makefile: "Makefile",
      mariadb: "MariaDB",
      markdown: "Markdown",
      mathematica: "Mathematica",
      matlab: "MATLAB",
      mbox: "Mbox",
      mermaid: "Mermaid",
      mssql: "MSSQL",
      mysql: "MySQL",
      nginx: "Nginx",
      nim: "Nim",
      nsis: "NSIS",
      objc: "Objective-C",
      ocaml: "OCaml",
      octave: "Octave",
      oz: "Oz",
      pascal: "Pascal",
      pegjs: "PEG.js",
      perl: "Perl",
      perl6: "Perl6",
      pgp: "PGP",
      php: "PHP",
      phphtml: "PHP+HTML",
      plsql: "PL/SQL",
      postgresql: "PostgreSQL",
      powershell: "PowerShell",
      properties: "Properties",
      protobuf: "Protocol Buffers",
      pseudocode: "Pseudocode",
      pug: "Pug",
      python: "Python",
      q: "Q",
      r: "R",
      react: "React",
      restructuredtext: "reStructuredText",
      rst: "RST",
      ruby: "Ruby",
      rust: "Rust",
      sas: "SAS",
      scala: "Scala",
      scheme: "Scheme",
      scss: "SCSS",
      sequence: "Sequence",
      sh: "Shell",
      shell: "Shell",
      smalltalk: "Smalltalk",
      solidity: "Solidity",
      sparql: "SPARQL",
      spreadsheet: "Spreadsheet",
      sql: "SQL",
      sqlite: "SQLite",
      squirrel: "Squirrel",
      stata: "Stata",
      stylus: "Stylus",
      svelte: "Svelte",
      swift: "Swift",
      systemverilog: "SystemVerilog",
      tcl: "Tcl",
      tex: "TeX",
      tiddlywiki: "TiddlyWiki",
      tikiwiki: "Tiki Wiki",
      toml: "TOML",
      ts: "TypeScript",
      tsx: "TSX",
      turtle: "Turtle",
      twig: "Twig",
      typescript: "TypeScript",
      v: "V",
      vb: "VB",
      vbscript: "VBScript",
      velocity: "Velocity",
      verilog: "Verilog",
      vhdl: "VHDL",
      visualbasic: "Visual Basic",
      vue: "Vue",
      webidl: "Web IDL",
      wiki: "Wiki",
      xaml: "XAML",
      xml: "XML",
      xmldtd: "XML DTD",
      xquery: "XQuery",
      yacas: "Yacas",
      yaml: "YAML",
      yara: "YARA",
    };

    // 代码语言格式化
      function getLanguage(lang) {
        var lang_lower = lang.toLowerCase();
        return lang_lower in codeLang ? codeLang[lang_lower] : lang;
      }
      // 获取唯一 ID
      function getUuiD() {
        return Math.random().toString(36).substring(2, 8) + Date.now().toString(36);
      }
      // 文本复制
      function copyText(text) {
        navigator.clipboard.writeText(text).then(function () {
          console.log('代码复制成功');
        }).catch(function (err) {
          console.error('代码复制失败', err);
        });
      }
      // 添加复制按钮
      function addCopyButton(wrapper) {
        if (!enableCodeCopy) {
          return;
        }
      // 创建复制按钮
      var copyBtn = document.createElement('i');
      copyBtn.className = 'iconfont icon-clipboard copy-code copy-btn';
      copyBtn.addEventListener('click', function () {
        var codeContent = wrapper.lastChild;
        console.log(codeContent);
        copyText(codeContent.innerText);
        copyBtn.style.display = 'none';
        var successIcon = document.createElement('i');
        successIcon.className = 'iconfont icon-check copy-btn';
        wrapper.prepend(successIcon);
        setTimeout(function () {
          successIcon.remove();
          copyBtn.style.display = 'block';
        }, 1000);
      });
      wrapper.prepend(copyBtn);
    }
    // 代码折叠
    function addCodeCollapse(wrapper) {
      var lang = wrapper.firstChild.firstChild.classList[1];
      var id = `collapse-${getUuiD()}`;
      var btn = enableCodeCollapse ? `<i class="iconfont icon-regular-down" type="button" data-toggle="collapse" data-target="#${id}"></i>` : '';
      var span = enableCodeLanguage ? `<span class="code-lang">${getLanguage(lang)}</span>` : '';
      var isLargeCode = wrapper.innerText.split('\n').length > (maxDisplayLines + 1);
      var defaultCollapseClass = isLargeCode && enableCodeCollapse ? 'collapse' : 'collapse show';
      var div = `<div class="${defaultCollapseClass}" id="${id}">${wrapper.innerHTML}</div>`;
      wrapper.innerHTML = btn + span + div;
      // 如果是大型代码块且开启了折叠
      if (isLargeCode && enableCodeCollapse) {
        // 获取折叠按钮
        var collapseButton = wrapper.querySelector(".icon-regular-down");
        // 添加旋转效果
        collapseButton.classList.add('rotate');
        // 点击折叠按钮时,移除旋转效果
        collapseButton.addEventListener('click', function () {
          var icon = $(this);
          icon.removeClass('rotate');
        });
      }
    }
    function codeEnhanced() {
      // 获取所有代码块的容器
      var wrappers = $(".code-wrapper");
      for (var i = 0; i < wrappers.length; i++) {
        var wrapper = wrappers[i];
        // 调用折叠函数
        addCodeCollapse(wrapper);
        // 添加复制按钮
        addCopyButton(wrapper);
      }
    }
    // 页面加载完成后执行主逻辑
    $(document).ready(codeEnhanced);
  </script>
<% } %>

3、样式修改

CSS 代码如下,复制主题正在使用的 CSS 文件内。

/* —————————————————————— 代码块 —————————————————————— */
/* 公共代码和 figure.highlight 的样式 */
.markdown-body .highlight pre,
.markdown-body pre,
figure.highlight pre {
  padding                : 5px 10px;
  border-radius          : 5px;
  border-top-right-radius: 0;
  border-top-left-radius : 0;
}

/* 公共代码和 figure.highlight 的样式 */
.markdown-body .code-wrapper,
.markdown-body figure.highlight {
  background   : #e6ebf1;
  border-radius: 5px;
}

/* 暗黑模式的样式 */
[data-user-color-scheme='dark'] .markdown-body .code-wrapper,
[data-user-color-scheme='dark'] .markdown-body figure.highlight {
  background: #1d1f23;
  position  : relative;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.15);
}

/* 折叠/展开图标 */
.code-wrapper .iconfont.icon-regular-down,
figure.highlight .iconfont.icon-regular-down {
  transform : none;
  transition: transform 0.2s ease-in-out;
}

.code-wrapper .iconfont.icon-regular-down.rotate,
figure.highlight .iconfont.icon-regular-down.rotate,
.code-wrapper .iconfont.icon-regular-down.collapsed,
figure.highlight .iconfont.icon-regular-down.collapsed {
  transform: rotate(-90deg) !important;
}

/* 其他共享样式 */
.code-wrapper>i,
.code-wrapper>span,
figure.highlight>i,
figure.highlight>span {
  color      : var(--text-color);
  opacity    : .6;
  margin-left: 10px;
  line-height: 2rem;
}

/* pre 标签样式 */
.markdown-body pre {
  margin-bottom: 0;
}

/* 复制按钮样式 */
.copy-btn {
  cursor   : pointer;
  float    : right;
  position : relative;
  top      : 0;
  right    : 10px;
  font-size: 16px;
}

/* 代码语言标签样式 */
.code-wrapper .code-lang,
figure.highlight .code-lang {
  font-weight: bold;
}

/* 有行号+代码块折叠,复制提示样式 */
.copy-tip {
  float      : right;
  font-size  : 14px;
  position   : relative;
  top        : 5px;
  right      : 8px;
  margin-left: 0;
  font-weight: normal !important;
}

注意:当代码块处于折叠 + 有行号时,复制的代码一行显示。

1.2 跳转评论区按钮

Fluid 主题有回到顶部按钮,但缺少跳转评论区按钮,现在补上。

1、events.js 文件修改

events.js 位于themes\fluid\source\js\ 路径,添加以下代码。

Fluid.events = {
  // ...
  registerScrollTopArrowEvent: function () {
    var topArrow = jQuery('#scroll-top-button');
    if (topArrow.length === 0) {
      return;
    }
    var board = jQuery('#board');
    if (board.length === 0) {
      return;
    }
    var posDisplay = false;
    var scrollDisplay = false;
    // Position
    var setTopArrowPos = function () {
      var boardRight = board[0].getClientRects()[0].right;
      var bodyWidth = document.body.offsetWidth;
      var right = bodyWidth - boardRight;
      posDisplay = right >= 50;
      topArrow.css({
        'bottom': posDisplay && scrollDisplay ? '20px' : '-60px',
        'right': right - 64 + 'px'
      });
    };
    setTopArrowPos();
    jQuery(window).resize(setTopArrowPos);
    // Display
    var headerHeight = board.offset().top;
    Fluid.utils.listenScroll(function () {
      var scrollHeight = document.body.scrollTop + document.documentElement.scrollTop;
      scrollDisplay = scrollHeight >= headerHeight;
      topArrow.css({
        'bottom': posDisplay && scrollDisplay ? '20px' : '-60px'
      });
    });
    // Click
    topArrow.on('click', function () {
      jQuery('body,html').animate({
        scrollTop: 0,
        easing: 'swing'
      });
    });
  },

  // 文章页面跳转评论区按钮
  registerScrollToCommentsEvent: function () {
    // 判断是否为文章页面
    if (window.location.href.indexOf("posts") === -1) {
      return;
    }
    var offsetToComments = 70; // 评论区顶部到距离页面顶部高度
    var bottomComment = jQuery('#scroll-comment-button');
    if (bottomComment.length === 0) {
      return;
    }
    var board = jQuery('#board');
    if (board.length === 0) {
      return;
    }
    var posDisplay = false;
    var scrollDisplay = false;
    // Position
    var setCommentButtonPos = function () {
      var boardRight = board[0].getClientRects()[0].right;
      var bodyWidth = document.body.offsetWidth;
      var right = bodyWidth - boardRight;
      posDisplay = right >= 50;
      bottomComment.css({
        'bottom': posDisplay && scrollDisplay ? '80px' : '-60px',
        'right': right - 64 + 'px'
      });
    };
    setCommentButtonPos();
    jQuery(window).resize(setCommentButtonPos);
    // Display
    var headerHeight = board.offset().top;
    Fluid.utils.listenScroll(function () {
      var scrollHeight = document.body.scrollTop + document.documentElement.scrollTop;
      scrollDisplay = scrollHeight >= headerHeight;
      bottomComment.css({
        'bottom': posDisplay && scrollDisplay ? '80px' : '-60px'
      });
    });
    var setCommentButtonPos = function () {
      var boardRight = board[0].getClientRects()[0].right;
      var bodyWidth = document.body.offsetWidth;
      var right = bodyWidth - boardRight;
      posDisplay = right >= 50;
      bottomComment.css({
        'bottom': posDisplay && scrollDisplay ? '20px' : '-60px',
        'right': right - 64 + 'px'
      });
    };
    // Click
    bottomComment.on('click', function () {
      var commentsSection = jQuery('#comments');
      if (commentsSection.length > 0) {
        var scrollTo = commentsSection.offset().top - offsetToComments;
        jQuery('body,html').animate({
          scrollTop: scrollTo,
          easing: 'swing'
        });
      }
    });
    // Button Aimation
    let commentsSection = document.querySelector("#comments"); // 获取评论区的div元素
    let scrollButton = document.querySelector("#scroll-comment-button"); // 获取跳转按钮元素
    // 添加页面滚动事件监听
    document.addEventListener("scroll", handleScroll);
    // 页面滚动事件处理函数
    function handleScroll() {
      // 获取评论区相对于页面的位置
      const sectionRect = commentsSection.getBoundingClientRect();
      // 评论区顶部相对于当前页面顶部的垂直距离
      const distanceFromTop = sectionRect.top;
      // 如果评论区顶部在页面高度内
      if (distanceFromTop > window.innerHeight && distanceFromTop > 0) {
        // 显示跳转按钮,应用淡入效果
        scrollButton.style.visibility = "visible";
        scrollButton.style.opacity = "1";
        scrollButton.style.transition = "background-color .2s, bottom .3s, opacity .5s, color .3s";
      } else {
        // 隐藏跳转按钮,应用淡出效果
        scrollButton.style.visibility = "hidden";
        scrollButton.style.opacity = "0";
        scrollButton.style.transition = "background-color .2s, bottom .3s, visibility 0s .5s, opacity .5s";
      }
    }
  },
  // ...
};

2、boot.js 文件修改

boot.js 位于 themes\fluid\source\js\ 路径,添加以下代码。

Fluid.boot.registerEvents = function () {
  // ...
  // 文章页面调整评论区按钮
  Fluid.events.registerScrollToCommentsEvent();
  // ...
};

3、样式修改

CSS 代码如下,复制主题正在使用的 CSS 文件内。

/* 跳转评论区按钮 */
#scroll-comment-button {
  position                  : fixed;
  bottom                    : -60px;
  right                     : 20px;
  z-index                   : 99;
  background                : var(--board-bg-color);
  transition-timing-function: ease-in-out;
  border-radius             : 4px;
  min-width                 : 40px;
  min-height                : 40px;
  outline                   : none;
  display                   : flex;
  align-items               : center;
  box-shadow                : 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
  justify-content           : center;
  font-size                 : 23px;
  color                     : var(--sec-text-color);
}

#scroll-comment-button:hover {
  color: var(--link-hover-color);
}

4、layout.ejs 文件修改

layout.ejs 位于 themes\fluid\layout\ 路径,添加以下代码。

<!-- 不要格式化 -->
<!-- 跳转评论区按钮 -->
<% if (theme.SeeYue_Mod.scroll_comments_btn.enable && !is_home()) { %>
  <a id="scroll-comment-button" aria-label="Comment" href="#conments" role="button">
    <i class="iconfont icon-pinglun" aria-hidden="true"></i>
  </a>
<% } %>

<% if (theme.scroll_top_arrow.enable) { %>
  <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
    <i class="iconfont icon-arrowup" aria-hidden="true"></i>
  </a>
<% } %>

5、_config.fluid.yml 文件修改

增加以下代码。

SeeYue_Mod:
  # 跳转评论区按钮
  scroll_comments_btn:
    enable: true

1.3 首页公告栏

看到别的主题都有类似公告栏的模块,修修改改弄出了一个简单的版本。

1、_config.fluid.yml 文件修改

增加以下代码

SeeYue_Mod:
  # 公告栏
  broadcast:
    enable: true # true 开启,false 关闭。
    startDelay: 1500 # 开始延迟,单位毫秒
    loop: false # 文本是否循环
    cursorChar: "_"
    icon: "iconfont icon-laba" # icnfont 图标库
    text: "看的文章越多,越深感自己的不足,后面的时间,我将把精力放在学习新知识上。博客将停更一段时间。等我回来!"

2、增加 broadcast.ejs 文件

broadcast.ejs 放在 themes\fluid\layout_partials\plugins\ 路径,代码如下。

<!-- 不要格式化 -->
<% if (theme.SeeYue_Mod.broadcast.enable && !page.layout){ %>
  <div class="notice">
    <i class="iconfont icon-laba"></i>
      <span class="notice-content">
          <span class="element"></span>
      </span>
  </div>
  <script src="https://lib.baomitu.com/typed.js/2.1.0/typed.umd.min.js"></script>
  <script>
    var typed = new Typed(".element", {
      strings: ["<%= theme.SeeYue_Mod.broadcast.text %>"], //输入内容, 支持html标签
      startDelay: ["<%= theme.SeeYue_Mod.broadcast.startDelay %>"], //开始延迟
      typeSpeed: 50, //打字速度,数字越大,速度越慢。
      backSpeed: 75, //回退速度
      loop: <%= theme.SeeYue_Mod.broadcast.loop %>, //是否循环
      showCursor: true, //显示游标
      cursorChar: "<%= theme.SeeYue_Mod.broadcast.cursorChar %>", //游标样式
    });
  </script>
<% } %>

3、样式修改

CSS 代码如下,复制主题正在使用的 CSS 文件内。

/* —————————————————————— 公告栏 ——————————————————————  */
@keyframes scaleDraw {
  0% {
    transform: scale(1)
  }

  25% {
    transform: scale(1.2)
  }

  50% {
    transform: scale(1)
  }

  75% {
    transform: scale(1.2)
  }

  100% {
    transform: scale(1)
  }
}

.icon-laba {
  position         : relative;
  font-size        : 2rem !important;
  display          : inline-block;
  color            : #d81e06;
  vertical-align   : sub;
  -webkit-animation: scaleDraw 1s ease-in-out infinite !important;
  animation        : scaleDraw 1s ease-in-out infinite !important
}

.typed-cursor {
  opacity          : 1;
  -webkit-animation: blink .7s infinite;
  -moz-animation   : blink .7s infinite;
  animation        : blink .7s infinite;
  font-size        : 20px;
  font-weight      : bolder;
  padding-left     : 5px
}

@keyframes blink {
  0% {
    opacity: 1
  }

  25% {
    opacity: .5
  }

  50% {
    opacity: 0
  }

  75% {
    opacity: .5
  }

  100% {
    opacity: 1
  }
}

@-webkit-keyframes blink {
  0% {
    opacity: 1
  }

  25% {
    opacity: .5
  }

  50% {
    opacity: 0
  }

  75% {
    opacity: .5
  }

  100% {
    opacity: 1
  }
}

@-moz-keyframes blink {
  0% {
    opacity: 1
  }

  25% {
    opacity: .5
  }

  50% {
    opacity: 0
  }

  75% {
    opacity: .5
  }

  100% {
    opacity: 1
  }
}

.notice_board {
  margin : 20px 0 !important;
  padding: 0 !important
}

.notice {
  border-radius: .5rem;
  padding      : 8px 10px 10px 10px
}

@media only screen and (max-width:768px) {
  .notice {
    padding: 10px
  }

  .icon-laba {
    top: 1px
  }
}

/* 页面正文宽度 */
@media screen and (min-width: 1080px) {

  .post-content,
  post-custom {
    box-sizing   : border-box;
    padding-left : 5%;
    padding-right: 5%;
  }
}

4、layout.ejs 文件修改

layout.ejs 位于 themes\fluid\layout\ 路径,添加以下代码。

<!-- 不要格式化 -->
<main>
  <% if(is_post() || page.layout === '404') { %>
    <%- body %>
  <% } else { %>
    <div class="container nopadding-x-md">
      <!-- 公告栏 -->
      <div id="board" class="notice_board">
        <% if (theme.SeeYue_Mod.broadcast.enable){ %>
        <%- partial('_partials/plugins/broadcast.ejs') %>
        <% } %>
      </div>
      <div id="board"
        // ...
    </div>
  <% } %>
  // ...

</main>

1.4 文末结束语

1、_config.fluid.yml 文件修改

增加以下代码

SeeYue_Mod:
  #...
  # 文末结束语
  conclusion:
    enable: true
    # 结束语样式,使用 Fluid 主题内置的 Tag 插件,详情请看 https://hexo.fluid-dev.com/docs/guide/#tag-%E6%8F%92%E4%BB%B6
    style: success
    content: "如有疑问,请在评论区留言,我会尽快回复。觉得文章不错?点击右侧按钮复制文章链接。"

2、post.ejs 文件修改

post.ejs 位于 themes\fluid\layout\ 路径,添加以下代码。

<!-- 不要格式化 -->
<article class="post-content mx-auto">
            <!-- ... -->
            <% if (page.encrypt === true) { %>
              <%- inject_point('postMarkdownBegin') %>
              <%- page.content %>
              <%- partial('_partials/plugins/encrypt') %>
              <%- inject_point('postMarkdownEnd') %>
            <% } else { %>
              <div class="markdown-body">
                <%- inject_point('postMarkdownBegin') %>
                <%- page.content %>
                <%- inject_point('postMarkdownEnd') %>
              </div>
            <% } %>
            <!-- 添加的代码 -->
            <% if (theme.SeeYue_Mod.conclusion.enable) { %>
              <div class="note note-<%- theme.SeeYue_Mod.conclusion.style %>"><%- theme.SeeYue_Mod.conclusion.content %></div>
            <% } %>
            <div>
            <hr/>
             <!-- ... -->

</article>

1.5 复制文章链接按钮

看完一篇文章,觉得写得不错,想要分享给他人,却发现浏览器仅支持复制链接,不支持复制文章标题。现在可以通过以下代码实现复制文章链接和标题。效果如下:

Fluid 主题修改记录 - 望月家:
https://blog.seeyue.top/posts/b78a5b0f/

1、_config.fluid.yml 文件修改

增加以下代码

SeeYue_Mod:
  #...
  # 文章页
  post:
    # 复制文章链接按钮
    copy_post_link_btn: true

2、post.ejs 文件修改

post.ejs 位于 themes\fluid\layout\ 路径,添加以下代码。

<% if (theme.SeeYue_Mod.conclusion.enable) { %>
  <div class="note note-<%- theme.SeeYue_Mod.conclusion.style %>" style="display: -webkit-flex;justify-content: space-between;"><span><%- theme.SeeYue_Mod.conclusion.content %></span>
      <!-- 添加的代码 -->
    <% if (theme.SeeYue_Mod.post.copy_post_link_btn) { %>
      <span>
        <span style="cursor: pointer;" id="copyButton" title="复制文章链接"><i class="iconfont icon-fenxiang"></i></span>
        <script>
          document.getElementById('copyButton').addEventListener('click', function () {
            var articleTitle = document.title.trim(); // 获取网页标题
            var articleLink = window.location.href.split('#')[0]; // 去除锚点
            var copiedText = articleTitle + ":" + "\n" + articleLink;
            navigator.clipboard.writeText(copiedText)
              .then(function () {
                var button = document.getElementById('copyButton');
                button.innerHTML = '<i style="font-weight: bold" class="iconfont icon-check"></i>';
                setTimeout(function () {
                  button.innerHTML = '<i class="iconfont icon-fenxiang"></i>';
                }, 2000);
              })
              .catch(function (err) {
                console.error('复制失败: ', err);
              });
          });
        </script>
      </span>
    <% } %>
  </div>
<% } %>

1.6 图片编号

j进入 themes\fluid\source\js\ 路径,打开 plugins.js

  imageCaption: function (selector) {
    // ...
  },
// 以上代码替换为以下代码
  imageCaption: function (selector) {
    if (!CONFIG.image_caption.enable) { return; }
    var imageCount = 0; // 初始化图片数量
    jQuery(selector || `.markdown-body > p > img, .markdown-body > figure > img,
    .markdown-body > p > a.fancybox, .markdown-body > figure > a.fancybox`).each(function () {
      var $target = jQuery(this);
      var $figcaption = $target.next('figcaption');
      if ($figcaption.length !== 0) {
        $figcaption.addClass('image-caption');
      } else {
        var imageTitle = $target.attr('title') || $target.attr('alt');
        imageCount++; // 增加图片数量
        if (imageTitle) {
          $target.after(`<figcaption aria-hidden="true" class="image-caption">图 ${imageCount}&nbsp&nbsp${imageTitle}</figcaption>`);
        } else {
          $target.after(`<figcaption aria-hidden="true" class="image-caption">图 ${imageCount}</figcaption>`);
        }
      }
    });
  },

1.7 更新主题

如果你按照上述方法修改了主题源代码,并且希望在升级主题时保留主题的修改,你可以使用 Beyond Compare 4 进行文件夹对比。通过比较每个文件,你可以将主题作者所做的更改合并到你的主题源码中。

Scooter Software - Home of Beyond Compare

Beyond Compare v4.4.7.28397 修改版 - 果核剥壳

Beyond Compare 4 重置专业版使用时长

  1. win + s,打开 Windows 搜索,搜索注册表编辑器,并打开。
  2. 查找「计算机\HKEY_CURRENT_USER\SOFTWARE\Scooter Software\Beyond Compare 4」。
  3. 右侧内容栏选中 CacheID 一行,删除。

参考

如有疑问,请在评论区留言,我会尽快回复。觉得文章不错?点击右侧按钮可复制文章链接。

作者
See Yue
发布于
2024年3月3日
更新于
2024年3月19日
许可协议
评论区