@easysociable/cli 0.1.2 → 0.1.4
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 +32 -21
- package/{skills/easysociable-content → content-engine}/scripts/starter.mjs +3 -1
- package/{skills/easysociable-content → content-engine}/scripts/workbench.mjs +13 -8
- package/{skills/easysociable-content → content-engine}/starter/CLAUDE.md +217 -128
- package/{skills/easysociable-content → content-engine}/starter/engine.json +3 -0
- package/content-engine/starter/needs/README.md +38 -0
- package/content-engine/starter/needs/_index.md +31 -0
- package/content-engine/starter/needs/_template.md +24 -0
- package/content-engine/starter/needs/entries/README.md +5 -0
- package/content-engine/starter/products/README.md +38 -0
- package/content-engine/starter/products/_index.md +24 -0
- package/content-engine/starter/products/_template.md +56 -0
- package/content-engine/starter/products/entries/P-001-easysociable.md +150 -0
- package/content-engine/starter/profiles/_index.md +16 -0
- package/{skills/easysociable-content → content-engine}/starter/profiles/default/README.md +4 -1
- package/content-engine/starter/profiles/default/boundaries.md +14 -0
- package/content-engine/starter/profiles/default/expression.md +18 -0
- package/content-engine/starter/profiles/default/lanes.md +12 -0
- package/content-engine/starter/profiles/default/stories.md +15 -0
- package/{skills/easysociable-content → content-engine}/starter/profiles/default/voice.md +14 -0
- package/content-engine/starter/recommendations/README.md +21 -0
- package/content-engine/starter/recommendations/_index.md +21 -0
- package/content-engine/starter/recommendations/_template.md +44 -0
- package/{skills/easysociable-content → content-engine}/starter/runs/_template/brief.md +1 -1
- package/{skills/easysociable-content → content-engine}/starter/runs/_template/pack.md +15 -7
- package/{skills/easysociable-content → content-engine}/starter/runs/_template/packet.md +6 -0
- package/{skills/easysociable-content → content-engine}/starter/swipe/_template.md +3 -1
- package/content-engine/starter/topics/README.md +21 -0
- package/{skills/easysociable-content → content-engine}/starter/topics/_index.md +12 -5
- package/content-engine/starter/topics/_template-item.md +103 -0
- package/{skills/easysociable-content → content-engine}/starter/topics/scoring.md +55 -4
- package/content-engine/workbench/__pycache__/build.cpython-310.pyc +0 -0
- package/{skills/easysociable-content → content-engine}/workbench/build.py +306 -97
- package/{skills/easysociable-content → content-engine}/workbench/serve.py +0 -0
- package/{skills/easysociable-content → content-engine}/workbench/template.html +173 -27
- package/dist/easysociable.js +629 -142
- package/dist/easysociable.js.map +1 -1
- package/package.json +15 -15
- package/skills/ONBOARDING.md +21 -18
- package/skills/easysociable-content/SKILL.md +104 -98
- package/skills/easysociable-content/workflows/INTERVIEW.md +70 -0
- package/skills/easysociable-content/workflows/NEEDS.md +82 -0
- package/skills/easysociable-slideshow/SKILL.md +79 -44
- package/skills/easysociable-slideshow/references/ARC.md +44 -0
- package/skills/easysociable-slideshow/references/CONTENT_PACK.md +34 -6
- package/skills/easysociable-slideshow/workflows/CREATE_RUN.md +24 -5
- package/skills/easysociable-slideshow/workflows/OUT_OF_SCOPE.md +3 -0
- package/skills/easysociable-template/SKILL.md +29 -30
- package/skills/easysociable-template/references/CATALOG_METADATA.md +23 -20
- package/skills/easysociable-template/references/DESIGN_V2_1.md +53 -2
- package/skills/easysociable-template/references/GATEWAY.md +7 -2
- package/skills/easysociable-template/references/PLATFORM_SPECS.md +11 -3
- package/skills/easysociable-template/references/THEME_TOKENS.md +1 -1
- package/skills/easysociable-template/references/fixtures/image-reference.design-plan.json +74 -0
- package/skills/easysociable-template/references/fixtures/image-reference.visual-qa.json +28 -0
- package/skills/easysociable-template/scripts/generate-theme-from-hex.mjs +0 -0
- package/skills/easysociable-template/scripts/validate-design-v2.mjs +97 -0
- package/skills/easysociable-template/workflows/ASSET_PLAN.md +2 -1
- package/skills/easysociable-template/workflows/AUTHORING_FROM_BRIEF.md +4 -4
- package/skills/easysociable-template/workflows/AUTHORING_FROM_IMAGE.md +66 -16
- package/skills/easysociable-template/workflows/AUTHORING_STUDIO.md +28 -15
- package/skills/easysociable-template/workflows/DESIGN_BRIEF.md +4 -3
- package/skills/easysociable-template/workflows/FILL_AND_RENDER.md +4 -83
- package/skills/easysociable-template/workflows/MULTI_PLATFORM_FAMILY.md +81 -0
- package/skills/easysociable-template/workflows/OUT_OF_SCOPE.md +3 -2
- package/skills/easysociable-template/workflows/PUBLISH_FROM_DRAFT.md +1 -1
- package/skills/easysociable-template/workflows/VISUAL_QA.md +10 -0
- package/skills/easysociable-content/INSTALL.md +0 -60
- package/skills/easysociable-content/platforms/claude.md +0 -4
- package/skills/easysociable-content/platforms/codex.md +0 -4
- package/skills/easysociable-content/platforms/hermes.md +0 -4
- package/skills/easysociable-content/platforms/openclaw.md +0 -4
- package/skills/easysociable-content/references/CLI.md +0 -40
- package/skills/easysociable-content/references/CONTRACT_SYNC.md +0 -42
- package/skills/easysociable-content/references/MCP.md +0 -15
- package/skills/easysociable-content/references/PAGE_PACK.md +0 -129
- package/skills/easysociable-content/references/PLATFORM_GUIDE.md +0 -36
- package/skills/easysociable-content/references/RUN_LAYOUT.md +0 -73
- package/skills/easysociable-content/references/TROUBLESHOOTING.md +0 -13
- package/skills/easysociable-content/references/VAULT.md +0 -40
- package/skills/easysociable-content/references/VOICE.md +0 -16
- package/skills/easysociable-content/scripts/package-skill.mjs +0 -49
- package/skills/easysociable-content/scripts/setup.mjs +0 -200
- package/skills/easysociable-content/scripts/setup.test.mjs +0 -82
- package/skills/easysociable-content/starter/discovery/README.md +0 -18
- package/skills/easysociable-content/starter/discovery/_index.md +0 -27
- package/skills/easysociable-content/starter/discovery/_template.md +0 -41
- package/skills/easysociable-content/starter/profiles/_index.md +0 -13
- package/skills/easysociable-content/starter/topics/README.md +0 -25
- package/skills/easysociable-content/starter/topics/WATCHLIST.md +0 -65
- package/skills/easysociable-content/starter/topics/_template-item.md +0 -90
- package/skills/easysociable-content/starter/topics/watchlists/README.md +0 -10
- package/skills/easysociable-content/starter/topics/watchlists/_shared.md +0 -14
- package/skills/easysociable-content/starter/topics/watchlists/default.md +0 -6
- package/skills/easysociable-content/workflows/ANALYSIS_AND_COVERAGE.md +0 -17
- package/skills/easysociable-content/workflows/CONTENT_EXPORT.md +0 -24
- package/skills/easysociable-content/workflows/GETTING_STARTED.md +0 -40
- package/skills/easysociable-content/workflows/MCP_FIRST.md +0 -5
- package/skills/easysociable-content/workflows/OUT_OF_SCOPE.md +0 -18
- package/skills/easysociable-content/workflows/PACK_AUTHORING.md +0 -42
- package/skills/easysociable-content/workflows/SWIPE_CAPTURE.md +0 -18
- package/skills/easysociable-content/workflows/TOPIC_DRAFT.md +0 -29
- package/skills/easysociable-content/workflows/WORKING_DRAFT.md +0 -19
- /package/{skills/easysociable-content → content-engine}/fixtures/golden-run-en/draft.md +0 -0
- /package/{skills/easysociable-content → content-engine}/fixtures/golden-run-en/idea.md +0 -0
- /package/{skills/easysociable-content → content-engine}/fixtures/golden-run-en/pack-tiktok.json +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/contracts.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/export-contracts.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/fixture.test.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/validate-export.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/validate-pack.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/validate-run.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/scripts/validate.test.mjs +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/accounts/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/accounts/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/accounts/overrides/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/exports/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/inbox/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/inbox/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/inbox/entries/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/ig.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/instagram.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/linkedin.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/threads.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/tiktok.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/x.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/platforms/xiaohongshu.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/profiles/default/audience.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/profiles/default/pillars.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/published/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/raw/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/raw/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/_template/draft.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/_template/editor.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/_template/feedback.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/_template/idea.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/runs/_template/rubric.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/swipe/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/topics/items/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/wiki/README.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/wiki/atoms/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/wiki/atoms/_template.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/wiki/claims/_index.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/wiki/claims/_template.md +0 -0
- /package/{skills/easysociable-content → content-engine}/starter/workbench/README.md +0 -0
|
@@ -158,8 +158,8 @@
|
|
|
158
158
|
.row.sel { border-color: var(--accent); box-shadow: var(--shadow); }
|
|
159
159
|
.stripe { border-radius: 14px 0 0 14px; background: var(--accent-dim); }
|
|
160
160
|
.row[data-kind="capture"] .stripe { background: #7d9aa8; }
|
|
161
|
+
.row[data-kind="need"] .stripe { background: #5a9e8f; }
|
|
161
162
|
.row[data-kind="raw"] .stripe { background: #6e7f6a; }
|
|
162
|
-
.row[data-kind="discovery"] .stripe { background: #6b7c8a; }
|
|
163
163
|
.row[data-kind="topic"] .stripe { background: var(--accent); }
|
|
164
164
|
.row[data-kind="swipe"] .stripe { background: #c4a06a; }
|
|
165
165
|
.row[data-kind="atom"] .stripe { background: #a78bb0; }
|
|
@@ -623,17 +623,17 @@
|
|
|
623
623
|
</div>
|
|
624
624
|
<script>
|
|
625
625
|
const GRAPH = /*__GRAPH__*/null;
|
|
626
|
-
const TRACE_ORDER = ["raw", "capture", "
|
|
626
|
+
const TRACE_ORDER = ["raw", "capture", "need", "product", "recommendation", "topic", "swipe", "atom", "claim", "run", "published"];
|
|
627
627
|
const STR = {
|
|
628
628
|
zh: {
|
|
629
629
|
title: "Content Engine · 观察台",
|
|
630
630
|
brand: "观察台",
|
|
631
631
|
search: "搜索 ID、一句话、来源…",
|
|
632
|
-
overview: "总览",
|
|
633
|
-
notes_in: "记下的", notes_lib: "进库的",
|
|
632
|
+
overview: "总览", needs: "需求库", products: "产品库", recommendations: "推荐库", topics: "选题库", notes: "记录与知识", runs: "Run 档案", pub: "发布与复盘",
|
|
633
|
+
notes_in: "记下的", notes_needs: "需求原话", notes_lib: "进库的",
|
|
634
634
|
lead: "先认 IP,再看库存。",
|
|
635
|
-
kpi_cap: "记下的", kpi_lib: "进库的", kpi_topics: "选题", kpi_out: "下场",
|
|
636
|
-
kpi_cap_sub: "Capture", kpi_lib_sub: "Swipe / Atom / Claim",
|
|
635
|
+
kpi_cap: "记下的", kpi_needs: "需求", kpi_lib: "进库的", kpi_topics: "选题", kpi_out: "下场",
|
|
636
|
+
kpi_cap_sub: "Capture", kpi_needs_sub: "Needs 原话", kpi_lib_sub: "Swipe / Atom / Claim",
|
|
637
637
|
kpi_topics_sub: "{n} 条 ready 未开单", kpi_out_sub: "Run / 已发帖",
|
|
638
638
|
ip_section: "IP · Profiles",
|
|
639
639
|
ip_all: "全部 Profile",
|
|
@@ -644,6 +644,8 @@
|
|
|
644
644
|
gap_section: "断链",
|
|
645
645
|
gap_none: "没有明显断链。",
|
|
646
646
|
gap_ready_n: "ready 选题未开单 {n}",
|
|
647
|
+
gap_needs_thin_n: "需求原话不足 3 条(出图硬门闩)· 现有 {n}",
|
|
648
|
+
gap_needs_n: "需求原话未选题 {n}",
|
|
647
649
|
gap_lib_n: "Capture 未入库 {n}",
|
|
648
650
|
gap_review_n: "已发但无法复盘 {n}",
|
|
649
651
|
kv_profile: "Profile",
|
|
@@ -657,6 +659,7 @@
|
|
|
657
659
|
doc_voice: "Voice",
|
|
658
660
|
doc_audience: "Audience",
|
|
659
661
|
doc_pillars: "Pillars",
|
|
662
|
+
doc_lanes: "Lanes",
|
|
660
663
|
empty_profile_t: "点选一个 Profile",
|
|
661
664
|
empty_profile_b: "右侧会显示该 IP 的支柱、账号、档案与断链。",
|
|
662
665
|
acct_handle: "Handle",
|
|
@@ -680,6 +683,7 @@
|
|
|
680
683
|
lib_claim_ev: "命题证据在本 claim 的 Evidence 表;命中率看 n/win/loss。",
|
|
681
684
|
f_status: "状态(登记)", f_pillar: "Pillar", f_src: "来源", f_use: "使用", f_unused: "未开单", f_promoted: "已开单",
|
|
682
685
|
f_sort: "排序",
|
|
686
|
+
f_sort_recommend: "报题优先",
|
|
683
687
|
f_sort_bookmarks: "Bookmarks ↓",
|
|
684
688
|
f_sort_replies: "Replies ↓",
|
|
685
689
|
f_sort_likes: "Likes ↓",
|
|
@@ -702,7 +706,8 @@
|
|
|
702
706
|
f_cap_ingest: "入库",
|
|
703
707
|
f_cap_ingested: "已入库",
|
|
704
708
|
f_cap_not_ingested: "未入库",
|
|
705
|
-
no_topic: "无匹配选题",
|
|
709
|
+
no_topic: "无匹配选题", no_note: "无匹配记录", no_need: "尚无需求原话", no_pub: "尚无已发帖",
|
|
710
|
+
need_empty_hint: "对 Agent 说「记需求:……」写入第一条读者原话。不要编造。",
|
|
706
711
|
no_stage: "无阶段文件",
|
|
707
712
|
empty_t: "从左边拾起一件东西",
|
|
708
713
|
empty_b: "它从哪来、有没有被写过、发过没有、值不值得再拿出来——会在这里连成一条。",
|
|
@@ -728,7 +733,7 @@
|
|
|
728
733
|
thin_warn: "数据不足:result 不是 win / flat / loss,不画趋势。",
|
|
729
734
|
topic_bind: "选题绑定:{t} · swipe {s} · claim {c}",
|
|
730
735
|
supersedes: "取代 {id}", superseded_by: "被取代 {id}",
|
|
731
|
-
kind_raw: "Raw", kind_capture: "Capture",
|
|
736
|
+
kind_raw: "Raw", kind_capture: "Capture", kind_need: "需求", kind_product: "产品", kind_recommendation: "推荐对象", kind_topic: "选题", kind_swipe: "Swipe",
|
|
732
737
|
kind_atom: "Atom", kind_claim: "Claim", kind_run: "Run", kind_published: "发布",
|
|
733
738
|
kv_kind: "类型", kv_date: "日期", kv_status: "状态", kv_plat: "平台", kv_score: "分数", kv_relevance: "关联度", kv_ownership: "归属度", kv_product_relevance: "产品关联",
|
|
734
739
|
kv_use: "使用", kv_src: "来源", kv_result: "结果", kv_pillar: "支柱",
|
|
@@ -740,11 +745,11 @@
|
|
|
740
745
|
title: "Content Engine · Observatory",
|
|
741
746
|
brand: "Observatory",
|
|
742
747
|
search: "Search ID, one-liner, source…",
|
|
743
|
-
overview: "Overview",
|
|
744
|
-
notes_in: "Captured", notes_lib: "Catalog",
|
|
748
|
+
overview: "Overview", needs: "Needs", products: "Products", recommendations: "Recommendations", topics: "Topics", notes: "Notes & library", runs: "Run files", pub: "Shipped & review",
|
|
749
|
+
notes_in: "Captured", notes_needs: "Needs", notes_lib: "Catalog",
|
|
745
750
|
lead: "Pick an IP, then inspect the stock.",
|
|
746
|
-
kpi_cap: "Captured", kpi_lib: "Catalog", kpi_topics: "Topics", kpi_out: "Outcomes",
|
|
747
|
-
kpi_cap_sub: "Capture", kpi_lib_sub: "Swipe / Atom / Claim",
|
|
751
|
+
kpi_cap: "Captured", kpi_needs: "Needs", kpi_lib: "Catalog", kpi_topics: "Topics", kpi_out: "Outcomes",
|
|
752
|
+
kpi_cap_sub: "Capture", kpi_needs_sub: "Audience quotes", kpi_lib_sub: "Swipe / Atom / Claim",
|
|
748
753
|
kpi_topics_sub: "{n} ready, never opened as a run", kpi_out_sub: "Runs / shipped URLs",
|
|
749
754
|
ip_section: "IP · Profiles",
|
|
750
755
|
ip_all: "All profiles",
|
|
@@ -755,6 +760,8 @@
|
|
|
755
760
|
gap_section: "Breaks",
|
|
756
761
|
gap_none: "No obvious breaks.",
|
|
757
762
|
gap_ready_n: "{n} ready topics with no run",
|
|
763
|
+
gap_needs_thin_n: "Needs under 3 quotes (graphics hard gate) · have {n}",
|
|
764
|
+
gap_needs_n: "{n} needs not yet in a topic",
|
|
758
765
|
gap_lib_n: "{n} captures not ingested",
|
|
759
766
|
gap_review_n: "{n} shipped posts not reviewable",
|
|
760
767
|
kv_profile: "Profile",
|
|
@@ -768,6 +775,7 @@
|
|
|
768
775
|
doc_voice: "Voice",
|
|
769
776
|
doc_audience: "Audience",
|
|
770
777
|
doc_pillars: "Pillars",
|
|
778
|
+
doc_lanes: "Lanes",
|
|
771
779
|
empty_profile_t: "Pick a Profile",
|
|
772
780
|
empty_profile_b: "The inspector shows that IP’s pillars, accounts, files, and breaks.",
|
|
773
781
|
acct_handle: "Handle",
|
|
@@ -791,6 +799,7 @@
|
|
|
791
799
|
lib_claim_ev: "Proposition evidence is this claim’s Evidence table; hit rate is n/win/loss.",
|
|
792
800
|
f_status: "Registry status", f_pillar: "Pillar", f_src: "Source", f_use: "Use", f_unused: "unused", f_promoted: "promoted",
|
|
793
801
|
f_sort: "Sort",
|
|
802
|
+
f_sort_recommend: "Report first",
|
|
794
803
|
f_sort_bookmarks: "Bookmarks ↓",
|
|
795
804
|
f_sort_replies: "Replies ↓",
|
|
796
805
|
f_sort_likes: "Likes ↓",
|
|
@@ -813,7 +822,8 @@
|
|
|
813
822
|
f_cap_ingest: "Ingest",
|
|
814
823
|
f_cap_ingested: "Ingested",
|
|
815
824
|
f_cap_not_ingested: "Not ingested",
|
|
816
|
-
no_topic: "No matching topics",
|
|
825
|
+
no_topic: "No matching topics", no_note: "No matching notes", no_need: "No audience quotes yet", no_pub: "No shipped posts",
|
|
826
|
+
need_empty_hint: "Ask the Agent: “capture audience quotes: …” with a verbatim quote. Do not invent quotes.",
|
|
817
827
|
no_stage: "no stage files",
|
|
818
828
|
empty_t: "Pick something on the left",
|
|
819
829
|
empty_b: "Where it came from, whether it was written, whether it shipped, whether it is worth reusing — that chain shows up here.",
|
|
@@ -839,7 +849,7 @@
|
|
|
839
849
|
thin_warn: "Too thin to review: result is not win / flat / loss. No chart.",
|
|
840
850
|
topic_bind: "Topic: {t} · swipe {s} · claim {c}",
|
|
841
851
|
supersedes: "supersedes {id}", superseded_by: "superseded by {id}",
|
|
842
|
-
kind_raw: "Raw", kind_capture: "Capture",
|
|
852
|
+
kind_raw: "Raw", kind_capture: "Capture", kind_need: "Need", kind_product: "Product", kind_recommendation: "Recommendation", kind_topic: "Topic", kind_swipe: "Swipe",
|
|
843
853
|
kind_atom: "Atom", kind_claim: "Claim", kind_run: "Run", kind_published: "Shipped",
|
|
844
854
|
kv_kind: "Kind", kv_date: "Date", kv_status: "Status", kv_plat: "Platform", kv_score: "Score", kv_relevance: "Relevance", kv_ownership: "Ownership", kv_product_relevance: "Product relevance",
|
|
845
855
|
kv_use: "Use", kv_src: "Source", kv_result: "Result", kv_pillar: "Pillar",
|
|
@@ -937,7 +947,7 @@
|
|
|
937
947
|
let topicSrc = "";
|
|
938
948
|
let topicUsage = "";
|
|
939
949
|
let discStatus = "";
|
|
940
|
-
let discSort = "
|
|
950
|
+
let discSort = "recommend";
|
|
941
951
|
let capIngest = "";
|
|
942
952
|
let selected = null;
|
|
943
953
|
const $list = document.getElementById("list");
|
|
@@ -1283,7 +1293,7 @@
|
|
|
1283
1293
|
sel.innerHTML = `<option value="">${t("ip_all")}</option>` +
|
|
1284
1294
|
ids.map(id => `<option value="${id}" ${id === profileScope ? "selected" : ""}>${id}</option>`).join("");
|
|
1285
1295
|
tabs.innerHTML = "";
|
|
1286
|
-
for (const id of ["overview", "
|
|
1296
|
+
for (const id of ["overview", "needs", "products", "recommendations", "topics", "notes", "runs", "pub"]) {
|
|
1287
1297
|
const b = document.createElement("button");
|
|
1288
1298
|
b.textContent = t(id);
|
|
1289
1299
|
b.dataset.view = id;
|
|
@@ -1343,7 +1353,7 @@
|
|
|
1343
1353
|
function qmatch(n) {
|
|
1344
1354
|
const q = $q.value.trim().toLowerCase();
|
|
1345
1355
|
if (!q) return true;
|
|
1346
|
-
const blob = [n.ident, n.label, n.kind, n.status, n.pillar, n.profile, n.profiles, n.src_handle, n.url, n.notes, n.type, n.atom_type, n.topic_id].filter(Boolean).join(" ").toLowerCase();
|
|
1356
|
+
const blob = [n.ident, n.label, n.kind, n.status, n.pillar, n.lane, n.generation_mode, n.profile, n.profiles, n.src_handle, n.url, n.notes, n.type, n.atom_type, n.topic_id, n.audience, n.product_ids, n.product_fit, n.recommendation_ids].filter(Boolean).join(" ").toLowerCase();
|
|
1347
1357
|
return blob.includes(q);
|
|
1348
1358
|
}
|
|
1349
1359
|
function connected(id) {
|
|
@@ -1423,11 +1433,16 @@
|
|
|
1423
1433
|
function heatMetric(n, key) {
|
|
1424
1434
|
return numCompact(n[`src_${key}`]);
|
|
1425
1435
|
}
|
|
1436
|
+
function hasHeat(n) {
|
|
1437
|
+
return ["likes", "replies", "bookmarks", "views"].some(k => heatMetric(n, k) !== null);
|
|
1438
|
+
}
|
|
1426
1439
|
function heatStripHtml(n, opts = {}) {
|
|
1440
|
+
// No strip when every metric is missing — empty "—" chips inflate row height.
|
|
1441
|
+
if (!hasHeat(n)) return "";
|
|
1427
1442
|
const hint = opts.hint ? `<span class="heat-note">${esc(t("heat_hint"))}</span>` : "";
|
|
1428
1443
|
const items = [
|
|
1429
1444
|
{ key: "likes", sym: "♥", title: "likes" },
|
|
1430
|
-
{ key: "replies", sym: "
|
|
1445
|
+
{ key: "replies", sym: "💬", title: "replies" },
|
|
1431
1446
|
{ key: "bookmarks", sym: "🔖", title: "bookmarks" },
|
|
1432
1447
|
{ key: "views", sym: "👁", title: "views" },
|
|
1433
1448
|
];
|
|
@@ -1458,6 +1473,25 @@
|
|
|
1458
1473
|
</div>`;
|
|
1459
1474
|
return d;
|
|
1460
1475
|
}
|
|
1476
|
+
function angleRecommendRank(n) {
|
|
1477
|
+
const r = String(n.angle_recommend || "").toLowerCase();
|
|
1478
|
+
if (r === "promote") return 0;
|
|
1479
|
+
if (r === "library") return 1;
|
|
1480
|
+
if (r === "hold") return 2;
|
|
1481
|
+
if (r === "reject") return 3;
|
|
1482
|
+
if (String(n.next_action || "") === "promote_to_topic") return 0;
|
|
1483
|
+
return 4;
|
|
1484
|
+
}
|
|
1485
|
+
function discoveryUnprocessed(n) {
|
|
1486
|
+
const st = String(n.status || "");
|
|
1487
|
+
if (st === "promoted" || st === "rejected") return false;
|
|
1488
|
+
const ang = String(n.angle_status || "");
|
|
1489
|
+
if (ang === "accepted") return false;
|
|
1490
|
+
if (ang === "held" || ang === "rejected") return false;
|
|
1491
|
+
if (ang === "proposed" && (n.angle_recommend === "promote" || !n.angle_recommend)) return true;
|
|
1492
|
+
if (String(n.next_action || "") === "promote_to_topic") return true;
|
|
1493
|
+
return false;
|
|
1494
|
+
}
|
|
1461
1495
|
function sortDiscoveries(rows, mode) {
|
|
1462
1496
|
const missing = -1;
|
|
1463
1497
|
const num = (n, key) => {
|
|
@@ -1465,6 +1499,10 @@
|
|
|
1465
1499
|
return Number.isFinite(v) ? v : missing;
|
|
1466
1500
|
};
|
|
1467
1501
|
return rows.slice().sort((a, b) => {
|
|
1502
|
+
if (mode === "recommend" || !mode) {
|
|
1503
|
+
const rec = angleRecommendRank(a) - angleRecommendRank(b);
|
|
1504
|
+
if (rec !== 0) return rec;
|
|
1505
|
+
}
|
|
1468
1506
|
let cmp = 0;
|
|
1469
1507
|
if (mode === "likes") cmp = num(b, "likes") - num(a, "likes");
|
|
1470
1508
|
else if (mode === "replies") cmp = num(b, "replies") - num(a, "replies");
|
|
@@ -1477,11 +1515,20 @@
|
|
|
1477
1515
|
}
|
|
1478
1516
|
function pills(n) {
|
|
1479
1517
|
const bits = [];
|
|
1518
|
+
if (n.kind === "need") {
|
|
1519
|
+
const st = n.status || "";
|
|
1520
|
+
const cls = st === "promoted" ? "ok" : (st === "captured" ? "gap" : "");
|
|
1521
|
+
if (st) bits.push(`<span class="pill ${cls}">${esc(st)}</span>`);
|
|
1522
|
+
if (n.source_type) bits.push(`<span class="pill">${esc(n.source_type)}</span>`);
|
|
1523
|
+
if (n.frequency) bits.push(`<span class="pill">×${esc(n.frequency)}</span>`);
|
|
1524
|
+
}
|
|
1480
1525
|
if (n.kind === "discovery") {
|
|
1481
1526
|
const st = n.status || "";
|
|
1482
1527
|
const cls = st === "read" || st === "promoted" ? "ok"
|
|
1483
1528
|
: (st === "saved" || st === "rejected" || st === "unread" ? "gap" : "");
|
|
1484
1529
|
if (st) bits.push(`<span class="pill ${cls}">${esc(st)}</span>`);
|
|
1530
|
+
if (n.angle_recommend) bits.push(`<span class="pill ${n.angle_recommend === "promote" && discoveryUnprocessed(n) ? "gap" : ""}">${esc(n.angle_recommend)}</span>`);
|
|
1531
|
+
else if (discoveryUnprocessed(n)) bits.push(`<span class="pill gap">${esc(t("gap_angle"))}</span>`);
|
|
1485
1532
|
if (n.source_role) bits.push(`<span class="pill">${esc(n.source_role)}</span>`);
|
|
1486
1533
|
if (n.next_action && n.next_action !== "none") bits.push(`<span class="pill">${esc(n.next_action)}</span>`);
|
|
1487
1534
|
}
|
|
@@ -1526,7 +1573,9 @@
|
|
|
1526
1573
|
function render() {
|
|
1527
1574
|
for (const b of tabs.querySelectorAll("button")) b.classList.toggle("on", b.dataset.view === view);
|
|
1528
1575
|
if (view === "overview") renderOverview();
|
|
1529
|
-
if (view === "
|
|
1576
|
+
if (view === "needs") renderNeeds();
|
|
1577
|
+
if (view === "products") renderProducts();
|
|
1578
|
+
if (view === "recommendations") renderRecommendations();
|
|
1530
1579
|
if (view === "topics") renderTopics();
|
|
1531
1580
|
if (view === "notes") renderNotes();
|
|
1532
1581
|
if (view === "runs") renderRuns();
|
|
@@ -1534,6 +1583,69 @@
|
|
|
1534
1583
|
renderInsp();
|
|
1535
1584
|
}
|
|
1536
1585
|
|
|
1586
|
+
function renderNeedsList(into) {
|
|
1587
|
+
const cards = document.createElement("div");
|
|
1588
|
+
cards.className = "cards";
|
|
1589
|
+
const needs = nodesOf("need").filter(qmatch).sort((a, b) => (b.date || "").localeCompare(a.date || ""));
|
|
1590
|
+
needs.forEach(n => {
|
|
1591
|
+
const meta = [
|
|
1592
|
+
n.source_type || "",
|
|
1593
|
+
n.status || "",
|
|
1594
|
+
n.frequency ? `×${n.frequency}` : "",
|
|
1595
|
+
n.topic_ids && n.topic_ids !== "none" ? n.topic_ids : "",
|
|
1596
|
+
].filter(Boolean).join(" · ");
|
|
1597
|
+
cards.appendChild(discoveryRowEl(n, meta));
|
|
1598
|
+
});
|
|
1599
|
+
if (!needs.length) {
|
|
1600
|
+
cards.innerHTML = `<p class='empty'>${t("no_need")}</p><p class="note">${esc(t("need_empty_hint"))}</p>`;
|
|
1601
|
+
}
|
|
1602
|
+
into.appendChild(cards);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
function renderNeeds() {
|
|
1606
|
+
$list.innerHTML = "";
|
|
1607
|
+
$list.insertAdjacentHTML("beforeend", `<p class="lead">${esc(t("need_empty_hint"))}</p>`);
|
|
1608
|
+
renderNeedsList($list);
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
function renderProducts() {
|
|
1612
|
+
$list.innerHTML = "";
|
|
1613
|
+
const products = nodesOf("product").filter(qmatch).sort((a, b) => String(a.label).localeCompare(String(b.label)));
|
|
1614
|
+
$list.insertAdjacentHTML("beforeend", `<p class="lead">Needs describe demand. Products describe the offer. Topics connect them only when the fit is honest.</p>`);
|
|
1615
|
+
const cards = document.createElement("div");
|
|
1616
|
+
cards.className = "cards";
|
|
1617
|
+
products.forEach(product => {
|
|
1618
|
+
const meta = [
|
|
1619
|
+
product.status,
|
|
1620
|
+
product.audience,
|
|
1621
|
+
product.price,
|
|
1622
|
+
product.effective_from,
|
|
1623
|
+
].filter(Boolean).join(" · ");
|
|
1624
|
+
cards.appendChild(rowEl(product, meta));
|
|
1625
|
+
});
|
|
1626
|
+
if (!products.length) cards.innerHTML = `<p class='empty'>No products in products/_index.md</p>`;
|
|
1627
|
+
$list.appendChild(cards);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
function renderRecommendations() {
|
|
1631
|
+
$list.innerHTML = "";
|
|
1632
|
+
const recommendations = nodesOf("recommendation").filter(qmatch).sort((a, b) => String(a.label).localeCompare(String(b.label)));
|
|
1633
|
+
$list.insertAdjacentHTML("beforeend", `<p class="lead">Recommendations are third-party review subjects, not owned Products.</p>`);
|
|
1634
|
+
const cards = document.createElement("div");
|
|
1635
|
+
cards.className = "cards";
|
|
1636
|
+
recommendations.forEach(item => {
|
|
1637
|
+
const meta = [
|
|
1638
|
+
item.status,
|
|
1639
|
+
item.category,
|
|
1640
|
+
item.relationship,
|
|
1641
|
+
item.last_researched,
|
|
1642
|
+
].filter(Boolean).join(" · ");
|
|
1643
|
+
cards.appendChild(rowEl(item, meta));
|
|
1644
|
+
});
|
|
1645
|
+
if (!recommendations.length) cards.innerHTML = `<p class='empty'>No recommendations in recommendations/_index.md</p>`;
|
|
1646
|
+
$list.appendChild(cards);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1537
1649
|
function renderOverview() {
|
|
1538
1650
|
$list.innerHTML = "";
|
|
1539
1651
|
$list.insertAdjacentHTML("beforeend", `<p class="lead">${t("lead")}</p>`);
|
|
@@ -1601,6 +1713,7 @@
|
|
|
1601
1713
|
$list.innerHTML = "";
|
|
1602
1714
|
const statuses = [...new Set(nodesOf("discovery").map(x => x.status).filter(Boolean))];
|
|
1603
1715
|
const sortOpts = [
|
|
1716
|
+
["recommend", "f_sort_recommend"],
|
|
1604
1717
|
["bookmarks", "f_sort_bookmarks"],
|
|
1605
1718
|
["replies", "f_sort_replies"],
|
|
1606
1719
|
["likes", "f_sort_likes"],
|
|
@@ -1615,7 +1728,7 @@
|
|
|
1615
1728
|
const sortEl = w.querySelector("#d-sort");
|
|
1616
1729
|
const paint = () => {
|
|
1617
1730
|
discStatus = status.value;
|
|
1618
|
-
discSort = sortEl.value || "
|
|
1731
|
+
discSort = sortEl.value || "recommend";
|
|
1619
1732
|
const cards = document.createElement("div");
|
|
1620
1733
|
cards.className = "cards";
|
|
1621
1734
|
let rows = nodesOf("discovery").filter(qmatch);
|
|
@@ -1623,6 +1736,7 @@
|
|
|
1623
1736
|
rows = sortDiscoveries(rows, discSort);
|
|
1624
1737
|
rows.forEach(x => {
|
|
1625
1738
|
const meta = [
|
|
1739
|
+
x.angle_recommend || "",
|
|
1626
1740
|
x.source_role,
|
|
1627
1741
|
x.next_action && x.next_action !== "none" ? x.next_action : "",
|
|
1628
1742
|
`@${x.source_handle || "—"}`,
|
|
@@ -1646,7 +1760,7 @@
|
|
|
1646
1760
|
filterBar(
|
|
1647
1761
|
`<select id="f-st"><option value="">${t("f_status")}</option>${statuses.map(s => `<option value="${s}" ${s === topicStatus ? "selected" : ""}>${esc(s)}</option>`).join("")}</select>
|
|
1648
1762
|
<select id="f-p"><option value="">${t("f_pillar")}</option>${pillarIds().map(id => `<option value="${id}" ${id === topicPillar ? "selected" : ""}>${esc(formatPillar(id))}</option>`).join("")}</select>
|
|
1649
|
-
<select id="f-src"><option value="">${t("f_src")}</option>${["watchlist", "inbox", "user"].map(s => `<option value="${s}" ${s === topicSrc ? "selected" : ""}>${s}</option>`).join("")}</select>
|
|
1763
|
+
<select id="f-src"><option value="">${t("f_src")}</option>${["watchlist", "inbox", "user", "discovery", "need"].map(s => `<option value="${s}" ${s === topicSrc ? "selected" : ""}>${s}</option>`).join("")}</select>
|
|
1650
1764
|
<select id="f-u"><option value="">${t("f_use")}</option>
|
|
1651
1765
|
<option value="unused" ${topicUsage === "unused" ? "selected" : ""}>${t("f_unused")}</option>
|
|
1652
1766
|
<option value="promoted" ${topicUsage === "promoted" ? "selected" : ""}>${t("f_promoted")}</option></select>`,
|
|
@@ -1685,7 +1799,7 @@
|
|
|
1685
1799
|
$list.innerHTML = "";
|
|
1686
1800
|
const sub = document.createElement("div");
|
|
1687
1801
|
sub.className = "subtabs";
|
|
1688
|
-
sub.innerHTML = `<button data-t="notes">${t("notes_in")}</button><button data-t="lib">${t("notes_lib")}</button>`;
|
|
1802
|
+
sub.innerHTML = `<button data-t="notes">${t("notes_in")}</button><button data-t="needs">${t("notes_needs")}</button><button data-t="lib">${t("notes_lib")}</button>`;
|
|
1689
1803
|
$list.appendChild(sub);
|
|
1690
1804
|
sub.querySelectorAll("button").forEach(b => b.classList.toggle("on", b.dataset.t === notesTab));
|
|
1691
1805
|
sub.onclick = (e) => {
|
|
@@ -1712,11 +1826,15 @@
|
|
|
1712
1826
|
let caps = nodesOf("capture").filter(qmatch).sort((a, b) => (b.date || "").localeCompare(a.date || ""));
|
|
1713
1827
|
if (capIngest === "ingested") caps = caps.filter(c => c.status === "ingested");
|
|
1714
1828
|
if (capIngest === "not_ingested") caps = caps.filter(c => c.status !== "ingested");
|
|
1715
|
-
caps.forEach(c => cards.appendChild(
|
|
1829
|
+
caps.forEach(c => cards.appendChild(discoveryRowEl(c, `${c.type} · ${c.status} · raw ${c.has_raw ? t("raw_yes") : t("raw_no")}`)));
|
|
1716
1830
|
if (!caps.length) cards.innerHTML = `<p class='empty'>${t("no_note")}</p>`;
|
|
1717
1831
|
$list.appendChild(cards);
|
|
1718
1832
|
return;
|
|
1719
1833
|
}
|
|
1834
|
+
if (notesTab === "needs") {
|
|
1835
|
+
renderNeedsList($list);
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1720
1838
|
const items = GRAPH.nodes.filter(n => n.lib && inScope(n));
|
|
1721
1839
|
const subtypeOf = (n) => n.atom_type || n.form || n.claim_type || "";
|
|
1722
1840
|
const kinds = [...new Set(items.map(n => n.kind))];
|
|
@@ -1907,6 +2025,7 @@
|
|
|
1907
2025
|
function profileCounts(profileId) {
|
|
1908
2026
|
return {
|
|
1909
2027
|
capture: nodesOfAll("capture").filter(n => n.profile === profileId).length,
|
|
2028
|
+
need: nodesOfAll("need").filter(n => n.profile === profileId).length,
|
|
1910
2029
|
topic: nodesOfAll("topic").filter(n => n.profile === profileId).length,
|
|
1911
2030
|
lib: GRAPH.nodes.filter(n => n.lib && (String(n.profiles || "").includes(profileId) || String(n.profiles || "").includes("*"))).length,
|
|
1912
2031
|
run: nodesOfAll("run").filter(n => n.profile === profileId).length,
|
|
@@ -1918,6 +2037,7 @@
|
|
|
1918
2037
|
if (profileId) return profileCounts(profileId);
|
|
1919
2038
|
return {
|
|
1920
2039
|
capture: nodesOfAll("capture").length,
|
|
2040
|
+
need: nodesOfAll("need").length,
|
|
1921
2041
|
topic: nodesOfAll("topic").length,
|
|
1922
2042
|
lib: GRAPH.nodes.filter(n => n.lib).length,
|
|
1923
2043
|
run: nodesOfAll("run").length,
|
|
@@ -1927,18 +2047,28 @@
|
|
|
1927
2047
|
|
|
1928
2048
|
function gapsFor(profileId) {
|
|
1929
2049
|
const topics = profileId ? nodesOfAll("topic").filter(n => n.profile === profileId) : nodesOfAll("topic");
|
|
2050
|
+
const discs = profileId ? nodesOfAll("discovery").filter(n => n.profile === profileId) : nodesOfAll("discovery");
|
|
2051
|
+
const needs = profileId ? nodesOfAll("need").filter(n => n.profile === profileId) : nodesOfAll("need");
|
|
1930
2052
|
const caps = profileId ? nodesOfAll("capture").filter(n => n.profile === profileId) : nodesOfAll("capture");
|
|
1931
2053
|
const pubs = profileId ? nodesOfAll("published").filter(n => n.profile === profileId) : nodesOfAll("published");
|
|
1932
|
-
|
|
2054
|
+
const needCount = needs.length;
|
|
2055
|
+
const gaps = [
|
|
1933
2056
|
[topics.filter(x => x.status === "ready" && x.usage === "unused").length, "gap_ready_n"],
|
|
2057
|
+
[discs.filter(discoveryUnprocessed).length, "gap_angle_n"],
|
|
2058
|
+
[needs.filter(n => n.status === "captured" && (!n.topic_ids || n.topic_ids === "none")).length, "gap_needs_n"],
|
|
1934
2059
|
[caps.filter(c => c.status !== "ingested").length, "gap_lib_n"],
|
|
1935
2060
|
[pubs.filter(p => !p.reviewable).length, "gap_review_n"],
|
|
1936
2061
|
].filter(([n]) => n > 0);
|
|
2062
|
+
if (GRAPH.needs_index_present && needCount < 3) {
|
|
2063
|
+
gaps.splice(2, 0, [needCount, "gap_needs_thin_n"]);
|
|
2064
|
+
}
|
|
2065
|
+
return gaps;
|
|
1937
2066
|
}
|
|
1938
2067
|
|
|
1939
2068
|
function statsHtml(counts) {
|
|
1940
2069
|
return `<div class="prof-stats">
|
|
1941
2070
|
<div><b>${counts.capture}</b><span>${t("kpi_cap")}</span></div>
|
|
2071
|
+
<div><b>${counts.need || 0}</b><span>${t("kpi_needs")}</span></div>
|
|
1942
2072
|
<div><b>${counts.topic}</b><span>${t("kpi_topics")}</span></div>
|
|
1943
2073
|
<div><b>${counts.lib}</b><span>${t("kpi_lib")}</span></div>
|
|
1944
2074
|
<div><b>${counts.run}</b><span>Run</span></div>
|
|
@@ -1972,6 +2102,7 @@
|
|
|
1972
2102
|
["voice", t("doc_voice")],
|
|
1973
2103
|
["audience", t("doc_audience")],
|
|
1974
2104
|
["pillars", t("doc_pillars")],
|
|
2105
|
+
["lanes", t("doc_lanes")],
|
|
1975
2106
|
];
|
|
1976
2107
|
const pillarRows = Object.entries(pillars).map(([id, p]) => {
|
|
1977
2108
|
const title = lang === "zh" ? p.zh : p.en;
|
|
@@ -2035,16 +2166,31 @@
|
|
|
2035
2166
|
? `${n.win || 0}w / ${n.loss || 0}l / n=${n.n}`
|
|
2036
2167
|
: "",
|
|
2037
2168
|
[t("kv_pillar")]: formatPillar(n.pillar),
|
|
2169
|
+
Lane: n.kind === "topic" ? (n.lane || "") : "",
|
|
2170
|
+
"Generation mode": n.kind === "topic" ? (n.generation_mode || "") : "",
|
|
2038
2171
|
[t("kv_plat")]: n.platform || n.platforms,
|
|
2039
2172
|
[t("kv_profile")]: n.profile || n.profile_id || (n.profiles || ""),
|
|
2040
2173
|
[t("kv_score")]: n.fit ? `${n.craft} opp / ${n.fit} aud` : n.total,
|
|
2041
|
-
[t("kv_use")]: n.kind === "discovery" ? (n.next_action || "") : n.usage,
|
|
2174
|
+
[t("kv_use")]: n.kind === "discovery" ? (n.angle_recommend || n.next_action || "") : n.usage,
|
|
2042
2175
|
[t("kv_src")]: n.kind === "discovery" ? (n.source_role || "") : n.source_type,
|
|
2176
|
+
Angle: n.kind === "discovery" ? ([n.angle_status, n.need_ids].filter(Boolean).join(" · ")) : "",
|
|
2177
|
+
Quote: n.kind === "need" ? (n.quote || "") : "",
|
|
2178
|
+
Speaker: n.kind === "need" ? (n.speaker || "") : "",
|
|
2179
|
+
Frequency: n.kind === "need" ? (n.frequency || "") : "",
|
|
2180
|
+
Topics: n.kind === "need" ? (n.topic_ids || "") : "",
|
|
2181
|
+
Products: n.kind === "topic" ? (n.product_ids || "") : "",
|
|
2182
|
+
"Product fit": n.kind === "topic" ? (n.product_fit || "") : "",
|
|
2183
|
+
Audience: n.kind === "product" ? (n.audience || "") : "",
|
|
2184
|
+
Price: n.kind === "product" ? (n.price || "") : "",
|
|
2185
|
+
"Effective from": n.kind === "product" ? (n.effective_from || "") : "",
|
|
2186
|
+
Category: n.kind === "recommendation" ? (n.category || "") : "",
|
|
2187
|
+
Relationship: n.kind === "recommendation" ? (n.relationship || "") : "",
|
|
2188
|
+
"Last researched": n.kind === "recommendation" ? (n.last_researched || "") : "",
|
|
2043
2189
|
Handle: n.source_handle || n.src_handle || "",
|
|
2044
|
-
[t("kv_heat_at")]: n.kind === "discovery" ? (n.engagement_at || "") : "",
|
|
2190
|
+
[t("kv_heat_at")]: (n.kind === "discovery" || n.kind === "capture") ? (n.engagement_at || "") : "",
|
|
2045
2191
|
[t("kv_result")]: n.result,
|
|
2046
2192
|
}).filter(([, v]) => v);
|
|
2047
|
-
const heatBlock = n.kind === "discovery"
|
|
2193
|
+
const heatBlock = (n.kind === "discovery" || n.kind === "capture")
|
|
2048
2194
|
? `${heatStripHtml(n, { hint: true })}${n.source_url ? `<p class="note">${t("src_url")}<a href="${esc(n.source_url)}" target="_blank" rel="noreferrer">${esc(n.source_url)}</a></p>` : ""}`
|
|
2049
2195
|
: "";
|
|
2050
2196
|
$insp.innerHTML = `<h2>${t("obj")}</h2>
|