feat: add custom thumb support with url suffix. (#49)

This commit is contained in:
Yufan Sheng 2024-06-21 00:17:18 +08:00
parent 179a2b088f
commit 6b2211ba85
Signed by: syhily
GPG Key ID: 9D18A22A7DCD5A9B
13 changed files with 92 additions and 86 deletions

View File

@ -121,6 +121,7 @@
"tsconfigs",
"ultrahtml",
"unpic",
"unsharp",
"upyun",
"urlset",
"varchar",

View File

@ -13,6 +13,9 @@ export default defineConfig({
security: {
checkOrigin: true,
},
image: {
domains: ['localhost', '127.0.0.1'],
},
experimental: {
env: {
schema: {

View File

@ -1,5 +1,7 @@
import { z } from 'astro/zod';
const isProd = (): boolean => import.meta.env.MODE === 'production' || process.env.NODE_ENV === 'production';
// The type of the options, use zod for better validation.
const Options = z
.object({
@ -65,9 +67,12 @@ const Options = z
admins: z.array(z.number()),
}),
}),
thumbnail: z
.function()
.args(z.object({ src: z.string().min(1), width: z.number(), height: z.number() }))
.returns(z.string()),
})
.transform((opts) => {
const isProd = (): boolean => import.meta.env.MODE === 'production' || process.env.NODE_ENV === 'production';
const assetsPrefix = (): string => (isProd() ? opts.settings.assetPrefix : opts.local.website);
return {
...opts,
@ -81,7 +86,7 @@ const Options = z
};
});
const options = {
const options: z.input<typeof Options> = {
local: {
port: 4321,
},
@ -172,6 +177,15 @@ const options = {
admins: [3],
},
},
thumbnail: ({ src, width, height }) => {
if (isProd()) {
// Add upyun thumbnail support.
return `${src}!upyun520/both/${width}x${height}/quality/100/unsharp/true/progressive/true`;
}
// See https://docs.astro.build/en/reference/image-service-reference/#local-services
// Remember to add the localhost to you image service settings.
return `http://localhost:4321/_image?href=${src}&w=${width}&h=${height}&f=webp&q=100`;
},
};
export default Options.parse(options);

View File

@ -1,5 +1,6 @@
---
import { blurStyle, type Image } from '@/helpers/images';
import options from '@/options';
interface Props extends Image {
alt: string;
@ -8,4 +9,11 @@ interface Props extends Image {
const { alt, src, width, height } = Astro.props;
---
<img {src} {alt} loading="lazy" {width} {height} style={blurStyle(Astro.props)} />
<img
src={options.thumbnail({ src, width, height })}
{alt}
loading="lazy"
{width}
{height}
style={blurStyle(Astro.props)}
/>

View File

@ -1,14 +0,0 @@
---
import PinnedCategory from '@/components/page/category/PinnedCategory.astro';
import { getCategory } from '@/helpers/schema';
import options from '@/options';
const pinnedSlug = options.settings.post.category ?? [];
const pinnedCategories = pinnedSlug
.map((slug) => getCategory(undefined, slug))
.flatMap((category) => (category !== undefined ? [category] : []));
---
<div class="row g-2 g-md-4 list-grouped mt-3 mt-md-4">
{pinnedCategories.map((category) => <PinnedCategory category={category} />)}
</div>

View File

@ -1,35 +0,0 @@
---
import Image from '@/components/image/Image.astro';
import type { Category } from '@/helpers/schema';
interface Props {
category: Category;
}
const { category } = Astro.props;
---
<div class="col-md-6">
<div class="list-item block">
<div class="media media-3x1">
<a href={category.permalink} class="media-content">
<Image {...category.cover} alt={category.name} />
</a>
</div>
<div class="list-content">
<div class="list-body">
<a href={category.permalink} class="list-title h5">
{category.name}
</a>
<div class="list-subtitle d-none d-md-block text-md text-secondary mt-2">
<div class="h-1x">{category.description}</div>
</div>
</div>
<div class="list-footer mt-2">
<div class="text-muted text-sm">
<span class="d-inline-block">{`${category.counts} 篇文章`}</span>
</div>
</div>
</div>
</div>
</div>

View File

@ -12,7 +12,7 @@ const { post } = Astro.props;
<div class="list-item list-nice-overlay">
<div class="media media-3x2">
<a href={post.permalink} class="media-content">
<Image {...post.cover} alt={post.title} />
<Image {...post.cover} alt={post.title} width={750} height={500} />
<div class="overlay"></div>
</a>
</div>

View File

@ -15,7 +15,7 @@ const category = getCategory(post.category, undefined);
<div class="list-item block">
<div class="media media-3x2 col-6 col-md-5">
<a href={post.permalink} class="media-content">
<Image {...post.cover} alt={post.title} />
<Image {...post.cover} alt={post.title} width={600} height={400} />
</a>
<div class="media-overlay overlay-top">
<a class="d-none d-md-inline-block badge badge-md bg-white-overlay" href={category ? category.permalink : ''}>

View File

@ -1,12 +1,25 @@
---
import PostCard from '@/components/page/post/PostCard.astro';
import Pagination from '@/components/page/pagination/Pagination.astro';
import { slicePosts } from '@/helpers/formatter';
import type { Post } from '@/helpers/schema';
import options from '@/options';
import PostCard from './PostCard.astro';
interface Props {
posts: Post[];
pageNum: number;
}
const { posts } = Astro.props;
const { pageNum, posts } = Astro.props;
const results = slicePosts(posts, pageNum, options.settings.pagination.posts);
if (!results) {
return Astro.redirect('/404');
}
const { currentPosts, totalPage } = results;
---
<div class="list-grid">{posts.map((post) => <PostCard post={post} />)}</div>
<div class="content-wrapper content-wrapper col-12 col-xl-9">
<div class="list-grid">{currentPosts.map((post) => <PostCard post={post} />)}</div>
<Pagination current={pageNum} total={totalPage} rootPath={'/'} />
</div>

View File

@ -0,0 +1,41 @@
---
import Image from '@/components/image/Image.astro';
import { getCategory } from '@/helpers/schema';
import options from '@/options';
const pinnedSlug = options.settings.post.category ?? [];
const pinnedCategories = pinnedSlug
.map((slug) => getCategory(undefined, slug))
.flatMap((category) => (category !== undefined ? [category] : []));
---
<div class="row g-2 g-md-4 list-grouped mt-3 mt-md-4">
{
pinnedCategories.map((category) => (
<div class="col-md-6">
<div class="list-item block">
<div class="media media-3x1">
<a href={category.permalink} class="media-content">
<Image {...category.cover} alt={category.name} width={600} height={200} />
</a>
</div>
<div class="list-content">
<div class="list-body">
<a href={category.permalink} class="list-title h5">
{category.name}
</a>
<div class="list-subtitle d-none d-md-block text-md text-secondary mt-2">
<div class="h-1x">{category.description}</div>
</div>
</div>
<div class="list-footer mt-2">
<div class="text-muted text-sm">
<span class="d-inline-block">{`${category.counts} 篇文章`}</span>
</div>
</div>
</div>
</div>
</div>
))
}
</div>

View File

@ -1,25 +0,0 @@
---
import Pagination from '@/components/page/pagination/Pagination.astro';
import PostCards from '@/components/page/post/PostCards.astro';
import { slicePosts } from '@/helpers/formatter';
import type { Post } from '@/helpers/schema';
import options from '@/options';
interface Props {
posts: Post[];
pageNum: number;
}
const { pageNum, posts } = Astro.props;
const results = slicePosts(posts, pageNum, options.settings.pagination.posts);
if (!results) {
return Astro.redirect('/404');
}
const { currentPosts, totalPage } = results;
---
<div class="content-wrapper content-wrapper col-12 col-xl-9">
<PostCards posts={currentPosts} />
<Pagination current={pageNum} total={totalPage} rootPath={'/'} />
</div>

View File

@ -16,7 +16,7 @@ const { post, first } = Astro.props;
<div class="list-item list-nice-overlay">
<div class={`media ${first ? 'media-36x17' : ''}`}>
<a href={post.permalink} class="media-content">
<Image {...post.cover} alt={post.title} />
<Image {...post.cover} alt={post.title} width={first ? 600 : 300} height={300} />
<div class="overlay"></div>
</a>
</div>

View File

@ -1,7 +1,7 @@
---
import PinnedCategories from '@/components/page/category/PinnedCategories.astro';
import FeaturePosts from '@/components/page/post/FeaturePosts.astro';
import PostPagination from '@/components/page/post/PostPagination.astro';
import PostCards from '@/components/page/post/PostCards.astro';
import PinnedCategories from '@/components/page/post/PostCategory.astro';
import Sidebar from '@/components/sidebar/Sidebar.astro';
import type { Post, Tag } from '@/helpers/schema';
@ -27,7 +27,7 @@ if (pageNum < 1) {
<FeaturePosts {posts} />
<div class="container">
<div class="row">
<PostPagination {pageNum} {posts} />
<PostCards {pageNum} {posts} />
<Sidebar {posts} {tags} />
</div>
<PinnedCategories />