Compare commits
15
Commits
v2.0.3
...
5b166ef0e2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b166ef0e2 | ||
|
|
4f89c63b28 | ||
|
|
7bfeffaaa0 | ||
|
|
aff5764b9b | ||
|
|
bb830f779c | ||
|
|
63d329db5f | ||
|
|
e83a4e6ee1 | ||
|
|
0153f770f6 | ||
|
|
789a2d9b33 | ||
|
|
5a878c1aab | ||
|
|
5e4cdf26b9 | ||
|
|
2faace4810 | ||
|
|
45002b809a | ||
|
|
1b62bf99ce | ||
|
|
6fafa6eb00 |
@@ -186,6 +186,7 @@ function seedDefaults() {
|
|||||||
smtp_from_name: 'RainWeb',
|
smtp_from_name: 'RainWeb',
|
||||||
theme_wallpaper: '',
|
theme_wallpaper: '',
|
||||||
theme_wallpaper_scale: 'cover',
|
theme_wallpaper_scale: 'cover',
|
||||||
|
theme_wallpaper_enabled: '1',
|
||||||
nav_style: 'default',
|
nav_style: 'default',
|
||||||
card_style: 'default',
|
card_style: 'default',
|
||||||
glass_blur: '20',
|
glass_blur: '20',
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export default function ThemeSettings() {
|
|||||||
primary_color: '#6750a4',
|
primary_color: '#6750a4',
|
||||||
theme_wallpaper: '',
|
theme_wallpaper: '',
|
||||||
theme_wallpaper_scale: 'cover',
|
theme_wallpaper_scale: 'cover',
|
||||||
|
theme_wallpaper_enabled: true,
|
||||||
nav_style: 'default',
|
nav_style: 'default',
|
||||||
card_style: 'default',
|
card_style: 'default',
|
||||||
glass_blur: '20',
|
glass_blur: '20',
|
||||||
@@ -34,6 +35,7 @@ export default function ThemeSettings() {
|
|||||||
primary_color: s.primary_color || '#6750a4',
|
primary_color: s.primary_color || '#6750a4',
|
||||||
theme_wallpaper: s.theme_wallpaper || '',
|
theme_wallpaper: s.theme_wallpaper || '',
|
||||||
theme_wallpaper_scale: s.theme_wallpaper_scale || 'cover',
|
theme_wallpaper_scale: s.theme_wallpaper_scale || 'cover',
|
||||||
|
theme_wallpaper_enabled: s.theme_wallpaper_enabled !== '0',
|
||||||
nav_style: s.nav_style || 'default',
|
nav_style: s.nav_style || 'default',
|
||||||
card_style: s.card_style || 'default',
|
card_style: s.card_style || 'default',
|
||||||
glass_blur: s.glass_blur || '20',
|
glass_blur: s.glass_blur || '20',
|
||||||
@@ -65,6 +67,7 @@ export default function ThemeSettings() {
|
|||||||
primary_color: form.primary_color,
|
primary_color: form.primary_color,
|
||||||
theme_wallpaper: form.theme_wallpaper.trim(),
|
theme_wallpaper: form.theme_wallpaper.trim(),
|
||||||
theme_wallpaper_scale: form.theme_wallpaper_scale,
|
theme_wallpaper_scale: form.theme_wallpaper_scale,
|
||||||
|
theme_wallpaper_enabled: form.theme_wallpaper_enabled ? '1' : '0',
|
||||||
theme_force_dark: form.theme_force_dark ? '1' : '0',
|
theme_force_dark: form.theme_force_dark ? '1' : '0',
|
||||||
nav_style: form.nav_style,
|
nav_style: form.nav_style,
|
||||||
card_style: form.card_style,
|
card_style: form.card_style,
|
||||||
@@ -92,6 +95,11 @@ export default function ThemeSettings() {
|
|||||||
|
|
||||||
<Paper sx={{ p: 3, mb: 2 }}>
|
<Paper sx={{ p: 3, mb: 2 }}>
|
||||||
<Typography variant="subtitle1" sx={{ mb: 1 }}>壁纸背景</Typography>
|
<Typography variant="subtitle1" sx={{ mb: 1 }}>壁纸背景</Typography>
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={form.theme_wallpaper_enabled} onChange={(e) => setForm((p) => ({ ...p, theme_wallpaper_enabled: e.target.checked }))} />}
|
||||||
|
label="启用壁纸背景"
|
||||||
|
sx={{ mb: 1 }}
|
||||||
|
/>
|
||||||
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mb: 1 }}>
|
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center', mb: 1 }}>
|
||||||
<Button variant="outlined" onClick={() => fileRef.current && fileRef.current.click()}>上传图片</Button>
|
<Button variant="outlined" onClick={() => fileRef.current && fileRef.current.click()}>上传图片</Button>
|
||||||
<input ref={fileRef} type="file" accept="image/*" style={{ display: 'none' }} onChange={handleWallpaperUpload} />
|
<input ref={fileRef} type="file" accept="image/*" style={{ display: 'none' }} onChange={handleWallpaperUpload} />
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default function Layout() {
|
|||||||
const wallpaper = settings.theme_wallpaper || '';
|
const wallpaper = settings.theme_wallpaper || '';
|
||||||
const scale = settings.theme_wallpaper_scale || 'cover';
|
const scale = settings.theme_wallpaper_scale || 'cover';
|
||||||
|
|
||||||
if (wallpaper) {
|
if (wallpaper && settings.theme_wallpaper_enabled !== '0') {
|
||||||
body.classList.add('has-wallpaper');
|
body.classList.add('has-wallpaper');
|
||||||
body.style.setProperty('--wallpaper', `url(${wallpaper})`);
|
body.style.setProperty('--wallpaper', `url(${wallpaper})`);
|
||||||
const bgSizeMap = { cover: 'cover', contain: 'contain', repeat: 'auto', stretch: '100% 100%' };
|
const bgSizeMap = { cover: 'cover', contain: 'contain', repeat: 'auto', stretch: '100% 100%' };
|
||||||
|
|||||||
@@ -43,7 +43,13 @@ export function renderContent(content, useMarkdown) {
|
|||||||
|
|
||||||
html = html.replace(/\x00IMG(\d+)\x00/g, (m, i) => imageTag(images[parseInt(i)]));
|
html = html.replace(/\x00IMG(\d+)\x00/g, (m, i) => imageTag(images[parseInt(i)]));
|
||||||
html = html.replace(/\x00FILE(\d+)\x00/g, (m, i) => fileTag(files[parseInt(i)]));
|
html = html.replace(/\x00FILE(\d+)\x00/g, (m, i) => fileTag(files[parseInt(i)]));
|
||||||
return DOMPurify.sanitize(html);
|
html = DOMPurify.sanitize(html);
|
||||||
|
|
||||||
|
// 给 h2 注入稳定锚点 id(在 HTML 字符串内生成,重渲一致,供目录锚点定位;
|
||||||
|
// 不在渲染后 DOM 上赋 id——React 重渲可能替换 DOM 导致 id 丢失)
|
||||||
|
let h2Index = 0;
|
||||||
|
html = html.replace(/<h2(?![^>]*\bid=)/gi, () => `<h2 id="toc-${h2Index++}"`);
|
||||||
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MarkdownRenderer({ content = '', useMarkdown = true }) {
|
export default function MarkdownRenderer({ content = '', useMarkdown = true }) {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ export default function BlogDetail() {
|
|||||||
const [prevnext, setPrevnext] = useState(null);
|
const [prevnext, setPrevnext] = useState(null);
|
||||||
const [like, setLike] = useState({ liked: false, count: 0 });
|
const [like, setLike] = useState({ liked: false, count: 0 });
|
||||||
const [toc, setToc] = useState([]);
|
const [toc, setToc] = useState([]);
|
||||||
const [tocOpen, setTocOpen] = useState(true);
|
|
||||||
const [replyTo, setReplyTo] = useState(null); // {id, name}
|
const [replyTo, setReplyTo] = useState(null); // {id, name}
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
@@ -67,20 +66,22 @@ export default function BlogDetail() {
|
|||||||
}
|
}
|
||||||
}, [load]);
|
}, [load]);
|
||||||
|
|
||||||
// 目录:从已渲染的 .md-body 提取 h2/h3 并打锚点 id
|
|
||||||
useEffect(() => {
|
|
||||||
if (!post) return;
|
|
||||||
const body = document.querySelector('.blog-article .md-body');
|
|
||||||
if (!body) { setToc([]); return; }
|
|
||||||
const items = [...body.querySelectorAll('h2, h3')].map((h, i) => {
|
|
||||||
if (!h.id) h.id = 'toc-' + i;
|
|
||||||
return { id: h.id, text: (h.textContent || '').trim(), level: h.tagName === 'H2' ? 2 : 3 };
|
|
||||||
});
|
|
||||||
setToc(items);
|
|
||||||
}, [post]);
|
|
||||||
|
|
||||||
const canEdit = user && post && (user.role === 'admin' || user.id === post.author_id);
|
const canEdit = user && post && (user.role === 'admin' || user.id === post.author_id);
|
||||||
const wordCount = useMemo(() => (post ? countWords(post.content) : 0), [post]);
|
const wordCount = useMemo(() => (post ? countWords(post.content) : 0), [post]);
|
||||||
|
|
||||||
|
// 目录:从已渲染的 .md-body 提取 h2(仅一级章节)打锚点;短文章(<500 字)不提取
|
||||||
|
useEffect(() => {
|
||||||
|
if (!post) return;
|
||||||
|
if (wordCount < 500) { setToc([]); return; }
|
||||||
|
const body = document.querySelector('.blog-article .md-body');
|
||||||
|
if (!body) { setToc([]); return; }
|
||||||
|
const items = [...body.querySelectorAll('h2')].map((h, i) => {
|
||||||
|
if (!h.id) h.id = 'toc-' + i;
|
||||||
|
return { id: h.id, text: (h.textContent || '').trim(), level: 2 };
|
||||||
|
});
|
||||||
|
setToc(items);
|
||||||
|
}, [post, wordCount]);
|
||||||
|
|
||||||
const tags = useMemo(() => String(post?.tags || '').split(',').map((t) => t.trim()).filter(Boolean), [post]);
|
const tags = useMemo(() => String(post?.tags || '').split(',').map((t) => t.trim()).filter(Boolean), [post]);
|
||||||
|
|
||||||
// ── 点赞(乐观更新)──
|
// ── 点赞(乐观更新)──
|
||||||
@@ -161,7 +162,8 @@ export default function BlogDetail() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="blog-article">
|
<div className="article-layout">
|
||||||
|
<div className="blog-article article-main">
|
||||||
<Link to="/blog.html" className="btn btn-text btn-sm" style={{ marginBottom: 16 }}>
|
<Link to="/blog.html" className="btn btn-text btn-sm" style={{ marginBottom: 16 }}>
|
||||||
<span className="material-icons" style={{ fontSize: 16 }}>arrow_back</span> 返回列表
|
<span className="material-icons" style={{ fontSize: 16 }}>arrow_back</span> 返回列表
|
||||||
</Link>
|
</Link>
|
||||||
@@ -194,36 +196,6 @@ export default function BlogDetail() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 目录(正文顶部,可折叠) */}
|
|
||||||
{toc.length > 0 && (
|
|
||||||
<div className="toc-block">
|
|
||||||
<button className="toc-toggle" onClick={() => setTocOpen((v) => !v)}>
|
|
||||||
<span className="material-icons" style={{ fontSize: 17 }}>format_list_bulleted</span>
|
|
||||||
目录
|
|
||||||
<span className="toc-count">{toc.length}</span>
|
|
||||||
<span className={'material-icons toc-arrow' + (tocOpen ? ' open' : '')} style={{ fontSize: 18 }}>expand_more</span>
|
|
||||||
</button>
|
|
||||||
{tocOpen && (
|
|
||||||
<ul className="toc-list">
|
|
||||||
{toc.map((t) => (
|
|
||||||
<li key={t.id} className={'toc-item toc-lv' + t.level}>
|
|
||||||
<a
|
|
||||||
href={'#' + t.id}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const el = document.getElementById(t.id);
|
|
||||||
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t.text}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<MarkdownRenderer content={post.content} useMarkdown={post.use_markdown} />
|
<MarkdownRenderer content={post.content} useMarkdown={post.use_markdown} />
|
||||||
|
|
||||||
{/* 上一篇 / 下一篇 */}
|
{/* 上一篇 / 下一篇 */}
|
||||||
@@ -295,5 +267,32 @@ export default function BlogDetail() {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 侧边目录(仅 h2 章节;短文章 <500 字不显示) */}
|
||||||
|
{toc.length > 0 && (
|
||||||
|
<aside className="article-toc-side">
|
||||||
|
<div className="toc-title">
|
||||||
|
<span className="material-icons" style={{ fontSize: 16 }}>format_list_bulleted</span>
|
||||||
|
目录 <span className="toc-count">{toc.length}</span>
|
||||||
|
</div>
|
||||||
|
<ul className="toc-list">
|
||||||
|
{toc.map((t) => (
|
||||||
|
<li key={t.id} className="toc-item">
|
||||||
|
<a
|
||||||
|
href={'#' + t.id}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const el = document.getElementById(t.id);
|
||||||
|
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t.text}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+134
-4
@@ -779,13 +779,13 @@ table tr:hover td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Login Page ===== */
|
/* ===== Login Page ===== */
|
||||||
.login-page {
|
.login-page, .register-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
background: var(--md-ref-background);
|
background: transparent; /* 完全透明,透出壁纸 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card {
|
.login-card {
|
||||||
@@ -1559,6 +1559,18 @@ button.glass-card, .btn.glass-card, .nav-tab.glass-card, .chip.glass-card {
|
|||||||
-webkit-backdrop-filter: blur(8px);
|
-webkit-backdrop-filter: blur(8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 壁纸下内容区统一磨砂背景:半透明底 + 模糊,保证文字清晰同时保留壁纸美感 */
|
||||||
|
body.has-wallpaper .page {
|
||||||
|
background: rgba(255,251,254,0.65);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] body.has-wallpaper .page {
|
||||||
|
background: rgba(28,27,31,0.6);
|
||||||
|
}
|
||||||
|
|
||||||
/* Forum sidebar glass with wallpaper */
|
/* Forum sidebar glass with wallpaper */
|
||||||
.has-wallpaper .forum-sidebar .forum-cat-item {
|
.has-wallpaper .forum-sidebar .forum-cat-item {
|
||||||
backdrop-filter: blur(4px);
|
backdrop-filter: blur(4px);
|
||||||
@@ -1802,7 +1814,13 @@ button.glass-card, .btn.glass-card, .nav-tab.glass-card, .chip.glass-card {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding: 22px 28px 28px;
|
padding: 22px 28px 28px;
|
||||||
border-top: 1px solid var(--md-ref-outline-variant);
|
border-top: 1px solid var(--md-ref-outline-variant);
|
||||||
background: var(--md-ref-background);
|
/* 磨砂玻璃:半透明底 + 模糊,壁纸下增强可读性 */
|
||||||
|
background: rgba(255, 251, 254, 0.55);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
-webkit-backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
[data-theme="dark"] .footer-classic {
|
||||||
|
background: rgba(28, 27, 31, 0.6);
|
||||||
}
|
}
|
||||||
.footer-classic .fc-left {
|
.footer-classic .fc-left {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@@ -1840,9 +1858,15 @@ button.glass-card, .btn.glass-card, .nav-tab.glass-card, .chip.glass-card {
|
|||||||
|
|
||||||
/* ---- 分栏导航 ---- */
|
/* ---- 分栏导航 ---- */
|
||||||
.footer-columns {
|
.footer-columns {
|
||||||
background: var(--md-ref-background);
|
/* 磨砂玻璃:半透明底 + 模糊,壁纸下增强可读性 */
|
||||||
|
background: rgba(255, 251, 254, 0.55);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
-webkit-backdrop-filter: blur(20px);
|
||||||
border-top: 1px solid var(--md-ref-outline-variant);
|
border-top: 1px solid var(--md-ref-outline-variant);
|
||||||
}
|
}
|
||||||
|
[data-theme="dark"] .footer-columns {
|
||||||
|
background: rgba(28, 27, 31, 0.6);
|
||||||
|
}
|
||||||
.footer-columns .fc-grid {
|
.footer-columns .fc-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr 1fr;
|
grid-template-columns: 2fr 1fr 1fr;
|
||||||
@@ -2449,3 +2473,109 @@ button.glass-card, .btn.glass-card, .nav-tab.glass-card, .chip.glass-card {
|
|||||||
0%, 55% { left: -60%; }
|
0%, 55% { left: -60%; }
|
||||||
100% { left: 130%; }
|
100% { left: 130%; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== 博客文章详情页壁纸下磨砂背景(增强可读性) ===== */
|
||||||
|
.blog-article {
|
||||||
|
background: rgba(255, 251, 254, 0.5);
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
-webkit-backdrop-filter: blur(16px);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
[data-theme="dark"] .blog-article {
|
||||||
|
background: rgba(28, 27, 31, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 文章详情页布局:正文卡片(居中固定宽)+ 右侧悬浮目录 =====
|
||||||
|
* 注意:.blog-article 带 backdrop-filter,会成为 position:fixed 后代的包含块,
|
||||||
|
* 因此目录卡片必须放在 .article-layout 层(磨砂卡片的兄弟),
|
||||||
|
* 其 fixed 才相对视口定位。正文宽 720 居中,目录左缘 = 50% + 388px(360+28)。 */
|
||||||
|
.article-layout {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.article-main {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 720px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.article-toc-side {
|
||||||
|
width: 220px;
|
||||||
|
/* 独立悬浮卡片:相对视口 fixed,锚定在正文右缘 + 28px 处,
|
||||||
|
不占文档流、不挤压正文,任何视口下都不会与阅读区重叠 */
|
||||||
|
position: fixed;
|
||||||
|
top: 88px;
|
||||||
|
left: calc(50% + 388px); /* 正文半宽 360px + 间距 28px */
|
||||||
|
max-height: calc(100vh - 120px);
|
||||||
|
overflow-y: auto;
|
||||||
|
background: rgba(255, 251, 254, 0.55);
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
-webkit-backdrop-filter: blur(16px);
|
||||||
|
border: 1px solid var(--md-ref-outline-variant);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
box-shadow: 0 4px 20px var(--md-shadow);
|
||||||
|
}
|
||||||
|
[data-theme="dark"] .article-toc-side {
|
||||||
|
background: rgba(28, 27, 31, 0.6);
|
||||||
|
}
|
||||||
|
.article-toc-side .toc-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--md-ref-on-surface);
|
||||||
|
}
|
||||||
|
.article-toc-side .toc-count {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
|
.article-toc-side .toc-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
.article-toc-side .toc-item a {
|
||||||
|
display: block;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--md-ref-on-surface-variant);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 0.15s, color 0.15s;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.article-toc-side .toc-item a:hover {
|
||||||
|
background: var(--md-ref-surface-container-high);
|
||||||
|
color: var(--md-ref-primary);
|
||||||
|
}
|
||||||
|
/* 小屏隐藏:视口容不下「正文 720 + 目录 220 + 间距 28 + 边距」时收起,
|
||||||
|
内容区不受影响(目录 fixed 不占文档流) */
|
||||||
|
@media (max-width: 1299px) {
|
||||||
|
.article-toc-side { display: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 文章 meta 间距(作者 · 时间 · 阅读 · 字数) ===== */
|
||||||
|
.article-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--md-ref-on-surface-variant);
|
||||||
|
}
|
||||||
|
.article-meta .meta-stat {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@ const router = express.Router();
|
|||||||
|
|
||||||
const PUBLIC_KEYS = ['site_name','site_description','site_url','primary_color',
|
const PUBLIC_KEYS = ['site_name','site_description','site_url','primary_color',
|
||||||
'recaptcha_site_key','turnstile_site_key',
|
'recaptcha_site_key','turnstile_site_key',
|
||||||
'theme_wallpaper','theme_wallpaper_scale','nav_style','card_style',
|
'theme_wallpaper','theme_wallpaper_scale','theme_wallpaper_enabled','nav_style','card_style',
|
||||||
'glass_blur','glass_opacity','theme_force_dark',
|
'glass_blur','glass_opacity','theme_force_dark',
|
||||||
'captcha_type','captcha_login','captcha_register','captcha_forum',
|
'captcha_type','captcha_login','captcha_register','captcha_forum',
|
||||||
'homepage_avatar','homepage_bio','homepage_content','blog_show_sidebar',
|
'homepage_avatar','homepage_bio','homepage_content','blog_show_sidebar',
|
||||||
@@ -15,7 +15,7 @@ const PUBLIC_KEYS = ['site_name','site_description','site_url','primary_color',
|
|||||||
|
|
||||||
const ALL_KEYS = ['site_name','site_description','site_url','primary_color','recaptcha_site_key','turnstile_site_key',
|
const ALL_KEYS = ['site_name','site_description','site_url','primary_color','recaptcha_site_key','turnstile_site_key',
|
||||||
'smtp_host','smtp_port','smtp_user','smtp_from_email','smtp_from_name',
|
'smtp_host','smtp_port','smtp_user','smtp_from_email','smtp_from_name',
|
||||||
'theme_wallpaper','theme_wallpaper_scale','nav_style','card_style','glass_blur','glass_opacity','theme_force_dark',
|
'theme_wallpaper','theme_wallpaper_scale','theme_wallpaper_enabled','nav_style','card_style','glass_blur','glass_opacity','theme_force_dark',
|
||||||
'captcha_type','captcha_login','captcha_register','captcha_forum',
|
'captcha_type','captcha_login','captcha_register','captcha_forum',
|
||||||
'homepage_avatar','homepage_bio','homepage_content','blog_show_sidebar',
|
'homepage_avatar','homepage_bio','homepage_content','blog_show_sidebar',
|
||||||
'site_favicon','homepage_contacts','music_embed_enabled','music_embed_code','music_embed_position','music_embed_autohide','music_embed_idle_timeout',
|
'site_favicon','homepage_contacts','music_embed_enabled','music_embed_code','music_embed_position','music_embed_autohide','music_embed_idle_timeout',
|
||||||
|
|||||||
Reference in New Issue
Block a user