TOC
1. 构建想法
看到一些有趣的图片thiings ,之前也有做shakagame,我觉得还是可以好好做一些有趣,有意思的小型应用或游戏。
2. 原则
原则是个好东西,可以在发生冲突的时候帮助决策,所以在构建之前,确定这几个原则:
- 简单:越简单越好,至少初期,不要不必要的功能,样式,从设计上就要去掉;
- 模块化:减少工作量,方便一处修改,全部可用;
- 快速构建:拿来主义,不重复造轮子(网上有的,不依赖其他库的,就用)。
- 代码清晰,带注释。
- 多用Gemini
3. 开始构建
创建网站
xdl@MacBook-Air ~/Documents/github % hugo new site aimlobo-2 --format yaml
Congratulations! Your new Hugo site was created in /Users/xdl/Documents/github/aimlobo-2.
Just a few more steps...
1. Change the current directory to /Users/xdl/Documents/github/aimlobo-2.
2. Create or install a theme:
- Create a new theme with the command "hugo new theme <THEMENAME>"
- Or, install a theme from https://themes.gohugo.io/
3. Edit hugo.yaml, setting the "theme" property to the theme name.
4. Create new content with the command "hugo new content <SECTIONNAME>/<FILENAME>.<FORMAT>".
5. Start the embedded web server with the command "hugo server --buildDrafts".
See documentation at https://gohugo.io/.
xdl@MacBook-Air ~/Documents/github % cd aimlobo-2
xdl@MacBook-Air ~/Documents/github/aimlobo-2 % hugo new theme aimlobo
Creating new theme in /Users/xdl/Documents/github/aimlobo-2/themes/aimlobo
xdl@MacBook-Air ~/Documents/github/aimlobo-2 % code .
然后删除~/themes/aimlobo/下的演示内容。
这个时候可以生成Favicon :
上传你想要的图标的图片,然后按照说明一步步往下走;
填写要把图标放在哪里
下载文件即可,然后把网站上提供的内容复制到后边的编辑head/meta.html部分。
编辑~/hugo.yaml
baseURL: https://aimlobo.com/
title: Aimlobo
theme: aimlobo
# language
defaultContentLanguage: en
defaultContentLanguageInSubdir: true
languages:
en:
contentDir: content/en
disabled: false
languageCode: en
languageDirection: ltr
languageName: English
weight: 100
zh-hant:
contentDir: content/zh-hant
disabled: false
languageCode: zh-Hant
languageDirection: ltr
languageName: 繁體中文
weight: 200
zh-hans:
contentDir: content/zh-hans
disabled: false
languageCode: zh-Hans
languageDirection: ltr
languageName: 简体中文
weight: 300
params:
slogan: head_slogan # site slogan
play_slogan: play_slogan # play slogan, used in app page
description: head_description
outputs:
home:
- HTML
- JSON
# not wanted
disableHugoGeneratorInject: true
disableRSS: true
disableKinds:
- taxonomy
- term
markup:
goldmark:
renderer:
unsafe: true
# 这是为了hugo可以读取npm安装的库并进行复制
module:
mounts:
- source: assets
target: assets
- source: node_modules
target: assets/node_modules
编辑~/themes/aimlobo/layouts/partials/head
这一版不考虑theme,所以:
{{ partial "head/extend_top.html" . }}
{{ partial "head/meta.html" . }}
{{ partial "head/css.html" . }}
{{ partial "head/js.html" . }}
{{ partial "head/extend_bottom.html" . }}
partial "文件名":用于调用一个可复用的模板。.:表示当前页面的上下文对象,包含了所有数据。partial "文件名" .:用于将当前页面的数据传递给 partial 模板,让它能够访问和使用这些数据。
所以,在你的 Hugo 项目中,当你需要一个 partial 模板来访问调用它的页面的任何信息(比如文章标题、分类、日期等)时,你就需要使用 {{ partial “search-box” . }} 这种语法。如果你调用的 partial 模板不需要任何页面信息,那么只写 {{ partial “header” }} 也是可以的。
1. 编辑head/meta.html
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="
{{- with .Params.description -}}
{{- . -}}
{{- else -}}
{{- with site.Params.description -}}
{{- T . -}}
{{- end -}}
{{- end -}}
">
<title>
{{- if .IsHome -}}
{{- printf "%s - %s - %s" site.Title (T site.Params.slogan) (T site.Params.play_slogan) -}}
{{- else -}}
{{- printf "%s - %s | %s" .Title (T site.Params.play_slogan) site.Title -}}
{{- end -}}
</title>
{{- /* Favicons */}}
<link rel="icon" type="image/png" href="/assets/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/assets/favicon/favicon.svg" />
<link rel="shortcut icon" href="/assets/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="Aimlobo" />
<link rel="manifest" href="/assets/favicon/site.webmanifest" />
<link rel="canonical" href="{{- site.BaseURL -}}">
{{- with site.Languages -}}
{{ range . }}
<link rel="alternate" href="{{- site.BaseURL -}}{{- .LanguageCode -}}" hreflang="{{- .LanguageCode -}}">
{{- end -}}
{{- end -}}
2. 编辑head/css.html
{{- /*
定义一个可复用的模板,用于生成 <link> 标签。
该模板会根据 Hugo 的环境(开发或生产)自动添加指纹(fingerprint)和子资源完整性(SRI)属性,
以确保资源的缓存高效和内容完整性。
*/ -}}
{{- define "cssTag" -}}
{{- $style := . -}}
{{- if eq hugo.Environment "development" -}}
<link rel="stylesheet" href="{{ $style.RelPermalink }}">
{{- else -}}
{{- with $style | fingerprint -}}
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{- end -}}
{{- end -}}
{{- end -}}
{{- /*
为开发和生产环境设置 PostCSS 构建选项。
在生产环境(非 development)下,启用 CSS 压缩(minify),以减小文件体积。
*/ -}}
{{- $cssBuildOpts := dict "minify" (not (eq hugo.Environment "development")) -}}
{{- /*
加载第三方 CSS 库 (cssLibs)。
这些库通常通过 npm 安装,并从 pages Front Matter 中的 .Params.cssLibs 参数中获取。
每个库都会被独立处理和加载,以利用浏览器的长期缓存机制。
*/ -}}
{{- with .Params.cssLibs -}}
{{- range . -}}
{{- /* 获取 npm 包资源 */ -}}
{{- $style := resources.Get . -}}
{{- if $style -}}
{{- /* 将资源从 node_modules 复制到 public 目录,确保可被浏览器访问 */ -}}
{{- $style = $style | resources.Copy (printf "css/%s.css" (path.BaseName $style)) -}}
{{- /* 调用可复用模板,生成带指纹和完整性校验的 <link> 标签 */ -}}
{{- template "cssTag" $style -}}
{{- else -}}
{{- /* 如果资源未找到,则发出警告 */ -}}
{{- warnf "无法找到 CSS 资源:%s" . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- /*
加载全局 CSS (main.css)。
该文件是网站的基础样式入口,通常包含通过 @import 导入的其他样式。
使用 PostCSS 管道进行处理,并生成带指纹的 <link> 标签。
*/ -}}
{{- with resources.Get "css/main.css" | postCSS $cssBuildOpts -}}
{{- template "cssTag" . -}}
{{- end -}}
{{- /*
加载页面自定义 CSS (css)。
这些文件通过页面的 Front Matter 参数 .Params.css 声明。
为了减少 HTTP 请求,所有自定义 CSS 文件都会被合并成一个,并进行构建和压缩。
*/ -}}
{{- with .Params.css -}}
{{- $cssFiles := slice -}}
{{- range . -}}
{{- $cssFiles = $cssFiles | append (resources.Get .) -}}
{{- end -}}
{{- /* 生成一个基于页面路径和标题的唯一合并文件名,避免文件名冲突 */ -}}
{{- $pageCssPath := printf "%s-%s" .Path .Title | base64Encode -}}
{{- $mergedCss := $cssFiles | resources.Concat (printf "css/%s-merged.css" $pageCssPath) | postCSS $cssBuildOpts -}}
{{- /* 调用可复用模板,生成最终的 <link> 标签 */ -}}
{{- template "cssTag" $mergedCss -}}
{{- end -}}
说下逻辑:
- 如果有外部CSS库,那么在页面的front matter中cssLibs下写明文件路径,目前的代码是按照所有外部内容都使用npm安装来写的,注意文件要使用minify过了的版本;
- 加载全站通用的main.css,和其他文件区分开,虽说加载次数增加了,但是好处在于可以利用浏览器缓存;
- 加载页面需要的自定义的section.css等,说明下,合并的文件名称采用页面所在的路径+名称(Path + Title) 然后使用
base64Encode编码以生成唯一的名称。
3. 编辑head/js.html
{{- /*
定义一个可复用的模板来生成 <script> 标签。
它会根据环境自动添加指纹和完整性属性,确保资源的安全加载和缓存。
*/ -}}
{{- define "jsTag" -}}
{{- $script := . -}}
{{- if eq hugo.Environment "development" -}}
<script type="module" src="{{ $script.RelPermalink }}" defer></script>
{{- else -}}
{{- with $script | fingerprint -}}
<script type="module" src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous" defer></script>
{{- end -}}
{{- end -}}
{{- end -}}
{{- /*
为开发和生产环境设置 JavaScript 构建选项。
在生产环境(非 development)下,启用压缩(minify)。
"target" 设置为 ES2018,确保代码兼容主流浏览器。
*/ -}}
{{- $jsBuildOpts := dict "minify" (not (eq hugo.Environment "development")) "target" "es2018" -}}
{{- /*
加载第三方 JavaScript 库 (jsLibs)。
这些库通常通过 npm 安装,并通过页面的 Front Matter 参数 .Params.jsLibs 声明。
遍历列表,Hugo 会处理每个文件,并独立加载以最大化浏览器缓存效果。
*/ -}}
{{- with .Params.jsLibs -}}
{{- range . -}}
{{- /* 获取 npm 包资源 */ -}}
{{- $script := resources.Get . -}}
{{- if $script -}}
{{- /* 将资源从 node_modules 复制到 public 目录,确保可被浏览器访问 */ -}}
{{- $script = $script | resources.Copy (printf "js/%s.js" (path.BaseName $script)) -}}
{{- /* 调用可复用模板,生成带指纹和完整性校验的 <script> 标签 */ -}}
{{- template "jsTag" $script -}}
{{- else -}}
{{- /* 如果资源未找到,发出警告 */ -}}
{{- warnf "无法找到 JS 资源:%s" . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- /*
加载全局 JS (main.js)。
该文件通常包含全站通用的功能,如导航、基础交互等。
使用 js.Build 管道处理,并生成带指纹的 <script> 标签。
*/ -}}
{{- with resources.Get "js/main.js" | js.Build $jsBuildOpts -}}
{{- template "jsTag" . -}}
{{- end -}}
{{- /*
加载页面自定义 JS (js)。
这些文件通过页面的 Front Matter 参数 .Params.js 声明。
为了减少 HTTP 请求,将所有自定义 JS 文件合并成一个,并进行构建和压缩。
*/ -}}
{{- with .Params.js -}}
{{- $jsFiles := slice -}}
{{- range . -}}
{{- $jsFiles = $jsFiles | append (resources.Get .) -}}
{{- end -}}
{{- /* 生成一个基于页面路径和标题的唯一合并文件名,避免冲突 */ -}}
{{- $pageJsPath := printf "%s-%s" .Path .Title | base64Encode -}}
{{- $mergedJs := $jsFiles | resources.Concat (printf "js/%s-merged.js" $pageJsPath) | js.Build $jsBuildOpts -}}
{{- /* 调用可复用模板,生成最终的 <script> 标签 */ -}}
{{- template "jsTag" $mergedJs -}}
{{- end -}}
说下逻辑:
- 如果有外部JS库,那么在页面的front matter中jsLibs下写明文件路径,目前的代码是按照所有外部内容都使用npm安装来写的,注意文件要使用minify过了的版本;
- 加载全站通用的main.js,和其他文件区分开,虽说加载次数增加了,但是好处在于可以利用浏览器缓存;
- 加载页面需要的自定义的section.js等,说明下,合并的文件名称采用页面所在的路径+名称(Path + Title) 然后使用
base64Encode编码以生成唯一的名称。
编辑~/assets/css/
根据hugo中模块化css的说明,安装插件:
xdl@MacBook-Air ~/Documents/github/aimlobo-2 % npm install postcss postcss-cli postcss-import autoprefixer --save-dev
added 68 packages in 4s
22 packages are looking for funding
run `npm fund` for details
在项目根目录创建 postcss.config.js 文件:
module.exports = {
plugins: [
require('postcss-import')({
path: ['assets/css'] // 指定 CSS 模块的基准路径
}),
require('autoprefixer') // 可选:添加浏览器前缀
]
}
安装一个animate.css
第三方库,用来实现一些CSS相关的动画效果:
xdl@MacBook-Air ~/Documents/github/aimlobo-2 % npm install animate.css --save-dev
added 2 packages, and audited 71 packages in 642ms
22 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
说明:
--save-dev: 将包添加到 devDependencies。这通常用于项目开发时所必需的工具和库,例如打包工具(Webpack, Gulp)、测试框架、CSS 预处理器(PostCSS, Sass)以及你所使用的 animate.css。对于 animate.css 这样的 CSS 库,它是在你的 Hugo 网站构建时被处理,而不是在网站运行时被用户浏览器下载和执行的。因此,它更适合被归类为开发依赖。
安装音频库:
xdl@MacBook-Air ~/Documents/github/aimlobo-2 % npm install howler
added 1 package, and audited 72 packages in 680ms
22 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
这里没有-save-dev是因为howler.js是一个音频库,它需要在用户的浏览器中运行,以便播放音频。因此,它是你项目功能的一部分,属于运行时依赖。
文件基础结构:
xdl@MacBook-Air ~/Documents/github/aimlobo-2/assets/css % tree
.
├── _basic.css
├── _reset.css
├── _typography.css
├── _var.css
└── main.css
1 directory, 5 files
后期每个页面有自己的需求,就创建相应的文件夹然后section.css等就好。
逐一说明下:
1. _reset.css
重置浏览器的所有默认CSS样式。
/*
Modern Reset
See https://hankchizljaw.com/wrote/a-modern-css-reset/
Note: This file uses some CSS variables and thus cannot be wholly updated via copy+paste.
*/
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Remove default margin */
* {
margin: 0;
}
ul,
ol {
list-style: none;
padding: 0;
}
/* Set core root defaults */
html {
scroll-behavior: smooth;
}
/* body {
-webkit-font-smoothing: antialiased;
} */
/* A elements that don't have a class get default styles */
a:not([class]) {
text-decoration-skip-ink: auto;
}
a {
text-decoration: none;
}
/* Make images easier to work with */
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
img {
height: auto;
}
/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
}
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords;
}
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
hyphens: auto;
}
p {
text-wrap: pretty;
}
h1,
h2,
h3,
h4,
h5,
h6 {
text-wrap: balance;
}
2. _typography.css
网站会用到的字体:
@font-face {
font-family: 'Mija';
src: url('/assets/fonts/Mija_Bold-webfont-subset-v2.woff2') format('woff2');
font-weight: bold;
font-style: normal;
font-display: swap;
unicode-range: U+0000-007F; /* 覆盖 ASCII 的 0-127 号字符 */
}
@font-face {
font-family: 'Torus';
src: url('/assets/fonts/torus-bold-latin.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
unicode-range: U+0000-007F; /* 覆盖 ASCII 的 0-127 号字符 */
}
@font-face {
font-family: 'Proxima Nova';
src: url('/assets/fonts/proxima-nova-bold-latin.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
unicode-range: U+0000-007F; /* 覆盖 ASCII 的 0-127 号字符 */
}
@font-face {
font-family: 'Proxima Nova';
src: url('/assets/fonts/proxima-nova-regular-latin.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0000-007F; /* 覆盖 ASCII 的 0-127 号字符 */
}
我这里因为这个字体只需要英文的部分,所以有个unicode-range: U+0000-007F;,浏览器可以只加载这128个字符,有利于减少不必要的流量消耗;
当然要在~/statics/assets/fonts/下边放置这些字体文件。
3. _var.css
存储CSS变量,好处不用多说:一处更改,处处适用,但是相应的也需要在各个地方都尽可能使用变量以便统一。另外有个不方便的地方:目前是hugo v0.147.7,如果后期编辑_var.css这个文件,每次编辑后都需要重新hugo server才能看到变化的地方,这是因为这个文件是被import到_basic.css(该文件又被import到main.css),我不知道原因,但我猜测是import的缓存问题。反正只要是被import的CSS文件发生变化,就重新启动服务就好。
4. _basic.css
这个文件可以用来放针对要搭建的网站而独立于其他项目的内容。比如前三个_reset.css, _typography.css, _var.css 这些内容可以在不同项目间通用,那么这个文件就可以放个性化的东西,当然也可以在main.css中来操作。