fix: 链接对话框站内搜索收进高级选项

默认只显示网址与文字;展开高级选项后再搜站内内容,点选时同步更新链接文字。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-01 21:33:24 +08:00
parent d5aa36416c
commit ea9e0058d4
2 changed files with 105 additions and 54 deletions

View File

@@ -14,7 +14,7 @@ import { api } from '@/api/client';
import type { PostItem, SitePageSummary } from '@/api/types';
import { pagePath, postPath } from '@/utils/permalink';
import { useForumLimits } from '@/hooks/useForumLimits';
import { Loader2 } from 'lucide-react';
import { ChevronDown, Loader2 } from 'lucide-react';
export interface ArticleLinkConfirm {
url: string;
@@ -69,6 +69,7 @@ export function ArticleLinkDialog({
const { limits } = useForumLimits();
const [url, setUrl] = useState('');
const [text, setText] = useState('');
const [advancedOpen, setAdvancedOpen] = useState(false);
const [query, setQuery] = useState('');
const [debouncedQuery, setDebouncedQuery] = useState('');
const [posts, setPosts] = useState<PostItem[]>([]);
@@ -80,15 +81,19 @@ export function ArticleLinkDialog({
if (!open) return;
setUrl(initialUrl || '');
setText(initialText || '');
setAdvancedOpen(false);
setQuery('');
setDebouncedQuery('');
setPosts([]);
setPages([]);
setLoaded(false);
}, [open, initialUrl, initialText]);
useEffect(() => {
if (!open) return;
if (!open || !advancedOpen) return;
const t = window.setTimeout(() => setDebouncedQuery(query.trim()), SEARCH_DEBOUNCE_MS);
return () => window.clearTimeout(t);
}, [query, open]);
}, [query, open, advancedOpen]);
const loadSiteHits = useCallback(async (keyword: string) => {
setLoading(true);
@@ -120,10 +125,11 @@ export function ArticleLinkDialog({
}
}, []);
// 仅展开高级选项时再请求站内内容,避免默认打开就打接口
useEffect(() => {
if (!open) return;
if (!open || !advancedOpen) return;
void loadSiteHits(debouncedQuery);
}, [open, debouncedQuery, loadSiteHits]);
}, [open, advancedOpen, debouncedQuery, loadSiteHits]);
const hits: SiteHit[] = useMemo(() => {
const postHits: SiteHit[] = posts.map(p => ({
@@ -143,7 +149,8 @@ export function ArticleLinkDialog({
const pickHit = (hit: SiteHit) => {
setUrl(hit.url);
setText(prev => (prev.trim() ? prev : hit.title));
// 选站内内容时同步用标题作为链接文字
setText(hit.title);
};
const handleConfirm = () => {
@@ -171,7 +178,6 @@ export function ArticleLinkDialog({
</DialogHeader>
<section className="article-link-dialog__section">
<h3 className="article-link-dialog__section-title"> URL</h3>
<div className="article-link-dialog__field">
<Label htmlFor="article-link-url"></Label>
<Input
@@ -206,8 +212,19 @@ export function ArticleLinkDialog({
</div>
</section>
<section className="article-link-dialog__section">
<h3 className="article-link-dialog__section-title"></h3>
<section className="article-link-dialog__section article-link-dialog__advanced">
<button
type="button"
className={`article-link-dialog__advanced-toggle${advancedOpen ? ' is-open' : ''}`}
aria-expanded={advancedOpen}
onClick={() => setAdvancedOpen(v => !v)}
>
<span></span>
<ChevronDown size={16} aria-hidden className="article-link-dialog__advanced-chevron" />
</button>
{advancedOpen ? (
<div className="article-link-dialog__advanced-body">
<h3 className="article-link-dialog__section-title"></h3>
<div className="article-link-dialog__field">
<Label htmlFor="article-link-search"></Label>
<Input
@@ -255,6 +272,8 @@ export function ArticleLinkDialog({
</div>
) : null}
</div>
</div>
) : null}
</section>
<DialogFooter className="article-link-dialog__footer">

View File

@@ -10990,6 +10990,38 @@ button.profile-stat:hover strong {
font-size: 12px;
color: var(--color-text-2);
}
.article-link-dialog__advanced {
padding-bottom: 8px;
}
.article-link-dialog__advanced-toggle {
display: inline-flex;
align-items: center;
gap: 6px;
margin: 0;
padding: 0;
border: none;
background: transparent;
font-size: 13px;
font-weight: 600;
color: var(--color-text-2);
cursor: pointer;
user-select: none;
}
.article-link-dialog__advanced-toggle:hover {
color: var(--color-text-1);
}
.article-link-dialog__advanced-chevron {
transition: transform 0.15s ease;
}
.article-link-dialog__advanced-toggle.is-open .article-link-dialog__advanced-chevron {
transform: rotate(180deg);
}
.article-link-dialog__advanced-body {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 12px;
}
.article-link-dialog__hits {
position: relative;
border: 1px solid var(--j13-border);