wyast / wyast.github.io

未央科协网站
https://wyast.github.io/
3 stars 1 forks source link

文章加入统一格式 #10

Open RebelPotato opened 7 months ago

RebelPotato commented 7 months ago

大部分不同的文章都需要一些公共内容,比如上方的导航栏,footer等。 需要一个从模板生成文章的方案。可以考虑使用现成的模板语言(单独使用,或结合静态网页生成器使用),也可以自己编写。

An-314 commented 6 months ago

我觉得如果直接使用Jekyll是方便的,我稍微调研了一下

RebelPotato commented 6 months ago

看起来很好,可行!过一段时间尝试编写模板,将已有的md文件转化为有格式的html。 不过md好像有一些限制(比如aside元素无法方便地生成,必须用inline element;比如没法方便地加入.hide类),这导致生成的html文件经常需要手动修改。 不知道Jekyll能否解决此类问题?

An-314 commented 6 months ago

可以的,Markdown支持内嵌的HTML。大概是如果css文件中有,我们在_includehead.html中引入了这个css

<link rel="stylesheet" href="{{ '/style/classless.css' | relative_url }}">

大概就是可以的。

这是正文内容。

<aside>
   使用<code>aside</code>把内容放到旁边。
</aside>

即可。

我本地环境之前配置过,我先试着研究一下Jekyll。

RebelPotato commented 6 months ago

使用markdown的目的是尽可能少写html,我希望尽量少用内联的html元素。不知道有没有其他方法?

An-314 commented 6 months ago

对于markdown已有元素的类

我查到了Jekyll默认使用Kramdown作为Markdown解析器,它支持一种{: .class}语法来给Markdown元素添加CSS类。但是这种方法不直接适用于创建新的HTML块,用于为现有的Markdown元素(如段落、列表、代码块等)添加类,而不是创建新的HTML容器。

新的html容器的添加

有一种方法可以让我们自定义Liquid标签插件

Jekyll允许在Markdown文件中使用Liquid模板语言,这提供了一种间接扩展Markdown语法的方式。通过自定义Liquid标签和过滤器,可以实现特定的内容处理逻辑,然后将结果嵌入到Markdown内容中。这种方法的优点是灵活性高,但它更多地依赖于Liquid而不是直接扩展Markdown本身。

首先,在Jekyll站点的_plugins目录中创建一个新的Ruby文件,例如aside_tag.rb,然后定义一个新的Liquid标签:

module Jekyll
  class RenderAsideTag < Liquid::Tag

    def initialize(tag_name, text, tokens)
      super
      @text = text.strip
    end

    def render(context)
      "<aside class='aside'>#{@text}</aside>"
    end
  end
end

Liquid::Template.register_tag('aside', Jekyll::RenderAsideTag)

这个插件定义了一个新的aside标签,可以在Markdown文件中这样使用它:

{% aside 使用`aside`把内容放到旁边。 %}

这会在生成的HTML中插入一个类名为aside<aside>元素。

Github Pages可能不支持这个功能(需要我们测试一下)

利用GitHub Actions

但是GitHub Pages可能不支持自定义插件,我们可能要通过GitHub Actions完成扩展markdown语法的功能

修改.github/workflows/jekyll.yml

jobs:
  build-and-deploy:
    steps:
    - name: Custom Markdown Processing
      run:  # 写一下脚本

我让AI给我写了一个例子:

要通过自定义处理脚本扩展Markdown语法并在GitHub Actions中使用,你需要决定要添加哪些自定义功能,然后编写一个脚本来实现这些功能。以下是一个基本的流程和示例,演示如何实现这样一个脚本。

确定自定义功能

假设你想添加一个自定义语法,以便在Markdown中使用特定标记来创建带有特定CSS类的<aside>元素。例如,你希望通过这样的标记:

{{aside:这是旁注内容。}}

将其转换为:

<aside class="custom-aside">这是旁注内容。</aside>

编写处理脚本

你可以使用Python作为脚本语言来实现这个功能,因为它广泛应用于文本处理和模式匹配。以下是一个简单的Python脚本示例,它搜索Markdown文件中的自定义标记并替换为HTML代码。

import re
import os

# 定义要搜索的Markdown文件的目录
markdown_dir = 'path/to/your/markdown/files'

# 遍历指定目录中的所有Markdown文件
for root, dirs, files in os.walk(markdown_dir):
    for file in files:
        if file.endswith('.md'):
            filepath = os.path.join(root, file)
            with open(filepath, 'r', encoding='utf-8') as f:
                content = f.read()

            # 使用正则表达式查找所有自定义标记并替换为HTML
            updated_content = re.sub(r'\{\{aside:(.*?)\}\}', r'<aside class="custom-aside">\1</aside>', content, flags=re.DOTALL)

            # 如果内容发生变化,则写回文件
            if content != updated_content:
                with open(filepath, 'w', encoding='utf-8') as f:
                    f.write(updated_content)

