Hugo装修 | 爱心点赞与文章页默认Layout修改

最后编辑于:

可以跳过的前言:
我一直非常羞于在社交媒体上发po说自己写了新文章,偶有写了文章发给朋友看,或者有朋友看到我的博客,似乎也并没有什么特别需要留下评论的内容。点个赞,已阅,也挺好。于是乎想来找了几个做点赞教程的帖子,抄了まなみ的这条装修博客 ,没有多加改动。不过由于cloudflare更新、hugo stack框架和Fuji(まなみ老师的博客主题)不一样,导致我还是花了大量时间和精力完成这次的点赞装修。最后呈现的效果可见此文末端!(来点击一下吧!)
之前我在想我应该不会写任何装修博客,因为自己根本不懂代码也看不懂这些内容。但由于我昨天不断地,竟也最终打成了自己想要的效果,欣喜万分。故写此篇博客,如果能帮到任何需要的人就太好了。

第一部分:Cloudflare配置

1. 登录Cloudflare

2. 左侧工具栏→“存储和数据库”→选择“KV”→右上角“创建”

alt text

3. 创建KV命名空间

alt text

4.左侧工具栏→计算(workers)→“workers和pages”→“从Hello World开始”

alt text

5.worker名称命名

alt text

6.“workers和pages”→“添加绑定”

alt text

7.“添加绑定”→选择“KV命名空间”→“添加绑定”

alt text

8.变量名称、KV命名空间绑定并添加绑定

“KV命名空间”从下拉选项中选择先前创建的“kudos”。
alt text

9.选择右上角“编辑代码” ,将下列代码替代原文本,注意将66、96、97行代码中“env.KV”的“KV”部分改成你的KV命名空间的变量名称。比如我将改为“kudos”。同时,记住图片右上角打码处你的worker地址

alt text alt text

まなみ在博客里感谢了白石京老师在第三夏尔博客里分享的魔改代码,让我们一起谢谢白石京老师!
>>代码部分<<
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
const instruction = `.^^.
'. .'
  \`

dddddddddzzzz
OpenHeart protocol API

https://api.oh.dddddddddzzzz.org

Test with example.com as <domain>.

GET /<domain>/<uid> to look up reactions for <uid> under <domain>

POST /<domain>/<uid> to send an emoji

<uid> must not contain a forward slash.
<domain> owner has the right to remove data under its domain scope.

----- Test in CLI -----
Send emoji:
curl -d '<emoji>' -X POST 'https://api.oh.dddddddddzzzz.org/example.com/uid'

Get all emoji counts for /example.com/uid:
curl 'https://api.oh.dddddddddzzzz.org/example.com/uid'
`;

export default {
  async fetch(request, env) {
    if (request.method == 'OPTIONS') {
      return new Response(null, { headers });
    }
    if (request.method === 'GET') {
      if (url(request).pathname === '/') {
        return new Response(instruction, { headers });
      } else {
        return handleGet(request, env);
      }
    }
    if (request.method === 'POST') return handlePost(request, env);
  },
};

const headers = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET,POST",
  "Access-Control-Max-Age": "86400",
};

function error(text, code = 400) {
  return new Response(text, { headers, status: code });
}

async function handleGet(request, env) {
  const [domain, ...uidParts] = url(request).pathname.slice(1).split('/');
  const uid = uidParts ? uidParts.join('/') : null;
  if (!domain || !uid) {
    return error('Domain or UID missing.');
  }

  const list = {};
  const emojis = ["❤️", "👍", "😂", "🎉"]; // Add expected emojis here

  // Fetch counts for each emoji directly
  for (const emoji of emojis) {
    const key = `${domain}:${uid}:${emoji}`;
    const value = await env.KV.get(key);
    if (value) {
      list[emoji] = Number(value);
    }
  }

  return new Response(
    JSON.stringify(list, null, 2), // Return only the found counts
    { headers: { ...headers, "Content-Type": "application/json;charset=UTF-8" } }
  );
}

function url(request) {
  return new URL(request.url);
}

async function handlePost(request, env) {
  const urlObject = url(request);
  const path = urlObject.pathname.slice(1);
  if (path === '') return error('Pathname missing');

  const [domain, ...uidParts] = path.split('/');
  const uid = uidParts ? uidParts.join('/') : '';
  if (uid.length < 1) return error('UID required.');

  const id = [encodeURI(domain), uid].join(':');
  const emoji = ensureEmoji(await request.text());
  if (!emoji) return error('Request body should contain an emoji');

  const key = `${id}:${emoji}`;
  const currentCount = Number(await env.KV.get(key) || 0);
  await env.KV.put(key, (currentCount + 1).toString());

  const redirection = urlObject.searchParams.get('redirect');
  if (redirection !== null) {
    headers['Location'] = redirection || request.headers.get('Referer');
    return new Response('recorded', { headers, status: 303 });
  } else {
    return new Response('recorded', { headers });
  }
}

function ensureEmoji(emoji) {
  const segments = Array.from(
    new Intl.Segmenter({ granularity: 'grapheme' }).segment(emoji.trim())
  );
  const parsedEmoji = segments.length > 0 ? segments[0].segment : null;

  if (/\p{Emoji}/u.test(parsedEmoji)) return parsedEmoji;
}

