2025.07.16:更新DLC。

图片文字并列布局

抄的是自用短代码 & 零碎代码集合里的作业,感谢蛋卷!我需要做的修改只是添加fancybox锚点和给所有css后面加!important而已。

首先,在.md文件直接写html代码:

<div class="flex-container">
	<div class="flex-text">
		<p class="flex-start">第一行</p>
		<p>第二行</p>
		<p class="flex-end">最后一行</p>
	</div>
	<img data-fancybox src="http://image.url/" class="flex-image" />
</div>

然后,丢自定义css:

.flex-container {
	display: flex!important;
	align-items: flex-start!important;
	margin: 15px 0!important;
}

.flex-image {
	max-width: 350px !important; /* 或任意你想要的宽度 */
	margin-left: 20px!important;
	margin-top: 0!important;
	margin-bottom: 0!important;
}

.flex-text {
	flex: 1!important;
}

.flex-text p {
	margin-bottom: 1.25em!important;
}

/* 以下代码是我自行添加的,为确保第一行前面和最后一行后面不会多出奇怪的空白 */
.flex-start {
	margin-top: 0 !important;
}

.flex-end {
	margin-bottom: 0 !important;
}

/* 响应式设计 */
@media (max-width: 600px) {
	.flex-container {
		flex-direction: column!important; /* 垂直排列 */
	}

	.flex-image {
		margin-left: 0!important; /* 取消左边距 */
		margin-top: 20px!important; /* 增加上边距,分隔内容 */
		max-width: 100%!important; /* 使图片宽度自适应容器 */
	}
}

效果如下:

请看!右图(手机端上是下图)是蔓酱在圣诞节给我画的超绝无敌可爱的红脸猫形态的小肥!(之完全不红版)

小猫现已绝赞入住博客搜索弹窗!只要在电脑和平板上搜索博客就能纵享小猫陪伴!(即日起小狗搜索员永久下岗,辛苦了!)

机不可失,童叟无欺!欢迎体验!

博客年终总结批注窗口

2025年终总结博客(在黏贴链接的时候,发现我年终博客的链接格式写错了……)上的批注窗口样式存档!因为代码堆得很乱,所以如果要参考的话比起抄我的不如直接让GPT老师再写一个。

写在md文件里的基本html框架:

<div class="journal-card theme4">
  <div class="jc-window-header">
    <span class="jc-window-title">标题</span>
    <button class="jc-window-close" onclick="openWindow('noclose-window')">×</button>
  </div>

  <div class="jc-window-menu">
    <span>File</span>
    <span>Edit</span>
    <span>View</span>
    <span>Help</span>
  </div>

  <div class="jc-divider-full"></div>

  <div class="jc-row">
    <div class="jc-left">
    <span class="jc-date4">January.7th</span>
      <h3 class="jc-title">
        <a href="/post/2025-jan-24th/">博客标题</a>
      </h3>
      <p>
	  目录
      </p>
    </div>
    <div class="jc-right">
      <h4>♠</h4>
      <p>
       批注内容
      </p>
    </div>
  </div>

  <div class="jc-row">
    <div class="jc-left">
    <span class="jc-date4">February.7th</span>
      <h3 class="jc-title">
        <a href="/post/2025-feb-18th/">下一个博客标题</a>
      </h3>
      <p>
又一个目录<br>
br标签分行
      </p>
    </div>
    <div class="jc-right">
      <h4>♠</h4>
      <p>
批注
      </p>
    </div>
  </div>

<div class="jc-footnote">
  <span class="footnote-text">左下角尾注</span>
  <div class="footnote-dots">
    <span class="dot ten"></span>
    <span class="dot eleven"></span>
    <span class="dot twelve"></span>
  </div>
</div>
</div>

自定义css,根据theme后面的序号区分了五种季节+马戏团的印象色,主题配色也是GPT写的,身为色盲的我做的只是饱和度上的微调。