集成脚本到GitHub Actions

  1. 将上述Python脚本保存到你的仓库中,例如命名为process_markdown.py
  2. 在GitHub Actions工作流中添加一个步骤来执行这个脚本。确保在安装Python环境后和Jekyll构建之前执行此脚本:
- name: Custom Markdown Processing
  run: python process_markdown.py
  1. 更新脚本中的markdown_dir变量,以指向你的Markdown文件的实际目录。

注意事项

通过这种方式,你可以灵活地扩展Markdown语法并自动化处理过程,使得内容创作和展示更加符合你的特定需求。

An-314 commented 6 months ago

而且发现创建展示所有Posts或者Pages的二级页面,也有自动生成的方法。这样我们要做的只是添加md文件,和写一些其他页面,posts的管理就不用太过于操心。

---
layout: page
title: "all posts"
permalink: /posts/
---

<ul>
{% for post in site.posts %}
<li>
 <a href="{{ post.url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>

就可以把排列这些posts的过程自动化

RebelPotato commented 6 months ago

原来liquid标签可以自定义!很有用的信息。只是不想为此再学一门ruby。

我认为使用github action可能会使我们受限于github,最好的方法是把jekyll安装在本地,每次pr自己生成文章后再merge。不过这可能会带来统一环境的麻烦:jekyll不原生支持windows! image 如上图所示,被套牢的风险始终存在。

更重要的是,我希望未来写文章的同学们能在写作的过程中实时看到自己文章的效果,以此调整自己的内容,而不是把时间浪费于与管理员的联络中。

或许自己写一个脚本(比如用python+jinja)然后打包成exe,会更方便?

RebelPotato commented 6 months ago

https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll

在这里看到了更多信息,我先读一读。

An-314 commented 6 months ago

文档中提到似乎支持Jekyll插件

Jekyll的官方文档中提到了converters插件,大概是上文

新的html容器的添加

有一种方法可以让我们自定义Liquid标签插件

Jekyll允许在Markdown文件中使用Liquid模板语言,这提供了一种间接扩展Markdown语法的方式。通过自定义Liquid标签和过滤器,可以实现特定的内容处理逻辑,然后将结果嵌入到Markdown内容中。这种方法的优点是灵活性高,但它更多地依赖于Liquid而不是直接扩展Markdown本身。

首先,在Jekyll站点的_plugins目录中创建一个新的Ruby文件,例如aside_tag.rb,然后定义一个新的Liquid标签:

module Jekyll
  class RenderAsideTag < Liquid::Tag

    def initialize(tag_name, text, tokens)
      super
      @text = text.strip
    end

    def render(context)
      "<aside class='aside'>#{@text}</aside>"
    end
  end
end

Liquid::Template.register_tag('aside', Jekyll::RenderAsideTag)

这个插件定义了一个新的aside标签,可以在Markdown文件中这样使用它:

{% aside 使用`aside`把内容放到旁边。 %}

这会在生成的HTML中插入一个类名为aside<aside>元素。

我在本地尝试了一下,发现是可行的。在md文件内使用我们扩展的md语法确实可以在自动生成的html内成为相应的html块。

如果如文档中所说GitHub pages是支持这样的插件的话,我们不妨可以直接使用这种方法。这样在本地也可以实时预览。

而且我觉得对于学习ruby的代价也是几乎没有的,我们只需要在示例代码上稍加更改即可。

An-314 commented 6 months ago

具体撰写我们可以借助AI,所以应该不是问题。我们只需要给出自己的一套新的语法标准。

虽然Windows不原生支持Jekyll,官方也提供了安装的方法,也不是很复杂。(但是具体和Linux的区别我不清楚,但对于我们目前的应用,我觉得是完全够用的)

RebelPotato commented 6 months ago

关于本地生成

我在本地尝试了一下,发现是可行的。在md文件内使用我们扩展的md语法确实可以在自动生成的html内成为相应的html块。

好耶!这说明至少“本地生成后上传到github”是一个可行的方案。

关于jekyll插件与自定义语法

如果如文档中所说GitHub pages是支持这样的插件的话,我们不妨可以直接使用这种方法。这样在本地也可以实时预览。

我们只需要给出自己的一套新的语法标准。

这与文档中的说明不符。文档说:

For a list of supported plugins, see "Dependency versions" on the GitHub Pages site. For usage information for a specific plugin, see the plugin's documentation. GitHub Pages cannot build sites using unsupported plugins. If you want to use unsupported plugins, generate your site locally and then push your site's static files to GitHub.

加粗的字说明,并非是想加什么插件就可以随便加。只有在Dependency versions上出现的插件,才能加到github workflow运行的jekyll上。也就是说,只有这些插件中的一个支持我们想要加入的新语法时,我们才能使用此语法。受制于人!

