Browse Source

更新依赖项,新增样式文件,优化Markdown渲染

- 在package.json中添加了extend-shallow、koa-helmet和koa-ratelimit等依赖
- 新增markdown-reset.scss和markdown-green.scss样式文件,增强Markdown内容的样式支持
- 更新公共样式,改善响应式设计,提升用户体验
- 在中间件中集成了安全性和速率限制功能,增强应用的安全性
pure
谢亚昕 3 months ago
parent
commit
e67238e42e
  1. BIN
      bun.lockb
  2. 5
      package.json
  3. 677
      public/css/layouts/markdown-reset.scss
  4. 1188
      public/scss-compiler/page/index/_global.css
  5. 136
      public/scss-compiler/page/index/index.css
  6. 1188
      public/scss-compiler/page/index/markdown-green.css
  7. 1188
      public/scss-compiler/page/index/markdown-reset.css
  8. 1188
      public/scss-compiler/page/index/style.css
  9. 2
      src/logger.js
  10. 12
      src/main.js
  11. 83
      src/middlewares/PugHelper/sass.js
  12. 10
      src/middlewares/Views/index.js
  13. 71
      src/middlewares/install.js
  14. 89
      src/utils/ForRegister.js
  15. 20
      src/utils/cache/RouteCache.js
  16. 34
      src/views/layouts/empty.pug
  17. 0
      src/views/page/index/_global.scss
  18. 22
      src/views/page/index/index copy.pug
  19. 25
      src/views/page/index/index.pug
  20. 316
      src/views/page/index/markdown-green.scss
  21. 677
      src/views/page/index/markdown-reset.scss
  22. 0
      src/views/page/index/style.scss
  23. 0
      src/views/temp/person.pug

BIN
bun.lockb

Binary file not shown.

5
package.json

@ -32,16 +32,18 @@
"@koa/etag": "^5.0.1", "@koa/etag": "^5.0.1",
"bcryptjs": "^3.0.2", "bcryptjs": "^3.0.2",
"consolidate": "^1.0.4", "consolidate": "^1.0.4",
"extend-shallow": "^3.0.2",
"formidable": "^3.5.4", "formidable": "^3.5.4",
"get-paths": "^0.0.7", "get-paths": "^0.0.7",
"image-thumbnail": "^1.0.17", "image-thumbnail": "^1.0.17",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"jstransformer-markdown-it": "^3.0.0", "jstransformer-markdown-it": "^3.0.0",
"jstransformer-scss": "^2.0.0",
"knex": "^3.1.0", "knex": "^3.1.0",
"koa": "^3.0.0", "koa": "^3.0.0",
"koa-bodyparser": "^4.4.1", "koa-bodyparser": "^4.4.1",
"koa-conditional-get": "^3.0.0", "koa-conditional-get": "^3.0.0",
"koa-helmet": "^8.0.1",
"koa-ratelimit": "^6.0.0",
"koa-session": "^7.0.2", "koa-session": "^7.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"log4js": "^6.9.1", "log4js": "^6.9.1",
@ -51,6 +53,7 @@
"path-to-regexp": "^8.2.0", "path-to-regexp": "^8.2.0",
"pretty": "^2.0.0", "pretty": "^2.0.0",
"pug": "^3.0.3", "pug": "^3.0.3",
"sass": "^1.92.1",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"svg-captcha": "^1.4.0" "svg-captcha": "^1.4.0"
}, },

677
public/css/layouts/markdown-reset.scss

