Files
blog-frontend-v2/src/pages/index.astro
passthem bcba683f48
All checks were successful
continuous-integration/drone/push Build is passing
添加西多友链
2026-05-16 01:17:27 +08:00

698 lines
17 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 FullLayoutV1 from '../layout/FullLayoutV1.astro'
import MainpageButton from '../components/MainpageButton.svelte'
import MainpageComments from '../components/MainpageComments.astro'
import MainpageTypewriter from '../components/MainpageTypewriter.svelte'
import MainpageContactMe from '../components/MainpageContactMe.svelte'
import { Image } from 'astro:assets'
import { Icon } from 'astro-icon/components'
import PassthemAvatar from '../assets/mainpage_avatars/passthem.png'
import IgbtAvatar from '../assets/mainpage_avatars/igbt.png'
import AsynkioAvatar from '../assets/mainpage_avatars/aio.jpg'
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>
<MainpageContactMe client:idle />
</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">
{
[
{
avatar: 'https://omega98.top/images/blog_avatar.jpg',
href: 'https://omega98.top',
name: '核子的博客',
},
{
avatar: 'https://www.tnot.top/logo.png',
href: 'https://tnot.top',
name: 'TNOT 的博客',
},
{
avatar: 'https://ruusuge.top/img/logo_hu_cc283ac364b1bc0b.png',
href: 'https://ruusuge.top',
name: 'ルース毛的博客',
},
{
avatar: IgbtAvatar,
href: 'https://zetsuengate.org',
name: 'IGBT :: Home',
},
{
avatar:
'https://cdn.jsdelivr.net/gh/TransparentLC/transparentlc.github.io/img/avatar.jpg',
href: 'https://akarin.dev',
name: '存在感消失的地方',
},
{
avatar: 'https://wzq02.top/assets/icons/favicon-96x96.png',
href: 'https://wzq02.top',
name: 'wzq02 的博客',
},
{
avatar:
'https://pics.r1kka.one/file/1738764637932_-305500c1acccdf39.jpg',
href: 'https://r1kka.one/',
name: "Rikka's Blog",
},
{
avatar: 'https://shimizukaede.top/vite.svg',
href: 'https://shimizukaede.top',
name: 'Kaede 的博客',
},
{
avatar: 'https://nonerd.tech/assets/apple-touch-icon.png',
href: 'https://nonerd.tech/',
name: '废柴铁克诺',
},
{
avatar: AsynkioAvatar,
href: 'https://www.asynk.top/',
name: 'Asynkio 的小站',
},
{
avatar: 'https://legacy.passthem.top/assets/ydt-DIeb2Djx.png',
href: 'https://qm.qq.com/q/nDnHUy9KQo',
name: '有顶天变电站 (QQ)',
},
{
avatar: 'https://legacy.passthem.top/assets/lfxdxy-BogfTZvz.png',
href: 'https://qm.qq.com/q/QOpCVZcvyS',
name: '六方相的新月 (QQ)',
},
].map((b) => (
<a href={b.href} class="friend">
<div class="avatar">
<Image
src={b.avatar as string}
width={60}
height={60}
alt={`网站「${b.name}」的图标`}
densities={[1.5, 2]}
/>
</div>
<div class="description">{b.name}</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));
}
}
}
/* 友链页 */
.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>