@heycys/gallery 0.1.2 → 0.2.1
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/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icon/page.mjs +6 -4
- package/browser/editor/components/icons.mjs +5 -2
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +6 -2
- package/browser/editor/components/installed/page.mjs +80 -13
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +17 -5
- package/browser/editor/components/table/index.mjs +4 -2
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/hint.mjs +64 -27
- package/browser/editor/page/board/index.mjs +160 -71
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +4 -3
- package/browser/editor/page/clipboard/import/read.mjs +20 -2
- package/browser/editor/page/clipboard/index.mjs +10 -3
- package/browser/editor/page/clipboard/own/blocks.mjs +3 -4
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/commit.mjs +2 -2
- package/browser/editor/page/core.mjs +3 -1
- package/browser/editor/page/custom-page.mjs +15 -11
- package/browser/editor/page/editor.mjs +31 -14
- package/browser/editor/page/history.mjs +19 -4
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/menu.mjs +15 -7
- package/browser/editor/page/page-objects.mjs +3 -7
- package/browser/editor/page/present-links.mjs +5 -4
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/icons.mjs +0 -2
- package/browser/editor/page/table/index.mjs +10 -14
- package/browser/editor/page/table/views.mjs +5 -52
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/typing/index.mjs +44 -12
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/shared/block-packs.mjs +23 -8
- package/browser/shared/component-catalog.mjs +15 -8
- package/browser/shared/component-source.mjs +3 -1
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/installed.mjs +1 -1
- package/browser/shared/components/page.mjs +2 -0
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-copy.mjs +43 -0
- package/browser/shared/drafts.mjs +10 -3
- package/browser/shared/emoji/icon-value.mjs +2 -2
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extensions.mjs +83 -7
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +50 -17
- package/browser/shared/outline-shape.mjs +6 -0
- package/browser/shared/outline.mjs +165 -12
- package/browser/shared/pack-manifest.mjs +12 -1
- package/browser/shared/pages.mjs +169 -57
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/web-links.mjs +5 -0
- package/browser/shared/workspace-columns.mjs +11 -7
- package/dist/{chunk-N7AZZLGT.mjs → chunk-2GKGEVMR.mjs} +29 -24
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/{chunk-HYMEEXKN.mjs → chunk-2RKIHJI2.mjs} +1 -1
- package/dist/{chunk-742D2WWJ.mjs → chunk-36FIRJIF.mjs} +2 -2
- package/dist/{chunk-BPL64HGA.mjs → chunk-3A5I2GJK.mjs} +1 -1
- package/dist/{chunk-RFDZXFJF.mjs → chunk-3OFXMN6N.mjs} +1 -1
- package/dist/chunk-46ACXOU5.mjs +2 -0
- package/dist/{chunk-PUOQ65NC.mjs → chunk-4AMTKWDO.mjs} +1 -1
- package/dist/{chunk-VTKNEYT3.mjs → chunk-4DNHHJSL.mjs} +1 -1
- package/dist/chunk-5DPABPBI.mjs +2 -0
- package/dist/chunk-5IIH335D.mjs +3 -0
- package/dist/chunk-5L26JUYA.mjs +2 -0
- package/dist/{chunk-3NJACR4W.mjs → chunk-5MEXZ2UF.mjs} +1 -1
- package/dist/{chunk-ZHEHPMBK.mjs → chunk-6MPKCH3P.mjs} +1 -1
- package/dist/{chunk-C564NU2H.mjs → chunk-74RPP2M2.mjs} +1 -1
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/{chunk-VXACTLO3.mjs → chunk-7M7UPWU6.mjs} +1 -1
- package/dist/{chunk-ZB4H7ZN4.mjs → chunk-7N2LPG33.mjs} +1 -1
- package/dist/{chunk-UBBRTJ2R.mjs → chunk-7XDYK3UC.mjs} +1 -1
- package/dist/chunk-AEMVZYZQ.mjs +166 -0
- package/dist/{chunk-POQSE4C2.mjs → chunk-AFGUR7SY.mjs} +1 -1
- package/dist/{chunk-QKXMPUXC.mjs → chunk-AMDGVDNV.mjs} +1 -1
- package/dist/{chunk-KTKHRC6H.mjs → chunk-ASAXY2DJ.mjs} +1 -1
- package/dist/{chunk-NVRNLK25.mjs → chunk-BYSF5UMM.mjs} +2 -2
- package/dist/{chunk-U3SSPL4K.mjs → chunk-CCSGFCLZ.mjs} +1 -1
- package/dist/{chunk-NWFBE2YA.mjs → chunk-CG3UHDKH.mjs} +1 -1
- package/dist/chunk-CPS4SRPF.mjs +5 -0
- package/dist/{chunk-B4P2CM2J.mjs → chunk-CZ5KJSGK.mjs} +1 -1
- package/dist/chunk-DAMVDXR3.mjs +2 -0
- package/dist/{chunk-NG375ILQ.mjs → chunk-DH6GMDNN.mjs} +1 -1
- package/dist/chunk-DHB7UZ7F.mjs +3 -0
- package/dist/{chunk-MHW7ZKOU.mjs → chunk-DKR7LFIY.mjs} +1 -1
- package/dist/chunk-DLFZJJEE.mjs +2 -0
- package/dist/{chunk-6EZ7FNIK.mjs → chunk-F4ZA6JRZ.mjs} +1 -1
- package/dist/{chunk-6VTU6KEO.mjs → chunk-FCK6NXON.mjs} +1 -1
- package/dist/{chunk-ZWPMCK7P.mjs → chunk-FX42XU6J.mjs} +1 -1
- package/dist/chunk-FXQBADMN.mjs +5 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-G4YP7GVC.mjs} +1 -1
- package/dist/{chunk-V6XZ4VIR.mjs → chunk-GWOYMENX.mjs} +1 -1
- package/dist/chunk-HATA2W7X.mjs +2 -0
- package/dist/{chunk-YI43RG4P.mjs → chunk-HBAUKKQH.mjs} +1 -1
- package/dist/{chunk-MAFIGVXY.mjs → chunk-HM4E43VM.mjs} +1 -1
- package/dist/{chunk-CRJEG7MT.mjs → chunk-JI6T3A4Y.mjs} +1 -1
- package/dist/{chunk-NFMCP2HI.mjs → chunk-JJNRIFND.mjs} +2 -2
- package/dist/chunk-JL6R4FG4.mjs +4 -0
- package/dist/{chunk-UMHUSOPJ.mjs → chunk-JXLSHVJ2.mjs} +1 -1
- package/dist/{chunk-FJYN7RTH.mjs → chunk-KFZBYDIS.mjs} +1 -1
- package/dist/{chunk-ZTHICSSF.mjs → chunk-KH24LWAT.mjs} +1 -1
- package/dist/{chunk-RKPWLGZ3.mjs → chunk-KUILYI7H.mjs} +1 -1
- package/dist/{chunk-RMECZA2K.mjs → chunk-L7W624FD.mjs} +1 -1
- package/dist/chunk-LE44MD3O.mjs +4 -0
- package/dist/{chunk-4K5KC6V2.mjs → chunk-LV24RY2E.mjs} +1 -1
- package/dist/{chunk-43B75J5T.mjs → chunk-MKTX5PGV.mjs} +1 -1
- package/dist/{chunk-LKX55H76.mjs → chunk-NAGMRVW4.mjs} +1 -1
- package/dist/{chunk-D4CKRD3V.mjs → chunk-NFABH3QW.mjs} +2 -2
- package/dist/{chunk-PVER7LSC.mjs → chunk-NIW7F7LU.mjs} +2 -2
- package/dist/{chunk-PAREWQGB.mjs → chunk-NWRZXELO.mjs} +1 -1
- package/dist/{chunk-OJKMINIU.mjs → chunk-OU3S466R.mjs} +15 -15
- package/dist/{chunk-5ZJA7CXT.mjs → chunk-PAFSFVYB.mjs} +1 -1
- package/dist/chunk-QCEATQC4.mjs +2 -0
- package/dist/{chunk-Y34NR5JL.mjs → chunk-QJ3TFJLQ.mjs} +1 -1
- package/dist/{chunk-IA4PSIMD.mjs → chunk-QK3VISCA.mjs} +1 -1
- package/dist/{chunk-ZUNVAXLH.mjs → chunk-QXVNUASA.mjs} +1 -1
- package/dist/{chunk-GRAXKKG4.mjs → chunk-QZ35UAB4.mjs} +1 -1
- package/dist/{chunk-UGWYKHBL.mjs → chunk-S2Y7VI4H.mjs} +2 -2
- package/dist/{chunk-OW5NWPOJ.mjs → chunk-SAHS56QM.mjs} +1 -1
- package/dist/{chunk-QOUEFUCH.mjs → chunk-SOD23RGL.mjs} +1 -1
- package/dist/chunk-TDWJKOLN.mjs +2 -0
- package/dist/{chunk-V6RIYQZZ.mjs → chunk-TOE6DPLH.mjs} +1 -1
- package/dist/chunk-UGO5N3EI.mjs +15 -0
- package/dist/{chunk-Q47PLKIJ.mjs → chunk-UGWMMEJ5.mjs} +1 -1
- package/dist/{chunk-NWR2LT5B.mjs → chunk-V5JRSGZF.mjs} +1 -1
- package/dist/{chunk-BZ5RAF7L.mjs → chunk-VA3KAQZD.mjs} +1 -1
- package/dist/chunk-VG5JEIUQ.mjs +12 -0
- package/dist/{chunk-UNOYVIYR.mjs → chunk-VGTMLQWZ.mjs} +1 -1
- package/dist/chunk-VKSRM7EY.mjs +22 -0
- package/dist/{chunk-YQGT4AB2.mjs → chunk-VNUWREXU.mjs} +1 -1
- package/dist/{chunk-AGDILNWB.mjs → chunk-VPVOAJ7X.mjs} +1 -1
- package/dist/{chunk-HLYV7RIH.mjs → chunk-WCWYNFDF.mjs} +1 -1
- package/dist/chunk-WTEGUPFG.mjs +16 -0
- package/dist/{chunk-N76HWBA3.mjs → chunk-XKOHV4H6.mjs} +1 -1
- package/dist/{chunk-HMYTM3GT.mjs → chunk-XMKHCUI6.mjs} +1 -1
- package/dist/{chunk-OUUP3WKT.mjs → chunk-XQRUG4G3.mjs} +1 -1
- package/dist/{chunk-32ZUEFZ7.mjs → chunk-YBB5LWZK.mjs} +1 -1
- package/dist/{chunk-SX4LJYT6.mjs → chunk-YFJU3O7G.mjs} +1 -1
- package/dist/chunk-YPPJVDQI.mjs +2 -0
- package/dist/chunk-ZANMKAWS.mjs +2 -0
- package/dist/{chunk-6QBHU4DF.mjs → chunk-ZCP7BTOZ.mjs} +1 -1
- package/dist/{chunk-ERLAIBOA.mjs → chunk-ZEY2RLBT.mjs} +2 -2
- package/dist/{chunk-SQ6Y2ZMA.mjs → chunk-ZO7SFB2E.mjs} +2 -2
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +5 -5
- package/kit/code.js +15 -15
- package/kit/math.js +1 -1
- package/kit/report.css +123 -44
- package/kit/runtime.js +45 -7
- package/kit/tables.js +2 -0
- package/kit/ui.js +2 -0
- package/package.json +1 -1
- package/packs/gallery/chart-view/kit.js +3 -3
- package/packs/gallery/chart-view/writing.md +1 -1
- package/packs/gallery/countdown/component.json +1 -1
- package/packs/gallery/countdown/kit.js +89 -29
- package/packs/gallery/countdown/preview.svg +1 -1
- package/packs/gallery/countdown/style.css +88 -100
- package/packs/gallery/countdown/writing.md +2 -2
- package/packs/gallery/habit/component.json +3 -3
- package/packs/gallery/habit/kit.js +114 -75
- package/packs/gallery/habit/preview.svg +1 -1
- package/packs/gallery/habit/style.css +133 -205
- package/packs/gallery/habit/writing.md +2 -2
- package/packs/gallery/heatmap/component.json +2 -2
- package/packs/gallery/heatmap/kit.js +335 -173
- package/packs/gallery/heatmap/preview.svg +1 -1
- package/packs/gallery/heatmap/style.css +158 -170
- package/packs/gallery/heatmap/writing.md +2 -2
- package/packs/gallery/kanban/kit.js +3 -3
- package/packs/gallery/kanban/writing.md +1 -1
- package/packs/gallery/metric/kit.js +3 -3
- package/packs/gallery/metric/writing.md +1 -1
- package/packs/gallery/note/component.json +3 -3
- package/packs/gallery/note/kit.js +40 -13
- package/packs/gallery/note/preview.svg +1 -1
- package/packs/gallery/note/style.css +51 -30
- package/packs/gallery/note/writing.md +2 -2
- package/packs/gallery/recent/component.json +2 -2
- package/packs/gallery/recent/kit.js +141 -86
- package/packs/gallery/recent/preview.svg +1 -1
- package/packs/gallery/recent/style.css +53 -126
- package/packs/gallery/recent/writing.md +2 -2
- package/packs/gallery/static/component.json +2 -2
- package/packs/gallery/static/preview.svg +1 -1
- package/packs/gallery/static/style.css +99 -66
- package/packs/gallery/static/writing.md +2 -2
- package/packs/gallery/stats/component.json +3 -3
- package/packs/gallery/stats/kit.js +253 -72
- package/packs/gallery/stats/preview.svg +1 -1
- package/packs/gallery/stats/style.css +64 -142
- package/packs/gallery/stats/writing.md +2 -2
- package/packs/gallery/today/component.json +2 -2
- package/packs/gallery/today/kit.js +62 -27
- package/packs/gallery/today/preview.svg +1 -1
- package/packs/gallery/today/style.css +101 -72
- package/packs/gallery/today/writing.md +2 -2
- package/packs/gallery/todos/component.json +1 -1
- package/packs/gallery/todos/kit.js +218 -71
- package/packs/gallery/todos/preview.svg +1 -1
- package/packs/gallery/todos/style.css +170 -223
- package/packs/gallery/todos/writing.md +1 -1
- package/packs/gallery/weather/component.json +2 -2
- package/packs/gallery/weather/kit.js +165 -90
- package/packs/gallery/weather/preview.svg +1 -1
- package/packs/gallery/weather/style.css +100 -218
- package/packs/gallery/weather/writing.md +1 -1
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +10 -10
- package/skill/SKILL.md +15 -14
- package/skill/references/building-blocks.md +4 -4
- package/skill/references/extensions.md +11 -7
- package/skill/references/pages-and-data.md +13 -9
- package/skill/references/writing-html.md +2 -0
- package/web/assets/index-BHC5ZOMh.js +15 -0
- package/web/assets/index-xP0uw3a0.css +1 -0
- package/web/index.html +2 -2
- package/dist/chunk-2NRBY6AJ.mjs +0 -2
- package/dist/chunk-35NQ4PLQ.mjs +0 -2
- package/dist/chunk-3KJHLHUO.mjs +0 -2
- package/dist/chunk-4AV456RQ.mjs +0 -2
- package/dist/chunk-5XYHDBJ5.mjs +0 -2
- package/dist/chunk-6A53MZYZ.mjs +0 -2
- package/dist/chunk-6EXH3ORZ.mjs +0 -166
- package/dist/chunk-BVEFGE4B.mjs +0 -2
- package/dist/chunk-D4EURAX4.mjs +0 -4
- package/dist/chunk-DQCE7TJY.mjs +0 -5
- package/dist/chunk-FWNRPMCJ.mjs +0 -12
- package/dist/chunk-FWW4CSAZ.mjs +0 -2
- package/dist/chunk-GY3FAUVM.mjs +0 -2
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L7UP52JO.mjs +0 -2
- package/dist/chunk-NAMN3RAF.mjs +0 -2
- package/dist/chunk-PZDLJJTJ.mjs +0 -3
- package/dist/chunk-SXHBYZST.mjs +0 -16
- package/dist/chunk-TEZAWDSQ.mjs +0 -2
- package/dist/chunk-UFNYFFKO.mjs +0 -20
- package/dist/chunk-UKSHDZZ6.mjs +0 -2
- package/dist/chunk-VJPFVNNW.mjs +0 -15
- package/dist/chunk-VS3ZMVGX.mjs +0 -5
- package/web/assets/index-BK2e_07w.js +0 -13
- package/web/assets/index-CWFI83mF.css +0 -1
- /package/dist/{chunk-YEY3RSFQ.mjs → chunk-5MMN3N5J.mjs} +0 -0
- /package/dist/{chunk-UH4SIXTR.mjs → chunk-74UW7QSL.mjs} +0 -0
- /package/dist/{chunk-W7XHE4CT.mjs → chunk-EKGYYOSP.mjs} +0 -0
- /package/dist/{chunk-QAIHRH3I.mjs → chunk-KNZJT4ET.mjs} +0 -0
- /package/dist/{chunk-A55HN5OK.mjs → chunk-N3DSBH5S.mjs} +0 -0
- /package/dist/{chunk-QR6A54KJ.mjs → chunk-ZW2A6GBW.mjs} +0 -0
|
@@ -2,13 +2,13 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { descendantsIn, outlineAndFile, parentIn, placeIn, readOutline, withOutlineLock, writeOutline, writtenAs } from "./outline.mjs";
|
|
5
|
+
import { descendantsIn, outlineAndFile, parentIn, placeIn, readOutline, sharedOutline, withOutlineLock, writeOutline, writtenAs } from "./outline.mjs";
|
|
6
6
|
import { DOCS, GROUP_LIMITS, isForeign, isTop, newGroupId, topIn, topOf } from "./outline-shape.mjs";
|
|
7
7
|
import { findPreviewServer } from "./preview-server.mjs";
|
|
8
8
|
import { idsOf, shownIcon } from "./workspace-columns.mjs";
|
|
9
9
|
import { nameStops, workspaceLabels, workspaceName } from "./workspace-name.mjs";
|
|
10
10
|
import { isWorkspace, readRegistry, workspaceId, workspaceKey } from "./workspace-registry.mjs";
|
|
11
|
-
import { defaultWorkspace, documentFiles, isSlugName, listDocumentSlugs } from "./workspace.mjs";
|
|
11
|
+
import { defaultWorkspace, documentFiles, isSlugName, listDocumentSlugs, readLink } from "./workspace.mjs";
|
|
12
12
|
|
|
13
13
|
// The drafts of other workspaces in a workspace's sidebar (notes/plans/workspaces-links-plan-2026-11-08.md
|
|
14
14
|
// §2.2, §2.5, §7.2; docs/workbench.md "Drafts of other workspaces"): an entry of the outline written
|
|
@@ -76,6 +76,8 @@ export async function draftFacts(entry, ids = registeredIds()) {
|
|
|
76
76
|
const none = { entry, ws, slug, root: null, folder: null, path: null, title: slug, description: "", icon: null };
|
|
77
77
|
if (!found.root) return { ...none, missing: found.refused === "ambiguous" ? "ambiguous" : "workspace" };
|
|
78
78
|
const folder = path.join(found.root, slug);
|
|
79
|
+
const link = existsSync(documentFiles(folder).html) ? null : await readLink(folder);
|
|
80
|
+
if (link) return { entry, ws, slug, root: found.root, folder, path: path.join(folder, 'link.json'), title: link.title, description: '', kind: 'link', url: link.url, icon: link.icon, siteIcon: link.siteIcon, missing: null };
|
|
79
81
|
const { files, html, metadata } = await metadataAt(folder);
|
|
80
82
|
const missing = !isWorkspace(found.root) ? "workspace" : !html || metadata?.instructions === true ? "draft" : null;
|
|
81
83
|
// An untitled document says so (its title empty: the workbench names it 未命名文档); one with no doc.json to read, its slug.
|
|
@@ -226,6 +228,11 @@ export async function addDraft(treeRoot, draftRoot, slug, { changed = () => {},
|
|
|
226
228
|
return { parent, column: top === null || top === "" ? DOCS : top.slice(1), under: parent !== null && !isTop(parent) ? parent : null };
|
|
227
229
|
};
|
|
228
230
|
const columnOf = (key) => outline.groups.find((each) => topOf(each.id) === topIn(outline.children, key)) ?? null;
|
|
231
|
+
if (sharedOutline(treeRoot) && holds(entry)) {
|
|
232
|
+
if (!writtenAs(outline, stored)) { await writeOutline(treeRoot, outline); changed(); }
|
|
233
|
+
const existing = pick || storedHolds;
|
|
234
|
+
return { entry, existing, added: existing ? [] : [entry], shown: false, ...where() };
|
|
235
|
+
}
|
|
229
236
|
let shown = false;
|
|
230
237
|
let column = outline.groups.find((each) => each.workspace === id) ?? null;
|
|
231
238
|
const put = () => {
|
|
@@ -425,7 +432,7 @@ export function joinedLine(joined) {
|
|
|
425
432
|
if (joined.failed) return `${where}:没有加进去(${joined.failed})`;
|
|
426
433
|
if (joined.existing) return `${where}里已经有它(${joined.names.under ? `在「${joined.names.under}」下面` : `「${joined.names.column}」栏`})`;
|
|
427
434
|
const more = joined.added.length > 1 ? `,连同它下面的 ${joined.added.length - 1} 篇` : "";
|
|
428
|
-
return `${where}:已加进${joined.names.under ? `「${joined.names.under}」下面` : `「${joined.names.column}」栏`}${more}
|
|
435
|
+
return `${where}:已加进${joined.names.under ? `「${joined.names.under}」下面` : `「${joined.names.column}」栏`}${more}(工作区内排序全局同步,文件位置不变)`;
|
|
429
436
|
}
|
|
430
437
|
|
|
431
438
|
/** Whether a gallery.json at `folder` would be another program's or not readable (what draft-add refuses to make a workspace of). */
|
|
@@ -73,12 +73,12 @@ export const iconUrl = (value, slug = null, { tab = false } = {}) => `/__gallery
|
|
|
73
73
|
const [TAB_LIGHT, TAB_DARK] = ICON_COLOR_VALUES.gray;
|
|
74
74
|
/**
|
|
75
75
|
* The browser tab's image of a page with no icon (the workbench's and the preview page's): the page
|
|
76
|
-
* the workbench's tree shows for one (its "page" icon, components/icons.ts: Lucide's file
|
|
76
|
+
* the workbench's tree shows for one (its "page" icon, components/icons.ts: Lucide's plain file outline,
|
|
77
77
|
* FinHarness's 文档), its box cropped to `1 1 22 22` so it fills the tab as an emoji does, in the tab
|
|
78
78
|
* glyphs' gray, light or dark as the system is. An image, never none: a tab given no image, or one that does not
|
|
79
79
|
* load, keeps the one it showed (Chrome), so a page with no icon opened after one with one showed that one's.
|
|
80
80
|
*/
|
|
81
|
-
export const DEFAULT_TAB_ICON = `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="1 1 22 22" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><style>svg{color:${TAB_LIGHT}}@media (prefers-color-scheme:dark){svg{color:${TAB_DARK}}}</style><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"
|
|
81
|
+
export const DEFAULT_TAB_ICON = `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="1 1 22 22" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><style>svg{color:${TAB_LIGHT}}@media (prefers-color-scheme:dark){svg{color:${TAB_DARK}}}</style><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/></svg>`)}`;
|
|
82
82
|
|
|
83
83
|
/** The value of an icon's element as the file (or a page) has it, or null. */
|
|
84
84
|
export function iconValueOf(html) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ICON_COLOR_VALUES } from "./icon-value.mjs";
|
|
2
|
+
|
|
3
|
+
// Gallery's own line icons as a custom page's icon (page.json's `icon`): the look of the workbench's sidebar
|
|
4
|
+
// head, whose 新建 and 搜索 are Lucide's line icons (a 1.75 line in 24 units, workbench/app/components/icons.ts),
|
|
5
|
+
// so that a page Gallery makes stands among them in the same hand (the user's word of 2026-11-09: no filled
|
|
6
|
+
// icon there). A value is `/icons/lucide/<name>.svg`, with no color of its own: the workbench masks it in the
|
|
7
|
+
// color of where it stands (the sidebar's icon gray, as an icon of no icon's color), the browser tab draws it
|
|
8
|
+
// in the tab's gray (as a page with no icon, icon-value.mjs DEFAULT_TAB_ICON). It is none of the three kinds
|
|
9
|
+
// of a document's icon (icon-value.mjs iconKind: no document has one), nor an icon of the 图标 tab: Gallery's
|
|
10
|
+
// default home page's house (src/editor/home-page.mjs HOME_ICON), alone so far. The icon route draws it
|
|
11
|
+
// (src/render/emoji.mjs iconImage).
|
|
12
|
+
|
|
13
|
+
const LINE_ICONS = {
|
|
14
|
+
// Lucide's house (1.67.0), the one the sidebar drew for the home page before its page.json said its icon.
|
|
15
|
+
house: '<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',
|
|
16
|
+
};
|
|
17
|
+
const LINE = /^\/icons\/lucide\/([a-z0-9-]+)\.svg$/;
|
|
18
|
+
|
|
19
|
+
/** The value of Gallery's line icon `name` (one LINE_ICONS has). */
|
|
20
|
+
export const lineIconValue = (name) => `/icons/lucide/${name}.svg`;
|
|
21
|
+
|
|
22
|
+
/** Whether `value` names one of Gallery's line icons. */
|
|
23
|
+
export const isLineIcon = (value) => lineIconSvg(value) !== null;
|
|
24
|
+
|
|
25
|
+
const [TAB_LIGHT, TAB_DARK] = ICON_COLOR_VALUES.gray;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The SVG of the line icon `value` names, or null (none of them): its lines in `color` (black, the
|
|
29
|
+
* workbench's mask); with `tab`, a browser tab's, its box cropped to `1 1 22 22` as the tab's icon of a
|
|
30
|
+
* page with no icon is, in the tab glyphs' gray, light or dark as the system is.
|
|
31
|
+
*/
|
|
32
|
+
export function lineIconSvg(value, { color = "currentColor", tab = false } = {}) {
|
|
33
|
+
const name = typeof value === "string" ? LINE.exec(value)?.[1] : null;
|
|
34
|
+
if (!name || !Object.hasOwn(LINE_ICONS, name)) return null;
|
|
35
|
+
const style = tab ? `<style>svg{color:${TAB_LIGHT}}@media (prefers-color-scheme:dark){svg{color:${TAB_DARK}}}</style>` : "";
|
|
36
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${tab ? "1 1 22 22" : "0 0 24 24"}" fill="none" stroke="${tab ? "currentColor" : color}" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">${style}${LINE_ICONS[name]}</svg>`;
|
|
37
|
+
}
|
|
@@ -3,9 +3,12 @@ import path from "node:path";
|
|
|
3
3
|
import { SIDEBAR_FILE, SIDEBAR_LIMITS, readSidebarText } from "./extension-sidebar.mjs";
|
|
4
4
|
import { said } from "./i18n/index.mjs";
|
|
5
5
|
import { isExtensionId } from "./outline-shape.mjs";
|
|
6
|
-
import { DOCUMENT_FOLDERS, layoutOf } from "./workspace.mjs";
|
|
6
|
+
import { defaultWorkspace, DOCUMENT_FOLDERS, layoutOf } from "./workspace.mjs";
|
|
7
|
+
import { sameDirectory } from "./preview-server.mjs";
|
|
8
|
+
import { writeAtomic } from "./files.mjs";
|
|
7
9
|
|
|
8
|
-
// The extensions
|
|
10
|
+
// The extensions visible in a workspace (docs/workbench.md "Extension columns"): public columns from
|
|
11
|
+
// the default workspace plus this project's own, a project sidebar.json taking precedence by id. Each a folder
|
|
9
12
|
// <workspace>/extensions/<id>/ whose sidebar.json (./extension-sidebar.mjs) gives a column of the sidebar
|
|
10
13
|
// its entries; what else the folder holds (the extension's own server, its code) is none of Gallery's.
|
|
11
14
|
// Read from disk each time it is asked (the workbench's list, the outline's columns, gallery extension):
|
|
@@ -26,10 +29,32 @@ export async function extensionFolders(root) {
|
|
|
26
29
|
.sort((a, b) => (a.id < b.id ? -1 : 1));
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
/** Public columns live in the default workspace; a project's own sidebar.json overrides the same id.
|
|
33
|
+
* Empty local folders do not hide a public column. Keep one source for listing, outline and writes.
|
|
34
|
+
*/
|
|
35
|
+
export async function visibleExtensionFolders(root) {
|
|
36
|
+
const home = defaultWorkspace();
|
|
37
|
+
const roots = sameDirectory(home, root) ? [root] : [home, root];
|
|
38
|
+
const found = new Map();
|
|
39
|
+
for (const owner of roots) {
|
|
40
|
+
for (const entry of await extensionFolders(owner)) {
|
|
41
|
+
const file = path.join(entry.folder, SIDEBAR_FILE);
|
|
42
|
+
const present = await fs.lstat(file).then(() => true, () => false);
|
|
43
|
+
if (present || !found.has(entry.id)) found.set(entry.id, { ...entry, root: owner, file, present });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [...found.values()].sort((a, b) => a.id < b.id ? -1 : 1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Resolve an id, never a client-supplied directory, to the file this workspace actually shows. */
|
|
50
|
+
export async function extensionSource(root, id) {
|
|
51
|
+
if (!isExtensionId(id)) return null;
|
|
52
|
+
return (await visibleExtensionFolders(root)).find(entry => entry.id === id) ?? null;
|
|
53
|
+
}
|
|
54
|
+
|
|
29
55
|
/** The ids of the extensions that have a sidebar.json (the columns the sidebar has), sorted. */
|
|
30
56
|
export async function extensionColumnIds(root) {
|
|
31
|
-
|
|
32
|
-
return found.filter(Boolean);
|
|
57
|
+
return (await visibleExtensionFolders(root)).filter(entry => entry.present).map(entry => entry.id);
|
|
33
58
|
}
|
|
34
59
|
|
|
35
60
|
/**
|
|
@@ -69,11 +94,62 @@ export async function readExtension(root, id) {
|
|
|
69
94
|
}
|
|
70
95
|
|
|
71
96
|
/**
|
|
72
|
-
* The extensions
|
|
97
|
+
* The extensions visible in workspace `root`, by id: those with a sidebar.json (the sidebar's columns), or with `all`
|
|
73
98
|
* every folder that may be one (gallery extension list). Each as readExtension says it.
|
|
74
99
|
*/
|
|
75
100
|
export async function listExtensions(root, { all = false } = {}) {
|
|
76
|
-
const folders = await
|
|
77
|
-
const read = await Promise.all(folders.map(({ id }) => readExtension(
|
|
101
|
+
const folders = await visibleExtensionFolders(root);
|
|
102
|
+
const read = await Promise.all(folders.map(({ id, root: owner }) => readExtension(owner, id)));
|
|
78
103
|
return all ? read : read.filter((extension) => !extension.missing);
|
|
79
104
|
}
|
|
105
|
+
|
|
106
|
+
/** Edit only a column's title or the order of its root entries. Called under the workspace lock.
|
|
107
|
+
* Read the latest source, keep unknown fields and whole subtrees, and refuse stale UI changes.
|
|
108
|
+
* Atomic replacement checks the original text again so an external writer is not silently overwritten.
|
|
109
|
+
*/
|
|
110
|
+
export async function editExtension(root, id, change) {
|
|
111
|
+
const refused = (status, reason, error) => ({ ok: false, status, reason, error });
|
|
112
|
+
const bad = () => refused(400, "body", said("请求格式不对"));
|
|
113
|
+
const stale = () => refused(409, "stale", said("扩展目录刚在别处改过,请重试"));
|
|
114
|
+
if (!isExtensionId(id) || !change || typeof change !== "object") return bad();
|
|
115
|
+
const rename = Object.hasOwn(change, "title");
|
|
116
|
+
if (rename ? (typeof change.title !== "string" || typeof change.baseTitle !== "string" || change.move !== undefined)
|
|
117
|
+
: (!change.move || !["before", "after"].includes(change.move.side) || typeof change.move.entry !== "string" || typeof change.move.ref !== "string" || !Array.isArray(change.baseOrder))) return bad();
|
|
118
|
+
const name = rename ? change.title.replace(/\s+/g, " ").trim() : null;
|
|
119
|
+
if (rename && (!name || name.length > SIDEBAR_LIMITS.column)) return bad();
|
|
120
|
+
const folder = path.join(layoutOf(root).extensions, id);
|
|
121
|
+
const file = path.join(folder, SIDEBAR_FILE);
|
|
122
|
+
// Never turn an extension path supplied by the client or a symlink into an arbitrary-file write.
|
|
123
|
+
for (const [target, directory] of [[layoutOf(root).extensions, true], [folder, true], [file, false]]) {
|
|
124
|
+
const stat = await fs.lstat(target).catch(() => null);
|
|
125
|
+
if (!stat) return refused(404, "missing", said("找不到这个扩展"));
|
|
126
|
+
if (stat.isSymbolicLink() || (directory ? !stat.isDirectory() : !stat.isFile())) return refused(409, "path", said("扩展路径不是普通文件或文件夹"));
|
|
127
|
+
if (!directory && stat.size > SIDEBAR_LIMITS.bytes) return refused(409, "extension", said("文件超过 1MB"));
|
|
128
|
+
}
|
|
129
|
+
const source = await fs.readFile(file, "utf8");
|
|
130
|
+
const read = readSidebarText(source);
|
|
131
|
+
if (read.error) return refused(409, "extension", read.error);
|
|
132
|
+
const value = JSON.parse(source.replace(/^\uFEFF/, ""));
|
|
133
|
+
if (rename) {
|
|
134
|
+
if (read.sidebar.title !== change.baseTitle) return stale();
|
|
135
|
+
if (read.sidebar.title === name) return { ok: true, written: false };
|
|
136
|
+
value.title = name;
|
|
137
|
+
} else {
|
|
138
|
+
const order = value.entries.map(entry => entry.id);
|
|
139
|
+
if (JSON.stringify(order) !== JSON.stringify(change.baseOrder)) return stale();
|
|
140
|
+
const from = order.indexOf(change.move.entry), to = order.indexOf(change.move.ref);
|
|
141
|
+
if (from < 0 || to < 0) return bad(); // Root entries only, in this file; no nesting or cross-column move.
|
|
142
|
+
if (from === to) return { ok: true, written: false };
|
|
143
|
+
const [entry] = value.entries.splice(from, 1);
|
|
144
|
+
const at = value.entries.findIndex(entry => entry.id === change.move.ref);
|
|
145
|
+
value.entries.splice(at + (change.move.side === "after" ? 1 : 0), 0, entry);
|
|
146
|
+
if (JSON.stringify(order) === JSON.stringify(value.entries.map(entry => entry.id))) return { ok: true, written: false };
|
|
147
|
+
}
|
|
148
|
+
const indent = source.match(/\n([ \t]+)"/)?.[1] ?? 2;
|
|
149
|
+
let next = JSON.stringify(value, null, indent) + "\n";
|
|
150
|
+
if (source.includes("\r\n")) next = next.replaceAll("\n", "\r\n");
|
|
151
|
+
if (source.startsWith("\uFEFF")) next = "\uFEFF" + next;
|
|
152
|
+
if (Buffer.byteLength(next) > SIDEBAR_LIMITS.bytes) return refused(409, "extension", said("文件超过 1MB"));
|
|
153
|
+
if (!(await writeAtomic(file, next, { expect: source }))) return stale();
|
|
154
|
+
return { ok: true, written: true };
|
|
155
|
+
}
|
package/browser/shared/http.mjs
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
// The local server's answers: JSON for its endpoints (the editor's saves, the workbench's commands),
|
|
2
2
|
// and files for its routes.
|
|
3
3
|
|
|
4
|
+
// Who may show a page of Gallery's in a frame (its HTML: the workbench, a document, a custom page): a page of
|
|
5
|
+
// its own origin, and a Gallery server of this computer, http://127.0.0.1 at any port (a workbench showing a
|
|
6
|
+
// draft of another workspace from that workspace's server, docs/workbench.md "Drafts of other workspaces";
|
|
7
|
+
// what such a frame may say and hear is still held to the servers vouched for). Never a site elsewhere, which
|
|
8
|
+
// could lay an editable page under a decoy, the reader's clicks and keys then editing the files (the security
|
|
9
|
+
// review of 0.2.0), nor localhost, which may lead to another program on [::1] (no workbench is shown there:
|
|
10
|
+
// src/server/routes.mjs toLoopback).
|
|
11
|
+
export const FRAMED_BY = { "Content-Security-Policy": "frame-ancestors 'self' http://127.0.0.1:*" };
|
|
12
|
+
|
|
4
13
|
// A JSON answer.
|
|
5
14
|
export function sendJson(response, status, body) {
|
|
6
15
|
response.statusCode = status;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// English for Gallery's UI, by the Chinese text the source writes (index.mjs t()), in the order the
|
|
2
2
|
// sources use them. tests/unit/i18n.mjs holds every string to an entry here and every entry to a string.
|
|
3
3
|
export default {
|
|
4
|
+
"扩展目录刚在别处改过,请重试": "The extension directory changed elsewhere. Please try again.",
|
|
5
|
+
"找不到这个扩展": "This extension could not be found",
|
|
6
|
+
"扩展路径不是普通文件或文件夹": "The extension path is not a regular file or directory",
|
|
4
7
|
"正在读取文档…": "Loading documents…",
|
|
5
8
|
"没有连上本地服务": "Not connected to the local service",
|
|
6
9
|
"重试": "Retry",
|
|
@@ -153,6 +156,8 @@ export default {
|
|
|
153
156
|
"撤销": "Undo",
|
|
154
157
|
"已恢复「{0}」": "Restored “{0}”",
|
|
155
158
|
"永久删除「{0}」?": "Delete “{0}” forever?",
|
|
159
|
+
"永久删除回收区中的全部 {0} 项?": "Permanently delete all {0} items in the trash?",
|
|
160
|
+
"删除全部": "Delete all",
|
|
156
161
|
"这份文档": "this document",
|
|
157
162
|
"删除后无法恢复。": "This can't be undone.",
|
|
158
163
|
"正在导出…": "Exporting…",
|
|
@@ -383,7 +388,7 @@ export default {
|
|
|
383
388
|
"不加载它的脚本和样式,已有的块只显示内容": "Its script and style aren't loaded. Existing blocks show only what they hold",
|
|
384
389
|
"文档菜单里出现哪些块,这个工作区加载哪些自定义块。": "Which blocks the document menus offer, and which custom blocks this workspace loads.",
|
|
385
390
|
"文档菜单里出现哪些块,这个工作区加载哪些自定义块": "Which blocks the document menus offer, and which custom blocks this workspace loads",
|
|
386
|
-
"块包的开关关掉后,它的块都不在
|
|
391
|
+
"块包的开关关掉后,它的块都不在 “/”和添加自定义块里;已经写在文档和页面里的块照常显示。": "With a pack's switch off, none of its blocks is offered in “/” or Add custom block; those already in documents and pages show as ever.",
|
|
387
392
|
"打开块包「{0}」": "Open the pack “{0}”",
|
|
388
393
|
"{0} 个块": "{0} blocks",
|
|
389
394
|
"启用块包": "Pack on",
|
|
@@ -391,18 +396,18 @@ export default {
|
|
|
391
396
|
"Gallery 自带": "Gallery's own",
|
|
392
397
|
"工作区自己写的块": "This workspace's own blocks",
|
|
393
398
|
"pack.json 读不出来:{0}": "pack.json can't be read: {0}",
|
|
394
|
-
"这个块包关着:它的块都不在
|
|
399
|
+
"这个块包关着:它的块都不在 “/”和添加自定义块里;已经写在文档和页面里的块照常显示。": "This pack is off: none of its blocks is offered in “/” or Add custom block; those already in documents and pages show as ever.",
|
|
395
400
|
"这个块包装上后改过({0}),Gallery 的新版本 {1} 不会换上改过的部分;没改过的块照常更新。": "This pack was changed after it was installed ({0}): Gallery's new version {1} is not put over what changed; the blocks not changed are updated as ever.",
|
|
396
401
|
"这个块包装上后改过({0}):再装一次新版本时,改过的部分保持不变。": "This pack was changed after it was installed ({0}): installing a new version keeps what changed as it is.",
|
|
397
402
|
"这个块包里还没有块。": "This pack has no blocks yet.",
|
|
398
403
|
"已导入块包「{0}」{1}": "Imported the pack “{0}” {1}",
|
|
399
404
|
"块包「{0}」已更新到 {1}": "The pack “{0}” is updated to {1}",
|
|
400
405
|
"块包「{0}」{1} 已经装好了": "The pack “{0}” {1} is installed already",
|
|
401
|
-
"自定义块按块包放:每个块包右边的开关管它的块在
|
|
406
|
+
"自定义块按块包放:每个块包右边的开关管它的块在 “/”和添加自定义块里提不提供;点一个块包看它的块。": "Custom blocks come in packs: the switch at a pack's right says whether its blocks are offered in “/” and Add custom block; click a pack to see its blocks.",
|
|
402
407
|
"这个工作区还没有自定义块:让 Agent 做一个,或导入一个块包,它们放在工作区的 components 文件夹里。": "This workspace has no custom blocks yet: ask an Agent to make one, or import a block pack. They live in the workspace's components folder.",
|
|
403
|
-
"每个块右边的开关管
|
|
408
|
+
"每个块右边的开关管 “/”和添加自定义块里提不提供它,默认打开;点一行看它的说明和别的开关。": "The switch right of each block decides whether \"/\" and Add custom block offer it, on by default. Click a row for what it is and its other switches.",
|
|
404
409
|
"在所有菜单里提供": "Offer in every menu",
|
|
405
|
-
"
|
|
410
|
+
"总开关关掉后,“/”和添加自定义块里都不再提供它;已经写在文档和页面里的块照常显示。": "With the master switch off, it is no longer offered in \"/\" or Add custom block. Blocks already written into documents and pages keep showing.",
|
|
406
411
|
"每个块右边的开关是「在文档菜单里显示」:关掉的块不再出现在 “/”、在下方新建和手柄的网格里,已有的块照常。": "The switch right of each block is \"Show in document menus\": a block switched off leaves \"/\", Add below and the handle's grid. Existing blocks stay as they are.",
|
|
407
412
|
"这个块总在文档菜单里": "This block is always in the document menus",
|
|
408
413
|
"读不出 component.json": "component.json cannot be read",
|
|
@@ -854,7 +859,6 @@ export default {
|
|
|
854
859
|
"在左侧插入": "Insert left",
|
|
855
860
|
"在右侧插入": "Insert right",
|
|
856
861
|
"均分列宽": "Even column widths",
|
|
857
|
-
"视图": "View",
|
|
858
862
|
"自动调整列宽": "Auto-fit column widths",
|
|
859
863
|
"列": "Column",
|
|
860
864
|
"行": "Row",
|
|
@@ -1026,6 +1030,9 @@ export default {
|
|
|
1026
1030
|
"左对齐": "Align left",
|
|
1027
1031
|
"居中对齐": "Align center",
|
|
1028
1032
|
"右对齐": "Align right",
|
|
1033
|
+
"对齐与缩进": "Align and indent",
|
|
1034
|
+
"增加缩进": "Indent",
|
|
1035
|
+
"减少缩进": "Outdent",
|
|
1029
1036
|
"粘贴图片链接…": "Paste an image link…",
|
|
1030
1037
|
"嵌入图片": "Embed image",
|
|
1031
1038
|
"适用于网络上的任何图片。": "Works with any image on the web.",
|
|
@@ -1048,6 +1055,9 @@ export default {
|
|
|
1048
1055
|
"替换图片": "Replace image",
|
|
1049
1056
|
"恢复原始大小": "Original size",
|
|
1050
1057
|
"已恢复原始大小 · Ctrl+Z 撤销": "Original size restored · Ctrl+Z to undo",
|
|
1058
|
+
"同步宽度到全局": "Use this width for all images",
|
|
1059
|
+
"页面上的图片已经都是这个宽度。": "The images on this page are all this width already.",
|
|
1060
|
+
"已将 {0} 张图片设为同一宽度 · Ctrl+Z 撤销": "{0} images set to the same width · Ctrl+Z to undo",
|
|
1051
1061
|
"上一张": "Previous",
|
|
1052
1062
|
"下一张": "Next",
|
|
1053
1063
|
"查看图片": "Image viewer",
|
|
@@ -1275,6 +1285,7 @@ export default {
|
|
|
1275
1285
|
"这份文档的标题和说明读不出来": "This document's title and description could not be read",
|
|
1276
1286
|
"应用到全部文档": "Apply to all documents",
|
|
1277
1287
|
"这份文档的字体与布局用到全部文档,新建的文档也一样": "Use this document's font and layout in every document, new ones too",
|
|
1288
|
+
"这份文档的字体与布局用到它所在工作区的全部文档,新建的文档也一样": "Use this document's font and layout in every document of its workspace, new ones too",
|
|
1278
1289
|
"已应用到全部文档": "Applied to all documents",
|
|
1279
1290
|
"已应用到全部文档,替换了 {0} 篇的单独设置": "Applied to all documents; own settings replaced in {0}",
|
|
1280
1291
|
"没有应用到全部文档:{0}": "Not applied to all documents: {0}",
|
|
@@ -1282,7 +1293,6 @@ export default {
|
|
|
1282
1293
|
"自定义页": "Custom page",
|
|
1283
1294
|
"更多页面": "More pages",
|
|
1284
1295
|
"未命名页面": "Untitled page",
|
|
1285
|
-
"首页不能移到回收区": "The home page cannot be moved to the trash",
|
|
1286
1296
|
"找不到这个页面": "This page was not found",
|
|
1287
1297
|
"标题不能是空的,也不能超过 200 个字": "A title cannot be empty or longer than 200 characters",
|
|
1288
1298
|
// 自定义页顶栏右上角的 ···(页的菜单)
|
|
@@ -1308,6 +1318,9 @@ export default {
|
|
|
1308
1318
|
"这个块不能放在页面上": "This block cannot go on a page",
|
|
1309
1319
|
"卡片设置": "Card settings",
|
|
1310
1320
|
"(未选择)": "(none)",
|
|
1321
|
+
// 自定义块的设置:视图读哪一张表格
|
|
1322
|
+
"表格 {0}": "Table {0}",
|
|
1323
|
+
"表格 {0} · {1}": "Table {0} · {1}",
|
|
1311
1324
|
// 首页:恢复默认卡片(侧栏里首页的菜单)和第一次打开时的说明
|
|
1312
1325
|
"恢复默认卡片": "Restore default cards",
|
|
1313
1326
|
"已放回默认卡片:{0}": "Default cards put back: {0}",
|
|
@@ -1315,18 +1328,18 @@ export default {
|
|
|
1315
1328
|
"没能放回:{0}": "Could not put back: {0}",
|
|
1316
1329
|
"默认卡片都在,没有要放回的": "All the default cards are there: nothing to put back",
|
|
1317
1330
|
"没能恢复默认卡片": "The default cards could not be restored",
|
|
1318
|
-
"
|
|
1331
|
+
"这一页之后又改过,在页面上按 Ctrl+Z 撤销": "This page changed since: press Ctrl+Z on the page to undo",
|
|
1319
1332
|
"放回的卡片之后被改过或拿掉了,没有撤销": "The cards put back were changed or taken out since: nothing undone",
|
|
1320
|
-
"
|
|
1333
|
+
"这一页的卡片可以自己摆": "This page's cards are yours to arrange",
|
|
1321
1334
|
"拖卡片右上角的 {0} 移动它,点一下它打开菜单(大小、设置、删除),点页面右上角的 ··· 里的「添加自定义块」加一张。": "Drag {0} at a card's top right to move it, click it to open the card's menu (Size, Settings, Delete), and use Add custom block in the ··· menu at the top right of the page to add one.",
|
|
1322
1335
|
"拖卡片右上角的 {0} 移动它,点一下它打开菜单(大小、设置、删除),点页面右上方的「添加自定义块」加一张。": "Drag {0} at a card's top right to move it, click it to open the card's menu (Size, Settings, Delete), and use Add custom block at the top right of the page to add one.",
|
|
1323
1336
|
"想要新卡片或新页面,跟 Agent 说,比如:": "For a new card or a new page, ask your Agent, for example:",
|
|
1324
|
-
"用 Gallery
|
|
1337
|
+
"用 Gallery 在「{0}」这一页加一张卡片,记我每天喝了几杯水。别动我摆好的卡片。": "Use Gallery to add a card to my page “{0}” that counts the glasses of water I drink each day. Leave the cards I placed where they are.",
|
|
1325
1338
|
"复制": "Copy",
|
|
1326
1339
|
"已复制": "Copied",
|
|
1327
1340
|
"已复制这句话,发给 Agent 就行": "Copied: send it to your Agent",
|
|
1328
1341
|
"关闭这条说明": "Close this note",
|
|
1329
|
-
"
|
|
1342
|
+
"这一页的说明": "About this page",
|
|
1330
1343
|
"没能记下这条说明已关闭": "Could not keep this note closed",
|
|
1331
1344
|
// 联网:卡片上的「允许访问」和组件列表的「允许联网」打开的同意框(netConsent.ts)
|
|
1332
1345
|
"这个块现在没有要联网的地方": "This block reaches no website now",
|
|
@@ -1337,11 +1350,23 @@ export default {
|
|
|
1337
1350
|
"允许联网": "Online",
|
|
1338
1351
|
"允许它从这些网站取数据:{0}": "Lets it fetch data from these websites: {0}",
|
|
1339
1352
|
"这个块不联网": "This block reaches no website",
|
|
1340
|
-
"
|
|
1341
|
-
"
|
|
1342
|
-
"
|
|
1343
|
-
"
|
|
1344
|
-
"
|
|
1353
|
+
"加到这一页": "Add to this page",
|
|
1354
|
+
"有了新的默认卡片": "New default cards",
|
|
1355
|
+
"点「加到这一页」放进空位,已有的卡片不动。以后也可以在这一页的菜单中点「恢复默认卡片」。": "Add to this page puts them in the empty spots and leaves your cards as they are. Later, Restore default cards in this page's menu does it too.",
|
|
1356
|
+
"新的默认卡片": "New default cards",
|
|
1357
|
+
"没能把卡片放到这一页": "The cards could not be put on this page",
|
|
1358
|
+
// 侧栏头部的拖动、自定义页的 ··· 菜单和新建页面、默认块包(SidebarHead.tsx、reportMenus.tsx、board/hint.mjs、ComponentSettings.tsx)
|
|
1359
|
+
"还没有块。让 Agent 写一个自定义块,没有指定块包时就放在这里。": "No blocks yet. Ask an Agent for a custom block: one it puts in no pack of its own goes here.",
|
|
1360
|
+
"新建页面": "New page",
|
|
1361
|
+
"一个空白页,放在这一页下面,让 Agent 来写": "A blank page under this one, for an Agent to write",
|
|
1362
|
+
"重命名、新建页面等…": "Rename, new page and more…",
|
|
1363
|
+
"页面的操作": "Page actions",
|
|
1364
|
+
"用 Gallery 把「{0}」这个自定义页写出来:放上我这周的待办,和离月底还有几天。": "Use Gallery to write my custom page “{0}”: this week's to-dos, and how many days are left in the month.",
|
|
1365
|
+
"这一页还是空的": "This page is empty",
|
|
1366
|
+
"自定义页由 Agent 来写:可以是一页卡片,也可以是它为你做的任何网页。": "An Agent writes a custom page: a page of cards, or any web page it makes for you.",
|
|
1367
|
+
"跟 Agent 说你想在这里放什么,比如:": "Tell your Agent what you want here, for example:",
|
|
1368
|
+
"空白的自定义页": "A blank custom page",
|
|
1369
|
+
"侧栏头部的顺序不对": "The order of the sidebar's top rows is not valid",
|
|
1345
1370
|
// 侧栏的栏和网页链接(SidebarTree.tsx、LinkForm.tsx、LinkView.tsx,服务器的 link、link-set)
|
|
1346
1371
|
"这是 Gallery 自己的地址,请直接链接文档": "This is Gallery's own address: link the document instead",
|
|
1347
1372
|
"这个网站不允许在别的页面里显示": "This website doesn't let other pages show it",
|
|
@@ -1388,7 +1413,10 @@ export default {
|
|
|
1388
1413
|
"只改它在这里的显示位置,文件不动": "Changes only where it shows here: no file moves",
|
|
1389
1414
|
"在文件夹中显示": "Show in folder",
|
|
1390
1415
|
"在它的工作区里打开": "Open in its workspace",
|
|
1391
|
-
"
|
|
1416
|
+
"「{0}」已移至它所在工作区的回收区": "“{0}” moved to the trash of its workspace",
|
|
1417
|
+
"副本在它所在的工作区里": "The copy is made in its workspace",
|
|
1418
|
+
"导入的页面在它所在的工作区里": "The imported pages are made in its workspace",
|
|
1419
|
+
"进它所在工作区的回收区": "Goes to the trash of its workspace",
|
|
1392
1420
|
"从文档树移除": "Remove from the sidebar",
|
|
1393
1421
|
"只移除这一条,不删除底稿": "Removes this entry only: the draft is not deleted",
|
|
1394
1422
|
"找不到底稿:本机登记的两个工作区编号相同": "Draft not found: two registered workspaces share one id",
|
|
@@ -1500,4 +1528,9 @@ export default {
|
|
|
1500
1528
|
"选的文件不是 zip": "The file chosen is not a zip",
|
|
1501
1529
|
"没有这个块包": "No such block pack",
|
|
1502
1530
|
"粘贴块包的文件夹或 zip 的路径": "Paste the path of the pack's folder or zip",
|
|
1531
|
+
"复制到另一个工作区?": "Copy to another workspace?",
|
|
1532
|
+
"将「{0}」及其子页面复制到「{1}」,原项保留。": "Copy “{0}” and its child pages to “{1}”, keeping the originals.",
|
|
1533
|
+
"已复制 {0} 项,原项保留": "Copied {0} items; originals kept",
|
|
1534
|
+
"跨工作区请复制,不能只移动目录位置": "Copy items to another workspace instead of moving their tree positions",
|
|
1535
|
+
"自定义块 {0} 缺失或版本冲突,未复制": "Custom block {0} is missing or has a version conflict; nothing was copied",
|
|
1503
1536
|
};
|
|
@@ -55,6 +55,10 @@ export const groupOfTop = (key) => (key === "" ? DOCS : key.slice(1));
|
|
|
55
55
|
/** Whether `entry` names a draft of another workspace. */
|
|
56
56
|
export const isForeign = (entry) => entry.startsWith("~");
|
|
57
57
|
|
|
58
|
+
/** File ownership is independent of which workspace's window is open. */
|
|
59
|
+
export const entryWorkspace = (entry, self) => /^~(ws-[0-9a-f]{6})\//.exec(entry)?.[1] ?? self;
|
|
60
|
+
export const columnWorkspaceId = (column, self) => column?.extension ? null : column?.workspace ?? column?.owner ?? self;
|
|
61
|
+
|
|
58
62
|
const tidy = (value) => (typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "");
|
|
59
63
|
|
|
60
64
|
/** A whole column's `left` as it is kept: the slugs once each, 1000 at most; none when there are none. */
|
|
@@ -80,6 +84,7 @@ export function groupOf(value) {
|
|
|
80
84
|
...(title ? { title } : {}),
|
|
81
85
|
...(GROUP_ROLES.includes(role) && id !== DOCS ? { role } : {}),
|
|
82
86
|
...(isWorkspaceColumn ? { workspace } : {}),
|
|
87
|
+
...(typeof value.owner === "string" && /^ws-[0-9a-f]{6}$/.test(value.owner) && !isWorkspaceColumn && id !== DOCS ? { owner: value.owner } : {}),
|
|
83
88
|
// A workspace's column alone is picked or hidden (the user's columns and 链接 are removed, never hidden).
|
|
84
89
|
...(isWorkspaceColumn && value.picked === true ? { picked: true } : {}),
|
|
85
90
|
...(isWorkspaceColumn && value.hidden === true ? { hidden: true } : {}),
|
|
@@ -98,6 +103,7 @@ export function validGroups(groups) {
|
|
|
98
103
|
if (value.title !== undefined && (typeof value.title !== "string" || tidy(value.title).length > GROUP_LIMITS.title)) return false;
|
|
99
104
|
if (value.role !== undefined && !GROUP_ROLES.includes(value.role)) return false;
|
|
100
105
|
if (value.extension !== undefined && group.extension !== value.extension) return false;
|
|
106
|
+
if (value.owner !== undefined && group.owner !== value.owner) return false;
|
|
101
107
|
if (value.left !== undefined && (!Array.isArray(value.left) || value.left.length > GROUP_LIMITS.left || !value.left.every((slug) => typeof slug === "string" && slugPattern.test(slug)))) return false;
|
|
102
108
|
ids.add(group.id);
|
|
103
109
|
}
|