contactsheet 0.1.6 → 0.1.7
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 +2 -1
- package/dist/canvas/app.js +39 -10
- package/dist/canvas/app.js.map +2 -2
- package/dist/canvas/style-pins.css +54 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -152,7 +152,8 @@ open(橙) ──标记完成──▶ resolved(绿·待核验) ──核验通
|
|
|
152
152
|
这份文件就是历史记录,日后沉淀 skill / 复盘"当初都提过什么、怎么改的"的原料。
|
|
153
153
|
- 「删除」只留给误钉的 pin,会真的从历史里抹掉。
|
|
154
154
|
- `Cmd/Ctrl + V` → 贴图,存进 `design/.canvas/refs/`。**在批注输入框或气泡编辑态里粘贴 = 挂到这条批注**
|
|
155
|
-
(缩略图跟着 pin 走,推给 Claude
|
|
155
|
+
(缩略图跟着 pin 走,推给 Claude 的上下文里带上它的路径);在别处粘贴才进右下角的全局坞。
|
|
156
|
+
气泡里的图显示为「图片 n」占位符 + 缩略图,点开大图;**悬停缩略图出 ✕ 可从批注移除**(文件保留在 refs/)
|
|
156
157
|
- `Ctrl + 滚轮` / 捏合 → 以光标为锚点缩放(0.05–2 倍);空白处拖拽或双指滚动 → 平移
|
|
157
158
|
- `1` 全景(一屏看完整面墙)· `2` 聚焦当前画板 · `0` 回到 100% · `+` / `-` 步进缩放
|
|
158
159
|
- 点一个 pin 选中它,然后 `Enter` 编辑(编辑中再按 `Enter` 保存,`Shift+Enter` 换行)、
|
package/dist/canvas/app.js
CHANGED
|
@@ -383,7 +383,7 @@ ${board.entry.kind} \xB7 ${board.entry.id}`);
|
|
|
383
383
|
function refSrc(path) {
|
|
384
384
|
return localSrc.get(path) ?? refUrl(path);
|
|
385
385
|
}
|
|
386
|
-
function refThumb(path) {
|
|
386
|
+
function refThumb(path, opts) {
|
|
387
387
|
const card = h("div", "cs-ref-thumb");
|
|
388
388
|
card.title = path;
|
|
389
389
|
const img = h("img");
|
|
@@ -395,11 +395,21 @@ ${board.entry.kind} \xB7 ${board.entry.id}`);
|
|
|
395
395
|
img.alt = path;
|
|
396
396
|
img.src = refSrc(path);
|
|
397
397
|
if (img.complete && img.naturalWidth === 0) broken();
|
|
398
|
-
card.append(img, h("span", "cs-ref-name", fileOf(path)));
|
|
398
|
+
card.append(img, h("span", "cs-ref-name", opts?.index ? `\u56FE\u7247 ${opts.index}` : fileOf(path)));
|
|
399
399
|
card.addEventListener("click", (e) => {
|
|
400
400
|
e.stopPropagation();
|
|
401
401
|
openLightbox(refSrc(path), path);
|
|
402
402
|
});
|
|
403
|
+
if (opts?.onRemove) {
|
|
404
|
+
const rm = h("button", "cs-ref-rm", "\u2715");
|
|
405
|
+
rm.title = "\u4ECE\u8FD9\u6761\u6279\u6CE8\u79FB\u9664(\u6587\u4EF6\u4FDD\u7559\u5728 refs/)";
|
|
406
|
+
rm.setAttribute("aria-label", rm.title);
|
|
407
|
+
rm.addEventListener("click", (e) => {
|
|
408
|
+
e.stopPropagation();
|
|
409
|
+
opts.onRemove?.();
|
|
410
|
+
});
|
|
411
|
+
card.appendChild(rm);
|
|
412
|
+
}
|
|
403
413
|
return card;
|
|
404
414
|
}
|
|
405
415
|
function openLightbox(src, caption) {
|
|
@@ -806,16 +816,25 @@ ${board.entry.kind} \xB7 ${board.entry.id}`);
|
|
|
806
816
|
}, 250);
|
|
807
817
|
});
|
|
808
818
|
}
|
|
809
|
-
function refStrip(paths) {
|
|
819
|
+
function refStrip(paths, onRemove) {
|
|
810
820
|
const strip = h("div", "cs-ref-strip");
|
|
811
|
-
|
|
821
|
+
paths.forEach(
|
|
822
|
+
(p, i) => strip.appendChild(refThumb(p, { index: i + 1, onRemove: onRemove ? () => onRemove(p) : void 0 }))
|
|
823
|
+
);
|
|
812
824
|
return strip;
|
|
813
825
|
}
|
|
814
826
|
function bubble(ann) {
|
|
815
827
|
const box = h("div", "cs-pin-bubble");
|
|
816
828
|
const textEl = h("div", "cs-pin-text", ann.text);
|
|
817
829
|
box.appendChild(textEl);
|
|
818
|
-
if (ann.refs?.length)
|
|
830
|
+
if (ann.refs?.length) {
|
|
831
|
+
box.appendChild(
|
|
832
|
+
refStrip(ann.refs, (path) => {
|
|
833
|
+
const next = (ann.refs ?? []).filter((r) => r !== path);
|
|
834
|
+
void transition(ann.id, { refs: next }, "\u53C2\u8003\u56FE\u5DF2\u79FB\u9664(\u6587\u4EF6\u4FDD\u7559\u5728 refs/ \u91CC)");
|
|
835
|
+
})
|
|
836
|
+
);
|
|
837
|
+
}
|
|
819
838
|
const meta = h("div", "cs-pin-meta");
|
|
820
839
|
meta.appendChild(h("span", void 0, ann.status === "open" ? "open" : "\u5F85\u6838\u9A8C"));
|
|
821
840
|
const act = (label, cls, fn) => {
|
|
@@ -861,15 +880,24 @@ ${board.entry.kind} \xB7 ${board.entry.id}`);
|
|
|
861
880
|
const ta = h("textarea", "cs-pin-edit");
|
|
862
881
|
ta.value = ann.text;
|
|
863
882
|
const refs = [...ann.refs ?? []];
|
|
864
|
-
|
|
865
|
-
|
|
883
|
+
let strip = box.querySelector(".cs-ref-strip");
|
|
884
|
+
const redrawStrip = () => {
|
|
885
|
+
const next = refStrip(refs, (path) => {
|
|
886
|
+
refs.splice(refs.indexOf(path), 1);
|
|
887
|
+
redrawStrip();
|
|
888
|
+
});
|
|
889
|
+
if (strip?.isConnected) strip.replaceWith(next);
|
|
890
|
+
else box.insertBefore(next, box.querySelector(".cs-pin-meta"));
|
|
891
|
+
strip = next;
|
|
892
|
+
};
|
|
893
|
+
redrawStrip();
|
|
866
894
|
setPasteTarget({
|
|
867
895
|
el: box,
|
|
868
896
|
onFile: (file) => {
|
|
869
897
|
void uploadRef(file).then((path) => {
|
|
870
898
|
refs.push(path);
|
|
871
|
-
|
|
872
|
-
toast(`\u53C2\u8003\u56FE\u5DF2\u4E0A\u4F20
|
|
899
|
+
redrawStrip();
|
|
900
|
+
toast(`\u53C2\u8003\u56FE\u5DF2\u4E0A\u4F20 \u2014\u2014 \u70B9\u300C\u4FDD\u5B58\u300D\u540E\u624D\u6302\u5230\u8FD9\u6761\u6279\u6CE8`, "ok");
|
|
873
901
|
}).catch((err) => toast(`\u53C2\u8003\u56FE\u4E0A\u4F20\u5931\u8D25:${String(err)}`, "error"));
|
|
874
902
|
}
|
|
875
903
|
});
|
|
@@ -890,7 +918,7 @@ ${board.entry.kind} \xB7 ${board.entry.id}`);
|
|
|
890
918
|
e.stopPropagation();
|
|
891
919
|
const text = ta.value.trim();
|
|
892
920
|
const textChanged = !!text && text !== ann.text;
|
|
893
|
-
const refsChanged = refs
|
|
921
|
+
const refsChanged = JSON.stringify(refs) !== JSON.stringify(ann.refs ?? []);
|
|
894
922
|
if (!textChanged && !refsChanged) return renderPins();
|
|
895
923
|
const patch = {};
|
|
896
924
|
if (textChanged) patch.text = text;
|
|
@@ -1255,6 +1283,7 @@ ${board.entry.kind} \xB7 ${board.entry.id}`);
|
|
|
1255
1283
|
viewport.addEventListener(
|
|
1256
1284
|
"wheel",
|
|
1257
1285
|
(e) => {
|
|
1286
|
+
if (e.target?.closest?.(".cs-pin-bubble, .cs-pin-input")) return;
|
|
1258
1287
|
e.preventDefault();
|
|
1259
1288
|
if (e.ctrlKey || e.metaKey) {
|
|
1260
1289
|
zoomAt(e.clientX, e.clientY, Math.exp(-e.deltaY / 260));
|