From e67238e42ed9eb696a17917e29b1f9541da02991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E4=BA=9A=E6=98=95?= <1549469775@qq.com> Date: Fri, 19 Sep 2025 11:04:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96=E9=A1=B9?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=A0=B7=E5=BC=8F=E6=96=87=E4=BB=B6?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96Markdown=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在package.json中添加了extend-shallow、koa-helmet和koa-ratelimit等依赖 - 新增markdown-reset.scss和markdown-green.scss样式文件,增强Markdown内容的样式支持 - 更新公共样式,改善响应式设计,提升用户体验 - 在中间件中集成了安全性和速率限制功能,增强应用的安全性 --- bun.lockb | Bin 190837 -> 199219 bytes package.json | 5 +- public/css/layouts/markdown-reset.scss | 677 +++++++++++ public/scss-compiler/page/index/_global.css | 1188 ++++++++++++++++++++ public/scss-compiler/page/index/index.css | 136 +++ public/scss-compiler/page/index/markdown-green.css | 1188 ++++++++++++++++++++ public/scss-compiler/page/index/markdown-reset.css | 1188 ++++++++++++++++++++ public/scss-compiler/page/index/style.css | 1188 ++++++++++++++++++++ src/logger.js | 2 +- src/main.js | 12 +- src/middlewares/PugHelper/sass.js | 83 ++ src/middlewares/Views/index.js | 10 +- src/middlewares/install.js | 71 +- src/utils/ForRegister.js | 89 +- src/utils/cache/RouteCache.js | 20 +- src/views/layouts/empty.pug | 34 - src/views/page/index/_global.scss | 0 src/views/page/index/index copy.pug | 22 - src/views/page/index/index.pug | 25 +- src/views/page/index/index.scss | 146 --- src/views/page/index/markdown-green.scss | 316 ++++++ src/views/page/index/markdown-reset.scss | 677 +++++++++++ src/views/page/index/person.pug | 9 - src/views/page/index/style.scss | 146 +++ src/views/temp/person.pug | 9 + 25 files changed, 6972 insertions(+), 269 deletions(-) create mode 100644 public/css/layouts/markdown-reset.scss create mode 100644 public/scss-compiler/page/index/_global.css create mode 100644 public/scss-compiler/page/index/index.css create mode 100644 public/scss-compiler/page/index/markdown-green.css create mode 100644 public/scss-compiler/page/index/markdown-reset.css create mode 100644 public/scss-compiler/page/index/style.css create mode 100644 src/middlewares/PugHelper/sass.js create mode 100644 src/views/page/index/_global.scss delete mode 100644 src/views/page/index/index copy.pug delete mode 100644 src/views/page/index/index.scss create mode 100644 src/views/page/index/markdown-green.scss create mode 100644 src/views/page/index/markdown-reset.scss delete mode 100644 src/views/page/index/person.pug create mode 100644 src/views/page/index/style.scss create mode 100644 src/views/temp/person.pug diff --git a/bun.lockb b/bun.lockb index 3882124f5e3b9c847ab429da73524e2c801c49ae..03b0eca55dc1c0d78eed6dadcd2f8d446a8aaba7 100644 GIT binary patch delta 38235 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 NYrLk^>nb0t`9C>~aFhT5 delta 33189 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 diff --git a/package.json b/package.json index c25f9e6..d242066 100644 --- a/package.json +++ b/package.json @@ -32,16 +32,18 @@ "@koa/etag": "^5.0.1", "bcryptjs": "^3.0.2", "consolidate": "^1.0.4", + "extend-shallow": "^3.0.2", "formidable": "^3.5.4", "get-paths": "^0.0.7", "image-thumbnail": "^1.0.17", "jsonwebtoken": "^9.0.0", "jstransformer-markdown-it": "^3.0.0", - "jstransformer-scss": "^2.0.0", "knex": "^3.1.0", "koa": "^3.0.0", "koa-bodyparser": "^4.4.1", "koa-conditional-get": "^3.0.0", + "koa-helmet": "^8.0.1", + "koa-ratelimit": "^6.0.0", "koa-session": "^7.0.2", "lodash": "^4.17.21", "log4js": "^6.9.1", @@ -51,6 +53,7 @@ "path-to-regexp": "^8.2.0", "pretty": "^2.0.0", "pug": "^3.0.3", + "sass": "^1.92.1", "sqlite3": "^5.1.7", "svg-captcha": "^1.4.0" }, diff --git a/public/css/layouts/markdown-reset.scss b/public/css/layouts/markdown-reset.scss new file mode 100644 index 0000000..d0dabe1 --- /dev/null +++ b/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" 来显示专名号 + * 关于 标签: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 + * 一篇关于 标签的很好文章: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; + } + } +} diff --git a/public/scss-compiler/page/index/_global.css b/public/scss-compiler/page/index/_global.css new file mode 100644 index 0000000..403ce31 --- /dev/null +++ b/public/scss-compiler/page/index/_global.css @@ -0,0 +1,1188 @@ +@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; + } +} +/* 深色主题媒体查询 - 当用户系统偏好深色模式时应用 */ +@media (prefers-color-scheme: dark) { + .markdown-body { + /* 告诉浏览器使用深色配色方案,影响滚动条等系统UI元素 */ + color-scheme: dark; + } +} +/* 浅色主题媒体查询 - 当用户系统偏好浅色模式时应用 */ +@media (prefers-color-scheme: light) { + .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); + --color-mark-fg: rgb(255, 187, 0); + } +} +/* 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 - 用于清除浮动 */ +} +.markdown-body::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 第一个子元素 - 移除顶部外边距 */ +} +.markdown-body > *:first-child { + /* 强制移除顶部外边距,避免不必要的空白 */ + margin-top: 0 !important; +} +.markdown-body { + /* 最后一个子元素 - 移除底部外边距 */ +} +.markdown-body > *:last-child { + /* 强制移除底部外边距,避免不必要的空白 */ + margin-bottom: 0 !important; +} +.markdown-body { + /* 块级元素统一间距设置 - 段落、引用、列表、表格等 */ +} +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body hr, +.markdown-body form, +.markdown-body pre, +.markdown-body details { + /* 移除顶部外边距,避免重复间距 */ + margin-top: 0; + /* 设置底部外边距为1em,保持适当间距 */ + margin-bottom: 1em; +} +.markdown-body { + /* 引用块内部元素间距处理 */ +} +.markdown-body blockquote { + /* 引用块内第一个子元素 - 移除顶部外边距 */ +} +.markdown-body blockquote > :first-child { + margin-top: 0; +} +.markdown-body blockquote { + /* 引用块内最后一个子元素 - 移除底部外边距 */ +} +.markdown-body blockquote > :last-child { + margin-bottom: 0; +} +.markdown-body { + /* 统一显示成块状元素 - 确保这些元素独占一行 */ +} +.markdown-body details, +.markdown-body figcaption, +.markdown-body figure { + /* 设置为块级元素,独占一行显示 */ + display: block; +} +.markdown-body { + /* HTML5 媒体文件跟 img 保持一致 - 内联块级元素 */ +} +.markdown-body audio, +.markdown-body canvas, +.markdown-body video { + /* 设置为内联块级元素,可以设置宽高但不会独占一行 */ + display: inline-block; +} +.markdown-body { + /* 按钮内部间距统一 - 移除Firefox默认内边距 */ +} +.markdown-body button::-moz-focus-inner, +.markdown-body input::-moz-focus-inner { + /* 移除Firefox浏览器按钮和输入框的内部内边距 */ + padding: 0; + /* 移除Firefox浏览器按钮和输入框的内部边框 */ + border: 0; +} +.markdown-body { + /* 定义元素显示为斜体 - 术语定义样式 */ +} +.markdown-body dfn { + /* 设置字体为斜体,用于术语定义 */ + font-style: italic; +} +.markdown-body { + /* 去掉各Table cell 的边距并让其边重合 - 表格样式统一 */ +} +.markdown-body table { + /* 合并表格边框,相邻单元格边框合并为一条 */ + border-collapse: collapse; + /* 设置表格单元格间距为0 */ + border-spacing: 0; + /* 设置为块级元素,可以设置宽高 */ + display: block; + /* 宽度根据内容自适应 */ + width: max-content; + /* 最大宽度不超过父容器 */ + max-width: 100%; + /* 内容溢出时显示滚动条 */ + overflow: auto; +} +.markdown-body { + /* 可拖动文件添加拖动手势 - 拖拽元素样式 */ +} +.markdown-body [draggable] { + /* 设置鼠标悬停时显示移动光标 */ + cursor: move; +} +.markdown-body { + /* 加粗元素 - 粗体文本样式 */ +} +.markdown-body b, +.markdown-body strong { + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); +} +.markdown-body { + /* 缩写元素样式统一 - 缩写和首字母缩写样式 */ +} +.markdown-body abbr, +.markdown-body acronym { + /* 移除底部边框 */ + border-bottom: none; + /* 设置字体变体为正常 */ + font-variant: normal; + /* 设置虚线下划线装饰 */ + text-decoration: underline dotted; +} +.markdown-body { + /* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */ +} +.markdown-body abbr { + /* 设置鼠标悬停时显示帮助光标 */ + cursor: help; +} +.markdown-body { + /* 一致的 del 样式 - 删除线文本样式 */ +} +.markdown-body del { + /* 设置文本装饰为删除线 */ + text-decoration: line-through; +} +.markdown-body { + /* a标签去除下划线 - 链接样式处理 */ +} +.markdown-body a { + /* 默认移除下划线,保持页面简洁 */ + text-decoration: none; + /* 没有href属性的链接样式 */ +} +.markdown-body a:not([href]) { + /* 继承父元素颜色 */ + color: inherit; + /* 移除下划线装饰 */ + text-decoration: none; +} +.markdown-body a { + /* 鼠标悬停时显示下划线 */ +} +.markdown-body a:hover { + text-decoration: underline; +} +.markdown-body { + /* 默认不显示下划线,保持页面简洁 - 插入文本样式 */ +} +.markdown-body ins { + /* 移除下划线装饰,保持页面简洁 */ + text-decoration: none; +} +.markdown-body { + /* 专名号:虽然 u 已经重回 html5 Draft,但在所有浏览器中都是可以使用的, + * 要做到更好,向后兼容的话,添加 class="typo-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 + * 一篇关于 标签的很好文章:http://html5doctor.com/u-element/ + */ +} +.markdown-body u, +.markdown-body .typo-u { + /* 设置文本装饰为下划线,用于专名号显示 */ + text-decoration: underline; +} +.markdown-body { + /* 隐藏指定元素 - 隐藏带有hidden属性的元素 */ +} +.markdown-body [hidden] { + /* 强制隐藏元素,优先级最高 */ + display: none !important; +} +.markdown-body { + /* 伸缩框显示为列表元素 - 详情框摘要样式 */ +} +.markdown-body summary { + /* 设置为列表项显示,显示为可点击的列表项 */ + display: list-item; +} +.markdown-body { + /* 引用元素前后内容 - 移除默认引号 */ +} +.markdown-body q:before, +.markdown-body q:after { + /* 移除引用元素前后的默认引号内容 */ + content: ""; +} +.markdown-body { + /* 表格标题和表头文本对齐 - 默认左对齐 */ +} +.markdown-body caption, +.markdown-body th { + /* 设置文本左对齐 */ + text-align: left; +} +.markdown-body { + /* 居中对齐的表格标题和表头 */ +} +.markdown-body caption[align=center], +.markdown-body th[align=center] { + /* 设置文本居中对齐 */ + text-align: center; +} +.markdown-body { + /* 特定元素字体粗细统一 - 地址、标题、引用等 */ +} +.markdown-body address, +.markdown-body caption, +.markdown-body cite, +.markdown-body em, +.markdown-body th, +.markdown-body var { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body { + /* 标记,类似于手写的荧光笔的作用 - 高亮标记样式 */ +} +.markdown-body mark { + /* 设置标记背景色,使用CSS变量 */ + background: var(--color-mark-default); + /* 设置内边距,增加标记的可读性 */ + padding: 2px; + /* 激活状态的标记样式 */ +} +.markdown-body mark.active { + /* 激活时使用强调色背景 */ + background: var(--color-mark-fg); +} +.markdown-body { + /* 统一h1元素的间隔和字体大小 - 一级标题样式 */ +} +.markdown-body h1 { + /* 设置上下外边距为0.67em */ + margin: 0.67em 0; + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); + /* 设置字体大小为2倍基础大小 */ + font-size: 2em; +} +.markdown-body { + /* small字体缩小 - 小字体文本样式 */ +} +.markdown-body small { + /* 设置字体大小为父元素的90% */ + font-size: 90%; +} +.markdown-body { + /* 上下标显示 - 下标和上标文本样式 */ +} +.markdown-body sub, +.markdown-body sup { + /* 设置字体大小为75% */ + font-size: 75%; + /* 设置行高为0,避免影响行间距 */ + line-height: 0; + /* 设置相对定位,用于精确控制位置 */ + position: relative; + /* 设置垂直对齐为基线 */ + vertical-align: baseline; +} +.markdown-body { + /* 上下标内链接样式 */ +} +.markdown-body sub a, +.markdown-body sup a { + /* 设置左右内边距为0.1em */ + padding: 0 0.1em; +} +.markdown-body { + /* 下标位置调整 */ +} +.markdown-body sub { + /* 向下偏移0.25em */ + bottom: -0.25em; +} +.markdown-body { + /* 上标位置调整 */ +} +.markdown-body sup { + /* 向上偏移0.5em */ + top: -0.5em; +} +.markdown-body { + /* 代码相关的字体大小统一 - 代码元素字体样式 */ +} +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp, +.markdown-body pre tt { + /* 设置字体为等宽字体,便于代码阅读 */ + font-family: monospace; + /* 设置字体大小为1em,保持一致性 */ + font-size: 1em; +} +.markdown-body { + /* 去除默认边框 - 移除字段集和图片的默认边框 */ +} +.markdown-body fieldset, +.markdown-body img { + /* 移除边框 */ + border: 0; +} +.markdown-body { + /* 图片初始化样式 - 图片元素基础样式 */ +} +.markdown-body img { + /* 设置边框样式为无 */ + border-style: none; + /* 设置最大宽度为100%,防止溢出 */ + max-width: 100%; + /* 设置盒模型为内容盒模型 */ + box-sizing: content-box; + /* 设置左右外边距为自动,实现居中 */ + margin: 0 auto; + /* 设置背景色,使用CSS变量 */ + background-color: var(--color-canvas-default); +} +.markdown-body { + /* 可附标题内容元素的间距 - 图片容器样式 */ +} +.markdown-body figure { + /* 设置上下外边距为1em,左右外边距为40px */ + margin: 1em 40px; +} +.markdown-body { + /* 间隔线 - 水平分隔线样式 */ + /* 一致化 horizontal rule - 统一水平分隔线样式 */ +} +.markdown-body 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 - 用于清除浮动 */ +} +.markdown-body hr::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body hr { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body hr::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 表单元素并不继承父级 font 的问题 - 表单元素字体继承 */ +} +.markdown-body button, +.markdown-body input, +.markdown-body select, +.markdown-body textarea { + /* 继承父元素的字体样式 */ + font: inherit; + /* 移除外边距 */ + margin: 0; + /* 设置溢出为可见 */ + overflow: visible; + /* 继承父元素的字体族 */ + font-family: inherit; + /* 继承父元素的字体大小 */ + font-size: inherit; + /* 继承父元素的行高 */ + line-height: inherit; +} +.markdown-body { + /* 外观显示为按钮 - 按钮类型输入框样式 */ +} +.markdown-body [type=button], +.markdown-body [type=reset], +.markdown-body [type=submit] { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 设置标准按钮外观,提高兼容性 */ + appearance: button; +} +.markdown-body { + /* 这两个表单样式规则覆盖 - 复选框和单选框样式 */ +} +.markdown-body [type=checkbox], +.markdown-body [type=radio] { + /* 设置盒模型为边框盒模型 */ + box-sizing: border-box; + /* 移除内边距 */ + padding: 0; +} +.markdown-body { + /* 数字按钮内部高度自动 - 数字输入框按钮样式 */ +} +.markdown-body [type=number]::-webkit-inner-spin-button, +.markdown-body [type=number]::-webkit-outer-spin-button { + /* 设置高度为自动,适应内容 */ + height: auto; +} +.markdown-body { + /* 搜索按钮内图标外观去除 - 搜索输入框样式 */ +} +.markdown-body [type=search]::-webkit-search-cancel-button, +.markdown-body [type=search]::-webkit-search-decoration { + /* 移除WebKit浏览器搜索框默认样式 */ + -webkit-appearance: none; +} +.markdown-body { + /* 输入框的占位符样式 - WebKit浏览器占位符样式 */ +} +.markdown-body ::-webkit-input-placeholder { + /* 继承父元素颜色 */ + color: inherit; + /* 设置透明度为0.54,创建半透明效果 */ + opacity: 0.54; +} +.markdown-body { + /* 文件选择按钮样式统一 - 文件上传按钮样式 */ +} +.markdown-body ::-webkit-file-upload-button { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 继承父元素字体样式 */ + font: inherit; +} +.markdown-body { + /* 占位符显示统一 - 通用占位符样式 */ +} +.markdown-body ::placeholder { + /* 设置占位符颜色,使用CSS变量 */ + color: var(--color-fg-subtle); + /* 设置完全不透明 */ + opacity: 1; +} +.markdown-body { + /* table内的td,th去除留白 - 表格单元格样式 */ +} +.markdown-body td, +.markdown-body th { + /* 移除表格单元格内边距 */ + padding: 0; +} +.markdown-body { + /* 伸缩框鼠标显示 - 详情框摘要样式 */ +} +.markdown-body details summary { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 未展开的详情框隐藏内容 - 详情框内容显示控制 */ +} +.markdown-body details:not([open]) > *:not(summary) { + /* 强制隐藏未展开详情框内的非摘要内容 */ + display: none !important; +} +.markdown-body { + /* 按键显示 - 键盘按键样式 */ +} +.markdown-body 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); +} +.markdown-body { + /* 清除浮动工具类 - 清除浮动伪元素 */ +} +.markdown-body .clearfix:before, +.markdown-body .clearfix:after { + /* 空内容,仅用于布局 */ + content: ""; + /* 设置为表格显示模式,用于清除浮动 */ + display: table; +} +.markdown-body { + /* 清除浮动工具类 - after伪元素 */ +} +.markdown-body .clearfix:after { + /* 清除左右浮动 */ + clear: both; +} +.markdown-body { + /* 清除浮动工具类 - 主容器 */ +} +.markdown-body .clearfix { + /* 触发IE的hasLayout属性,用于清除浮动 */ + zoom: 1; +} +.markdown-body { + /* 强制文本换行 - 文本换行工具类 */ +} +.markdown-body .textwrap, +.markdown-body .textwrap td, +.markdown-body .textwrap th { + /* 允许长单词在必要时换行,防止溢出 */ + word-wrap: break-word; + /* 强制在任意字符间换行,防止溢出 */ + word-break: break-all; +} +.markdown-body { + /* 文本换行表格 - 固定表格布局 */ +} +.markdown-body .textwrap-table { + /* 设置表格布局为固定,提高渲染性能 */ + table-layout: fixed; +} +.markdown-body { + /* 无序列表样式 - 项目符号列表 */ +} +.markdown-body ul { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为实心圆点 */ + list-style: disc; +} +.markdown-body { + /* 有序列表样式 - 数字列表 */ +} +.markdown-body ol { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为数字 */ + list-style: decimal; + /* 列表项样式 */ +} +.markdown-body ol li { + /* 设置左内边距为0.4em,增加数字与文本间距 */ + padding-left: 0.4em; +} +.markdown-body { + /* 相邻列表项间距 - 列表项之间的间距 */ +} +.markdown-body li + li { + /* 设置顶部外边距为0.25em,增加列表项间距 */ + margin-top: 0.25em; +} +.markdown-body { + /* 嵌套列表样式 - 列表项内的子列表 */ +} +.markdown-body li { + /* 无序子列表样式 */ +} +.markdown-body li ul { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; + /* 设置列表样式为空心圆点 */ + list-style: circle; + /* 三级无序列表样式 */ +} +.markdown-body li ul li ul { + /* 设置列表样式为实心方块 */ + list-style: square; +} +.markdown-body li { + /* 有序子列表样式 */ +} +.markdown-body li ol { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; +} +.markdown-body { + /* 任务列表项样式 - 待办事项列表项 */ +} +.markdown-body .task-list-item { + /* 移除列表样式,不显示项目符号 */ + list-style-type: none; + /* 设置相对定位,用于绝对定位子元素 */ + position: relative; + /* 第一个子输入框样式 */ +} +.markdown-body .task-list-item > input { + /* 第一个子元素右边距 */ +} +.markdown-body .task-list-item > input:nth-child(1) { + /* 设置右边距为6px */ + margin-right: 6px; +} +.markdown-body .task-list-item { + /* 标签样式 */ +} +.markdown-body .task-list-item label { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body .task-list-item { + /* 拖拽手柄样式 */ +} +.markdown-body .task-list-item .handle { + /* 隐藏拖拽手柄 */ + display: none; +} +.markdown-body .task-list-item { + /* 复选框样式 */ +} +.markdown-body .task-list-item 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; +} +.markdown-body { + /* 启用的任务列表项样式 */ +} +.markdown-body .task-list-item.enabled { + /* 标签样式 */ +} +.markdown-body .task-list-item.enabled label { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 相邻任务列表项间距 */ +} +.markdown-body .task-list-item + .task-list-item { + /* 设置顶部外边距为3px */ + margin-top: 3px; +} +.markdown-body { + /* 包含任务列表的容器样式 */ +} +.markdown-body .contains-task-list { + /* 从右到左文本方向样式 */ +} +.markdown-body .contains-task-list:dir(rtl) .task-list-item input[type=checkbox] { + /* 设置复选框外边距,适配RTL布局 */ + margin: 0 -1.6em 0.25em 0.2em; +} +.markdown-body { + /* 目录样式 - 表格目录容器 */ +} +.markdown-body .toc { + /* 重置左边距为0 */ + margin-left: 0; +} +.markdown-body { + /* 定义列表样式 - 描述列表容器 */ +} +.markdown-body 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; + /* 定义术语样式 */ +} +.markdown-body dl dt { + /* 设置为块级元素 */ + display: block; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} +.markdown-body dl { + /* 定义描述样式 */ +} +.markdown-body dl dd { + /* 设置为块级元素 */ + display: block; + /* 设置内联起始外边距为40px,创建缩进效果 */ + margin-inline-start: 40px; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} + +.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; +} +.markdown-body.green strong::before { + content: "『"; +} +.markdown-body.green strong::after { + content: "』"; +} +.markdown-body.green { + /* 块/段落引用 */ +} +.markdown-body.green 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; +} +.markdown-body.green blockquote > * { + position: relative; +} +.markdown-body.green blockquote > *:first-child:before { + content: "“"; + 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; +} +.markdown-body.green .tabs { + margin-top: 0; + margin-bottom: 1em; +} +.markdown-body.green { + /* 让链接在 hover 状态下显示下划线 */ +} +.markdown-body.green a { + position: relative; + z-index: 10; + transition: color 0.3s linear; + cursor: pointer; + font-weight: bolder; + text-decoration: none; + color: var(--color-base); + border-bottom: 1px solid currentColor; + padding: 0 4px; +} +.markdown-body.green a[data-footnote-backref], .markdown-body.green a[data-footnote-ref] { + border: none; +} +.markdown-body.green a[data-footnote-backref]:hover, .markdown-body.green a[data-footnote-ref]:hover { + background: none; + animation: none; +} +.markdown-body.green a:hover { + content: ""; + 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%; + } +} +.markdown-body.green pre { + background: var(--prism-background); + font-size: var(--prism-font-size); + display: block; + -webkit-overflow-scrolling: touch; +} +.markdown-body.green pre, +.markdown-body.green pre code { + font-family: var(--prism-font-family); +} +.markdown-body.green small, +.markdown-body.green figcaption { + font-size: 0.75em; + color: #888; +} +.markdown-body.green legend { + color: #000; + font-weight: inherit; +} +.markdown-body.green caption { + color: #000; + font-weight: inherit; +} +.markdown-body.green del { + text-decoration: line-through var(--color-base) 2px; +} +.markdown-body.green code { + color: rgb(45, 55, 72); + background-color: rgba(160, 174, 192, 0.25); + font-family: inherit; + font-size: 1em; + border-radius: 4px; + padding: 1px 6px; + margin: 0 2px; + vertical-align: bottom; +} +.markdown-body.green 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; +} +.markdown-body.green table { + width: 100%; + display: table; + border: 1px solid var(--color-light); +} +.markdown-body.green table tr:hover { + background: var(--color-light); +} +.markdown-body.green table:hover { + border: 1px solid var(--color-extra); +} +.markdown-body.green table:hover th { + border-right: 1px solid var(--color-extra); + background: var(--color-extra); + border-bottom: 1px solid var(--color-extra); +} +.markdown-body.green table:hover td { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover caption { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover thead th { + background: var(--color-extra); +} +.markdown-body.green table th { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + background: var(--color-light); + border-bottom: 1px solid var(--color-light); +} +.markdown-body.green table td { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; +} +.markdown-body.green table caption { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + border-bottom: none; +} +.markdown-body.green table thead th { + background: var(--color-extra); +} +.markdown-body.green h1, +.markdown-body.green h2, +.markdown-body.green h3, +.markdown-body.green h4, +.markdown-body.green h5, +.markdown-body.green h6 { + margin-top: 1.2em; + margin-bottom: 0.6em; + line-height: 1.35; + position: relative; +} +.markdown-body.green h1 { + font-size: 1.8em; +} +.markdown-body.green h2 { + font-size: 1.6em; +} +.markdown-body.green h3 { + font-size: 1.4em; +} +.markdown-body.green h4 { + font-size: 1.2em; +} +.markdown-body.green h5 { + font-size: 1em; +} +.markdown-body.green h6 { + font-size: 1em; +} +.markdown-body.green ::-webkit-calendar-picker-indicator { + filter: invert(50%); +} +.markdown-body.green em { + font-weight: inherit; + position: relative; +} +.markdown-body.green em:after { + position: absolute; + top: 0.65em; + left: 0; + width: 100%; + overflow: hidden; + white-space: nowrap; + pointer-events: none; + color: var(--color-base); + content: "・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・"; +} +.markdown-body.green ul.toc li { + list-style-type: none; +} +.markdown-body.green ul.toc li a { + text-decoration: none; + border: 0; + list-style-type: none; +} +.markdown-body.green.chinese { + text-indent: 1.5em; + font-weight: 300; +} +.markdown-body.green.chinese h1, +.markdown-body.green.chinese h2, +.markdown-body.green.chinese h3, +.markdown-body.green.chinese h4, +.markdown-body.green.chinese h5, +.markdown-body.green.chinese h6, +.markdown-body.green.chinese ol, +.markdown-body.green.chinese ul, +.markdown-body.green.chinese blockquote, +.markdown-body.green.chinese details, +.markdown-body.green.chinese summary, +.markdown-body.green.chinese pre, +.markdown-body.green.chinese .tabs { + text-indent: 0; +} \ No newline at end of file diff --git a/public/scss-compiler/page/index/index.css b/public/scss-compiler/page/index/index.css new file mode 100644 index 0000000..4189666 --- /dev/null +++ b/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; + } +} \ No newline at end of file diff --git a/public/scss-compiler/page/index/markdown-green.css b/public/scss-compiler/page/index/markdown-green.css new file mode 100644 index 0000000..403ce31 --- /dev/null +++ b/public/scss-compiler/page/index/markdown-green.css @@ -0,0 +1,1188 @@ +@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; + } +} +/* 深色主题媒体查询 - 当用户系统偏好深色模式时应用 */ +@media (prefers-color-scheme: dark) { + .markdown-body { + /* 告诉浏览器使用深色配色方案,影响滚动条等系统UI元素 */ + color-scheme: dark; + } +} +/* 浅色主题媒体查询 - 当用户系统偏好浅色模式时应用 */ +@media (prefers-color-scheme: light) { + .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); + --color-mark-fg: rgb(255, 187, 0); + } +} +/* 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 - 用于清除浮动 */ +} +.markdown-body::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 第一个子元素 - 移除顶部外边距 */ +} +.markdown-body > *:first-child { + /* 强制移除顶部外边距,避免不必要的空白 */ + margin-top: 0 !important; +} +.markdown-body { + /* 最后一个子元素 - 移除底部外边距 */ +} +.markdown-body > *:last-child { + /* 强制移除底部外边距,避免不必要的空白 */ + margin-bottom: 0 !important; +} +.markdown-body { + /* 块级元素统一间距设置 - 段落、引用、列表、表格等 */ +} +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body hr, +.markdown-body form, +.markdown-body pre, +.markdown-body details { + /* 移除顶部外边距,避免重复间距 */ + margin-top: 0; + /* 设置底部外边距为1em,保持适当间距 */ + margin-bottom: 1em; +} +.markdown-body { + /* 引用块内部元素间距处理 */ +} +.markdown-body blockquote { + /* 引用块内第一个子元素 - 移除顶部外边距 */ +} +.markdown-body blockquote > :first-child { + margin-top: 0; +} +.markdown-body blockquote { + /* 引用块内最后一个子元素 - 移除底部外边距 */ +} +.markdown-body blockquote > :last-child { + margin-bottom: 0; +} +.markdown-body { + /* 统一显示成块状元素 - 确保这些元素独占一行 */ +} +.markdown-body details, +.markdown-body figcaption, +.markdown-body figure { + /* 设置为块级元素,独占一行显示 */ + display: block; +} +.markdown-body { + /* HTML5 媒体文件跟 img 保持一致 - 内联块级元素 */ +} +.markdown-body audio, +.markdown-body canvas, +.markdown-body video { + /* 设置为内联块级元素,可以设置宽高但不会独占一行 */ + display: inline-block; +} +.markdown-body { + /* 按钮内部间距统一 - 移除Firefox默认内边距 */ +} +.markdown-body button::-moz-focus-inner, +.markdown-body input::-moz-focus-inner { + /* 移除Firefox浏览器按钮和输入框的内部内边距 */ + padding: 0; + /* 移除Firefox浏览器按钮和输入框的内部边框 */ + border: 0; +} +.markdown-body { + /* 定义元素显示为斜体 - 术语定义样式 */ +} +.markdown-body dfn { + /* 设置字体为斜体,用于术语定义 */ + font-style: italic; +} +.markdown-body { + /* 去掉各Table cell 的边距并让其边重合 - 表格样式统一 */ +} +.markdown-body table { + /* 合并表格边框,相邻单元格边框合并为一条 */ + border-collapse: collapse; + /* 设置表格单元格间距为0 */ + border-spacing: 0; + /* 设置为块级元素,可以设置宽高 */ + display: block; + /* 宽度根据内容自适应 */ + width: max-content; + /* 最大宽度不超过父容器 */ + max-width: 100%; + /* 内容溢出时显示滚动条 */ + overflow: auto; +} +.markdown-body { + /* 可拖动文件添加拖动手势 - 拖拽元素样式 */ +} +.markdown-body [draggable] { + /* 设置鼠标悬停时显示移动光标 */ + cursor: move; +} +.markdown-body { + /* 加粗元素 - 粗体文本样式 */ +} +.markdown-body b, +.markdown-body strong { + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); +} +.markdown-body { + /* 缩写元素样式统一 - 缩写和首字母缩写样式 */ +} +.markdown-body abbr, +.markdown-body acronym { + /* 移除底部边框 */ + border-bottom: none; + /* 设置字体变体为正常 */ + font-variant: normal; + /* 设置虚线下划线装饰 */ + text-decoration: underline dotted; +} +.markdown-body { + /* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */ +} +.markdown-body abbr { + /* 设置鼠标悬停时显示帮助光标 */ + cursor: help; +} +.markdown-body { + /* 一致的 del 样式 - 删除线文本样式 */ +} +.markdown-body del { + /* 设置文本装饰为删除线 */ + text-decoration: line-through; +} +.markdown-body { + /* a标签去除下划线 - 链接样式处理 */ +} +.markdown-body a { + /* 默认移除下划线,保持页面简洁 */ + text-decoration: none; + /* 没有href属性的链接样式 */ +} +.markdown-body a:not([href]) { + /* 继承父元素颜色 */ + color: inherit; + /* 移除下划线装饰 */ + text-decoration: none; +} +.markdown-body a { + /* 鼠标悬停时显示下划线 */ +} +.markdown-body a:hover { + text-decoration: underline; +} +.markdown-body { + /* 默认不显示下划线,保持页面简洁 - 插入文本样式 */ +} +.markdown-body ins { + /* 移除下划线装饰,保持页面简洁 */ + text-decoration: none; +} +.markdown-body { + /* 专名号:虽然 u 已经重回 html5 Draft,但在所有浏览器中都是可以使用的, + * 要做到更好,向后兼容的话,添加 class="typo-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 + * 一篇关于 标签的很好文章:http://html5doctor.com/u-element/ + */ +} +.markdown-body u, +.markdown-body .typo-u { + /* 设置文本装饰为下划线,用于专名号显示 */ + text-decoration: underline; +} +.markdown-body { + /* 隐藏指定元素 - 隐藏带有hidden属性的元素 */ +} +.markdown-body [hidden] { + /* 强制隐藏元素,优先级最高 */ + display: none !important; +} +.markdown-body { + /* 伸缩框显示为列表元素 - 详情框摘要样式 */ +} +.markdown-body summary { + /* 设置为列表项显示,显示为可点击的列表项 */ + display: list-item; +} +.markdown-body { + /* 引用元素前后内容 - 移除默认引号 */ +} +.markdown-body q:before, +.markdown-body q:after { + /* 移除引用元素前后的默认引号内容 */ + content: ""; +} +.markdown-body { + /* 表格标题和表头文本对齐 - 默认左对齐 */ +} +.markdown-body caption, +.markdown-body th { + /* 设置文本左对齐 */ + text-align: left; +} +.markdown-body { + /* 居中对齐的表格标题和表头 */ +} +.markdown-body caption[align=center], +.markdown-body th[align=center] { + /* 设置文本居中对齐 */ + text-align: center; +} +.markdown-body { + /* 特定元素字体粗细统一 - 地址、标题、引用等 */ +} +.markdown-body address, +.markdown-body caption, +.markdown-body cite, +.markdown-body em, +.markdown-body th, +.markdown-body var { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body { + /* 标记,类似于手写的荧光笔的作用 - 高亮标记样式 */ +} +.markdown-body mark { + /* 设置标记背景色,使用CSS变量 */ + background: var(--color-mark-default); + /* 设置内边距,增加标记的可读性 */ + padding: 2px; + /* 激活状态的标记样式 */ +} +.markdown-body mark.active { + /* 激活时使用强调色背景 */ + background: var(--color-mark-fg); +} +.markdown-body { + /* 统一h1元素的间隔和字体大小 - 一级标题样式 */ +} +.markdown-body h1 { + /* 设置上下外边距为0.67em */ + margin: 0.67em 0; + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); + /* 设置字体大小为2倍基础大小 */ + font-size: 2em; +} +.markdown-body { + /* small字体缩小 - 小字体文本样式 */ +} +.markdown-body small { + /* 设置字体大小为父元素的90% */ + font-size: 90%; +} +.markdown-body { + /* 上下标显示 - 下标和上标文本样式 */ +} +.markdown-body sub, +.markdown-body sup { + /* 设置字体大小为75% */ + font-size: 75%; + /* 设置行高为0,避免影响行间距 */ + line-height: 0; + /* 设置相对定位,用于精确控制位置 */ + position: relative; + /* 设置垂直对齐为基线 */ + vertical-align: baseline; +} +.markdown-body { + /* 上下标内链接样式 */ +} +.markdown-body sub a, +.markdown-body sup a { + /* 设置左右内边距为0.1em */ + padding: 0 0.1em; +} +.markdown-body { + /* 下标位置调整 */ +} +.markdown-body sub { + /* 向下偏移0.25em */ + bottom: -0.25em; +} +.markdown-body { + /* 上标位置调整 */ +} +.markdown-body sup { + /* 向上偏移0.5em */ + top: -0.5em; +} +.markdown-body { + /* 代码相关的字体大小统一 - 代码元素字体样式 */ +} +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp, +.markdown-body pre tt { + /* 设置字体为等宽字体,便于代码阅读 */ + font-family: monospace; + /* 设置字体大小为1em,保持一致性 */ + font-size: 1em; +} +.markdown-body { + /* 去除默认边框 - 移除字段集和图片的默认边框 */ +} +.markdown-body fieldset, +.markdown-body img { + /* 移除边框 */ + border: 0; +} +.markdown-body { + /* 图片初始化样式 - 图片元素基础样式 */ +} +.markdown-body img { + /* 设置边框样式为无 */ + border-style: none; + /* 设置最大宽度为100%,防止溢出 */ + max-width: 100%; + /* 设置盒模型为内容盒模型 */ + box-sizing: content-box; + /* 设置左右外边距为自动,实现居中 */ + margin: 0 auto; + /* 设置背景色,使用CSS变量 */ + background-color: var(--color-canvas-default); +} +.markdown-body { + /* 可附标题内容元素的间距 - 图片容器样式 */ +} +.markdown-body figure { + /* 设置上下外边距为1em,左右外边距为40px */ + margin: 1em 40px; +} +.markdown-body { + /* 间隔线 - 水平分隔线样式 */ + /* 一致化 horizontal rule - 统一水平分隔线样式 */ +} +.markdown-body 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 - 用于清除浮动 */ +} +.markdown-body hr::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body hr { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body hr::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 表单元素并不继承父级 font 的问题 - 表单元素字体继承 */ +} +.markdown-body button, +.markdown-body input, +.markdown-body select, +.markdown-body textarea { + /* 继承父元素的字体样式 */ + font: inherit; + /* 移除外边距 */ + margin: 0; + /* 设置溢出为可见 */ + overflow: visible; + /* 继承父元素的字体族 */ + font-family: inherit; + /* 继承父元素的字体大小 */ + font-size: inherit; + /* 继承父元素的行高 */ + line-height: inherit; +} +.markdown-body { + /* 外观显示为按钮 - 按钮类型输入框样式 */ +} +.markdown-body [type=button], +.markdown-body [type=reset], +.markdown-body [type=submit] { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 设置标准按钮外观,提高兼容性 */ + appearance: button; +} +.markdown-body { + /* 这两个表单样式规则覆盖 - 复选框和单选框样式 */ +} +.markdown-body [type=checkbox], +.markdown-body [type=radio] { + /* 设置盒模型为边框盒模型 */ + box-sizing: border-box; + /* 移除内边距 */ + padding: 0; +} +.markdown-body { + /* 数字按钮内部高度自动 - 数字输入框按钮样式 */ +} +.markdown-body [type=number]::-webkit-inner-spin-button, +.markdown-body [type=number]::-webkit-outer-spin-button { + /* 设置高度为自动,适应内容 */ + height: auto; +} +.markdown-body { + /* 搜索按钮内图标外观去除 - 搜索输入框样式 */ +} +.markdown-body [type=search]::-webkit-search-cancel-button, +.markdown-body [type=search]::-webkit-search-decoration { + /* 移除WebKit浏览器搜索框默认样式 */ + -webkit-appearance: none; +} +.markdown-body { + /* 输入框的占位符样式 - WebKit浏览器占位符样式 */ +} +.markdown-body ::-webkit-input-placeholder { + /* 继承父元素颜色 */ + color: inherit; + /* 设置透明度为0.54,创建半透明效果 */ + opacity: 0.54; +} +.markdown-body { + /* 文件选择按钮样式统一 - 文件上传按钮样式 */ +} +.markdown-body ::-webkit-file-upload-button { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 继承父元素字体样式 */ + font: inherit; +} +.markdown-body { + /* 占位符显示统一 - 通用占位符样式 */ +} +.markdown-body ::placeholder { + /* 设置占位符颜色,使用CSS变量 */ + color: var(--color-fg-subtle); + /* 设置完全不透明 */ + opacity: 1; +} +.markdown-body { + /* table内的td,th去除留白 - 表格单元格样式 */ +} +.markdown-body td, +.markdown-body th { + /* 移除表格单元格内边距 */ + padding: 0; +} +.markdown-body { + /* 伸缩框鼠标显示 - 详情框摘要样式 */ +} +.markdown-body details summary { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 未展开的详情框隐藏内容 - 详情框内容显示控制 */ +} +.markdown-body details:not([open]) > *:not(summary) { + /* 强制隐藏未展开详情框内的非摘要内容 */ + display: none !important; +} +.markdown-body { + /* 按键显示 - 键盘按键样式 */ +} +.markdown-body 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); +} +.markdown-body { + /* 清除浮动工具类 - 清除浮动伪元素 */ +} +.markdown-body .clearfix:before, +.markdown-body .clearfix:after { + /* 空内容,仅用于布局 */ + content: ""; + /* 设置为表格显示模式,用于清除浮动 */ + display: table; +} +.markdown-body { + /* 清除浮动工具类 - after伪元素 */ +} +.markdown-body .clearfix:after { + /* 清除左右浮动 */ + clear: both; +} +.markdown-body { + /* 清除浮动工具类 - 主容器 */ +} +.markdown-body .clearfix { + /* 触发IE的hasLayout属性,用于清除浮动 */ + zoom: 1; +} +.markdown-body { + /* 强制文本换行 - 文本换行工具类 */ +} +.markdown-body .textwrap, +.markdown-body .textwrap td, +.markdown-body .textwrap th { + /* 允许长单词在必要时换行,防止溢出 */ + word-wrap: break-word; + /* 强制在任意字符间换行,防止溢出 */ + word-break: break-all; +} +.markdown-body { + /* 文本换行表格 - 固定表格布局 */ +} +.markdown-body .textwrap-table { + /* 设置表格布局为固定,提高渲染性能 */ + table-layout: fixed; +} +.markdown-body { + /* 无序列表样式 - 项目符号列表 */ +} +.markdown-body ul { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为实心圆点 */ + list-style: disc; +} +.markdown-body { + /* 有序列表样式 - 数字列表 */ +} +.markdown-body ol { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为数字 */ + list-style: decimal; + /* 列表项样式 */ +} +.markdown-body ol li { + /* 设置左内边距为0.4em,增加数字与文本间距 */ + padding-left: 0.4em; +} +.markdown-body { + /* 相邻列表项间距 - 列表项之间的间距 */ +} +.markdown-body li + li { + /* 设置顶部外边距为0.25em,增加列表项间距 */ + margin-top: 0.25em; +} +.markdown-body { + /* 嵌套列表样式 - 列表项内的子列表 */ +} +.markdown-body li { + /* 无序子列表样式 */ +} +.markdown-body li ul { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; + /* 设置列表样式为空心圆点 */ + list-style: circle; + /* 三级无序列表样式 */ +} +.markdown-body li ul li ul { + /* 设置列表样式为实心方块 */ + list-style: square; +} +.markdown-body li { + /* 有序子列表样式 */ +} +.markdown-body li ol { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; +} +.markdown-body { + /* 任务列表项样式 - 待办事项列表项 */ +} +.markdown-body .task-list-item { + /* 移除列表样式,不显示项目符号 */ + list-style-type: none; + /* 设置相对定位,用于绝对定位子元素 */ + position: relative; + /* 第一个子输入框样式 */ +} +.markdown-body .task-list-item > input { + /* 第一个子元素右边距 */ +} +.markdown-body .task-list-item > input:nth-child(1) { + /* 设置右边距为6px */ + margin-right: 6px; +} +.markdown-body .task-list-item { + /* 标签样式 */ +} +.markdown-body .task-list-item label { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body .task-list-item { + /* 拖拽手柄样式 */ +} +.markdown-body .task-list-item .handle { + /* 隐藏拖拽手柄 */ + display: none; +} +.markdown-body .task-list-item { + /* 复选框样式 */ +} +.markdown-body .task-list-item 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; +} +.markdown-body { + /* 启用的任务列表项样式 */ +} +.markdown-body .task-list-item.enabled { + /* 标签样式 */ +} +.markdown-body .task-list-item.enabled label { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 相邻任务列表项间距 */ +} +.markdown-body .task-list-item + .task-list-item { + /* 设置顶部外边距为3px */ + margin-top: 3px; +} +.markdown-body { + /* 包含任务列表的容器样式 */ +} +.markdown-body .contains-task-list { + /* 从右到左文本方向样式 */ +} +.markdown-body .contains-task-list:dir(rtl) .task-list-item input[type=checkbox] { + /* 设置复选框外边距,适配RTL布局 */ + margin: 0 -1.6em 0.25em 0.2em; +} +.markdown-body { + /* 目录样式 - 表格目录容器 */ +} +.markdown-body .toc { + /* 重置左边距为0 */ + margin-left: 0; +} +.markdown-body { + /* 定义列表样式 - 描述列表容器 */ +} +.markdown-body 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; + /* 定义术语样式 */ +} +.markdown-body dl dt { + /* 设置为块级元素 */ + display: block; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} +.markdown-body dl { + /* 定义描述样式 */ +} +.markdown-body dl dd { + /* 设置为块级元素 */ + display: block; + /* 设置内联起始外边距为40px,创建缩进效果 */ + margin-inline-start: 40px; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} + +.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; +} +.markdown-body.green strong::before { + content: "『"; +} +.markdown-body.green strong::after { + content: "』"; +} +.markdown-body.green { + /* 块/段落引用 */ +} +.markdown-body.green 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; +} +.markdown-body.green blockquote > * { + position: relative; +} +.markdown-body.green blockquote > *:first-child:before { + content: "“"; + 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; +} +.markdown-body.green .tabs { + margin-top: 0; + margin-bottom: 1em; +} +.markdown-body.green { + /* 让链接在 hover 状态下显示下划线 */ +} +.markdown-body.green a { + position: relative; + z-index: 10; + transition: color 0.3s linear; + cursor: pointer; + font-weight: bolder; + text-decoration: none; + color: var(--color-base); + border-bottom: 1px solid currentColor; + padding: 0 4px; +} +.markdown-body.green a[data-footnote-backref], .markdown-body.green a[data-footnote-ref] { + border: none; +} +.markdown-body.green a[data-footnote-backref]:hover, .markdown-body.green a[data-footnote-ref]:hover { + background: none; + animation: none; +} +.markdown-body.green a:hover { + content: ""; + 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%; + } +} +.markdown-body.green pre { + background: var(--prism-background); + font-size: var(--prism-font-size); + display: block; + -webkit-overflow-scrolling: touch; +} +.markdown-body.green pre, +.markdown-body.green pre code { + font-family: var(--prism-font-family); +} +.markdown-body.green small, +.markdown-body.green figcaption { + font-size: 0.75em; + color: #888; +} +.markdown-body.green legend { + color: #000; + font-weight: inherit; +} +.markdown-body.green caption { + color: #000; + font-weight: inherit; +} +.markdown-body.green del { + text-decoration: line-through var(--color-base) 2px; +} +.markdown-body.green code { + color: rgb(45, 55, 72); + background-color: rgba(160, 174, 192, 0.25); + font-family: inherit; + font-size: 1em; + border-radius: 4px; + padding: 1px 6px; + margin: 0 2px; + vertical-align: bottom; +} +.markdown-body.green 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; +} +.markdown-body.green table { + width: 100%; + display: table; + border: 1px solid var(--color-light); +} +.markdown-body.green table tr:hover { + background: var(--color-light); +} +.markdown-body.green table:hover { + border: 1px solid var(--color-extra); +} +.markdown-body.green table:hover th { + border-right: 1px solid var(--color-extra); + background: var(--color-extra); + border-bottom: 1px solid var(--color-extra); +} +.markdown-body.green table:hover td { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover caption { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover thead th { + background: var(--color-extra); +} +.markdown-body.green table th { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + background: var(--color-light); + border-bottom: 1px solid var(--color-light); +} +.markdown-body.green table td { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; +} +.markdown-body.green table caption { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + border-bottom: none; +} +.markdown-body.green table thead th { + background: var(--color-extra); +} +.markdown-body.green h1, +.markdown-body.green h2, +.markdown-body.green h3, +.markdown-body.green h4, +.markdown-body.green h5, +.markdown-body.green h6 { + margin-top: 1.2em; + margin-bottom: 0.6em; + line-height: 1.35; + position: relative; +} +.markdown-body.green h1 { + font-size: 1.8em; +} +.markdown-body.green h2 { + font-size: 1.6em; +} +.markdown-body.green h3 { + font-size: 1.4em; +} +.markdown-body.green h4 { + font-size: 1.2em; +} +.markdown-body.green h5 { + font-size: 1em; +} +.markdown-body.green h6 { + font-size: 1em; +} +.markdown-body.green ::-webkit-calendar-picker-indicator { + filter: invert(50%); +} +.markdown-body.green em { + font-weight: inherit; + position: relative; +} +.markdown-body.green em:after { + position: absolute; + top: 0.65em; + left: 0; + width: 100%; + overflow: hidden; + white-space: nowrap; + pointer-events: none; + color: var(--color-base); + content: "・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・"; +} +.markdown-body.green ul.toc li { + list-style-type: none; +} +.markdown-body.green ul.toc li a { + text-decoration: none; + border: 0; + list-style-type: none; +} +.markdown-body.green.chinese { + text-indent: 1.5em; + font-weight: 300; +} +.markdown-body.green.chinese h1, +.markdown-body.green.chinese h2, +.markdown-body.green.chinese h3, +.markdown-body.green.chinese h4, +.markdown-body.green.chinese h5, +.markdown-body.green.chinese h6, +.markdown-body.green.chinese ol, +.markdown-body.green.chinese ul, +.markdown-body.green.chinese blockquote, +.markdown-body.green.chinese details, +.markdown-body.green.chinese summary, +.markdown-body.green.chinese pre, +.markdown-body.green.chinese .tabs { + text-indent: 0; +} \ No newline at end of file diff --git a/public/scss-compiler/page/index/markdown-reset.css b/public/scss-compiler/page/index/markdown-reset.css new file mode 100644 index 0000000..403ce31 --- /dev/null +++ b/public/scss-compiler/page/index/markdown-reset.css @@ -0,0 +1,1188 @@ +@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; + } +} +/* 深色主题媒体查询 - 当用户系统偏好深色模式时应用 */ +@media (prefers-color-scheme: dark) { + .markdown-body { + /* 告诉浏览器使用深色配色方案,影响滚动条等系统UI元素 */ + color-scheme: dark; + } +} +/* 浅色主题媒体查询 - 当用户系统偏好浅色模式时应用 */ +@media (prefers-color-scheme: light) { + .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); + --color-mark-fg: rgb(255, 187, 0); + } +} +/* 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 - 用于清除浮动 */ +} +.markdown-body::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 第一个子元素 - 移除顶部外边距 */ +} +.markdown-body > *:first-child { + /* 强制移除顶部外边距,避免不必要的空白 */ + margin-top: 0 !important; +} +.markdown-body { + /* 最后一个子元素 - 移除底部外边距 */ +} +.markdown-body > *:last-child { + /* 强制移除底部外边距,避免不必要的空白 */ + margin-bottom: 0 !important; +} +.markdown-body { + /* 块级元素统一间距设置 - 段落、引用、列表、表格等 */ +} +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body hr, +.markdown-body form, +.markdown-body pre, +.markdown-body details { + /* 移除顶部外边距,避免重复间距 */ + margin-top: 0; + /* 设置底部外边距为1em,保持适当间距 */ + margin-bottom: 1em; +} +.markdown-body { + /* 引用块内部元素间距处理 */ +} +.markdown-body blockquote { + /* 引用块内第一个子元素 - 移除顶部外边距 */ +} +.markdown-body blockquote > :first-child { + margin-top: 0; +} +.markdown-body blockquote { + /* 引用块内最后一个子元素 - 移除底部外边距 */ +} +.markdown-body blockquote > :last-child { + margin-bottom: 0; +} +.markdown-body { + /* 统一显示成块状元素 - 确保这些元素独占一行 */ +} +.markdown-body details, +.markdown-body figcaption, +.markdown-body figure { + /* 设置为块级元素,独占一行显示 */ + display: block; +} +.markdown-body { + /* HTML5 媒体文件跟 img 保持一致 - 内联块级元素 */ +} +.markdown-body audio, +.markdown-body canvas, +.markdown-body video { + /* 设置为内联块级元素,可以设置宽高但不会独占一行 */ + display: inline-block; +} +.markdown-body { + /* 按钮内部间距统一 - 移除Firefox默认内边距 */ +} +.markdown-body button::-moz-focus-inner, +.markdown-body input::-moz-focus-inner { + /* 移除Firefox浏览器按钮和输入框的内部内边距 */ + padding: 0; + /* 移除Firefox浏览器按钮和输入框的内部边框 */ + border: 0; +} +.markdown-body { + /* 定义元素显示为斜体 - 术语定义样式 */ +} +.markdown-body dfn { + /* 设置字体为斜体,用于术语定义 */ + font-style: italic; +} +.markdown-body { + /* 去掉各Table cell 的边距并让其边重合 - 表格样式统一 */ +} +.markdown-body table { + /* 合并表格边框,相邻单元格边框合并为一条 */ + border-collapse: collapse; + /* 设置表格单元格间距为0 */ + border-spacing: 0; + /* 设置为块级元素,可以设置宽高 */ + display: block; + /* 宽度根据内容自适应 */ + width: max-content; + /* 最大宽度不超过父容器 */ + max-width: 100%; + /* 内容溢出时显示滚动条 */ + overflow: auto; +} +.markdown-body { + /* 可拖动文件添加拖动手势 - 拖拽元素样式 */ +} +.markdown-body [draggable] { + /* 设置鼠标悬停时显示移动光标 */ + cursor: move; +} +.markdown-body { + /* 加粗元素 - 粗体文本样式 */ +} +.markdown-body b, +.markdown-body strong { + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); +} +.markdown-body { + /* 缩写元素样式统一 - 缩写和首字母缩写样式 */ +} +.markdown-body abbr, +.markdown-body acronym { + /* 移除底部边框 */ + border-bottom: none; + /* 设置字体变体为正常 */ + font-variant: normal; + /* 设置虚线下划线装饰 */ + text-decoration: underline dotted; +} +.markdown-body { + /* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */ +} +.markdown-body abbr { + /* 设置鼠标悬停时显示帮助光标 */ + cursor: help; +} +.markdown-body { + /* 一致的 del 样式 - 删除线文本样式 */ +} +.markdown-body del { + /* 设置文本装饰为删除线 */ + text-decoration: line-through; +} +.markdown-body { + /* a标签去除下划线 - 链接样式处理 */ +} +.markdown-body a { + /* 默认移除下划线,保持页面简洁 */ + text-decoration: none; + /* 没有href属性的链接样式 */ +} +.markdown-body a:not([href]) { + /* 继承父元素颜色 */ + color: inherit; + /* 移除下划线装饰 */ + text-decoration: none; +} +.markdown-body a { + /* 鼠标悬停时显示下划线 */ +} +.markdown-body a:hover { + text-decoration: underline; +} +.markdown-body { + /* 默认不显示下划线,保持页面简洁 - 插入文本样式 */ +} +.markdown-body ins { + /* 移除下划线装饰,保持页面简洁 */ + text-decoration: none; +} +.markdown-body { + /* 专名号:虽然 u 已经重回 html5 Draft,但在所有浏览器中都是可以使用的, + * 要做到更好,向后兼容的话,添加 class="typo-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 + * 一篇关于 标签的很好文章:http://html5doctor.com/u-element/ + */ +} +.markdown-body u, +.markdown-body .typo-u { + /* 设置文本装饰为下划线,用于专名号显示 */ + text-decoration: underline; +} +.markdown-body { + /* 隐藏指定元素 - 隐藏带有hidden属性的元素 */ +} +.markdown-body [hidden] { + /* 强制隐藏元素,优先级最高 */ + display: none !important; +} +.markdown-body { + /* 伸缩框显示为列表元素 - 详情框摘要样式 */ +} +.markdown-body summary { + /* 设置为列表项显示,显示为可点击的列表项 */ + display: list-item; +} +.markdown-body { + /* 引用元素前后内容 - 移除默认引号 */ +} +.markdown-body q:before, +.markdown-body q:after { + /* 移除引用元素前后的默认引号内容 */ + content: ""; +} +.markdown-body { + /* 表格标题和表头文本对齐 - 默认左对齐 */ +} +.markdown-body caption, +.markdown-body th { + /* 设置文本左对齐 */ + text-align: left; +} +.markdown-body { + /* 居中对齐的表格标题和表头 */ +} +.markdown-body caption[align=center], +.markdown-body th[align=center] { + /* 设置文本居中对齐 */ + text-align: center; +} +.markdown-body { + /* 特定元素字体粗细统一 - 地址、标题、引用等 */ +} +.markdown-body address, +.markdown-body caption, +.markdown-body cite, +.markdown-body em, +.markdown-body th, +.markdown-body var { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body { + /* 标记,类似于手写的荧光笔的作用 - 高亮标记样式 */ +} +.markdown-body mark { + /* 设置标记背景色,使用CSS变量 */ + background: var(--color-mark-default); + /* 设置内边距,增加标记的可读性 */ + padding: 2px; + /* 激活状态的标记样式 */ +} +.markdown-body mark.active { + /* 激活时使用强调色背景 */ + background: var(--color-mark-fg); +} +.markdown-body { + /* 统一h1元素的间隔和字体大小 - 一级标题样式 */ +} +.markdown-body h1 { + /* 设置上下外边距为0.67em */ + margin: 0.67em 0; + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); + /* 设置字体大小为2倍基础大小 */ + font-size: 2em; +} +.markdown-body { + /* small字体缩小 - 小字体文本样式 */ +} +.markdown-body small { + /* 设置字体大小为父元素的90% */ + font-size: 90%; +} +.markdown-body { + /* 上下标显示 - 下标和上标文本样式 */ +} +.markdown-body sub, +.markdown-body sup { + /* 设置字体大小为75% */ + font-size: 75%; + /* 设置行高为0,避免影响行间距 */ + line-height: 0; + /* 设置相对定位,用于精确控制位置 */ + position: relative; + /* 设置垂直对齐为基线 */ + vertical-align: baseline; +} +.markdown-body { + /* 上下标内链接样式 */ +} +.markdown-body sub a, +.markdown-body sup a { + /* 设置左右内边距为0.1em */ + padding: 0 0.1em; +} +.markdown-body { + /* 下标位置调整 */ +} +.markdown-body sub { + /* 向下偏移0.25em */ + bottom: -0.25em; +} +.markdown-body { + /* 上标位置调整 */ +} +.markdown-body sup { + /* 向上偏移0.5em */ + top: -0.5em; +} +.markdown-body { + /* 代码相关的字体大小统一 - 代码元素字体样式 */ +} +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp, +.markdown-body pre tt { + /* 设置字体为等宽字体,便于代码阅读 */ + font-family: monospace; + /* 设置字体大小为1em,保持一致性 */ + font-size: 1em; +} +.markdown-body { + /* 去除默认边框 - 移除字段集和图片的默认边框 */ +} +.markdown-body fieldset, +.markdown-body img { + /* 移除边框 */ + border: 0; +} +.markdown-body { + /* 图片初始化样式 - 图片元素基础样式 */ +} +.markdown-body img { + /* 设置边框样式为无 */ + border-style: none; + /* 设置最大宽度为100%,防止溢出 */ + max-width: 100%; + /* 设置盒模型为内容盒模型 */ + box-sizing: content-box; + /* 设置左右外边距为自动,实现居中 */ + margin: 0 auto; + /* 设置背景色,使用CSS变量 */ + background-color: var(--color-canvas-default); +} +.markdown-body { + /* 可附标题内容元素的间距 - 图片容器样式 */ +} +.markdown-body figure { + /* 设置上下外边距为1em,左右外边距为40px */ + margin: 1em 40px; +} +.markdown-body { + /* 间隔线 - 水平分隔线样式 */ + /* 一致化 horizontal rule - 统一水平分隔线样式 */ +} +.markdown-body 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 - 用于清除浮动 */ +} +.markdown-body hr::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body hr { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body hr::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 表单元素并不继承父级 font 的问题 - 表单元素字体继承 */ +} +.markdown-body button, +.markdown-body input, +.markdown-body select, +.markdown-body textarea { + /* 继承父元素的字体样式 */ + font: inherit; + /* 移除外边距 */ + margin: 0; + /* 设置溢出为可见 */ + overflow: visible; + /* 继承父元素的字体族 */ + font-family: inherit; + /* 继承父元素的字体大小 */ + font-size: inherit; + /* 继承父元素的行高 */ + line-height: inherit; +} +.markdown-body { + /* 外观显示为按钮 - 按钮类型输入框样式 */ +} +.markdown-body [type=button], +.markdown-body [type=reset], +.markdown-body [type=submit] { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 设置标准按钮外观,提高兼容性 */ + appearance: button; +} +.markdown-body { + /* 这两个表单样式规则覆盖 - 复选框和单选框样式 */ +} +.markdown-body [type=checkbox], +.markdown-body [type=radio] { + /* 设置盒模型为边框盒模型 */ + box-sizing: border-box; + /* 移除内边距 */ + padding: 0; +} +.markdown-body { + /* 数字按钮内部高度自动 - 数字输入框按钮样式 */ +} +.markdown-body [type=number]::-webkit-inner-spin-button, +.markdown-body [type=number]::-webkit-outer-spin-button { + /* 设置高度为自动,适应内容 */ + height: auto; +} +.markdown-body { + /* 搜索按钮内图标外观去除 - 搜索输入框样式 */ +} +.markdown-body [type=search]::-webkit-search-cancel-button, +.markdown-body [type=search]::-webkit-search-decoration { + /* 移除WebKit浏览器搜索框默认样式 */ + -webkit-appearance: none; +} +.markdown-body { + /* 输入框的占位符样式 - WebKit浏览器占位符样式 */ +} +.markdown-body ::-webkit-input-placeholder { + /* 继承父元素颜色 */ + color: inherit; + /* 设置透明度为0.54,创建半透明效果 */ + opacity: 0.54; +} +.markdown-body { + /* 文件选择按钮样式统一 - 文件上传按钮样式 */ +} +.markdown-body ::-webkit-file-upload-button { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 继承父元素字体样式 */ + font: inherit; +} +.markdown-body { + /* 占位符显示统一 - 通用占位符样式 */ +} +.markdown-body ::placeholder { + /* 设置占位符颜色,使用CSS变量 */ + color: var(--color-fg-subtle); + /* 设置完全不透明 */ + opacity: 1; +} +.markdown-body { + /* table内的td,th去除留白 - 表格单元格样式 */ +} +.markdown-body td, +.markdown-body th { + /* 移除表格单元格内边距 */ + padding: 0; +} +.markdown-body { + /* 伸缩框鼠标显示 - 详情框摘要样式 */ +} +.markdown-body details summary { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 未展开的详情框隐藏内容 - 详情框内容显示控制 */ +} +.markdown-body details:not([open]) > *:not(summary) { + /* 强制隐藏未展开详情框内的非摘要内容 */ + display: none !important; +} +.markdown-body { + /* 按键显示 - 键盘按键样式 */ +} +.markdown-body 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); +} +.markdown-body { + /* 清除浮动工具类 - 清除浮动伪元素 */ +} +.markdown-body .clearfix:before, +.markdown-body .clearfix:after { + /* 空内容,仅用于布局 */ + content: ""; + /* 设置为表格显示模式,用于清除浮动 */ + display: table; +} +.markdown-body { + /* 清除浮动工具类 - after伪元素 */ +} +.markdown-body .clearfix:after { + /* 清除左右浮动 */ + clear: both; +} +.markdown-body { + /* 清除浮动工具类 - 主容器 */ +} +.markdown-body .clearfix { + /* 触发IE的hasLayout属性,用于清除浮动 */ + zoom: 1; +} +.markdown-body { + /* 强制文本换行 - 文本换行工具类 */ +} +.markdown-body .textwrap, +.markdown-body .textwrap td, +.markdown-body .textwrap th { + /* 允许长单词在必要时换行,防止溢出 */ + word-wrap: break-word; + /* 强制在任意字符间换行,防止溢出 */ + word-break: break-all; +} +.markdown-body { + /* 文本换行表格 - 固定表格布局 */ +} +.markdown-body .textwrap-table { + /* 设置表格布局为固定,提高渲染性能 */ + table-layout: fixed; +} +.markdown-body { + /* 无序列表样式 - 项目符号列表 */ +} +.markdown-body ul { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为实心圆点 */ + list-style: disc; +} +.markdown-body { + /* 有序列表样式 - 数字列表 */ +} +.markdown-body ol { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为数字 */ + list-style: decimal; + /* 列表项样式 */ +} +.markdown-body ol li { + /* 设置左内边距为0.4em,增加数字与文本间距 */ + padding-left: 0.4em; +} +.markdown-body { + /* 相邻列表项间距 - 列表项之间的间距 */ +} +.markdown-body li + li { + /* 设置顶部外边距为0.25em,增加列表项间距 */ + margin-top: 0.25em; +} +.markdown-body { + /* 嵌套列表样式 - 列表项内的子列表 */ +} +.markdown-body li { + /* 无序子列表样式 */ +} +.markdown-body li ul { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; + /* 设置列表样式为空心圆点 */ + list-style: circle; + /* 三级无序列表样式 */ +} +.markdown-body li ul li ul { + /* 设置列表样式为实心方块 */ + list-style: square; +} +.markdown-body li { + /* 有序子列表样式 */ +} +.markdown-body li ol { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; +} +.markdown-body { + /* 任务列表项样式 - 待办事项列表项 */ +} +.markdown-body .task-list-item { + /* 移除列表样式,不显示项目符号 */ + list-style-type: none; + /* 设置相对定位,用于绝对定位子元素 */ + position: relative; + /* 第一个子输入框样式 */ +} +.markdown-body .task-list-item > input { + /* 第一个子元素右边距 */ +} +.markdown-body .task-list-item > input:nth-child(1) { + /* 设置右边距为6px */ + margin-right: 6px; +} +.markdown-body .task-list-item { + /* 标签样式 */ +} +.markdown-body .task-list-item label { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body .task-list-item { + /* 拖拽手柄样式 */ +} +.markdown-body .task-list-item .handle { + /* 隐藏拖拽手柄 */ + display: none; +} +.markdown-body .task-list-item { + /* 复选框样式 */ +} +.markdown-body .task-list-item 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; +} +.markdown-body { + /* 启用的任务列表项样式 */ +} +.markdown-body .task-list-item.enabled { + /* 标签样式 */ +} +.markdown-body .task-list-item.enabled label { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 相邻任务列表项间距 */ +} +.markdown-body .task-list-item + .task-list-item { + /* 设置顶部外边距为3px */ + margin-top: 3px; +} +.markdown-body { + /* 包含任务列表的容器样式 */ +} +.markdown-body .contains-task-list { + /* 从右到左文本方向样式 */ +} +.markdown-body .contains-task-list:dir(rtl) .task-list-item input[type=checkbox] { + /* 设置复选框外边距,适配RTL布局 */ + margin: 0 -1.6em 0.25em 0.2em; +} +.markdown-body { + /* 目录样式 - 表格目录容器 */ +} +.markdown-body .toc { + /* 重置左边距为0 */ + margin-left: 0; +} +.markdown-body { + /* 定义列表样式 - 描述列表容器 */ +} +.markdown-body 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; + /* 定义术语样式 */ +} +.markdown-body dl dt { + /* 设置为块级元素 */ + display: block; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} +.markdown-body dl { + /* 定义描述样式 */ +} +.markdown-body dl dd { + /* 设置为块级元素 */ + display: block; + /* 设置内联起始外边距为40px,创建缩进效果 */ + margin-inline-start: 40px; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} + +.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; +} +.markdown-body.green strong::before { + content: "『"; +} +.markdown-body.green strong::after { + content: "』"; +} +.markdown-body.green { + /* 块/段落引用 */ +} +.markdown-body.green 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; +} +.markdown-body.green blockquote > * { + position: relative; +} +.markdown-body.green blockquote > *:first-child:before { + content: "“"; + 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; +} +.markdown-body.green .tabs { + margin-top: 0; + margin-bottom: 1em; +} +.markdown-body.green { + /* 让链接在 hover 状态下显示下划线 */ +} +.markdown-body.green a { + position: relative; + z-index: 10; + transition: color 0.3s linear; + cursor: pointer; + font-weight: bolder; + text-decoration: none; + color: var(--color-base); + border-bottom: 1px solid currentColor; + padding: 0 4px; +} +.markdown-body.green a[data-footnote-backref], .markdown-body.green a[data-footnote-ref] { + border: none; +} +.markdown-body.green a[data-footnote-backref]:hover, .markdown-body.green a[data-footnote-ref]:hover { + background: none; + animation: none; +} +.markdown-body.green a:hover { + content: ""; + 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%; + } +} +.markdown-body.green pre { + background: var(--prism-background); + font-size: var(--prism-font-size); + display: block; + -webkit-overflow-scrolling: touch; +} +.markdown-body.green pre, +.markdown-body.green pre code { + font-family: var(--prism-font-family); +} +.markdown-body.green small, +.markdown-body.green figcaption { + font-size: 0.75em; + color: #888; +} +.markdown-body.green legend { + color: #000; + font-weight: inherit; +} +.markdown-body.green caption { + color: #000; + font-weight: inherit; +} +.markdown-body.green del { + text-decoration: line-through var(--color-base) 2px; +} +.markdown-body.green code { + color: rgb(45, 55, 72); + background-color: rgba(160, 174, 192, 0.25); + font-family: inherit; + font-size: 1em; + border-radius: 4px; + padding: 1px 6px; + margin: 0 2px; + vertical-align: bottom; +} +.markdown-body.green 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; +} +.markdown-body.green table { + width: 100%; + display: table; + border: 1px solid var(--color-light); +} +.markdown-body.green table tr:hover { + background: var(--color-light); +} +.markdown-body.green table:hover { + border: 1px solid var(--color-extra); +} +.markdown-body.green table:hover th { + border-right: 1px solid var(--color-extra); + background: var(--color-extra); + border-bottom: 1px solid var(--color-extra); +} +.markdown-body.green table:hover td { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover caption { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover thead th { + background: var(--color-extra); +} +.markdown-body.green table th { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + background: var(--color-light); + border-bottom: 1px solid var(--color-light); +} +.markdown-body.green table td { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; +} +.markdown-body.green table caption { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + border-bottom: none; +} +.markdown-body.green table thead th { + background: var(--color-extra); +} +.markdown-body.green h1, +.markdown-body.green h2, +.markdown-body.green h3, +.markdown-body.green h4, +.markdown-body.green h5, +.markdown-body.green h6 { + margin-top: 1.2em; + margin-bottom: 0.6em; + line-height: 1.35; + position: relative; +} +.markdown-body.green h1 { + font-size: 1.8em; +} +.markdown-body.green h2 { + font-size: 1.6em; +} +.markdown-body.green h3 { + font-size: 1.4em; +} +.markdown-body.green h4 { + font-size: 1.2em; +} +.markdown-body.green h5 { + font-size: 1em; +} +.markdown-body.green h6 { + font-size: 1em; +} +.markdown-body.green ::-webkit-calendar-picker-indicator { + filter: invert(50%); +} +.markdown-body.green em { + font-weight: inherit; + position: relative; +} +.markdown-body.green em:after { + position: absolute; + top: 0.65em; + left: 0; + width: 100%; + overflow: hidden; + white-space: nowrap; + pointer-events: none; + color: var(--color-base); + content: "・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・"; +} +.markdown-body.green ul.toc li { + list-style-type: none; +} +.markdown-body.green ul.toc li a { + text-decoration: none; + border: 0; + list-style-type: none; +} +.markdown-body.green.chinese { + text-indent: 1.5em; + font-weight: 300; +} +.markdown-body.green.chinese h1, +.markdown-body.green.chinese h2, +.markdown-body.green.chinese h3, +.markdown-body.green.chinese h4, +.markdown-body.green.chinese h5, +.markdown-body.green.chinese h6, +.markdown-body.green.chinese ol, +.markdown-body.green.chinese ul, +.markdown-body.green.chinese blockquote, +.markdown-body.green.chinese details, +.markdown-body.green.chinese summary, +.markdown-body.green.chinese pre, +.markdown-body.green.chinese .tabs { + text-indent: 0; +} \ No newline at end of file diff --git a/public/scss-compiler/page/index/style.css b/public/scss-compiler/page/index/style.css new file mode 100644 index 0000000..403ce31 --- /dev/null +++ b/public/scss-compiler/page/index/style.css @@ -0,0 +1,1188 @@ +@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; + } +} +/* 深色主题媒体查询 - 当用户系统偏好深色模式时应用 */ +@media (prefers-color-scheme: dark) { + .markdown-body { + /* 告诉浏览器使用深色配色方案,影响滚动条等系统UI元素 */ + color-scheme: dark; + } +} +/* 浅色主题媒体查询 - 当用户系统偏好浅色模式时应用 */ +@media (prefers-color-scheme: light) { + .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); + --color-mark-fg: rgb(255, 187, 0); + } +} +/* 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 - 用于清除浮动 */ +} +.markdown-body::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 第一个子元素 - 移除顶部外边距 */ +} +.markdown-body > *:first-child { + /* 强制移除顶部外边距,避免不必要的空白 */ + margin-top: 0 !important; +} +.markdown-body { + /* 最后一个子元素 - 移除底部外边距 */ +} +.markdown-body > *:last-child { + /* 强制移除底部外边距,避免不必要的空白 */ + margin-bottom: 0 !important; +} +.markdown-body { + /* 块级元素统一间距设置 - 段落、引用、列表、表格等 */ +} +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body hr, +.markdown-body form, +.markdown-body pre, +.markdown-body details { + /* 移除顶部外边距,避免重复间距 */ + margin-top: 0; + /* 设置底部外边距为1em,保持适当间距 */ + margin-bottom: 1em; +} +.markdown-body { + /* 引用块内部元素间距处理 */ +} +.markdown-body blockquote { + /* 引用块内第一个子元素 - 移除顶部外边距 */ +} +.markdown-body blockquote > :first-child { + margin-top: 0; +} +.markdown-body blockquote { + /* 引用块内最后一个子元素 - 移除底部外边距 */ +} +.markdown-body blockquote > :last-child { + margin-bottom: 0; +} +.markdown-body { + /* 统一显示成块状元素 - 确保这些元素独占一行 */ +} +.markdown-body details, +.markdown-body figcaption, +.markdown-body figure { + /* 设置为块级元素,独占一行显示 */ + display: block; +} +.markdown-body { + /* HTML5 媒体文件跟 img 保持一致 - 内联块级元素 */ +} +.markdown-body audio, +.markdown-body canvas, +.markdown-body video { + /* 设置为内联块级元素,可以设置宽高但不会独占一行 */ + display: inline-block; +} +.markdown-body { + /* 按钮内部间距统一 - 移除Firefox默认内边距 */ +} +.markdown-body button::-moz-focus-inner, +.markdown-body input::-moz-focus-inner { + /* 移除Firefox浏览器按钮和输入框的内部内边距 */ + padding: 0; + /* 移除Firefox浏览器按钮和输入框的内部边框 */ + border: 0; +} +.markdown-body { + /* 定义元素显示为斜体 - 术语定义样式 */ +} +.markdown-body dfn { + /* 设置字体为斜体,用于术语定义 */ + font-style: italic; +} +.markdown-body { + /* 去掉各Table cell 的边距并让其边重合 - 表格样式统一 */ +} +.markdown-body table { + /* 合并表格边框,相邻单元格边框合并为一条 */ + border-collapse: collapse; + /* 设置表格单元格间距为0 */ + border-spacing: 0; + /* 设置为块级元素,可以设置宽高 */ + display: block; + /* 宽度根据内容自适应 */ + width: max-content; + /* 最大宽度不超过父容器 */ + max-width: 100%; + /* 内容溢出时显示滚动条 */ + overflow: auto; +} +.markdown-body { + /* 可拖动文件添加拖动手势 - 拖拽元素样式 */ +} +.markdown-body [draggable] { + /* 设置鼠标悬停时显示移动光标 */ + cursor: move; +} +.markdown-body { + /* 加粗元素 - 粗体文本样式 */ +} +.markdown-body b, +.markdown-body strong { + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); +} +.markdown-body { + /* 缩写元素样式统一 - 缩写和首字母缩写样式 */ +} +.markdown-body abbr, +.markdown-body acronym { + /* 移除底部边框 */ + border-bottom: none; + /* 设置字体变体为正常 */ + font-variant: normal; + /* 设置虚线下划线装饰 */ + text-decoration: underline dotted; +} +.markdown-body { + /* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */ +} +.markdown-body abbr { + /* 设置鼠标悬停时显示帮助光标 */ + cursor: help; +} +.markdown-body { + /* 一致的 del 样式 - 删除线文本样式 */ +} +.markdown-body del { + /* 设置文本装饰为删除线 */ + text-decoration: line-through; +} +.markdown-body { + /* a标签去除下划线 - 链接样式处理 */ +} +.markdown-body a { + /* 默认移除下划线,保持页面简洁 */ + text-decoration: none; + /* 没有href属性的链接样式 */ +} +.markdown-body a:not([href]) { + /* 继承父元素颜色 */ + color: inherit; + /* 移除下划线装饰 */ + text-decoration: none; +} +.markdown-body a { + /* 鼠标悬停时显示下划线 */ +} +.markdown-body a:hover { + text-decoration: underline; +} +.markdown-body { + /* 默认不显示下划线,保持页面简洁 - 插入文本样式 */ +} +.markdown-body ins { + /* 移除下划线装饰,保持页面简洁 */ + text-decoration: none; +} +.markdown-body { + /* 专名号:虽然 u 已经重回 html5 Draft,但在所有浏览器中都是可以使用的, + * 要做到更好,向后兼容的话,添加 class="typo-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 + * 一篇关于 标签的很好文章:http://html5doctor.com/u-element/ + */ +} +.markdown-body u, +.markdown-body .typo-u { + /* 设置文本装饰为下划线,用于专名号显示 */ + text-decoration: underline; +} +.markdown-body { + /* 隐藏指定元素 - 隐藏带有hidden属性的元素 */ +} +.markdown-body [hidden] { + /* 强制隐藏元素,优先级最高 */ + display: none !important; +} +.markdown-body { + /* 伸缩框显示为列表元素 - 详情框摘要样式 */ +} +.markdown-body summary { + /* 设置为列表项显示,显示为可点击的列表项 */ + display: list-item; +} +.markdown-body { + /* 引用元素前后内容 - 移除默认引号 */ +} +.markdown-body q:before, +.markdown-body q:after { + /* 移除引用元素前后的默认引号内容 */ + content: ""; +} +.markdown-body { + /* 表格标题和表头文本对齐 - 默认左对齐 */ +} +.markdown-body caption, +.markdown-body th { + /* 设置文本左对齐 */ + text-align: left; +} +.markdown-body { + /* 居中对齐的表格标题和表头 */ +} +.markdown-body caption[align=center], +.markdown-body th[align=center] { + /* 设置文本居中对齐 */ + text-align: center; +} +.markdown-body { + /* 特定元素字体粗细统一 - 地址、标题、引用等 */ +} +.markdown-body address, +.markdown-body caption, +.markdown-body cite, +.markdown-body em, +.markdown-body th, +.markdown-body var { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body { + /* 标记,类似于手写的荧光笔的作用 - 高亮标记样式 */ +} +.markdown-body mark { + /* 设置标记背景色,使用CSS变量 */ + background: var(--color-mark-default); + /* 设置内边距,增加标记的可读性 */ + padding: 2px; + /* 激活状态的标记样式 */ +} +.markdown-body mark.active { + /* 激活时使用强调色背景 */ + background: var(--color-mark-fg); +} +.markdown-body { + /* 统一h1元素的间隔和字体大小 - 一级标题样式 */ +} +.markdown-body h1 { + /* 设置上下外边距为0.67em */ + margin: 0.67em 0; + /* 设置字体粗细,使用CSS变量或默认600 */ + font-weight: var(--base-text-weight-semibold, 600); + /* 设置字体大小为2倍基础大小 */ + font-size: 2em; +} +.markdown-body { + /* small字体缩小 - 小字体文本样式 */ +} +.markdown-body small { + /* 设置字体大小为父元素的90% */ + font-size: 90%; +} +.markdown-body { + /* 上下标显示 - 下标和上标文本样式 */ +} +.markdown-body sub, +.markdown-body sup { + /* 设置字体大小为75% */ + font-size: 75%; + /* 设置行高为0,避免影响行间距 */ + line-height: 0; + /* 设置相对定位,用于精确控制位置 */ + position: relative; + /* 设置垂直对齐为基线 */ + vertical-align: baseline; +} +.markdown-body { + /* 上下标内链接样式 */ +} +.markdown-body sub a, +.markdown-body sup a { + /* 设置左右内边距为0.1em */ + padding: 0 0.1em; +} +.markdown-body { + /* 下标位置调整 */ +} +.markdown-body sub { + /* 向下偏移0.25em */ + bottom: -0.25em; +} +.markdown-body { + /* 上标位置调整 */ +} +.markdown-body sup { + /* 向上偏移0.5em */ + top: -0.5em; +} +.markdown-body { + /* 代码相关的字体大小统一 - 代码元素字体样式 */ +} +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp, +.markdown-body pre tt { + /* 设置字体为等宽字体,便于代码阅读 */ + font-family: monospace; + /* 设置字体大小为1em,保持一致性 */ + font-size: 1em; +} +.markdown-body { + /* 去除默认边框 - 移除字段集和图片的默认边框 */ +} +.markdown-body fieldset, +.markdown-body img { + /* 移除边框 */ + border: 0; +} +.markdown-body { + /* 图片初始化样式 - 图片元素基础样式 */ +} +.markdown-body img { + /* 设置边框样式为无 */ + border-style: none; + /* 设置最大宽度为100%,防止溢出 */ + max-width: 100%; + /* 设置盒模型为内容盒模型 */ + box-sizing: content-box; + /* 设置左右外边距为自动,实现居中 */ + margin: 0 auto; + /* 设置背景色,使用CSS变量 */ + background-color: var(--color-canvas-default); +} +.markdown-body { + /* 可附标题内容元素的间距 - 图片容器样式 */ +} +.markdown-body figure { + /* 设置上下外边距为1em,左右外边距为40px */ + margin: 1em 40px; +} +.markdown-body { + /* 间隔线 - 水平分隔线样式 */ + /* 一致化 horizontal rule - 统一水平分隔线样式 */ +} +.markdown-body 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 - 用于清除浮动 */ +} +.markdown-body hr::before { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body hr { + /* 伪元素after - 用于清除浮动 */ +} +.markdown-body hr::after { + /* 设置为表格显示模式,用于清除浮动 */ + display: table; + /* 清除左右浮动 */ + clear: both; + /* 空内容,仅用于布局 */ + content: ""; +} +.markdown-body { + /* 表单元素并不继承父级 font 的问题 - 表单元素字体继承 */ +} +.markdown-body button, +.markdown-body input, +.markdown-body select, +.markdown-body textarea { + /* 继承父元素的字体样式 */ + font: inherit; + /* 移除外边距 */ + margin: 0; + /* 设置溢出为可见 */ + overflow: visible; + /* 继承父元素的字体族 */ + font-family: inherit; + /* 继承父元素的字体大小 */ + font-size: inherit; + /* 继承父元素的行高 */ + line-height: inherit; +} +.markdown-body { + /* 外观显示为按钮 - 按钮类型输入框样式 */ +} +.markdown-body [type=button], +.markdown-body [type=reset], +.markdown-body [type=submit] { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 设置标准按钮外观,提高兼容性 */ + appearance: button; +} +.markdown-body { + /* 这两个表单样式规则覆盖 - 复选框和单选框样式 */ +} +.markdown-body [type=checkbox], +.markdown-body [type=radio] { + /* 设置盒模型为边框盒模型 */ + box-sizing: border-box; + /* 移除内边距 */ + padding: 0; +} +.markdown-body { + /* 数字按钮内部高度自动 - 数字输入框按钮样式 */ +} +.markdown-body [type=number]::-webkit-inner-spin-button, +.markdown-body [type=number]::-webkit-outer-spin-button { + /* 设置高度为自动,适应内容 */ + height: auto; +} +.markdown-body { + /* 搜索按钮内图标外观去除 - 搜索输入框样式 */ +} +.markdown-body [type=search]::-webkit-search-cancel-button, +.markdown-body [type=search]::-webkit-search-decoration { + /* 移除WebKit浏览器搜索框默认样式 */ + -webkit-appearance: none; +} +.markdown-body { + /* 输入框的占位符样式 - WebKit浏览器占位符样式 */ +} +.markdown-body ::-webkit-input-placeholder { + /* 继承父元素颜色 */ + color: inherit; + /* 设置透明度为0.54,创建半透明效果 */ + opacity: 0.54; +} +.markdown-body { + /* 文件选择按钮样式统一 - 文件上传按钮样式 */ +} +.markdown-body ::-webkit-file-upload-button { + /* 设置WebKit浏览器按钮外观 */ + -webkit-appearance: button; + /* 继承父元素字体样式 */ + font: inherit; +} +.markdown-body { + /* 占位符显示统一 - 通用占位符样式 */ +} +.markdown-body ::placeholder { + /* 设置占位符颜色,使用CSS变量 */ + color: var(--color-fg-subtle); + /* 设置完全不透明 */ + opacity: 1; +} +.markdown-body { + /* table内的td,th去除留白 - 表格单元格样式 */ +} +.markdown-body td, +.markdown-body th { + /* 移除表格单元格内边距 */ + padding: 0; +} +.markdown-body { + /* 伸缩框鼠标显示 - 详情框摘要样式 */ +} +.markdown-body details summary { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 未展开的详情框隐藏内容 - 详情框内容显示控制 */ +} +.markdown-body details:not([open]) > *:not(summary) { + /* 强制隐藏未展开详情框内的非摘要内容 */ + display: none !important; +} +.markdown-body { + /* 按键显示 - 键盘按键样式 */ +} +.markdown-body 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); +} +.markdown-body { + /* 清除浮动工具类 - 清除浮动伪元素 */ +} +.markdown-body .clearfix:before, +.markdown-body .clearfix:after { + /* 空内容,仅用于布局 */ + content: ""; + /* 设置为表格显示模式,用于清除浮动 */ + display: table; +} +.markdown-body { + /* 清除浮动工具类 - after伪元素 */ +} +.markdown-body .clearfix:after { + /* 清除左右浮动 */ + clear: both; +} +.markdown-body { + /* 清除浮动工具类 - 主容器 */ +} +.markdown-body .clearfix { + /* 触发IE的hasLayout属性,用于清除浮动 */ + zoom: 1; +} +.markdown-body { + /* 强制文本换行 - 文本换行工具类 */ +} +.markdown-body .textwrap, +.markdown-body .textwrap td, +.markdown-body .textwrap th { + /* 允许长单词在必要时换行,防止溢出 */ + word-wrap: break-word; + /* 强制在任意字符间换行,防止溢出 */ + word-break: break-all; +} +.markdown-body { + /* 文本换行表格 - 固定表格布局 */ +} +.markdown-body .textwrap-table { + /* 设置表格布局为固定,提高渲染性能 */ + table-layout: fixed; +} +.markdown-body { + /* 无序列表样式 - 项目符号列表 */ +} +.markdown-body ul { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为实心圆点 */ + list-style: disc; +} +.markdown-body { + /* 有序列表样式 - 数字列表 */ +} +.markdown-body ol { + /* 重置左边距为0 */ + margin-left: 0; + /* 重置左内边距为0 */ + padding-left: 0; + /* 设置左边距为2em,创建缩进效果 */ + margin-left: 2em; + /* 设置列表样式为数字 */ + list-style: decimal; + /* 列表项样式 */ +} +.markdown-body ol li { + /* 设置左内边距为0.4em,增加数字与文本间距 */ + padding-left: 0.4em; +} +.markdown-body { + /* 相邻列表项间距 - 列表项之间的间距 */ +} +.markdown-body li + li { + /* 设置顶部外边距为0.25em,增加列表项间距 */ + margin-top: 0.25em; +} +.markdown-body { + /* 嵌套列表样式 - 列表项内的子列表 */ +} +.markdown-body li { + /* 无序子列表样式 */ +} +.markdown-body li ul { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; + /* 设置列表样式为空心圆点 */ + list-style: circle; + /* 三级无序列表样式 */ +} +.markdown-body li ul li ul { + /* 设置列表样式为实心方块 */ + list-style: square; +} +.markdown-body li { + /* 有序子列表样式 */ +} +.markdown-body li ol { + /* 设置底部外边距为0.8em */ + margin-bottom: 0.8em; + /* 设置左边距为2em,创建嵌套缩进 */ + margin-left: 2em; +} +.markdown-body { + /* 任务列表项样式 - 待办事项列表项 */ +} +.markdown-body .task-list-item { + /* 移除列表样式,不显示项目符号 */ + list-style-type: none; + /* 设置相对定位,用于绝对定位子元素 */ + position: relative; + /* 第一个子输入框样式 */ +} +.markdown-body .task-list-item > input { + /* 第一个子元素右边距 */ +} +.markdown-body .task-list-item > input:nth-child(1) { + /* 设置右边距为6px */ + margin-right: 6px; +} +.markdown-body .task-list-item { + /* 标签样式 */ +} +.markdown-body .task-list-item label { + /* 设置字体粗细为正常(400) */ + font-weight: 400; +} +.markdown-body .task-list-item { + /* 拖拽手柄样式 */ +} +.markdown-body .task-list-item .handle { + /* 隐藏拖拽手柄 */ + display: none; +} +.markdown-body .task-list-item { + /* 复选框样式 */ +} +.markdown-body .task-list-item 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; +} +.markdown-body { + /* 启用的任务列表项样式 */ +} +.markdown-body .task-list-item.enabled { + /* 标签样式 */ +} +.markdown-body .task-list-item.enabled label { + /* 设置鼠标悬停时显示手型光标 */ + cursor: pointer; +} +.markdown-body { + /* 相邻任务列表项间距 */ +} +.markdown-body .task-list-item + .task-list-item { + /* 设置顶部外边距为3px */ + margin-top: 3px; +} +.markdown-body { + /* 包含任务列表的容器样式 */ +} +.markdown-body .contains-task-list { + /* 从右到左文本方向样式 */ +} +.markdown-body .contains-task-list:dir(rtl) .task-list-item input[type=checkbox] { + /* 设置复选框外边距,适配RTL布局 */ + margin: 0 -1.6em 0.25em 0.2em; +} +.markdown-body { + /* 目录样式 - 表格目录容器 */ +} +.markdown-body .toc { + /* 重置左边距为0 */ + margin-left: 0; +} +.markdown-body { + /* 定义列表样式 - 描述列表容器 */ +} +.markdown-body 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; + /* 定义术语样式 */ +} +.markdown-body dl dt { + /* 设置为块级元素 */ + display: block; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} +.markdown-body dl { + /* 定义描述样式 */ +} +.markdown-body dl dd { + /* 设置为块级元素 */ + display: block; + /* 设置内联起始外边距为40px,创建缩进效果 */ + margin-inline-start: 40px; + /* 设置Unicode双向算法为隔离 */ + unicode-bidi: isolate; +} + +.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; +} +.markdown-body.green strong::before { + content: "『"; +} +.markdown-body.green strong::after { + content: "』"; +} +.markdown-body.green { + /* 块/段落引用 */ +} +.markdown-body.green 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; +} +.markdown-body.green blockquote > * { + position: relative; +} +.markdown-body.green blockquote > *:first-child:before { + content: "“"; + 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; +} +.markdown-body.green .tabs { + margin-top: 0; + margin-bottom: 1em; +} +.markdown-body.green { + /* 让链接在 hover 状态下显示下划线 */ +} +.markdown-body.green a { + position: relative; + z-index: 10; + transition: color 0.3s linear; + cursor: pointer; + font-weight: bolder; + text-decoration: none; + color: var(--color-base); + border-bottom: 1px solid currentColor; + padding: 0 4px; +} +.markdown-body.green a[data-footnote-backref], .markdown-body.green a[data-footnote-ref] { + border: none; +} +.markdown-body.green a[data-footnote-backref]:hover, .markdown-body.green a[data-footnote-ref]:hover { + background: none; + animation: none; +} +.markdown-body.green a:hover { + content: ""; + 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%; + } +} +.markdown-body.green pre { + background: var(--prism-background); + font-size: var(--prism-font-size); + display: block; + -webkit-overflow-scrolling: touch; +} +.markdown-body.green pre, +.markdown-body.green pre code { + font-family: var(--prism-font-family); +} +.markdown-body.green small, +.markdown-body.green figcaption { + font-size: 0.75em; + color: #888; +} +.markdown-body.green legend { + color: #000; + font-weight: inherit; +} +.markdown-body.green caption { + color: #000; + font-weight: inherit; +} +.markdown-body.green del { + text-decoration: line-through var(--color-base) 2px; +} +.markdown-body.green code { + color: rgb(45, 55, 72); + background-color: rgba(160, 174, 192, 0.25); + font-family: inherit; + font-size: 1em; + border-radius: 4px; + padding: 1px 6px; + margin: 0 2px; + vertical-align: bottom; +} +.markdown-body.green 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; +} +.markdown-body.green table { + width: 100%; + display: table; + border: 1px solid var(--color-light); +} +.markdown-body.green table tr:hover { + background: var(--color-light); +} +.markdown-body.green table:hover { + border: 1px solid var(--color-extra); +} +.markdown-body.green table:hover th { + border-right: 1px solid var(--color-extra); + background: var(--color-extra); + border-bottom: 1px solid var(--color-extra); +} +.markdown-body.green table:hover td { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover caption { + border-right: 1px solid var(--color-extra); +} +.markdown-body.green table:hover thead th { + background: var(--color-extra); +} +.markdown-body.green table th { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + background: var(--color-light); + border-bottom: 1px solid var(--color-light); +} +.markdown-body.green table td { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; +} +.markdown-body.green table caption { + border-right: 1px solid var(--color-light); + padding: 0.5em 1em; + border-bottom: none; +} +.markdown-body.green table thead th { + background: var(--color-extra); +} +.markdown-body.green h1, +.markdown-body.green h2, +.markdown-body.green h3, +.markdown-body.green h4, +.markdown-body.green h5, +.markdown-body.green h6 { + margin-top: 1.2em; + margin-bottom: 0.6em; + line-height: 1.35; + position: relative; +} +.markdown-body.green h1 { + font-size: 1.8em; +} +.markdown-body.green h2 { + font-size: 1.6em; +} +.markdown-body.green h3 { + font-size: 1.4em; +} +.markdown-body.green h4 { + font-size: 1.2em; +} +.markdown-body.green h5 { + font-size: 1em; +} +.markdown-body.green h6 { + font-size: 1em; +} +.markdown-body.green ::-webkit-calendar-picker-indicator { + filter: invert(50%); +} +.markdown-body.green em { + font-weight: inherit; + position: relative; +} +.markdown-body.green em:after { + position: absolute; + top: 0.65em; + left: 0; + width: 100%; + overflow: hidden; + white-space: nowrap; + pointer-events: none; + color: var(--color-base); + content: "・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・"; +} +.markdown-body.green ul.toc li { + list-style-type: none; +} +.markdown-body.green ul.toc li a { + text-decoration: none; + border: 0; + list-style-type: none; +} +.markdown-body.green.chinese { + text-indent: 1.5em; + font-weight: 300; +} +.markdown-body.green.chinese h1, +.markdown-body.green.chinese h2, +.markdown-body.green.chinese h3, +.markdown-body.green.chinese h4, +.markdown-body.green.chinese h5, +.markdown-body.green.chinese h6, +.markdown-body.green.chinese ol, +.markdown-body.green.chinese ul, +.markdown-body.green.chinese blockquote, +.markdown-body.green.chinese details, +.markdown-body.green.chinese summary, +.markdown-body.green.chinese pre, +.markdown-body.green.chinese .tabs { + text-indent: 0; +} \ No newline at end of file diff --git a/src/logger.js b/src/logger.js index 9dacabe..2b590ac 100644 --- a/src/logger.js +++ b/src/logger.js @@ -46,7 +46,7 @@ log4js.configure({ type: "console", layout: { 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', }, }, }, diff --git a/src/main.js b/src/main.js index 07f5261..4db469f 100644 --- a/src/main.js +++ b/src/main.js @@ -31,13 +31,11 @@ const PORT = process.env.PORT || 3000; return "localhost" } const localIP = getLocalIP() - logger.trace(`──────────────────── 服务器已启动 ────────────────────`) - logger.trace(` `) - logger.trace(` 本地访问: http://localhost:${port} `) - logger.trace(` 局域网: http://${localIP}:${port} `) - logger.trace(` `) - logger.trace(` 服务启动时间: ${new Date().toLocaleString()} `) - logger.trace(`──────────────────────────────────────────────────────\n`) + logger.info(`🚀 服务器已启动`) + logger.info(` 本地访问: http://localhost:${port}`) + logger.info(` 局域网: http://${localIP}:${port}`) + logger.info(` 启动时间: ${new Date().toLocaleString()}`) + logger.info(`────────────────────────────────────────`) }) diff --git a/src/middlewares/PugHelper/sass.js b/src/middlewares/PugHelper/sass.js new file mode 100644 index 0000000..1f98eab --- /dev/null +++ b/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 + }), + }) + }) + }) +} diff --git a/src/middlewares/Views/index.js b/src/middlewares/Views/index.js index e323d43..51115d6 100644 --- a/src/middlewares/Views/index.js +++ b/src/middlewares/Views/index.js @@ -24,15 +24,7 @@ function viewsMiddleware(path, { engineSource = consolidate, extension = "html", currentPath: ctx.path, } 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, locals, options, diff --git a/src/middlewares/install.js b/src/middlewares/install.js index 7a494f0..24ac31f 100644 --- a/src/middlewares/install.js +++ b/src/middlewares/install.js @@ -13,6 +13,10 @@ import conditional from "koa-conditional-get" import { autoRegisterControllers } from "@/utils/ForRegister.js" import performanceMonitor from "./RoutePerformance/index.js" 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 config from "config/index.js" @@ -46,10 +50,46 @@ export default async app => { } 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) => { // 提供全局数据 ctx.state.siteConfig = await SiteConfigService.getAll() - ctx.state.base = config.base + ctx.state.$config = config return await next() }) // 错误处理,主要处理运行中抛出的错误 @@ -64,6 +104,35 @@ export default async app => { extension: "pug", options: { 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=>``).join("\n")} + ` + }, + }, }, }) ) diff --git a/src/utils/ForRegister.js b/src/utils/ForRegister.js index 578dbb5..1107e0d 100644 --- a/src/utils/ForRegister.js +++ b/src/utils/ForRegister.js @@ -10,7 +10,6 @@ if (import.meta.env.PROD) { // 通过引用返回值,防止被摇树优化 let controllers = import.meta.glob("../controllers/**/*Controller.js", { eager: true }) controllers = null - console.log(controllers); } /** @@ -45,7 +44,7 @@ export async function autoRegisterControllers(app, controllersDir) { if (cachedRoutes) { // 缓存命中,直接使用缓存结果 allRouter.push(...cachedRoutes) - logger.info(`[控制器注册] ✨ ${file} - 从缓存加载路由成功`) + logger.debug(`[控制器注册] ✨ ${file} - 从缓存加载`) continue } @@ -92,9 +91,9 @@ export async function autoRegisterControllers(app, controllersDir) { // 根据缓存状态显示不同的日志信息 const cacheEnabled = routeCache.config.enabled if (cacheEnabled) { - logger.info(`[控制器注册] ✅ ${file} - 路由创建成功,已缓存`) + logger.debug(`[控制器注册] ✅ ${file} - 已缓存`) } else { - logger.info(`[控制器注册] ✅ ${file} - 路由创建成功`) + logger.debug(`[控制器注册] ✅ ${file} - 创建成功`) } } else { logger.warn(`[控制器注册] ⚠️ ${file} - createRoutes() 返回的不是有效的路由器对象`) @@ -124,43 +123,97 @@ export async function autoRegisterControllers(app, controllersDir) { return } - logger.info(`[路由注册] 📋 发现 ${allRouter.length} 个控制器,开始注册到应用`) + logger.info(`[路由注册] 📋 发现 ${allRouter.length} 个控制器,开始注册`) // 按顺序注册路由,确保中间件执行顺序 + const routeTable = [] + let totalRoutes = 0 + for (let i = 0; i < allRouter.length; i++) { const router = allRouter[i] try { app.use(router.middleware()) - logger.debug(`[路由注册] 🔗 路由 ${i + 1}/${allRouter.length} 注册成功`) - // 枚举并紧凑输出该路由器下的所有路由方法与路径(单行聚合) + // 收集路由信息 const methodEntries = Object.entries(router.routes || {}) - const items = [] + const routes = [] for (const [method, list] of methodEntries) { if (!Array.isArray(list) || list.length === 0) continue for (const r of list) { 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 : "" - logger.info(`[路由注册] ✅ ${prefix || "/"} 共 ${items.length} 条 -> ${items.join("; ")}`) - } else { - logger.warn(`[路由注册] ⚠️ 该控制器未包含任何可用路由`) + + if (routes.length > 0) { + const prefix = router.options && router.options.prefix ? router.options.prefix : "/" + routeTable.push({ + prefix: prefix, + count: routes.length, + routes: routes + }) + totalRoutes += routes.length } } 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() - logger.info(`[路由缓存] 缓存状态: ${cacheStats.enabled ? '启用' : '禁用'}, 总命中率: ${cacheStats.hitRate}`) if (cacheStats.enabled) { - logger.debug(`[路由缓存] 详细统计:`, cacheStats.caches) + logger.debug(`[路由缓存] 状态: 启用, 命中率: ${cacheStats.hitRate}`) } } catch (error) { diff --git a/src/utils/cache/RouteCache.js b/src/utils/cache/RouteCache.js index 459bb55..75edf81 100644 --- a/src/utils/cache/RouteCache.js +++ b/src/utils/cache/RouteCache.js @@ -49,7 +49,7 @@ class RouteCache extends BaseSingleton { 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 }) - logger.info('[路由缓存] 所有缓存已清除') + logger.debug('[路由缓存] 所有缓存已清除') } /** @@ -264,7 +264,7 @@ class RouteCache extends BaseSingleton { */ clearRouteMatches() { this.matchCache.clear() - logger.info('[路由缓存] 路由匹配缓存已清除') + logger.debug('[路由缓存] 路由匹配缓存已清除') } /** @@ -272,7 +272,7 @@ class RouteCache extends BaseSingleton { */ clearControllers() { this.controllerCache.clear() - logger.info('[路由缓存] 控制器实例缓存已清除') + logger.debug('[路由缓存] 控制器实例缓存已清除') } /** @@ -280,7 +280,7 @@ class RouteCache extends BaseSingleton { */ clearMiddlewares() { this.middlewareCache.clear() - logger.info('[路由缓存] 中间件组合缓存已清除') + logger.debug('[路由缓存] 中间件组合缓存已清除') } /** @@ -288,7 +288,7 @@ class RouteCache extends BaseSingleton { */ clearRegistrations() { this.registrationCache.clear() - logger.info('[路由缓存] 路由注册缓存已清除') + logger.debug('[路由缓存] 路由注册缓存已清除') } /** @@ -306,7 +306,7 @@ class RouteCache extends BaseSingleton { // 清除路由匹配缓存(因为路由可能已变更) this.clearRouteMatches() - logger.info(`[路由缓存] 已清除文件 ${filePath} 相关缓存`) + logger.debug(`[路由缓存] 已清除文件 ${filePath} 相关缓存`) } /** @@ -362,7 +362,7 @@ class RouteCache extends BaseSingleton { */ updateConfig(newConfig) { this.config = { ...this.config, ...newConfig } - logger.info('[路由缓存] 配置已更新', this.config) + logger.debug('[路由缓存] 配置已更新', this.config) } /** @@ -370,7 +370,7 @@ class RouteCache extends BaseSingleton { */ enable() { this.config.enabled = true - logger.info('[路由缓存] 缓存已启用') + logger.debug('[路由缓存] 缓存已启用') } /** @@ -379,7 +379,7 @@ class RouteCache extends BaseSingleton { disable() { this.config.enabled = false this.clearAll() - logger.info('[路由缓存] 缓存已禁用并清除') + logger.debug('[路由缓存] 缓存已禁用并清除') } } diff --git a/src/views/layouts/empty.pug b/src/views/layouts/empty.pug index d3a915e..42cda1b 100644 --- a/src/views/layouts/empty.pug +++ b/src/views/layouts/empty.pug @@ -1,5 +1,4 @@ extends /layouts/root.pug -//- 采用纯背景页面的布局,背景图片随机切换,卡片采用高斯滤镜类玻璃化效果 block $$head +css('css/layouts/empty.css') @@ -12,7 +11,6 @@ block $$content .container.clearfix(class="h-full") .navbar-brand a(href="/" class="text-[20px]") #{siteConfig.site_title} - // 桌面端菜单 .left.menu.desktop-only a.menu-item( href="/articles" @@ -33,26 +31,6 @@ block $$content a.menu-item(href="/notice") .fe--notice-active 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.container block pageContent @@ -94,8 +72,6 @@ block $$content .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="微信") 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") 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") @@ -113,13 +89,3 @@ block $$content block $$scripts 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'); - }); - } - })(); \ No newline at end of file diff --git a/src/views/page/index/_global.scss b/src/views/page/index/_global.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/views/page/index/index copy.pug b/src/views/page/index/index copy.pug deleted file mode 100644 index b59f6ea..0000000 --- a/src/views/page/index/index copy.pug +++ /dev/null @@ -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; - ``` \ No newline at end of file diff --git a/src/views/page/index/index.pug b/src/views/page/index/index.pug index 37b6843..64b6fe2 100644 --- a/src/views/page/index/index.pug +++ b/src/views/page/index/index.pug @@ -1,19 +1,22 @@ extends /layouts/empty.pug block pageHead - style - + :scss + @use "./_global.scss"; + @use "./style.scss"; + @use "./markdown-reset.scss"; + @use "./markdown-green.scss"; block pageContent - :my-own-filter(addStart addEnd) - Filter - Body - :markdown-it(linkify langPrefix='highlight-') - # Markdown + .markdown-body + :markdown-it(linkify langPrefix='highlight-') + # Markdown - Markdown document with http://links.com and + Markdown document with http://links.com and - ```js - var codeBlocks; - ``` \ No newline at end of file + ```js + var codeBlocks; + ``` + + > blockquote \ No newline at end of file diff --git a/src/views/page/index/index.scss b/src/views/page/index/index.scss deleted file mode 100644 index 0ac4c77..0000000 --- a/src/views/page/index/index.scss +++ /dev/null @@ -1,146 +0,0 @@ -/* 首页样式 */ - -.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; - } -} \ No newline at end of file diff --git a/src/views/page/index/markdown-green.scss b/src/views/page/index/markdown-green.scss new file mode 100644 index 0000000..a42ac47 --- /dev/null +++ b/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; +} diff --git a/src/views/page/index/markdown-reset.scss b/src/views/page/index/markdown-reset.scss new file mode 100644 index 0000000..d0dabe1 --- /dev/null +++ b/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" 来显示专名号 + * 关于 标签: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 + * 一篇关于 标签的很好文章: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; + } + } +} diff --git a/src/views/page/index/person.pug b/src/views/page/index/person.pug deleted file mode 100644 index a78eb26..0000000 --- a/src/views/page/index/person.pug +++ /dev/null @@ -1,9 +0,0 @@ -extends /layouts/pure.pug - -block pageHead - +css("css/page/index.css") - -block pageContent - +include() - - let timeLine = [{icon: '11',title: "aaaa",desc:"asd"}] - include /htmx/timeline.pug \ No newline at end of file diff --git a/src/views/page/index/style.scss b/src/views/page/index/style.scss new file mode 100644 index 0000000..0ac4c77 --- /dev/null +++ b/src/views/page/index/style.scss @@ -0,0 +1,146 @@ +/* 首页样式 */ + +.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; + } +} \ No newline at end of file diff --git a/src/views/temp/person.pug b/src/views/temp/person.pug new file mode 100644 index 0000000..a78eb26 --- /dev/null +++ b/src/views/temp/person.pug @@ -0,0 +1,9 @@ +extends /layouts/pure.pug + +block pageHead + +css("css/page/index.css") + +block pageContent + +include() + - let timeLine = [{icon: '11',title: "aaaa",desc:"asd"}] + include /htmx/timeline.pug \ No newline at end of file