@ -0,0 +1,677 @@
/* 深色主题媒体查询 - 当用户系统偏好深色模式时应用 */
@media (prefers-color-scheme: dark) {
.markdown-body {
/* 告诉浏览器使用深色配色方案,影响滚动条等系统UI元素 */
color-scheme: dark;
}
}
/* 浅色主题媒体查询 - 当用户系统偏好浅色模式时应用 */
@media (prefers-color-scheme: light) {
// https://verytoolz.com/blog/03bfb3598f/
.markdown-body {
/* 告诉浏览器使用浅色配色方案,影响滚动条等系统UI元素 */
color-scheme: light;
/* 定义CSS自定义属性,用于主题色彩管理 */
--color-fg-default: #24292f; // 文本色-默认 - 主要文本颜色
--color-fg-muted: #57606a; // 文本色-柔和 - 次要文本颜色
--color-fg-subtle: #6e7781; // 文本色-微妙 - 最淡的文本颜色
--color-canvas-default: #ffffff; // 底色-默认 - 主要背景颜色
--color-canvas-subtle: #f6f8fa; // 底色-微妙 - 次要背景颜色
--color-border-default: #d0d7de; // 边框色-默认 - 主要边框颜色
--color-border-muted: hsla(210, 18%, 87%, 1); // 边框色-柔和 - 次要边框颜色
--color-neutral-muted: rgba(175, 184, 193, 0.2); // 边框色-中性 - 中性边框颜色
--color-accent-fg: #0969da; // 文本强调色 - 强调文本颜色
--color-accent-emphasis: #0969da; // 背景强调色 - 强调背景颜色
--color-attention-subtle: #fff8c5; // 背景注意色 - 注意提示背景色
--color-danger-fg: #cf222e; // 文本危险色 - 危险/错误文本颜色
--color-mark-default: rgb(255, 255, 0); // mark 默认色 - 标记默认背景色
--color-mark-fg: rgb(255, 187, 0); // mark 强调色 - 标记强调背景色
}
}
/* Markdown内容主体样式 - 用于渲染Markdown文档的容器 */
.markdown-body {
/* 防止iOS Safari自动调整文本大小 */
-webkit-text-size-adjust: 100%;
/* 防止IE自动调整文本大小 */
-ms-text-size-adjust: 100%;
/* 优化文本渲染质量,提升可读性 */
text-rendering: optimizelegibility;
/* 重置外边距为0 */
margin: 0;
/* 允许长单词在必要时换行,防止溢出 */
word-wrap: break-word;
/* 使用CSS变量设置文本颜色 */
color: var(--color-fg-muted);
/* 伪元素before - 用于清除浮动 */
&::before {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 空内容,仅用于布局 */
content: "";
}
/* 伪元素after - 用于清除浮动 */
&::after {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 清除左右浮动 */
clear: both;
/* 空内容,仅用于布局 */
content: "";
}
/* 第一个子元素 - 移除顶部外边距 */
> *:first-child {
/* 强制移除顶部外边距,避免不必要的空白 */
margin-top: 0 !important;
}
/* 最后一个子元素 - 移除底部外边距 */
> *:last-child {
/* 强制移除底部外边距,避免不必要的空白 */
margin-bottom: 0 !important;
}
/* 块级元素统一间距设置 - 段落、引用、列表、表格等 */
p,
blockquote,
ul,
ol,
dl,
table,
hr,
form,
pre,
details {
/* 移除顶部外边距,避免重复间距 */
margin-top: 0;
/* 设置底部外边距为1em,保持适当间距 */
margin-bottom: 1em;
}
/* 引用块内部元素间距处理 */
blockquote {
/* 引用块内第一个子元素 - 移除顶部外边距 */
& > :first-child {
margin-top: 0;
}
/* 引用块内最后一个子元素 - 移除底部外边距 */
& > :last-child {
margin-bottom: 0;
}
}
/* 统一显示成块状元素 - 确保这些元素独占一行 */
details,
figcaption,
figure {
/* 设置为块级元素,独占一行显示 */
display: block;
}
/* HTML5 媒体文件跟 img 保持一致 - 内联块级元素 */
audio,
canvas,
video {
/* 设置为内联块级元素,可以设置宽高但不会独占一行 */
display: inline-block;
}
/* 按钮内部间距统一 - 移除Firefox默认内边距 */
button::-moz-focus-inner,
input::-moz-focus-inner {
/* 移除Firefox浏览器按钮和输入框的内部内边距 */
padding: 0;
/* 移除Firefox浏览器按钮和输入框的内部边框 */
border: 0;
}
/* 定义元素显示为斜体 - 术语定义样式 */
dfn {
/* 设置字体为斜体,用于术语定义 */
font-style: italic;
}
/* 去掉各Table cell 的边距并让其边重合 - 表格样式统一 */
table {
/* 合并表格边框,相邻单元格边框合并为一条 */
border-collapse: collapse;
/* 设置表格单元格间距为0 */
border-spacing: 0;
/* 设置为块级元素,可以设置宽高 */
display: block;
/* 宽度根据内容自适应 */
width: max-content;
/* 最大宽度不超过父容器 */
max-width: 100%;
/* 内容溢出时显示滚动条 */
overflow: auto;
}
/* 可拖动文件添加拖动手势 - 拖拽元素样式 */
[draggable] {
/* 设置鼠标悬停时显示移动光标 */
cursor: move;
}
/* 加粗元素 - 粗体文本样式 */
b,
strong {
/* 设置字体粗细,使用CSS变量或默认600 */
font-weight: var(--base-text-weight-semibold, 600);
}
/* 缩写元素样式统一 - 缩写和首字母缩写样式 */
abbr,
acronym {
/* 移除底部边框 */
border-bottom: none;
/* 设置字体变体为正常 */
font-variant: normal;
/* 设置虚线下划线装饰 */
text-decoration: underline dotted;
}
/* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */
abbr {
/* 设置鼠标悬停时显示帮助光标 */
cursor: help;
}
/* 一致的 del 样式 - 删除线文本样式 */
del {
/* 设置文本装饰为删除线 */
text-decoration: line-through;
}
/* a标签去除下划线 - 链接样式处理 */
a {
/* 默认移除下划线,保持页面简洁 */
text-decoration: none;
/* 没有href属性的链接样式 */
&:not([href]) {
/* 继承父元素颜色 */
color: inherit;
/* 移除下划线装饰 */
text-decoration: none;
}
/* 鼠标悬停时显示下划线 */
&:hover {
text-decoration: underline;
}
}
/* 默认不显示下划线,保持页面简洁 - 插入文本样式 */
ins {
/* 移除下划线装饰,保持页面简洁 */
text-decoration: none;
}
/* 专名号虽然 u 已经重回 html5 Draft但在所有浏览器中都是可以使用的
* 要做到更好向后兼容的话添加 class="typo-u" 来显示专名号
* 关于 <u> 标签http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-u-element
* 被放弃的是 4之前一直搞错 http://www.w3.org/TR/html401/appendix/changes.html#idx-deprecated
* 一篇关于 <u> 标签的很好文章http://html5doctor.com/u-element/
*/
u,
.typo-u {
/* 设置文本装饰为下划线,用于专名号显示 */
text-decoration: underline;
}
/* 隐藏指定元素 - 隐藏带有hidden属性的元素 */
[hidden] {
/* 强制隐藏元素,优先级最高 */
display: none !important;
}
/* 伸缩框显示为列表元素 - 详情框摘要样式 */
summary {
/* 设置为列表项显示,显示为可点击的列表项 */
display: list-item;
}
/* 引用元素前后内容 - 移除默认引号 */
q:before,
q:after {
/* 移除引用元素前后的默认引号内容 */
content: "";
}
/* 表格标题和表头文本对齐 - 默认左对齐 */
caption,
th {
/* 设置文本左对齐 */
text-align: left;
}
/* 居中对齐的表格标题和表头 */
caption[align="center"],
th[align="center"] {
/* 设置文本居中对齐 */
text-align: center;
}
/* 特定元素字体粗细统一 - 地址、标题、引用等 */
address,
caption,
cite,
em,
th,
var {
/* 设置字体粗细为正常(400) */
font-weight: 400;
}
/* 标记,类似于手写的荧光笔的作用 - 高亮标记样式 */
mark {
/* 设置标记背景色,使用CSS变量 */
background: var(--color-mark-default);
// background: #fffdd1; // 备用背景色
// border-bottom: 1px solid #ffedce; // 备用底部边框
/* 设置内边距,增加标记的可读性 */
padding: 2px;
/* 激活状态的标记样式 */
&.active {
/* 激活时使用强调色背景 */
background: var(--color-mark-fg);
}
// margin: 0 5px; // 备用外边距
}
/* 统一h1元素的间隔和字体大小 - 一级标题样式 */
h1 {
/* 设置上下外边距为0.67em */
margin: 0.67em 0;
/* 设置字体粗细,使用CSS变量或默认600 */
font-weight: var(--base-text-weight-semibold, 600);
/* 设置字体大小为2倍基础大小 */
font-size: 2em;
}
/* small字体缩小 - 小字体文本样式 */
small {
/* 设置字体大小为父元素的90% */
font-size: 90%;
}
/* 上下标显示 - 下标和上标文本样式 */
sub,
sup {
/* 设置字体大小为75% */
font-size: 75%;
/* 设置行高为0,避免影响行间距 */
line-height: 0;
/* 设置相对定位,用于精确控制位置 */
position: relative;
/* 设置垂直对齐为基线 */
vertical-align: baseline;
}
/* 上下标内链接样式 */
sub a,
sup a {
/* 设置左右内边距为0.1em */
padding: 0 0.1em;
}
/* 下标位置调整 */
sub {
/* 向下偏移0.25em */
bottom: -0.25em;
}
/* 上标位置调整 */
sup {
/* 向上偏移0.5em */
top: -0.5em;
}
/* 代码相关的字体大小统一 - 代码元素字体样式 */
code,
kbd,
pre,
samp,
pre tt {
/* 设置字体为等宽字体,便于代码阅读 */
font-family: monospace;
/* 设置字体大小为1em,保持一致性 */
font-size: 1em;
}
/* 去除默认边框 - 移除字段集和图片的默认边框 */
fieldset,
img {
/* 移除边框 */
border: 0;
}
/* 图片初始化样式 - 图片元素基础样式 */
img {
/* 设置边框样式为无 */
border-style: none;
/* 设置最大宽度为100%,防止溢出 */
max-width: 100%;
/* 设置盒模型为内容盒模型 */
box-sizing: content-box;
/* 设置左右外边距为自动,实现居中 */
margin: 0 auto;
/* 设置背景色,使用CSS变量 */
background-color: var(--color-canvas-default);
}
/* 可附标题内容元素的间距 - 图片容器样式 */
figure {
/* 设置上下外边距为1em,左右外边距为40px */
margin: 1em 40px;
}
/* 间隔线 - 水平分隔线样式 */
/* 一致化 horizontal rule - 统一水平分隔线样式 */
hr {
/* 设置盒模型为内容盒模型 */
box-sizing: content-box;
/* 隐藏溢出内容 */
overflow: hidden;
/* 设置背景为透明 */
background: transparent;
/* 设置底部边框,使用CSS变量 */
border-bottom: 1px solid var(--color-border-muted);
/* 设置高度为0.25em */
height: 0.25em;
/* 移除内边距 */
padding: 0;
/* 设置上下外边距为24px */
margin: 24px 0;
/* 设置背景色,使用CSS变量 */
background-color: var(--color-border-default);
/* 移除边框 */
border: 0;
/* 伪元素before - 用于清除浮动 */
&::before {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 空内容,仅用于布局 */
content: "";
}
/* 伪元素after - 用于清除浮动 */
&::after {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 清除左右浮动 */
clear: both;
/* 空内容,仅用于布局 */
content: "";
}
}
/* 表单元素并不继承父级 font 的问题 - 表单元素字体继承 */
button,
input,
select,
textarea {
/* 继承父元素的字体样式 */
font: inherit;
/* 移除外边距 */
margin: 0;
/* 设置溢出为可见 */
overflow: visible;
/* 继承父元素的字体族 */
font-family: inherit;
/* 继承父元素的字体大小 */
font-size: inherit;
/* 继承父元素的行高 */
line-height: inherit;
}
/* 外观显示为按钮 - 按钮类型输入框样式 */
[type="button"],
[type="reset"],
[type="submit"] {
/* 设置WebKit浏览器按钮外观 */
-webkit-appearance: button;
/* 设置标准按钮外观,提高兼容性 */
appearance: button;
}
/* 这两个表单样式规则覆盖 - 复选框和单选框样式 */
[type="checkbox"],
[type="radio"] {
/* 设置盒模型为边框盒模型 */
box-sizing: border-box;
/* 移除内边距 */
padding: 0;
}
/* 数字按钮内部高度自动 - 数字输入框按钮样式 */
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
/* 设置高度为自动,适应内容 */
height: auto;
}
/* 搜索按钮内图标外观去除 - 搜索输入框样式 */
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
/* 移除WebKit浏览器搜索框默认样式 */
-webkit-appearance: none;
}
/* 输入框的占位符样式 - WebKit浏览器占位符样式 */
::-webkit-input-placeholder {
/* 继承父元素颜色 */
color: inherit;
/* 设置透明度为0.54,创建半透明效果 */
opacity: 0.54;
}
/* 文件选择按钮样式统一 - 文件上传按钮样式 */
::-webkit-file-upload-button {
/* 设置WebKit浏览器按钮外观 */
-webkit-appearance: button;
/* 继承父元素字体样式 */
font: inherit;
}
/* 占位符显示统一 - 通用占位符样式 */
::placeholder {
/* 设置占位符颜色,使用CSS变量 */
color: var(--color-fg-subtle);
/* 设置完全不透明 */
opacity: 1;
}
/* table内的td,th去除留白 - 表格单元格样式 */
td,
th {
/* 移除表格单元格内边距 */
padding: 0;
}
/* 伸缩框鼠标显示 - 详情框摘要样式 */
details summary {
/* 设置鼠标悬停时显示手型光标 */
cursor: pointer;
}
/* 未展开的详情框隐藏内容 - 详情框内容显示控制 */
details:not([open]) > *:not(summary) {
/* 强制隐藏未展开详情框内的非摘要内容 */
display: none !important;
}
/* 按键显示 - 键盘按键样式 */
kbd {
/* 设置为内联块级元素,可以设置宽高但不会独占一行 */
display: inline-block;
/* 设置内边距为3px上下,5px左右 */
padding: 3px 5px;
/* 设置字体为11px等宽字体,包含多种等宽字体备选 */
font: 11px ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
/* 设置行高为10px */
line-height: 10px;
/* 设置文本颜色,使用CSS变量 */
color: var(--color-fg-default);
/* 设置垂直对齐为中间 */
vertical-align: middle;
/* 设置背景色,使用CSS变量 */
background-color: var(--color-canvas-subtle);
/* 设置边框为1px实线,使用CSS变量 */
border: solid 1px var(--color-neutral-muted);
/* 设置底部边框颜色,使用CSS变量 */
border-bottom-color: var(--color-neutral-muted);
/* 设置圆角为6px */
border-radius: 6px;
/* 设置内阴影,创建按键凹陷效果 */
box-shadow: inset 0 -1px 0 var(--color-neutral-muted);
}
/* 清除浮动工具类 - 清除浮动伪元素 */
.clearfix:before,
.clearfix:after {
/* 空内容,仅用于布局 */
content: "";
/* 设置为表格显示模式,用于清除浮动 */
display: table;
}
/* 清除浮动工具类 - after伪元素 */
.clearfix:after {
/* 清除左右浮动 */
clear: both;
}
/* 清除浮动工具类 - 主容器 */
.clearfix {
/* 触发IE的hasLayout属性,用于清除浮动 */
zoom: 1;
}
/* 强制文本换行 - 文本换行工具类 */
.textwrap,
.textwrap td,
.textwrap th {
/* 允许长单词在必要时换行,防止溢出 */
word-wrap: break-word;
/* 强制在任意字符间换行,防止溢出 */
word-break: break-all;
}
/* 文本换行表格 - 固定表格布局 */
.textwrap-table {
/* 设置表格布局为固定,提高渲染性能 */
table-layout: fixed;
}
/* 无序列表样式 - 项目符号列表 */
ul {
/* 重置左边距为0 */
margin-left: 0;
/* 重置左内边距为0 */
padding-left: 0;
/* 设置左边距为2em,创建缩进效果 */
margin-left: 2em;
/* 设置列表样式为实心圆点 */
list-style: disc;
}
/* 有序列表样式 - 数字列表 */
ol {
/* 重置左边距为0 */
margin-left: 0;
/* 重置左内边距为0 */
padding-left: 0;
/* 设置左边距为2em,创建缩进效果 */
margin-left: 2em;
/* 设置列表样式为数字 */
list-style: decimal;
/* 列表项样式 */
li {
/* 设置左内边距为0.4em,增加数字与文本间距 */
padding-left: 0.4em;
}
}
/* 相邻列表项间距 - 列表项之间的间距 */
li + li {
/* 设置顶部外边距为0.25em,增加列表项间距 */
margin-top: 0.25em;
}
/* 嵌套列表样式 - 列表项内的子列表 */
li {
/* 无序子列表样式 */
ul {
/* 设置底部外边距为0.8em */
margin-bottom: 0.8em;
/* 设置左边距为2em,创建嵌套缩进 */
margin-left: 2em;
/* 设置列表样式为空心圆点 */
list-style: circle;
/* 三级无序列表样式 */
li {
ul {
/* 设置列表样式为实心方块 */
list-style: square;
}
}
}
/* 有序子列表样式 */
ol {
/* 设置底部外边距为0.8em */
margin-bottom: 0.8em;
/* 设置左边距为2em,创建嵌套缩进 */
margin-left: 2em;
}
}
/* 任务列表项样式 - 待办事项列表项 */
.task-list-item {
/* 移除列表样式,不显示项目符号 */
list-style-type: none;
/* 设置相对定位,用于绝对定位子元素 */
position: relative;
/* 第一个子输入框样式 */
> input {
/* 第一个子元素右边距 */
&:nth-child(1) {
/* 设置右边距为6px */
margin-right: 6px;
}
}
/* 标签样式 */
label {
/* 设置字体粗细为正常(400) */
font-weight: 400;
}
/* 拖拽手柄样式 */
.handle {
/* 隐藏拖拽手柄 */
display: none;
}
/* 复选框样式 */
input[type="checkbox"] {
/* 设置宽度为0.9em */
width: 0.9em;
/* 设置高度为0.9em */
height: 0.9em;
/* 设置绝对定位 */
position: absolute;
/* 向左偏移1.3em */
left: -1.3em;
/* 向下偏移0.35em */
top: 0.35em;
}
}
/* 启用的任务列表项样式 */
.task-list-item.enabled {
/* 标签样式 */
label {
/* 设置鼠标悬停时显示手型光标 */
cursor: pointer;
}
}
/* 相邻任务列表项间距 */
.task-list-item + .task-list-item {
/* 设置顶部外边距为3px */
margin-top: 3px;
}
/* 包含任务列表的容器样式 */
.contains-task-list {
// margin-left: 0.6em; // 备用左边距
/* 从右到左文本方向样式 */
&:dir(rtl) {
.task-list-item {
input[type="checkbox"] {
/* 设置复选框外边距,适配RTL布局 */
margin: 0 -1.6em 0.25em 0.2em;
}
}
}
}
/* 目录样式 - 表格目录容器 */
.toc {
/* 重置左边距为0 */
margin-left: 0;
}
/* 定义列表样式 - 描述列表容器 */
dl {
/* 设置为块级元素 */
display: block;
/* 设置块级起始外边距为1em */
margin-block-start: 1em;
/* 设置块级结束外边距为1em */
margin-block-end: 1em;
/* 设置内联起始外边距为0px */
margin-inline-start: 0px;
/* 设置内联结束外边距为0px */
margin-inline-end: 0px;
/* 设置Unicode双向算法为隔离 */
unicode-bidi: isolate;
/* 定义术语样式 */
dt {
/* 设置为块级元素 */
display: block;
/* 设置Unicode双向算法为隔离 */
unicode-bidi: isolate;
}
/* 定义描述样式 */
dd {
/* 设置为块级元素 */
display: block;
/* 设置内联起始外边距为40px,创建缩进效果 */
margin-inline-start: 40px;
/* 设置Unicode双向算法为隔离 */
unicode-bidi: isolate;
}
}
}

