MVP: 按 07 风格重写前端 + Go 后端落地(长文/短文、编辑器、后台管理)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import { marked } from 'marked'
|
||||
import DOMPurify from 'dompurify'
|
||||
|
||||
marked.setOptions({ breaks: true, gfm: true })
|
||||
|
||||
// 编辑器预览与前台渲染共用这一个入口:先 marked 渲染,再过 DOMPurify
|
||||
export function renderMarkdown(text) {
|
||||
return DOMPurify.sanitize(marked.parse(text || '', { async: false }))
|
||||
}
|
||||
|
||||
// 编辑器按 `md.render(...)` 的用法调用
|
||||
export const md = { render: renderMarkdown }
|
||||
|
||||
export function formatDate(iso) {
|
||||
if (!iso) return ''
|
||||
const d = new Date(iso)
|
||||
if (Number.isNaN(d.getTime())) return iso
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${y} 年 ${m} 月 ${day} 日`
|
||||
}
|
||||
|
||||
export function formatDateShort(iso) {
|
||||
if (!iso) return ''
|
||||
const d = new Date(iso)
|
||||
if (Number.isNaN(d.getTime())) return iso
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(
|
||||
d.getDate()
|
||||
).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
// 时间线上的相对时间:三天内用「几小时前」,同年省略年份
|
||||
export function relativeDate(iso) {
|
||||
if (!iso) return ''
|
||||
const d = new Date(iso)
|
||||
if (Number.isNaN(d.getTime())) return iso
|
||||
const diff = Date.now() - d.getTime()
|
||||
const hour = 3600 * 1000
|
||||
if (diff < hour) return `${Math.max(1, Math.floor(diff / 60000))} 分钟前`
|
||||
if (diff < 24 * hour) return `${Math.floor(diff / hour)} 小时前`
|
||||
if (diff < 3 * 24 * hour) return `${Math.floor(diff / (24 * hour))} 天前`
|
||||
const sameYear = d.getFullYear() === new Date().getFullYear()
|
||||
return sameYear
|
||||
? `${d.getMonth() + 1} 月 ${d.getDate()} 日`
|
||||
: `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`
|
||||
}
|
||||
|
||||
export function stripTags(html) {
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = html || ''
|
||||
return div.textContent || ''
|
||||
}
|
||||
|
||||
// 短文在列表里没有标题,用正文首句当索引
|
||||
export function displayTitle(post) {
|
||||
if (post.kind === 'short') return ''
|
||||
return post.title || '无题'
|
||||
}
|
||||
|
||||
export function excerpt(post, limit = 60) {
|
||||
if (post.summary) return post.summary
|
||||
const text = stripTags(post.content_html || '')
|
||||
return text.length > limit ? text.slice(0, limit) + '…' : text
|
||||
}
|
||||
|
||||
export function minutesLabel(post) {
|
||||
if (post.kind === 'short') return '短文'
|
||||
return `${post.reading_minutes || 1} 分钟`
|
||||
}
|
||||
Reference in New Issue
Block a user