htmldeck 0.1.0__py3-none-any.whl
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.
- htmldeck/__init__.py +0 -0
- htmldeck/__main__.py +4 -0
- htmldeck/notes.py +86 -0
- htmldeck/server.py +739 -0
- htmldeck/web/css/editor.css +474 -0
- htmldeck/web/index.html +449 -0
- htmldeck/web/js/app.mjs +4161 -0
- htmldeck/web/js/core/history.mjs +38 -0
- htmldeck/web/js/core/model.mjs +46 -0
- htmldeck/web/js/core/operations.mjs +62 -0
- htmldeck/web/js/core/sanitize.mjs +11 -0
- htmldeck/web/js/core/serializer.mjs +216 -0
- htmldeck/web/js/core/utils.mjs +25 -0
- htmldeck/web/js/formats/registry.mjs +15 -0
- htmldeck/web/js/formats/reveal.mjs +139 -0
- htmldeck/web/js/fx/runtime.mjs +326 -0
- htmldeck/web/js/i18n.mjs +1227 -0
- htmldeck/web/js/policy/edit-policy.mjs +32 -0
- htmldeck/web/js/present/render.mjs +200 -0
- htmldeck/web/js/present/session.mjs +72 -0
- htmldeck/web/js/runtime/freeze.mjs +37 -0
- htmldeck/web/js/runtime/provenance.mjs +49 -0
- htmldeck/web/js/services/api.mjs +10 -0
- htmldeck-0.1.0.dist-info/METADATA +163 -0
- htmldeck-0.1.0.dist-info/RECORD +29 -0
- htmldeck-0.1.0.dist-info/WHEEL +5 -0
- htmldeck-0.1.0.dist-info/entry_points.txt +3 -0
- htmldeck-0.1.0.dist-info/licenses/LICENSE +21 -0
- htmldeck-0.1.0.dist-info/top_level.txt +1 -0
htmldeck/__init__.py
ADDED
|
File without changes
|
htmldeck/__main__.py
ADDED
htmldeck/notes.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""List (or resolve) review notes pinned in the HTML editor, for an agent to act on.
|
|
2
|
+
|
|
3
|
+
Notes live beside the document in ``.htmldeck_notes/<name>.json``. Each carries the CSS
|
|
4
|
+
selector of the element, the source line at the time it was pinned, and a text snippet;
|
|
5
|
+
this runner re-locates the line in the current file so it stays useful after edits.
|
|
6
|
+
|
|
7
|
+
Run (in the workspace, or with --root):
|
|
8
|
+
htmldeck-notes --file output/deck.html
|
|
9
|
+
htmldeck-notes --file output/deck.html --done <id>
|
|
10
|
+
(or python -m htmldeck.notes ...)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from htmldeck.server import EditorError, apply_note_ops, display_path, notes_path, read_notes, utf8_stdio
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def current_line(source: str, note: dict) -> int | None:
|
|
23
|
+
"""Line of the note's snippet nearest to where it was pinned, else the pinned line."""
|
|
24
|
+
snippet = " ".join(note.get("text", "").split())[:40]
|
|
25
|
+
pinned = note.get("line")
|
|
26
|
+
lines = []
|
|
27
|
+
idx = source.find(snippet) if snippet else -1
|
|
28
|
+
while idx >= 0:
|
|
29
|
+
lines.append(source.count("\n", 0, idx) + 1)
|
|
30
|
+
idx = source.find(snippet, idx + 1)
|
|
31
|
+
if not lines:
|
|
32
|
+
return pinned
|
|
33
|
+
return min(lines, key=lambda n: abs(n - pinned)) if pinned else lines[0]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def format_notes(target: Path, notes: list[dict], show_all: bool, root: Path | None = None) -> str:
|
|
37
|
+
root = root or Path.cwd()
|
|
38
|
+
source = target.read_text(encoding="utf-8") if target.is_file() else ""
|
|
39
|
+
shown = [n for n in notes if show_all or n.get("status") == "open"]
|
|
40
|
+
if not shown:
|
|
41
|
+
return f"Không có ghi chú {'nào' if show_all else 'đang mở'} cho {display_path(target, root)}."
|
|
42
|
+
lines = [f"# Ghi chú cần sửa — {display_path(target, root)} ({len(shown)})", ""]
|
|
43
|
+
for i, n in enumerate(shown, 1):
|
|
44
|
+
where = [f"dòng {current_line(source, n) or '?'}"]
|
|
45
|
+
if n.get("slide") is not None:
|
|
46
|
+
where.append(f"slide {n['slide'] + 1}")
|
|
47
|
+
lines.append(f"{i}. [{n['status']}] id={n['id']} · {' · '.join(where)} · <{n.get('tag', '?')}>")
|
|
48
|
+
lines.append(f" selector: {n.get('selector', '')}")
|
|
49
|
+
if n.get("text"):
|
|
50
|
+
lines.append(f" đoạn chữ: \"{n['text'][:160]}\"")
|
|
51
|
+
lines.append(f" → {n['note']}")
|
|
52
|
+
lines.append("")
|
|
53
|
+
return "\n".join(lines).rstrip()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def main(argv: list[str] | None = None):
|
|
57
|
+
parser = argparse.ArgumentParser(description="List review notes left in the HTML editor")
|
|
58
|
+
parser.add_argument("--root", default=".", help="Workspace folder (default: the current folder)")
|
|
59
|
+
parser.add_argument("--file", required=True, help="HTML document the notes belong to")
|
|
60
|
+
parser.add_argument("--all", action="store_true", help="Include notes already marked done")
|
|
61
|
+
parser.add_argument("--done", metavar="ID", action="append", default=[], help="Mark a note as done (repeatable)")
|
|
62
|
+
args = parser.parse_args(argv)
|
|
63
|
+
utf8_stdio()
|
|
64
|
+
|
|
65
|
+
root = Path(args.root).expanduser().resolve()
|
|
66
|
+
target = Path(args.file).expanduser()
|
|
67
|
+
target = (target if target.is_absolute() else root / target).resolve()
|
|
68
|
+
notes = read_notes(target)
|
|
69
|
+
if args.done:
|
|
70
|
+
known = {n["id"] for n in notes}
|
|
71
|
+
missing = [i for i in args.done if i not in known]
|
|
72
|
+
if missing:
|
|
73
|
+
print(f"Không tìm thấy ghi chú: {', '.join(missing)}", file=sys.stderr)
|
|
74
|
+
sys.exit(1)
|
|
75
|
+
try:
|
|
76
|
+
apply_note_ops(target, [{"op": "update", "id": i, "patch": {"status": "done"}} for i in args.done], root)
|
|
77
|
+
except EditorError as exc:
|
|
78
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
print(f"Đã đánh dấu xong {len(args.done)} ghi chú → {display_path(notes_path(target), root)}")
|
|
81
|
+
return
|
|
82
|
+
print(format_notes(target, notes, args.all, root))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
main()
|