1188
public/scss-compiler/page/index/_global.css

File diff suppressed because it is too large

136
public/scss-compiler/page/index/index.css

@ -0,0 +1,136 @@
@charset "UTF-8";
/* 首页样式 */
.hero-section {
position: relative;
overflow: hidden;
}
.hero-section::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url("/images/hero-bg.svg") no-repeat center center;
background-size: cover;
opacity: 0.1;
z-index: 0;
}
.hero-content {
position: relative;
z-index: 1;
}
.feature-card {
transition: all 0.3s ease;
}
.feature-card:hover {
transform: translateY(-5px);
}
.feature-card .material-symbols-light--article,
.feature-card .material-symbols-light--bookmark,
.feature-card .material-symbols-light--person {
transition: all 0.3s ease;
}
.feature-card:hover .material-symbols-light--article,
.feature-card:hover .material-symbols-light--bookmark,
.feature-card:hover .material-symbols-light--person {
transform: scale(1.1);
}
.stats-section {
position: relative;
}
.stats-section::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url("/images/stats-bg.svg") no-repeat center center;
background-size: cover;
opacity: 0.05;
z-index: 0;
}
.stat-item {
transition: all 0.3s ease;
}
.stat-item:hover {
transform: scale(1.05);
}
.user-dashboard {
position: relative;
}
.user-dashboard::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url("/images/dashboard-bg.svg") no-repeat center center;
background-size: cover;
opacity: 0.03;
z-index: 0;
}
.avatar {
transition: all 0.3s ease;
}
.avatar:hover {
transform: scale(1.05);
}
/* 响应式设计 */
@media (max-width: 768px) {
.hero-section {
padding: 4rem 0;
}
.hero-content h1 {
font-size: 2.5rem;
}
.features-grid {
grid-template-columns: 1fr;
}
.stats-grid {
grid-template-columns: 1fr 1fr;
}
.user-info {
text-align: center;
margin-bottom: 1.5rem;
}
.user-actions {
justify-content: center;
}
}
@media (max-width: 480px) {
.hero-content h1 {
font-size: 2rem;
}
.hero-content p {
font-size: 1rem;
}
.stats-grid {
grid-template-columns: 1fr;
}
.hero-actions {
flex-direction: column;
gap: 1rem;
}
.hero-actions a {
width: 100%;
text-align: center;
}
}

1188
public/scss-compiler/page/index/markdown-green.css

File diff suppressed because it is too large

1188
public/scss-compiler/page/index/markdown-reset.css

File diff suppressed because it is too large

1188
public/scss-compiler/page/index/style.css

File diff suppressed because it is too large

2
src/logger.js

@ -46,7 +46,7 @@ log4js.configure({
type: "console", type: "console",
layout: { layout: {
type: "pattern", type: "pattern",
pattern: '\x1b[36m[%d{yyyy-MM-dd hh:mm:ss}]\x1b[0m \x1b[1m[%p]\x1b[0m %m', pattern: '\x1b[90m[%d{hh:mm:ss}]\x1b[0m \x1b[1m[%p]\x1b[0m %m',
}, },
}, },
}, },

12
src/main.js

@ -31,13 +31,11 @@ const PORT = process.env.PORT || 3000;
return "localhost" return "localhost"
} }
const localIP = getLocalIP() const localIP = getLocalIP()
logger.trace(`──────────────────── 服务器已启动 ────────────────────`) logger.info(`🚀 服务器已启动`)
logger.trace(` `) logger.info(` 本地访问: http://localhost:${port}`)
logger.trace(` 本地访问: http://localhost:${port} `) logger.info(` 局域网: http://${localIP}:${port}`)
logger.trace(` 局域网: http://${localIP}:${port} `) logger.info(` 启动时间: ${new Date().toLocaleString()}`)
logger.trace(` `) logger.info(`────────────────────────────────────────`)
logger.trace(` 服务启动时间: ${new Date().toLocaleString()} `)
logger.trace(`──────────────────────────────────────────────────────\n`)
}) })

83
src/middlewares/PugHelper/sass.js

