SuperAPI AI Directory

html-effectiveness-editor

Coding & development

View repository

Updated 10-15 20:05

About this skill

09-editor — custom editing interface

"Sometimes it's hard to describe what you want in a text box. Ask for a throwaway editor for the exact thing you're working on — and always end with an export button that turns whatever you did in the UI back into something you can paste into the agent or commit."

Core constraints (non-negotiable)

Every page produced by the 09-editor paradigm must have a "copy result" button. Let all of the user's operations in the UI → a pasteable block of text → go back to the agent.

An "editor" with no export outlet = a toy, not a tool.


When to use

User says Which paradigm Template
"help me prioritize / triage 20 tickets" Drag-and-drop triage board Self-built
"toggle a set of feature flags / configure some parameters" Config editor Self-built
"tune a prompt, I want to see a few samples" Prompt tuner ../../templates/prompt.html
"I want to edit in the UI and then copy it back" Any —

Paradigm 9.1 · Drag-and-drop triage board

Spatial shape: N columns (typically 4: Now / Next / Later / Cut), each column a <ul>, cards can be dragged between columns. "Copy as markdown" export at the top.

HTML5 drag-and-drop key JS:

let dragged = null;
document.querySelectorAll('.card').forEach(c => {
  c.draggable = true;
  c.addEventListener('dragstart', () => { dragged = c; c.classList.add('dragging'); });
  c.addEventListener('dragend',   () => c.classList.remove('dragging'));
});

document.querySelectorAll('.column ul').forEach(col => {
  col.addEventListener('dragover', e => {
    e.preventDefault();
    const after = [...col.querySelectorAll('.card:not(.dragging)')]
      .find(c => e.clientY < c.getBoundingClientRect().top + c.offsetHeight / 2);
    if (after) col.insertBefore(dragged, after);
    else col.appendChild(dragged);
  });
});

// 导出
document.querySelector('#copy-md').onclick = async () => {
  const md = [...document.querySelectorAll('.column')].map(col => {
    const title = col.querySelector('h2').textContent;
    const items = [...col.querySelectorAll('.card')]
      .map(c => `- ${c.querySelector('.card-title').textContent.trim()}`)
      .join('\n');
    return `## ${title}\n${items}`;
  }).join('\n\n');
  await navigator.clipboard.writeText(md);
  document.querySelector('#copy-md').textContent = 'Copied ✓';
};

Key CSS(columns and drag states):

.board { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.column { background: var(--gray-100); border-radius: 12px; padding: 16px;
          min-height: 400px; }
.column h2 { font-size: 14px; text-transform: uppercase;
             letter-spacing: 0.06em; color: var(--gray-700); margin: 0 0 12px; }
.column ul { list-style: none; padding: 0; margin: 0;
             display: flex; flex-direction: column; gap: 8px; min-height: 100px; }
.card { background: var(--white); border: 1px solid var(--gray-300);
        border-radius: 8px; padding: 12px; cursor: grab; }
.card.dragging { opacity: 0.4; cursor: grabbing; }
.card:hover { border-color: var(--clay); }

No standalone template (the data varies per person, generate as needed).


Paradigm 9.2 · Config editor (feature flag editor)

Spatial shape: grouped fieldset, each flag is a toggle.change event checks dependencies (if A is on, B must be on too). "Copy diff" outputsonly the changed keys。

Key JS(diff output):

function readState() {
  const state = {};
  document.querySelectorAll('input[type="checkbox"][data-flag]').forEach(el => {
    state[el.dataset.flag] = el.checked;
  });
  return state;
}
const initial = readState();

// 依赖检查
document.addEventListener('change', () => {
  document.querySelectorAll('[data-requires]').forEach(el => {
    const reqs = el.dataset.requires.split(',');
    const unmet = reqs.find(r => !readState()[r]);
    el.parentElement.querySelector('.warning').hidden = !unmet || !el.checked;
    if (unmet && el.checked) {
      el.parentElement.querySelector('.warning').textContent =
        `Requires ${unmet} to be enabled`;
    }
  });
});

document.querySelector('#copy-diff').onclick = async () => {
  const now = readState();
  const diff = Object.fromEntries(
    Object.entries(now).filter(([k, v]) => initial[k] !== v)
  );
  if (Object.keys(diff).length === 0) {
    document.querySelector('#copy-diff').textContent = 'No changes';
    return;
  }
  await navigator.clipboard.writeText(JSON.stringify(diff, null, 2));
  document.querySelector('#copy-diff').textContent = 'Copied ✓';
};

No standalone template (the flag set varies per project).


Paradigm 9.3 · Prompt tuner

Spatial shape: left <textarea>(template, including {{slot}}) + N sample input cards on the top right + N live-filled results on the bottom right. Typing re-renders immediately. "Copy prompt" outputs the current template.

Key JS:

const tpl = document.querySelector('#tpl');
const samples = JSON.parse(document.querySelector('#samples').textContent);

function fill(template, data) {
  return template.replace(/\{\{(\w+)\}\}/g, (_, k) =>
    data[k] != null ? data[k] : `{{${k}}}`
  );
}

function render() {
  document.querySelectorAll('.preview').forEach((p, i) => {
    p.textContent = fill(tpl.value, samples[i]);
  });
  document.querySelector('#tpl-meta').textContent =
    tpl.value.length + ' chars · ~' + Math.ceil(tpl.value.length / 4) + ' tokens';
}

tpl.addEventListener('input', render);
document.querySelector('#copy-tpl').onclick = async () => {
  await navigator.clipboard.writeText(tpl.value);
};
render();

Sample data is embedded in the page (no external API calls):

<script type="application/json" id="samples">
[
  { "label": "Frustrated", "customer_name": "Mira", "tone": "calm", "issue": "..." },
  { "label": "Confused",   "customer_name": "Devon", "tone": "warm",  "issue": "..." }
]
</script>

Ready-to-use template:../../templates/prompt.html — includes 3 real samples and a live preview.


Generic export button template (standard implementation)

async function copyResult(text, btn) {
  try {
    await navigator.clipboard.writeText(text);
    const old = btn.textContent;
    btn.textContent = 'Copied ✓';
    setTimeout(() => { btn.textContent = old; }, 1500);
  } catch (e) {
    btn.textContent = 'Press Ctrl+C';
    // fallback: select hidden textarea + execCommand('copy')
  }
}

Common principles

  • Always have an export button— this is the hallmark of 09-editor; without it, it is not this paradigm
  • Export format serves the agent— markdown / JSON diff / plain text, depending on how the user will use it afterward
  • Real data mock— not "Sample 1, Sample 2", but "Frustrated · long-time user / Confused · new user"
  • Dragging must have hover visual feedback——.card.dragging { opacity: 0.4 } is the bottom line
  • The config editor's dependency warning must appear immediately— use the change event, not submit
  • The prompt tuner's token count estimate uses chars/4—No real tokenizer needed