/** * Supan Content — Gutenberg block editor sidebar plugin. * * Shows semantic link suggestions for the current post. * "Copy link" copies the HTML anchor tag — paste directly into Gutenberg. */ const { registerPlugin } = wp.plugins; const { PluginSidebar, PluginSidebarMoreMenuItem } = wp.editPost; const { PanelBody, Button, Spinner } = wp.components; const { useSelect } = wp.data; const { useState } = wp.element; interface Suggestion { slug: string; title: string; relevance: number; reason: string; } function SupanContentSidebar() { const [suggestions, setSuggestions] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [copied, setCopied] = useState(null); const { postId } = useSelect((select) => { const editor = select('core/editor') as any; return { postId: editor.getCurrentPostId() as number, }; }); async function fetchSuggestions() { if (!postId) { setError('Save the post first to get suggestions.'); return; } setLoading(true); setError(''); setSuggestions([]); try { const res = await fetch(`${window.supacoCHBridge.restUrl}semantic-suggest`, { method: 'POST', headers: { 'X-WP-Nonce': window.supacoCHBridge.nonce, 'Content-Type': 'application/json', }, body: JSON.stringify({ post_id: postId }), }); if (!res.ok) { const err = await res.json().catch(() => ({})); if (res.status === 429) { setError(err.reason || 'Monthly limit reached. Upgrade to continue.'); } else { setError(err.message || `Error ${res.status}`); } return; } const data = await res.json(); setSuggestions(data.suggestions || []); } catch { setError('Connection failed'); } finally { setLoading(false); } } function copyLink(suggestion: Suggestion) { const linkHtml = `${suggestion.title}`; navigator.clipboard.writeText(linkHtml).then(() => { setCopied(suggestion.slug); setTimeout(() => setCopied(null), 2000); }); } return ( <> Supan Content Links {error && (

{error}

)} {suggestions.length > 0 && (

Click "Copy" then paste in the editor

{suggestions.map((s) => (
{s.title}
Relevance: {Math.round(s.relevance * 100)}%
))}
)} {!loading && suggestions.length === 0 && !error && (

Click above to find semantically related posts to link from this one.

)}
); } registerPlugin('supan-content-sidebar', { render: SupanContentSidebar });