@ -0,0 +1,83 @@
const path = require("path")
const sass = require("sass")
const extend = require("extend-shallow")
exports.name = "scss"
exports.outputFormat = "css"
exports.render = function (str, options) {
const includePaths = [
path.parse(options.filename).dir,
...options.includePaths,
]
const input = extend({}, options, { data: str, includePaths })
// TODO: Replace with sass.compileString()
const out = sass.renderSync(input)
return {
body: out.css.toString(),
dependencies: out.stats.includedFiles.map(filename => {
return path.resolve(filename)
}),
}
}
exports.renderAsync = function (str, options) {
const input = extend({}, options, { data: str })
return new Promise((resolve, reject) => {
// TODO: Replace with sass.compileStringAsync()
sass.render(input, (err, out) => {
if (err) {
return reject(err)
}
return resolve({
body: out.css.toString(),
dependencies: out.stats.includedFiles.map(filename => {
return path.resolve(filename)
}),
})
})
})
}
exports.renderFile = function (filename, options) {
const input = extend({}, options, {
file: path.resolve(filename),
})
// TODO: Replace with sass.compile()
const out = sass.renderSync(input)
return {
body: out.css.toString(),
dependencies: out.stats.includedFiles
.map(filename => {
return path.resolve(filename)
})
.filter(name => {
return name !== filename
}),
}
}
exports.renderFileAsync = function (filename, options) {
const input = extend({}, options, { file: path.resolve(filename) })
return new Promise((resolve, reject) => {
// TODO: Replace with sass.compileAsync()
sass.render(input, (err, out) => {
if (err) {
return reject(err)
}
return resolve({
body: out.css.toString(),
dependencies: out.stats.includedFiles
.map(filename => {
return path.resolve(filename)
})
.filter(name => {
return name !== filename
}),
})
})
})
}

10
src/middlewares/Views/index.js

@ -24,15 +24,7 @@ function viewsMiddleware(path, { engineSource = consolidate, extension = "html",
currentPath: ctx.path, currentPath: ctx.path,
} }
const state = assign( const state = assign(
{ {},
filters: {
"my-own-filter": function (text, options) {
if (options.addStart) text = "Start\n" + text
if (options.addEnd) text = text + "\nEnd"
return text
},
},
},
otherData, otherData,
locals, locals,
options, options,

71
src/middlewares/install.js

@ -13,6 +13,10 @@ import conditional from "koa-conditional-get"
import { autoRegisterControllers } from "@/utils/ForRegister.js" import { autoRegisterControllers } from "@/utils/ForRegister.js"
import performanceMonitor from "./RoutePerformance/index.js" import performanceMonitor from "./RoutePerformance/index.js"
import app from "@/global" import app from "@/global"
import fs from "fs"
import helmet from "koa-helmet"
import ratelimit from "koa-ratelimit"
import { render } from "./PugHelper/sass.js"
import { SiteConfigService } from "services/SiteConfigService.js" import { SiteConfigService } from "services/SiteConfigService.js"
import config from "config/index.js" import config from "config/index.js"
@ -46,10 +50,46 @@ export default async app => {
} }
return await next() return await next()
}) })
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "'unsafe-inline'"],
},
},
})
)
// apply rate limit
const db = new Map()
app.use(
ratelimit({
driver: "memory",
db: db,
duration: 60000,
errorMessage: "Sometimes You Just Have to Slow Down.",
id: ctx => ctx.ip,
headers: {
remaining: "Rate-Limit-Remaining",
reset: "Rate-Limit-Reset",
total: "Rate-Limit-Total",
},
max: 100,
disableHeader: false,
whitelist: ctx => {
// some logic that returns a boolean
},
blacklist: ctx => {
// some logic that returns a boolean
},
})
)
app.use(async (ctx, next) => { app.use(async (ctx, next) => {
// 提供全局数据 // 提供全局数据
ctx.state.siteConfig = await SiteConfigService.getAll() ctx.state.siteConfig = await SiteConfigService.getAll()
ctx.state.base = config.base ctx.state.$config = config
return await next() return await next()
}) })
// 错误处理,主要处理运行中抛出的错误 // 错误处理,主要处理运行中抛出的错误
@ -64,6 +104,35 @@ export default async app => {
extension: "pug", extension: "pug",
options: { options: {
basedir: resolve(__dirname, "../views"), basedir: resolve(__dirname, "../views"),
filters: {
"my-own-filter": function (text, options) {
if (options.addStart) text = "Start\n" + text
if (options.addEnd) text = text + "\nEnd"
return text
},
scss: function (text, options) {
//- process.env.SASS_PATH = "D:/@code/demo/koa3-demo/src/views/page/index"
const root = path.resolve(__dirname, "../views")
const publicPath = path.resolve(__dirname, "../../public")
const publicScssPath = path.resolve(publicPath, "scss-compiler")
const result = render(text, {
...options,
includePaths: [...(options.includePaths || []), path.resolve(__dirname, "../views")],
})
const links = []
// result.dependencies.forEach(file => {
// const scssFile = path.resolve(publicScssPath, path.relative(root, file))
// const cssFile = scssFile.replace(path.extname(scssFile), ".css")
// if (!fs.existsSync(scssFile)) {
// fs.mkdirSync(path.parse(scssFile).dir, { recursive: true })
// }
// fs.writeFileSync(cssFile, result.body)
// links.push(cssFile)
// })
return `${links.map(v=>`<link rel="stylesheet" href="${config.base + path.relative(publicPath, v).replaceAll("\\", "/")}">`).join("\n")}
<style>${result.body}</style>`
},
},
}, },
}) })
) )

89
src/utils/ForRegister.js

