Files
blog-frontend-v2/src/pages/index.astro
passthem d605131bda
All checks were successful
continuous-integration/drone/push Build is passing
添加格式化相关
2026-04-07 03:27:22 +08:00

778 lines
18 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
export const prerender = false
// import BoringLayout from '../layout/BoringLayout.astro'
import FullLayoutV1 from '../layout/FullLayoutV1.astro'
import MainpageButton from '../components/MainpageButton.svelte'
import MainpageComments from '../components/MainpageComments.astro'
import MainpageTypewriter from '../components/MainpageTypewriter.svelte'
import { Image } from 'astro:assets'
import { Icon } from 'astro-icon/components'
import PassthemAvatar from '../assets/mainpage_avatars/passthem.png'
import { mainpageGetClick } from '../lib/apis/legacy/mainpage'
// 无用按钮的数字预注入
let initialClicks = 0
try {
const resp = await mainpageGetClick()
initialClicks = resp.data
} catch (e) {
console.error('在获取点击数量时失败了', e)
}
---
<FullLayoutV1 title="首页 - 小帕的小窝">
<!-- 就像写幻灯片一样的逻辑写它吧! -->
<section class="slide">
<!-- 自我介绍部分 -->
<div class="self-introduction">
<figure class="avatar">
<Image
src={PassthemAvatar}
alt="passthem 的头像,一个戴眼镜的男孩"
loading="lazy"
width={240}
height={240}
densities={[1.5, 2]}
/>
</figure>
<div class="descriptions">
<div class="motto">
<p>passthem¹</p>
<p>一个<MainpageTypewriter client:load />的</p>
<p>个人势创作者</p>
</div>
<div class="buttons">
<MainpageButton initialClicks={initialClicks} client:load />
</div>
</div>
</div>
<div class="notation">
<p>¹我在各个平台的惯用 ID开头字母大小写无所谓</p>
<p>
²头像由 <a href="https://space.bilibili.com/2017869">Yscao@bilibili</a> 绘制
</p>
<p>
³有人说这个配色像 <a
href="https://www.bilibili.com/video/av383664698/"
class="thsx">涂黑书信</a
>
</p>
<p class="animation-error-warning">
⁴你的系统设置中似乎禁用了动画效果,而 Firefox
在禁用动画效果时,网页的表现会很奇怪
</p>
</div>
</section>
<section class="slide">
<div class="slide-title-design1" aria-hidden="true">
<svg width="800" height="240" viewBox="0 0 800 240">
<text x="10" y="220" class="stroke-layer">留言</text>
<text x="0" y="210" class="main-layer">留言</text>
</svg>
</div>
<div class="slide-title-design2" aria-hidden="true">
<Icon name="mdi:comment-quote" />
</div>
<div class="comment-page-container">
<h1>来自大家的留言</h1>
<div class="comment-container">
<MainpageComments />
</div>
</div>
</section>
<section class="slide">
<div class="slide-title-design1" aria-hidden="true">
<svg width="800" height="240" viewBox="0 0 800 240">
<text x="10" y="220" class="stroke-layer">联络</text>
<text x="0" y="210" class="main-layer">联络</text>
</svg>
</div>
<div class="slide-title-design2" aria-hidden="true">
<Icon name="mdi:email" />
</div>
<div class="contact-container">
<h1>
<div class="text">联系我<div class="animation-before"></div></div><div
class="animation"
>
</div>
</h1>
<table>
<tbody>
<tr>
<th>Github</th>
<th><a href="https://github.com/passthem-desu">passthem-desu</a></th
>
</tr>
<tr>
<th>Wakatime</th>
<th><a href="https://wakatime.com/@passthem">@passthem</a></th>
</tr>
<tr>
<th>Youtube</th>
<th
><a href="https://www.youtube.com/@Passthem183">@Passthem183</a
></th
>
</tr>
<tr>
<th>OtoSite</th>
<th><a href="https://otomad.site/@passthem">@passthem</a></th>
</tr>
<tr>
<th>Email</th>
<th
><a href="mailto:passthem183@gmail.com">passthem183@gmail.com</a
></th
>
</tr>
<tr>
<th>Bilibili</th>
<th><a href="https://space.bilibili.com/92852604">passthem</a></th>
</tr>
</tbody>
</table>
</div>
</section>
<section class="slide">
<div class="slide-title-design1" aria-hidden="true">
<svg width="800" height="240" viewBox="0 0 800 240">
<text x="10" y="220" class="stroke-layer">友链</text>
<text x="0" y="210" class="main-layer">友链</text>
</svg>
</div>
<div class="slide-title-design2" aria-hidden="true">
<Icon name="mdi:link-variant" />
</div>
<h1>友情链接</h1>
<div class="friends">
{
[
[
'https://omega98.top/images/blog_avatar.jpg',
'https://omega98.top',
'核子的博客',
],
['https://www.tnot.top/logo.png', 'https://tnot.top', 'TNOT 的博客'],
[
'https://ruusuge.top/img/logo_hu_cc283ac364b1bc0b.png',
'https://ruusuge.top',
'ルース毛的博客',
],
[
'https://cdn.jsdelivr.net/gh/TransparentLC/transparentlc.github.io/img/avatar.jpg',
'https://akarin.dev',
'存在感消失的地方',
],
[
'https://wzq02.top/assets/icons/favicon-96x96.png',
'https://wzq02.top',
'wzq02 的博客',
],
[
'https://pics.r1kka.one/file/1738764637932_-305500c1acccdf39.jpg',
'https://r1kka.one/',
"Rikka's Blog",
],
[
'https://shimizukaede.top/vite.svg',
'https://shimizukaede.top',
'Kaede 的博客',
],
[
'https://nonerd.tech/assets/apple-touch-icon.png',
'https://nonerd.tech/',
'废柴铁克诺',
],
[
'https://legacy.passthem.top/assets/ydt-DIeb2Djx.png',
'https://qm.qq.com/q/nDnHUy9KQo',
'有顶天变电站 (QQ)',
],
[
'https://legacy.passthem.top/assets/lfxdxy-BogfTZvz.png',
'https://qm.qq.com/q/QOpCVZcvyS',
'六方相的新月 (QQ)',
],
].map((b) => (
<a href={b[1]} class="friend">
<div class="avatar">
<Image
src={b[0]}
width={60}
height={60}
alt={`网站「${b[2]}」的图标`}
/>
</div>
<div class="description">{b[2]}</div>
</a>
))
}
</div>
</section>
</FullLayoutV1>
<script>
const setupObserver = () => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0.5) {
entry.target.classList.add('slide-visible')
} else {
entry.target.classList.remove('slide-visible')
}
})
},
{ threshold: 0.5 },
)
document.querySelectorAll('section.slide').forEach((ele) => {
observer.observe(ele)
;(ele as HTMLElement).addEventListener('focusin', () => {
ele.scrollIntoView({
block: 'start',
})
})
})
}
document.addEventListener('astro:page-load', setupObserver)
</script>
<style>
:global(html) {
scroll-snap-type: y proximity;
scroll-behavior: smooth;
}
.slide {
scroll-snap-align: start;
scroll-snap-stop: always;
height: 100lvh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
isolation: isolate;
&:nth-child(2n) {
background-color: var(--color-bg-1);
}
& > .notation {
position: absolute;
width: 100dvw;
padding-inline-start: 2rem;
padding-block-end: 2rem;
inset-inline-start: 0;
inset-block-end: calc(100lvh - 100dvh);
font-size: smaller;
color: var(--color-fg-0);
opacity: 0.3;
& a {
text-decoration: underline;
&:hover {
background-color: var(--color-fg-0);
color: var(--color-bg-0);
}
}
}
& h1 {
font-size: clamp(2.5rem, 6vw, 3rem);
font-weight: 800;
}
}
.animation-error-warning {
display: none;
}
@media (prefers-reduced-motion: reduce) {
@-moz-document url-prefix() {
.animation-error-warning {
display: block;
}
:global(html) {
scroll-snap-type: none;
scroll-behavior: auto;
}
}
}
@property --avatar-scalar {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
@property --avatar-hover-scalar {
syntax: '<number>';
inherits: true;
initial-value: 0;
}
@property --avatar-rotation {
syntax: '<angle>';
inherits: true;
initial-value: 0deg;
}
/* 自我介绍部分 */
.self-introduction {
display: flex;
flex-direction: column;
text-align: center;
align-items: center;
gap: 2rem;
@media (min-width: 768px) {
flex-direction: row-reverse;
text-align: left;
}
& > .avatar {
margin: 0;
border-radius: 50%;
--final-width: clamp(160px, 30vw, 240px);
--avatar-scalar: 0;
--avatar-hover-scalar: 1;
--avatar-rotation: 20deg;
transition:
--avatar-rotation cubic-bezier(0.2, 1, 0.4, 1) 1.8s,
--avatar-scalar cubic-bezier(0.2, 2, 0.3, 0.8) 1.2s,
--avatar-hover-scalar cubic-bezier(0.2, 3, 0.4, 0.6) 0.6s,
width cubic-bezier(0.4, 1, 0.4, 1) 0.9s;
transform: rotate(var(--avatar-rotation)) scale(var(--avatar-scalar))
scale(var(--avatar-hover-scalar));
aspect-ratio: 1 / 1;
overflow: hidden;
width: 0;
section.slide.slide-visible & {
--avatar-scalar: 1;
--avatar-rotation: 0deg;
width: var(--final-width);
}
&:hover,
&:focus {
--avatar-hover-scalar: 1.05;
}
}
& > .descriptions {
display: flex;
flex-direction: column;
gap: 3rem;
& > .motto {
font-size: clamp(2rem, 4vw, 4rem);
font-weight: 800;
display: grid;
grid-template-rows: repeat(3, 1fr);
align-items: center;
width: 11em;
& > p {
width: max-content;
margin-inline: auto;
@media (min-width: 768px) {
margin-inline: 0;
}
}
}
& > .buttons {
display: flex;
flex-direction: column;
align-items: center;
@media (min-width: 768px) {
flex-direction: row;
}
}
}
}
/* 涂黑书信的特殊处理 */
.thsx {
cursor: pointer;
text-decoration: underline;
}
.motto > p {
position: relative;
overflow: hidden;
&::before {
content: '';
display: block;
background-color: var(--color-fg-0);
width: 100%;
height: 100%;
position: absolute;
z-index: 2;
inset-inline-start: -100%;
}
}
section:has(.thsx:hover) .motto > p,
section:has(.thsx:focus) .motto > p {
&:nth-child(1)::before {
transition-delay: 0;
}
&:nth-child(2)::before {
transition-delay: 0.1s;
}
&:nth-child(3)::before {
transition-delay: 0.2s;
}
&::before {
transition: inset-inline-start cubic-bezier(0.2, 1, 0.17, 1) 1s;
inset-inline-start: 0%;
}
}
section:has(.thsx:hover) .buttons {
transition: filter cubic-bezier(0.2, 1, 0.17, 1) 1s;
filter: grayscale(100%);
}
/* 一个特殊设计的标题元素,呼呼 */
.slide-title-design1 {
position: absolute;
inset-inline-start: -3rem;
inset-block-end: -2rem;
opacity: 0;
user-select: none;
z-index: -1;
transition: all ease 1.5s;
section.slide.slide-visible & {
opacity: 0.2;
inset-inline-start: -1rem;
}
& > svg {
font-weight: 900;
font-size: 10rem;
& > .stroke-layer {
fill: none;
stroke: var(--color-fg-0);
stroke-width: 1px;
stroke-linejoin: round;
}
& > .main-layer {
fill: var(--color-fg-0);
}
}
}
.slide-title-design2 {
position: absolute;
inset-inline-end: -5rem;
inset-block-start: -2rem;
opacity: 0;
user-select: none;
z-index: -1;
transition: all ease 1.5s;
section.slide.slide-visible & {
opacity: 0.2;
inset-inline-end: -3rem;
}
& > svg {
font-size: 288px;
transform: rotate(-12deg);
}
}
/* 评论页 */
.comment-page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
& > .comment-container {
height: 0;
padding: 0;
margin: 0;
transition: all cubic-bezier(0.4, 1, 0.4, 1) 1.2s;
border-radius: 1rem;
background-color: var(--color-bg-n);
width: calc(min(100dvw - 2rem, 40rem));
position: relative;
&::before {
content: '';
display: block;
width: 100%;
height: 100%;
border-radius: 1rem;
transition: all cubic-bezier(0.4, 1, 0.4, 1) 1.2s;
position: absolute;
transform: rotate(0deg);
z-index: -1;
background-color: rgb(from var(--color-fg-0) r g b / 0.05);
}
section.slide.slide-visible & {
margin-block-start: 2rem;
height: 60dvh;
&::before {
transform: rotate(-6deg);
}
}
}
}
/* 联络页 */
@keyframes bg-contact-roll {
0% {
background-position: 0 0;
}
100% {
background-position: var(--bg-width) 0;
}
}
.contact-container {
& > h1 {
--height: 1.5em;
--skew-angle: 15deg;
--col1: var(--color-fg-0);
--bg-width: 2rem;
--unit: calc(tan(var(--skew-angle)) * var(--height) * 0.5);
height: var(--height);
line-height: var(--height);
display: grid;
grid-template-columns: auto 1fr;
color: var(--color-bg-0);
margin-block-end: 0.5em;
position: relative;
& > .text {
background-color: var(--color-fg-0);
position: relative;
}
& .animation-before {
width: calc(var(--unit) * 2);
position: absolute;
overflow: hidden;
height: 100%;
inset-inline-end: calc(var(--unit) * -2);
inset-block-start: 0;
&::after {
content: '';
display: block;
background-color: var(--col1);
width: 100%;
height: 100%;
transform: skewX(var(--skew-angle)) translateX(calc(-1 * var(--unit)));
}
}
& > .animation {
content: '';
display: block;
background-image: linear-gradient(
90deg,
transparent 0,
transparent 25%,
var(--col1) 25%,
var(--col1) 75%,
transparent 75%,
transparent 100%
);
background-repeat: repeat;
background-size: var(--bg-width) 100%;
animation: bg-contact-roll infinite linear 2s;
transform: skewX(var(--skew-angle)) translateX(calc(var(--unit) - 1px));
}
}
& > table {
font-family: var(--font-mono);
& caption {
text-align: center;
}
& tr {
text-align: left;
display: grid;
grid-template-columns: 6em 16em;
gap: 1em;
line-height: 2em;
@media (max-width: 767px) {
grid-template-columns: 18em;
gap: 0;
line-height: 1.8em;
margin-block: 1em;
}
& th:nth-child(1) {
display: flex;
justify-content: space-between;
@media (max-width: 767px) {
justify-content: left;
}
&::after {
content: ':';
}
}
& th:nth-child(2) {
display: flex;
justify-content: space-between;
@media (max-width: 767px) {
justify-content: end;
}
&::before {
content: '[';
}
&::after {
content: ']';
}
&:hover,
&:has(a:focus) {
background-color: var(--color-fg-0);
color: var(--color-bg-0);
}
& > a {
text-align: center;
margin-inline: 1em;
&:focus {
outline: none;
}
}
}
}
}
}
/* 友链页 */
.slide:has(> .friends) {
flex-direction: column;
gap: 1rem;
}
.friends {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 1rem;
max-width: 50rem;
max-height: 30rem;
padding-block: 3rem;
overflow-y: auto;
margin-inline: 1rem;
/* background-color: rgb(from var(--color-bg-0) r g b / .3); */
background-color: rgb(from var(--color-bg-2) r g b / 0.5);
border-radius: 2rem;
backdrop-filter: blur(5px);
& > .friend {
background-color: var(--color-bg-0);
display: grid;
align-items: center;
border-radius: 30px;
overflow: hidden;
width: 14rem;
height: 60px;
grid-template-columns: 60px 1fr;
position: relative;
isolation: isolate;
& > .avatar {
border-radius: 30px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
background-color: var(--color-bg-n);
/* box-shadow: 0 0 0 10px var(--color-bg-2); */
transition: all cubic-bezier(0.2, 1, 0.4, 1) 0.5s;
}
& > .description {
text-align: center;
}
&::before {
content: '';
display: block;
border-radius: 30px;
background-color: var(--color-bg-n);
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
inset-inline-start: calc(-100% + 30px);
box-shadow: 0 0 0 10px var(--color-blue);
transition: inset-inline-start cubic-bezier(0.2, 1, 0.4, 1) 0.5s;
}
outline: solid 0px transparent;
outline-offset: 0px;
transition: all cubic-bezier(0.2, 1, 0.4, 1) 0.5s;
&:focus {
outline: solid 3px var(--color-blue);
outline-offset: 3px;
}
&:hover,
&:focus {
transform: scale(1.1);
}
&:hover::before,
&:focus::before {
inset-inline-start: 0;
}
&:hover .avatar,
&:focus .avatar {
/* transform: rotate(360deg); */
}
}
}
</style>