import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import BlogSidebar from '../components/BlogSidebar.jsx'; import { listPosts, searchPosts, getTags } from '../api/blog.js'; import { getPublicSettings } from '../api/settings.js'; /** 摘要:优先取 excerpt,否则从内容中剥离 markdown 符号截取(照搬 blog.js) */ function excerptOf(p) { if (p.excerpt) return p.excerpt; return (p.content || '').replace(/[#*`\[\]()>|~_]/g, '').slice(0, 200); } /** 博客列表页(迁移自 blog.html + blog.js loadPosts):瀑布流卡片,点击进详情; * 顶部搜索框(/api/blog/search)+ 标签云(/api/blog/tags,点击进 /tag/:name)+ 归档入口 */ export default function Blog() { const [settings, setSettings] = useState({}); const [posts, setPosts] = useState(null); // null=加载中 const [error, setError] = useState(''); // 搜索状态 const [query, setQuery] = useState(''); const [results, setResults] = useState(null); // null=未搜索 const [searching, setSearching] = useState(false); // 标签云 const [tags, setTags] = useState([]); useEffect(() => { getPublicSettings().then(setSettings).catch(() => {}); listPosts() .then((ps) => setPosts(ps || [])) .catch((e) => setError(e.message || '加载失败')); getTags() .then((ts) => setTags(ts || [])) .catch(() => setTags([])); }, []); const doSearch = async (e) => { e && e.preventDefault(); const q = query.trim(); if (!q) { setResults(null); return; } setSearching(true); try { const rs = await searchPosts(q); setResults(rs || []); } catch (err) { setResults([]); setError(err.message || '搜索失败'); } setSearching(false); }; const clearSearch = () => { setQuery(''); setResults(null); setError(''); }; // 搜索结果以列表呈现(区别于瀑布流卡片) const renderResults = () => (
没有找到相关内容
{error}
暂无文章