@ -10,7 +10,6 @@ if (import.meta.env.PROD) {
// 通过引用返回值,防止被摇树优化 // 通过引用返回值,防止被摇树优化
let controllers = import.meta.glob("../controllers/**/*Controller.js", { eager: true }) let controllers = import.meta.glob("../controllers/**/*Controller.js", { eager: true })
controllers = null controllers = null
console.log(controllers);
} }
/** /**
@ -45,7 +44,7 @@ export async function autoRegisterControllers(app, controllersDir) {
if (cachedRoutes) { if (cachedRoutes) {
// 缓存命中,直接使用缓存结果 // 缓存命中,直接使用缓存结果
allRouter.push(...cachedRoutes) allRouter.push(...cachedRoutes)
logger.info(`[控制器注册] ✨ ${file} - 从缓存加载路由成功`) logger.debug(`[控制器注册] ✨ ${file} - 从缓存加载`)
continue continue
} }
@ -92,9 +91,9 @@ export async function autoRegisterControllers(app, controllersDir) {
// 根据缓存状态显示不同的日志信息 // 根据缓存状态显示不同的日志信息
const cacheEnabled = routeCache.config.enabled const cacheEnabled = routeCache.config.enabled
if (cacheEnabled) { if (cacheEnabled) {
logger.info(`[控制器注册] ✅ ${file} - 路由创建成功,已缓存`) logger.debug(`[控制器注册] ✅ ${file} - 已缓存`)
} else { } else {
logger.info(`[控制器注册] ✅ ${file} - 路由创建成功`) logger.debug(`[控制器注册] ✅ ${file} - 创建成功`)
} }
} else { } else {
logger.warn(`[控制器注册] ⚠️ ${file} - createRoutes() 返回的不是有效的路由器对象`) logger.warn(`[控制器注册] ⚠️ ${file} - createRoutes() 返回的不是有效的路由器对象`)
@ -124,43 +123,97 @@ export async function autoRegisterControllers(app, controllersDir) {
return return
} }
logger.info(`[路由注册] 📋 发现 ${allRouter.length} 个控制器,开始注册到应用`) logger.info(`[路由注册] 📋 发现 ${allRouter.length} 个控制器,开始注册`)
// 按顺序注册路由,确保中间件执行顺序 // 按顺序注册路由,确保中间件执行顺序
const routeTable = []
let totalRoutes = 0
for (let i = 0; i < allRouter.length; i++) { for (let i = 0; i < allRouter.length; i++) {
const router = allRouter[i] const router = allRouter[i]
try { try {
app.use(router.middleware()) app.use(router.middleware())
logger.debug(`[路由注册] 🔗 路由 ${i + 1}/${allRouter.length} 注册成功`)
// 枚举并紧凑输出该路由器下的所有路由方法与路径(单行聚合) // 收集路由信息
const methodEntries = Object.entries(router.routes || {}) const methodEntries = Object.entries(router.routes || {})
const items = [] const routes = []
for (const [method, list] of methodEntries) { for (const [method, list] of methodEntries) {
if (!Array.isArray(list) || list.length === 0) continue if (!Array.isArray(list) || list.length === 0) continue
for (const r of list) { for (const r of list) {
if (!r || !r.path) continue if (!r || !r.path) continue
items.push(`${method.toUpperCase()} ${r.path}`) routes.push({
method: method.toUpperCase(),
path: r.path,
fullPath: `${method.toUpperCase()} ${r.path}`
})
} }
} }
if (items.length > 0) {
const prefix = router.options && router.options.prefix ? router.options.prefix : "" if (routes.length > 0) {
logger.info(`[路由注册] ✅ ${prefix || "/"}${items.length} 条 -> ${items.join("; ")}`) const prefix = router.options && router.options.prefix ? router.options.prefix : "/"
} else { routeTable.push({
logger.warn(`[路由注册] ⚠️ 该控制器未包含任何可用路由`) prefix: prefix,
count: routes.length,
routes: routes
})
totalRoutes += routes.length
} }
} catch (error) { } catch (error) {
logger.error(`[路由注册] ❌ 路由 ${i + 1}/${allRouter.length} 注册失败: ${error.message}`) logger.error(`[路由注册] ❌ 路由注册失败: ${error.message}`)
} }
} }
logger.info(`[路由注册] ✅ 完成!成功注册 ${allRouter.length} 个控制器路由`) // 输出表格形式的路由摘要
if (routeTable.length > 0) {
logger.info(`[路由注册] ✅ 注册完成!`)
logger.info(`+===============================================================+`)
logger.info(`| 路由注册摘要表 |`)
logger.info(`+===============================================================+`)
logger.info(`| 前缀路径 | 数量 | 路由详情 |`)
logger.info(`+===============================================================+`)
routeTable.forEach(({ prefix, count, routes }) => {
const prefixStr = prefix.padEnd(28)
const countStr = count.toString().padStart(3)
const routesStr = routes.map(r => r.fullPath).join(', ')
// 如果路由详情太长,分行显示
if (routesStr.length > 40) {
const lines = []
let currentLine = ''
const routeParts = routesStr.split(', ')
for (const part of routeParts) {
if (currentLine.length + part.length + 2 > 40) {
lines.push(currentLine)
currentLine = part
} else {
currentLine += (currentLine ? ', ' : '') + part
}
}
if (currentLine) lines.push(currentLine)
// 输出第一行
logger.info(`| ${prefixStr} | ${countStr} | ${lines[0].padEnd(40)} |`)
// 输出剩余行
for (let i = 1; i < lines.length; i++) {
logger.info(`| ${' '.repeat(28)} | ${' '.repeat(3)} | ${lines[i].padEnd(40)} |`)
}
} else {
logger.info(`| ${prefixStr} | ${countStr} | ${routesStr.padEnd(40)} |`)
}
})
logger.info(`+===============================================================+`)
logger.info(`| 总计: ${totalRoutes} 条路由,${routeTable.length} 个控制器组 |`)
logger.info(`+===============================================================+`)
}
// 输出缓存统计信息 // 输出缓存统计信息
const cacheStats = routeCache.getStats() const cacheStats = routeCache.getStats()
logger.info(`[路由缓存] 缓存状态: ${cacheStats.enabled ? '启用' : '禁用'}, 总命中率: ${cacheStats.hitRate}`)
if (cacheStats.enabled) { if (cacheStats.enabled) {
logger.debug(`[路由缓存] 详细统计:`, cacheStats.caches) logger.debug(`[路由缓存] 状态: 启用, 命中率: ${cacheStats.hitRate}`)
} }
} catch (error) { } catch (error) {

20
src/utils/cache/RouteCache.js

@ -49,7 +49,7 @@ class RouteCache extends BaseSingleton {
enabled: config.routeCache?.enabled ?? (process.env.NODE_ENV === 'production') enabled: config.routeCache?.enabled ?? (process.env.NODE_ENV === 'production')
} }
logger.info(`[路由缓存] 初始化完成,缓存状态: ${this.config.enabled ? '启用' : '禁用'}`) logger.debug(`[路由缓存] 初始化完成,状态: ${this.config.enabled ? '启用' : '禁用'}`)
} }
/** /**
@ -256,7 +256,7 @@ class RouteCache extends BaseSingleton {
this.stats[key] = 0 this.stats[key] = 0
}) })
logger.info('[路由缓存] 所有缓存已清除') logger.debug('[路由缓存] 所有缓存已清除')
} }
/** /**
@ -264,7 +264,7 @@ class RouteCache extends BaseSingleton {
*/ */
clearRouteMatches() { clearRouteMatches() {
this.matchCache.clear() this.matchCache.clear()
logger.info('[路由缓存] 路由匹配缓存已清除') logger.debug('[路由缓存] 路由匹配缓存已清除')
} }
/** /**
@ -272,7 +272,7 @@ class RouteCache extends BaseSingleton {
*/ */
clearControllers() { clearControllers() {
this.controllerCache.clear() this.controllerCache.clear()
logger.info('[路由缓存] 控制器实例缓存已清除') logger.debug('[路由缓存] 控制器实例缓存已清除')
} }
/** /**
@ -280,7 +280,7 @@ class RouteCache extends BaseSingleton {
*/ */
clearMiddlewares() { clearMiddlewares() {
this.middlewareCache.clear() this.middlewareCache.clear()
logger.info('[路由缓存] 中间件组合缓存已清除') logger.debug('[路由缓存] 中间件组合缓存已清除')
} }
/** /**
@ -288,7 +288,7 @@ class RouteCache extends BaseSingleton {
*/ */
clearRegistrations() { clearRegistrations() {
this.registrationCache.clear() this.registrationCache.clear()
logger.info('[路由缓存] 路由注册缓存已清除') logger.debug('[路由缓存] 路由注册缓存已清除')
} }
/** /**
@ -306,7 +306,7 @@ class RouteCache extends BaseSingleton {
// 清除路由匹配缓存(因为路由可能已变更) // 清除路由匹配缓存(因为路由可能已变更)
this.clearRouteMatches() this.clearRouteMatches()
logger.info(`[路由缓存] 已清除文件 ${filePath} 相关缓存`) logger.debug(`[路由缓存] 已清除文件 ${filePath} 相关缓存`)
} }
/** /**
@ -362,7 +362,7 @@ class RouteCache extends BaseSingleton {
*/ */
updateConfig(newConfig) { updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig } this.config = { ...this.config, ...newConfig }
logger.info('[路由缓存] 配置已更新', this.config) logger.debug('[路由缓存] 配置已更新', this.config)
} }
/** /**
@ -370,7 +370,7 @@ class RouteCache extends BaseSingleton {
*/ */
enable() { enable() {
this.config.enabled = true this.config.enabled = true
logger.info('[路由缓存] 缓存已启用') logger.debug('[路由缓存] 缓存已启用')
} }
/** /**
@ -379,7 +379,7 @@ class RouteCache extends BaseSingleton {
disable() { disable() {
this.config.enabled = false this.config.enabled = false
this.clearAll() this.clearAll()
logger.info('[路由缓存] 缓存已禁用并清除') logger.debug('[路由缓存] 缓存已禁用并清除')
} }
} }

34
src/views/layouts/empty.pug

@ -1,5 +1,4 @@
extends /layouts/root.pug extends /layouts/root.pug
//- 采用纯背景页面的布局,背景图片随机切换,卡片采用高斯滤镜类玻璃化效果
block $$head block $$head
+css('css/layouts/empty.css') +css('css/layouts/empty.css')
@ -12,7 +11,6 @@ block $$content
.container.clearfix(class="h-full") .container.clearfix(class="h-full")
.navbar-brand .navbar-brand
a(href="/" class="text-[20px]") #{siteConfig.site_title} a(href="/" class="text-[20px]") #{siteConfig.site_title}
// 桌面端菜单
.left.menu.desktop-only .left.menu.desktop-only
a.menu-item( a.menu-item(
href="/articles" href="/articles"
@ -33,26 +31,6 @@ block $$content
a.menu-item(href="/notice") a.menu-item(href="/notice")
.fe--notice-active .fe--notice-active
a.menu-item(hx-post="/logout") 退出 a.menu-item(hx-post="/logout") 退出
// 移动端:汉堡按钮
button.menu-toggle(type="button" aria-label="打开菜单")
span.bar
span.bar
span.bar
// 移动端菜单内容(与桌面端一致)
.mobile-menu.container
.left.menu
a.menu-item(href="/articles") 所有文章
if !isLogin
.right.menu
a.menu-item(href="/login") 登录
a.menu-item(href="/register") 注册
else
.right.menu
a.menu-item(href="/profile")
span 欢迎您,
span.font-semibold #{user.name || user.username}
a.menu-item(href="/notice" class="fe--notice-active") 公告
a.menu-item(hx-post="/logout") 退出
.page-layout .page-layout
.page.container .page.container
block pageContent block pageContent
@ -94,8 +72,6 @@ block $$content
.social-links(class="flex space-x-4 flex-wrap") .social-links(class="flex space-x-4 flex-wrap")
a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-blue-100 transition-colors duration-200" title="微信") a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-blue-100 transition-colors duration-200" title="微信")
span.streamline-ultimate-color--wechat-logo span.streamline-ultimate-color--wechat-logo
// a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-red-100 transition-colors duration-200" title="微博")
span.fa7-brands--weibo
a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-blue-100 transition-colors duration-200" title="QQ") a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-blue-100 transition-colors duration-200" title="QQ")
span.cib--tencent-qq span.cib--tencent-qq
a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-gray-200 transition-colors duration-200" title="GitHub") a(href="#" class="social-link p-2 rounded-full bg-gray-100 hover:bg-gray-200 transition-colors duration-200" title="GitHub")
@ -113,13 +89,3 @@ block $$content
block $$scripts block $$scripts
block pageScripts block pageScripts
script.
(function(){
var navbar = document.querySelector('.navbar');
var toggle = navbar && navbar.querySelector('.menu-toggle');
if(toggle){
toggle.addEventListener('click', function(){
navbar.classList.toggle('open');
});
}
})();

0
src/views/page/index/_global.scss

22
src/views/page/index/index copy.pug

@ -1,22 +0,0 @@
extends /layouts/empty.pug
block pageHead
style
:scss(includePaths=["D:/@code/demo/koa3-demo/src/views/page/index", "D:/@code/demo/koa3-demo/src/views"])
//- process.env.SASS_PATH = "D:/@code/demo/koa3-demo/src/views/page/index"
@import "./index.scss";
$color: red;
* {
color: $color;
}
block pageContent
:markdown-it(linkify langPrefix='highlight-')
# Markdown
Markdown document with http://links.com and
```js
var codeBlocks;
```

25
src/views/page/index/index.pug

@ -1,19 +1,22 @@
extends /layouts/empty.pug extends /layouts/empty.pug
block pageHead block pageHead
style :scss
@use "./_global.scss";
@use "./style.scss";
@use "./markdown-reset.scss";
@use "./markdown-green.scss";
block pageContent block pageContent
:my-own-filter(addStart addEnd) .markdown-body
Filter :markdown-it(linkify langPrefix='highlight-')
Body # Markdown
:markdown-it(linkify langPrefix='highlight-')
# Markdown
Markdown document with http://links.com and Markdown document with http://links.com and
```js ```js
var codeBlocks; var codeBlocks;
``` ```
> blockquote

316
src/views/page/index/markdown-green.scss

@ -0,0 +1,316 @@
@mixin chinese() {
&.chinese {
text-indent: 1.5em;
font-weight: 300;
h1,
h2,
h3,
h4,
h5,
h6,
ol,
ul,
blockquote,
details,
summary,
pre,
.tabs {
text-indent: 0;
}
}
}
// ::selection {
// background-color: #1abc9c;
// color: #fff;
// }
// pre ::selection {
// color: inherit;
// }
.markdown-body {
--color-base: #ef4444;
--markdown-bg: white;
--color-bg: #ff47479c;
--color-light: #ef44441a;
--color-extra: rgba(239, 68, 68, 0.3);
--color-more: rgba(239, 68, 68, 0.4);
}
.markdown-body.green {
background-color: var(--markdown-bg);
@apply p-3 lg:p-6;
strong {
&::before {
content: "";
}
&::after {
content: "";
}
// color: #ff4d20;
}
/* 块/段落引用 */
// blockquote {
// position: relative;
// // color: #555;
// font-weight: 400;
// border-left: 6px solid var(--color-base);
// padding-left: 1em;
// margin-left: 0;
// padding: 1em;
// background-color: var(--color-light);
// }
blockquote {
position: relative;
z-index: 600;
padding: 20px 20px 15px 20px;
line-height: 1.4 !important;
background-color: rgba(239, 68, 68, 0.06);
border-radius: 0.4em;
> * {
position: relative;
&:first-child:before {
content: "\201C";
color: var(--color-light);
font-size: 6.5em;
font-weight: 700;
transform: rotate(15deg) translateX(-10px);
opacity: 1;
position: absolute;
top: -0.4em;
left: -0.2em;
text-shadow: none;
z-index: -10;
}
}
}
.tabs {
margin-top: 0;
margin-bottom: 1em;
}
/* 让链接在 hover 状态下显示下划线 */
// a {
// color: var(--color-base);
// text-decoration: none;
// &:hover {
// text-decoration: underline;
// }
// }
a {
position: relative;
z-index: 10;
transition: color 0.3s linear;
cursor: pointer;
font-weight: bolder;
// text-decoration: underline #c7254e;
text-decoration: none;
color: var(--color-base);
border-bottom: 1px solid currentColor;
padding: 0 4px;
&[data-footnote-backref],
&[data-footnote-ref] {
// text-decoration: none;
border: none;
&:hover {
background: none;
animation: none;
}
}
&:hover {
content: "";
// text-decoration: none;
border: none;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 4'%3E%3Cpath fill='none' stroke='%23ff4d20' d='M0 3.5c5 0 5-3 10-3s5 3 10 3 5-3 10-3 5 3 10 3'/%3E%3C/svg%3E")
repeat-x 0 100%;
background-size: 20px auto;
animation: waveMove 1s infinite linear;
}
@keyframes waveMove {
0% {
background-position: 0 100%;
}
100% {
background-position: -20px 100%;
}
}
}
// 由prism.scss处理了
pre {
background: var(--prism-background);
font-size: var(--prism-font-size);
// /* border: 1px solid #ddd; */
// padding: 1em 1.5em;
display: block;
-webkit-overflow-scrolling: touch;
}
pre,
pre code {
font-family: var(--prism-font-family);
}
// /* 底部印刷体版本等标记 */
small,
/* 图片说明 */
figcaption {
font-size: 0.75em;
color: #888;
}
// .markdown-body {
legend {
color: #000;
font-weight: inherit;
}
caption {
color: #000;
font-weight: inherit;
}
del {
text-decoration: line-through var(--color-base) 2px;
}
code {
color: rgb(45, 55, 72);
background-color: rgba(160, 174, 192, 0.25);
font-family: inherit;
font-size: 1em;
// color: #ffffff;
// background-color: #ff4c209c;
border-radius: 4px;
padding: 1px 6px;
// font-size: 0.875em;
// font-size: 1.0769em;
// position: relative;
// top: 0.1em;
margin: 0 2px;
vertical-align: bottom;
}
pre {
code {
padding: 0;
font-size: inherit;
font-weight: inherit;
color: inherit;
white-space: pre;
background-color: transparent;
vertical-align: baseline;
border-radius: 0;
margin: 0;
}
}
table {
width: 100%;
display: table;
border: 1px solid var(--color-light);
tr:hover {
background: var(--color-light);
}
&:hover {
border: 1px solid var(--color-extra);
th {
border-right: 1px solid var(--color-extra);
background: var(--color-extra);
border-bottom: 1px solid var(--color-extra);
}
td {
border-right: 1px solid var(--color-extra);
}
caption {
border-right: 1px solid var(--color-extra);
}
thead {
th {
background: var(--color-extra);
}
}
}
// table-layout: fixed;
th {
border-right: 1px solid var(--color-light);
padding: 0.5em 1em;
background: var(--color-light);
border-bottom: 1px solid var(--color-light);
}
td {
border-right: 1px solid var(--color-light);
padding: 0.5em 1em;
}
caption {
border-right: 1px solid var(--color-light);
padding: 0.5em 1em;
border-bottom: none;
}
thead {
th {
background: var(--color-extra);
}
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 1.2em;
margin-bottom: 0.6em;
line-height: 1.35;
position: relative;
}
h1 {
font-size: 1.8em;
}
h2 {
font-size: 1.6em;
}
h3 {
font-size: 1.4em;
}
h4 {
font-size: 1.2em;
}
h5 {
font-size: 1em;
}
h6 {
font-size: 1em;
}
::-webkit-calendar-picker-indicator {
filter: invert(50%);
}
em {
// color: #000;
font-weight: inherit;
position: relative;
&:after {
position: absolute;
top: 0.65em;
left: 0;
width: 100%;
overflow: hidden;
white-space: nowrap;
pointer-events: none;
color: var(--color-base);
content: "・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・";
}
}
ul.toc {
li {
list-style-type: none;
a {
text-decoration: none;
border: 0;
list-style-type: none;
}
}
}
@include chinese;
}

