docs: code-block copy buttons + 'Connect your broker' guide (0.58.0)
- fix fenced code blocks: reset the doubled inline-code background on 'pre code', readable monospace styling (applies to all technical docs) - DocsApp decorates rendered code blocks with a hover copy button - seed a 'Connect your broker' guide (guides/) — the lasting reference for the supply-side last mile: heartbeat loop (curl + Node) to stay online, the relay WebSocket, and how it fits together (accurate from the API) - verified live on docs.amerc.ai: guide renders, 3 code blocks, 3 copy buttons wired, clean styling
This commit is contained in:
parent
fb3c523d4a
commit
6a8fc0a5c0
@ -4,7 +4,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#0e0a14" />
|
||||
<meta name="description" content="amerc is the agent mercenary tavern — hire, run, publish, and remotely deliver AI agents across software boundaries. No infrastructure, just skills." />
|
||||
<meta name="version" content="0.57.0-loadstates" />
|
||||
<meta name="version" content="0.58.0-docscode" />
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="icon" href="/app-192.png" type="image/png" sizes="192x192" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amerc-site",
|
||||
"version": "0.57.0-loadstates",
|
||||
"version": "0.58.0-docscode",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { marked } from 'marked';
|
||||
import ConsoleShell from './ConsoleShell.jsx';
|
||||
import { api } from './api.js';
|
||||
import { copyToast } from './toast.js';
|
||||
|
||||
marked.setOptions({ breaks: true });
|
||||
|
||||
@ -13,6 +14,7 @@ function DocsWorkspace({ canEdit }) {
|
||||
const [draft, setDraft] = useState({ title: '', folder: '', body: '' });
|
||||
const [err, setErr] = useState('');
|
||||
const [q, setQ] = useState('');
|
||||
const renderRef = useRef(null);
|
||||
|
||||
const loadList = useCallback(async () => {
|
||||
try { const d = await api('/docs'); setDocs(d.docs || []); } catch (e) { setErr(e.message); }
|
||||
@ -22,6 +24,18 @@ function DocsWorkspace({ canEdit }) {
|
||||
if (sel == null) { setDoc(null); return; }
|
||||
api(`/docs/${sel}`).then((d) => { setDoc(d.doc); setDraft({ title: d.doc.title, folder: d.doc.folder, body: d.doc.body }); setEditing(false); }).catch((e) => setErr(e.message));
|
||||
}, [sel]);
|
||||
// decorate rendered code blocks with a hover copy button
|
||||
useEffect(() => {
|
||||
const el = renderRef.current;
|
||||
if (!el || editing) return;
|
||||
el.querySelectorAll('pre').forEach((pre) => {
|
||||
if (pre.parentElement?.classList.contains('docs-code')) return;
|
||||
const wrap = document.createElement('div'); wrap.className = 'docs-code';
|
||||
const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'docs-copy'; btn.textContent = 'copy';
|
||||
btn.addEventListener('click', () => copyToast(pre.innerText, 'Copied'));
|
||||
pre.parentNode.insertBefore(wrap, pre); wrap.appendChild(btn); wrap.appendChild(pre);
|
||||
});
|
||||
}, [doc, editing]);
|
||||
|
||||
const create = async () => {
|
||||
const title = window.prompt('Document title', 'New document'); if (!title) return;
|
||||
@ -73,7 +87,7 @@ function DocsWorkspace({ canEdit }) {
|
||||
<p className="docs-byline">updated by {doc.updated_by || '—'}</p>
|
||||
{editing
|
||||
? <textarea className="docs-editor" value={draft.body} onChange={(e) => setDraft({ ...draft, body: e.target.value })} />
|
||||
: <article className="docs-render" dangerouslySetInnerHTML={{ __html: marked.parse(doc.body || '') }} />}
|
||||
: <article ref={renderRef} className="docs-render" dangerouslySetInnerHTML={{ __html: marked.parse(doc.body || '') }} />}
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
|
||||
@ -7,7 +7,7 @@ import Account from './Account.jsx';
|
||||
import TavernGame from './TavernGame.jsx';
|
||||
import { api } from './api.js';
|
||||
|
||||
const RELEASE = '0.57.0-loadstates';
|
||||
const RELEASE = '0.58.0-docscode';
|
||||
|
||||
const NAV = [
|
||||
{ id: 'home', label: 'Tavern' },
|
||||
|
||||
@ -1413,3 +1413,12 @@ button {
|
||||
.ap-skel-row { display: flex; align-items: center; gap: 11px; }
|
||||
.mn-skel { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
|
||||
.mn-skel .ap-skel-row .sk-p { height: 12px; }
|
||||
|
||||
/* docs code blocks + copy button (0.58) */
|
||||
.docs-render pre { position: relative; }
|
||||
.docs-render pre code { background: none; padding: 0; color: #cfe8ff; font-size: 0.86em; line-height: 1.6; }
|
||||
.docs-code { position: relative; margin: 14px 0; }
|
||||
.docs-code pre { margin: 0; }
|
||||
.docs-copy { position: absolute; top: 8px; right: 8px; font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-size: 11px; padding: 3px 10px; border-radius: 6px; background: #1b2536; color: #9fc8e8; border: 1px solid #2a3a52; cursor: pointer; opacity: 0; transition: opacity .15s, background .15s, color .15s; }
|
||||
.docs-code:hover .docs-copy { opacity: 1; }
|
||||
.docs-copy:hover { background: var(--accent); color: #061018; border-color: transparent; }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user