性能、逻辑、结构优化

This commit is contained in:
Han 2025-04-02 19:14:32 +08:00
parent 7dab27d0a3
commit f333964d10
50 changed files with 1674 additions and 1259 deletions

View File

@ -1,138 +1,134 @@
section.vh-container { section.vh-archive-main {
&>section.vh-archive-main { flex: 1;
flex: 1; padding: 2rem 1rem;
padding: 2rem 1rem; border-radius: 1rem;
border-radius: 1rem; background-color: var(--vh-white-color);
background-color: #fff; overflow: hidden;
overflow: hidden;
&>.archive-list { &>.archive-list {
display: flex;
flex-direction: column;
gap: 1rem;
&>.archive-list-item {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem;
&>.archive-list-item { &>p,
a {
display: flex; display: flex;
flex-direction: column; align-items: center;
width: 100%;
&>p, height: 2.5rem;
a { border-radius: 1rem;
display: flex; font-size: 1rem;
align-items: center; transition: background .18s;
width: 100%;
height: 2.5rem;
border-radius: 1rem;
font-size: var(--vh-size-p);
transition: background .16s;
&:not(.title) { &:not(.title) {
&:hover {
&:hover { background-color: #EEEFF3;
background-color: var(--vh-main-color);
&>i {
&::before {
height: 50.66%;
}
}
&>span {
padding-left: 0.28rem;
}
}
&>em {
color: var(--vh-black-38);
font-size: var(--vh-size-span);
font-weight: 500;
}
&>i { &>i {
&::before { &::before {
width: 0.25rem; height: 50.66%;
height: 0.25rem;
border: none;
border-radius: 0.25rem;
background-color: #4E667F;
}
&::after {
content: "";
position: absolute;
width: 0.125rem;
height: 1rem;
left: calc(50% - 0.0625rem);
transform: translateY(-50%);
border-left: 2px dashed rgba(0, 0, 0, .1);
pointer-events: none;
} }
} }
&>span { &>span {
font-size: var(--vh-size-p); padding-left: 0.28rem;
color: var(--vh-black-100);
font-weight: 600;
} }
} }
&>em { &>em {
flex-shrink: 0; color: var(--vh-font-28);
width: 5.05rem; font-size: 0.875rem;
height: 3.75rem; font-weight: 500;
color: var(--vh-black-100);
font-size: 1.5rem;
font-weight: 600;
line-height: 3.75rem;
text-align: right;
font-style: normal;
} }
&>i { &>i {
position: relative;
width: 2.5rem;
height: 100%;
&::before { &::before {
content: ''; width: 0.25rem;
height: 0.25rem;
border: none;
border-radius: 0.25rem;
background-color: #4E667F;
}
&::after {
content: "";
position: absolute; position: absolute;
left: 50%; width: 0.125rem;
top: 50%; height: 1rem;
transform: translate(-50%, -50%); left: calc(50% - 0.0625rem);
display: block; transform: translateY(-50%);
width: 0.36rem; border-left: 2px dashed rgba(0, 0, 0, .1);
height: 0.36rem; pointer-events: none;
border: solid 0.28rem #0000006D;
border-radius: 50%;
background-color: #fff;
transition: all .3s;
} }
} }
&>span {
flex: 1;
white-space: nowrap;
overflow: hidden;
color: var(--vh-black-66);
font-weight: 500;
text-overflow: ellipsis;
transition: all .16s;
}
&>cite { &>span {
margin-left: auto; font-size: 1rem;
width: 7.8rem; color: var(--vh-font-color);
font-size: var(--vh-size-span); font-weight: 600;
color: var(--vh-black-66);
font-weight: 400;
font-style: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
} }
&>em {
flex-shrink: 0;
width: 5.05rem;
height: 3.75rem;
color: var(--vh-font-color);
font-size: 1.5rem;
font-weight: 600;
line-height: 3.75rem;
text-align: right;
font-style: normal;
}
&>i {
position: relative;
width: 2.5rem;
height: 100%;
&::before {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: block;
width: 0.36rem;
height: 0.36rem;
border: solid 0.28rem #0000006D;
border-radius: 50%;
background-color: var(--vh-white-color);
transition: all .3s;
}
}
&>span {
flex: 1;
white-space: nowrap;
overflow: hidden;
color: var(--vh-font-66);
font-weight: 500;
text-overflow: ellipsis;
transition: all .18s;
}
&>cite {
margin-left: auto;
width: 7.8rem;
font-size: 0.875rem;
color: var(--vh-font-66);
font-weight: 400;
font-style: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
} }
} }
} }
@ -140,18 +136,15 @@ section.vh-container {
@media screen and (max-width: 1198px) { @media screen and (max-width: 1198px) {
section.vh-container { section.vh-archive-main {
&>section.vh-archive-main { &>.archive-list {
&>.archive-list { &>.archive-list-item {
&>.archive-list-item {
&>p, &>p,
a { a {
&>cite { &>cite {
display: none; display: none;
}
} }
} }
} }
@ -160,40 +153,37 @@ section.vh-container {
} }
@media screen and (max-width: 888px) { @media screen and (max-width: 888px) {
section.vh-container { section.vh-archive-main {
&>section.vh-archive-main { padding: 0;
padding: 0; background-color: transparent;
background-color: transparent;
&>.archive-list { &>.archive-list {
&>.archive-list-item { &>.archive-list-item {
&>p,
a {
&:not(.title) {
&>em {
font-size: var(--vh-size-h3);
}
&>span {
font-size: var(--vh-size-h2);
}
}
&>p,
a {
&:not(.title) {
&>em { &>em {
width: 3rem; font-size: 0.8rem;
font-size: 1.2rem;
}
&>i {
width: 1.8rem;
} }
&>span { &>span {
font-size: var(--vh-size-h3); font-size: 0.88rem;
} }
} }
&>em {
width: 3rem;
font-size: 1.2rem;
}
&>i {
width: 1.8rem;
}
&>span {
font-size: 0.8rem;
}
} }
} }
} }

View File

@ -13,13 +13,13 @@ import "./ArticleCard.less";
<article class="vh-article-item vh-animation vh-animation-init"> <article class="vh-article-item vh-animation vh-animation-init">
<a class={`vh-article-link${post.data.top ? " active" : ""}`} href={`/article/${post.data.id}`}> <a class={`vh-article-link${post.data.top ? " active" : ""}`} href={`/article/${post.data.id}`}>
<section class="vh-article-banner"><Image src="/assets/images/lazy-loading.webp" data-vh-lz-src={ARTICLE_COVER} alt={post.data.title} width="10" height="10" /></section> <section class="vh-article-banner"><Image src="/assets/images/lazy-loading.webp" data-vh-lz-src={ARTICLE_COVER} alt={post.data.title} width="1" height="1" /></section>
<section class="vh-article-desc"> <section class="vh-article-desc">
<header> <header>
<span class={`vh-article-categories vh-categories-${post.data.categories}`}>{post.data.categories}</span> <span class={`vh-article-cat vh-cat-${post.data.categories}`}>{post.data.categories}</span>
<h2 class="title">{post.data.title}</h2> <h2 class="title vh-ellipsis">{post.data.title}</h2>
</header> </header>
<p class="vh-article-excerpt">{description}</p> <p class="vh-article-excerpt vh-ellipsis-2">{description}</p>
<footer>{fmtTime(post.data.date)}</footer> <footer>{fmtTime(post.data.date)}</footer>
</section> </section>
</a> </a>

View File

@ -1,226 +1,222 @@
section.article-list { .article-list-main {
flex: 1;
position: relative; position: relative;
padding-bottom: 6rem; box-sizing: border-box;
display: grid; padding-bottom: 6.88rem;
grid-template-columns: repeat(3, 1fr);
gap: 1.6rem;
width: 100%; width: 100%;
min-width: 0;
height: max-content; height: max-content;
overflow: hidden;
&>.vh-article-item { &>section.article-list {
box-sizing: border-box; position: relative;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.288rem;
width: 100%; width: 100%;
height: initial; min-width: 0;
min-height: max-content; height: max-content;
border: solid 1px #eee;
border-radius: 1rem;
background-color: #fff;
overflow: hidden; overflow: hidden;
&>a.vh-article-link { &>.vh-article-item {
position: relative;
box-sizing: border-box; box-sizing: border-box;
display: flex;
flex-direction: column;
width: 100%; width: 100%;
height: max-content; height: initial;
min-height: 100%; min-height: max-content;
border-radius: 0.618rem; border: solid 1px #eee;
border-radius: 1rem;
background-color: #fff;
overflow: hidden; overflow: hidden;
transition: background 0.16s;
&:hover { &>a.vh-article-link {
&>.vh-article-banner {
&>img {
transform: scale(1.08);
}
}
}
&.active {
&::before {
content: "置顶";
position: absolute;
top: 1.6rem;
left: 0.66rem;
box-sizing: border-box;
padding: 0.18rem 1rem;
width: max-content;
height: max-content;
font-size: var(--vh-size-p);
color: #fff;
border-radius: 0.66rem;
transform: rotate(-45deg);
/* 确保元素有半透明背景 */
background: #00000033;
box-shadow: 0 2rem 1rem rgba(0, 0, 0, 0.1);
z-index: 1;
/* 高斯模糊效果 */
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
/* 兼容旧版浏览器 */
}
&>.vh-article-banner {
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.06);
z-index: 1;
pointer-events: none;
}
}
}
&>.vh-article-banner {
position: relative; position: relative;
flex-shrink: 0;
box-sizing: border-box; box-sizing: border-box;
width: 100%;
height: 12rem;
overflow: hidden;
&>img {
width: 100%;
height: 100%;
object-fit: cover;
// transition公共区域有动画效果
}
}
&>.vh-article-desc {
flex: 1;
box-sizing: border-box;
padding: 1.188rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: max-content;
min-height: max-content; min-height: 100%;
border-radius: 0.618rem;
overflow: hidden; overflow: hidden;
transition: background 0.18s;
&>header { &:hover {
&>.vh-article-banner {
&>img {
transform: scale(1.08);
}
}
}
&.active {
&::before {
content: "置顶";
position: absolute;
top: 1.6rem;
left: 0.66rem;
box-sizing: border-box;
padding: 0.18rem 1rem;
width: max-content;
height: max-content;
font-size: 1rem;
color: #fff;
border-radius: 0.66rem;
transform: rotate(-45deg);
/* 确保元素有半透明背景 */
background: #00000033;
box-shadow: 0 2rem 1rem rgba(0, 0, 0, 0.1);
z-index: 1;
/* 高斯模糊效果 */
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
/* 兼容旧版浏览器 */
}
&>.vh-article-banner {
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.06);
z-index: 1;
pointer-events: none;
}
}
}
&>.vh-article-banner {
flex-shrink: 0;
position: relative;
box-sizing: border-box;
width: 100%;
height: 12rem;
overflow: hidden;
&>img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
&>.vh-article-desc {
flex: 1;
box-sizing: border-box;
padding: 1.188rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.36rem;
&>.vh-article-categories {
box-sizing: border-box;
width: max-content;
font-size: var(--vh-size-span);
font-weight: 700;
/* 默认渐变色起始 */
--gradient-color-1: #a32cc4;
/* 默认渐变色中间 */
--gradient-color-2: #b65fcf;
/* 默认渐变色结束 */
--gradient-color-3: #e39ff6;
background: linear-gradient(118deg, var(--gradient-color-1), var(--gradient-color-2) 26%, var(--gradient-color-3));
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
&.vh-categories-Code {
/* 默认渐变色起始 */
--gradient-color-1: #f48600;
/* 默认渐变色中间 */
--gradient-color-2: #ffa12e;
/* 默认渐变色结束 */
--gradient-color-3: #ffe9c9;
}
&.vh-categories-Daily {
/* 默认渐变色起始 */
--gradient-color-1: #6270ee;
/* 默认渐变色中间 */
--gradient-color-2: #2b90d9;
/* 默认渐变色结束 */
--gradient-color-3: #37dede;
}
&.vh-categories-Software {
/* 默认渐变色起始 */
--gradient-color-1: #006633;
/* 默认渐变色中间 */
--gradient-color-2: #00cc66;
/* 默认渐变色结束 */
--gradient-color-3: #66ff99;
}
&.vh-categories-Share {
/* 默认渐变色起始 */
--gradient-color-1: rgb(240, 45, 133);
/* 默认渐变色中间 */
--gradient-color-2: #f95ba5;
/* 默认渐变色结束 */
--gradient-color-3: #f4bdd0;
}
}
&>.title {
margin: 0;
font-size: var(--vh-size-h1);
font-weight: 600;
line-height: 1.36;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
word-break: break-all;
overflow: hidden;
}
}
&>.vh-article-excerpt {
margin: 0.88rem 0;
width: 100%; width: 100%;
height: max-content; height: 100%;
color: var(--vh-black-66); min-height: max-content;
font-size: var(--vh-size-small);
letter-spacing: 0.88px;
line-height: 1.28rem;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
word-break: break-all;
overflow: hidden; overflow: hidden;
}
&>footer { &>header {
margin-top: auto; display: flex;
font-size: var(--vh-size-mini); flex-direction: column;
color: var(--vh-black-100); gap: 0.36rem;
&>.vh-article-cat {
box-sizing: border-box;
width: max-content;
font-size: 0.875rem;
font-weight: 700;
/* 默认渐变色起始 */
--gradient-color-1: #a32cc4;
/* 默认渐变色中间 */
--gradient-color-2: #b65fcf;
/* 默认渐变色结束 */
--gradient-color-3: #e39ff6;
background: linear-gradient(118deg, var(--gradient-color-1), var(--gradient-color-2) 26%, var(--gradient-color-3));
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
&.vh-cat-Code {
/* 默认渐变色起始 */
--gradient-color-1: #f48600;
/* 默认渐变色中间 */
--gradient-color-2: #ffa12e;
/* 默认渐变色结束 */
--gradient-color-3: #ffe9c9;
}
&.vh-cat-Daily {
/* 默认渐变色起始 */
--gradient-color-1: #6270ee;
/* 默认渐变色中间 */
--gradient-color-2: #2b90d9;
/* 默认渐变色结束 */
--gradient-color-3: #37dede;
}
&.vh-cat-Software {
/* 默认渐变色起始 */
--gradient-color-1: #006633;
/* 默认渐变色中间 */
--gradient-color-2: #00cc66;
/* 默认渐变色结束 */
--gradient-color-3: #66ff99;
}
&.vh-cat-Share {
/* 默认渐变色起始 */
--gradient-color-1: rgb(240, 45, 133);
/* 默认渐变色中间 */
--gradient-color-2: #f95ba5;
/* 默认渐变色结束 */
--gradient-color-3: #f4bdd0;
}
}
&>.title {
font-size: 1.06rem;
font-weight: 600;
line-height: 1.36;
}
}
&>.vh-article-excerpt {
margin: 0.88rem 0;
width: 100%;
height: max-content;
color: var(--vh-font-66);
font-size: 0.805rem;
letter-spacing: 0.88px;
line-height: 1.28rem;
}
&>footer {
margin-top: auto;
font-size: 0.805rem;
color: var(--vh-font-color);
}
} }
} }
} }
}
&>.vh-article-pagination { &>.vh-article-pagination {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
right: 0; right: 0;
}
} }
} }
@media screen and (max-width: 1150px) { @media screen and (max-width: 1150px) {
section.article-list { .article-list-main {
grid-template-columns: repeat(2, 1fr); &>section.article-list {
grid-template-columns: repeat(2, 1fr);
}
} }
} }
@media screen and (max-width: 556px) { @media screen and (max-width: 556px) {
section.article-list { .article-list-main {
grid-template-columns: repeat(1, 1fr); &>section.article-list {
grid-template-columns: repeat(1, 1fr);
}
} }
} }

View File

@ -7,13 +7,16 @@ import { Image } from "astro:assets";
import { fmtTime } from "@/utils/index"; import { fmtTime } from "@/utils/index";
// 获取用户配置数据 // 获取用户配置数据
import SITE_CONFIG from "@/config"; import SITE_CONFIG from "@/config";
const { Avatar, Author, Motto, WebSites, GoogleAds } = SITE_CONFIG; const { Avatar, Author, Motto, WebSites, GoogleAds, AsideShow } = SITE_CONFIG;
// 获取文章数据 // 获取文章数据
import { getCategories, getTags, getRecommendArticles } from "@/utils/getPostInfo"; import { getCategories, getTags, getRecommendArticles, getCountInfo } from "@/utils/getPostInfo";
// 获取数据统计
// 分类列表 // 分类列表
const categories = getCategories(); const categories = getCategories();
// 热门标签 // 热门标签
const tags = getTags(); const tags = getTags().slice(0, 16);
// 获取网站统计数据
const CountInfo = getCountInfo();
// 最新文章 // 最新文章
const recommendArticles = getRecommendArticles(); const recommendArticles = getRecommendArticles();
// Google 广告组件 // Google 广告组件
@ -24,68 +27,107 @@ import "./Aside.less";
<aside class="vh-aside"> <aside class="vh-aside">
<!-- 头像块 --> <!-- 头像块 -->
<section class="vh-aside-item user"> {
<Image class="vh-aside-avatar" src="/assets/images/lazy-loading.webp" data-vh-lz-src={Avatar} alt={Author} width="1" height="1" /> AsideShow.WebSitesShow && (
<span class="vh-aside-auther">{Author}</span> <section class="vh-aside-item user">
<p class="vh-aside-motto">{Motto}</p> <Image class="vh-aside-avatar" src="/assets/images/lazy-loading.webp" data-vh-lz-src={Avatar} alt={Author} width="1" height="1" />
<section class="vh-aside-links"> <span class="vh-aside-auther">{Author}</span>
{ <p class="vh-aside-motto">{Motto}</p>
WebSites.map(item => ( <section class="vh-aside-links">
<a class="vh-aside-links-item" href={item.link} title={item.text} target="_blank" rel="noopener nofollow"> {WebSites.map(item => (
<Svg src={item.icon} /> <a class="vh-aside-links-item" href={item.link} title={item.text} target="_blank" rel="noopener nofollow">
</a> <Svg src={item.icon} />
)) </a>
} ))}
</section> </section>
</section> <section class="vh-aside-info">
<div class="art-item count">
<span>{CountInfo.ArticleCount}</span>
<p>文章数</p>
</div>
<div class="cat-item count">
<span>{CountInfo.CategoryCount}</span>
<p>分类数</p>
</div>
<div class="tag-item count">
<span>{CountInfo.TagCount}</span>
<p>标签数</p>
</div>
</section>
<canvas class="vh-aside-canvas" width="888" height="1888" />
</section>
)
}
<!-- 公告块 -->
{
AsideShow.TipsShow && (
<section class="vh-aside-item tips">
<span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M3 9.662c2 2.338 2 4.338 0 6.338c3 .5 4.5 1 5 4c2 -3 6 -4 9 0c0 -3 1 -4 4 -4.004q -3 -2.995 0 -5.996c-3 0 -5 -2 -5 -5c-2 4 -5 3 -7.5 -1c-.5 3 -2.5 5 -5.5 5.662" />
</svg>
公告
</span>
<div class="tips-content">
<p>欢迎访问我的博客,我是一名前端工程师,喜欢分享前端知识和技巧。</p>
<p>如果你对我的博客感兴趣,欢迎关注我的公众号,我会定期发布一些前端技术文章和教程。</p>
</div>
</section>
)
}
<!-- 分类块 --> <!-- 分类块 -->
<section class="vh-aside-item categories"> {
<h3>分类</h3> AsideShow.CategoriesShow && (
<div class="vh-aside-categories"> <section class="vh-aside-item cat">
{ <h3>分类</h3>
categories <div class="vh-aside-cat">
.sort((a: any, b: any) => b.count - a.count) {categories
.map(i => ( .sort((a: any, b: any) => b.count - a.count)
<a href={`/categories/${i.title}`}> .map(i => (
<span>{i.title}</span> <a href={`/categories/${i.title}`}>
<i>{i.count}</i> <span>{i.title}</span>
</a> <i>{i.count}</i>
)) </a>
} ))}
</div> </div>
</section> </section>
)
}
<!-- 标签块 --> <!-- 标签块 -->
<section class="vh-aside-item tags"> {
<h3>热门标签</h3> AsideShow.TagsShow && (
<div class="vh-aside-tags"> <section class="vh-aside-item tags">
{ <h3>热门标签</h3>
tags.map(i => ( <div class="vh-aside-tags">
<a href={`/tag/${i}`}> {tags.map(i => (
<span>{i}</span> <a href={`/tag/${i[0]}`}>
</a> <span>{i[0]}</span>
)) <em>{i[1]}</em>
} </a>
</div> ))}
</section> </div>
</section>
)
}
<section class="sticky-aside"> <section class="sticky-aside">
<!-- 最新文章块 --> <!-- 最新文章块 -->
{ {
recommendArticles.length && ( recommendArticles.length && AsideShow.recommendArticleShow && (
<section class="vh-aside-item articles"> <section class="vh-aside-item articles">
<h3>推荐文章</h3> <h3>推荐文章</h3>
<div class="vh-aside-articles"> <div class="vh-aside-articles">
{recommendArticles.map(async i => ( {recommendArticles.map((i, idx) => (
<a href={`/article/${(await i).id}`}> <a href={`/article/${i.id}`}>
<p class="cover"> <span>
<Image src="/assets/images/lazy-loading.webp" data-vh-lz-src={(await i).cover} alt={(await i).title} width="1" height="1" /> {idx < 3 ? <i>{idx + 1}</i> : <em>{idx + 1}.</em>}
</p> <cite class="vh-ellipsis">{i.title}</cite>
<p class="info"> </span>
<span>{(await i).title}</span> <time>{fmtTime(i.date, "YYYY-MM-DD A")}</time>
<time>{fmtTime((await i).date, "YYYY-MM-DD A")}</time>
</p>
</a> </a>
))} ))}
</div> </div>

View File

@ -1,26 +1,29 @@
aside.vh-aside { aside.vh-aside {
flex-shrink: 0; flex-shrink: 0;
position: relative;
box-sizing: border-box; box-sizing: border-box;
padding: 0.88rem 0.66rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 1rem;
width: 288px; width: var(--vh-aside-width);
height: initial; height: auto;
&>.sticky-aside { &>.sticky-aside {
position: -webkit-sticky;
position: sticky; position: sticky;
top: var(--vh-padding-top); top: calc(66px + 1rem);
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 1rem;
width: 100%; width: 100%;
height: max-content;
} }
.vh-aside-item { .vh-aside-item {
position: relative;
box-sizing: border-box; box-sizing: border-box;
padding: 0.75rem; padding: 1.28rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -28,28 +31,16 @@ aside.vh-aside {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
height: max-content; height: max-content;
border-radius: 1rem; border-radius: var(--vh-main-radius);
background-color: #fff; background-color: var(--vh-white-color);
color: #000; box-shadow: var(--vh-box-shadow);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
overflow: hidden; overflow: hidden;
&>h3 { &>h3 {
padding-bottom: 0.618rem;
display: flex;
align-items: center;
gap: 0.68rem;
width: 100%; width: 100%;
font-size: var(--vh-size-h1); font-size: 0.68rem;
font-weight: 600; font-weight: 400;
color: var(--vh-font-56);
&::before {
content: '';
width: 0.25rem;
height: 1.16rem;
border-radius: 0.5rem;
background-color: var(--vh-main-color-88);
}
} }
// 用户信息 // 用户信息
@ -84,7 +75,7 @@ aside.vh-aside {
&>.vh-aside-motto { &>.vh-aside-motto {
font-size: 0.86rem; font-size: 0.86rem;
color: var(--vh-black-66); color: var(--vh-font-66);
line-height: 1.5; line-height: 1.5;
text-align: center; text-align: center;
} }
@ -102,12 +93,15 @@ aside.vh-aside {
width: 1.88rem; width: 1.88rem;
height: 1.88rem; height: 1.88rem;
border: solid 1px #333; border: solid 1px #333;
background-color: #fff; background-color: var(--vh-white-color);
border-radius: 0.38rem; border-radius: 0.38rem;
overflow: hidden; overflow: hidden;
z-index: 1; z-index: 1;
&:hover { &:hover {
color: var(--vh-white-color);
border-color: var(--vh-white-color);
&::after { &::after {
height: 100%; height: 100%;
} }
@ -121,7 +115,7 @@ aside.vh-aside {
width: 100%; width: 100%;
height: 0; height: 0;
background-color: var(--vh-main-color-88); background-color: var(--vh-main-color-88);
transition: height 0.16s ease-in-out; transition: height 0.18s ease-in-out;
z-index: -1; z-index: -1;
} }
@ -133,11 +127,90 @@ aside.vh-aside {
} }
} }
} }
&>.vh-aside-info {
box-sizing: border-box;
padding: 0 1rem;
display: grid;
grid-template-columns: repeat(3, 1fr);
width: 100%;
height: max-content;
&>.count {
box-sizing: border-box;
padding: 1rem 0;
display: flex;
flex-direction: column;
justify-content: center;
gap: 0.66rem;
text-align: center;
background: var(--vh-white-color);
border-radius: var(--vh-main-radius);
user-select: none;
transition: box-shadow 0.18s ease-in-out;
&:hover {
box-shadow: var(--vh-box-shadow);
z-index: 1;
}
&>span {
font-size: 1.05rem;
color: var(--vh-font-color);
}
&>p {
font-size: 0.8rem;
color: var(--vh-font-56);
}
}
}
&>.vh-aside-canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 1;
pointer-events: none;
}
}
// 公告
&.tips {
align-items: flex-start;
&>span {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 0.288rem;
font-size: 1rem;
&>svg {
margin-bottom: 0.188rem;
color: var(--vh-main-color);
width: 1.18rem;
height: 1.18rem;
object-fit: contain;
animation: talking-tag-active 0.18s ease-in-out infinite;
}
}
&>.tips-content {
font-size: 0.88rem;
p {
padding: 0.28rem 0;
}
}
} }
// 分类 // 分类
&.categories { &.cat {
&>.vh-aside-categories { &>.vh-aside-cat {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
@ -149,20 +222,21 @@ aside.vh-aside {
&>a { &>a {
flex-shrink: 0; flex-shrink: 0;
box-sizing: border-box; box-sizing: border-box;
padding: 0.5rem 0.28rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
height: 2.36rem; height: 2.18rem;
font-size: 0.88rem;
border-radius: 0.38rem; border-radius: 0.38rem;
background-color: #fff; background-color: var(--vh-white-color);
transition: all 0.16s ease-in-out; transition: all 0.18s ease-in-out;
overflow: hidden; overflow: hidden;
&:hover { &:hover {
padding-left: 0.66rem; padding-left: 0.66rem;
background-color: var(--vh-main-color-66); background-color: var(--vh-main-color-66);
color: var(--vh-white-color);
&>i { &>i {
background-color: transparent; background-color: transparent;
@ -173,13 +247,14 @@ aside.vh-aside {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 2rem; width: 1.68rem;
height: 1.75rem; height: 1.28rem;
font-size: var(--vh-size-span); color: var(--vh-white-color);
font-size: 0.66rem;
font-style: normal; font-style: normal;
border-radius: 0.38rem; border-radius: 0.38rem;
background-color: var(--vh-main-color-66); background-color: var(--vh-main-color-66);
transition: background 0.16s ease-in-out; transition: background 0.18s ease-in-out;
overflow: hidden; overflow: hidden;
} }
} }
@ -191,35 +266,39 @@ aside.vh-aside {
&>.vh-aside-tags { &>.vh-aside-tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.5rem; gap: 0.68rem 1rem;
width: 100%; width: 100%;
height: max-content; height: max-content;
overflow: hidden; overflow: hidden;
&>a { &>a {
display: flex;
align-items: center;
gap: 0.18rem;
width: max-content; width: max-content;
height: max-content; height: max-content;
&:hover { &:hover {
&>span { &>span {
background-color: var(--vh-main-color); color: var(--vh-main-color);
} }
} }
&>span { &>span {
display: block;
box-sizing: border-box; box-sizing: border-box;
padding: 0 0.618rem;
width: max-content; width: max-content;
height: 1.75rem; font-size: 0.8rem;
border-radius: 0.38rem; line-height: 1.5;
background-color: var(--vh-main-color-38); transition: color 0.18s ease-in-out;
font-size: var(--vh-size-span);
font-style: normal;
line-height: 1.75rem;
transition: background 0.16s ease-in-out;
overflow: hidden; overflow: hidden;
} }
&>em {
// display: none;
color: var(--vh-font-28);
font-size: 0.688rem;
font-style: normal;
}
} }
} }
} }
@ -236,73 +315,93 @@ aside.vh-aside {
&>a { &>a {
box-sizing: border-box; box-sizing: border-box;
padding: 0 0.625rem;
display: flex; display: flex;
align-items: center; flex-direction: column;
gap: 0.625rem; justify-content: space-between;
width: 100%; width: 100%;
height: 4.6rem; height: 2.68rem;
border-bottom: 1px dashed #f3f2f2;
overflow: hidden; overflow: hidden;
&:nth-last-of-type(1) {
border: none;
}
&:hover { &:hover {
&>span {
&>cite {
color: var(--vh-main-color);
&>p { &::after {
&>img { width: 100%;
transform: scale(1.2); }
} }
} }
} }
&>p { &:nth-of-type(2) {
&>span {
&>i {
background-color: var(--vh-warning);
}
}
}
&:nth-of-type(3) {
&>span {
&>i {
background-color: var(--vh-import);
}
}
}
&>span {
box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; align-items: center;
justify-content: center; gap: 0.618rem;
overflow: hidden; width: 100%;
&.cover { &>cite {
flex-shrink: 0; width: max-content;
width: 3.88rem; max-width: 100%;
height: 3.88rem; border-bottom: 1px solid transparent;
border-radius: 0.288rem; font-size: 0.8rem;
overflow: hidden; line-height: 1.5;
font-style: normal;
transition: color 0.288s ease-in-out;
&>img { &::after {
width: 100%; content: '';
height: 100%; display: block;
object-fit: cover; width: 0;
transition: transform 0.16s ease-in-out; height: 1px;
background-color: var(--vh-main-color);
transition: width 0.58s cubic-bezier(.6, .1, 0, 1);
} }
} }
&.info { &>i {
flex: 1; flex-shrink: 0;
width: 100%; width: 0.875rem;
height: 100%; height: 0.875rem;
border-radius: 0.18rem;
color: var(--vh-white-color);
text-align: center;
font-size: 0.66rem;
font-style: normal;
background-color: var(--vh-success);
}
&>em {
&>span { flex-shrink: 0;
width: 100%; width: max-content;
font-size: var(--vh-size-h3); font-style: normal;
line-height: 1.5; font-size: 0.8125rem;
display: -webkit-box; color: var(--vh-font-66);
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
word-break: break-all;
overflow: hidden;
}
&>time {
color: #858585;
font-size: 0.68rem;
}
} }
} }
&>time {
color: var(--vh-font-56);
font-size: 0.688rem;
}
} }
} }
} }

View File

@ -6,7 +6,7 @@ section.vh-back-top {
height: 2.6rem; height: 2.6rem;
border-radius: 50%; border-radius: 50%;
border: 1px solid #e5e7eb; border: 1px solid #e5e7eb;
background-color: #fff; background-color: var(--vh-white-color);
transform: translateX(1rem); transform: translateX(1rem);
cursor: pointer; cursor: pointer;
opacity: 0; opacity: 0;

View File

@ -4,13 +4,13 @@
width: 100%; width: 100%;
height: max-content; height: max-content;
border-radius: 0.5rem; border-radius: 0.5rem;
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); box-shadow: var(--vh-box-shadow);
overflow: hidden; overflow: hidden;
// 评论样式 // 评论样式
.twikoo { .twikoo {
font-size: var(--vh-size-h2); font-size: 0.88rem;
img:not(.tk-avatar-img) { img:not(.tk-avatar-img) {
cursor: pointer; cursor: pointer;
@ -28,7 +28,7 @@
ol { ol {
li { li {
color: #33333388; color: #33333388;
font-size: var(--vh-size-span); font-size: 0.875rem;
line-height: 1.6; line-height: 1.6;
} }
@ -39,7 +39,7 @@
:not(pre) { :not(pre) {
&>code { &>code {
background-color: var(--vh-black-16); background-color: var(--vh-font-16);
padding: .125rem .375rem; padding: .125rem .375rem;
font-size: 0.8125rem; font-size: 0.8125rem;
} }
@ -53,19 +53,19 @@
} }
p { p {
color: var(--vh-black-100); color: var(--vh-font-color);
font-weight: 400; font-weight: 400;
font-size: var(--vh-size-span); font-size: 0.875rem;
line-height: 28px; line-height: 28px;
a { a {
color: var(--vh-black-56); color: var(--vh-font-56);
box-shadow: inset 0 -.12rem #60a5fa; box-shadow: inset 0 -.12rem var(--vh-main-color);
transition: box-shadow .2s ease-in-out, color .2s ease-in-out; transition: box-shadow .2s ease-in-out, color .2s ease-in-out;
&:hover { &:hover {
box-shadow: inset 0 -1.5rem #60a5fa66; box-shadow: inset 0 -1.5rem var(--vh-main-color-38);
} }
} }
} }
@ -78,7 +78,7 @@
} }
p { p {
color: #fff; color: var(--vh-white-color);
} }
.tk-admin-warn p { .tk-admin-warn p {
@ -190,7 +190,7 @@
width: 0.8rem; width: 0.8rem;
height: 0.8rem; height: 0.8rem;
border-radius: 50%; border-radius: 50%;
background: #fff url("/public/assets/images/admin.svg") no-repeat; background: var(--vh-white-color) url("/public/assets/images/admin.svg") no-repeat;
background-size: cover; background-size: cover;
} }
} }
@ -215,7 +215,7 @@
&>.tk-nick { &>.tk-nick {
position: relative; position: relative;
color: var(--vh-black-100); color: var(--vh-font-color);
line-height: 1.18rem; line-height: 1.18rem;
&.tk-nick-link { &.tk-nick-link {
@ -229,7 +229,7 @@
bottom: 0; bottom: 0;
width: 0; width: 0;
height: 1px; height: 1px;
background-color: var(--vh-black-88); background-color: var(--vh-font-88);
transition: all 0.28s; transition: all 0.28s;
} }
@ -292,7 +292,7 @@
box-sizing: border-box; box-sizing: border-box;
padding: 4px; padding: 4px;
border-radius: 0.2rem; border-radius: 0.2rem;
background-color: var(--vh-black-6); background-color: var(--vh-font-6);
} }
} }
@ -324,7 +324,7 @@
// 头像尺寸和圆角 // 头像尺寸和圆角
--waline-avatar-size: 2.56rem; --waline-avatar-size: 2.56rem;
--waline-avatar-radius: 0.58rem; --waline-avatar-radius: 0.58rem;
font-size: var(--vh-size-h2); font-size: 0.88rem;
.wl-comment { .wl-comment {
.wl-panel { .wl-panel {
@ -350,8 +350,8 @@
&>.wl-head { &>.wl-head {
.wl-nick { .wl-nick {
color: var(--vh-black-100); color: var(--vh-font-color);
font-size: var(--vh-size-h2); font-size: 0.88rem;
line-height: 1.18; line-height: 1.18;
&::after { &::after {
@ -362,7 +362,7 @@
bottom: 0; bottom: 0;
width: 0; width: 0;
height: 1px; height: 1px;
background-color: var(--vh-black-88); background-color: var(--vh-font-88);
transition: all 0.28s; transition: all 0.28s;
} }
@ -389,8 +389,8 @@
p { p {
padding: 0.18rem 0; padding: 0.18rem 0;
color: var(--vh-black-100); color: var(--vh-font-color);
font-size: var(--vh-size-span); font-size: 0.875rem;
line-height: 1.75rem; line-height: 1.75rem;
} }
@ -400,7 +400,7 @@
} }
a { a {
color: var(--vh-black-100); color: var(--vh-font-color);
font-size: 0.76rem; font-size: 0.76rem;
font-weight: 700; font-weight: 700;
} }
@ -415,7 +415,7 @@
// item 中 wl-card 虚线间距 // item 中 wl-card 虚线间距
&>.wl-card { &>.wl-card {
padding-bottom: 1.25rem; padding-bottom: 1.25rem;
border-bottom-color: var(--vh-black-16); border-bottom-color: var(--vh-font-16);
} }
} }
} }
@ -448,7 +448,7 @@
} }
a { a {
color: var(--vh-black-56); color: var(--vh-font-56);
line-height: 1.288; line-height: 1.288;
} }

View File

@ -15,7 +15,7 @@
position: relative; position: relative;
width: max-content; width: max-content;
height: max-content; height: max-content;
color: #33333388; color: var(--vh-font-56) !important;
box-shadow: none !important; box-shadow: none !important;
overflow: hidden; overflow: hidden;
@ -26,7 +26,7 @@
content: ''; content: '';
width: 0; width: 0;
height: 2px; height: 2px;
background-color: #60a5fa; background-color: var(--vh-main-color);
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
} }
@ -48,7 +48,7 @@
font-size: 0.875rem !important; font-size: 0.875rem !important;
&>span { &>span {
color: #9CC5FB; color: var(--vh-main-color);
} }
} }

View File

@ -51,7 +51,7 @@
width: max-content; width: max-content;
height: 100%; height: 100%;
line-height: 1.25rem; line-height: 1.25rem;
color: #fff; color: var(--vh-white-color);
font-style: normal; font-style: normal;
} }
@ -96,11 +96,11 @@
&.text { &.text {
&>p { &>p {
font-size: var(--vh-size-h2); font-size: 0.88rem;
&>a { &>a {
color: #94A3B8; color: #94A3B8;
transition: opacity 0.16s ease-in-out; transition: opacity 0.18s ease-in-out;
&:hover { &:hover {
opacity: 0.88; opacity: 0.88;

View File

@ -1,4 +1,7 @@
--- ---
// 当前路由
const { activeNav } = Astro.props;
// 站点配置
import SITE_CONFIG from "@/config"; import SITE_CONFIG from "@/config";
const { Navs } = SITE_CONFIG; const { Navs } = SITE_CONFIG;
// Svg 组件 // Svg 组件
@ -11,24 +14,22 @@ import "./Header.less";
<header class="vh-header"> <header class="vh-header">
<section class="main"> <section class="main">
<a href="/" class="index"> <a href="/" class="home vh-hover">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-smart-home"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M19 8.71l-5.333 -4.148a2.666 2.666 0 0 0 -3.274 0l-5.334 4.148a2.665 2.665 0 0 0 -1.029 2.105v7.2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-7.2c0 -.823 -.38 -1.6 -1.03 -2.105"></path><path d="M16 15c-2.21 1.333 -5.792 1.333 -8 0"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M19 8.71l-5.333 -4.148a2.666 2.666 0 0 0 -3.274 0l-5.334 4.148a2.665 2.665 0 0 0 -1.029 2.105v7.2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-7.2c0 -.823 -.38 -1.6 -1.03 -2.105"></path><path d="M16 15c-2.21 1.333 -5.792 1.333 -8 0"></path></svg>
<span>Home</span> <span>Home</span>
</a> </a>
<div class="link-list vh-link-list"> <nav>
{ {
Navs.map(i => ( Navs.map(i => (
<a class={i.link.replace("/", "")} href={i.link} target={i.target ? "_blank" : "_self"}> <a class={`nav-link vh-hover${i.link.includes(activeNav) ? " active" : ""}`} href={i.link} target={i.target ? "_blank" : "_self"}>
{i.text} {i.text}
<Svg src={i.icon} /> <Svg src={i.icon} />
</a> </a>
)) ))
} }
</div> <span class="nav-link vh-hover search-btn"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0"></path><path d="M21 21l-6 -6"></path></svg> 搜索</span>
<div class="nav-btn"> <span class="nav-link vh-hover menu-btn"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 6h16"></path><path d="M7 12h13"></path><path d="M10 18h10"></path></svg></span>
<span class="nav-btn-item search-btn"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"></path></svg> 搜索</span> </nav>
<span class="nav-btn-item menu-btn"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"></path></svg></span>
</div>
<Search /> <Search />
</section> </section>
</header> </header>

View File

@ -3,70 +3,46 @@ header.vh-header {
left: 0; left: 0;
top: 0; top: 0;
box-sizing: border-box; box-sizing: border-box;
padding: 0 1rem;
display: flex;
align-items: center;
justify-content: center;
width: 100vw; width: 100vw;
height: 3.6rem; height: 66px;
background-color: var(--vh-white-6);
backdrop-filter: blur(2rem); backdrop-filter: blur(2rem);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); background-color: rgba(255, 255, 255, 0.36);
box-shadow: var(--vh-box-shadow);
transition: background-color 0.18s ease-in-out;
z-index: 9; z-index: 9;
&>section.main { &>section {
position: relative;
margin: 0 auto; margin: 0 auto;
box-sizing: border-box; box-sizing: border-box;
padding: 0 1rem; padding: 0 0.88rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
width: 100%; width: 100%;
height: 80%; height: 100%;
max-width: var(--vh-main-max-width); max-width: var(--vh-main-max-width);
a, &>.home {
span.nav-btn-item {
flex-shrink: 0;
position: relative;
box-sizing: border-box; box-sizing: border-box;
padding: 0 0.5rem; padding: 0.266rem 0.188rem;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.618rem;
width: max-content; width: max-content;
height: 80%; height: max-content;
font-size: var(--vh-size-p); color: var(--vh-font-color);
font-weight: 700;
z-index: 1;
transition: all 0.08s ease-in-out;
user-select: none;
cursor: pointer;
&:hover { &:hover {
&::before { &>span {
transform: scale(1.2); color: var(--vh-white-color);
opacity: 1;
}
&::after {
opacity: 0;
} }
} }
&::before { &>span {
content: ''; font-size: 0.98rem;
position: absolute; font-weight: 600;
left: 0; padding-top: 0.188rem;
top: 0; transition: all 0.1s;
width: 100%; font-weight: 700;
height: 100%;
border-radius: 0.5rem;
background-color: var(--vh-main-color);
opacity: 0;
transition: transform 0.16s ease-in-out, opacity 0.16s ease-in-out;
z-index: -1;
} }
&>svg { &>svg {
@ -74,123 +50,63 @@ header.vh-header {
width: auto; width: auto;
object-fit: contain; object-fit: contain;
} }
&.index {
padding-right: 2rem;
&>span {
box-sizing: border-box;
padding-top: 0.188rem;
width: max-content;
height: max-content;
font-size: 1.088rem;
line-height: 1;
}
}
&.search-btn {
&>svg {
width: 1rem;
height: 1rem;
}
}
} }
&>.link-list, &>nav {
&>.nav-btn {
flex: 1;
box-sizing: border-box; box-sizing: border-box;
padding-right: 1rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; margin-left: auto;
gap: 0.88rem; gap: 1.18rem;
height: 100%; height: 100%;
width: max-content;
max-width: 100%;
&:nth-last-of-type(1) { &>.nav-link {
padding-right: 0; box-sizing: border-box;
} padding: 0.288rem 0.36rem;
display: flex;
align-items: center;
gap: 0.28rem;
line-height: inherit;
height: max-content;
font-size: 0.98rem;
font-weight: 600;
user-select: none;
&>a, &.search-btn,
&>span { &.menu-btn {
&.active { cursor: pointer;
pointer-events: none; }
&::before { &.menu-btn {
transform: scale(1); display: none;
opacity: 1;
&>svg {
height: 1.28rem;
} }
} }
&>svg { &>svg {
pointer-events: none; height: 1rem;
width: auto; width: auto;
height: 1.18rem;
object-fit: contain; object-fit: contain;
stroke: var(--vh-black-88);
stroke-width: 2.88px;
} }
}
}
&>.nav-btn {
flex: none;
width: max-content;
&>.menu-btn {
display: none;
&>svg {
box-sizing: border-box;
padding: 0.36rem;
width: 1.88rem;
height: 1.88rem;
border: 1px solid var(--vh-black-16);
border-radius: 0.6rem;
}
} }
} }
} }
} }
@media screen and (max-width: 888px) {
header.vh-header {
padding: 0;
&>section.main {
a {
font-size: var(--vh-size-span);
&:hover {
&::before {
transform: scale(1.1);
}
}
&>svg {
width: 1.18rem;
height: 1.18rem;
}
}
&>.link-list {
display: none;
}
}
}
}
@media screen and (max-width: 888px) { @media screen and (max-width: 888px) {
header.vh-header { header.vh-header {
&>section.main { &>section {
&>.nav-btn { &>nav {
&>.menu-btn { &>a.nav-link {
display: none;
}
&>.menu-btn.nav-link {
display: flex; display: flex;
} }
} }

View File

@ -0,0 +1,12 @@
---
import SITE_INFO from "@/config";
import "./MainHeader.less";
---
<div class="header-main">
<div class="avatar">
<img src="/assets/images/lazy-loading.webp" data-vh-lz-src={SITE_INFO.Avatar} alt="avatar" />
</div>
<h3 class="auther">{SITE_INFO.Author || "-"}</h3>
<p class="desc"></p>
</div>

View File

@ -0,0 +1,105 @@
.header-main {
position: relative;
box-sizing: border-box;
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
gap: 0.88rem;
width: 100%;
height: var(--vh-main-header-height);
transition: height 0.3s ease-in-out;
z-index: 1;
&::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
background: var(--vh-home-banner) no-repeat top center;
background-size: cover;
z-index: -1;
}
&>.avatar {
width: 8.5rem;
height: 8.5rem;
border: 2px solid var(--vh-white-color);
border-radius: 50%;
transition: transform 0.3s ease-in-out;
overflow: hidden;
&:hover {
transform: rotate(18.88deg);
}
&>img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
&>.auther {
padding-top: 1.88rem;
font-size: 1.88rem;
font-weight: 600;
color: var(--vh-white-color);
}
&>.desc {
position: relative;
box-sizing: border-box;
padding: 0.66rem 0.66rem 0;
width: 100%;
max-width: 26rem;
height: max-content;
color: var(--vh-white-color);
text-align: center;
font-size: 0.88rem;
line-height: 1.5rem;
&::before {
content: "";
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
opacity: .5;
background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgb(0 0 0 / 70%)), color-stop(35%, var(--vh-white-color)), color-stop(65%, var(--vh-white-color)), color-stop(100%, rgb(0 0 0 / 70%)));
}
&::after {
content: "|";
padding-left: 0.188rem;
display: inline-block;
animation: blink 1s infinite;
color: #fff;
}
@keyframes blink {
50% {
opacity: 0;
}
}
}
}
@media screen and (max-width: 1150px) {
.header-main {
height: 26rem;
&>.avatar {
width: 6rem;
height: 6rem;
}
&>.auther {
padding-top: 0;
}
}
}

View File

@ -7,7 +7,7 @@
box-sizing: border-box; box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.26); background-color: rgba(0, 0, 0, 0.26);
overflow: hidden; overflow: hidden;
transition: opacity 0.16s ease-in-out, z-index 0.16s ease-in-out; transition: opacity 0.18s ease-in-out;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
z-index: 10; z-index: 10;
@ -38,9 +38,9 @@
width: 100%; width: 100%;
max-width: 17.6rem; max-width: 17.6rem;
height: 100%; height: 100%;
background-color: #fff; background-color: var(--vh-white-color);
transform: translateX(-1rem); transform: translateX(-1rem);
transition: transform 0.16s ease-in; transition: transform 0.18s ease-in;
overflow: hidden; overflow: hidden;
&>.vh-mobilesidebar-list { &>.vh-mobilesidebar-list {
@ -69,7 +69,7 @@
gap: 0.618rem; gap: 0.618rem;
width: 100%; width: 100%;
height: 2.25rem; height: 2.25rem;
font-size: var(--vh-size-p); font-size: 1rem;
color: #66758c; color: #66758c;
font-weight: 600; font-weight: 600;
border-radius: 0.375rem; border-radius: 0.375rem;
@ -87,11 +87,11 @@
&:hover, &:hover,
&.active { &.active {
color: #fff; color: var(--vh-white-color);
background-color: #3366FF; background-color: var(--vh-main-color);
&>svg { &>svg {
stroke: #fff; stroke: var(--vh-white-color);
} }
} }
@ -99,7 +99,7 @@
width: auto; width: auto;
height: 0.888rem; height: 0.888rem;
object-fit: contain; object-fit: contain;
transition: stroke 0.16s ease-in-out; transition: stroke 0.18s ease-in-out;
} }
} }
} }

View File

@ -6,12 +6,10 @@ import { fmtPage } from "@/utils/index";
import "./Pagination.less"; import "./Pagination.less";
--- ---
<section class="vh-article-pagination"> <section class="vh-art-page">
<!-- 上一页 --> <!-- 上一页 -->
<a class={`vh-pagination-item${!data.prev ? " disabled" : ""}`} href={data.prev || "javascript:;"} title="上一页"> <a class={`vh-pagination-item${!data.prev ? " disabled" : ""}`} href={data.prev || "javascript:;"} title="上一页">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M15 6l-6 6l6 6"></path></svg>
<path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"></path>
</svg>
</a> </a>
<!-- 首页 --> <!-- 首页 -->
{ {
@ -49,8 +47,6 @@ import "./Pagination.less";
} }
<!-- 下一页 --> <!-- 下一页 -->
<a class={`vh-pagination-item${!data.next ? " disabled" : ""}`} href={data.next || "javascript:;"} title="下一页"> <a class={`vh-pagination-item${!data.next ? " disabled" : ""}`} href={data.next || "javascript:;"} title="下一页">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M9 6l6 6l-6 6"></path></svg>
<path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"></path>
</svg>
</a> </a>
</section> </section>

View File

@ -1,7 +1,7 @@
section.vh-article-pagination { section.vh-art-page {
position: absolute; position: absolute;
left: 0; bottom: 0.88rem;
bottom: 0; right: 0;
box-sizing: border-box; box-sizing: border-box;
padding: 1rem; padding: 1rem;
display: flex; display: flex;
@ -10,6 +10,7 @@ section.vh-article-pagination {
gap: 1rem; gap: 1rem;
width: 100%; width: 100%;
height: max-content; height: max-content;
overflow: hidden;
&>a.vh-pagination-item { &>a.vh-pagination-item {
display: flex; display: flex;
@ -18,20 +19,21 @@ section.vh-article-pagination {
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
border-radius: 0.5rem; border-radius: 0.5rem;
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); box-shadow: var(--vh-box-shadow);
font-size: var(--vh-size-span); font-size: 0.875rem;
color: #99a9bf; color: #99a9bf;
user-select: none; user-select: none;
transition: background-color 0.16s ease-in-out; transition: background-color 0.18s ease-in-out;
cursor: pointer; cursor: pointer;
overflow: hidden;
&:hover { &:hover {
color: #fff; color: var(--vh-white-color);
background-color: rgba(129, 146, 174, 0.36); background-color: rgba(129, 146, 174, 0.36);
&>svg { &>svg {
fill: #fff; color: var(--vh-white-color);
} }
} }
@ -39,22 +41,21 @@ section.vh-article-pagination {
background-color: #8192AE; background-color: #8192AE;
cursor: default; cursor: default;
pointer-events: none; pointer-events: none;
color: #fff; color: var(--vh-white-color);
} }
&.disabled { &.disabled {
pointer-events: none; pointer-events: none;
&>svg { &>svg {
fill: #E8E8E8; color: #E8E8E8;
} }
} }
&>svg { &>svg {
width: 0.8rem; height: 1.18rem;
height: 0.8rem; width: auto;
fill: #99a9bf; object-fit: contain;
transition: fill 0.16s ease-in-out;
} }
} }
} }

View File

@ -7,8 +7,9 @@
gap: 0.88rem; gap: 0.88rem;
width: 100%; width: 100%;
height: max-content; height: max-content;
background-color: #fff; border-radius: var(--vh-main-radius);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); background-color: var(--vh-white-color);
box-shadow: var(--vh-box-shadow);
&>p { &>p {
padding: 0 !important; padding: 0 !important;
@ -36,9 +37,9 @@
width: max-content; width: max-content;
height: 2rem; height: 2rem;
border-radius: 0.28rem; border-radius: 0.28rem;
color: #fff; color: var(--vh-white-color);
cursor: pointer; cursor: pointer;
transition: opacity 0.16s, transform 0.16s; transition: opacity 0.18s, transform 0.18s;
user-select: none; user-select: none;
&:hover { &:hover {
@ -82,8 +83,8 @@
background-size: cover; background-size: cover;
z-index: 1; z-index: 1;
overflow: hidden; overflow: hidden;
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
transition: opacity 0.16s, transform 0.16s; transition: opacity 0.18s, transform 0.18s;
} }

View File

@ -11,7 +11,7 @@
flex-direction: column; flex-direction: column;
background-color: rgba(0, 0, 0, 0.26); background-color: rgba(0, 0, 0, 0.26);
overflow: hidden; overflow: hidden;
transition: opacity 0.16s ease-in-out; transition: opacity 0.18s ease-in-out;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
z-index: 1; z-index: 1;
@ -37,10 +37,10 @@
height: max-content; height: max-content;
max-height: 88vh; max-height: 88vh;
border-radius: 1rem; border-radius: 1rem;
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
transform: translateY(-1rem); transform: translateY(-1rem);
transition: transform 0.16s; transition: transform 0.18s;
overflow: hidden; overflow: hidden;
@ -53,11 +53,10 @@
gap: 0.28rem; gap: 0.28rem;
width: 100%; width: 100%;
height: 2.425rem; height: 2.425rem;
background-color: var(--vh-white-100); background-color: var(--vh-font-6);
border-radius: 0.66rem; border-radius: 0.66rem;
overflow: hidden; overflow: hidden;
&>svg { &>svg {
flex-shrink: 0; flex-shrink: 0;
width: 1.28rem; width: 1.28rem;
@ -69,13 +68,13 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
border: none; border: none;
color: var(--vh-black-88); color: var(--vh-font-88);
font-size: var(--vh-size-span); font-size: 0.875rem;
background-color: transparent; background-color: transparent;
transition: width 0.16s ease-in-out; transition: width 0.18s ease-in-out;
&::placeholder { &::placeholder {
color: var(--vh-black-88); color: var(--vh-font-88);
} }
} }
} }
@ -86,7 +85,7 @@
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
height: max-content; height: max-content;
background-color: #fff; background-color: var(--vh-white-color);
user-select: none; user-select: none;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
@ -117,9 +116,9 @@
&>span { &>span {
width: 100%; width: 100%;
font-size: var(--vh-size-h1); font-size: 1.125rem;
font-weight: 600; font-weight: 600;
color: var(--vh-black-100); color: var(--vh-font-color);
line-height: 1.16; line-height: 1.16;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@ -128,8 +127,8 @@
&>p { &>p {
width: 100%; width: 100%;
font-size: var(--vh-size-span); font-size: 0.875rem;
color: var(--vh-black-56); color: var(--vh-font-56);
font-weight: 400; font-weight: 400;
line-height: 1.25rem; line-height: 1.25rem;
display: -webkit-box; display: -webkit-box;

View File

@ -1,19 +1,27 @@
--- ---
const { title, keywords, description, pagecover } = Astro.props; const { title, keywords, description, pagecover, activeNav } = Astro.props;
// 网站配置 // 网站配置
import SITE_INFO from "@/config"; import SITE_INFO from "@/config";
const { GoogleAds } = SITE_INFO; const { GoogleAds, Theme, HomeBanner } = SITE_INFO;
const { ad_Client, asideAD_Slot, articleAD_Slot } = GoogleAds; const { ad_Client, asideAD_Slot, articleAD_Slot } = GoogleAds;
// Head 依赖 // Head 依赖
import Head from "@/components/Head/Head.astro"; import Head from "@/components/Head/Head.astro";
// 顶部 Header // 顶部 Header
import Header from "@/components/Header/Header.astro"; import Header from "@/components/Header/Header.astro";
// Main 区域 Header
import MainHeader from "@/components/MainHeader/MainHeader.astro";
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// 底部 Footer // 底部 Footer
import Footer from "@/components/Footer/Footer.astro"; import Footer from "@/components/Footer/Footer.astro";
// 返回顶部 // 返回顶部
import BackTop from "@/components/BackTop/BackTop.astro"; import BackTop from "@/components/BackTop/BackTop.astro";
// 手机端侧边栏 // 手机端侧边栏
import MobileSidebar from "@/components/MobileSidebar/MobileSidebar.astro"; import MobileSidebar from "@/components/MobileSidebar/MobileSidebar.astro";
// A Modern CSS Reset
import "@/styles/Reset.less";
// 全局基础样式
import "@/styles/Base.less";
// Layout 样式 // Layout 样式
import "./Layout.less"; import "./Layout.less";
--- ---
@ -22,15 +30,31 @@ import "./Layout.less";
<Head Title={title} Keywords={keywords} Description={description} PageCover={pagecover}> <Head Title={title} Keywords={keywords} Description={description} PageCover={pagecover}>
<!-- 谷歌广告JS加载项 --> <!-- 谷歌广告JS加载项 -->
{ad_Client && (asideAD_Slot || articleAD_Slot) && <script is:inline async src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ad_Client}`} crossorigin="anonymous" />} {ad_Client && (asideAD_Slot || articleAD_Slot) && <script is:inline async src={`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${ad_Client}`} crossorigin="anonymous" />}
<!-- 泡泡🫧 -->
<script is:inline src="/assets/js/vhPaopao.js" defer></script>
<!-- 彩旗🎈 -->
<script is:inline src="/assets/js/vhCaiqi.js" defer></script>
<!-- 设置主题颜色 -->
<Fragment
set:html={`<style>:root {${Object.entries(Theme)
.map(([key, value]) => `${key}:${value};`)
.join("")}--vh-home-banner:url('${HomeBanner.cover}')}</style>`}
/>
</Head> </Head>
<body> <body>
<MobileSidebar /> <MobileSidebar />
<Header /> <Header activeNav={activeNav} />
<main class="vh-main"> <main class="main">
<slot /> {HomeBanner.enable && <MainHeader />}
<section class="main-inner" style={`padding-top:${HomeBanner.enable ? "2rem" : "calc(66px + 0.68rem)"}`}>
<section class="main-inner-content">
<slot />
</section>
<Aside />
</section>
<BackTop />
</main> </main>
<Footer /> <Footer />
<BackTop />
<script> <script>
import InitFn from "@/scripts/Init"; import InitFn from "@/scripts/Init";
// 全局初始化 // 全局初始化

View File

@ -1,53 +1,39 @@
body { main.main {
&::before { box-sizing: border-box;
content: ""; display: flex;
position: fixed; flex-direction: column;
left: 0; align-items: center;
top: 0; width: 100%;
width: 100vw; height: max-content;
height: 100vh; overflow: visible !important;
background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='8' height='8' fill='none' stroke='rgb(0 0 0 / 0.1)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e");
z-index: -1;
}
&>main.vh-main { &>.main-inner {
flex-shrink: 0;
position: relative;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: row-reverse;
gap: 1rem;
width: 100%; width: 100%;
max-width: var(--vh-main-max-width); max-width: var(--vh-main-max-width);
height: max-content; height: max-content;
z-index: 1;
&>section.vh-container { &>.main-inner-content {
position: relative; flex: 1 1 0%;
box-sizing: border-box; box-sizing: border-box;
display: flex; padding: 0.88rem 0.66rem;
flex-direction: row-reverse;
gap: 1.8rem;
width: 100%; width: 100%;
min-width: 0;
height: max-content; height: max-content;
overflow: hidden;
&>section:not(.article-list) {
box-sizing: border-box;
display: flex;
flex-direction: column;
width: 100%;
min-width: 0;
height: max-content;
}
} }
} }
} }
@media screen and (max-width: 888px) { @media screen and (max-width: 888px) {
body { main.main {
&>main.vh-main { &>.main-inner {
&>section.vh-container { flex-direction: column;
flex-direction: column;
}
} }
} }
} }

View File

@ -14,18 +14,17 @@ import Comment from "@/components/Comment/Comment.astro";
import "@/styles/About.less"; import "@/styles/About.less";
// 文章内容基础样式 // 文章内容基础样式
import "@/styles/ArticleBase.less"; import "@/styles/ArticleBase.less";
// PageLayout 样式
import "./PageLayout.less";
--- ---
<Layout title={frontmatter.title || Title} description={Description}> <Layout title={frontmatter.title || Title} description={Description} activeNav={frontmatter.type || "-"}>
<section class="vh-container"> <section class="vh-page vh-about vh-animation vh-animation-init">
<section class="vh-about vh-animation vh-animation-init"> <header class="vh-page-header">
<header class="vh-page-header"> <h1>{frontmatter.h1}</h1>
<h1>{frontmatter.h1}</h1> <p>{frontmatter.desc}</p>
<p>{frontmatter.desc}</p> </header>
</header> <main><slot /></main>
<main><slot /></main> {checkComment() && frontmatter.comment != false && <Comment />}
{checkComment() && frontmatter.comment != false && <Comment />}
</section>
<Aside />
</section> </section>
</Layout> </Layout>

View File

@ -0,0 +1,18 @@
.vh-page {
display: flex;
flex-direction: column;
gap: 1.25rem;
&>.vh-page-header {
box-sizing: border-box;
padding: 1rem;
box-shadow: var(--vh-box-shadow);
background-color: var(--vh-white-color);
border-radius: 0.5rem;
h1,
p {
padding: 0;
}
}
}

View File

@ -16,17 +16,14 @@ import "./ToolLayout.less";
import "@/styles/ArticleBase.less"; import "@/styles/ArticleBase.less";
--- ---
<Layout title={frontmatter.title || Title} description={Description}> <Layout title={frontmatter.title || Title} description={Description} activeNav={frontmatter.type || "-"}>
<section class="vh-container"> <section class="vh-tools-main vh-animation vh-animation-init">
<section class="vh-tools-main vh-animation vh-animation-init"> <header class="vh-page-header">
<header class="vh-page-header"> <h1>{frontmatter.h1}</h1>
<h1>{frontmatter.h1}</h1> <p>{frontmatter.desc}</p>
<p>{frontmatter.desc}</p> </header>
</header> <main><slot /></main>
<main><slot /></main> <main class={`${frontmatter.type}-main main`}><section class="vh-space-loading"><span></span><span></span><span></span></section></main>
<main class={`${frontmatter.type}-main main`}><section class="vh-space-loading"><span></span><span></span><span></span></section></main> {checkComment() && frontmatter.comment != false && <Comment />}
{checkComment() && frontmatter.comment != false && <Comment />}
</section>
<Aside />
</section> </section>
</Layout> </Layout>

View File

@ -1,7 +1,26 @@
// 说说页评论 // 说说页评论
.vh-tools-main { .vh-tools-main {
display: flex;
flex-direction: column;
gap: 1.25rem; gap: 1.25rem;
.vh-node {
margin: -0.58rem 0 !important;
}
&>.vh-page-header {
box-sizing: border-box;
padding: 1rem;
background-color: var(--vh-white-color);
box-shadow: var(--vh-box-shadow);
border-radius: 0.5rem;
h1,
p {
padding: 0;
}
}
&>main { &>main {
box-sizing: border-box; box-sizing: border-box;
border-radius: 0.5rem; border-radius: 0.5rem;
@ -16,9 +35,7 @@
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 1rem; gap: 1rem;
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
&>a { &>a {
position: relative; position: relative;
@ -30,12 +47,12 @@
width: 100%; width: 100%;
height: 5.5rem; height: 5.5rem;
border-radius: 0.88rem; border-radius: 0.88rem;
transition: background-color 0.16s ease-in-out; transition: background-color 0.18s ease-in-out;
overflow: hidden; overflow: hidden;
z-index: 1; z-index: 1;
&:hover { &:hover {
background-color: var(--vh-black-16); background-color: var(--vh-font-16);
&>.avatar { &>.avatar {
transform: scale(1.2) rotate(8deg); transform: scale(1.2) rotate(8deg);
@ -52,7 +69,7 @@
border: solid 1px #E8E8E8; border: solid 1px #E8E8E8;
overflow: hidden; overflow: hidden;
opacity: 1; opacity: 1;
transition: all .16s; transition: all .18s;
} }
&>.link-info { &>.link-info {
@ -67,7 +84,7 @@
z-index: 1; z-index: 1;
&>span { &>span {
font-size: var(--vh-size-p); font-size: 1rem;
font-weight: 700; font-weight: 700;
line-height: 1rem; line-height: 1rem;
} }
@ -97,8 +114,7 @@
gap: 1.25rem; gap: 1.25rem;
&>.vh-space-loading { &>.vh-space-loading {
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
} }
&>article { &>article {
@ -107,8 +123,8 @@
width: 100%; width: 100%;
height: max-content; height: max-content;
border-radius: 0.5rem; border-radius: 0.5rem;
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); box-shadow: var(--vh-box-shadow);
background: #fff linear-gradient(90deg, #EDEEF388, #fff) no-repeat 100% 100% / 0 1px; background: var(--vh-white-color) linear-gradient(90deg, #EDEEF388, var(--vh-white-color)) no-repeat 100% 100% / 0 1px;
background-position: 0 100%; background-position: 0 100%;
background-size: 0 100%; background-size: 0 100%;
transition: .7s cubic-bezier(.6, .1, 0, 1), background-position 0s; transition: .7s cubic-bezier(.6, .1, 0, 1), background-position 0s;
@ -139,7 +155,7 @@
&>p { &>p {
padding: 0; padding: 0;
color: #26262680; color: #26262680;
font-size: var(--vh-size-span); font-size: 0.875rem;
line-height: 1.8; line-height: 1.8;
display: -webkit-box; display: -webkit-box;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
@ -164,7 +180,7 @@
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
height: 1.56rem; height: 1.56rem;
font-size: var(--vh-size-h3); font-size: 0.8rem;
overflow: hidden; overflow: hidden;
&>em { &>em {
@ -206,8 +222,7 @@
gap: 1.25rem; gap: 1.25rem;
&>.vh-space-loading { &>.vh-space-loading {
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
} }
&>article { &>article {
@ -215,9 +230,11 @@
padding: 2.188rem 1.875rem; padding: 2.188rem 1.875rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%;
height: max-content;
border-radius: 0.5rem; border-radius: 0.5rem;
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); box-shadow: var(--vh-box-shadow);
overflow: hidden; overflow: hidden;
&>header { &>header {
@ -244,7 +261,7 @@
overflow: hidden; overflow: hidden;
&>span { &>span {
font-size: var(--vh-size-span); font-size: 0.875rem;
} }
&>time { &>time {
@ -258,7 +275,7 @@
&>.main { &>.main {
box-sizing: border-box; box-sizing: border-box;
padding: 1rem 0; padding: 1rem 0;
font-size: var(--vh-size-span); font-size: 0.875rem;
font-weight: 500; font-weight: 500;
img { img {
@ -309,8 +326,6 @@
} }
} }
&>footer { &>footer {
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
@ -325,17 +340,17 @@
align-items: center; align-items: center;
height: 1.68rem; height: 1.68rem;
width: max-content; width: max-content;
border: 1px solid var(--vh-info); border: 1px solid var(--vh-main-color);
border-radius: 0.88rem; border-radius: var(--vh-main-radius);
background-color: #fff; background-color: var(--vh-white-color);
font-size: 0.72rem; font-size: 0.72rem;
color: var(--vh-info); color: var(--vh-main-color);
transition: all .2s ease-in-out; transition: all .2s ease-in-out;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
animation: talking-tag-active 0.16s ease-in-out infinite; animation: talking-tag-active 0.18s ease-in-out infinite;
} }
} }
} }
@ -390,31 +405,3 @@
} }
} }
} }
// 动画效果
@keyframes talking-tag-active {
0% {
transform: translateX(0);
}
25% {
transform: translateX(-1.66px);
}
50% {
transform: translateX(1.66px);
}
75% {
transform: translateX(-1.66px);
}
100% {
transform: translateX(0);
}
}

View File

@ -1,19 +0,0 @@
---
// 公共 Layout
import Layout from "@/layouts/Layout/Layout.astro";
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// 文章页面样式
import "@/styles/Article.less";
---
<Layout title="404 Not Found" keywords={[404]} description="404 Not Found">
<section class="vh-container">
<article class="vh-article-main vh-animation vh-animation-init">
<header>
<h1 class="error-title">404 Not Found</h1>
</header>
</article>
<Aside />
</section>
</Layout>

10
src/pages/404.md Normal file
View File

@ -0,0 +1,10 @@
---
title: "404 Not Found"
h1: "404 Not Found"
layout: "@/layouts/PageLayout/PageLayout.astro"
comment: false
---
:::note{type="error"}
你来到了一个不存在的页面。
:::

View File

@ -26,21 +26,18 @@ const { Description } = SITE_CONFIG;
import ArticleCard from "@/components/ArticleCard/ArticleCard.astro"; import ArticleCard from "@/components/ArticleCard/ArticleCard.astro";
// 公共 Layout // 公共 Layout
import Layout from "@/layouts/Layout/Layout.astro"; import Layout from "@/layouts/Layout/Layout.astro";
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// 分页组件 // 分页组件
import Pagination from "@/components/Pagination/Pagination.astro"; import Pagination from "@/components/Pagination/Pagination.astro";
const currentPage = page_data.url.current.replace("/", ""); const currentPage = page_data.url.current.replace("/", "");
--- ---
<Layout title={currentPage ? `第${currentPage}页文章` : ""} description={Description}> <Layout title={currentPage ? `第${currentPage}页文章` : ""} description={Description}>
<section class="vh-container"> <section class="article-list-main">
<section class="article-list vh-animation vh-animation-init"> <section class="article-list">
<!-- 文章列表 --> <!-- 文章列表 -->
{data.map((post, index) => <ArticleCard post={post} index={index} />)} {data.map((post, index) => <ArticleCard post={post} index={index} />)}
<!-- 分页 --> <!-- 分页 -->
<Pagination data={page_data.url} />
</section> </section>
<Aside /> <Pagination data={page_data.url} />
</section> </section>
</Layout> </Layout>

View File

@ -3,23 +3,42 @@ title: "关于"
h1: "关于我" h1: "关于我"
desc: "Hi there, Im Han 👋" desc: "Hi there, Im Han 👋"
layout: "@/layouts/PageLayout/PageLayout.astro" layout: "@/layouts/PageLayout/PageLayout.astro"
type: "about"
--- ---
:::note{type="success"} :::note{type="success"}
我是一名热爱前端开发并拥有丰富经验的工程师,喜欢探索新技术并应用于实际项目中 我是韩小韩,一位对技术充满热情、涉猎广泛的探索者,同时也是一名热衷于探索前沿技术的实践者
我始终保持对新技术的热情,并将我的知识与经验分享在我的博客中。我期待在这里与你分享我的见解、经验和最新的技术动态。 我始终保持对新技术的热情,并将我的知识与经验分享在我的博客中。
我的技术兴趣广泛涵盖前端工程、云计算、自托管服务、AI 应用以及网络架构优化。我始终相信,优秀的技术人不仅要有深度,更要有广度,因此我不断学习新知识,并将其转化为实际解决方案。
我期待在这里与你分享我的见解、经验和最新的技术动态。
::: :::
## Hi there, I'm Han 👋
<div class="enfj-dom"> **在 Web 开发方面**,我深耕 Vue.js 生态,并且关注了现代 CSS 框架如 Tailwind CSS。同时对前端构建工具如 Webpack、Rollup 和 Vite 以及代码质量和规范工具如 ESLint 进行了研究,我还关注了前端性能优化,例如代码分割、资源加载策略以及 Astro、Hexo 等现代网站构建工具的使用。
<div class="text">
<em>主人公</em> **在后端开发和云计算领域**,我对 Node.js 生态系统非常熟悉,并积极探索 Serverless 架构。我长期使用 Cloudflare Workers、Vercel 和腾讯云 EdgeOne 等平台优化边缘计算、KV 存储和全球 CDN 加速方案,确保应用的高可用性和低延迟。
<span>ENFJ-A</span>
<a class="more-enfj" href="https://www.16personalities.com/ch/enfj-%E4%BA%BA%E6%A0%BC">在 16personalities 了解更多关于 主人公</a> **在自托管Homelab和个人服务器管理方面**,我对个人服务器运维充满热情,搭建了基于 Jellyfin 的媒体中心、Home Assistant 智能家居系统,并利用 OpenWrt 优化家庭网络。在 Linux 系统管理、Docker 容器化部署和自动化脚本方面积累了丰富经验。
</div>
</div> **在人工智能与大型语言模型LLMs领域**,我密切关注 AI 领域的发展,尤其是 DeepSeek、Gemini 和 Claude 等大模型的应用。我尝试将 AI 能力整合到开发流程中,例如自动化文档生成、代码优化辅助,并且对 AI SDK 和相关工具保持关注。
**在网络与 DevOps 方面**,我熟悉 DNS 解析、CDN 加速、SSL 证书管理,并研究 TCP/IP、HTTP/3 等协议优化。我实践 Git 工作流、CI/CD 自动化GitHub Actions / Cloudflare Pages并利用 Docker 实现开发环境标准化。
**🚀 技术理念**
- **持续学习:** 技术日新月异,我始终保持开放心态,学习新框架、新工具,并评估其适用性。
- **实践驱动:** 无论是个人项目还是开源贡献,我都倾向于动手实践,而非仅停留在理论层面。
- **效率优先:** 我注重自动化与工具链优化,减少重复劳动,提升开发体验。
**🎯 未来方向**
未来,我计划进一步探索:
- **边缘计算与全球化部署**,优化分布式应用的性能。
- **AI 增强开发**,探索 LLM 在代码生成、调试和文档管理中的应用。
- **智能家居与自动化**,结合 Home Assistant 打造更高效的家庭 lab。
## Languages and Tools ## Languages and Tools
@ -45,12 +64,12 @@ layout: "@/layouts/PageLayout/PageLayout.astro"
## 小站点 ## 小站点
| 主&emsp;页 | <https://www.4ce.cn> | | 主&emsp;页 | <https://www.4ce.cn> |
| :-----------------: | :-----------------: | | :-----------------: | :-------------------------------: |
| **博&emsp;客** | **<https://www.vvhan.com>** | | **博&emsp;客** | **<https://www.vvhan.com>** |
| **Web&emsp;API** | **<https://api.vvhan.com>** | | **Web&emsp;API** | **<https://api.vvhan.com>** |
| **Han Analytics** | **<https://analytics.vvhan.com>** | | **Han Analytics** | **<https://analytics.vvhan.com>** |
| **Cloudflare 优选** | **<https://cf.vvhan.com>** | | **Cloudflare 优选** | **<https://cf.vvhan.com>** |
## 联系我 ## 联系我

View File

@ -13,7 +13,7 @@ import Aside from "@/components/Aside/Aside.astro";
import Archive from "@/components/Archive/Archive.astro"; import Archive from "@/components/Archive/Archive.astro";
--- ---
<Layout title="归档" description={Description}> <Layout title="归档" description={Description} activeNav="archives">
<section class="vh-container"> <section class="vh-container">
<Archive articleList={articleList} /> <Archive articleList={articleList} />
<Aside /> <Aside />

View File

@ -22,8 +22,6 @@ const { Content, remarkPluginFrontmatter } = await render(post);
const { reading_time, article_word_count } = remarkPluginFrontmatter; const { reading_time, article_word_count } = remarkPluginFrontmatter;
// 公共 Layout // 公共 Layout
import Layout from "@/layouts/Layout/Layout.astro"; import Layout from "@/layouts/Layout/Layout.astro";
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// Copyright 组件 // Copyright 组件
import Copyright from "@/components/Copyright/Copyright.astro"; import Copyright from "@/components/Copyright/Copyright.astro";
// Reward 组件 // Reward 组件
@ -40,39 +38,47 @@ import "@/styles/ArticleBase.less";
--- ---
<Layout title={post.data.title} keywords={post.data.tags} description={description} pagecover={ARTICLE_COVER}> <Layout title={post.data.title} keywords={post.data.tags} description={description} pagecover={ARTICLE_COVER}>
<section class="vh-container"> <article class="vh-article-main vh-animation vh-animation-init">
<article class="vh-article-main vh-animation vh-animation-init"> <header>
<header> <h1>{post.data.title}</h1>
<h1>{post.data.title}</h1> <div class="article-meta">
<div class="article-meta"> <span class="article-meta-item">
<span class="article-meta-item"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path><path d="M12 12h3.5"></path><path d="M12 7v5"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path><path d="M12 12h3.5"></path><path d="M12 7v5"></path></svg> <time>{fmtTime(post.data.date, "YYYY-MM-DD A")}</time>
<time>{fmtTime(post.data.date, "YYYY-MM-DD A")}</time> <span class="count"><strong>{article_word_count || "一点"}</strong>字</span>
<span class="count"><strong>{article_word_count || "一点"}</strong>字</span> <span class="time"><strong>{parseFloat((Number(reading_time) || 0).toFixed(1).replace(/\.0+$/, ""))}</strong>分钟</span>
<span class="time"><strong>{parseFloat((Number(reading_time) || 0).toFixed(1).replace(/\.0+$/, ""))}</strong>分钟</span> </span>
</span> <a class="article-meta-item" href={`/categories/${post.data.categories}`}>
<a class="article-meta-item" href={`/categories/${post.data.categories}`}> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 6h16"></path><path d="M7 12h13"></path><path d="M10 18h10"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 6h16"></path><path d="M7 12h13"></path><path d="M10 18h10"></path></svg> <span>{post.data.categories}</span>
<span>{post.data.categories}</span> </a>
</a> </div>
</div> </header>
</header> <main>
<main> <Content />
<Content /> <nav class="tag-list">
<nav class="tag-list"> {
{post.data.tags.map((i: any) => <a href={`/tag/${i}`}>{i}</a>)} post.data.tags.map((i: any) => (
</nav> <a href={`/tag/${i}`}>
</main> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<footer> <path stroke="none" d="M0 0h24v24H0z" fill="none" />
<!-- 打赏组件 --> <path d="M7.5 7.5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0" />
<Reward /> <path d="M3 6v5.172a2 2 0 0 0 .586 1.414l7.71 7.71a2.41 2.41 0 0 0 3.408 0l5.592 -5.592a2.41 2.41 0 0 0 0 -3.408l-7.71 -7.71a2 2 0 0 0 -1.414 -.586h-5.172a3 3 0 0 0 -3 3z" />
<!-- 版权©️信息 --> </svg>
<Copyright site={Site} id={post.data.id} title={post.data.title} sitename={Title} time={fmtTime(post.data.date, "YYYY-MM-DD A")} auther={Author} /> {i}
<!-- 底部谷歌广告 --> </a>
{GoogleAds.ad_Client && GoogleAds.articleAD_Slot && <GoogleAd className="vh-article-ad" slotID={GoogleAds.articleAD_Slot} />} ))
</footer> }
{checkComment() && <Comment />} </nav>
</article> </main>
<Aside /> <footer>
</section> <!-- 打赏组件 -->
<Reward />
<!-- 版权©️信息 -->
<Copyright site={Site} id={post.data.id} title={post.data.title} sitename={Title} time={fmtTime(post.data.date, "YYYY-MM-DD A")} auther={Author} />
<!-- 底部谷歌广告 -->
{GoogleAds.ad_Client && GoogleAds.articleAD_Slot && <GoogleAd className="vh-article-ad" slotID={GoogleAds.articleAD_Slot} />}
</footer>
{checkComment() && <Comment />}
</article>
</Layout> </Layout>

View File

@ -13,15 +13,10 @@ import SITE_CONFIG from "@/config";
const { Description } = SITE_CONFIG; const { Description } = SITE_CONFIG;
// 公共 Layout // 公共 Layout
import Layout from "@/layouts/Layout/Layout.astro"; import Layout from "@/layouts/Layout/Layout.astro";
// Aside组件
import Aside from "@/components/Aside/Aside.astro";
// 文章列表组件 // 文章列表组件
import Archive from "@/components/Archive/Archive.astro"; import Archive from "@/components/Archive/Archive.astro";
--- ---
<Layout title={`分类 ${categories} 下的文章`} description={Description}> <Layout title={`分类 ${categories} 下的文章`} description={Description} activeNav="categories">
<section class="vh-container"> <Archive articleList={articleList} />
<Archive articleList={articleList} />
<Aside />
</section>
</Layout> </Layout>

View File

@ -22,8 +22,5 @@ import Archive from "@/components/Archive/Archive.astro";
--- ---
<Layout title={`标签 ${tags} 下的文章`} description={Description}> <Layout title={`标签 ${tags} 下的文章`} description={Description}>
<section class="vh-container"> <Archive articleList={articleList} />
<Archive articleList={articleList} />
<Aside />
</section>
</Layout> </Layout>

View File

@ -15,7 +15,16 @@ const WalineFn = async (commentDOM: string, walineInit: any) => {
import('@waline/client/waline-meta.css'); import('@waline/client/waline-meta.css');
const { init } = await import('@waline/client'); const { init } = await import('@waline/client');
walineInit = init({ walineInit = init({
el: commentDOM, path: window.location.pathname.replace(/\/$/, ''), serverURL: SITE_INFO.Comment.Waline.serverURL, emoji: ['https://registry.npmmirror.com/@waline/emojis/1.3.0/files/alus', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/bilibili', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/bmoji', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/qq', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/weibo', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/soul-emoji'], el: commentDOM, path: window.location.pathname.replace(/\/$/, ''), serverURL: SITE_INFO.Comment.Waline.serverURL,
emoji: ['https://registry.npmmirror.com/@waline/emojis/1.3.0/files/alus', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/bilibili', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/bmoji', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/qq', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/weibo', 'https://registry.npmmirror.com/@waline/emojis/1.3.0/files/soul-emoji'],
reaction: [
"https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba/tieba_agree.png",
"https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba/tieba_look_down.png",
"https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba/tieba_sunglasses.png",
"https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba/tieba_pick_nose.png",
"https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba/tieba_awkward.png",
"https://registry.npmmirror.com/@waline/emojis/1.3.0/files/tieba/tieba_sleep.png",
],
imageUploader: async (file: any) => { imageUploader: async (file: any) => {
const body = new FormData(); const body = new FormData();
body.append('file', file); body.append('file', file);

View File

@ -6,7 +6,7 @@ import { $GET } from '@/utils/index'
import vhLzImgInit from "@/scripts/vhLazyImg"; import vhLzImgInit from "@/scripts/vhLazyImg";
const FriendsInit = async (data: any) => { const FriendsInit = async (data: any) => {
const friendsDOM = document.querySelector('.vh-container>.vh-tools-main>main.friends-main') const friendsDOM = document.querySelector('.main-inner-content>.vh-tools-main>main.friends-main')
if (!friendsDOM) return; if (!friendsDOM) return;
try { try {
let res = data; let res = data;

View File

@ -0,0 +1,4 @@
import { $POST } from '@/utils/index'
export default async () => {
await $POST('https://vh-api.4ce.cn/api/seoPush', { url: window.location.href.replace(/\/$/, '') }, { 'Content-Type': 'application/json; charset=utf-8' })
}

View File

@ -1,11 +0,0 @@
const linkListArr = ['links', 'friends', 'talking', 'archives', 'message', 'about']
export default () => {
const linkARR = document.querySelectorAll('.vh-link-list>a');
if (!linkARR.length) return;
linkARR.forEach((i: any) => {
i.classList.remove('active');
const linkName = (window.location.pathname).split('/')[1]
if (!linkListArr.includes(linkName)) return;
document.querySelectorAll(`.${linkName}`).forEach((i: any) => i.classList.add('active'));
})
}

View File

@ -1,4 +1,6 @@
import { inRouter, outRouter } from "@/utils/updateRouter"; import { inRouter, outRouter } from "@/utils/updateRouter";
// Banner 打字效果
import TypeWriteInit from "@/scripts/TypeWrite";
// 初始化文章代码块 // 初始化文章代码块
import codeInit from "@/scripts/Code"; import codeInit from "@/scripts/Code";
// 初始化视频播放器 // 初始化视频播放器
@ -15,8 +17,6 @@ import { searchFn, vhSearchInit } from "@/scripts/Search";
import vhLzImgInit from "@/scripts/vhLazyImg"; import vhLzImgInit from "@/scripts/vhLazyImg";
// 图片灯箱 // 图片灯箱
import ViewImage from "@/scripts/ViewImage"; import ViewImage from "@/scripts/ViewImage";
// 顶部导航 Current 状态
import initLinkCurrent from "@/scripts/Header";
// 底部网站运行时间 // 底部网站运行时间
import initWebSiteTime from "@/scripts/Footer"; import initWebSiteTime from "@/scripts/Footer";
// 友情链接初始化 // 友情链接初始化
@ -33,6 +33,8 @@ import initMobileSidebar from "@/scripts/MobileSidebar";
import GoogleAdInit from "@/scripts/GoogleAd"; import GoogleAdInit from "@/scripts/GoogleAd";
// Han Analytics 统计 // Han Analytics 统计
import HanAnalyticsInit from "@/scripts/HanAnalytics"; import HanAnalyticsInit from "@/scripts/HanAnalytics";
// 谷歌 SEO 推送
import GoogleSEOInit from "@/scripts/GoogleSeoPush";
// SmoothScroll 滚动优化 // SmoothScroll 滚动优化
import SmoothScroll from "@/scripts/Smoothscroll"; import SmoothScroll from "@/scripts/Smoothscroll";
@ -43,28 +45,26 @@ const videoList: any[] = [];
const MusicList: any[] = []; const MusicList: any[] = [];
let commentLIst: any = { walineInit: null }; let commentLIst: any = { walineInit: null };
const indexInit = async (only: boolean = true) => { const indexInit = async (only: boolean = true) => {
// 预加载搜索数据 // 打字效果
only && searchFn(""); only && TypeWriteInit();
// 初始化搜索功能
only && vhSearchInit();
// 初始化网站运行时间 // 初始化网站运行时间
only && initWebSiteTime(); only && initWebSiteTime();
// 初始化BackTop组件 // 初始化BackTop组件
only && BackTopInitFn(); only && BackTopInitFn();
// 移动端侧边栏初始化
only && initMobileSidebar();
// SmoothScroll 滚动优化 // SmoothScroll 滚动优化
only && SmoothScroll(); only && SmoothScroll();
// 图片灯箱 // 图片灯箱
only && ViewImage(); only && ViewImage();
// 顶部导航 Current 状态
initLinkCurrent()
// 初始化文章代码块 // 初始化文章代码块
codeInit(); codeInit();
// 文章评论初始化
checkComment() && commentInit(checkComment(), commentLIst)
// 图片懒加载初始化 // 图片懒加载初始化
vhLzImgInit(); vhLzImgInit();
// 初始化 LivePhoto
livePhotoInit();
// 文章视频播放器初始化
videoInit(videoList);
// 文章音乐播放器初始化
musicInit(MusicList);
// 友情链接初始化 // 友情链接初始化
initLinks(); initLinks();
// 朋友圈 RSS 初始化 // 朋友圈 RSS 初始化
@ -73,14 +73,18 @@ const indexInit = async (only: boolean = true) => {
initTalking(); initTalking();
// Google 广告 // Google 广告
GoogleAdInit(); GoogleAdInit();
// 谷歌 SEO 推送
GoogleSEOInit();
// 文章评论初始化
checkComment() && commentInit(checkComment(), commentLIst)
// Han Analytics 统计 // Han Analytics 统计
HanAnalyticsInit(); HanAnalyticsInit();
// 文章视频播放器初始化 // 预加载搜索数据
videoInit(videoList); only && searchFn("");
// 文章音乐播放器初始化 // 初始化搜索功能
musicInit(MusicList); vhSearchInit();
// 初始化 LivePhoto // 移动端侧边栏初始化
livePhotoInit(); initMobileSidebar();
}; };
export default () => { export default () => {

View File

@ -4,7 +4,7 @@ import { $GET } from '@/utils/index'
import vhLzImgInit from "@/scripts/vhLazyImg"; import vhLzImgInit from "@/scripts/vhLazyImg";
// 渲染 // 渲染
const LinksInit = async (data: any) => { const LinksInit = async (data: any) => {
const linksDOM = document.querySelector('.vh-container>.vh-tools-main>main.links-main') const linksDOM = document.querySelector('.main-inner-content>.vh-tools-main>main.links-main')
if (!linksDOM) return; if (!linksDOM) return;
try { try {
let res = data; let res = data;

View File

@ -1,6 +1,6 @@
// 初始化侧边栏 // 初始化侧边栏
export default () => { export default () => {
const menuDOM: any = document.querySelector(".vh-header>.main>.nav-btn>span.menu-btn"); const menuDOM: any = document.querySelector(".vh-header>.main>nav>span.menu-btn");
const mobileSidebarDOM: any = document.querySelector("body>.vh-mobilesidebar"); const mobileSidebarDOM: any = document.querySelector("body>.vh-mobilesidebar");
const addActive = () => setTimeout(() => mobileSidebarDOM.classList.add("active")); const addActive = () => setTimeout(() => mobileSidebarDOM.classList.add("active"));
const removeActive = () => setTimeout(() => mobileSidebarDOM.classList.remove("active")); const removeActive = () => setTimeout(() => mobileSidebarDOM.classList.remove("active"));

View File

@ -44,7 +44,7 @@ const searchInputChange = (v: any) => {
// 初始化搜索框 // 初始化搜索框
const vhSearchInit = () => { const vhSearchInit = () => {
const searchDOM: any = document.querySelector(".vh-header>.main>.nav-btn>span.search-btn"); const searchDOM: any = document.querySelector(".vh-header>.main>nav>span.search-btn");
const searchMainDOM: any = document.querySelector(".vh-header>.main>.vh-search>main"); const searchMainDOM: any = document.querySelector(".vh-header>.main>.vh-search>main");
const searchListDOM: any = document.querySelector(".vh-header>.main>.vh-search"); const searchListDOM: any = document.querySelector(".vh-header>.main>.vh-search");
const addActive = () => setTimeout(() => { const addActive = () => setTimeout(() => {

View File

@ -6,7 +6,7 @@ import { $GET } from '@/utils/index'
import vhLzImgInit from "@/scripts/vhLazyImg"; import vhLzImgInit from "@/scripts/vhLazyImg";
const TalkingInit = async (data: any) => { const TalkingInit = async (data: any) => {
const talkingDOM = document.querySelector('.vh-container>.vh-tools-main>main.talking-main') const talkingDOM = document.querySelector('.main-inner-content>.vh-tools-main>main.talking-main')
if (!talkingDOM) return; if (!talkingDOM) return;
try { try {
let res = data; let res = data;

38
src/scripts/TypeWrite.ts Normal file
View File

@ -0,0 +1,38 @@
import SITE_INFO from '@/config';
export default () => {
const writeDom = document.querySelector('.header-main>.desc');
if (!writeDom) return;
const TypeWriteList = SITE_INFO.TypeWriteList;
let TypeWriteListIndex = 0;
let index = 0;
let isDeleting = false;
// 主动画函数
const run = () => {
writeDom.innerHTML = TypeWriteList[TypeWriteListIndex].substring(0, index);
// 正常打字阶段
if (!isDeleting) {
if (index < TypeWriteList[TypeWriteListIndex].length) {
index++;
setTimeout(run, 188); // 打字速度
} else {
// 完整展示后开始删除
setTimeout(() => {
isDeleting = true;
run();
}, 2888);
}
} else {
if (index > 0) {
index--;
setTimeout(run, 88); // 删除速度(比打字快)
} else {
isDeleting = false;
TypeWriteListIndex++;
TypeWriteListIndex = TypeWriteListIndex % TypeWriteList.length;
setTimeout(run, 500);
}
}
}
// 启动动画
run();
}

View File

@ -4,7 +4,7 @@ import { LoadScript } from "@/utils/index";
declare const ViewImage: any; declare const ViewImage: any;
const ViewImgList: string[] = [ const ViewImgList: string[] = [
// 文章内图片 // 文章内图片
".vh-container>article.vh-article-main img.vh-article-img", "article.vh-article-main img.vh-article-img",
// 动态页面图片 // 动态页面图片
"main.talking-main>article>.main img", "main.talking-main>article>.main img",
// Twikoo 评论区图片 // Twikoo 评论区图片

View File

@ -4,7 +4,7 @@ import LazyLoad from "vanilla-lazyload";
// 初始化图片懒加载 // 初始化图片懒加载
let lazyLoadStatus: any = null; let lazyLoadStatus: any = null;
export default () => { export default () => {
document.querySelectorAll("main>.vh-container img:not(.view-image-container)").forEach((i: any) => { document.querySelectorAll(".main-inner>.main-inner-content img:not(.view-image-container)").forEach((i: any) => {
// 是否包含data-vh-lz-src // 是否包含data-vh-lz-src
if (!i.hasAttribute("data-vh-lz-src")) { if (!i.hasAttribute("data-vh-lz-src")) {
i.setAttribute("data-vh-lz-src", i.getAttribute("src")); i.setAttribute("data-vh-lz-src", i.getAttribute("src"));

View File

@ -4,11 +4,12 @@
&>main { &>main {
box-sizing: border-box; box-sizing: border-box;
padding: 1rem; padding: 1rem;
border-radius: 0.5rem;
background-color: #fff;
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
width: 100%; width: 100%;
height: max-content;
min-height: 5.5rem; min-height: 5.5rem;
border-radius: 0.5rem;
background-color: var(--vh-white-color);
box-shadow: var(--vh-box-shadow);
overflow: hidden; overflow: hidden;
&>h3 { &>h3 {
@ -16,7 +17,7 @@
padding: 0.88rem 0; padding: 0.88rem 0;
width: 100%; width: 100%;
height: max-content; height: max-content;
font-size: var(--vh-size-h1); font-size: 1.125rem;
} }
&>.language-tool { &>.language-tool {
@ -34,7 +35,7 @@
height: 2rem; height: 2rem;
line-height: 1; line-height: 1;
overflow: hidden; overflow: hidden;
transition: transform 0.16s ease-in-out; transition: transform 0.18s ease-in-out;
&>img { &>img {
height: calc(100% - 1px); height: calc(100% - 1px);

View File

@ -1,176 +1,243 @@
section.vh-container { article.vh-article-main {
&>article.vh-article-main { position: relative;
flex: 1; box-sizing: border-box;
min-width: 0; display: flex;
flex-direction: column;
width: 100%;
height: max-content;
&>header { &>header {
box-sizing: border-box; box-sizing: border-box;
padding: 2rem 1rem 1rem; padding: 2rem 1rem 1rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%;
height: max-content;
background-color: var(--vh-white-color);
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
box-shadow: var(--vh-box-shadow);
overflow: hidden;
&>h1 {
width: 100%; width: 100%;
height: max-content; font-weight: 700;
background-color: #fff; }
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
box-shadow: 0 -3px 8px 6px rgba(7, 17, 27, 0.05);
overflow: hidden;
&>h1 { &>.article-meta {
width: 100%; display: flex;
font-weight: 700; align-items: center;
} gap: 0.88rem;
font-size: 0.85rem;
&>.article-meta { &>.article-meta-item {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.88rem; gap: 0.18rem;
font-size: 0.85rem; width: max-content;
&>.article-meta-item { &>svg {
display: flex; flex-shrink: 0;
align-items: center; height: 0.888rem;
gap: 0.18rem; width: auto;
width: max-content; }
&>svg { &>time {
flex-shrink: 0; color: var(--vh-font-66);
height: 0.888rem; }
width: auto;
}
&>time { &>span {
color: var(--vh-black-66); &.count {
} padding-left: 0.38rem;
color: #3FA67F;
&>span { strong {
&.count {
padding-left: 0.38rem;
color: #3FA67F; color: #3FA67F;
strong {
color: #3FA67F;
}
} }
}
&.time { &.time {
color: #E9B740;
strong {
color: #E9B740; color: #E9B740;
strong {
color: #E9B740;
}
} }
} }
} }
} }
} }
}
&>main { &>main {
box-sizing: border-box;
padding: 1rem;
display: flex;
flex-direction: column;
width: 100%;
height: max-content;
background-color: var(--vh-white-color);
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
box-shadow: 0 12px 8px 6px #07111b0d;
overflow: hidden;
.aplayer-list {
max-height: max-content !important;
&>ol {
max-height: 566px !important;
}
}
.dplayer-controller {
span {
color: var(--vh-white-color);
}
}
&>.tag-list {
margin-top: 2rem;
position: relative;
box-sizing: border-box; box-sizing: border-box;
padding: 1rem; padding: 1rem 0;
display: flex; display: flex;
flex-direction: column; flex-wrap: wrap;
gap: 0.58rem;
width: 100%; width: 100%;
height: max-content;
background-color: #fff;
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
box-shadow: 0 12px 8px 6px rgba(7, 17, 27, 0.05);
overflow: hidden;
.aplayer-list { &>a {
max-height: max-content !important; position: relative;
&>ol {
max-height: 566px !important;
}
}
.dplayer-controller {
span {
color: #fff;
}
}
&>.tag-list {
box-sizing: border-box; box-sizing: border-box;
padding-top: 2rem; padding: 0 0.3125rem;
display: flex; display: flex;
flex-wrap: wrap; align-items: center;
gap: 0.58rem; gap: 0.28rem;
width: 100%; width: max-content;
height: 1.5rem;
color: var(--vh-info);
border-radius: 0.28rem;
font-size: 0.76rem;
transition: color 0.288s ease-in-out;
overflow: hidden;
z-index: 1;
&>a { &:hover {
position: relative; color: var(--vh-main-color) !important;
box-sizing: border-box;
padding: 0.28rem 0.68rem;
padding-left: 2rem;
display: flex;
align-items: center;
gap: 0.18rem;
height: 1.68rem;
width: max-content;
font-size: var(--vh-size-span);
border-radius: 1rem;
background-color: var(--vh-main-color-56);
transition: background 0.16s ease-in-out, transform 0.16s ease-in-out;
&:hover {
background-color: var(--vh-main-color-88);
transform: translateY(-0.18rem);
}
&::before { &::before {
position: absolute; width: 100%;
left: 3px; left: 0;
top: 50%; right: auto;
transform: translateY(-50%);
content: '';
width: 1.38rem;
height: 1.38rem;
background: #fff url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20d%3D%22M345%2039.1L472.8%20168.4c52.4%2053%2052.4%20138.2%200%20191.2L360.8%20472.9c-9.3%209.4-24.5%209.5-33.9%20.2s-9.5-24.5-.2-33.9L438.6%20325.9c33.9-34.3%2033.9-89.4%200-123.7L310.9%2072.9c-9.3-9.4-9.2-24.6%20.2-33.9s24.6-9.2%2033.9%20.2zM0%20229.5L0%2080C0%2053.5%2021.5%2032%2048%2032l149.5%200c17%200%2033.3%206.7%2045.3%2018.7l168%20168c25%2025%2025%2065.5%200%2090.5L277.3%20442.7c-25%2025-65.5%2025-90.5%200l-168-168C6.7%20262.7%200%20246.5%200%20229.5zM144%20144a32%2032%200%201%200%20-64%200%2032%2032%200%201%200%2064%200z%22%2F%3E%3C%2Fsvg%3E') no-repeat center center;
background-size: 0.88rem;
border-radius: 1rem;
overflow: hidden;
} }
&::after {
width: 0;
right: 0;
left: auto;
}
}
&::before,
&::after {
content: '';
position: absolute;
left: auto;
right: 0;
top: 0;
width: 0;
height: 100%;
z-index: 1;
transition: width 0.288s ease-in-out;
background-color: var(--vh-main-color-16);
}
&::after {
width: 100%;
left: 0;
right: auto;
z-index: -1;
}
&:nth-of-type(2n+1) {
color: var(--vh-info);
&::after {
background-color: var(--vh-info-hover);
}
}
&:nth-of-type(2n+2) {
color: var(--vh-success);
&::after {
background-color: var(--vh-success-hover);
}
}
&:nth-of-type(2n+3) {
color: var(--vh-warning);
&::after {
background-color: var(--vh-warning-hover);
}
}
&:nth-of-type(2n+4) {
color: var(--vh-error);
&::after {
background-color: var(--vh-error-hover);
}
}
&:nth-of-type(2n+5) {
color: var(--vh-import);
&::after {
background-color: var(--vh-import-hover);
}
}
&>svg {
height: 0.8rem;
width: auto;
object-fit: contain;
transform: rotate(90deg);
} }
} }
} }
}
&>footer { &>footer {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
height: max-content; height: max-content;
}
} }
} }
@media screen and (max-width: 999px) { @media screen and (max-width: 999px) {
section.vh-container { article.vh-article-main {
&>article.vh-article-main { &>header {
&>header { &>h1 {
&>h1 {
font-size: 1.36rem;
}
}
h1 {
font-size: 1.36rem; font-size: 1.36rem;
} }
}
h2 { h1 {
font-size: 1.26rem; font-size: 1.36rem;
} }
h3 { h2 {
font-size: var(--vh-size-h1); font-size: 1.26rem;
} }
h3 {
font-size: 1.125rem;
}
.vh-node { .vh-node {
&.vh-picture { &.vh-picture {
grid-template-columns: repeat(auto-fit, minmax(48%, 1fr)); grid-template-columns: repeat(auto-fit, minmax(48%, 1fr));
}
} }
} }
} }

View File

@ -1,4 +1,4 @@
.vh-container { .main-inner {
&>section, &>section,
&>article { &>article {
@ -12,7 +12,7 @@
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
margin: 1.666rem 0 0.36rem; margin: 1.666rem 0 0.36rem;
font-size: var(--vh-size-p); font-size: 1rem;
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;
word-break: break-all; word-break: break-all;
@ -26,8 +26,8 @@
&::before { &::before {
padding-right: 0.56rem; padding-right: 0.56rem;
content: "#"; content: "#";
color: var(--vh-black-38); color: var(--vh-font-28);
transition: color 0.16s ease-in-out; transition: color 0.18s ease-in-out;
} }
} }
@ -54,7 +54,7 @@
} }
h4 { h4 {
font-size: var(--vh-size-h1); font-size: 1.125rem;
} }
// p标签样式 // p标签样式
@ -68,25 +68,25 @@
line-height: 1.6; line-height: 1.6;
li { li {
color: var(--vh-black-66); color: var(--vh-font-66);
font-size: var(--vh-size-span); font-size: 0.875rem;
line-height: 1.6; line-height: 1.6;
} }
// 其下面的 a 标签样式 // 其下面的 a 标签样式
a { a {
color: var(--vh-black-56); color: var(--vh-font-56);
box-shadow: inset 0 -.12rem #60a5fa; box-shadow: inset 0 -.12rem var(--vh-main-color);
transition: box-shadow .2s ease-in-out, color .2s ease-in-out; transition: box-shadow .2s ease-in-out, color .2s ease-in-out;
&:hover { &:hover {
box-shadow: inset 0 -1.5rem #60a5fa66; box-shadow: inset 0 -1.5rem var(--vh-main-color-28);
} }
} }
// 其下面的code标签样式 // 其下面的code标签样式
code { code {
background-color: var(--vh-black-16); background-color: var(--vh-font-16);
padding: .125rem .375rem; padding: .125rem .375rem;
font-size: 0.8125rem; font-size: 0.8125rem;
} }
@ -109,7 +109,7 @@
border-radius: 0.618rem; border-radius: 0.618rem;
&>p { &>p {
font-size: var(--vh-size-span); font-size: 0.875rem;
font-weight: 500; font-weight: 500;
line-height: 1.58rem; line-height: 1.58rem;
color: #6A737D; color: #6A737D;
@ -124,14 +124,14 @@
// border-collapse: collapse; // border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
font-size: 0.9rem; font-size: 0.9rem;
background-color: #fff; background-color: var(--vh-white-color);
border: 1px solid #EEEEEE; border: 1px solid #EEEEEE;
border-radius: 0.38rem; border-radius: 0.38rem;
overflow: hidden; overflow: hidden;
a { a {
color: #49B1F5; color: #49B1F5;
transition: all .16s; transition: all .18s;
&:hover { &:hover {
color: #1b99ee; color: #1b99ee;
@ -165,7 +165,7 @@
} }
tr { tr {
transition: background-color 0.16s ease-in-out; transition: background-color 0.18s ease-in-out;
&:nth-last-of-type(1) { &:nth-last-of-type(1) {
td { td {
@ -180,7 +180,7 @@
// 其下面的code标签样式 // 其下面的code标签样式
code { code {
background-color: var(--vh-black-16); background-color: var(--vh-font-16);
padding: .125rem .375rem; padding: .125rem .375rem;
font-size: 0.8125rem; font-size: 0.8125rem;
} }
@ -242,8 +242,9 @@
} }
p { p {
font-size: var(--vh-size-span); padding: 0.38rem 0;
line-height: 2; font-size: 0.875rem;
line-height: 1.388rem;
font-weight: 500; font-weight: 500;
} }
} }
@ -261,7 +262,7 @@
height: 2.28rem; height: 2.28rem;
border: solid 1px #333; border: solid 1px #333;
border-radius: 0.28rem; border-radius: 0.28rem;
background-color: #fff; background-color: var(--vh-white-color);
cursor: pointer; cursor: pointer;
transition: background-color 0.18s ease-in-out; transition: background-color 0.18s ease-in-out;
z-index: 1; z-index: 1;
@ -270,31 +271,31 @@
&:hover { &:hover {
&::before { &::before {
height: 100%; left: 0;
width: 100%;
} }
} }
&::after { &::after {
flex-shrink: 0; flex-shrink: 0;
content: ''; content: '';
background-color: #000; background-color: #000;
mask: url('data:image/svg+xml,%3Csvg%20%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20%20width%3D%22100%25%22%20%20height%3D%22100%25%22%20%20viewBox%3D%220%200%2024%2024%22%20%20fill%3D%22none%22%20%20stroke%3D%22currentColor%22%20%20stroke-width%3D%222%22%20%20stroke-linecap%3D%22round%22%20%20stroke-linejoin%3D%22round%22%20%20class%3D%22icon%20icon-tabler%20icons-tabler-outline%20icon-tabler-unlink%22%3E%3Cpath%20stroke%3D%22none%22%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3Cpath%20d%3D%22M17%2022v-2%22%20%2F%3E%3Cpath%20d%3D%22M9%2015l6%20-6%22%20%2F%3E%3Cpath%20d%3D%22M11%206l.463%20-.536a5%205%200%200%201%207.071%207.072l-.534%20.464%22%20%2F%3E%3Cpath%20d%3D%22M13%2018l-.397%20.534a5.068%205.068%200%200%201%20-7.127%200a4.972%204.972%200%200%201%200%20-7.071l.524%20-.463%22%20%2F%3E%3Cpath%20d%3D%22M20%2017h2%22%20%2F%3E%3Cpath%20d%3D%22M2%207h2%22%20%2F%3E%3Cpath%20d%3D%22M7%202v2%22%20%2F%3E%3C%2Fsvg%3E') no-repeat center center; mask: url('data:image/svg+xml,%3Csvg%20%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20%20width%3D%22100%25%22%20%20height%3D%22100%25%22%20%20viewBox%3D%220%200%2024%2024%22%20%20fill%3D%22none%22%20%20stroke%3D%22currentColor%22%20%20stroke-width%3D%222%22%20%20stroke-linecap%3D%22round%22%20%20stroke-linejoin%3D%22round%22%3E%3Cpath%20stroke%3D%22none%22%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3Cpath%20d%3D%22M17%2022v-2%22%20%2F%3E%3Cpath%20d%3D%22M9%2015l6%20-6%22%20%2F%3E%3Cpath%20d%3D%22M11%206l.463%20-.536a5%205%200%200%201%207.071%207.072l-.534%20.464%22%20%2F%3E%3Cpath%20d%3D%22M13%2018l-.397%20.534a5.068%205.068%200%200%201%20-7.127%200a4.972%204.972%200%200%201%200%20-7.071l.524%20-.463%22%20%2F%3E%3Cpath%20d%3D%22M20%2017h2%22%20%2F%3E%3Cpath%20d%3D%22M2%207h2%22%20%2F%3E%3Cpath%20d%3D%22M7%202v2%22%20%2F%3E%3C%2Fsvg%3E') no-repeat center center;
background-size: contain; background-size: contain;
width: 1.18rem; width: 1.18rem;
height:1.18rem; height: 1.18rem;
overflow: hidden; overflow: hidden;
} }
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
left: 0; right: 0;
bottom: 0; top: 0;
width: 100%; width: 0;
height: 0; height: 100%;
background-color: var(--vh-main-color); background-color: var(--vh-font-6);
transition: height 0.16s ease-in-out; transition: width 0.18s ease-in-out;
z-index: -1; z-index: -1;
} }
@ -302,7 +303,7 @@
box-sizing: border-box; box-sizing: border-box;
color: #000; color: #000;
font-weight: 600; font-weight: 600;
font-size: var(--vh-size-span); font-size: 0.875rem;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
@ -316,7 +317,7 @@
color: var(--vh-success); color: var(--vh-success);
} }
&::before{ &::before {
background-color: var(--vh-success-hover); background-color: var(--vh-success-hover);
} }
@ -332,7 +333,7 @@
color: var(--vh-info); color: var(--vh-info);
} }
&::before{ &::before {
background-color: var(--vh-info-hover); background-color: var(--vh-info-hover);
} }
@ -348,7 +349,7 @@
color: var(--vh-warning); color: var(--vh-warning);
} }
&::before{ &::before {
background-color: var(--vh-warning-hover); background-color: var(--vh-warning-hover);
} }
@ -364,7 +365,7 @@
color: var(--vh-error); color: var(--vh-error);
} }
&::before{ &::before {
background-color: var(--vh-error-hover); background-color: var(--vh-error-hover);
} }
@ -380,7 +381,7 @@
color: var(--vh-import); color: var(--vh-import);
} }
&::before{ &::before {
background-color: var(--vh-import-hover); background-color: var(--vh-import-hover);
} }
@ -464,7 +465,7 @@
justify-content: center; justify-content: center;
width: 100%; width: 100%;
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='8' height='8' fill='none' stroke='rgb(0 0 0 / 0.1)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e"); background: var(--vh-white-color) url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='8' height='8' fill='none' stroke='rgb(0 0 0 / 0.1)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e");
&.vhLivePhoto-y { &.vhLivePhoto-y {
aspect-ratio: 9 / 16; aspect-ratio: 9 / 16;
@ -524,7 +525,7 @@
overflow: hidden; overflow: hidden;
cursor: pointer; cursor: pointer;
opacity: 0.66; opacity: 0.66;
transition: all .16s; transition: all .18s;
&:hover { &:hover {
opacity: 1; opacity: 1;
@ -539,7 +540,7 @@
background: rgba(125, 125, 125, .2) url('data:image/svg+xml,%0A%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%20-960%20960%20960%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M368.37-237.37q-34.48%200-58.74-24.26-24.26-24.26-24.26-58.74v-474.26q0-34.48%2024.26-58.74%2024.26-24.26%2058.74-24.26h378.26q34.48%200%2058.74%2024.26%2024.26%2024.26%2024.26%2058.74v474.26q0%2034.48-24.26%2058.74-24.26%2024.26-58.74%2024.26H368.37Zm0-83h378.26v-474.26H368.37v474.26Zm-155%20238q-34.48%200-58.74-24.26-24.26-24.26-24.26-58.74v-515.76q0-17.45%2011.96-29.48%2011.97-12.02%2029.33-12.02t29.54%2012.02q12.17%2012.03%2012.17%2029.48v515.76h419.76q17.45%200%2029.48%2011.96%2012.02%2011.97%2012.02%2029.33t-12.02%2029.54q-12.03%2012.17-29.48%2012.17H213.37Zm155-238v-474.26%20474.26Z%22%2F%3E%3C%2Fsvg%3E') no-repeat center center; background: rgba(125, 125, 125, .2) url('data:image/svg+xml,%0A%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%20-960%20960%20960%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M368.37-237.37q-34.48%200-58.74-24.26-24.26-24.26-24.26-58.74v-474.26q0-34.48%2024.26-58.74%2024.26-24.26%2058.74-24.26h378.26q34.48%200%2058.74%2024.26%2024.26%2024.26%2024.26%2058.74v474.26q0%2034.48-24.26%2058.74-24.26%2024.26-58.74%2024.26H368.37Zm0-83h378.26v-474.26H368.37v474.26Zm-155%20238q-34.48%200-58.74-24.26-24.26-24.26-24.26-58.74v-515.76q0-17.45%2011.96-29.48%2011.97-12.02%2029.33-12.02t29.54%2012.02q12.17%2012.03%2012.17%2029.48v515.76h419.76q17.45%200%2029.48%2011.96%2012.02%2011.97%2012.02%2029.33t-12.02%2029.54q-12.03%2012.17-29.48%2012.17H213.37Zm155-238v-474.26%20474.26Z%22%2F%3E%3C%2Fsvg%3E') no-repeat center center;
background-size: 1.16rem 1.16rem; background-size: 1.16rem 1.16rem;
opacity: 0; opacity: 0;
transition: opacity 0.16s; transition: opacity 0.18s;
} }
&::after { &::after {
@ -572,7 +573,7 @@
border-radius: 0.618rem; border-radius: 0.618rem;
height: max-content; height: max-content;
max-height: 888px; max-height: 888px;
background-color: var(--vh-white-66) !important; background-color: #F3F4F7 !important;
code { code {
box-sizing: border-box; box-sizing: border-box;
@ -580,10 +581,15 @@
&>span { &>span {
box-sizing: border-box; box-sizing: border-box;
font-size: var(--vh-size-span); font-size: 0.875rem;
line-height: 1.66; line-height: 1.66;
&>span {
text-decoration: none !important;
}
&::before { &::before {
box-sizing: content-box;
counter-increment: line; counter-increment: line;
content: counter(line); content: counter(line);
display: inline-block; display: inline-block;
@ -595,7 +601,6 @@
text-align: center; text-align: center;
user-select: none; user-select: none;
} }
} }
} }
} }

View File

@ -1,34 +1,30 @@
@import url('/assets/font/index.css'); @import url('/assets/font/index.css');
:root { :root {
// 基础色 // 白色颜色
--vh-black-color: #34495e; //文字颜色 --vh-white-color: #fff;
--vh-white-color: #EDEEF3; //背景颜色 // BoxShadow
--vh-black-100: rgb(from var(--vh-black-color) r g b); --vh-box-shadow: 0 3px 8px 6px #07111b0d;
--vh-black-88: rgb(from var(--vh-black-color) r g b / 88%); // Body 背景颜色
--vh-black-66: rgb(from var(--vh-black-color) r g b / 66%); --vh-body-bg: #F8F8F8;
--vh-black-56: rgb(from var(--vh-black-color) r g b / 56%); // Back Top 按钮位置
--vh-black-38: rgb(from var(--vh-black-color) r g b / 38.88%); --vh-back-top: calc((calc(100vw - 2rem) - min((100vw - 2rem), var(--vh-main-max-width))) / 2);
--vh-black-28: rgb(from var(--vh-black-color) r g b / 28%); // Main Header 封面高度
--vh-black-16: rgb(from var(--vh-black-color) r g b / 16%); --vh-main-header-height: 38.88rem;
--vh-black-6: rgb(from var(--vh-black-color) r g b / 6%); // 字体颜色
--vh-white-100: rgb(from var(--vh-white-color) r g b); --vh-font-88: rgb(from var(--vh-font-color) r g b / 88%);
--vh-white-88: rgb(from var(--vh-white-color) r g b / 88%); --vh-font-66: rgb(from var(--vh-font-color) r g b / 66%);
--vh-white-66: rgb(from var(--vh-white-color) r g b / 66%); --vh-font-56: rgb(from var(--vh-font-color) r g b / 56%);
--vh-white-38: rgb(from var(--vh-white-color) r g b / 38.88%); --vh-font-28: rgb(from var(--vh-font-color) r g b / 28%);
--vh-white-28: rgb(from var(--vh-white-color) r g b / 28%); --vh-font-16: rgb(from var(--vh-font-color) r g b / 16%);
--vh-white-16: rgb(from var(--vh-white-color) r g b / 16%); --vh-font-6: rgb(from var(--vh-font-color) r g b / 6%);
--vh-white-6: rgb(from var(--vh-white-color) r g b / 6%);
// 主题色 // 主题色
--vh-main-color: #EDEEF3;
--vh-main-color-88: rgb(from var(--vh-main-color) r g b / 88%); --vh-main-color-88: rgb(from var(--vh-main-color) r g b / 88%);
--vh-main-color-66: rgb(from var(--vh-main-color) r g b / 66%); --vh-main-color-66: rgb(from var(--vh-main-color) r g b / 66%);
--vh-main-color-56: rgb(from var(--vh-main-color) r g b / 56%); --vh-main-color-56: rgb(from var(--vh-main-color) r g b / 56%);
--vh-main-color-38: rgb(from var(--vh-main-color) r g b / 38.88%);
--vh-main-color-28: rgb(from var(--vh-main-color) r g b / 28%); --vh-main-color-28: rgb(from var(--vh-main-color) r g b / 28%);
--vh-main-color-16: rgb(from var(--vh-main-color) r g b / 16%); --vh-main-color-16: rgb(from var(--vh-main-color) r g b / 16%);
--vh-main-color-6: rgb(from var(--vh-main-color) r g b / 6%); --vh-main-color-6: rgb(from var(--vh-main-color) r g b / 6%);
// Info // Info
--vh-info: #3253b4; --vh-info: #3253b4;
--vh-info-hover: #3253b418; --vh-info-hover: #3253b418;
@ -44,67 +40,9 @@
// Import // Import
--vh-import: #B984DF; --vh-import: #B984DF;
--vh-import-hover: #B984DF18; --vh-import-hover: #B984DF18;
// 尺寸
--vh-size-h1: 1.125rem;
--vh-size-h2: 0.88rem;
--vh-size-h3: 0.8rem;
--vh-size-p: 1rem;
--vh-size-span: 0.875rem;
--vh-size-small: 0.8625rem;
--vh-size-mini: 0.805rem;
--vh-padding-top: calc(66px + 1rem);
--vh-main-max-width: 1388px;
--vh-back-top: calc((calc(100vw - 2rem) - min((100vw - 2rem), var(--vh-main-max-width))) / 2 + 1rem);
}
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote {
margin: 0;
padding: 0;
text-decoration: none;
}
span {
text-decoration: none !important;
}
p {
line-height: 2;
}
a {
margin: 0;
padding: 0;
text-decoration: none;
line-height: 1.6;
}
pre,
code {
margin: 0;
padding: 0;
font-family: 'SF Mono' !important;
font-weight: normal;
}
img {
max-width: 100%;
max-height: 100%;
overflow: hidden;
} }
* { * {
color: var(--vh-black-100);
// IOS 点击阴影 // IOS 点击阴影
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
// 隐藏滚动条 // 隐藏滚动条
@ -112,69 +50,127 @@ img {
-ms-overflow-style: none; -ms-overflow-style: none;
// 平滑滚动 // 平滑滚动
scroll-behavior: smooth; scroll-behavior: smooth;
// 去除下划线
text-decoration: none;
// 消除边框 // 消除边框
outline: none; // 隐藏滚动条 outline: none;
// 隐藏滚动条
::-webkit-scrollbar { ::-webkit-scrollbar {
display: none; display: none;
} }
} }
// 设置文本选中颜色
::selection,
::-webkit-selection {
color: #fff;
background: var(--vh-main-color-88);
}
html { html {
word-wrap: break-word; word-wrap: break-word;
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 16px;
font-weight: 400;
&>body { &>body {
position: relative; position: relative;
margin: 0;
box-sizing: border-box; box-sizing: border-box;
padding: var(--vh-padding-top) 0.5rem 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
width: 100vw; width: 100vw;
height: max-content; height: max-content;
color: var(--vh-font-color);
font-family: 'HarmonyOS Sans SC', serif; font-family: 'HarmonyOS Sans SC', serif;
font-weight: 400; font-weight: 400;
cursor: url(/assets/images/default.cur), default; cursor: url('/assets/images/default.cur'), default;
overflow-x: hidden; overflow-x: hidden;
&::before {
content: "";
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='8' height='8' fill='none' stroke='rgb(0 0 0 / 0.1)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e");
z-index: -1;
}
&>footer {
box-sizing: border-box;
width: 100%;
height: max-content;
}
}
}
pre,
code {
font-family: 'SF Mono' !important;
}
a {
color: var(--vh-font-color);
}
img[data-vh-lz-src] {
transition: all 0.18s ease-in;
&:not(.loaded) {
filter: blur(0.88rem) brightness(1);
}
}
// ===================================================================== Other
// 悬浮背景 a 标签
.vh-hover {
position: relative;
transition: all 0.18s ease-in-out;
&:hover,
&.active {
color: var(--vh-white-color) !important;
&::before {
transform: scale(1.2);
opacity: 1;
}
} }
// 其他页面Header 封装 &::before {
header.vh-page-header { content: "";
box-sizing: border-box; position: absolute;
padding: 1rem; left: 0;
top: 0;
width: 100%; width: 100%;
height: max-content; height: 100%;
border-radius: 0.5rem; border-radius: .5rem;
background-color: #fff; background-color: var(--vh-main-color-88);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); opacity: 0;
overflow: hidden; z-index: -1;
transition: all 0.18s ease-in-out;
&>h1 {
padding: 0;
font-size: 1.5rem;
}
&>p {
padding: 0;
font-size: var(--vh-size-p);
line-height: 2;
}
} }
} }
// 设置图片懒加载样式 // 超出一行省略
main>.vh-container { .vh-ellipsis {
img[data-vh-lz-src] { text-overflow: ellipsis;
transition: all 0.18s ease-in; white-space: nowrap;
overflow: hidden;
&:not(.loaded) {
filter: blur(0.88rem) brightness(1);
}
}
} }
// 超出两行省略
.vh-ellipsis-2 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
// 手机端 禁止选择 // 手机端 禁止选择
user-select: none; user-select: none;
@ -183,12 +179,24 @@ main>.vh-container {
-ms-user-select: none; -ms-user-select: none;
} }
// 设置图片懒加载样式
.main-inner>.main-inner-content,
.avatar {
img[data-vh-lz-src] {
transition: all 0.18s ease-in;
&:not(.loaded) {
filter: blur(0.88rem) brightness(1);
}
}
}
// 首次加载效果 // 首次加载效果
.vh-animation.vh-animation-init { .vh-animation.vh-animation-init {
opacity: 0; opacity: 0;
animation: 300ms vh-init-show; animation: 300ms vh-init-show;
animation-fill-mode: forwards; animation-fill-mode: forwards;
transition: opacity 0.16s ease-in-out, transform 0.16s ease-in-out; transition: opacity 0.18s ease-in-out, transform 0.18s ease-in-out;
} }
// swup 动画效果 // swup 动画效果
@ -250,7 +258,6 @@ html.is-animating {
} }
// 谷歌广告模块 // 谷歌广告模块
.vh-ad { .vh-ad {
position: relative; position: relative;
display: block; display: block;
@ -265,8 +272,8 @@ html.is-animating {
box-sizing: border-box; box-sizing: border-box;
padding: 0.75rem; padding: 0.75rem;
border-radius: 0.5rem; border-radius: 0.5rem;
background-color: #fff; background-color: var(--vh-white-color);
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05); box-shadow: var(--vh-box-shadow);
overflow: hidden; overflow: hidden;
&::before { &::before {
@ -330,3 +337,49 @@ html.is-animating {
height: 5px height: 5px
} }
} }
// 动画效果
@keyframes talking-tag-active {
0% {
transform: translateX(0);
}
25% {
transform: translateX(-1.66px);
}
50% {
transform: translateX(1.66px);
}
75% {
transform: translateX(-1.66px);
}
100% {
transform: translateX(0);
}
}
@-webkit-keyframes talking-tag-active {
0% {
transform: translateX(0);
}
25% {
transform: translateX(-1.66px);
}
50% {
transform: translateX(1.66px);
}
75% {
transform: translateX(-1.66px);
}
100% {
transform: translateX(0);
}
}

68
src/styles/Reset.less Normal file
View File

@ -0,0 +1,68 @@
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Remove default margin */
body,
h1,
h2,
h3,
h4,
p,
pre,
code,
figure,
blockquote,
dl,
dd {
margin: 0;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role="list"],
ol[role="list"] {
list-style: none;
}
/* Set core root defaults */
html:focus-within {
scroll-behavior: smooth;
}
/* Set core body defaults */
body {
min-height: 100vh;
line-height: 1.5;
}
/* A elements that don't have a class get default styles */
a:not([class]) {
text-decoration-skip-ink: auto;
}
/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
/* Remove all animations and transitions for people that prefer not to see them */
@media (prefers-reduced-motion: reduce) {
html:focus-within {
scroll-behavior: auto;
}
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

View File

@ -1,6 +1,4 @@
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
// 获取封面图
import getCover from "@/utils/getCover";
const posts = (await getCollection("blog")).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf()); const posts = (await getCollection("blog")).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
// 获取文章分类 // 获取文章分类
const getCategories = () => { const getCategories = () => {
@ -11,21 +9,26 @@ const getCategories = () => {
return Object.entries(categoriesList).map(([title, count]) => ({ title, count })); return Object.entries(categoriesList).map(([title, count]) => ({ title, count }));
} }
// 获取统计数据
const getCountInfo = () => {
return { ArticleCount: posts.length, CategoryCount: getCategories().length, TagCount: getTags().length }
}
// 获取文章标签 // 获取文章标签
const getTags = () => { const getTags = () => {
const frequencyMap = new Map(); const tagList = posts.reduce((acc: any, i: any) => {
// 统计每个元素出现的频率 i.data.tags.forEach((tag: string) => {
posts.forEach(i => { acc[tag] = (acc[tag] || 0) + 1;
i.data.tags.forEach(tag => frequencyMap.set(tag, (frequencyMap.get(tag) || 0) + 1)); });
}); return acc;
const sortedArray = [...frequencyMap.entries()].sort((a, b) => b[1] - a[1]); }, {});
return sortedArray.slice(0, 16).map(item => item[0]); return Object.entries(tagList).sort((a: any, b: any) => b[1] - a[1]);
} }
// 获取推荐文章 (给文章添加 recommend: true 字段) // 获取推荐文章 (给文章添加 recommend: true 字段)
const getRecommendArticles = () => { const getRecommendArticles = () => {
const recommendList = posts.filter(i => i.data.recommend); const recommendList = posts.filter(i => i.data.recommend);
return (recommendList.length ? recommendList : posts.slice(0, 6)).map(async i => ({ title: i.data.title, date: i.data.date, id: i.data.id, cover: await getCover(i.data.cover) })) return (recommendList.length ? recommendList : posts.slice(0, 6)).map(i => ({ title: i.data.title, date: i.data.date, id: i.data.id }))
}; };
export { getCategories, getTags, getRecommendArticles }; export { getCategories, getTags, getRecommendArticles, getCountInfo };