init
This commit is contained in:
66
src/utils/date.ts
Normal file
66
src/utils/date.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { themeConfig } from '@/config'
|
||||
import type { DateFormat } from '@/types'
|
||||
|
||||
const MONTHS_EN = [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec'
|
||||
]
|
||||
|
||||
const VALID_SEPARATORS = ['.', '-', '/']
|
||||
|
||||
/**
|
||||
* @param date
|
||||
* @param format
|
||||
* @returns
|
||||
*/
|
||||
export function formatDate(date: Date, format?: string): string {
|
||||
const formatStr = (format || themeConfig.date.dateFormat).trim()
|
||||
const configSeparator = themeConfig.date.dateSeparator || '-'
|
||||
|
||||
const separator = VALID_SEPARATORS.includes(configSeparator.trim()) ? configSeparator.trim() : '.'
|
||||
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
const monthName = MONTHS_EN[date.getMonth()]
|
||||
|
||||
const pad = (num: number) => String(num).padStart(2, '0')
|
||||
|
||||
switch (formatStr) {
|
||||
case 'YYYY-MM-DD':
|
||||
return `${year}${separator}${pad(month)}${separator}${pad(day)}`
|
||||
|
||||
case 'MM-DD-YYYY':
|
||||
return `${pad(month)}${separator}${pad(day)}${separator}${year}`
|
||||
|
||||
case 'DD-MM-YYYY':
|
||||
return `${pad(day)}${separator}${pad(month)}${separator}${year}`
|
||||
|
||||
case 'MONTH DAY YYYY':
|
||||
return `<span class="month">${monthName}</span> ${day} ${year}`
|
||||
|
||||
case 'DAY MONTH YYYY':
|
||||
return `${day} <span class="month">${monthName}</span> ${year}`
|
||||
|
||||
default:
|
||||
return `${year}${separator}${pad(month)}${separator}${pad(day)}`
|
||||
}
|
||||
}
|
||||
|
||||
export const SUPPORTED_DATE_FORMATS: readonly DateFormat[] = [
|
||||
'YYYY-MM-DD',
|
||||
'MM-DD-YYYY',
|
||||
'DD-MM-YYYY',
|
||||
'MONTH DAY YYYY',
|
||||
'DAY MONTH YYYY'
|
||||
] as const
|
||||
20
src/utils/draft.ts
Normal file
20
src/utils/draft.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { getCollection, type CollectionEntry } from 'astro:content'
|
||||
|
||||
/**
|
||||
* Get all posts, filtering out posts whose filenames start with _
|
||||
*/
|
||||
export async function getFilteredPosts() {
|
||||
const posts = await getCollection('posts')
|
||||
return posts.filter((post: CollectionEntry<'posts'>) => !post.id.startsWith('_'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all posts sorted by publication date, filtering out posts whose filenames start with _
|
||||
*/
|
||||
export async function getSortedFilteredPosts() {
|
||||
const posts = await getFilteredPosts()
|
||||
return posts.sort(
|
||||
(a: CollectionEntry<'posts'>, b: CollectionEntry<'posts'>) =>
|
||||
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
|
||||
)
|
||||
}
|
||||
81
src/utils/feed.ts
Normal file
81
src/utils/feed.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { getCollection, type CollectionEntry } from 'astro:content'
|
||||
import { themeConfig } from '@/config'
|
||||
import type { APIContext } from 'astro'
|
||||
|
||||
export async function generateRSS(context: APIContext) {
|
||||
const posts = await getCollection('posts')
|
||||
const filteredPosts = posts.filter((post: CollectionEntry<'posts'>) => !post.id.startsWith('_'))
|
||||
const sortedPosts = filteredPosts.sort(
|
||||
(a: CollectionEntry<'posts'>, b: CollectionEntry<'posts'>) =>
|
||||
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
|
||||
)
|
||||
|
||||
const rss = `<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>${themeConfig.site.title}</title>
|
||||
<link>${context.site}</link>
|
||||
<description>${themeConfig.site.description}</description>
|
||||
<language>zh-CN</language>
|
||||
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
|
||||
<atom:link href="${context.site}/rss.xml" rel="self" type="application/rss+xml" />
|
||||
${sortedPosts
|
||||
.map(
|
||||
(post: CollectionEntry<'posts'>) => `
|
||||
<item>
|
||||
<title><![CDATA[${post.data.title}]]></title>
|
||||
<link>${context.site}/${post.id}/</link>
|
||||
<guid>${context.site}/${post.id}/</guid>
|
||||
<pubDate>${post.data.pubDate.toUTCString()}</pubDate>
|
||||
<content:encoded><![CDATA[${post.body}]]></content:encoded>
|
||||
</item>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</channel>
|
||||
</rss>`
|
||||
|
||||
return new Response(rss, {
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function generateAtom(context: APIContext) {
|
||||
const posts = await getCollection('posts')
|
||||
const filteredPosts = posts.filter((post: CollectionEntry<'posts'>) => !post.id.startsWith('_'))
|
||||
const sortedPosts = filteredPosts.sort(
|
||||
(a: CollectionEntry<'posts'>, b: CollectionEntry<'posts'>) =>
|
||||
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
|
||||
)
|
||||
|
||||
const atom = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>${themeConfig.site.title}</title>
|
||||
<subtitle>${themeConfig.site.description}</subtitle>
|
||||
<link href="${context.site}/atom.xml" rel="self" type="application/atom+xml" />
|
||||
<link href="${context.site}" />
|
||||
<id>${context.site}</id>
|
||||
<updated>${new Date().toISOString()}</updated>
|
||||
${sortedPosts
|
||||
.map(
|
||||
(post: CollectionEntry<'posts'>) => `
|
||||
<entry>
|
||||
<title>${post.data.title}</title>
|
||||
<link href="${context.site}/${post.id}/" />
|
||||
<id>${context.site}/${post.id}/</id>
|
||||
<published>${post.data.pubDate.toISOString()}</published>
|
||||
<content type="html"><![CDATA[${post.body}]]></content>
|
||||
</entry>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</feed>`
|
||||
|
||||
return new Response(atom, {
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8'
|
||||
}
|
||||
})
|
||||
}
|
||||
27
src/utils/image-config.ts
Normal file
27
src/utils/image-config.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export const imageConfig = {
|
||||
// Enhanced image optimization settings
|
||||
limitInputPixels: 268402689, // ~16K x 16K pixels
|
||||
jpeg: {
|
||||
quality: 85,
|
||||
progressive: true,
|
||||
optimizeScans: true,
|
||||
mozjpeg: true
|
||||
},
|
||||
png: {
|
||||
quality: 85,
|
||||
progressive: true,
|
||||
compressionLevel: 9,
|
||||
adaptiveFiltering: true
|
||||
},
|
||||
webp: {
|
||||
quality: 85,
|
||||
lossless: false,
|
||||
nearLossless: true,
|
||||
smartSubsample: true
|
||||
},
|
||||
avif: {
|
||||
quality: 85,
|
||||
lossless: false,
|
||||
speed: 5
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user