feat: add custom thumb support with url suffix. (#49)
This commit is contained in:
parent
ca71f7b924
commit
6addf4e95d
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -121,6 +121,7 @@
|
||||
"tsconfigs",
|
||||
"ultrahtml",
|
||||
"unpic",
|
||||
"unsharp",
|
||||
"upyun",
|
||||
"urlset",
|
||||
"varchar",
|
||||
|
@ -13,6 +13,9 @@ export default defineConfig({
|
||||
security: {
|
||||
checkOrigin: true,
|
||||
},
|
||||
image: {
|
||||
domains: ['localhost', '127.0.0.1'],
|
||||
},
|
||||
experimental: {
|
||||
env: {
|
||||
schema: {
|
||||
|
18
options.ts
18
options.ts
@ -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);
|
||||
|
@ -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)}
|
||||
/>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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 : ''}>
|
||||
|
@ -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>
|
||||
|
41
src/components/page/post/PostCategory.astro
Normal file
41
src/components/page/post/PostCategory.astro
Normal 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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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 />
|
||||
|
Loading…
Reference in New Issue
Block a user