添加一个简陋的用户页
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-04-18 10:12:44 +08:00
parent 8c3aa00e15
commit b6eb62fc80
7 changed files with 128 additions and 15 deletions

View File

@ -30,7 +30,7 @@ const { title = '小帕的小窝', withGap = false } = Astro.props
<a href="/">小帕的小窝</a>
</li>
<li>
<a href="/blogs"><Icon name="mdi:invoice-text-outline" />文章</a>
<a href="/blog"><Icon name="mdi:invoice-text-outline" />文章</a>
</li>
<li>
<a href="/about"

View File

@ -1,6 +1,6 @@
import { legacyClient } from '../clients'
export type ListBlogItemType = {
export type LegacyListBlogItemType = {
id: number
title: string
@ -24,7 +24,7 @@ export type ListBlogItemType = {
}
}
export type BlogContentType = ListBlogItemType & {
export type LegacyBlogContentType = LegacyListBlogItemType & {
content: string
}
@ -57,12 +57,12 @@ export const listBlogs = async ({
_blog.updated_at = new Date(_blog.updated_at)
return _blog
}) as ListBlogItemType[]
}) as LegacyListBlogItemType[]
}
export const getBlog: (
blog_id: number,
) => Promise<null | BlogContentType> = async (blog_id: number) => {
) => Promise<null | LegacyBlogContentType> = async (blog_id: number) => {
const resp = await legacyClient.get(`/v1/blog/${blog_id}`, {
validateStatus: (status) => status == 200 || status == 404,
})

View File

@ -0,0 +1,27 @@
import { legacyClient } from '../clients'
export type LegacyUserType = {
id: number
created_at: Date
username: string
nickname: string
permission: number
introduction: string
avatar: {
image_url: string
}
}
export const getUserInfo = async ({ username }: { username: string }) => {
const resp = await legacyClient.get(`/v1/user/${username}/info`)
if (resp.status != 200) {
return null
}
return {
...resp.data,
created_at: new Date(resp.data.created_at),
avatar: {
image_url: 'https://legacy.passthem.top' + resp.data.avatar.image_url,
},
} as LegacyUserType
}

View File

@ -1,6 +1,6 @@
---
import FullLayoutV1 from '../layout/FullLayoutV1.astro'
import { listBlogs, type ListBlogItemType } from '../lib/apis/legacy/blog'
import { listBlogs, type LegacyListBlogItemType } from '../lib/apis/legacy/blog'
import BlogCard from '../components/BlogCard.astro'
import BlogHeaderImage from '../assets/blogs-header.webp'
import { Image } from 'astro:assets'
@ -10,7 +10,7 @@ export const prerender = false
const _page = parseInt(Astro.url.searchParams.get('page') || '1')
const page = isNaN(_page) ? 1 : Math.max(1, _page)
let blogs: ListBlogItemType[] = []
let blogs: LegacyListBlogItemType[] = []
try {
blogs = await listBlogs({ page, limit: 100 })
@ -45,7 +45,7 @@ try {
blogs.map((blog) => (
<BlogCard
title={blog.title}
link={`/blogs/${blog.id}`}
link={`/blog/${blog.id}`}
featureImage={blog.featured_image?.image_url}
author={{
name: blog.author.nickname,

View File

@ -54,10 +54,7 @@ const formatDate = (date: Date) =>
{
blogData.author && (
<div class="blog-info">
<a
class="author"
href={`https://legacy.passthem.top/user/${blogData.author.username}`}
>
<a class="author" href={`/user/${blogData.author.username}`}>
<div class="avatar">
<Image
class="image"

View File

@ -3,7 +3,7 @@ import type { APIRoute } from 'astro'
import {
getBlog,
listBlogs,
type ListBlogItemType,
type LegacyListBlogItemType,
} from '../lib/apis/legacy/blog'
import { ensureShikiEngine } from '../lib/markdown'
// import { toMarkdocTree } from '../lib/markdoc'
@ -50,7 +50,7 @@ const _getBlog = async (blogId: number) => {
}
export const GET = (async (context) => {
let blogs: ListBlogItemType[] = []
let blogs: LegacyListBlogItemType[] = []
let pid = 0
let newBlogs = []
@ -76,7 +76,7 @@ export const GET = (async (context) => {
const rssItem: RSSFeedItem = {
title: blog.title,
description: `一篇由 ${blog.author.nickname} 写的博客`,
link: `${site}/blogs/${blog.id}`,
link: `${site}/blog/${blog.id}`,
pubDate: new Date(blog.created_at),
content: await _render(blogContent),
author: blog.author.nickname,

View File

@ -0,0 +1,89 @@
---
import FullLayoutV1 from '../../layout/FullLayoutV1.astro'
import { getUserInfo, type LegacyUserType } from '../../lib/apis/legacy/user'
import { Image } from 'astro:assets'
const { user_id = '' } = Astro.params
var user_data: LegacyUserType
try {
const _user_data = await getUserInfo({ username: user_id })
if (_user_data === null) {
return Astro.redirect('/404')
}
user_data = _user_data
} catch (e) {
console.warn('访问了不存在的用户', user_id)
console.warn(e)
return Astro.redirect('/404')
}
---
<FullLayoutV1>
<div class="container">
<div class="user-card">
<div class="avatar">
<Image
src={user_data.avatar.image_url}
densities={[1.5, 2]}
width={150}
height={150}
alt=`用户 ${user_data.username} 的头像`
/>
</div>
<div class="user-info">
<h1 class="name">
<span class="nickname">{user_data.nickname}</span><span
class="username">{user_data.username}</span
>
</h1>
<h2 class="introduction">{user_data.introduction}</h2>
</div>
</div>
</div>
</FullLayoutV1>
<style>
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100dvh;
.user-card {
background-color: var(--color-bg-n);
display: flex;
flex-direction: column;
padding: 4rem;
gap: 1rem;
border-radius: 1rem;
@media (width >= 768px) {
flex-direction: row;
gap: 3rem;
}
.user-info {
.name {
display: flex;
font-weight: 600;
gap: 0.5rem;
margin-block-end: 0.25rem;
align-items: center;
font-size: larger;
.username {
opacity: 0.3;
font-family: var(--font-mono);
font-size: 0.9em;
&::before {
content: '@';
display: inline;
}
}
}
}
}
}
</style>