但不知道为什么右下方的圆点没有办法按照theme序号改变颜色,于是就这么one two three four地一个个编了下去……(?

/*年终总结*/
.journal-card {
  position: relative;
  background: #f9f1f5; 
  border: 2px solid #bba6bd;
  border-radius: 6px;
  padding: 20px 20px 40px;
  margin: 22px 0;
  box-shadow: 0 4px 5px rgba(0,0,0,0.5);
  font-family: 'Press Start 2P', monospace;
  color: #eee;
}

/* 窗口标题栏 */
.jc-window-header {
  display: flex;
  justify-content: center; /* 标题居中 */
  align-items: center;
  position: relative; /* 为关闭按钮定位 */
  background: #f4d9e3; 
  padding: 6px 10px;   /* 增加高度 */
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
  margin: -20px -20px 0; /* 覆盖卡片上边缘 */
  font-size: 1rem; /* 字体增大 */
  font-weight: bold; 
  color: #8a3c6b; 
  box-shadow: inset 0 -1px 0 rgba(255,255,255,0.4);
}

/* 标题 */
.jc-window-title {
  font-weight: bold;
  font-size: 1.3rem; /* 可微调 */
  font-family: "ipxs","Product Sans",sans-serif !important;
}

/* 关闭按钮 - 右上角 */
.jc-window-close {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  background: #d69bb3; 
  border: none;
  color: #fff;
  font-weight: bold;
  cursor: pointer;
  width: 22px;  /* 略大一些 */
  height: 22px;
  border-radius: 50%;
  line-height: 20px;
  text-align: center;
  padding-left: 7.5px;
  font-family: "ipxs","Product Sans",sans-serif !important;
}

/* 窗口菜单栏 */
.jc-window-menu {
  display: flex;
  font-family: "ipxs","Product Sans",sans-serif !important;
  gap: 24px; 
  font-size: 0.8rem;
  background: #eec3d3; 
  padding: 4px 10px;   /* 增加高度 */
  margin: 0 -20px 12px;
  color: #8a3c6b; 
  border-bottom: 1px solid #caa3b4; /* 模拟分隔线 */
  padding-left: 10px; 
}


/* 每行 row */
.jc-row {
  display: flex;
  align-items: flex-start;
  margin-bottom: 16px;
  position: relative;
}

/* 左栏 padding 分开设置 */
.jc-row .jc-left {
  flex: 1;
  padding-top: 45px;     
  padding-bottom: 10px;  
  padding-left: 5px;    
  padding-right: 20px;   
}

/* 右栏 padding 分开设置 */
.jc-row .jc-right {
  flex: 1;
  padding-top: 25px;     
  padding-bottom: 10px;  
  padding-left: 20px;    
  padding-right: 5px;   
  margin-top: 8px;
}

/* 连续虚线 */
.jc-divider-full {
  position: absolute;
  top: 85px;        
  bottom: 25px;     
  left: 50%;
  width: 3px;
  border-left: 3px dashed #caa3b4;
}

/* 左栏文字 */
.jc-left p {
  font-family: "ipxs","Product Sans",sans-serif !important;
  color: var(--color-font);
  line-height: 1.6;
  margin: 0;
}

/* 右栏文字 */
.jc-right p {
  font-family: "write","ZCOOL KuaiLe", cursive, sans-serif;
  color: var(--color-font);
  line-height: 1.6;
  margin: 0;
  font-weight: 600!important;
}



.jc-right h4 {
  margin: 0 0 8px 0;
  font-size: 1rem;
  color: #b78092!important;
  font-family: "ipxs","Product Sans",sans-serif !important;
}

/* 保留原本标题链接样式 */
.jc-title a {
  color: #8aa2d3!important;  
  border-bottom: 2px solid rgba(58, 111, 175, 0.4)!important;
  padding-bottom: 2px!important;
  line-height: 1.65!important;
  text-decoration: none;
  font-size: 1.55rem!important;
}
.jc-title a:hover {
  color: #87aac9!important;
  border-bottom: 2px solid rgba(94, 138, 192, 0.4)!important;
}

/* 尾注 */
.jc-footnote {
  position: absolute;
  left: 15px;      /* 左下角文字起点 */
  right: 15px;     /* 右下角圆点位置 */
  bottom: 10px;
  display: flex;
  justify-content: space-between; /* 左右分开 */
  align-items: center;
  font-size: 0.85rem;
  color: var(--color-font);
}

/* 左下文字 */
.jc-footnote .footnote-text {
 font-family: "ipxs","Product Sans",sans-serif !important;
}

/* 右下圆点容器 */
.jc-footnote .dots {
  display: flex;
  gap: 8px;       /* 圆点间距 */
}

/* 圆点样式 */
.jc-footnote .dot {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  display: inline-block;
}



/* 小屏上下布局 */
@media (max-width: 760px) {
  .jc-row {
    flex-direction: column;
  }
  .jc-divider-full {
    display: none;
  }
}

/*秋天*/

/* theme2 · 低饱和柔和橙 */

.journal-card.theme2 {
  background: #fff6eb;         
  border: 2px solid #d9a46d;    
  color: #76563a;
}

.journal-card.theme2 .jc-window-header {
  background: #ffe8c9;          
  color: #76563a;
}

.journal-card.theme2 .jc-window-title {
  color: inherit;
}

.journal-card.theme2 .jc-window-close {
  background: #d88d47;      
  color: #fff;    
}

.journal-card.theme2 .jc-window-menu {
  background: #f4d29c;         
  border-bottom: 1px solid #d9a46d;
  color: #76563a;
}

.journal-card.theme2 .jc-divider-full {
  border-left: 3px dashed #d9a46d;  
}

.journal-card.theme2 .jc-right h4 {
  color: #c96f55 !important;   
}

/*夏天*/

/* 夏天(低饱和度版)*/

.journal-card.theme3 {
  background: #f1f7f1;      
  border: 2px solid #a4cfa4; 
  color: #506450;
}

.journal-card.theme3 .jc-window-header {
  background: #dcefdc;     
  color: #4e634e;
}

.journal-card.theme3 .jc-window-title {
  color: inherit;
}

.journal-card.theme3 .jc-window-close {
  background: #a4cfa4;   
  color: #fff;
}

.journal-card.theme3 .jc-window-menu {
  background: #bcd5bc;      
  color: #4e634e;
  border-bottom: 1px solid #a4cfa4;
}

.journal-card.theme3 .jc-divider-full {
  border-left: 3px dashed #a4cfa4; 
}

.journal-card.theme3 .jc-right h4 {
  color: #7caf7c !important; 
}



/*冬天*/

.journal-card.theme4 {
  background: #f0f7ff; 
  border: 2px solid #8bb7d9;
  color: #42586d;
}

.journal-card.theme4 .jc-window-header {
  background: #d9ecff; 
  color: #42586d;
}

.journal-card.theme4 .jc-window-title {
  color: inherit;
}

.journal-card.theme4 .jc-window-close {
  background: #8bb7d9;
  color: #fff;
}

.journal-card.theme4 .jc-window-menu {
  background: #b4d4f0;
  color: #42586d;
  border-bottom: 1px solid #8bb7d9;
}

.journal-card.theme4 .jc-divider-full {
  border-left: 3px dashed #8bb7d9;
}

.journal-card.theme4 .jc-right h4 {
  color: #5f9dd0 !important; 
}

/*马戏团*/
.journal-card.theme5 {
  background: #f2f1f4; 
  border: 2px solid #4d4761; 
  color: #4d485f;
}

.journal-card.theme5 .jc-window-header {
  background: #e3e1e9; 
  color: #4d485f;
}

.journal-card.theme5 .jc-window-title {
  color: inherit;
}

.journal-card.theme5 .jc-window-close {
  background: #4d4761; 
  color: #fff;
}

.journal-card.theme5 .jc-window-menu {
  background: #bbb7c8; 
  color: #4d485f;
  border-bottom: 1px solid #4d4761;
}

.journal-card.theme5 .jc-divider-full {
  border-left: 3px dashed #4d4761;
}

.journal-card.theme5 .jc-right h4 {
  color: #6a6581 !important;
}


/*右下圆点*/

.jc-footnote .dot.one {
  background-color: #eec3d3;
}

.jc-footnote .dot.two {
  background-color: #caa3b4;
}

.jc-footnote .dot.three {
  background-color: #8a3c6b;
}

.jc-footnote .dot.four {
  background-color: #d9a46d;
}

.jc-footnote .dot.five {
  background-color: #c96f55;
}

.jc-footnote .dot.six {
  background-color: #76563a;
}
.jc-footnote .dot.seven {
  background-color: #a4cfa4;
}

.jc-footnote .dot.eight {
  background-color: #7caf7c;
}

.jc-footnote .dot.nine {
  background-color: #506450;
}
.jc-footnote .dot.ten {
  background-color: #8bb7d9;
}

.jc-footnote .dot.eleven {
  background-color: #5f9dd0;
}

.jc-footnote .dot.twelve {
  background-color: #42586d;
}

.jc-footnote .dot.thirteen {
  background-color: #bbb7c8;
}

.jc-footnote .dot.fourteen {
  background-color: #6a6581;
}

.jc-footnote .dot.fifteen {
  background-color: #4d485f;
}

/* 日期徽章,标题左上角,不影响布局 */
.jc-left .jc-date {
  display: inline-block;   /* 只包裹文字 */
  position: absolute;      /* 浮在标题左上角 */
  top: 35px;               /* 控制日期与标题的垂直距离,可调 */
  left: 0;                 /* 对齐标题左侧 */
  padding: 2px 6px; 
  color: #b78092;
  border-radius: 3px;
  font-size: 1em;
  font-weight: bold;
  line-height: 1.2;
  font-family: "ipxs","Product Sans",sans-serif !important;
  z-index: 1;
}

.jc-left .jc-date3 {
  display: inline-block;   /* 只包裹文字 */
  position: absolute;      /* 浮在标题左上角 */
  top: 35px;               /* 控制日期与标题的垂直距离,可调 */
  left: 0;                 /* 对齐标题左侧 */
  padding: 2px 6px; 
  color: #7caf7c;
  border-radius: 3px;
  font-size: 1em;
  font-weight: bold;
  line-height: 1.2;
  font-family: "ipxs","Product Sans",sans-serif !important;
  z-index: 1;
}

.jc-left .jc-date2 {
  display: inline-block;   /* 只包裹文字 */
  position: absolute;      /* 浮在标题左上角 */
  top: 35px;               /* 控制日期与标题的垂直距离,可调 */
  left: 0;                 /* 对齐标题左侧 */
  padding: 2px 6px; 
  color: #c96f55;
  border-radius: 3px;
  font-size: 1em;
  font-weight: bold;
  line-height: 1.2;
  font-family: "ipxs","Product Sans",sans-serif !important;
  z-index: 1;
}
.jc-left .jc-date4 {
  display: inline-block;   /* 只包裹文字 */
  position: absolute;      /* 浮在标题左上角 */
  top: 35px;               /* 控制日期与标题的垂直距离,可调 */
  left: 0;                 /* 对齐标题左侧 */
  padding: 2px 6px; 
  color: #5f9dd0;
  border-radius: 3px;
  font-size: 1em;
  font-weight: bold;
  line-height: 1.2;
  font-family: "ipxs","Product Sans",sans-serif !important;
  z-index: 1;
}

.jc-left .jc-date5 {
  display: inline-block;   /* 只包裹文字 */
  position: absolute;      /* 浮在标题左上角 */
  top: 35px;               /* 控制日期与标题的垂直距离,可调 */
  left: 0;                 /* 对齐标题左侧 */
  padding: 2px 6px; 
  color: #6a6581;
  border-radius: 3px;
  font-size: 1em;
  font-weight: bold;
  line-height: 1.2;
  font-family: "ipxs","Product Sans",sans-serif !important;
  z-index: 1;
}

因为css实在是太长,我单独把它分出来放在/static/css目录下了,所以最后要记得在用到这个批注的博客里引用css。

今年年终总结右栏批注部分的手写体用的是猫啃写意体并在css里默认加粗,我个人对这个字体的可爱和易读程度都挺满意的!不过这个字体有一个很明显的缺点是字库不全or损坏,像“嗑cp”的“嗑”和“岚少”的“岚”都没法显示,如果还有下次年终批注环节的话,打算再找一个新的手写体。

<link rel="stylesheet" href="/css/year.css">

最终效果如下:

标题
File Edit View Help
January.7th

博客标题

目录

批注内容

February.7th

下一个博客标题

又一个目录
br标签分行

下一个批注内容

左下角尾注

彩蛋:摆设的关闭按钮

想着要达到一种感谢大家来游玩我的年终总结的效果(?)所以就顺手做了!

关于博客弹窗的装修,可以参考■■Loading:《hugo装修日志09》■■,这个彩蛋就是在这个装修的基础上完成的,因此在这里只记录一下和窗口相关的html代码。

 <!-- 假关闭 窗口 -->
<div class="window" id="noclose-window">
  <div class="window-header">
  <div style="display: inline-block;"> 哎呀,非常抱歉! </div>
    <button class="close-btn" onclick="closeWindow('noclose-window')">
    <img src="https://img.naturaleki.one/lock/closebtn.png" />
    </button>
  </div>
  <div class="scrollable-content" id="extra">
   <p style="font-size: 22px; color: #8aa2d3;font-family: ipx; text-align: center;">这个关闭按钮好像是个摆设呢!</p>
   <p style="font-size: 22px; color: #8aa2d3;font-family: ipx; text-align: center;">不过我的关闭按钮是真的噢(ฅ•ω•ฅ)♡</p>
  <p style="font-size: 18px; color: #8aa2d3;font-family: ipx; text-align: center;">(为什么会有这个窗口呢,因为博主也经常会忍不住点一下(×_×)……)</p>
   </div>
</div>

Waline评论区数据库迁移

之前一直使用的Leancloud数据库将在2027年1月27日停止提供对外服务并销毁全部数据,搜索了一下选择迁移到了有5GB免费额度的TiDB Cloud,按照Waline官方手册教程里手把手的步骤设置好了新的数据库后,去vercel设置里删除Leancloud的环境变量改成TiDB,再Redeploy一下,服务端数据库就会自动迁移过去了。

评论区数据迁移可以直接使用Waline控制台自带的导入导出功能,不需要从Leancloud里导出再想办法导入TiDB。毕竟后者我也不会(。)最后记得数据要在修改环境变量之前提前下载好。

导入导出

一些查缺补漏

Waline不知道哪一次更新给自定义表情选项卡增加了一个十分碍眼的Preview,询问了一下GPT老师然后在自定义CSS里强行给它关掉了,顺便还添加了全新的hover放大,感谢小鱼场外的代码援助!

.wl-emoji-popup img:hover {
  transform: scale(1.35)!important;
}

.wl-emoji-preview {
  display: none !important;
}

页面切出时的标签页文字切换

2026.07.14 已删除

其实最早在拜访有这个设计的博客时就在馋此小巧思了,但不知为何居然(也)一直没装修。不过早装早享受晚装有朋友!感谢超级热心能干的卷毛羊酱倾情提供的现成js代码!

装修过程也很简单,只要把下面的代码放到\layous\partials\head.html里就行了,请GPT老师在羊羊原有的代码基础上又做了点个性化修改,增加了切回博客页面的文字变化随机文字的功能。

<script>
function pick(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

function initTitleEffect() {

  const originalTitle = document.title;

  const awayTitles = [
    "悄悄摸鱼中( ˘ω˘ ).。oO…",
    "捕捉宝可梦中ヾ(≧▽≦*)o…",
    "暴风吸入家产中(っ˘ڡ˘ς)…",
    "睡觉中(∪。∪)zzz…",
  ];

  const backTitles = [
    "哎呀!(;・∀・)",
    "哇啊啊!Σ(°Д°;)",
    "诶嘿!(´>ω∂`)☆",
    "げっ!(°ー°〃)",
  ];

  let hasHidden = false;
  let timer = null;

  document.addEventListener("visibilitychange", () => {

    if (document.hidden) {
      hasHidden = true;

      clearTimeout(timer);
      document.title = pick(awayTitles);

    } else {
      if (hasHidden) {
        document.title = pick(backTitles);

        timer = setTimeout(() => {
          document.title = originalTitle;
        }, 700);

        hasHidden = false;
      } else {
        document.title = originalTitle;
      }
    }
  });

  window.addEventListener("pageshow", () => {
    clearTimeout(timer);
    document.title = originalTitle;
  });

}

initTitleEffect();
</script>

PJAX

老生常谈的问题,因为博客装了局部刷新的pjax,所以最初切回页面时标签文字的显示会出现bug,遂继续请GPT老师给原有js代码暴力封装了初始化函数。

<script>
function pick(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

function initTitleEffect() {

  const originalTitle = document.title;

  // 👇 可选“离开时”标题
  const awayTitles = [
    "悄悄摸鱼中( ˘ω˘ ).。oO…",
    "捕捉宝可梦中ヾ(≧▽≦*)o…",
    "暴风吸入家产中(っ˘ڡ˘ς)…",
    "睡觉中(∪。∪)zzz…",
  ];

  // 👇 可选“回来时”标题
  const backTitles = [
    "哎呀!(;・∀・)",
    "哇啊啊!Σ(°Д°;)",
    "诶嘿!(´>ω∂`)☆",
    "げっ!(°ー°〃)",
  ];

  let hasHidden = false;
  let timer = null;

  if (window.__titleEffectBound) return;
  window.__titleEffectBound = true;

  document.addEventListener("visibilitychange", () => {

    if (document.hidden) {
      hasHidden = true;

      clearTimeout(timer);
      document.title = pick(awayTitles);

    } else {
      if (hasHidden) {
        document.title = pick(backTitles);

        timer = setTimeout(() => {
          document.title = originalTitle;
        }, 700);

        hasHidden = false;
      } else {
        document.title = originalTitle;
      }
    }
  });

  window.addEventListener("pageshow", () => {
    clearTimeout(timer);
    document.title = originalTitle;
  });

}

// 初始化一次
initTitleEffect();

// ===== PJAX 修复 =====
document.addEventListener("pjax:complete", () => {

  window.__titleEffectBound = false;

  setTimeout(() => {
    document.title = document.querySelector("title").innerText;
    initTitleEffect();
  }, 0);

});
</script>

装完后我忽然意识到我以后好像可以利用这个功能来更新近期动态(?

DLC1:Library页面

总感觉在上一篇博客装修日志封笔还没到一个月又开一篇新装修日志这一行为多少有些微妙,遂效仿2号装修日志直接在这里追加DLC

之前博客冲浪时就经常在漂亮的博客里看到用于展示喜欢东西的博物馆页面。起初觉得自己喜欢的游戏数量实在太多,光是决定展示哪些作品就足够纠结半天,就一直没有将其列入博客装修的to do计划。但现在博客即将迎来四周年大寿(?),必须得想办法装修点什么,于是这个Library页面就在一周的摸鱼时间里诞生了。

因为我想在页面中展示的游戏和动漫数量加起来有40多个,所以最好还是先创建一个json专门录入数据,然后让Hugo模板循环读取json内容批量生成页面元素。这样可以避免手动排版编写大量重复html的麻烦,后续维护起来也比较方便。由于Fuji主题默认没有提供data文件夹,因此可以直接在博客根目录新建一个,然后再在该文件夹里创建museum.json,复制下面的模板:

{
  "games": [
    {
      "title": "精灵宝○梦",
      "cover": "https://img.○○○○○.○○○/ne○○○○○ta/b○○○○k.jpg",
      "copy": "ポケット○○スター"
    },
    {
      "title": "逆○裁判 成○堂精选集",
      "cover": "https://img.○○○○○.○○○/ne○○○○○ta/g○○○○n.jpg",
      "copy": "逆○裁判123 成○堂セレクション"
    }
  ],
  "anime": [
    {
      "title": "○魂",
      "cover": "https://img.○○○○○.○○○/ne○○○○○ta/○○○tama.jpg",
      "copy": "○魂"
    },
    {
      "title": "文豪○犬",
      "cover": "https://img.○○○○○.○○○/ne○○○○○ta/b○d.jpg",
      "copy": "文豪○○○○ドッグス"
    }
  ]
}

这里的copy是用于设置文字复制功能的自定义内容,具体用法会在后面说明。

下一步是编写用于页面引入的html代码框架,在\layouts\shortcodes内新建library.html,复制以下内容。这个html里面除了将JSON数据处理转换为海报展示页面外,还包含了放在页面最前面的介绍卡片和最后面的歌单展示区域的设计,不过具体音乐播放器的MetingJS引入部分我是直接写在了对应的md文件里。

<div class="museum-intro">

  <img 
    class="museum-deco left"
    src="https://img.naturaleki.one/neversista/npc1.png"
  >

  <div class="museum-intro-content">

    <h1>
      Read me.txt
    </h1>

    <p>
      这里登记着一部分管理员喜欢的作品。
    </p>

    <p>
      点击卡片下方的作品名称,即可复制其对应原名。
    </p>

  </div>


  <img 
    class="museum-deco right"
    src="https://img.naturaleki.one/neversista/npc2.png"
  >

</div>

<section class="museum-section">

<h2 class="museum-title">
  <img src="https://img.naturaleki.one/neversista/game.png">
  游戏
</h2>

  <div class="game-library">
    {{ range site.Data.museum.games }}
      <div class="game-card">
        <img data-fancybox src="{{ .cover }}" alt="{{ .title }}">

        <p
          class="museum-copy-text"
          data-copy="{{ .copy }}"
          title="点击复制"
          tabindex="0"
          role="button"
        >
          {{ .title }}
        </p>
      </div>
    {{ end }}
  </div>

<h2 class="museum-title">
  <img src="https://img.naturaleki.one/neversista/manga.png">
  动漫
</h2>

  <div class="game-library">
    {{ range site.Data.museum.anime }}
      <div class="game-card">
        <img data-fancybox src="{{ .cover }}" alt="{{ .title }}">

        <p
          class="museum-copy-text"
          data-copy="{{ .copy }}"
          title="点击复制"
          tabindex="0"
          role="button"
        >
          {{ .title }}
        </p>
      </div>
    {{ end }}
  </div>

<h2 class="museum-title">
  <img src="https://img.naturaleki.one/neversista/music.png">
  音乐
</h2>

</section>

\static\css中新建library.css,注入排版灵魂。

/* Museum Intro Card */

.museum-intro {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;

  min-height: 180px;
  margin: 2rem 0 3rem;
  padding: 2rem 5rem;

  background: #f8fbff;
  border: 2px solid #d8e3f5;
  border-radius: 18px;

  box-shadow: 2px 2px 0 rgba(138,162,211,.18);

  overflow: hidden;
}

.museum-intro-content {
  width: 80%;
  max-width: 600px;
  font-family: ipx;
  text-align: center;
}

.museum-intro h1 {
  margin: 0 0 1rem;

  color: #8aa2d3;
  font-size: 1.8rem;
  font-family: ipxs;
}

.museum-intro p {
  margin: .5rem 0;

  line-height: 1.8;
  color: #667;
}

.museum-deco {
  position: absolute;

  width: 80px;
  height: 80px;

  object-fit: contain;
  image-rendering: pixelated;
}

.museum-deco.left {
  left: 1.1rem;
}

.museum-deco.right {
  right: 1.1rem;
}

@media(max-width:600px){

  .museum-intro {
    padding: 2rem 1rem;
  }

  .museum-intro-content {
    width: 85%;
  }

  .museum-deco {
    width: 50px;
    height: 50px;
  }

}

.post-title::before,
.post-title::after {
  content: "";
  display: inline-block;

  width: 36px;
  height: 36px;

  background-image: url("https://img.naturaleki.one/neversista/love.png");
  background-size: contain;
  background-repeat: no-repeat;

  image-rendering: pixelated;

  vertical-align: middle;
  transform: translateY(-5px);
}


/* ===========================
   Game Library
=========================== */

.game-library {
  width: 98%;
  margin: 2rem auto;

  display: grid;
  grid-template-columns: repeat(5, 1fr);

  column-gap: .8rem;
  row-gap: 1.5rem;
}

.game-card {
  display: flex;
  flex-direction: column;
  gap: .2rem;

  text-decoration: none !important;
  color: inherit;
}

.game-card img {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;

  border-radius: 5px;
  background: #f3f3f3;
}

.game-card p {
  margin: 0 !important;
  padding: 0;

  text-align: center;
  font-size: 1rem;
  line-height: 1.25;
  font-weight: 500;
  font-family: ipxs;
  color: #8aa2d3;
}

/* Section Title */
.museum-title {
  display: flex;
  align-items: center;
  margin: 3rem 0 1.5rem;
  font-size: 1.5rem;
  font-weight: 600;
  color: #8aa2d3;
}

.museum-title img {
  width: 30px;
  height: 30px;
  margin-right: 5px;
  object-fit: contain;
  image-rendering: pixelated;
  transform: translateY(4px);
}

/* Responsive */
@media(max-width:1000px){
  .game-library {
    grid-template-columns: repeat(4,minmax(0,1fr));
  }
}

@media(max-width:800px){
  .game-library {
    grid-template-columns: repeat(3,minmax(0,1fr));
  }
}

@media(max-width:600px){
  .game-library {
    grid-template-columns: repeat(2,minmax(0,1fr));
  }
}

@media(max-width:600px){
  .museum-intro {
    min-height: auto;
    padding: 6rem 1.2rem 2rem;
  }
  .museum-intro-content {
    width: 100%;
    max-width: none;
  }
  .museum-deco {
    width: 52px;
    height: 52px;
    top: 1.5rem;
    bottom: auto;
  }
  .museum-deco.left {
    left: 2rem;
  }
  .museum-deco.right {
    right: 2rem;
  }
  .museum-intro h1 {
    margin: 0 0 1rem;
    font-size: 1.55rem;
  }
  .museum-intro p {
    font-size: .95rem;
    line-height: 1.7;
  }
}

然后记得要在刚才短代码的html中引入css。

<link rel="stylesheet" href="/css/library.css">

接着,在/content里新建neversista.md,引入短代码html。

+++
title = "爱之间"
description = "画廊,展柜,玩具箱,冠军殿堂"
showLicense = false
showToc = false
showComments = false
showkudos= false
disablePangu= true
+++
    
{{< library >}}

这样,一个可供访问的页面就装修完毕了。最后参考■■Loading:《hugo装修日志09》■■中关于侧栏导航样式修改的部分,将这个页面加入博客侧栏导航后,天堂错误文件的爱之间便堂堂上线啦!

点击文字复制作品原名功能

由于我在实际浏览Library页面时,总是会忍不住会以希望获得一些交互反馈为目的去点击海报下方的作品名称,但又不太想给每个文字做跳转外链。思考了一会,意识到或许可以做一个点击文字后自动复制游戏或动漫对应日文或英文原名的功能,这样万一能安利到来造访的朋友的话,就可以方便他们直接去搜索(图穷匕见)。于是询问了伟大的GPT老师,让它给我编写了相应的js代码,直接用<script>标签包裹起来贴进library.html里即可。

(function () {
  function copyMuseumText(event) {
    const item = event.target.closest(".museum-copy-text");

    if (!item) return;

    const text = item.dataset.copy;

    if (!text) return;

    function showCopied() {
      const originalText = item.textContent;

      item.textContent = "复制成功!";

      window.setTimeout(function () {
        item.textContent = originalText;
      }, 1200);
    }

    if (navigator.clipboard && window.isSecureContext) {
      navigator.clipboard.writeText(text)
        .then(showCopied)
        .catch(function () {
          fallbackCopy(text);
          showCopied();
        });
    } else {
      fallbackCopy(text);
      showCopied();
    }
  }

  function fallbackCopy(text) {
    const textarea = document.createElement("textarea");

    textarea.value = text;
    textarea.style.position = "fixed";
    textarea.style.left = "-9999px";
    textarea.style.opacity = "0";

    document.body.appendChild(textarea);

    textarea.focus();
    textarea.select();

    document.execCommand("copy");

    textarea.remove();
  }

  document.addEventListener("click", copyMuseumText);

  document.addEventListener("keydown", function (event) {
    if (event.key !== "Enter" && event.key !== " ") return;

    const item = event.target.closest(".museum-copy-text");

    if (!item) return;

    event.preventDefault();
    item.click();
  });
})();

PJAX

请在此处输入文字。

(function () {
  function copyMuseumText(event) {
    const item = event.target.closest(".museum-copy-text");

    if (!item) return;

    const text = item.dataset.copy;

    if (!text) return;

    function showCopied() {
      const originalText = item.textContent;

      item.textContent = "复制成功!";

      window.setTimeout(function () {
        item.textContent = originalText;
      }, 1200);
    }

    if (navigator.clipboard && window.isSecureContext) {
      navigator.clipboard.writeText(text)
        .then(showCopied)
        .catch(function () {
          fallbackCopy(text);
          showCopied();
        });
    } else {
      fallbackCopy(text);
      showCopied();
    }
  }

  function fallbackCopy(text) {
    const textarea = document.createElement("textarea");

    textarea.value = text;
    textarea.style.position = "fixed";
    textarea.style.left = "-9999px";
    textarea.style.opacity = "0";

    document.body.appendChild(textarea);
    textarea.focus();
    textarea.select();

    document.execCommand("copy");
    textarea.remove();
  }

  /*
   * 使用事件委托,只绑定一次。
   * PJAX 替换页面内容后,新生成的标题仍然可以点击复制。
   */
  if (!window.museumCopyInitialized) {
    document.addEventListener("click", copyMuseumText);

    document.addEventListener("keydown", function (event) {
      if (event.key !== "Enter" && event.key !== " ") return;

      const item = event.target.closest(".museum-copy-text");

      if (!item) return;

      event.preventDefault();
      item.click();
    });

    window.museumCopyInitialized = true;
  }

  /*
   * Fuji PJAX 页面切换完成后保留接口。
   * 因为用了事件委托,这里不需要重新绑定。
   */
  document.addEventListener("pjax:complete", function () {
    // 无需重复初始化
  });
})();

后记

不知不觉又炼成了一篇时间跨度长达半年多的装修日志啊。其实这期间还有一部分维护时的debug记录没有写进去,比如netlify自动续证书失败,waline评论区前端显示问题,以及cf worker在不知情情况下被注入神秘钓鱼验证网站页面……但感觉确实没什么好展开的,因此仅在这里简单罗列一下就好了!