677
src/views/page/index/markdown-reset.scss

@ -0,0 +1,677 @@
/* 深色主题媒体查询 - 当用户系统偏好深色模式时应用 */
@media (prefers-color-scheme: dark) {
.markdown-body {
/* 告诉浏览器使用深色配色方案,影响滚动条等系统UI元素 */
color-scheme: dark;
}
}
/* 浅色主题媒体查询 - 当用户系统偏好浅色模式时应用 */
@media (prefers-color-scheme: light) {
// https://verytoolz.com/blog/03bfb3598f/
.markdown-body {
/* 告诉浏览器使用浅色配色方案,影响滚动条等系统UI元素 */
color-scheme: light;
/* 定义CSS自定义属性,用于主题色彩管理 */
--color-fg-default: #24292f; // 文本色-默认 - 主要文本颜色
--color-fg-muted: #57606a; // 文本色-柔和 - 次要文本颜色
--color-fg-subtle: #6e7781; // 文本色-微妙 - 最淡的文本颜色
--color-canvas-default: #ffffff; // 底色-默认 - 主要背景颜色
--color-canvas-subtle: #f6f8fa; // 底色-微妙 - 次要背景颜色
--color-border-default: #d0d7de; // 边框色-默认 - 主要边框颜色
--color-border-muted: hsla(210, 18%, 87%, 1); // 边框色-柔和 - 次要边框颜色
--color-neutral-muted: rgba(175, 184, 193, 0.2); // 边框色-中性 - 中性边框颜色
--color-accent-fg: #0969da; // 文本强调色 - 强调文本颜色
--color-accent-emphasis: #0969da; // 背景强调色 - 强调背景颜色
--color-attention-subtle: #fff8c5; // 背景注意色 - 注意提示背景色
--color-danger-fg: #cf222e; // 文本危险色 - 危险/错误文本颜色
--color-mark-default: rgb(255, 255, 0); // mark 默认色 - 标记默认背景色
--color-mark-fg: rgb(255, 187, 0); // mark 强调色 - 标记强调背景色
}
}
/* Markdown内容主体样式 - 用于渲染Markdown文档的容器 */
.markdown-body {
/* 防止iOS Safari自动调整文本大小 */
-webkit-text-size-adjust: 100%;
/* 防止IE自动调整文本大小 */
-ms-text-size-adjust: 100%;
/* 优化文本渲染质量,提升可读性 */
text-rendering: optimizelegibility;
/* 重置外边距为0 */
margin: 0;
/* 允许长单词在必要时换行,防止溢出 */
word-wrap: break-word;
/* 使用CSS变量设置文本颜色 */
color: var(--color-fg-muted);
/* 伪元素before - 用于清除浮动 */
&::before {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 空内容,仅用于布局 */
content: "";
}
/* 伪元素after - 用于清除浮动 */
&::after {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 清除左右浮动 */
clear: both;
/* 空内容,仅用于布局 */
content: "";
}
/* 第一个子元素 - 移除顶部外边距 */
> *:first-child {
/* 强制移除顶部外边距,避免不必要的空白 */
margin-top: 0 !important;
}
/* 最后一个子元素 - 移除底部外边距 */
> *:last-child {
/* 强制移除底部外边距,避免不必要的空白 */
margin-bottom: 0 !important;
}
/* 块级元素统一间距设置 - 段落、引用、列表、表格等 */
p,
blockquote,
ul,
ol,
dl,
table,
hr,
form,
pre,
details {
/* 移除顶部外边距,避免重复间距 */
margin-top: 0;
/* 设置底部外边距为1em,保持适当间距 */
margin-bottom: 1em;
}
/* 引用块内部元素间距处理 */
blockquote {
/* 引用块内第一个子元素 - 移除顶部外边距 */
& > :first-child {
margin-top: 0;
}
/* 引用块内最后一个子元素 - 移除底部外边距 */
& > :last-child {
margin-bottom: 0;
}
}
/* 统一显示成块状元素 - 确保这些元素独占一行 */
details,
figcaption,
figure {
/* 设置为块级元素,独占一行显示 */
display: block;
}
/* HTML5 媒体文件跟 img 保持一致 - 内联块级元素 */
audio,
canvas,
video {
/* 设置为内联块级元素,可以设置宽高但不会独占一行 */
display: inline-block;
}
/* 按钮内部间距统一 - 移除Firefox默认内边距 */
button::-moz-focus-inner,
input::-moz-focus-inner {
/* 移除Firefox浏览器按钮和输入框的内部内边距 */
padding: 0;
/* 移除Firefox浏览器按钮和输入框的内部边框 */
border: 0;
}
/* 定义元素显示为斜体 - 术语定义样式 */
dfn {
/* 设置字体为斜体,用于术语定义 */
font-style: italic;
}
/* 去掉各Table cell 的边距并让其边重合 - 表格样式统一 */
table {
/* 合并表格边框,相邻单元格边框合并为一条 */
border-collapse: collapse;
/* 设置表格单元格间距为0 */
border-spacing: 0;
/* 设置为块级元素,可以设置宽高 */
display: block;
/* 宽度根据内容自适应 */
width: max-content;
/* 最大宽度不超过父容器 */
max-width: 100%;
/* 内容溢出时显示滚动条 */
overflow: auto;
}
/* 可拖动文件添加拖动手势 - 拖拽元素样式 */
[draggable] {
/* 设置鼠标悬停时显示移动光标 */
cursor: move;
}
/* 加粗元素 - 粗体文本样式 */
b,
strong {
/* 设置字体粗细,使用CSS变量或默认600 */
font-weight: var(--base-text-weight-semibold, 600);
}
/* 缩写元素样式统一 - 缩写和首字母缩写样式 */
abbr,
acronym {
/* 移除底部边框 */
border-bottom: none;
/* 设置字体变体为正常 */
font-variant: normal;
/* 设置虚线下划线装饰 */
text-decoration: underline dotted;
}
/* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */
abbr {
/* 设置鼠标悬停时显示帮助光标 */
cursor: help;
}
/* 一致的 del 样式 - 删除线文本样式 */
del {
/* 设置文本装饰为删除线 */
text-decoration: line-through;
}
/* a标签去除下划线 - 链接样式处理 */
a {
/* 默认移除下划线,保持页面简洁 */
text-decoration: none;
/* 没有href属性的链接样式 */
&:not([href]) {
/* 继承父元素颜色 */
color: inherit;
/* 移除下划线装饰 */
text-decoration: none;
}
/* 鼠标悬停时显示下划线 */
&:hover {
text-decoration: underline;
}
}
/* 默认不显示下划线,保持页面简洁 - 插入文本样式 */
ins {
/* 移除下划线装饰,保持页面简洁 */
text-decoration: none;
}
/* 专名号虽然 u 已经重回 html5 Draft但在所有浏览器中都是可以使用的
* 要做到更好向后兼容的话添加 class="typo-u" 来显示专名号
* 关于 <u> 标签http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-u-element
* 被放弃的是 4之前一直搞错 http://www.w3.org/TR/html401/appendix/changes.html#idx-deprecated
* 一篇关于 <u> 标签的很好文章http://html5doctor.com/u-element/
*/
u,
.typo-u {
/* 设置文本装饰为下划线,用于专名号显示 */
text-decoration: underline;
}
/* 隐藏指定元素 - 隐藏带有hidden属性的元素 */
[hidden] {
/* 强制隐藏元素,优先级最高 */
display: none !important;
}
/* 伸缩框显示为列表元素 - 详情框摘要样式 */
summary {
/* 设置为列表项显示,显示为可点击的列表项 */
display: list-item;
}
/* 引用元素前后内容 - 移除默认引号 */
q:before,
q:after {
/* 移除引用元素前后的默认引号内容 */
content: "";
}
/* 表格标题和表头文本对齐 - 默认左对齐 */
caption,
th {
/* 设置文本左对齐 */
text-align: left;
}
/* 居中对齐的表格标题和表头 */
caption[align="center"],
th[align="center"] {
/* 设置文本居中对齐 */
text-align: center;
}
/* 特定元素字体粗细统一 - 地址、标题、引用等 */
address,
caption,
cite,
em,
th,
var {
/* 设置字体粗细为正常(400) */
font-weight: 400;
}
/* 标记,类似于手写的荧光笔的作用 - 高亮标记样式 */
mark {
/* 设置标记背景色,使用CSS变量 */
background: var(--color-mark-default);
// background: #fffdd1; // 备用背景色
// border-bottom: 1px solid #ffedce; // 备用底部边框
/* 设置内边距,增加标记的可读性 */
padding: 2px;
/* 激活状态的标记样式 */
&.active {
/* 激活时使用强调色背景 */
background: var(--color-mark-fg);
}
// margin: 0 5px; // 备用外边距
}
/* 统一h1元素的间隔和字体大小 - 一级标题样式 */
h1 {
/* 设置上下外边距为0.67em */
margin: 0.67em 0;
/* 设置字体粗细,使用CSS变量或默认600 */
font-weight: var(--base-text-weight-semibold, 600);
/* 设置字体大小为2倍基础大小 */
font-size: 2em;
}
/* small字体缩小 - 小字体文本样式 */
small {
/* 设置字体大小为父元素的90% */
font-size: 90%;
}
/* 上下标显示 - 下标和上标文本样式 */
sub,
sup {
/* 设置字体大小为75% */
font-size: 75%;
/* 设置行高为0,避免影响行间距 */
line-height: 0;
/* 设置相对定位,用于精确控制位置 */
position: relative;
/* 设置垂直对齐为基线 */
vertical-align: baseline;
}
/* 上下标内链接样式 */
sub a,
sup a {
/* 设置左右内边距为0.1em */
padding: 0 0.1em;
}
/* 下标位置调整 */
sub {
/* 向下偏移0.25em */
bottom: -0.25em;
}
/* 上标位置调整 */
sup {
/* 向上偏移0.5em */
top: -0.5em;
}
/* 代码相关的字体大小统一 - 代码元素字体样式 */
code,
kbd,
pre,
samp,
pre tt {
/* 设置字体为等宽字体,便于代码阅读 */
font-family: monospace;
/* 设置字体大小为1em,保持一致性 */
font-size: 1em;
}
/* 去除默认边框 - 移除字段集和图片的默认边框 */
fieldset,
img {
/* 移除边框 */
border: 0;
}
/* 图片初始化样式 - 图片元素基础样式 */
img {
/* 设置边框样式为无 */
border-style: none;
/* 设置最大宽度为100%,防止溢出 */
max-width: 100%;
/* 设置盒模型为内容盒模型 */
box-sizing: content-box;
/* 设置左右外边距为自动,实现居中 */
margin: 0 auto;
/* 设置背景色,使用CSS变量 */
background-color: var(--color-canvas-default);
}
/* 可附标题内容元素的间距 - 图片容器样式 */
figure {
/* 设置上下外边距为1em,左右外边距为40px */
margin: 1em 40px;
}
/* 间隔线 - 水平分隔线样式 */
/* 一致化 horizontal rule - 统一水平分隔线样式 */
hr {
/* 设置盒模型为内容盒模型 */
box-sizing: content-box;
/* 隐藏溢出内容 */
overflow: hidden;
/* 设置背景为透明 */
background: transparent;
/* 设置底部边框,使用CSS变量 */
border-bottom: 1px solid var(--color-border-muted);
/* 设置高度为0.25em */
height: 0.25em;
/* 移除内边距 */
padding: 0;
/* 设置上下外边距为24px */
margin: 24px 0;
/* 设置背景色,使用CSS变量 */
background-color: var(--color-border-default);
/* 移除边框 */
border: 0;
/* 伪元素before - 用于清除浮动 */
&::before {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 空内容,仅用于布局 */
content: "";
}
/* 伪元素after - 用于清除浮动 */
&::after {
/* 设置为表格显示模式,用于清除浮动 */
display: table;
/* 清除左右浮动 */
clear: both;
/* 空内容,仅用于布局 */
content: "";
}
}
/* 表单元素并不继承父级 font 的问题 - 表单元素字体继承 */
button,
input,
select,
textarea {
/* 继承父元素的字体样式 */
font: inherit;
/* 移除外边距 */
margin: 0;
/* 设置溢出为可见 */
overflow: visible;
/* 继承父元素的字体族 */
font-family: inherit;
/* 继承父元素的字体大小 */
font-size: inherit;
/* 继承父元素的行高 */
line-height: inherit;
}
/* 外观显示为按钮 - 按钮类型输入框样式 */
[type="button"],
[type="reset"],
[type="submit"] {
/* 设置WebKit浏览器按钮外观 */
-webkit-appearance: button;
/* 设置标准按钮外观,提高兼容性 */
appearance: button;
}
/* 这两个表单样式规则覆盖 - 复选框和单选框样式 */
[type="checkbox"],
[type="radio"] {
/* 设置盒模型为边框盒模型 */
box-sizing: border-box;
/* 移除内边距 */
padding: 0;
}
/* 数字按钮内部高度自动 - 数字输入框按钮样式 */
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
/* 设置高度为自动,适应内容 */
height: auto;
}
/* 搜索按钮内图标外观去除 - 搜索输入框样式 */
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
/* 移除WebKit浏览器搜索框默认样式 */
-webkit-appearance: none;
}
/* 输入框的占位符样式 - WebKit浏览器占位符样式 */
::-webkit-input-placeholder {
/* 继承父元素颜色 */
color: inherit;
/* 设置透明度为0.54,创建半透明效果 */
opacity: 0.54;
}
/* 文件选择按钮样式统一 - 文件上传按钮样式 */
::-webkit-file-upload-button {
/* 设置WebKit浏览器按钮外观 */
-webkit-appearance: button;
/* 继承父元素字体样式 */
font: inherit;
}
/* 占位符显示统一 - 通用占位符样式 */
::placeholder {
/* 设置占位符颜色,使用CSS变量 */
color: var(--color-fg-subtle);
/* 设置完全不透明 */
opacity: 1;
}
/* table内的td,th去除留白 - 表格单元格样式 */
td,
th {
/* 移除表格单元格内边距 */
padding: 0;
}
/* 伸缩框鼠标显示 - 详情框摘要样式 */
details summary {
/* 设置鼠标悬停时显示手型光标 */
cursor: pointer;
}
/* 未展开的详情框隐藏内容 - 详情框内容显示控制 */
details:not([open]) > *:not(summary) {
/* 强制隐藏未展开详情框内的非摘要内容 */
display: none !important;
}
/* 按键显示 - 键盘按键样式 */
kbd {
/* 设置为内联块级元素,可以设置宽高但不会独占一行 */
display: inline-block;
/* 设置内边距为3px上下,5px左右 */
padding: 3px 5px;
/* 设置字体为11px等宽字体,包含多种等宽字体备选 */
font: 11px ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
/* 设置行高为10px */
line-height: 10px;
/* 设置文本颜色,使用CSS变量 */
color: var(--color-fg-default);
/* 设置垂直对齐为中间 */
vertical-align: middle;
/* 设置背景色,使用CSS变量 */
background-color: var(--color-canvas-subtle);
/* 设置边框为1px实线,使用CSS变量 */
border: solid 1px var(--color-neutral-muted);
/* 设置底部边框颜色,使用CSS变量 */
border-bottom-color: var(--color-neutral-muted);
/* 设置圆角为6px */
border-radius: 6px;
/* 设置内阴影,创建按键凹陷效果 */
box-shadow: inset 0 -1px 0 var(--color-neutral-muted);
}
/* 清除浮动工具类 - 清除浮动伪元素 */
.clearfix:before,
.clearfix:after {
/* 空内容,仅用于布局 */
content: "";
/* 设置为表格显示模式,用于清除浮动 */
display: table;
}
/* 清除浮动工具类 - after伪元素 */
.clearfix:after {
/* 清除左右浮动 */
clear: both;
}
/* 清除浮动工具类 - 主容器 */
.clearfix {
/* 触发IE的hasLayout属性,用于清除浮动 */
zoom: 1;
}
/* 强制文本换行 - 文本换行工具类 */
.textwrap,
.textwrap td,
.textwrap th {
/* 允许长单词在必要时换行,防止溢出 */
word-wrap: break-word;
/* 强制在任意字符间换行,防止溢出 */
word-break: break-all;
}
/* 文本换行表格 - 固定表格布局 */
.textwrap-table {
/* 设置表格布局为固定,提高渲染性能 */
table-layout: fixed;
}
/* 无序列表样式 - 项目符号列表 */
ul {
/* 重置左边距为0 */
margin-left: 0;
/* 重置左内边距为0 */
padding-left: 0;
/* 设置左边距为2em,创建缩进效果 */
margin-left: 2em;
/* 设置列表样式为实心圆点 */
list-style: disc;
}
/* 有序列表样式 - 数字列表 */
ol {
/* 重置左边距为0 */
margin-left: 0;
/* 重置左内边距为0 */
padding-left: 0;
/* 设置左边距为2em,创建缩进效果 */
margin-left: 2em;
/* 设置列表样式为数字 */
list-style: decimal;
/* 列表项样式 */
li {
/* 设置左内边距为0.4em,增加数字与文本间距 */
padding-left: 0.4em;
}
}
/* 相邻列表项间距 - 列表项之间的间距 */
li + li {
/* 设置顶部外边距为0.25em,增加列表项间距 */
margin-top: 0.25em;
}
/* 嵌套列表样式 - 列表项内的子列表 */
li {
/* 无序子列表样式 */
ul {
/* 设置底部外边距为0.8em */
margin-bottom: 0.8em;
/* 设置左边距为2em,创建嵌套缩进 */
margin-left: 2em;
/* 设置列表样式为空心圆点 */
list-style: circle;
/* 三级无序列表样式 */
li {
ul {
/* 设置列表样式为实心方块 */
list-style: square;
}
}
}
/* 有序子列表样式 */
ol {
/* 设置底部外边距为0.8em */
margin-bottom: 0.8em;
/* 设置左边距为2em,创建嵌套缩进 */
margin-left: 2em;
}
}
/* 任务列表项样式 - 待办事项列表项 */
.task-list-item {
/* 移除列表样式,不显示项目符号 */
list-style-type: none;
/* 设置相对定位,用于绝对定位子元素 */
position: relative;
/* 第一个子输入框样式 */
> input {
/* 第一个子元素右边距 */
&:nth-child(1) {
/* 设置右边距为6px */
margin-right: 6px;
}
}
/* 标签样式 */
label {
/* 设置字体粗细为正常(400) */
font-weight: 400;
}
/* 拖拽手柄样式 */
.handle {
/* 隐藏拖拽手柄 */
display: none;
}
/* 复选框样式 */
input[type="checkbox"] {
/* 设置宽度为0.9em */
width: 0.9em;
/* 设置高度为0.9em */
height: 0.9em;
/* 设置绝对定位 */
position: absolute;
/* 向左偏移1.3em */
left: -1.3em;
/* 向下偏移0.35em */
top: 0.35em;
}
}
/* 启用的任务列表项样式 */
.task-list-item.enabled {
/* 标签样式 */
label {
/* 设置鼠标悬停时显示手型光标 */
cursor: pointer;
}
}
/* 相邻任务列表项间距 */
.task-list-item + .task-list-item {
/* 设置顶部外边距为3px */
margin-top: 3px;
}
/* 包含任务列表的容器样式 */
.contains-task-list {
// margin-left: 0.6em; // 备用左边距
/* 从右到左文本方向样式 */
&:dir(rtl) {
.task-list-item {
input[type="checkbox"] {
/* 设置复选框外边距,适配RTL布局 */
margin: 0 -1.6em 0.25em 0.2em;
}
}
}
}
/* 目录样式 - 表格目录容器 */
.toc {
/* 重置左边距为0 */
margin-left: 0;
}
/* 定义列表样式 - 描述列表容器 */
dl {
/* 设置为块级元素 */
display: block;
/* 设置块级起始外边距为1em */
margin-block-start: 1em;
/* 设置块级结束外边距为1em */
margin-block-end: 1em;
/* 设置内联起始外边距为0px */
margin-inline-start: 0px;
/* 设置内联结束外边距为0px */
margin-inline-end: 0px;
/* 设置Unicode双向算法为隔离 */
unicode-bidi: isolate;
/* 定义术语样式 */
dt {
/* 设置为块级元素 */
display: block;
/* 设置Unicode双向算法为隔离 */
unicode-bidi: isolate;
}
/* 定义描述样式 */
dd {
/* 设置为块级元素 */
display: block;
/* 设置内联起始外边距为40px,创建缩进效果 */
margin-inline-start: 40px;
/* 设置Unicode双向算法为隔离 */
unicode-bidi: isolate;
}
}
}

0
src/views/page/index/index.scss → src/views/page/index/style.scss

0
src/views/page/index/person.pug → src/views/temp/person.pug

Loading…
Cancel
Save