diff --git a/admin/src/pages/posts-page.tsx b/admin/src/pages/posts-page.tsx
index ee1584e..0efbeef 100644
--- a/admin/src/pages/posts-page.tsx
+++ b/admin/src/pages/posts-page.tsx
@@ -237,6 +237,11 @@ function formatWorkbenchStateLabel(
.join(' / ')}`
}
+function buildVirtualPostPath(slug: string) {
+ const normalizedSlug = slug.trim() || 'new-post'
+ return `article://posts/${normalizedSlug}`
+}
+
function parseImageList(value: string) {
return value
.split('\n')
@@ -1145,9 +1150,7 @@ export function PostsPage() {
setMetadataDialog({
target: 'create',
title: createForm.title.trim() || createForm.slug.trim() || '新建草稿',
- path: createForm.slug.trim()
- ? `backend/content/posts/${createForm.slug.trim()}.md`
- : 'backend/content/posts/new-post.md',
+ path: buildVirtualPostPath(createForm.slug),
proposal: nextProposal,
})
})
@@ -2130,8 +2133,7 @@ export function PostsPage() {
{editor.markdown.split(/\r?\n/).length} 行
-
{editor.path}
-
+
创建于 {formatDateTime(editor.createdAt)} · 更新于 {formatDateTime(editor.updatedAt)}
@@ -2945,11 +2947,7 @@ export function PostsPage() {
value={createForm.markdown}
originalValue={buildCreateMarkdownForWindow(defaultCreateForm)}
diffValue={buildCreateMarkdownForWindow(createForm)}
- path={
- createForm.slug.trim()
- ? `backend/content/posts/${createForm.slug.trim()}.md`
- : 'backend/content/posts/new-post.md'
- }
+ path={buildVirtualPostPath(createForm.slug)}
workspaceHeightClassName="h-[clamp(620px,74dvh,920px)]"
mode={createMode}
visiblePanels={createPanels}
@@ -3047,9 +3045,6 @@ export function PostsPage() {
{metadataDialog.title}
-
- {metadataDialog.path}
-
diff --git a/admin/src/pages/site-settings-page.tsx b/admin/src/pages/site-settings-page.tsx
index 6c312ef..ce8bbc0 100644
--- a/admin/src/pages/site-settings-page.tsx
+++ b/admin/src/pages/site-settings-page.tsx
@@ -15,6 +15,7 @@ import { adminApi, ApiError } from '@/lib/api'
import type {
AdminSiteSettingsResponse,
AiProviderConfig,
+ HumanVerificationMode,
MusicTrack,
SiteSettingsPayload,
} from '@/lib/types'
@@ -70,6 +71,30 @@ const NOTIFICATION_CHANNEL_OPTIONS = [
{ value: 'ntfy', label: 'ntfy' },
] as const
+const HUMAN_VERIFICATION_MODE_OPTIONS = [
+ { value: 'off', label: '关闭' },
+ { value: 'captcha', label: '普通验证码' },
+ { value: 'turnstile', label: 'Turnstile' },
+] as const
+
+function normalizeHumanVerificationMode(
+ value: string | null | undefined,
+ fallback: HumanVerificationMode,
+): HumanVerificationMode {
+ switch ((value ?? '').trim().toLowerCase()) {
+ case 'off':
+ return 'off'
+ case 'captcha':
+ case 'normal':
+ case 'simple':
+ return 'captcha'
+ case 'turnstile':
+ return 'turnstile'
+ default:
+ return fallback
+ }
+}
+
function isCloudflareProvider(provider: string | null | undefined) {
const normalized = provider?.trim().toLowerCase()
return normalized === 'cloudflare' || normalized === 'cloudflare-workers-ai' || normalized === 'workers-ai'
@@ -94,6 +119,14 @@ function normalizeSettingsResponse(
...input,
ai_providers: aiProviders,
search_synonyms: searchSynonyms,
+ comment_verification_mode: normalizeHumanVerificationMode(
+ input.comment_verification_mode,
+ input.comment_turnstile_enabled ? 'turnstile' : 'captcha',
+ ),
+ subscription_verification_mode: normalizeHumanVerificationMode(
+ input.subscription_verification_mode,
+ input.subscription_turnstile_enabled ? 'turnstile' : 'off',
+ ),
turnstile_site_key: input.turnstile_site_key ?? null,
turnstile_secret_key: input.turnstile_secret_key ?? null,
web_push_vapid_public_key: input.web_push_vapid_public_key ?? null,
@@ -123,6 +156,9 @@ function Field({
}
function toPayload(form: AdminSiteSettingsResponse): SiteSettingsPayload {
+ const commentTurnstileEnabled = form.comment_verification_mode === 'turnstile'
+ const subscriptionTurnstileEnabled = form.subscription_verification_mode === 'turnstile'
+
return {
siteName: form.site_name,
siteShortName: form.site_short_name,
@@ -143,8 +179,10 @@ function toPayload(form: AdminSiteSettingsResponse): SiteSettingsPayload {
musicPlaylist: form.music_playlist,
aiEnabled: form.ai_enabled,
paragraphCommentsEnabled: form.paragraph_comments_enabled,
- commentTurnstileEnabled: form.comment_turnstile_enabled,
- subscriptionTurnstileEnabled: form.subscription_turnstile_enabled,
+ commentVerificationMode: form.comment_verification_mode,
+ commentTurnstileEnabled,
+ subscriptionVerificationMode: form.subscription_verification_mode,
+ subscriptionTurnstileEnabled,
webPushEnabled: form.web_push_enabled,
turnstileSiteKey: form.turnstile_site_key,
turnstileSecretKey: form.turnstile_secret_key,
@@ -659,22 +697,28 @@ export function SiteSettingsPage() {
-
+
+
+
+
+
@@ -926,22 +970,28 @@ export function SiteSettingsPage() {
-
+
+
+
+
+