如果不在意这一点的话,我觉得可以按照 https://pages.github.com/versions/ 上的说明,尝试安装"the GitHub Pages Ruby gem",然后测试其支持的语法,看一看能否生成我们希望得到的内容。具体方法如网站所示:

Want a more programmatic way to keep your local version of Jekyll up to date? All dependencies are bundled within the GitHub Pages Ruby gem, or are available programmatically via pages.github.com/versions.json

安装这个gem以后可能需要再多尝试一下。

如果不使用github workflow,还有更多其他的SSG可供选择,就不一定要使用jekyll了。jekyll相对于其他的SSG有什么优势?

有关“只写markdown”

来自A Simple Mess

This is also something people keep getting wrong about Markdown as originally presented. Markdown isn’t a format. It’s a convenience tool that helps you write some of the boringest and commonest parts of HTML easier, and you can easily drop into more wonky HTML at any time. That way, call-tables and Markdown both avoid a common mistake we programmers do—I’ve done it too, a bunch of times—is introducing unnecessary intermediary formats. Full formats, with corner cases and completeness and specs and flowers and a wedding dress.

我倾向于认为,比起使用markdown生成完整的文章,更好的使用方法是用它生成html,把它作为权威的版本。这样的好处是去掉了中间商:原先是“整个网站数据, markdown, html->html”的工具,现在只需要维护一个“整个网站数据, html->html”的工具。

等等,真的需要这些工具吗?需要整体更换导航栏的时候再写个脚本,不香吗?

更多的内容详见A Simple Mess一文。当然,如果能让我改变主意,我会很高兴!

An-314 commented 6 months ago

关于jekyll插件与自定义语法

我又探索了一些扩展md语法的方式,包括一些环境的嵌套也可以实现(利用Jekyll的hook,在解析md前后两次进行替换)。

但是,很好,我发现我们自定义的ruby插件是在GitHub Pages上不被支持的。所以如果不愿意出现内联的html块,基本上可以放弃利用插件自动构建的方案了。

如果还想这么做,只能去在GitHub Actions增添步骤了

关于选择jekyll

之所以选择Jekyll最开始的原因是,GitHub Pages原生支持Jekyll,只需要把源码推送上去,无需额外配置。对于其他SSG,需要自己配置依赖项和GitHub Actions。所以在一开始就对本地的Jekyll环境进行了配置,后续我的研究也是在这个环境下进行的。

现在可行的方案

如果我们选择本地构建再推送,选什么SSG应该是没有什么区别的。这也是上文所说的以html为权威。

我之所以考虑采用这种构建方法,是想简化我们后序的维护和组织。

  1. 每次创建一个新的页面只需要在指定文件夹下新增一个md文件,剩下的一切,包括html的转化、归类、目录的生成等等都自动生成和维护了。
  2. 把各个组件(头、导航栏、主题样式、底部)分开管理,更容易批量维护。SSG提供了更简洁和容易写的连接方式,html本身不支持include(虽然可以用JavaScript实现),但是Jekyll利用liquid可以更方便和直观地组织这些部分,也可以避免在写每个html的时候都要考虑很多重复的内容。可以让后序的撰写只集中在文章的内容本身。(我是觉得这样的方法是优雅的,但确实很多时候优雅并不是最直接最简洁的)

顾虑应该在于:

  1. 直接写md再通过Jekyll转为html有时可能难以达到html的期望效果,这时候就很难进行更改。这时的效果可能不如直接写html了。
  2. 写md对于我们自定义块的预览也不是很方便。

所以一种好的方法是用外部的方式把md转化成html,这样既能预览又方便修改。一个比较主流的方式可能是直接在本地利用Pandoc直接转换,通过配置一些插件实现自定义语法扩展;甚至python都有markdown库可以使用。

我的想法

一般而言,我们新定义的html块的使用频率不会太高,并且出问题的概率也很低。在原生md预览的情况下基本上就能看出最后的效果。除非我们要用到很复杂的html设计,如果这些组件的位置都是二维的而不是像现在一样线性的,必须利用html进行预览验证。

如果我们对html样式本身没有什么太多的要求,撰写的结构是线性结构的文档,我希望我们能把最后的每篇文章的撰写变成写一个简单的md文档,这样可以完全把撰写与考虑布局和样式分离。这样减轻写稿人的负担。写稿人只用负责完成很容易的md的撰写,剩下的内容即可自动生成。

对于极少数需要考虑非线性的布局的文章(大概多是一级、二级页面),我们在自动生成的基础上单独处理,可以减少一些重复的工作。

(当然,我这么做纯属是个人喜好,是觉得整体组织起来比较优雅,但可能确实不是最直接有效的,所以最后选择什么方案还请大家讨论之后定夺)