comark-ui 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/{client-kUEiRbtp.mjs → client-zWY8yhUx.mjs} +1 -14
- package/dist/client.mjs +1 -1
- package/dist/{editor-9IcfELjG.mjs → editor-CW05gHp7.mjs} +46 -6
- package/dist/{editor-yoVL7Ajq.d.mts → editor-Dk8TRweM.d.mts} +13 -2
- package/dist/editor-vue.d.mts +1 -1
- package/dist/editor-vue.mjs +1 -1
- package/dist/editor.d.mts +2 -2
- package/dist/editor.mjs +1 -1
- package/dist/html.d.mts +1 -1
- package/dist/html.mjs +4 -2
- package/dist/{index-Cq3zytGw.d.mts → index-CNYr62nX.d.mts} +4 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react.d.mts +1 -1
- package/dist/react.mjs +4 -2
- package/dist/skills/before-after-evidence/SKILL.md +1 -1
- package/dist/skills/comark-ui/SKILL.md +3 -0
- package/dist/skills/comark-ui/references/annotate.md +1 -1
- package/dist/skills/comark-ui/references/time.md +28 -0
- package/dist/skills.mjs +8 -4
- package/dist/{src-MvpWiv9v.mjs → src-C3nMECXA.mjs} +2 -0
- package/dist/styles-vZMqDkIY.mjs +15 -0
- package/dist/svelte/index.js +2 -0
- package/dist/vue.d.mts +610 -1
- package/dist/vue.mjs +42 -3
- package/package.json +52 -51
package/README.md
CHANGED
|
@@ -33,6 +33,14 @@ comarkUi({
|
|
|
33
33
|
|
|
34
34
|
It also returns `tags` and `blocks`. `tags` is every element a parsed document can hold besides the components; with the components' names, it's the allowlist for Comark's `security` plugin. `blocks` are the blocks the plugins replace while parsing, such as `::code-group`, which a linter needs beside the components' names.
|
|
35
35
|
|
|
36
|
+
If a server already parsed your document, import Vue's `components` directly. This keeps the chart parsers and the rest of the parse preset out of the renderer bundle:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { components } from "comark-ui/vue";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The map includes every Vue renderer and the typeset styles. Use `comarkUi(options).components` when you need the map to follow plugin options.
|
|
43
|
+
|
|
36
44
|
## Renderers
|
|
37
45
|
|
|
38
46
|
| Renderer | Import |
|
|
@@ -55,7 +63,7 @@ Vue, React, and Svelte leave out annotate and diff, which render only to HTML.
|
|
|
55
63
|
| `ComarkKit` | The schema: StarterKit, task lists, inline images (drawn as players for video and audio), tables, footnotes, definition lists, CriticMarkup, and Comark's components, slots, and comments, each keeping the attributes it has no field for. |
|
|
56
64
|
| `fromMarkdown`, `toMarkdown` | Convert between Markdown and the editor's JSON with Comark's own parser and writer. Front matter stays beside the document. |
|
|
57
65
|
| `checkMarkdown(markdown, { plugins })` | Whether the editor can save the document without changing what readers see, judged with the plugins the page renders with. A document it can't keep opens read-only. |
|
|
58
|
-
| `Upload` | Uploads pasted and dropped files. Each shows a placeholder with its progress until `upload(file, progress)` returns its URL. |
|
|
66
|
+
| `Upload` | Uploads pasted and dropped files, and the files the `chooseFiles` command picks. Each shows a placeholder with its progress until `upload(file, progress)` returns its URL. |
|
|
59
67
|
| `createEditorCodec({ plugins })` | `{ extensions, split, join, fromMarkdown, toMarkdown, verify }` for a collaborative room, such as ViteHub Realtime's `editor` option. A room keeps the body as the editor's document and the frontmatter as its fields, so a text edit never overwrites the metadata. |
|
|
60
68
|
|
|
61
69
|
`comark-ui/editor/vue` binds the editor to a Markdown string with `useComarkEditor(markdown)` or `<ComarkEditor v-model="markdown" />`. Run `pnpm playground` in this package to try it.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as addStyles } from "./styles-vZMqDkIY.mjs";
|
|
1
2
|
import { theme } from "comark-zoom/theme";
|
|
2
3
|
//#region src/script.ts
|
|
3
4
|
/**
|
|
@@ -164,20 +165,6 @@ function start() {
|
|
|
164
165
|
window.__comarkMermaid = state;
|
|
165
166
|
return state.stop;
|
|
166
167
|
}
|
|
167
|
-
//#endregion
|
|
168
|
-
//#region ../../shared/styles.ts
|
|
169
|
-
/**
|
|
170
|
-
* Adds a package's styles to the page once, unless the page already carries them as a `style` or a `link` with
|
|
171
|
-
* `data-comark-<name>`, which is how the HTML renderer inlines them and how an app that imports `style.css` marks them.
|
|
172
|
-
*/
|
|
173
|
-
function addStyles(name, css) {
|
|
174
|
-
const attribute = `data-comark-${name}`;
|
|
175
|
-
if (document.querySelector(`style[${attribute}],link[${attribute}]`)) return;
|
|
176
|
-
const style = document.createElement("style");
|
|
177
|
-
style.setAttribute(attribute, "");
|
|
178
|
-
style.textContent = css;
|
|
179
|
-
document.head.append(style);
|
|
180
|
-
}
|
|
181
168
|
/**
|
|
182
169
|
* comark-pele's diagrams on the shared `--comark-*` tokens, on a card like comark-diagrams'. Pele paints with its
|
|
183
170
|
* `--pele-*` variables, so setting them on the wrapper themes every diagram, light and dark, without drawing it
|
package/dist/client.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as typesetStylesheet, t as typesetCss } from "./typeset-css-BOtdXbMg.mjs";
|
|
2
|
-
import { i as startMermaid, n as mermaidBar, r as mermaidCss, t as addMermaidStyles } from "./client-
|
|
2
|
+
import { i as startMermaid, n as mermaidBar, r as mermaidCss, t as addMermaidStyles } from "./client-zWY8yhUx.mjs";
|
|
3
3
|
export { addMermaidStyles, mermaidBar, mermaidCss, startMermaid, typesetCss, typesetStylesheet };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { t as addStyles } from "./styles-vZMqDkIY.mjs";
|
|
1
2
|
import { n as scalar } from "./text-D8j9clg3.mjs";
|
|
2
3
|
import cjk from "comark-cjk";
|
|
3
4
|
import critic from "comark-critic";
|
|
4
5
|
import deflist from "comark-deflist";
|
|
5
6
|
import footnotes from "comark-footnotes";
|
|
6
7
|
import { defineComarkPlugin, parseMarkdown } from "comark";
|
|
8
|
+
import { theme } from "comark-zoom/theme";
|
|
7
9
|
import { Extension, Mark, Node } from "@tiptap/core";
|
|
8
10
|
import Image from "@tiptap/extension-image";
|
|
9
11
|
import { TaskItem, TaskList } from "@tiptap/extension-list";
|
|
@@ -654,6 +656,7 @@ const isTaskItem = (child) => isElement(child) && child[0] === "li" && classes(c
|
|
|
654
656
|
const isCheckbox = (child) => isElement(child) && child[0] === "input" && child[1].type === "checkbox";
|
|
655
657
|
function readList(tag, props, children, reading) {
|
|
656
658
|
const items = children.filter(isElement);
|
|
659
|
+
if (tag === "ol" && items.some(isTaskItem)) reading.lossy = true;
|
|
657
660
|
if (tag === "ul" && items.length && items.every(isTaskItem)) return node("taskList", withProps({}, rest(withoutClass(props, "contains-task-list"))), items.map((item) => readTaskItem(item, reading)));
|
|
658
661
|
const listItems = items.map((item) => {
|
|
659
662
|
const blocks = readBlocks(childrenOf(item), reading);
|
|
@@ -1167,7 +1170,18 @@ const acceptMedia = (file) => /^(?:image|video|audio)\//.test(file.type);
|
|
|
1167
1170
|
function findUpload(state, id) {
|
|
1168
1171
|
return uploadKey.getState(state)?.find(void 0, void 0, (spec) => spec.id === id)[0]?.from;
|
|
1169
1172
|
}
|
|
1173
|
+
/** The placeholder's styles, which the editor adds to the page with the first one. */
|
|
1174
|
+
const uploadCss = `@layer comark{${[
|
|
1175
|
+
theme(".cue-upload", "primary"),
|
|
1176
|
+
`.cue-upload{display:inline-grid;position:relative;min-width:12rem;max-width:15rem;overflow:hidden;vertical-align:middle;border:1px solid var(--_comark-border);border-radius:var(--_comark-radius);background:var(--_comark-accent);color:var(--_comark-foreground);font:500 .75rem/1.4 var(--_comark-font)}`,
|
|
1177
|
+
`.cue-upload>img,.cue-upload>video{grid-area:1/1;width:100%;max-height:10rem;object-fit:cover;opacity:.55}`,
|
|
1178
|
+
`.cue-upload-label{grid-area:1/1;align-self:end;padding:.375rem .5rem .5rem;font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}`,
|
|
1179
|
+
`.cue-upload>img~.cue-upload-label,.cue-upload>video~.cue-upload-label{background:color-mix(in srgb,var(--_comark-background) 80%,transparent)}`,
|
|
1180
|
+
`.cue-upload::after{content:"";position:absolute;inset:auto 0 0;height:2px;width:var(--cue-upload);background:var(--_comark-primary);transition:width .2s ease-out}`,
|
|
1181
|
+
`@media (prefers-reduced-motion:reduce){.cue-upload::after{transition:none}}`
|
|
1182
|
+
].join("")}}`;
|
|
1170
1183
|
function placeholder(pending) {
|
|
1184
|
+
addStyles("editor-upload", uploadCss);
|
|
1171
1185
|
const root = document.createElement("span");
|
|
1172
1186
|
root.className = "cue-upload";
|
|
1173
1187
|
root.contentEditable = "false";
|
|
@@ -1247,6 +1261,28 @@ function send(view, file, pos, upload, options, batch) {
|
|
|
1247
1261
|
options.onError?.(error, file);
|
|
1248
1262
|
});
|
|
1249
1263
|
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Opens the file picker and uploads what's picked at the cursor, with the same placeholders as a paste. Returns false
|
|
1266
|
+
* without an `upload` callback. A "/" menu's Image item calls it through the `chooseFiles` command.
|
|
1267
|
+
*/
|
|
1268
|
+
function chooseFiles(view, options) {
|
|
1269
|
+
if (!options.upload) return false;
|
|
1270
|
+
const input = document.createElement("input");
|
|
1271
|
+
input.type = "file";
|
|
1272
|
+
input.multiple = true;
|
|
1273
|
+
input.accept = options.pick ?? "image/*,video/*,audio/*";
|
|
1274
|
+
input.style.cssText = "position:fixed;left:-9999px";
|
|
1275
|
+
input.tabIndex = -1;
|
|
1276
|
+
input.addEventListener("change", () => {
|
|
1277
|
+
const files = Array.from(input.files ?? []);
|
|
1278
|
+
input.remove();
|
|
1279
|
+
if (files.length) Promise.all(startUploads(view, files, view.state.selection.from, options));
|
|
1280
|
+
}, { once: true });
|
|
1281
|
+
input.addEventListener("cancel", () => input.remove(), { once: true });
|
|
1282
|
+
document.body.append(input);
|
|
1283
|
+
input.click();
|
|
1284
|
+
return true;
|
|
1285
|
+
}
|
|
1250
1286
|
function insertImage(tr, pos, image) {
|
|
1251
1287
|
if (tr.doc.resolve(pos).parent.inlineContent) tr.insert(pos, image);
|
|
1252
1288
|
else tr.insert(pos, tr.doc.type.schema.nodes.paragraph.create(null, image));
|
|
@@ -1321,17 +1357,21 @@ const Upload = Extension.create({
|
|
|
1321
1357
|
addOptions: () => ({
|
|
1322
1358
|
upload: void 0,
|
|
1323
1359
|
accept: acceptMedia,
|
|
1360
|
+
pick: void 0,
|
|
1324
1361
|
onError: void 0
|
|
1325
1362
|
}),
|
|
1326
1363
|
addProseMirrorPlugins() {
|
|
1327
1364
|
return [uploadPlugin(this.options)];
|
|
1328
1365
|
},
|
|
1329
1366
|
addCommands() {
|
|
1330
|
-
return {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1367
|
+
return {
|
|
1368
|
+
uploadFiles: (files) => ({ view }) => {
|
|
1369
|
+
if (!this.options.upload) return false;
|
|
1370
|
+
Promise.all(startUploads(view, files, view.state.selection.from, this.options));
|
|
1371
|
+
return true;
|
|
1372
|
+
},
|
|
1373
|
+
chooseFiles: () => ({ view, dispatch }) => dispatch ? chooseFiles(view, this.options) : Boolean(this.options.upload)
|
|
1374
|
+
};
|
|
1335
1375
|
}
|
|
1336
1376
|
});
|
|
1337
1377
|
//#endregion
|
|
@@ -1378,4 +1418,4 @@ function createEditorCodec(options = {}) {
|
|
|
1378
1418
|
};
|
|
1379
1419
|
}
|
|
1380
1420
|
//#endregion
|
|
1381
|
-
export {
|
|
1421
|
+
export { DefinitionList as C, InlineFootnote as D, FootnoteReference as E, DefinitionDescription as S, FootnoteDefinition as T, ComarkSlot as _, startUploads as a, CriticHighlight as b, uploadPlugin as c, toMarkdown as d, ComarkBlock as f, ComarkKit as g, ComarkInline as h, findUpload as i, checkMarkdown as l, ComarkImage as m, Upload as n, uploadCss as o, ComarkComment as p, chooseFiles as r, uploadKey as s, createEditorCodec as t, fromMarkdown as u, CriticComment as v, DefinitionTerm as w, CriticInsertion as x, CriticDeletion as y };
|
|
@@ -88,8 +88,10 @@ interface UploadOptions {
|
|
|
88
88
|
* bytes go; `fetch` can't report them, so use XMLHttpRequest's `upload.onprogress`. Without it, nothing uploads.
|
|
89
89
|
*/
|
|
90
90
|
upload?: (file: File, progress: (fraction: number) => void) => Promise<string>;
|
|
91
|
-
/** Which files to take from a paste or
|
|
91
|
+
/** Which files to take from a paste, a drop, or the file picker. Images, video, and audio by default. */
|
|
92
92
|
accept: (file: File) => boolean;
|
|
93
|
+
/** The file types `chooseFiles()` offers in the file picker, as an `<input accept>` value. Media by default. */
|
|
94
|
+
pick?: string;
|
|
93
95
|
/** Called when `upload` rejects. The placeholder is gone by then. */
|
|
94
96
|
onError?: (error: unknown, file: File) => void;
|
|
95
97
|
}
|
|
@@ -110,12 +112,19 @@ interface View {
|
|
|
110
112
|
declare const uploadKey: PluginKey<DecorationSet>;
|
|
111
113
|
/** Where placeholder `id` sits now, after every edit since it was added. */
|
|
112
114
|
declare function findUpload(state: EditorState, id: number): number | undefined;
|
|
115
|
+
/** The placeholder's styles, which the editor adds to the page with the first one. */
|
|
116
|
+
declare const uploadCss: string;
|
|
113
117
|
/**
|
|
114
118
|
* Uploads `files` into the document at `pos`. Each shows a placeholder there until its URL comes back, then becomes an
|
|
115
119
|
* image node, which comark-media plays when its URL ends in a video or audio extension. The placeholder is a
|
|
116
120
|
* decoration, so a collaborative room never sees a file that hasn't finished.
|
|
117
121
|
*/
|
|
118
122
|
declare function startUploads(view: View, files: File[], pos: number, options: UploadOptions): Promise<string | undefined>[];
|
|
123
|
+
/**
|
|
124
|
+
* Opens the file picker and uploads what's picked at the cursor, with the same placeholders as a paste. Returns false
|
|
125
|
+
* without an `upload` callback. A "/" menu's Image item calls it through the `chooseFiles` command.
|
|
126
|
+
*/
|
|
127
|
+
declare function chooseFiles(view: View, options: UploadOptions): boolean;
|
|
119
128
|
/** The plugin alone, for a ProseMirror editor without Tiptap. */
|
|
120
129
|
declare function uploadPlugin(options: UploadOptions): Plugin<DecorationSet>;
|
|
121
130
|
declare module "@tiptap/core" {
|
|
@@ -123,6 +132,8 @@ declare module "@tiptap/core" {
|
|
|
123
132
|
comarkUpload: {
|
|
124
133
|
/** Uploads files at the cursor, as a paste would, such as the ones a file picker returns. */
|
|
125
134
|
uploadFiles: (files: File[]) => ReturnType;
|
|
135
|
+
/** Opens the file picker and uploads the files picked at the cursor, as a "/" menu's Image item would. */
|
|
136
|
+
chooseFiles: () => ReturnType;
|
|
126
137
|
};
|
|
127
138
|
}
|
|
128
139
|
}
|
|
@@ -170,4 +181,4 @@ interface EditorCodecOptions {
|
|
|
170
181
|
}
|
|
171
182
|
declare function createEditorCodec(options?: EditorCodecOptions): EditorCodec;
|
|
172
183
|
//#endregion
|
|
173
|
-
export {
|
|
184
|
+
export { DefinitionDescription as A, ComarkKit as C, CriticDeletion as D, CriticComment as E, InlineFootnote as F, DefinitionTerm as M, FootnoteDefinition as N, CriticHighlight as O, FootnoteReference as P, ComarkInline as S, ComarkSlot as T, fromMarkdown as _, Upload as a, ComarkComment as b, findUpload as c, uploadKey as d, uploadPlugin as f, checkMarkdown as g, SplitMarkdown as h, PendingUpload as i, DefinitionList as j, CriticInsertion as k, startUploads as l, MarkdownCheck as m, EditorCodecOptions as n, UploadOptions as o, EditorDocument as p, createEditorCodec as r, chooseFiles as s, EditorCodec as t, uploadCss as u, toMarkdown as v, ComarkKitOptions as w, ComarkImage as x, ComarkBlock as y };
|
package/dist/editor-vue.d.mts
CHANGED
package/dist/editor-vue.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as isElement, t as childrenOf } from "./nodes-CwDBFXnO.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { d as toMarkdown, g as ComarkKit, l as checkMarkdown, u as fromMarkdown } from "./editor-CW05gHp7.mjs";
|
|
3
3
|
import { Editor, EditorContent } from "@tiptap/vue-3";
|
|
4
4
|
import { rowsOf } from "comark-properties";
|
|
5
5
|
import { Properties } from "comark-properties/vue";
|
package/dist/editor.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { ComarkBlock, ComarkComment, ComarkImage, ComarkInline, ComarkKit, type ComarkKitOptions, ComarkSlot, CriticComment, CriticDeletion, CriticHighlight, CriticInsertion, DefinitionDescription, DefinitionList, DefinitionTerm, type EditorCodec, type EditorCodecOptions, type EditorDocument, FootnoteDefinition, FootnoteReference, InlineFootnote, type MarkdownCheck, type PendingUpload, type SplitMarkdown, Upload, type UploadOptions, checkMarkdown, createEditorCodec, findUpload, fromMarkdown, startUploads, toMarkdown, uploadKey, uploadPlugin };
|
|
1
|
+
import { A as DefinitionDescription, C as ComarkKit, D as CriticDeletion, E as CriticComment, F as InlineFootnote, M as DefinitionTerm, N as FootnoteDefinition, O as CriticHighlight, P as FootnoteReference, S as ComarkInline, T as ComarkSlot, _ as fromMarkdown, a as Upload, b as ComarkComment, c as findUpload, d as uploadKey, f as uploadPlugin, g as checkMarkdown, h as SplitMarkdown, i as PendingUpload, j as DefinitionList, k as CriticInsertion, l as startUploads, m as MarkdownCheck, n as EditorCodecOptions, o as UploadOptions, p as EditorDocument, r as createEditorCodec, s as chooseFiles, t as EditorCodec, u as uploadCss, v as toMarkdown, w as ComarkKitOptions, x as ComarkImage, y as ComarkBlock } from "./editor-Dk8TRweM.mjs";
|
|
2
|
+
export { ComarkBlock, ComarkComment, ComarkImage, ComarkInline, ComarkKit, type ComarkKitOptions, ComarkSlot, CriticComment, CriticDeletion, CriticHighlight, CriticInsertion, DefinitionDescription, DefinitionList, DefinitionTerm, type EditorCodec, type EditorCodecOptions, type EditorDocument, FootnoteDefinition, FootnoteReference, InlineFootnote, type MarkdownCheck, type PendingUpload, type SplitMarkdown, Upload, type UploadOptions, checkMarkdown, chooseFiles, createEditorCodec, findUpload, fromMarkdown, startUploads, toMarkdown, uploadCss, uploadKey, uploadPlugin };
|
package/dist/editor.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { f as ComarkBlock, p as ComarkComment, m as ComarkImage, h as ComarkInline, g as ComarkKit, _ as ComarkSlot, v as CriticComment, y as CriticDeletion, b as CriticHighlight, x as CriticInsertion, S as DefinitionDescription, C as DefinitionList, w as DefinitionTerm, T as FootnoteDefinition, E as FootnoteReference, D as InlineFootnote, n as Upload, l as checkMarkdown, r as chooseFiles, t as createEditorCodec, i as findUpload, u as fromMarkdown, a as startUploads, d as toMarkdown, o as uploadCss, s as uploadKey, c as uploadPlugin } from "./editor-CW05gHp7.mjs";
|
package/dist/html.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as commentsCss, n as Preset, o as criticCss, r as PresetOptions } from "./index-
|
|
1
|
+
import { a as commentsCss, n as Preset, o as criticCss, r as PresetOptions } from "./index-CNYr62nX.mjs";
|
|
2
2
|
import { NodeHandler } from "comark";
|
|
3
3
|
//#region src/html.d.ts
|
|
4
4
|
/**
|
package/dist/html.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as criticCss, r as preset, t as commentsCss } from "./src-
|
|
1
|
+
import { n as criticCss, r as preset, t as commentsCss } from "./src-C3nMECXA.mjs";
|
|
2
2
|
import { t as typesetCss } from "./typeset-css-BOtdXbMg.mjs";
|
|
3
|
-
import { a as start, n as mermaidBar, r as mermaidCss } from "./client-
|
|
3
|
+
import { a as start, n as mermaidBar, r as mermaidCss } from "./client-zWY8yhUx.mjs";
|
|
4
4
|
import { t as rawText } from "./text-D8j9clg3.mjs";
|
|
5
5
|
import { escapeHtml } from "comark/utils";
|
|
6
6
|
import * as annotate from "comark-annotate/html";
|
|
@@ -38,6 +38,7 @@ import * as steps from "comark-steps/html";
|
|
|
38
38
|
import * as table from "comark-table/html";
|
|
39
39
|
import * as tabs from "comark-tabs/html";
|
|
40
40
|
import * as tests from "comark-tests/html";
|
|
41
|
+
import * as time from "comark-time/html";
|
|
41
42
|
import * as zoom from "comark-zoom/html";
|
|
42
43
|
//#region ../../shared/html.ts
|
|
43
44
|
/** A value as the inside of a double-quoted HTML attribute. */
|
|
@@ -107,6 +108,7 @@ var html_default = (options) => preset({
|
|
|
107
108
|
table,
|
|
108
109
|
tabs,
|
|
109
110
|
tests,
|
|
111
|
+
time,
|
|
110
112
|
typeset,
|
|
111
113
|
zoom
|
|
112
114
|
}, options);
|
|
@@ -28,6 +28,7 @@ import { QuizOptions } from "comark-quiz";
|
|
|
28
28
|
import { TableOptions } from "comark-table";
|
|
29
29
|
import { TabsOptions } from "comark-tabs";
|
|
30
30
|
import { TestsOptions } from "comark-tests";
|
|
31
|
+
import { TimeOptions } from "comark-time";
|
|
31
32
|
import { ZoomOptions } from "comark-zoom";
|
|
32
33
|
//#region src/mermaid-limits.d.ts
|
|
33
34
|
type MermaidOptions = PeleConfig & {
|
|
@@ -154,6 +155,8 @@ type PresetOptions = {
|
|
|
154
155
|
xref?: XrefOptions | boolean;
|
|
155
156
|
/** Reads no JUnit reports unless you pass `{ root }` or `{ read }`; inline reports render either way. */
|
|
156
157
|
tests?: TestsOptions | boolean;
|
|
158
|
+
/** `:time[2026-10-12]` as relative time: "3 days ago", a date past `threshold`, and the full date in a tooltip. */
|
|
159
|
+
time?: TimeOptions | boolean;
|
|
157
160
|
zoom?: ZoomOptions | boolean;
|
|
158
161
|
/**
|
|
159
162
|
* Highlights fenced code with your own Shiki, before comark-code. Off unless you pass one, so the preset bundles no
|
|
@@ -220,6 +223,7 @@ type Renderer<C> = {
|
|
|
220
223
|
tabs: Part<C, TabsOptions>;
|
|
221
224
|
outline: Part<C, OutlineOptions>;
|
|
222
225
|
tests: Part<C, TestsOptions>;
|
|
226
|
+
time: Part<C, TimeOptions>;
|
|
223
227
|
zoom: Part<C, ZoomOptions>;
|
|
224
228
|
code: Part<C, CodeOptions>;
|
|
225
229
|
codeNotes: Part<C>;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as typesetStylesheet, t as typesetCss } from "./typeset-css-DtOLAa1Z.mjs";
|
|
2
|
-
import { a as commentsCss, c as TYPESET_TAG, d as ShikiOptions, f as MermaidOptions, i as Renderer, l as typeset, n as Preset, o as criticCss, r as PresetOptions, s as preset, t as AnyPlugin, u as ShikiHighlighter } from "./index-
|
|
2
|
+
import { a as commentsCss, c as TYPESET_TAG, d as ShikiOptions, f as MermaidOptions, i as Renderer, l as typeset, n as Preset, o as criticCss, r as PresetOptions, s as preset, t as AnyPlugin, u as ShikiHighlighter } from "./index-CNYr62nX.mjs";
|
|
3
3
|
export { AnyPlugin, type MermaidOptions, Preset, PresetOptions, Renderer, type ShikiHighlighter, type ShikiOptions, TYPESET_TAG, commentsCss, criticCss, preset, typeset, typesetCss, typesetStylesheet };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as typeset, i as TYPESET_TAG, n as criticCss, r as preset, t as commentsCss } from "./src-
|
|
1
|
+
import { a as typeset, i as TYPESET_TAG, n as criticCss, r as preset, t as commentsCss } from "./src-C3nMECXA.mjs";
|
|
2
2
|
import { n as typesetStylesheet, t as typesetCss } from "./typeset-css-BOtdXbMg.mjs";
|
|
3
3
|
export { TYPESET_TAG, commentsCss, criticCss, preset, typeset, typesetCss, typesetStylesheet };
|
package/dist/react.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as commentsCss, n as Preset, o as criticCss, r as PresetOptions } from "./index-
|
|
1
|
+
import { a as commentsCss, n as Preset, o as criticCss, r as PresetOptions } from "./index-CNYr62nX.mjs";
|
|
2
2
|
import { ComponentType } from "react";
|
|
3
3
|
//#region src/react.d.ts
|
|
4
4
|
type AnyComponent = ComponentType<any>;
|
package/dist/react.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as criticCss, r as preset, t as commentsCss } from "./src-
|
|
1
|
+
import { n as criticCss, r as preset, t as commentsCss } from "./src-C3nMECXA.mjs";
|
|
2
2
|
import { t as typesetCss } from "./typeset-css-BOtdXbMg.mjs";
|
|
3
|
-
import { i as startMermaid, n as mermaidBar, t as addMermaidStyles } from "./client-
|
|
3
|
+
import { i as startMermaid, n as mermaidBar, t as addMermaidStyles } from "./client-zWY8yhUx.mjs";
|
|
4
4
|
import { createElement, useEffect } from "react";
|
|
5
5
|
import * as badge from "comark-badge/react";
|
|
6
6
|
import * as cards from "comark-cards/react";
|
|
@@ -33,6 +33,7 @@ import * as steps from "comark-steps/react";
|
|
|
33
33
|
import * as table from "comark-table/react";
|
|
34
34
|
import * as tabs from "comark-tabs/react";
|
|
35
35
|
import * as tests from "comark-tests/react";
|
|
36
|
+
import * as time from "comark-time/react";
|
|
36
37
|
import * as zoom from "comark-zoom/react";
|
|
37
38
|
//#region src/react.ts
|
|
38
39
|
const Pele = createPeleComponent({
|
|
@@ -90,6 +91,7 @@ var react_default = (options) => preset({
|
|
|
90
91
|
table,
|
|
91
92
|
tabs,
|
|
92
93
|
tests,
|
|
94
|
+
time,
|
|
93
95
|
typeset,
|
|
94
96
|
zoom
|
|
95
97
|
}, options);
|
|
@@ -19,7 +19,7 @@ An animation, a transition, a loading sequence, or feedback while dragging happe
|
|
|
19
19
|
|
|
20
20
|
## 1. Capture a comparable pair
|
|
21
21
|
|
|
22
|
-
Take the after capture from the branch or its preview, and the before capture from a deployment or commit that still behaves the old way. Capture both with the same viewport, zoom, theme, data, scroll position, and open menus, so the change is the only difference.
|
|
22
|
+
Take the after capture from the branch or its preview, and the before capture from a deployment, or from a separate worktree at the base commit, that still behaves the old way. Do not use `git stash` to switch between them: worktrees of one repository share the stash, so another session can pop your changes. Capture both with the same viewport, zoom, theme, data, scroll position, and open menus, so the change is the only difference.
|
|
23
23
|
|
|
24
24
|
- Set up the state that shows the change before you capture: the long name that wrapped, the error that stayed hidden, the empty list.
|
|
25
25
|
- Clip both captures to one region around the change, the same rectangle on each side. A `::compare` gives each image under half the page width, where a full-page capture's text is too small to read.
|
|
@@ -17,6 +17,8 @@ pnpm add comark @comark/html comark-ui
|
|
|
17
17
|
|
|
18
18
|
Run the comark CLIs with the [global Vite+ CLI](https://viteplus.dev/guide/global-cli): `vp dlx` for a package the project doesn't install, `vp exec` for one it does. Without Vite+, `pnpm dlx` and `pnpm exec` take the same arguments.
|
|
19
19
|
|
|
20
|
+
If pnpm reports `ERR_PNPM_TRUST_DOWNGRADE`, read [pnpm trust errors](https://comark-ui.onmax.me/getting-started/#pnpm-trust-errors) for the publishing history and exact-version exceptions. Apply an exception only when the user's instructions authorize the policy change.
|
|
21
|
+
|
|
20
22
|
```ts
|
|
21
23
|
import { createHtmlRenderer } from "@comark/html";
|
|
22
24
|
import comarkUi from "comark-ui/html";
|
|
@@ -77,6 +79,7 @@ Read the reference for each block you use before you write it. Mix the blocks fr
|
|
|
77
79
|
| A test run's passed, failed, and skipped counts and its failures, from a JUnit report | `::tests` | [tests](references/tests.md) |
|
|
78
80
|
| A note, tip, or warning box, or long output folded away, as on GitHub | `> [!NOTE]`, `<details>` | [github](references/github.md) |
|
|
79
81
|
| The review's status, pull request, author, date, and tags in a box | frontmatter, `::properties` | [properties](references/properties.md) |
|
|
82
|
+
| When something happened or is due, as "2 days ago" or a date, with the full date on hover | `:time[2026-11-02]` | [time](references/time.md) |
|
|
80
83
|
| Claims backed by links, with numbered citations | `:cite`, `::sources` | [sources](references/sources.md) |
|
|
81
84
|
| An icon in a sentence or a table cell, such as a logo or a status | `:icon` | [icon](references/icon.md) |
|
|
82
85
|
| A preview link a reviewer can scan with a phone | `:qr` | [qr](references/qr.md) |
|
|
@@ -35,7 +35,7 @@ Moon phase and vibes don't fit, so the toolbar wraps and pushes the table down.
|
|
|
35
35
|
|
|
36
36
|
- `::compare`: `title` is optional and names the comparison for screen readers. `mode` is `columns` (default, side by side) or `slider`. `ink` colors every annotation in both screenshots that doesn't set its own `color`. Its two screenshots are titled Before and After unless they set their own.
|
|
37
37
|
- `::screenshot`: `src` and `alt` are required; `title` (the heading above the image), `href` (the captured page, linked by its host), `viewport` (like `1440x900`), and `ink` are optional. Other content becomes the caption.
|
|
38
|
-
- `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `line` (straight through the middle, along the longer side), `highlight`, `bracket
|
|
38
|
+
- `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `line` (straight through the middle, along the longer side), `highlight`, `bracket` (down the side of a box at least twice as tall as it is wide, and across a wide one, whatever its `side`), `cross`, `check`, or `none`, which needs a `side`. `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color. `side` is `top`, `bottom`, `left`, or `right`; keep top or bottom notes at least a quarter of the image apart and left or right notes an eighth apart.
|
|
39
39
|
- `at` moves a side note along its margin, as a percentage of the image (across for top and bottom, down for left and right). A note set off from its point reads away from it, so put it on the side with room: a top note at `at=40` pointing left of 40 reads to the right. `to="x,y"` is the point the arrow lands on, measured like the box; without it the arrow meets the middle of the mark's facing edge. Both need a `side`.
|
|
40
40
|
- Annotations must be direct children of a screenshot.
|
|
41
41
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Dates as relative time
|
|
2
|
+
|
|
3
|
+
comark-time draws `:time[2026-11-02]` as the words a reader would say, such as "2 days ago" or "in 3 weeks", and past a threshold as a date, such as "Sep 30". Hover or focus opens a tooltip with the full date and time. Use it where a document says when something happened or will: when a pull request opened, when a benchmark ran, when a deadline falls. Write the date in ISO form and leave the words to the plugin.
|
|
4
|
+
|
|
5
|
+
## Syntax
|
|
6
|
+
|
|
7
|
+
```md
|
|
8
|
+
Opened :time[2026-11-02], last run :time[2026-11-04T11:59:56Z], due :time[2026-11-25].
|
|
9
|
+
|
|
10
|
+
The first sighting was :time[2026-09-30]{threshold="8w"}.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- The date goes in the brackets: `2026-11-02`, or with a time of day, `2026-11-02T09:30:00Z`. A date alone counts whole days, so it reads "today", "yesterday", "2 days ago", or "in 3 days", never hours. A time with no offset is in the `timeZone` option's zone.
|
|
14
|
+
- `threshold` sets how far from now it stops reading as relative: a number and `s`, `m`, `h`, `d`, `w`, `mo`, or `y`, such as `3w`. The default is `4w`. `none` keeps it relative at any distance.
|
|
15
|
+
- Past the threshold the text is "Sep 30", or "Sep 30, 2025" in another year, and the tooltip shows how far away it is. Before it, the tooltip shows the full date, with the time and zone when the date has one.
|
|
16
|
+
- No script runs. The words are worked out while parsing and are fixed in rendered HTML, so "2 days ago" stays that until the document is parsed again.
|
|
17
|
+
|
|
18
|
+
## Write the dates
|
|
19
|
+
|
|
20
|
+
- Write the exact date from the source: the pull request's `createdAt`, the report's timestamp. Never write "yesterday" or "last week" in prose for a date a reader may look up.
|
|
21
|
+
- A zone-less date and time is read in the host's zone, which the reader can't see. Give a time an offset, such as `Z`, unless it is the author's local time.
|
|
22
|
+
- A date the plugin can't read, such as `next friday` or `2026-02-31`, is shown as written and reported. Fix it to ISO.
|
|
23
|
+
- Leave the threshold alone unless a date is better read as one or the other: `threshold="none"` for a date that must always read relative, a short one such as `1w` for a date that is better absolute within a month.
|
|
24
|
+
|
|
25
|
+
## Register
|
|
26
|
+
|
|
27
|
+
- In `comark-ui`: on. `comarkUi({ time: { now, threshold, locale, timeZone } })` passes its options; `now` pins the moment every date is measured from, which a host that caches rendered HTML should do. `time: false` turns it off.
|
|
28
|
+
- Alone: `pnpm add comark @comark/html comark-time`, then `createHtmlRenderer({ plugins: [time()], components })` with both from `comark-time/html`. `comark-time/vue`, `/react`, and `/svelte` render it too. It has no script.
|
package/dist/skills.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const skills = [
|
|
|
12
12
|
"files": [
|
|
13
13
|
{
|
|
14
14
|
"path": "SKILL.md",
|
|
15
|
-
"text": "---\nname: before-after-evidence\ndescription: Shows a visible change as two comparable screenshots, before and after, with marks measured from the source and checked in the rendered page, and a change in motion as a short recording. Use when a pull request, bug fix, or design change alters what people see or how it moves, or when someone asks for before/after screenshots, a recording, or visual evidence.\nlicense: MIT\n---\n\n# Before/after evidence\n\nA before/after is evidence when a reviewer can check every claim against the two images and nothing else. The reader can't repair a bad pair, so get three things right: two captures of the same view, marks on what changed, and notes in the words the screen shows.\n\nThis skill writes the document. Your host decides where it's published and who can open it.\n\n## When the change is motion\n\nAn animation, a transition, a loading sequence, or feedback while dragging happens between frames, so record it. A still taken partway through a motion looks like a broken layout, and two of them can't show that anything moves. Follow [references/recording.md](references/recording.md) in place of steps 1 and 2, then write and check the document with steps 3 and 4, with the clip where the `::compare` goes.\n\n- When the old behavior jumped straight to its end state, the after clip alone is the evidence, and the document's first sentence says what happened before.\n- When the change retimes motion that already existed, such as its easing, its duration, or a stutter, record both sides with the same script.\n\n## 1. Capture a comparable pair\n\nTake the after capture from the branch or its preview, and the before capture from a deployment or commit that still behaves the old way. Capture both with the same viewport, zoom, theme, data, scroll position, and open menus, so the change is the only difference.\n\n- Set up the state that shows the change before you capture: the long name that wrapped, the error that stayed hidden, the empty list.\n- Clip both captures to one region around the change, the same rectangle on each side. A `::compare` gives each image under half the page width, where a full-page capture's text is too small to read.\n- Pin anything that moves the layout between the two states, such as a vertically centered dialog that grows by one line, so the same element sits at the same place in both.\n\nIf you can't capture one side comparably, stop and say what blocked you. A description in place of a screenshot, or one side alone, isn't before/after evidence.\n\nDone when both images exist, have the same size, and differ only where the change is.\n\n## 2. Measure every mark\n\nMarks take `x`, `y`, `w`, and `h` as percentages of the image. Measure them. An estimate drifts a few percent, which on a half-width image lands on the neighbouring button.\n\n- **A page you captured:** read the element's box in the same browser, viewport, and state, minus the clip's offset. [references/measuring.md](references/measuring.md) has the snippet.\n- **A still you didn't capture**, such as a frame from a screen recording, a design export, or an image attached to a bug report: there is no DOM to ask. Measure in image pixels and divide by the image's natural width and height. Confirm each box by cropping the image to it and looking at the crop, as the same reference shows.\n\nMark the change at its own size: the field, the label, the button. Use `red` on the before side for the problem and `green` on the after side for the fix, and leave what stayed the same unmarked. Two or three marks a side usually tell the whole story.\n\nDone when every mark has numbers you measured, and you can name the element or the pixel rectangle each came from.\n\n## 3. Write the document\n\nStart from [references/example.md](references/example.md) and keep its shape:\n\n1. One sentence: what changed, and for whom.\n2. One line of steps to reach the screen, so a reviewer can reproduce it.\n3. The `::compare`, each note a few words in the screen's own words. A value the screenshot doesn't show stays out of its note.\n4. A `::diff` of the line that caused it, only when the reader would otherwise ask.\n\nThe images carry the evidence, so the text only points into them. Put how the work went (checks, retries, CI) in your report to the user, not in the document. [references/blocks.md](references/blocks.md) has the syntax of each block.\n\nImage `src` must be a URL the renderer can reach: a path next to the document, or an https URL your host gives you for the upload.\n\n## 4. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui comark-lint evidence.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the page where it will be read and take a screenshot of it. To check the screenshots alone, copy the whole `::compare` block, nested screenshots and annotations included, into `evidence-screenshots.md` beside `evidence.md`.\n\n Make comark-annotate a direct dependency of this workspace package. A transitive one isn't linked, and `@latest` can run a different release from the project's renderers. Match the version of the installed Comark UI packages: `pnpm add -D comark-annotate@<version>`, with `-w` at the workspace root. With no Comark UI packages installed, omit `@<version>`. Then run:\n\n ```sh\n vp exec comark-annotate render evidence-screenshots.md -o evidence-screenshots.html\n ```\n\n Without Vite+, use `pnpm exec` with the same arguments. Open `evidence-screenshots.html` and take a screenshot of it. This CLI renders annotate, carousel, and zoom only; check any `::diff` or other blocks in the host's full Comark UI preview.\n\n3. Check that each mark sits on its target and each note matches what its side shows. A clip should start by itself and loop in the page. Measure a mark that misses again from the source; a box moved by eye stays a guess.\n\nDone when you've looked at the rendered page and every mark lands. Name any mark or block you couldn't check in your report.\n"
|
|
15
|
+
"text": "---\nname: before-after-evidence\ndescription: Shows a visible change as two comparable screenshots, before and after, with marks measured from the source and checked in the rendered page, and a change in motion as a short recording. Use when a pull request, bug fix, or design change alters what people see or how it moves, or when someone asks for before/after screenshots, a recording, or visual evidence.\nlicense: MIT\n---\n\n# Before/after evidence\n\nA before/after is evidence when a reviewer can check every claim against the two images and nothing else. The reader can't repair a bad pair, so get three things right: two captures of the same view, marks on what changed, and notes in the words the screen shows.\n\nThis skill writes the document. Your host decides where it's published and who can open it.\n\n## When the change is motion\n\nAn animation, a transition, a loading sequence, or feedback while dragging happens between frames, so record it. A still taken partway through a motion looks like a broken layout, and two of them can't show that anything moves. Follow [references/recording.md](references/recording.md) in place of steps 1 and 2, then write and check the document with steps 3 and 4, with the clip where the `::compare` goes.\n\n- When the old behavior jumped straight to its end state, the after clip alone is the evidence, and the document's first sentence says what happened before.\n- When the change retimes motion that already existed, such as its easing, its duration, or a stutter, record both sides with the same script.\n\n## 1. Capture a comparable pair\n\nTake the after capture from the branch or its preview, and the before capture from a deployment, or from a separate worktree at the base commit, that still behaves the old way. Do not use `git stash` to switch between them: worktrees of one repository share the stash, so another session can pop your changes. Capture both with the same viewport, zoom, theme, data, scroll position, and open menus, so the change is the only difference.\n\n- Set up the state that shows the change before you capture: the long name that wrapped, the error that stayed hidden, the empty list.\n- Clip both captures to one region around the change, the same rectangle on each side. A `::compare` gives each image under half the page width, where a full-page capture's text is too small to read.\n- Pin anything that moves the layout between the two states, such as a vertically centered dialog that grows by one line, so the same element sits at the same place in both.\n\nIf you can't capture one side comparably, stop and say what blocked you. A description in place of a screenshot, or one side alone, isn't before/after evidence.\n\nDone when both images exist, have the same size, and differ only where the change is.\n\n## 2. Measure every mark\n\nMarks take `x`, `y`, `w`, and `h` as percentages of the image. Measure them. An estimate drifts a few percent, which on a half-width image lands on the neighbouring button.\n\n- **A page you captured:** read the element's box in the same browser, viewport, and state, minus the clip's offset. [references/measuring.md](references/measuring.md) has the snippet.\n- **A still you didn't capture**, such as a frame from a screen recording, a design export, or an image attached to a bug report: there is no DOM to ask. Measure in image pixels and divide by the image's natural width and height. Confirm each box by cropping the image to it and looking at the crop, as the same reference shows.\n\nMark the change at its own size: the field, the label, the button. Use `red` on the before side for the problem and `green` on the after side for the fix, and leave what stayed the same unmarked. Two or three marks a side usually tell the whole story.\n\nDone when every mark has numbers you measured, and you can name the element or the pixel rectangle each came from.\n\n## 3. Write the document\n\nStart from [references/example.md](references/example.md) and keep its shape:\n\n1. One sentence: what changed, and for whom.\n2. One line of steps to reach the screen, so a reviewer can reproduce it.\n3. The `::compare`, each note a few words in the screen's own words. A value the screenshot doesn't show stays out of its note.\n4. A `::diff` of the line that caused it, only when the reader would otherwise ask.\n\nThe images carry the evidence, so the text only points into them. Put how the work went (checks, retries, CI) in your report to the user, not in the document. [references/blocks.md](references/blocks.md) has the syntax of each block.\n\nImage `src` must be a URL the renderer can reach: a path next to the document, or an https URL your host gives you for the upload.\n\n## 4. Check the render\n\n1. Lint it, and fix until it reports no problems:\n\n ```sh\n vp dlx --package comark-linter --package comark-ui comark-lint evidence.md\n ```\n\n These commands use the [global Vite+ CLI](https://viteplus.dev/guide/global-cli). Without it, `pnpm dlx` takes the same arguments.\n\n2. Open the page where it will be read and take a screenshot of it. To check the screenshots alone, copy the whole `::compare` block, nested screenshots and annotations included, into `evidence-screenshots.md` beside `evidence.md`.\n\n Make comark-annotate a direct dependency of this workspace package. A transitive one isn't linked, and `@latest` can run a different release from the project's renderers. Match the version of the installed Comark UI packages: `pnpm add -D comark-annotate@<version>`, with `-w` at the workspace root. With no Comark UI packages installed, omit `@<version>`. Then run:\n\n ```sh\n vp exec comark-annotate render evidence-screenshots.md -o evidence-screenshots.html\n ```\n\n Without Vite+, use `pnpm exec` with the same arguments. Open `evidence-screenshots.html` and take a screenshot of it. This CLI renders annotate, carousel, and zoom only; check any `::diff` or other blocks in the host's full Comark UI preview.\n\n3. Check that each mark sits on its target and each note matches what its side shows. A clip should start by itself and loop in the page. Measure a mark that misses again from the source; a box moved by eye stays a guess.\n\nDone when you've looked at the rendered page and every mark lands. Name any mark or block you couldn't check in your report.\n"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"path": "agents/openai.yaml",
|
|
@@ -46,7 +46,7 @@ const skills = [
|
|
|
46
46
|
"files": [
|
|
47
47
|
{
|
|
48
48
|
"path": "SKILL.md",
|
|
49
|
-
"text": "---\nname: comark-ui\ndescription: Writes PR evidence, explanations of how something works, and docs pages in Markdown with comark-ui. Use when a document needs an annotated screenshot, a before/after, a chart, a diagram, a code change, or another comark block, or when setting up comark-ui or a comark-* package.\n---\n\n# comark-ui\n\nYou write Markdown, and the comark plugins render it as static HTML. The reader sees only what you measured and wrote down, so measure every mark from the page, take every number from the data, and check the render before you hand it over.\n\n## Install\n\nInstall `comark-ui` by default. It holds every plugin and registers them in the order they need:\n\n```sh\npnpm add comark @comark/html comark-ui\n```\n\nRun the comark CLIs with the [global Vite+ CLI](https://viteplus.dev/guide/global-cli): `vp dlx` for a package the project doesn't install, `vp exec` for one it does. Without Vite+, `pnpm dlx` and `pnpm exec` take the same arguments.\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport comarkUi from \"comark-ui/html\";\n\nconst render = createHtmlRenderer(comarkUi());\n```\n\nEvery plugin is on except `include`. The [comark-ui reference](references/ui.md) covers its options, the plugins that read files or use the network, and its Vue, React, and Svelte entries.\n\nTo use only some plugins, install those packages and register each plugin with its components:\n\n```sh\npnpm add comark @comark/html comark-annotate\n```\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport annotate, { components } from \"comark-annotate/html\";\n\nconst render = createHtmlRenderer({ plugins: [annotate()], components });\n```\n\nEach reference ends with a Register section that says how its package registers alone and which options it needs.\n\nEither way, the HTML renderer inlines the styles once per document, and the Vue, React, and Svelte components add them on mount. On a server-rendered page, import each package's `style.css`, such as `comark-cards/style.css`, so the page doesn't shift.\n\nThe `--comark-*` tokens theme every plugin at once; https://comark-ui.onmax.me/guide/theming/ lists them. In a Nuxt UI app the plugins follow its `--ui-*` variables with no setup. For a page rendered outside the app, such as review evidence, put the CSS from `nuxtUiTheme({ colors: appConfig.ui?.colors, css: mainCss })` (from `comark-ui/nuxt-ui`) in a `<style>`, so the page matches the app.\n\nTo move a project to Comark, start with `migrate-to-comark`, which finds its Markdown libraries and runs the migrator for each; see the [migrate-to-comark reference](references/migrate-to-comark.md). A project that renders Markdown with remark moves to Comark with `remark-to-comark`; the [remark-to-comark reference](references/remark-to-comark.md) walks through it. One that renders with markdown-it moves with `markdown-it-to-comark`; see the [markdown-it-to-comark reference](references/markdown-it-to-comark.md). A project on marked moves with `marked-to-comark`; see the [marked-to-comark reference](references/marked-to-comark.md).\n\nProblems land in `meta.issues` after `parseMarkdown`, one sentence each, and a host can refuse a document while any remain. For untrusted input, add Comark's `security` plugin with `blockedTags` such as `script`, `style`, and `iframe`; it cleans the Markdown inside blocks too.\n\n## Shape the document\n\nThis skill teaches the blocks. Four sibling skills teach a whole document, what goes in it and in what order: `before-after-evidence`, `review-document`, `visual-explanation`, and `teach-lesson`. When the user asks for one of those and it isn't installed, suggest `vp dlx skills add onmax/comark-ui` and picking it from the list.\n\n## Pick the blocks\n\nRead the reference for each block you use before you write it. Mix the blocks freely with ordinary Markdown, such as headings, tables, and lists.\n\n### Review blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| One state of a screen, with marks, numbered notes, or arrows | `::screenshot` | [annotate](references/annotate.md) |\n| A change on screen, before and after | `::compare` | [annotate](references/annotate.md) |\n| A command's output, such as a test run or a build, as colored text | `::cast` | [cast](references/cast.md) |\n| Numbers, such as sizes, timings, before/after metrics, a trend, or a timeline | `::chart` | [charts](references/charts.md) |\n| A flow, a sequence, an architecture, or a schema as a diagram | a `mermaid`, `d2`, `dot`, `plantuml`, `dbml`, `goat`, or `svgbob` fence | [diagrams](references/diagrams.md) |\n| Links and `@mentions` with the site's favicon or the person's avatar | links, `@user`, `:chip` | [chips](references/chips.md) |\n| Colors, such as design tokens before and after, or a palette | a color in inline code, `::palette` | [colors](references/colors.md) |\n| A suggested change to one file, before and after | `::diff` | [diff](references/diff.md) |\n| Suggested edits and comment threads on prose, such as a copy review, each note in a card in the margin | `:suggestion`, `:comment` | [comments](references/comments.md) |\n| A video, a design file, or a live reproduction from its link | `::embed` | [embed](references/embed.md) |\n| A screen recording or a sound that a screenshot can't show | `` | [media](references/media.md) |\n| A number before and after, a table of befores and afters, or progress | `:delta`, `::stats`, `:progress` | [metrics](references/metrics.md) |\n| Data from a CSV, TSV, or JSON fence or file, as a table that copies and sorts | `::table`, a `csv` fence | [table](references/table.md) |\n| A test run's passed, failed, and skipped counts and its failures, from a JUnit report | `::tests` | [tests](references/tests.md) |\n| A note, tip, or warning box, or long output folded away, as on GitHub | `> [!NOTE]`, `<details>` | [github](references/github.md) |\n| The review's status, pull request, author, date, and tags in a box | frontmatter, `::properties` | [properties](references/properties.md) |\n| Claims backed by links, with numbered citations | `:cite`, `::sources` | [sources](references/sources.md) |\n| An icon in a sentence or a table cell, such as a logo or a status | `:icon` | [icon](references/icon.md) |\n| A preview link a reviewer can scan with a phone | `:qr` | [qr](references/qr.md) |\n| Why a line of code is there, as numbered notes under it | `// <1>` and a numbered list | [code-notes](references/code-notes.md) |\n\n### Page behavior\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A stable link to a section, or a link that opens a new tab | `{#id}`, `{target=\"_blank\"}` | [links](references/links.md) |\n| A table, code block, or diagram too small to read in place | `::zoom` | [zoom](references/zoom.md) |\n| A sequence to page through in one place, such as the screens of a flow | `::carousel` | [carousel](references/carousel.md) |\n| Versions of one thing where each reader needs only one, such as an OS or a package manager | `::tabs`, `::code-group`, `pm` | [tabs](references/tabs.md) |\n| Code with lines marked added, removed, or highlighted, or a pasted `git diff` | `ins={4}` after a fence's language, `diff lang=\"ts\"` | [code](references/code.md) |\n\n### Docs blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Content a reader may skip, such as a long log, behind a summary | `::details`, `::accordion`, `::collapsible` | [details](references/details.md) |\n| Folders and files, with what a change added, removed, or changed | `::file-tree` | [file-tree](references/file-tree.md) |\n| A component's props or a function's options, with types and defaults | `::field` | [fields](references/fields.md) |\n| A version, status, or deprecation tag in a heading or a sentence | `:badge` | [badge](references/badge.md) |\n| Links to the next pages as cards, or blocks side by side | `::card-group`, `::columns` | [cards](references/cards.md) |\n| Instructions the reader follows in order, such as repro or setup steps | `::steps` | [steps](references/steps.md) |\n| Code that changes over several steps, such as a refactor told one move at a time | `::magic-move` | [magic-move](references/magic-move.md) |\n| An interactive lesson question, poll, or recall card | `::question`, `::poll`, `::recall` | [quiz](references/quiz.md) |\n\n### Markdown syntax\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Bold or italics in Chinese, Japanese, or Korean text | `**…**`, `*…*` | [cjk](references/cjk.md) |\n| An image with a caption under it | `` | [figure](references/figure.md) |\n| A highlighted phrase or a superscript | `==text==`, `^2^` | [mark](references/mark.md) |\n| A suggested edit or a comment inside the text | `{++ ++}`, `{-- --}`, `{~~ ~> ~~}`, `{== ==}`, `{>> <<}` | [critic](references/critic.md) |\n| Terms and their definitions, such as a glossary | `Term`, then `: definition` | [deflist](references/deflist.md) |\n| A numbered note at the end of the page, such as a source or a caveat | `[^label]`, `^[note]` | [footnotes](references/footnotes.md) |\n| A formula, such as a complexity bound or how a number was computed | `$…$`, `$$…$$` | [math](references/math.md) |\n| A keyboard shortcut | `++ctrl+k++` | [keys](references/keys.md) |\n\n### Authoring tools\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A shared section, or real source lines, pasted from a file | `:include{src}` | [include](references/include.md) |\n| A table of contents of the page's headings | `::toc` | [outline](references/outline.md) |\n| Figures and tables numbered and referred to by number | `{#fig-name}`, `:ref{#fig-name}` | [xref](references/xref.md) |\n| Word count and reading time, for the page's layout | nothing; it writes `meta.readingTime` | [reading-time](references/reading-time.md) |\n\n### Chat\n\n| To show | Use | Reference |\n| --- | --- | --- |\n| An AI SDK chat message, with its reasoning, tool calls, sources, and files | `MessageParts` from `comark-chat` | [chat](references/chat.md) |\n\n## Marks\n\nScreenshots and charts draw the same marks. Each `::annotation` is one mark and its note, written in Markdown.\n\n- `mark` is `box` (default), `circle`, `underline`, `line`, `highlight`, `bracket`, `cross`, `check`, or `none`, which draws nothing, so its note needs a `side` and the arrow alone points.\n- `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color.\n- `side` is `top`, `bottom`, `left`, or `right`, and puts the note in that margin with an arrow to its mark. Notes without one are numbered in a list under the figure.\n\nMark only what your text talks about. Write each note in the words the screen or table shows, saying what changed or what is wrong, so the reader can check it against the figure. Leave out a value the figure doesn't show.\n\n## Check the result\n\n1. Lint the file with `vp exec comark-lint report.md`, in a project with `comark-linter` and the plugins installed (`comark-ui` counts as every plugin). It prints one line per problem with its line, its rule, and the fix, and exits with 1 while any remain. Fix every problem and run it again until it exits with 0. The [lint reference](references/lint.md) covers the flags, the config file, the library, ESLint, and Vite Doctor.\n2. Render the document as the block's reference says, open it in a browser, and take a screenshot. Each mark must sit on its target, each number must match its note, and each chart must say what your text says. Name anything you couldn't verify when you hand the document over.\n"
|
|
49
|
+
"text": "---\nname: comark-ui\ndescription: Writes PR evidence, explanations of how something works, and docs pages in Markdown with comark-ui. Use when a document needs an annotated screenshot, a before/after, a chart, a diagram, a code change, or another comark block, or when setting up comark-ui or a comark-* package.\n---\n\n# comark-ui\n\nYou write Markdown, and the comark plugins render it as static HTML. The reader sees only what you measured and wrote down, so measure every mark from the page, take every number from the data, and check the render before you hand it over.\n\n## Install\n\nInstall `comark-ui` by default. It holds every plugin and registers them in the order they need:\n\n```sh\npnpm add comark @comark/html comark-ui\n```\n\nRun the comark CLIs with the [global Vite+ CLI](https://viteplus.dev/guide/global-cli): `vp dlx` for a package the project doesn't install, `vp exec` for one it does. Without Vite+, `pnpm dlx` and `pnpm exec` take the same arguments.\n\nIf pnpm reports `ERR_PNPM_TRUST_DOWNGRADE`, read [pnpm trust errors](https://comark-ui.onmax.me/getting-started/#pnpm-trust-errors) for the publishing history and exact-version exceptions. Apply an exception only when the user's instructions authorize the policy change.\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport comarkUi from \"comark-ui/html\";\n\nconst render = createHtmlRenderer(comarkUi());\n```\n\nEvery plugin is on except `include`. The [comark-ui reference](references/ui.md) covers its options, the plugins that read files or use the network, and its Vue, React, and Svelte entries.\n\nTo use only some plugins, install those packages and register each plugin with its components:\n\n```sh\npnpm add comark @comark/html comark-annotate\n```\n\n```ts\nimport { createHtmlRenderer } from \"@comark/html\";\nimport annotate, { components } from \"comark-annotate/html\";\n\nconst render = createHtmlRenderer({ plugins: [annotate()], components });\n```\n\nEach reference ends with a Register section that says how its package registers alone and which options it needs.\n\nEither way, the HTML renderer inlines the styles once per document, and the Vue, React, and Svelte components add them on mount. On a server-rendered page, import each package's `style.css`, such as `comark-cards/style.css`, so the page doesn't shift.\n\nThe `--comark-*` tokens theme every plugin at once; https://comark-ui.onmax.me/guide/theming/ lists them. In a Nuxt UI app the plugins follow its `--ui-*` variables with no setup. For a page rendered outside the app, such as review evidence, put the CSS from `nuxtUiTheme({ colors: appConfig.ui?.colors, css: mainCss })` (from `comark-ui/nuxt-ui`) in a `<style>`, so the page matches the app.\n\nTo move a project to Comark, start with `migrate-to-comark`, which finds its Markdown libraries and runs the migrator for each; see the [migrate-to-comark reference](references/migrate-to-comark.md). A project that renders Markdown with remark moves to Comark with `remark-to-comark`; the [remark-to-comark reference](references/remark-to-comark.md) walks through it. One that renders with markdown-it moves with `markdown-it-to-comark`; see the [markdown-it-to-comark reference](references/markdown-it-to-comark.md). A project on marked moves with `marked-to-comark`; see the [marked-to-comark reference](references/marked-to-comark.md).\n\nProblems land in `meta.issues` after `parseMarkdown`, one sentence each, and a host can refuse a document while any remain. For untrusted input, add Comark's `security` plugin with `blockedTags` such as `script`, `style`, and `iframe`; it cleans the Markdown inside blocks too.\n\n## Shape the document\n\nThis skill teaches the blocks. Four sibling skills teach a whole document, what goes in it and in what order: `before-after-evidence`, `review-document`, `visual-explanation`, and `teach-lesson`. When the user asks for one of those and it isn't installed, suggest `vp dlx skills add onmax/comark-ui` and picking it from the list.\n\n## Pick the blocks\n\nRead the reference for each block you use before you write it. Mix the blocks freely with ordinary Markdown, such as headings, tables, and lists.\n\n### Review blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| One state of a screen, with marks, numbered notes, or arrows | `::screenshot` | [annotate](references/annotate.md) |\n| A change on screen, before and after | `::compare` | [annotate](references/annotate.md) |\n| A command's output, such as a test run or a build, as colored text | `::cast` | [cast](references/cast.md) |\n| Numbers, such as sizes, timings, before/after metrics, a trend, or a timeline | `::chart` | [charts](references/charts.md) |\n| A flow, a sequence, an architecture, or a schema as a diagram | a `mermaid`, `d2`, `dot`, `plantuml`, `dbml`, `goat`, or `svgbob` fence | [diagrams](references/diagrams.md) |\n| Links and `@mentions` with the site's favicon or the person's avatar | links, `@user`, `:chip` | [chips](references/chips.md) |\n| Colors, such as design tokens before and after, or a palette | a color in inline code, `::palette` | [colors](references/colors.md) |\n| A suggested change to one file, before and after | `::diff` | [diff](references/diff.md) |\n| Suggested edits and comment threads on prose, such as a copy review, each note in a card in the margin | `:suggestion`, `:comment` | [comments](references/comments.md) |\n| A video, a design file, or a live reproduction from its link | `::embed` | [embed](references/embed.md) |\n| A screen recording or a sound that a screenshot can't show | `` | [media](references/media.md) |\n| A number before and after, a table of befores and afters, or progress | `:delta`, `::stats`, `:progress` | [metrics](references/metrics.md) |\n| Data from a CSV, TSV, or JSON fence or file, as a table that copies and sorts | `::table`, a `csv` fence | [table](references/table.md) |\n| A test run's passed, failed, and skipped counts and its failures, from a JUnit report | `::tests` | [tests](references/tests.md) |\n| A note, tip, or warning box, or long output folded away, as on GitHub | `> [!NOTE]`, `<details>` | [github](references/github.md) |\n| The review's status, pull request, author, date, and tags in a box | frontmatter, `::properties` | [properties](references/properties.md) |\n| When something happened or is due, as \"2 days ago\" or a date, with the full date on hover | `:time[2026-11-02]` | [time](references/time.md) |\n| Claims backed by links, with numbered citations | `:cite`, `::sources` | [sources](references/sources.md) |\n| An icon in a sentence or a table cell, such as a logo or a status | `:icon` | [icon](references/icon.md) |\n| A preview link a reviewer can scan with a phone | `:qr` | [qr](references/qr.md) |\n| Why a line of code is there, as numbered notes under it | `// <1>` and a numbered list | [code-notes](references/code-notes.md) |\n\n### Page behavior\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A stable link to a section, or a link that opens a new tab | `{#id}`, `{target=\"_blank\"}` | [links](references/links.md) |\n| A table, code block, or diagram too small to read in place | `::zoom` | [zoom](references/zoom.md) |\n| A sequence to page through in one place, such as the screens of a flow | `::carousel` | [carousel](references/carousel.md) |\n| Versions of one thing where each reader needs only one, such as an OS or a package manager | `::tabs`, `::code-group`, `pm` | [tabs](references/tabs.md) |\n| Code with lines marked added, removed, or highlighted, or a pasted `git diff` | `ins={4}` after a fence's language, `diff lang=\"ts\"` | [code](references/code.md) |\n\n### Docs blocks\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Content a reader may skip, such as a long log, behind a summary | `::details`, `::accordion`, `::collapsible` | [details](references/details.md) |\n| Folders and files, with what a change added, removed, or changed | `::file-tree` | [file-tree](references/file-tree.md) |\n| A component's props or a function's options, with types and defaults | `::field` | [fields](references/fields.md) |\n| A version, status, or deprecation tag in a heading or a sentence | `:badge` | [badge](references/badge.md) |\n| Links to the next pages as cards, or blocks side by side | `::card-group`, `::columns` | [cards](references/cards.md) |\n| Instructions the reader follows in order, such as repro or setup steps | `::steps` | [steps](references/steps.md) |\n| Code that changes over several steps, such as a refactor told one move at a time | `::magic-move` | [magic-move](references/magic-move.md) |\n| An interactive lesson question, poll, or recall card | `::question`, `::poll`, `::recall` | [quiz](references/quiz.md) |\n\n### Markdown syntax\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| Bold or italics in Chinese, Japanese, or Korean text | `**…**`, `*…*` | [cjk](references/cjk.md) |\n| An image with a caption under it | `` | [figure](references/figure.md) |\n| A highlighted phrase or a superscript | `==text==`, `^2^` | [mark](references/mark.md) |\n| A suggested edit or a comment inside the text | `{++ ++}`, `{-- --}`, `{~~ ~> ~~}`, `{== ==}`, `{>> <<}` | [critic](references/critic.md) |\n| Terms and their definitions, such as a glossary | `Term`, then `: definition` | [deflist](references/deflist.md) |\n| A numbered note at the end of the page, such as a source or a caveat | `[^label]`, `^[note]` | [footnotes](references/footnotes.md) |\n| A formula, such as a complexity bound or how a number was computed | `$…$`, `$$…$$` | [math](references/math.md) |\n| A keyboard shortcut | `++ctrl+k++` | [keys](references/keys.md) |\n\n### Authoring tools\n\n| To show | Write | Reference |\n| --- | --- | --- |\n| A shared section, or real source lines, pasted from a file | `:include{src}` | [include](references/include.md) |\n| A table of contents of the page's headings | `::toc` | [outline](references/outline.md) |\n| Figures and tables numbered and referred to by number | `{#fig-name}`, `:ref{#fig-name}` | [xref](references/xref.md) |\n| Word count and reading time, for the page's layout | nothing; it writes `meta.readingTime` | [reading-time](references/reading-time.md) |\n\n### Chat\n\n| To show | Use | Reference |\n| --- | --- | --- |\n| An AI SDK chat message, with its reasoning, tool calls, sources, and files | `MessageParts` from `comark-chat` | [chat](references/chat.md) |\n\n## Marks\n\nScreenshots and charts draw the same marks. Each `::annotation` is one mark and its note, written in Markdown.\n\n- `mark` is `box` (default), `circle`, `underline`, `line`, `highlight`, `bracket`, `cross`, `check`, or `none`, which draws nothing, so its note needs a `side` and the arrow alone points.\n- `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color.\n- `side` is `top`, `bottom`, `left`, or `right`, and puts the note in that margin with an arrow to its mark. Notes without one are numbered in a list under the figure.\n\nMark only what your text talks about. Write each note in the words the screen or table shows, saying what changed or what is wrong, so the reader can check it against the figure. Leave out a value the figure doesn't show.\n\n## Check the result\n\n1. Lint the file with `vp exec comark-lint report.md`, in a project with `comark-linter` and the plugins installed (`comark-ui` counts as every plugin). It prints one line per problem with its line, its rule, and the fix, and exits with 1 while any remain. Fix every problem and run it again until it exits with 0. The [lint reference](references/lint.md) covers the flags, the config file, the library, ESLint, and Vite Doctor.\n2. Render the document as the block's reference says, open it in a browser, and take a screenshot. Each mark must sit on its target, each number must match its note, and each chart must say what your text says. Name anything you couldn't verify when you hand the document over.\n"
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"path": "agents/openai.yaml",
|
|
@@ -54,7 +54,7 @@ const skills = [
|
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
"path": "references/annotate.md",
|
|
57
|
-
"text": "# Screenshots and compares\n\ncomark-annotate draws `::screenshot` and `::compare`. Their marks take the values under Marks in SKILL.md.\n\n## Choose the layout\n\nPick what explains the change best:\n\n- One `::screenshot` with marks, when a single state shows the point.\n- A `::compare` of two screenshots, when the change is the point. Capture both at the same viewport, zoom, scroll, and page state, and set the same `viewport` on both. Each image gets under half the page width, where the text of a full-page capture is too small to read, so clip both captures to the same region around the change, such as Playwright's `screenshot({ clip })`.\n- `::compare{mode=\"slider\"}` instead, when both screenshots show the same spot and the change is small, such as a number or a label at the same place. The reader drags a divider across one full-width image instead of reading two half-width ones. Side notes become numbered notes there, so skip `side`.\n- A side note for the two or three points that matter most. With `mark=\"none\"` and `to` on the exact spot, the arrow alone points and nothing covers the screen, which reads cleanest. Other notes stay numbered in the list under the image. In a side-by-side compare only `top` and `bottom` keep their arrows; left and right notes join the list.\n\nFor a review the reader should follow without a key, write it the way a designer marks up a board: the default ink with no `color`, every note a side note in the margin nearest its point, set off with `at` so its arrow sweeps in, and a `bracket` where a note covers a run of rows. Write the notes of a compare as a pair that argue the change: \"The type gets the headline…\" on the before, \"The message becomes the starting point.\" on the after.\n\nMark the change at its own size: the bar, field, or label that changed. What stayed the same goes unmarked, or in one sentence above the screenshots. Keep it to about six marks per screenshot, fewer in a compare.\n\n## Syntax\n\n```md\n::compare\n:::screenshot{src=\"before.png\" alt=\"Filter toolbar wrapping onto a second row\" viewport=\"1440x900\" href=\"https://pr12.preview.example.com/correlations\"}\n::::annotation{x=3.6 y=20.6 w=92.9 h=31.4 color=\"red\"}\nMoon phase and vibes don't fit, so the toolbar wraps and pushes the table down.\n::::\n:::\n\n:::screenshot{src=\"after.png\" alt=\"Filter toolbar on one row\" viewport=\"1440x900\"}\n::::annotation{x=87.6 y=24.2 w=7.4 h=9.9 mark=\"check\" color=\"green\"}\n**Apply** lines up with the chips.\n::::\n:::\n::\n```\n\n- `::compare`: `title` is optional and names the comparison for screen readers. `mode` is `columns` (default, side by side) or `slider`. `ink` colors every annotation in both screenshots that doesn't set its own `color`. Its two screenshots are titled Before and After unless they set their own.\n- `::screenshot`: `src` and `alt` are required; `title` (the heading above the image), `href` (the captured page, linked by its host), `viewport` (like `1440x900`), and `ink` are optional. Other content becomes the caption.\n- `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `line` (straight through the middle, along the longer side), `highlight`, `bracket
|
|
57
|
+
"text": "# Screenshots and compares\n\ncomark-annotate draws `::screenshot` and `::compare`. Their marks take the values under Marks in SKILL.md.\n\n## Choose the layout\n\nPick what explains the change best:\n\n- One `::screenshot` with marks, when a single state shows the point.\n- A `::compare` of two screenshots, when the change is the point. Capture both at the same viewport, zoom, scroll, and page state, and set the same `viewport` on both. Each image gets under half the page width, where the text of a full-page capture is too small to read, so clip both captures to the same region around the change, such as Playwright's `screenshot({ clip })`.\n- `::compare{mode=\"slider\"}` instead, when both screenshots show the same spot and the change is small, such as a number or a label at the same place. The reader drags a divider across one full-width image instead of reading two half-width ones. Side notes become numbered notes there, so skip `side`.\n- A side note for the two or three points that matter most. With `mark=\"none\"` and `to` on the exact spot, the arrow alone points and nothing covers the screen, which reads cleanest. Other notes stay numbered in the list under the image. In a side-by-side compare only `top` and `bottom` keep their arrows; left and right notes join the list.\n\nFor a review the reader should follow without a key, write it the way a designer marks up a board: the default ink with no `color`, every note a side note in the margin nearest its point, set off with `at` so its arrow sweeps in, and a `bracket` where a note covers a run of rows. Write the notes of a compare as a pair that argue the change: \"The type gets the headline…\" on the before, \"The message becomes the starting point.\" on the after.\n\nMark the change at its own size: the bar, field, or label that changed. What stayed the same goes unmarked, or in one sentence above the screenshots. Keep it to about six marks per screenshot, fewer in a compare.\n\n## Syntax\n\n```md\n::compare\n:::screenshot{src=\"before.png\" alt=\"Filter toolbar wrapping onto a second row\" viewport=\"1440x900\" href=\"https://pr12.preview.example.com/correlations\"}\n::::annotation{x=3.6 y=20.6 w=92.9 h=31.4 color=\"red\"}\nMoon phase and vibes don't fit, so the toolbar wraps and pushes the table down.\n::::\n:::\n\n:::screenshot{src=\"after.png\" alt=\"Filter toolbar on one row\" viewport=\"1440x900\"}\n::::annotation{x=87.6 y=24.2 w=7.4 h=9.9 mark=\"check\" color=\"green\"}\n**Apply** lines up with the chips.\n::::\n:::\n::\n```\n\n- `::compare`: `title` is optional and names the comparison for screen readers. `mode` is `columns` (default, side by side) or `slider`. `ink` colors every annotation in both screenshots that doesn't set its own `color`. Its two screenshots are titled Before and After unless they set their own.\n- `::screenshot`: `src` and `alt` are required; `title` (the heading above the image), `href` (the captured page, linked by its host), `viewport` (like `1440x900`), and `ink` are optional. Other content becomes the caption.\n- `::annotation`: `x y w h` are required percentages of the image, numbers from 0 to 100 without `%`. `mark` is `box` (default), `circle`, `underline`, `line` (straight through the middle, along the longer side), `highlight`, `bracket` (down the side of a box at least twice as tall as it is wide, and across a wide one, whatever its `side`), `cross`, `check`, or `none`, which needs a `side`. `color` is `violet` (default) to point something out, `red` for a problem, `amber` for a warning, `green` for a fix, `blue` for a second voice, `gray` for neutral, or a 3- or 6-digit hex color. `side` is `top`, `bottom`, `left`, or `right`; keep top or bottom notes at least a quarter of the image apart and left or right notes an eighth apart.\n- `at` moves a side note along its margin, as a percentage of the image (across for top and bottom, down for left and right). A note set off from its point reads away from it, so put it on the side with room: a top note at `at=40` pointing left of 40 reads to the right. `to=\"x,y\"` is the point the arrow lands on, measured like the box; without it the arrow meets the middle of the mark's facing edge. Both need a `side`.\n- Annotations must be direct children of a screenshot.\n\n## Measure every mark\n\nTake each mark's coordinates from the page, in the browser you captured. Measure the element and divide by the viewport:\n\n```js\nconst r = document.querySelector(\"SELECTOR\").getBoundingClientRect();\n[(r.x / innerWidth) * 100, (r.y / innerHeight) * 100, (r.width / innerWidth) * 100, (r.height / innerHeight) * 100].map((v) => +v.toFixed(1));\n```\n\nFor a full-page screenshot, add `scrollX`/`scrollY` and divide by `document.documentElement.scrollWidth` and `scrollHeight` instead.\nFor a clipped capture, `getBoundingClientRect()` and Playwright's main-frame `clip` both use viewport-relative coordinates, so the formula takes no scroll offsets. Make sure the clip fully contains every marked element. Subtract the clip's `x` and `y` and divide by its `width` and `height`; if an element crosses the clip edge, intersect its measured rectangle with the clip before normalizing so every value stays between 0 and 100. If the clip is in document coordinates, convert it to viewport coordinates before subtracting.\n\n## Preview\n\nMake comark-annotate a direct dependency of the workspace package where you run the CLI, so its executable links. If it is only transitive, read the installed Comark UI version and add that exact version, such as `pnpm add -D comark-annotate@<version>` (add `-w` at the workspace root), because `@latest` could fetch a different renderer release. With no Comark UI packages installed, omit `@<version>`.\n\n```sh\nvp exec comark-annotate render report.md -o report.html\n```\n\n`render` writes a standalone page of the screenshots and compares, and relative `src` paths resolve next to it. Without comark-linter, `vp exec comark-annotate check report.md` lists these blocks' problems on its own. It names each one like `screenshot \"after.png\", annotation 2`, counting annotations within their screenshot, and exits with 1 while any remain.\n\n## Register\n\n- In `comark-ui`: on, in `comark-ui/html` only.\n- Alone: `pnpm add comark @comark/html comark-annotate`, then `createHtmlRenderer({ plugins: [annotate()], components })` with both from `comark-annotate/html`. It renders only to HTML. Screenshots reserve their `viewport`, or dimensions from a data URI. `annotate({ size: true })` also fetches remote screenshots at render time; enable it only for trusted documents, since requests follow redirects and can reach private networks. `annotate({ size: false })` disables measurement while retaining authored viewports. In `comark-ui`, put these options under `annotate`. Each document inlines the styles once, with style attributes for positions, so a strict Content Security Policy needs `style-src 'unsafe-inline'`.\n"
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
"path": "references/badge.md",
|
|
@@ -244,6 +244,10 @@ const skills = [
|
|
|
244
244
|
"path": "references/tests.md",
|
|
245
245
|
"text": "# Test results\n\ncomark-tests reads a JUnit XML report into one line of passed, failed, and skipped counts with the run's duration, and folds each failure under it with its message and stack. Use it when a pull request or a CI summary reports a test run, so the reader sees the run itself.\n\n## Syntax\n\n````md\n::tests{title=\"Pond census tests\"}\n```xml\n<testsuite name=\"pond.test.ts\" time=\"0.42\">\n <testcase classname=\"pond.test.ts\" name=\"counts the ducks\" time=\"0.01\"/>\n <testcase classname=\"pond.test.ts\" name=\"counts the geese\" time=\"0.02\">\n <failure message=\"expected 3 to be 4\">AssertionError: expected 3 to be 4\n at pond.test.ts:12:20</failure>\n </testcase>\n <testcase classname=\"pond.test.ts\" name=\"maps the herons\"><skipped/></testcase>\n</testsuite>\n```\n::\n````\n\nOr read the report from a file, and leave the block empty:\n\n```md\n::tests{src=\"reports/junit.xml\" title=\"CI run\"}\n::\n```\n\n| Prop | What it does |\n| --- | --- |\n| `src` | The JUnit XML file to read. The path starts at the document's folder, or at the host's `root` when it starts with `/`, and it can't leave `root` or be a URL. Without `src`, the block holds one fence with the report. |\n| `title` | Shown before the counts. It also names the results for screen readers, which hear \"Test results\" without one. |\n\nThe block shows:\n\n- The counts of `<testcase>` elements. A case with `<skipped>` is skipped, one with `<failure>` or `<error>` failed, and the rest passed. Failed and skipped show only when there are any.\n- The duration, from the `time` of `<testsuites>`, else the sum of the suites' times, else the cases', written as `250 ms`, `4.2 s`, or `1 min 21 s`. A report without times shows none.\n- Each failure as a closed disclosure named `classname › name`, with its `message` and its stack in a code block. In print, every failure prints open.\n\nThe root is `<testsuites>` or a single `<testsuite>`. A report with another root renders nothing, and so does malformed XML, which the plugin reports with its line.\n\n## Use the run's own report\n\nPaste or point at the report the runner wrote, unedited, so the counts are the run's. Most runners write JUnit XML with a flag:\n\n| Runner | Command |\n| --- | --- |\n| Vitest | `vitest run --reporter=junit --outputFile=junit.xml` |\n| Jest | `jest --reporters=jest-junit` |\n| pytest | `pytest --junitxml=junit.xml` |\n| Go | `go test -v ./... 2>&1 \\| go-junit-report > junit.xml` |\n| Playwright | `PLAYWRIGHT_JUNIT_OUTPUT_NAME=junit.xml playwright test --reporter=junit` |\n\nWhen the host reads files, have CI write the report next to the document and point `src` at it. Otherwise paste it into the fence. A long report stays short on the page, since the summary is one line and each failure stays closed until a reader opens it.\n\n## Register\n\n- In `comark-ui`: on. A pasted report renders, and every `src` reports a missing file until you pass `tests: { root: \".\" }` or `{ read }`.\n- Alone: `pnpm add comark @comark/html comark-tests`, then `createHtmlRenderer({ plugins: [tests({ root: \".\" })], components })` with both from `comark-tests/html`. `root` is the folder `src` can't leave, default `.`, the working directory. `base` is the document's folder under it, where relative paths start. `read(path)` returns a file's text, for browsers and edge runtimes. The output needs no script. `comark-tests/vue`, `/react`, and `/svelte` render it too. With comark-code registered, each stack gets a Copy button.\n"
|
|
246
246
|
},
|
|
247
|
+
{
|
|
248
|
+
"path": "references/time.md",
|
|
249
|
+
"text": "# Dates as relative time\n\ncomark-time draws `:time[2026-11-02]` as the words a reader would say, such as \"2 days ago\" or \"in 3 weeks\", and past a threshold as a date, such as \"Sep 30\". Hover or focus opens a tooltip with the full date and time. Use it where a document says when something happened or will: when a pull request opened, when a benchmark ran, when a deadline falls. Write the date in ISO form and leave the words to the plugin.\n\n## Syntax\n\n```md\nOpened :time[2026-11-02], last run :time[2026-11-04T11:59:56Z], due :time[2026-11-25].\n\nThe first sighting was :time[2026-09-30]{threshold=\"8w\"}.\n```\n\n- The date goes in the brackets: `2026-11-02`, or with a time of day, `2026-11-02T09:30:00Z`. A date alone counts whole days, so it reads \"today\", \"yesterday\", \"2 days ago\", or \"in 3 days\", never hours. A time with no offset is in the `timeZone` option's zone.\n- `threshold` sets how far from now it stops reading as relative: a number and `s`, `m`, `h`, `d`, `w`, `mo`, or `y`, such as `3w`. The default is `4w`. `none` keeps it relative at any distance.\n- Past the threshold the text is \"Sep 30\", or \"Sep 30, 2025\" in another year, and the tooltip shows how far away it is. Before it, the tooltip shows the full date, with the time and zone when the date has one.\n- No script runs. The words are worked out while parsing and are fixed in rendered HTML, so \"2 days ago\" stays that until the document is parsed again.\n\n## Write the dates\n\n- Write the exact date from the source: the pull request's `createdAt`, the report's timestamp. Never write \"yesterday\" or \"last week\" in prose for a date a reader may look up.\n- A zone-less date and time is read in the host's zone, which the reader can't see. Give a time an offset, such as `Z`, unless it is the author's local time.\n- A date the plugin can't read, such as `next friday` or `2026-02-31`, is shown as written and reported. Fix it to ISO.\n- Leave the threshold alone unless a date is better read as one or the other: `threshold=\"none\"` for a date that must always read relative, a short one such as `1w` for a date that is better absolute within a month.\n\n## Register\n\n- In `comark-ui`: on. `comarkUi({ time: { now, threshold, locale, timeZone } })` passes its options; `now` pins the moment every date is measured from, which a host that caches rendered HTML should do. `time: false` turns it off.\n- Alone: `pnpm add comark @comark/html comark-time`, then `createHtmlRenderer({ plugins: [time()], components })` with both from `comark-time/html`. `comark-time/vue`, `/react`, and `/svelte` render it too. It has no script.\n"
|
|
250
|
+
},
|
|
247
251
|
{
|
|
248
252
|
"path": "references/ui.md",
|
|
249
253
|
"text": "# Every plugin in one install\n\ncomark-ui registers every comark-ui package for one renderer, in the order they need, with one icon resolver shared by `:icon`, cards, details, file trees, tabs, and code actions. SKILL.md's Install section shows the basic use. This page covers the options, what the preset turns on, the other renderers, and how the linter uses it.\n\n## Options\n\n`comarkUi(options)` returns `{ plugins, components }`. Each key is a package's name without `comark-`, in camelCase, such as `fileTree`, `codeNotes`, or `readingTime`. The exceptions are `math` for comark-mathml, `outline` for comark-outline, and `mermaid`, `shiki`, and `typeset`, which are not packages. `false` turns a plugin off along with its components, and an object turns it on with those options. `true` turns on `include` and leaves the others as they are:\n\n```ts\ncomarkUi({\n zoom: false,\n code: { actions: [{ id: \"run\", label: \"Run\" }] },\n github: { callouts: false, references: { repo: \"owner/name\" } },\n table: { root: \"data\" },\n include: { root: \"content\", base: \"guide\" },\n});\n```\n\n`github` takes its three plugins by name, `callouts`, `references`, and `html`, and `links` takes `external` and `anchors`. Each package's reference lists its own options. The order stays fixed whatever you pass: `include` runs first, so the others read what it pastes, and `code` and `codeNotes` run late, after every plugin that writes code blocks.\n\n## What it turns on\n\n- Every plugin except `include`, which reads files from disk. `include: { root, base }` turns it on, or `{ read }` in a browser or an edge runtime. `include: true` reads under the working directory.\n- `cast`, `table`, and `tests` get a reader that finds no file. Inline casts, CSV fences, and pasted JUnit reports render, and a `src` file doesn't load until you pass `{ root }` or `{ read }`. Any other options object replaces that reader too, so the plugin reads under the working directory.\n- Three plugins use the network while parsing by default: `chips` downloads favicons and avatars, `icon` fetches icon sets from the Iconify API, and `diagrams` sends each diagram's source to `https://kroki.io`. In a browser, pass `chips: { download: false }`, because a browser may not download another site's images. To parse offline, also pass `icon: { fetch: false }` with your icon sets in `collections`, and `diagrams: { draw: false }`. To keep diagram sources private, pass your own Kroki `server`.\n- Media sizing reads only data URIs by default. `zoom: { size: true }` and `media: { size: true }` also fetch remote files while parsing, and `annotate: { size: true }` does so at HTML render time. Enable these only for trusted documents, because the requests follow redirects and can reach private networks. `{ size: false }` turns measurement off for that plugin; authored dimensions and screenshot viewports still work.\n- `icon`'s options apply to every icon the preset draws, in cards, details, file trees, tabs, and code actions too.\n- `mermaid` draws `mermaid` fences with comark-pele, on the server and offline. In the HTML entry the diagram zooms with comark-zoom unless `zoom` is `false`. `mermaid: false` turns it off.\n- `shiki` highlights fenced code with your own Shiki, before comark-code: `{ highlighter: (language) => shiki | undefined, themes: { light, dark } }`. It is off until you pass it, so the preset bundles no grammars. `maxBlocks` and `maxSource` cap how many blocks, and how many characters of code, a document highlights; the blocks past them show plain, each with an issue.\n- comark-critic has no component to add its styles, so put `criticCss`, which every entry exports, in the page.\n- The preset styles the text around the blocks, scoped to the element the document renders into, on the same `--comark-*` tokens. Pass `typeset: false` when the site already styles Markdown, such as with Tailwind Typography's `prose`.\n\n## Renderers\n\n| Renderer | Entry |\n| --- | --- |\n| `@comark/html` | `comark-ui/html` |\n| `@comark/vue` | `comark-ui/vue` |\n| `@comark/react` | `comark-ui/react` |\n| `@comark/svelte` | `comark-ui/svelte` |\n\nThe Vue, React, and Svelte entries leave out annotate, comments, diff, and quiz, which render only to HTML. Screenshots, compares, diffs, suggestions and comments, and the marks on charts need `comark-ui/html`.\n\nTo use another renderer, install it in place of `@comark/html`, such as `pnpm add comark @comark/vue comark-ui`, and pass it `plugins` and `components` as you would one package's. The preset needs Vue 3.5, React 18, or Svelte 5.20 or later. Every entry exports the `PresetOptions` type, and `comark-ui` itself exports `preset(renderer, options)`, which builds the same pair from renderer entries you pass.\n\n## In the linter\n\ncomark-linter imports `comark-ui/html` when the project has it, and lints with all its plugins and components, ahead of any comark package installed on its own, so none runs twice. It calls `comarkUi()` with options of its own, so the app's options don't reach it:\n\n- It draws no chart or diagram, and downloads no chip image.\n- `::cast`, `::table`, and `::tests` read their `src` files from the working directory.\n- `include` stays off until a lint config adds it, as [include](include.md) says.\n\n## Register\n\n- In `comark-ui`: this is the preset itself, registered as Install in SKILL.md shows.\n- Alone: each plugin is its own package, registered as its reference says. The preset ships in lockstep with them, so `comark-ui@X` holds every plugin at version `X`.\n"
|
|
@@ -341,6 +345,6 @@ const skills = [
|
|
|
341
345
|
}
|
|
342
346
|
];
|
|
343
347
|
/** The comark-ui version the skills come from, for a host's cache key or a digest. */
|
|
344
|
-
const version = "0.
|
|
348
|
+
const version = "0.10.0";
|
|
345
349
|
//#endregion
|
|
346
350
|
export { skills, version };
|