10.右上角“部署”,Cloudflare部分完成。


第二部分:修改HugoStack的默认文章的layout(可选)

我没有找到合适的教程来修改内容,于是自己摸索了一下,修改方法如下:

  1. 在\layouts\partials\article中新建article.html
>>article.html<<
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<article class="{{ if .Params.image }}has-image {{ end }}main-article">
    {{ partial "article/components/header" . }}
    {{ partial "article/components/content" . }}


    {{ if or .Params.math .Site.Params.article.math }}
        {{ partialCached "article/components/math.html" . }}
    {{ end }}

    <footer class="article-footer">
    {{ partial "article/components/tags" . }}

    {{ if and (.Site.Params.article.license.enabled) (not (eq .Params.license false)) }}
    <section class="article-copyright">
        {{ partial "helper/icon" "copyright" }}
        <span>{{ default .Site.Params.article.license.default .Params.license | markdownify }}</span>
    </section>
    {{ end }}
    </footer>
</article>


  1. 在\layouts\partials\article\components中新建footer.html和tags.html
>>footer.html<<
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<footer class="article-footer">
    {{ partial "article/components/tags" . }}

    {{ if and (.Site.Params.article.license.enabled) (not (eq .Params.license false)) }}
    <section class="article-copyright">
        {{ partial "helper/icon" "copyright" }}
        <span>{{ default .Site.Params.article.license.default .Params.license | markdownify }}</span>
    </section>
    {{ end }}

    {{- if ne .Lastmod .Date -}}
    <section class="article-lastmod">
        {{ partial "helper/icon" "clock" }}
        <span>
            {{ T "article.lastUpdatedOn" }} {{ .Lastmod | time.Format ( or .Site.Params.dateFormat.lastUpdated "Jan 02, 2006 15:04 MST" ) }}
        </span>
    </section>
    {{- end -}}
</footer>
>>tags.html<<
1
2
3
4
5
6
7
{{ if .Params.Tags }}
    <section class="article-tags">
        {{ range (.GetTerms "tags") }}
            <a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
        {{ end }}
    </section>
{{ end }}

现在你就得到了一个你的文章页layout的模版啦!你可以根据自己的喜好添加、删减内容了。


第三部分:实装点赞爱心按钮

1. 在/layouts/partials目录下新建kudos.html ,复制下面まなみ老师提供的爱心魔改代码。第一行中的链接改成你的Worker的域名,后面的{{ .Permalink }} 不要漏了。请说,谢谢まなみ老师!

>>代码如下<<
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!-- emoji 可为多个,但必须要在前面的可识别列表里出现 -->
<open-heart  href="你的Workers地址填写在这里!/{{ .Permalink }}" emoji="❤️"> 
  <img src="https://img.naturaleki.one/lock/kudoclick.png" width="25" height="25" style="position: relative; top: 5px;">
</open-heart>

<!-- load web component -->
<script src="https://unpkg.com/open-heart-element" type="module"></script>
<!-- when the webcomponent loads, fetch the current counts for that page -->
<script>
window.customElements.whenDefined('open-heart').then(() => {
  for (const oh of document.querySelectorAll('open-heart')) {
    oh.getCount()
  }
})
// refresh component after click
window.addEventListener('open-heart', e => {
	e && e.target && e.target.getCount && e.target.getCount()
})
</script>


2. 找到你的文章模版,在你喜欢的地方放入下面的代码。

>>代码如下<<
1
2
3
{{ if and (ne .Params.showkudos false) }}
{{ partial "kudos.html" . }}
{{ end }}


3. 将下面代码放入scss文件。如果你想要修改任何点赞小图标的内容,也可以在这里问chatgpt老师进行修改。

>>代码如下<<
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Open heart reaction style
open-heart {
    margin: 5px;
    margin-top: 0;
    display: block;  // Center alignment
    margin-left: auto;
    margin-right: auto;
    width: fit-content;
    border: 1px solid var(--color-secondary);
    border-radius: .2em;
    padding: .4em;
    font-family: 'ipx en';
  
  }
  open-heart:not([disabled]):hover,
  open-heart:not([disabled]):focus {
    border-color: var(--color-focus);
    cursor: pointer;
  }
  open-heart[disabled] {
    background: #ece9f4;
    border: 1px solid var(--color-secondary);
    cursor: not-allowed;
    color: var(--color-font);
  }
  open-heart[count]:not([count="0"])::after {
    content: attr(count);
    padding: .2em;
  }

截至这里,你应该完成了自己的点赞小按钮!恭喜!
再次感谢 まなみ老师的教程

很想碎碎念一下,如果不是网络上那么多优秀而乐于分享的老师们,我也不会一点点建成现在的博客,而我现在要走的路还很远很远。前人栽树后人乘凉,第一篇写下的装修文章一定有很多纰漏,但是如果能帮助到一些人,那是再好不过的了!希望你在写博客和装修博客的路上一路顺利!

Lodka | 禁止一切形式无授权转载 · 無断転用禁止 · Unauthorized reproduction in any form is strictly prohibited.
本博客已偷偷存活
发表了10篇文章 · 总计3万1千字