@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
|
@@ -3,27 +3,31 @@ import { postAnswer } from "../post.mjs";
|
|
|
3
3
|
import { say } from "../notices.mjs";
|
|
4
4
|
import { addStyle, element } from "../ui.mjs";
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
// "A custom page", **
|
|
8
|
-
// `hint` (src/server/routes.mjs:
|
|
9
|
-
// note on its cards: how to move one (the grip at its top-right: drag it), open its
|
|
10
|
-
// the same grip: 大小, 设置, 删除), add one (添加自定义块: the first item of the ··· menu at the
|
|
11
|
-
// alone in a tab has it at the top right of its board) and
|
|
12
|
-
// card or a new page is the Agent's to make, with a sentence
|
|
13
|
-
// button). Its × closes it for good, for the workspace (POST
|
|
14
|
-
// /__gallery/pages
|
|
6
|
+
// A custom page's first-open note (notes/plans/component-pages-plan-2026-11-07.md §5.2; docs/render.md
|
|
7
|
+
// "A custom page", **Notes of a page**): at the top of a page whose page.json says `hint` (the default home
|
|
8
|
+
// page's), while the page map says `hint` (src/server/routes.mjs: its note not yet closed in this
|
|
9
|
+
// workspace), a short note on its cards: how to move one (the grip at its top-right: drag it), open its
|
|
10
|
+
// menu (a click on the same grip: 大小, 设置, 删除), add one (添加自定义块: the first item of the ··· menu at the
|
|
11
|
+
// top right of the workbench's bar; a page open alone in a tab has it at the top right of its board) and
|
|
12
|
+
// take one out (the menu's 删除), and that a new card or a new page is the Agent's to make, with a sentence
|
|
13
|
+
// the reader can copy and say to one (its 复制 button). Its × closes it for good, for the workspace (POST
|
|
14
|
+
// /__gallery/pages/<slug>/hint: .gallery/hints.json), whichever browser shows the page next. In the
|
|
15
15
|
// editor's look: grays alone, a quiet fill, no colour; the kit's own light and dark through the
|
|
16
16
|
// editor's tokens (look.mjs).
|
|
17
17
|
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// that came since
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
18
|
+
// Its note of new default cards (showNews: the plan's 3.4), on a page with the default cards (its page.json's
|
|
19
|
+
// defaultCards) made before some of them, while the page map says `news`: which default cards it does not
|
|
20
|
+
// hold that came since, and that 加到这一页 puts them in the empty spots as 恢复默认卡片 in the page's menu
|
|
21
|
+
// does (the board's restoreDefaults: what is missing alone, the cards there untouched, one step of the
|
|
22
|
+
// page's undo). A page already made is never changed by itself: the reader is told once, at the top of
|
|
23
|
+
// the page, where the first-open note stands, and nothing moves on the board until they ask. Its × (or
|
|
24
|
+
// 加到这一页) says it for the workspace (POST /__gallery/pages/<slug>/hint with { cards: true }), which
|
|
25
|
+
// 恢复默认卡片 does too.
|
|
26
|
+
//
|
|
27
|
+
// And the middle of a blank page (showBlank: the workbench's 新建页面, which no one has written yet, while
|
|
28
|
+
// the page map says `blank`): that an Agent writes a custom page, any page it likes, a board of cards or
|
|
29
|
+
// not, with a request the reader can copy and say to one, as the first-open note's. Nothing of it is the
|
|
30
|
+
// file's: once an Agent writes page.html the page is shown again without it.
|
|
27
31
|
const STYLE = `
|
|
28
32
|
.ge-home-hint { box-sizing: border-box; max-width: var(--gallery-board-width, 944px); margin: 0 auto 12px; }
|
|
29
33
|
.ge-home-hint-box { position: relative; box-sizing: border-box; max-width: 720px; padding: 14px 44px 14px 16px; border-radius: 10px;
|
|
@@ -47,6 +51,9 @@ const STYLE = `
|
|
|
47
51
|
.ge-home-hint-box .ge-home-hint-add { margin-left: -2px; background: var(--ge-btn-primary); color: var(--ge-btn-primary-text); }
|
|
48
52
|
.ge-home-hint-box .ge-home-hint-add:hover:not(:disabled) { background: var(--ge-btn-primary-hover); color: var(--ge-btn-primary-text); }
|
|
49
53
|
.ge-home-hint-box .ge-home-hint-add:disabled { opacity: .5; cursor: default; }
|
|
54
|
+
.ge-page-blank { box-sizing: border-box; display: flex; justify-content: center; padding: max(48px, 18vh) 16px 48px; }
|
|
55
|
+
.ge-page-blank .ge-home-hint-box { width: 100%; max-width: 520px; padding: 20px 20px 18px; }
|
|
56
|
+
.ge-page-blank .ge-home-hint-title { font-size: 16px; }
|
|
50
57
|
`;
|
|
51
58
|
|
|
52
59
|
const DOTS = '<svg viewBox="0 0 10 16" aria-hidden="true"><circle cx="2.5" cy="2" r="1.25"/><circle cx="7.5" cy="2" r="1.25"/><circle cx="2.5" cy="8" r="1.25"/><circle cx="7.5" cy="8" r="1.25"/><circle cx="2.5" cy="14" r="1.25"/><circle cx="7.5" cy="14" r="1.25"/></svg>';
|
|
@@ -70,15 +77,15 @@ export function showNews(map, { restore }) {
|
|
|
70
77
|
if (!map?.news?.length || !main) return null;
|
|
71
78
|
addStyle(STYLE);
|
|
72
79
|
const named = ({ block, name }) => name?.[language === "en" ? "en" : "zh"] ?? name?.zh ?? block;
|
|
73
|
-
const add = element("button", { type: "button", class: "ge-home-hint-copy ge-home-hint-add", text: t("
|
|
80
|
+
const add = element("button", { type: "button", class: "ge-home-hint-copy ge-home-hint-add", text: t("加到这一页") });
|
|
74
81
|
const close = element("button", { type: "button", class: "ge-home-hint-close", "aria-label": t("关闭这条说明"), title: t("关闭"), html: CLOSE });
|
|
75
82
|
const box = element("div", { class: "ge-home-hint-box" },
|
|
76
|
-
element("p", { class: "ge-home-hint-title", text: t("
|
|
83
|
+
element("p", { class: "ge-home-hint-title", text: t("有了新的默认卡片") }),
|
|
77
84
|
element("p", { text: map.news.map(named).join(t("、")) }),
|
|
78
|
-
element("p", { class: "ge-home-hint-ask", text: t("
|
|
85
|
+
element("p", { class: "ge-home-hint-ask", text: t("点「加到这一页」放进空位,已有的卡片不动。以后也可以在这一页的菜单中点「恢复默认卡片」。") }),
|
|
79
86
|
element("div", { class: "ge-home-hint-act" }, add),
|
|
80
87
|
close);
|
|
81
|
-
const note = noteOf("ge-home-news", t("
|
|
88
|
+
const note = noteOf("ge-home-news", t("新的默认卡片"), box);
|
|
82
89
|
for (const button of [add, close]) button.addEventListener("mousedown", (event) => event.preventDefault());
|
|
83
90
|
const told = () => postAnswer(`/__gallery/pages/${map.slug}/hint`, map.token, { cards: true });
|
|
84
91
|
add.addEventListener("click", async () => {
|
|
@@ -86,7 +93,7 @@ export function showNews(map, { restore }) {
|
|
|
86
93
|
const answer = await restore();
|
|
87
94
|
if (!answer?.ok) {
|
|
88
95
|
add.disabled = false;
|
|
89
|
-
return say(t("
|
|
96
|
+
return say(t("没能把卡片放到这一页"), "error");
|
|
90
97
|
}
|
|
91
98
|
note.remove();
|
|
92
99
|
const added = answer.added ?? [];
|
|
@@ -104,7 +111,7 @@ export function showNews(map, { restore }) {
|
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
/**
|
|
107
|
-
* The note shown, on the
|
|
114
|
+
* The note shown, on the page whose map (`map`: slug, token) says `hint`, at the top of the page
|
|
108
115
|
* (`main.gallery-page`, before what the page holds). `hosted`: the page stands in a workbench, whose top
|
|
109
116
|
* bar's ··· menu has 添加自定义块 (the words say so), else the page's own at the top right of its board. Returns the
|
|
110
117
|
* note, or null where none is shown.
|
|
@@ -114,16 +121,16 @@ export function showHint(map, { hosted = false } = {}) {
|
|
|
114
121
|
if (!map?.hint || !main) return null;
|
|
115
122
|
addStyle(STYLE);
|
|
116
123
|
// The sentence offered: one that names Gallery, so that the Agent takes up its skill.
|
|
117
|
-
const ask = t("用 Gallery
|
|
124
|
+
const ask = t("用 Gallery 在「{0}」这一页加一张卡片,记我每天喝了几杯水。别动我摆好的卡片。", map.title ?? document.title);
|
|
118
125
|
const copy = element("button", { type: "button", class: "ge-home-hint-copy", text: t("复制") });
|
|
119
126
|
const close = element("button", { type: "button", class: "ge-home-hint-close", "aria-label": t("关闭这条说明"), title: t("关闭"), html: CLOSE });
|
|
120
127
|
const box = element("div", { class: "ge-home-hint-box" },
|
|
121
|
-
element("p", { class: "ge-home-hint-title", text: t("
|
|
128
|
+
element("p", { class: "ge-home-hint-title", text: t("这一页的卡片可以自己摆") }),
|
|
122
129
|
element("p", {}, ...filled(hosted ? t("拖卡片右上角的 {0} 移动它,点一下它打开菜单(大小、设置、删除),点页面右上角的 ··· 里的「添加自定义块」加一张。") : t("拖卡片右上角的 {0} 移动它,点一下它打开菜单(大小、设置、删除),点页面右上方的「添加自定义块」加一张。"), [icon(DOTS)])),
|
|
123
130
|
element("p", { class: "ge-home-hint-ask", text: t("想要新卡片或新页面,跟 Agent 说,比如:") }),
|
|
124
131
|
element("div", { class: "ge-home-hint-say" }, element("span", { text: ask }), copy),
|
|
125
132
|
close);
|
|
126
|
-
const note = noteOf("", t("
|
|
133
|
+
const note = noteOf("", t("这一页的说明"), box);
|
|
127
134
|
for (const button of [copy, close]) button.addEventListener("mousedown", (event) => event.preventDefault());
|
|
128
135
|
copy.addEventListener("click", () => {
|
|
129
136
|
// The frame given the focus first: in a workbench a press its mousedown keeps from moving the focus
|
|
@@ -143,3 +150,33 @@ export function showHint(map, { hosted = false } = {}) {
|
|
|
143
150
|
main.prepend(note);
|
|
144
151
|
return note;
|
|
145
152
|
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The middle of a blank page (the page map's `blank`: the workbench's 新建页面, which no one has written yet):
|
|
156
|
+
* that an Agent writes it, any page it likes, with a request to copy and say to one. Returns the note, or
|
|
157
|
+
* null where none is shown (no blank page, or no main.gallery-page to show it in).
|
|
158
|
+
*/
|
|
159
|
+
export function showBlank(map) {
|
|
160
|
+
const main = document.querySelector("main.gallery-page");
|
|
161
|
+
if (!map?.blank || !main) return null;
|
|
162
|
+
addStyle(STYLE);
|
|
163
|
+
const title = map.title ?? document.title;
|
|
164
|
+
const ask = t("用 Gallery 把「{0}」这个自定义页写出来:放上我这周的待办,和离月底还有几天。", title);
|
|
165
|
+
const copy = element("button", { type: "button", class: "ge-home-hint-copy", text: t("复制") });
|
|
166
|
+
const box = element("div", { class: "ge-home-hint-box" },
|
|
167
|
+
element("p", { class: "ge-home-hint-title", text: t("这一页还是空的") }),
|
|
168
|
+
element("p", { text: t("自定义页由 Agent 来写:可以是一页卡片,也可以是它为你做的任何网页。") }),
|
|
169
|
+
element("p", { class: "ge-home-hint-ask", text: t("跟 Agent 说你想在这里放什么,比如:") }),
|
|
170
|
+
element("div", { class: "ge-home-hint-say" }, element("span", { text: ask }), copy));
|
|
171
|
+
const note = noteOf("ge-page-blank", t("空白的自定义页"), box);
|
|
172
|
+
copy.addEventListener("mousedown", (event) => event.preventDefault());
|
|
173
|
+
copy.addEventListener("click", () => {
|
|
174
|
+
window.focus(); // as the first-open note's 复制: Chrome writes no clipboard of a document without the focus
|
|
175
|
+
navigator.clipboard?.writeText(ask).then(() => {
|
|
176
|
+
copy.textContent = t("已复制");
|
|
177
|
+
say(t("已复制这句话,发给 Agent 就行"));
|
|
178
|
+
}, () => say(t("没能复制:浏览器不允许写剪贴板。"), "error"));
|
|
179
|
+
});
|
|
180
|
+
main.append(note);
|
|
181
|
+
return note;
|
|
182
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { GAP, GRID, cellAt, fitHeight, gridFor, moved, pushDown, sizeFor, spanOf } from "../../../shared/board-places.mjs";
|
|
2
2
|
import { cellsOf } from "../../../shared/card-size.mjs";
|
|
3
3
|
import { language, t } from "../../../shared/i18n/index.mjs";
|
|
4
|
-
import { BLOCK_ICON, svg } from "../../components/icons.mjs";
|
|
4
|
+
import { BLOCK_ICON, SETTINGS_ICON, svg } from "../../components/icons.mjs";
|
|
5
5
|
import { instanceAround, instanceOf, packageOf } from "../../components/instances.mjs";
|
|
6
|
-
import { edgeScroll } from "../edge-scroll.mjs";
|
|
7
6
|
import { gestureLock } from "../gesture.mjs";
|
|
8
7
|
import { ICONS, createMenu } from "../menu.mjs";
|
|
9
8
|
import { say } from "../notices.mjs";
|
|
@@ -12,7 +11,8 @@ import { tooltip } from "../tooltip.mjs";
|
|
|
12
11
|
import { addStyle, element, mount } from "../ui.mjs";
|
|
13
12
|
import { createClient } from "./client.mjs";
|
|
14
13
|
import { createHistory } from "./history.mjs";
|
|
15
|
-
import {
|
|
14
|
+
import { createEdgeScroll, createSettle, glide, isGliding, stopGlide } from "./motion.mjs";
|
|
15
|
+
import { showBlank, showHint, showNews } from "./hint.mjs";
|
|
16
16
|
import { closeSettings, formOpen, openSettings } from "./settings.mjs";
|
|
17
17
|
|
|
18
18
|
// A custom page's board edited (docs/render.md "A custom page"; the plan's §5.3, the spec §6 and §8):
|
|
@@ -31,20 +31,33 @@ import { closeSettings, formOpen, openSettings } from "./settings.mjs";
|
|
|
31
31
|
// one that moves less, or a key (Enter, Space) on the grip, opens the card's menu: what is dragged
|
|
32
32
|
// and selected in a card is its block's (DocKit.drag never moves a card). A bare card (its block's
|
|
33
33
|
// card.bare) shows where it stands by a dashed line of the guides' gray.
|
|
34
|
-
// -
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
34
|
+
// - The board while a card is moved or resized (the user's word of 2026-11-09): no landing shadow
|
|
35
|
+
// under it; the board's lattice drawn as faint grey dots, one where the gaps between four cells
|
|
36
|
+
// cross (the board's outer edge too), from the gesture's start to its end (.ge-board-dots, light
|
|
37
|
+
// and dark), and the card snapping to the cells it would land at as it comes within SNAP px of them,
|
|
38
|
+
// each axis on its own: where it snaps is where a drop puts it.
|
|
39
|
+
// - Its motion (./motion.mjs; the user's word of 2026-11-09, an iPhone's home-screen widgets): the card
|
|
40
|
+
// held follows the pointer at once and settles onto the cells it snaps to (or off them) on a spring in
|
|
41
|
+
// SETTLE ms, never a jump; the cards making way, the card let go (to its cells, or back on Escape), a
|
|
42
|
+
// resize's and 大小 ›'s, an undo's and a redo's glide from where they were seen to their new place on
|
|
43
|
+
// that spring (FLIP, GLIDE ms), each starting again from where it is seen when the target changes under
|
|
44
|
+
// it; near the window's top or bottom edge the page scrolls, timed by the frames, faster nearer the edge
|
|
45
|
+
// and never past FASTEST px a second. prefers-reduced-motion: no glide or settling.
|
|
46
|
+
// - Moving. The card follows the pointer, and where it would go is the whole cells nearest to it
|
|
47
|
+
// (shared/board-places.mjs cellAt), which the card itself is drawn at (DocBoard.draft), moved off
|
|
48
|
+
// them by the pointer's offset but within SNAP px of them on an axis, where it stands on them; the
|
|
49
|
+
// cards it would meet are drawn pushed down under it (pushDown, the service's own rule), never up.
|
|
50
|
+
// Escape, or the pointer taken away, puts all back; a drop sends `place`, and the board stands as
|
|
51
|
+
// the service answers. The rows above a board's first card are not drawn (DocBoard.skipped): the
|
|
52
|
+
// pointer's row is the drawn one plus the rows skipped as the drag began, so that a card let go
|
|
53
|
+
// where it was writes nothing and one held above the first row goes above it (drawn at the top, the
|
|
54
|
+
// others under it).
|
|
42
55
|
// - Resizing. A card whose block says card.resize has a grip at its bottom-right: it follows the
|
|
43
|
-
// pointer,
|
|
44
|
-
// between card.min and card.max (sizeFor), never past the row's end;
|
|
45
|
-
// gets wider (its height is its content's); one whose manifest frees it
|
|
46
|
-
// whole size. The menu's 大小 › gives the listed sizes (the common ones), in a
|
|
47
|
-
// words alone, only as wide as they are.
|
|
56
|
+
// pointer, snapping to the size a drop gives (within SNAP px of its width or height), the nearest of
|
|
57
|
+
// card.sizes, else whole cells between card.min and card.max (sizeFor), never past the row's end;
|
|
58
|
+
// one of fit content only gets wider (its height is its content's); one whose manifest frees it
|
|
59
|
+
// (`any`) reaches every whole size. The menu's 大小 › gives the listed sizes (the common ones), in a
|
|
60
|
+
// card of rows of words alone, only as wide as they are.
|
|
48
61
|
// - The card's menu (the grip's click): 设置… (a block with settings: ./settings.mjs, written by the
|
|
49
62
|
// service's `settings`), 大小 ›, 删除 (`remove`).
|
|
50
63
|
// - 添加自定义块: in a workbench (`hosted`) the workbench's top bar has its button, which asks by the
|
|
@@ -53,7 +66,8 @@ import { closeSettings, formOpen, openSettings } from "./settings.mjs";
|
|
|
53
66
|
// centred, and adds to the page's FIRST board; a page open alone in a tab has the button of its own
|
|
54
67
|
// at the top right of each board, above it. The library (the service's GET library: the blocks
|
|
55
68
|
// whose places hold page and are not turned off, with their previews, Gallery's own not yet in the
|
|
56
|
-
// workspace too, which the service puts in)
|
|
69
|
+
// workspace too, which the service puts in), in a section of each pack under its name (no pack's
|
|
70
|
+
// name in grey after a block's): the card put at the first free spot by its block's
|
|
57
71
|
// default size (`add`); the page is then shown again (the host's hidden-frame swap), which brings
|
|
58
72
|
// the block's script and style.
|
|
59
73
|
// - A block's own write (context.edit, the kit's cancellable doc-component-edit): taken here, its
|
|
@@ -88,12 +102,14 @@ import { closeSettings, formOpen, openSettings } from "./settings.mjs";
|
|
|
88
102
|
const BOARD = ".gallery-board";
|
|
89
103
|
const CARD = ".gallery-card";
|
|
90
104
|
const THRESHOLD = 4; // px a press moves before it is a drag
|
|
105
|
+
const SNAP = 14; // px from the place (or the size) a drop gives within which a moved (or resized) card stands on it
|
|
106
|
+
const DOT = 3; // px of room around each of the board's dots while a card is moved or resized (their tile's corner)
|
|
91
107
|
const GRIP = { size: 28, inset: 6 }; // the grip's box, and its room from the card's top and right edges (inside the card)
|
|
92
108
|
const FIELDS = "input, textarea, select, [contenteditable]:not([contenteditable=false])";
|
|
93
109
|
|
|
94
110
|
const DOTS = '<svg viewBox="0 0 10 16" aria-hidden="true"><circle cx="2.5" cy="2" r="1.25"/><circle cx="7.5" cy="2" r="1.25"/><circle cx="2.5" cy="8" r="1.25"/><circle cx="7.5" cy="8" r="1.25"/><circle cx="2.5" cy="14" r="1.25"/><circle cx="7.5" cy="14" r="1.25"/></svg>';
|
|
95
111
|
const CORNER = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M13 6.5 6.5 13M13 10.5 10.5 13"/></svg>';
|
|
96
|
-
const GEAR =
|
|
112
|
+
const GEAR = SETTINGS_ICON;
|
|
97
113
|
const SIZE = svg('<rect x="3.25" y="3.25" width="13.5" height="13.5" rx="2.5"/><path d="M10 3.25v13.5M3.25 10H10"/>');
|
|
98
114
|
const BLOCK = BLOCK_ICON;
|
|
99
115
|
|
|
@@ -118,10 +134,21 @@ const STYLE = `
|
|
|
118
134
|
.ge-board-add:hover { background: var(--ge-hover); color: var(--ge-tx); }
|
|
119
135
|
.ge-board-add:active, .ge-board-add[data-pressed] { background: var(--ge-press); color: var(--ge-tx); }
|
|
120
136
|
.ge-board-add svg { display: block; width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.gallery-board > .
|
|
124
|
-
|
|
137
|
+
/* The board's lattice while a card is moved or resized: a faint grey dot where the gaps between four cells cross, under the cards (first in the board, which stands as their containing block meanwhile), placed by dotsOn. */
|
|
138
|
+
.gallery-board[data-ge-dotted] { position: relative; }
|
|
139
|
+
.gallery-board > .ge-board-dots { position: absolute; pointer-events: none; background-image: radial-gradient(circle at ${DOT}px ${DOT}px, light-dark(rgb(55 53 47 / 24%), rgb(255 255 255 / 20%)) 0 1.1px, transparent 1.6px); background-repeat: repeat; animation: ge-board-dots-in .14s ease-out; }
|
|
140
|
+
@keyframes ge-board-dots-in { from { opacity: 0; } }
|
|
141
|
+
@media (prefers-reduced-motion: reduce) { .gallery-board > .ge-board-dots { animation: none; } }
|
|
142
|
+
/* The card held lifts: its own shadow kept as it is, layer for layer, and a soft lift added after it, so
|
|
143
|
+
that only the lift eases in and out (a menu's shadow in its place made each of the card's layers turn
|
|
144
|
+
into another's, the shadow swelling and shrinking on the way: the user, 2026-11-09); a frameless card
|
|
145
|
+
takes the lift alone. One let go stays over the others while it glides to its cells. */
|
|
146
|
+
.gallery-board { --ge-board-lift: 0 10px 28px -10px light-dark(rgb(15 15 15 / 16%), rgb(0 0 0 / 55%)), 0 3px 10px -4px light-dark(rgb(15 15 15 / 8%), rgb(0 0 0 / 30%)); }
|
|
147
|
+
.gallery-board > .gallery-card[data-ge-lifted], .gallery-board > .gallery-card[data-ge-landing] { transition: box-shadow .2s ease-out; }
|
|
148
|
+
.gallery-board > .gallery-card[data-ge-lifted] { z-index: 3; box-shadow: var(--gallery-card-shadow), var(--ge-board-lift); cursor: grabbing; }
|
|
149
|
+
.gallery-board > .gallery-card[data-ge-bare][data-ge-lifted] { box-shadow: var(--ge-board-lift); }
|
|
150
|
+
.gallery-board > .gallery-card[data-ge-sizing], .gallery-board > .gallery-card[data-ge-landing] { z-index: 3; }
|
|
151
|
+
@media (prefers-reduced-motion: reduce) { .gallery-board > .gallery-card[data-ge-lifted], .gallery-board > .gallery-card[data-ge-landing] { transition: none; } }
|
|
125
152
|
.gallery-board > .gallery-card[data-ge-bare][data-ge-hover] { outline: 1px dashed var(--ge-guide); outline-offset: 2px; }
|
|
126
153
|
/* The card the grip stands in: a head's quiet note in its corner fades (the kit's --gallery-grip-shown, board.css). */
|
|
127
154
|
.gallery-board > .gallery-card[data-ge-hover] { --gallery-grip-shown: 1; }
|
|
@@ -218,7 +245,7 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
218
245
|
};
|
|
219
246
|
const drawn = (card) => globalThis.DocBoard?.drawn(card) ?? cellsOf(card);
|
|
220
247
|
// How many rows above its first card the board does not draw (the kit's DocBoard.skipped): its drawn row
|
|
221
|
-
// r is the file's row r + skipped, which
|
|
248
|
+
// r is the file's row r + skipped, which a dragged card's place and a drop are reckoned by.
|
|
222
249
|
const skipped = (board) => globalThis.DocBoard?.skipped?.(board) ?? 0;
|
|
223
250
|
const draft = (board, cells) => globalThis.DocBoard?.draft(board, cells);
|
|
224
251
|
|
|
@@ -226,16 +253,20 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
226
253
|
// has not, or one the page has that it does not name, is someone else's doing: the page is shown again.
|
|
227
254
|
function took(answer, { own = [] } = {}) {
|
|
228
255
|
const named = new Set();
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
256
|
+
// Where the page drew a card elsewhere than the service put it, it glides there (a held card follows the pointer).
|
|
257
|
+
glide(allCards(), () => {
|
|
258
|
+
for (const card of answer.cards ?? []) {
|
|
259
|
+
named.add(card.id);
|
|
260
|
+
const node = cardById(card.id);
|
|
261
|
+
if (!node) {
|
|
262
|
+
if (!own.includes(card.id) && !leaving.has(card.id)) wantSwap(); // one the page took out meanwhile, its remove asked, is its own
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
setCells(node, card);
|
|
266
|
+
node.dataset.geBase = card.base;
|
|
235
267
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
268
|
+
if (!gesture) for (const board of boards()) globalThis.DocBoard?.layout(board);
|
|
269
|
+
}, { still: gesture?.card ?? null, settled: placeAgain });
|
|
239
270
|
if (allCards().some((card) => !named.has(card.dataset.cardId))) wantSwap();
|
|
240
271
|
history.know(basesNow());
|
|
241
272
|
}
|
|
@@ -403,7 +434,8 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
403
434
|
if (resizable(card) && sizes.length > 1) {
|
|
404
435
|
items.push({
|
|
405
436
|
label: t("大小"), icon: SIZE, icons: false, compact: true,
|
|
406
|
-
|
|
437
|
+
// By width, then height (the user's word of 2026-11-09; the manifest lists its default first).
|
|
438
|
+
submenu: () => [...sizes].sort(([aw, ah], [bw, bh]) => aw - bw || ah - bh).map(([w, h]) => ({ label: `${w} × ${h}`, current: w === cells.w && h === cells.h, run: () => layOut(board, () => placeCard(card, { ...cells, w, h }), { lift: card }) })),
|
|
407
439
|
});
|
|
408
440
|
}
|
|
409
441
|
if (items.length) items.push({ separator: true });
|
|
@@ -435,37 +467,58 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
435
467
|
}, true);
|
|
436
468
|
|
|
437
469
|
// ---------- moving and resizing ----------
|
|
438
|
-
const
|
|
439
|
-
//
|
|
440
|
-
//
|
|
470
|
+
const dots = element("div", { class: "ge-board-dots", "data-doc-dev": "", "aria-hidden": "true" });
|
|
471
|
+
// The board's dots over all it draws now (its rows grow as a draft puts a card lower), each at a point of
|
|
472
|
+
// its lattice: where the gaps between four cells cross, and as far out on its edges, a DOT px room
|
|
473
|
+
// around each (the tile's corner the gradient draws it in).
|
|
474
|
+
const dotsOn = (board) => {
|
|
475
|
+
const { rect, step } = geometry(board);
|
|
476
|
+
const box = board.getBoundingClientRect();
|
|
477
|
+
const columns = Math.round((rect.right - rect.left + GAP) / step);
|
|
478
|
+
const rows = Math.max(1, Math.round((board.clientHeight + GAP) / step));
|
|
479
|
+
Object.assign(dots.style, {
|
|
480
|
+
left: `${rect.left - box.left - board.clientLeft - GAP / 2 - DOT}px`, top: `${-GAP / 2 - DOT}px`,
|
|
481
|
+
width: `${columns * step + 2 * DOT}px`, height: `${rows * step + 2 * DOT}px`, backgroundSize: `${step}px ${step}px`,
|
|
482
|
+
});
|
|
483
|
+
};
|
|
484
|
+
// Each frame of a gesture: near the window's top or bottom edge the page scrolls (./motion.mjs
|
|
485
|
+
// createEdgeScroll: timed by the frames, faster nearer the edge, never past FASTEST px a second) and the
|
|
486
|
+
// gesture follows what came into view; a card settling onto (or off) what it snaps to is drawn again.
|
|
441
487
|
let pointer = null;
|
|
442
488
|
let scrolling = 0;
|
|
443
|
-
const
|
|
489
|
+
const edge = createEdgeScroll();
|
|
490
|
+
const frame = () => {
|
|
444
491
|
scrolling = 0;
|
|
445
492
|
if (!gesture || !pointer) return;
|
|
446
|
-
if (
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
// The spot at cells of the file, drawn where its board draws them.
|
|
450
|
-
const placeSpot = (board, cells) => {
|
|
451
|
-
for (const axis of ["x", "y", "w", "h"]) spot.style.setProperty(`--gallery-${axis}`, String(axis === "y" ? cells.y - skipped(board) : cells[axis]));
|
|
493
|
+
if (edge.frame(pointer.clientY, performance.now())) follow(pointer);
|
|
494
|
+
else if (gesture.settle.gliding()) draw();
|
|
495
|
+
scrolling = requestAnimationFrame(frame);
|
|
452
496
|
};
|
|
497
|
+
// The cards of `board` laid out by `change` (cells set), those it moves gliding there (./motion.mjs), the grip
|
|
498
|
+
// put again on its card once they stand.
|
|
499
|
+
const layOut = (board, change, options = {}) => glide(cardsIn(board), () => {
|
|
500
|
+
const result = change();
|
|
501
|
+
globalThis.DocBoard?.layout(board);
|
|
502
|
+
return result;
|
|
503
|
+
}, { settled: placeAgain, ...options });
|
|
453
504
|
|
|
454
505
|
function begin(kind, card, event) {
|
|
506
|
+
stopGlide(card); // still gliding from a drop: taken up where its cells are
|
|
455
507
|
const board = card.parentElement;
|
|
456
508
|
const file = cellsOf(card);
|
|
457
509
|
const rect = card.getBoundingClientRect();
|
|
458
510
|
// skip: the rows the board skipped as the gesture began, which the kit keeps while its draft is shown
|
|
459
511
|
// (a card held above the first row skips fewer): the pointer's row is reckoned by it throughout.
|
|
460
|
-
gesture = { kind, card, board, file, skip: skipped(board), target: { ...file }, grab: { x: event.clientX - rect.left, y: event.clientY - rect.top }, start: { x: event.clientX, y: event.clientY, width: rect.width, height: rect.height, scroll: scrollY } };
|
|
512
|
+
gesture = { kind, card, board, file, skip: skipped(board), target: { ...file }, grab: { x: event.clientX - rect.left, y: event.clientY - rect.top }, start: { x: event.clientX, y: event.clientY, width: rect.width, height: rect.height, scroll: scrollY }, settle: createSettle(SNAP), size: null };
|
|
461
513
|
document.documentElement.setAttribute(kind === "move" ? "data-ge-dragging" : "data-ge-sizing", "");
|
|
462
514
|
card.setAttribute(kind === "move" ? "data-ge-lifted" : "data-ge-sizing", "");
|
|
463
|
-
|
|
464
|
-
board.
|
|
515
|
+
board.setAttribute("data-ge-dotted", "");
|
|
516
|
+
board.prepend(dots);
|
|
517
|
+
dotsOn(board);
|
|
465
518
|
grip.removeAttribute("data-shown");
|
|
466
519
|
corner.removeAttribute("data-shown");
|
|
467
520
|
follow(event);
|
|
468
|
-
scrolling = requestAnimationFrame(
|
|
521
|
+
scrolling = requestAnimationFrame(frame);
|
|
469
522
|
}
|
|
470
523
|
function follow(event) {
|
|
471
524
|
const { kind, card, board, file, skip, grab, start } = gesture;
|
|
@@ -479,7 +532,7 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
479
532
|
target = { ...file, x: clamp(cellAt(left, cell), 0, 12 - file.w), y: Math.max(0, cellAt(top, cell) + skip) };
|
|
480
533
|
} else {
|
|
481
534
|
// The card follows the pointer between the least and the most it can snap to (its listed sizes', or
|
|
482
|
-
// its min and max), never past its row's end
|
|
535
|
+
// its min and max), never past its row's end, standing at the size a drop gives where it is near it.
|
|
483
536
|
const block = infoOf(card)?.card ?? {};
|
|
484
537
|
const listed = block.any ? null : block.sizes?.filter(([w]) => file.x + w <= 12); // a card its block frees (any) takes every whole size
|
|
485
538
|
const least = listed?.length ? { w: Math.min(...listed.map(([w]) => w)), h: Math.min(...listed.map(([, h]) => h)) } : { w: block.min?.w ?? 1, h: block.min?.h ?? 1 };
|
|
@@ -490,36 +543,59 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
490
543
|
const asked = { w: Math.max(1, Math.round((width + GAP) / step)), h: Math.max(1, Math.round((height + GAP) / step)) };
|
|
491
544
|
const size = listed?.length ? sizeFor({ sizes: listed }, asked) : sizeFor(block, { w: Math.min(asked.w, 12 - file.x), h: asked.h }, 12 - file.x);
|
|
492
545
|
target = { ...file, w: size.w, h: fits ? file.h : size.h };
|
|
493
|
-
|
|
494
|
-
if (!fits) card.style.height = `${Math.round(height)}px`;
|
|
546
|
+
gesture.size = { width, height, w: spanOf(size.w, cell), h: spanOf(size.h, cell), fits };
|
|
495
547
|
}
|
|
496
548
|
if (!cellsSame(target, gesture.target) || !gesture.drafted) {
|
|
497
549
|
gesture.target = target;
|
|
498
550
|
gesture.drafted = true;
|
|
499
|
-
|
|
500
|
-
|
|
551
|
+
// The cards it meets make way, gliding (the held card follows the pointer: draw).
|
|
552
|
+
glide(cardsIn(board), () => draft(board, new Map([[card, target]])), { still: card });
|
|
501
553
|
}
|
|
554
|
+
draw();
|
|
555
|
+
dotsOn(board);
|
|
556
|
+
}
|
|
557
|
+
// The held card drawn where the pointer has it: moved, at the cells it would land at (the draft's), off them
|
|
558
|
+
// by the pointer's offset but where that is within SNAP px; resized, at the pointer's size but where that is
|
|
559
|
+
// within SNAP px of the size a drop gives. Each axis settles onto (or off) what it snaps to (createSettle).
|
|
560
|
+
function draw() {
|
|
561
|
+
const { kind, card, board, grab, settle, size } = gesture;
|
|
562
|
+
const time = performance.now();
|
|
502
563
|
if (kind === "move") {
|
|
564
|
+
const { rect, step } = geometry(board);
|
|
503
565
|
const now = drawn(card);
|
|
504
|
-
|
|
566
|
+
const cells = { x: now.x * step, y: (now.y - skipped(board)) * step };
|
|
567
|
+
const x = settle.at("x", pointer.clientX - grab.x - rect.left, cells.x, time);
|
|
568
|
+
const y = settle.at("y", pointer.clientY - grab.y - rect.top, cells.y, time);
|
|
569
|
+
card.style.translate = `${Math.round(x - cells.x)}px ${Math.round(y - cells.y)}px`;
|
|
570
|
+
} else {
|
|
571
|
+
card.style.width = `${Math.round(settle.at("w", size.width, size.w, time))}px`;
|
|
572
|
+
if (!size.fits) card.style.height = `${Math.round(settle.at("h", size.height, size.h, time))}px`;
|
|
505
573
|
}
|
|
506
574
|
}
|
|
507
575
|
function finish(drop) {
|
|
508
576
|
const done = gesture;
|
|
509
577
|
gesture = null;
|
|
510
578
|
cancelAnimationFrame(scrolling);
|
|
579
|
+
edge.stop();
|
|
511
580
|
pointer = null;
|
|
512
581
|
const { card, board, file, target, kind } = done;
|
|
513
582
|
document.documentElement.removeAttribute("data-ge-dragging");
|
|
514
583
|
document.documentElement.removeAttribute("data-ge-sizing");
|
|
584
|
+
card.setAttribute("data-ge-landing", ""); // its lifted shadow eases out (and it stays over the others while it glides)
|
|
515
585
|
card.removeAttribute("data-ge-lifted");
|
|
516
586
|
card.removeAttribute("data-ge-sizing");
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
587
|
+
// Let go: it glides from where it is seen to its cells (dropped) or back to its own (Escape), over the
|
|
588
|
+
// others meanwhile, and they to theirs.
|
|
589
|
+
glide(cardsIn(board), () => {
|
|
590
|
+
card.style.translate = "";
|
|
591
|
+
card.style.width = "";
|
|
592
|
+
card.style.height = "";
|
|
593
|
+
dots.remove();
|
|
594
|
+
board.removeAttribute("data-ge-dotted");
|
|
595
|
+
if (drop && !cellsSame(target, file)) placeCard(card, target, { kind });
|
|
596
|
+
draft(board, null);
|
|
597
|
+
}, { lift: card, settled: placeAgain });
|
|
598
|
+
if (!isGliding(card)) setTimeout(() => { if (!isGliding(card)) card.removeAttribute("data-ge-landing"); }, 220);
|
|
523
599
|
trySwap();
|
|
524
600
|
hideSoon(); // the grip comes back where the pointer is
|
|
525
601
|
}
|
|
@@ -722,14 +798,26 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
722
798
|
say(t("连不上本地服务"), "error");
|
|
723
799
|
return false;
|
|
724
800
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
801
|
+
// A section of each pack (the user's word of 2026-11-09), its name over its blocks, in the service's order
|
|
802
|
+
// (the packs as 设置 › 组件列表 has them, each's blocks by name); what is typed keeps the sections it finds blocks in.
|
|
803
|
+
const rows = (text = "") => {
|
|
804
|
+
const items = [];
|
|
805
|
+
let pack;
|
|
806
|
+
for (const block of listed) {
|
|
807
|
+
const words = `${said(block.name)} ${said(block.description)} ${block.id}`.toLowerCase();
|
|
808
|
+
if (text.trim() && !words.includes(text.trim().toLowerCase())) continue;
|
|
809
|
+
if (block.pack?.id !== pack) {
|
|
810
|
+
pack = block.pack?.id;
|
|
811
|
+
if (pack) items.push({ title: said(block.pack.name) || pack });
|
|
812
|
+
}
|
|
813
|
+
items.push({
|
|
814
|
+
label: said(block.name) || block.id, icon: BLOCK, hint: block.installed ? `${block.size.w} × ${block.size.h}` : t("自带"),
|
|
815
|
+
...(block.preview || block.description ? { preview: block.preview ? { src: block.preview, says: said(block.description) } : { says: said(block.description) } } : {}),
|
|
816
|
+
run: () => addBlock(board, block),
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
return items;
|
|
820
|
+
};
|
|
733
821
|
button?.setAttribute("data-pressed", "");
|
|
734
822
|
const closed = () => menu.close();
|
|
735
823
|
if (!button) addEventListener("blur", closed);
|
|
@@ -773,7 +861,7 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
773
861
|
});
|
|
774
862
|
|
|
775
863
|
// ---------- 恢复默认卡片 ----------
|
|
776
|
-
// The
|
|
864
|
+
// The default cards a page with them misses put back (the service's restore-defaults), a task as every
|
|
777
865
|
// op is: one step of undo for all of them (a group of adds), the page shown again with their blocks'
|
|
778
866
|
// scripts and styles. Gives the service's answer ({ ok, added: [{ card, block, name }], skipped }),
|
|
779
867
|
// which the workbench says, or its refusal.
|
|
@@ -822,7 +910,7 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
822
910
|
const cards = step.cards.filter(({ id }) => cardById(id));
|
|
823
911
|
if (cards.length === 0) return false;
|
|
824
912
|
const to = way === "undo" ? "before" : "after";
|
|
825
|
-
for (const one of cards) setCells(cardById(one.id), one[to]);
|
|
913
|
+
layOut(cardById(cards[0].id).parentElement, () => { for (const one of cards) setCells(cardById(one.id), one[to]); });
|
|
826
914
|
const answer = await send({ op: "arrange", cards: cards.map((one) => ({ card: one.id, ...one[to], base: cardById(one.id).dataset.geBase })) });
|
|
827
915
|
if (!answer?.ok) return failed(answer) ?? false;
|
|
828
916
|
took(answer);
|
|
@@ -960,10 +1048,11 @@ export function startBoard({ map, reload, hosted = false }) {
|
|
|
960
1048
|
watch.observe(document.documentElement, { attributes: true, attributeFilter: ["data-doc-drawn"] });
|
|
961
1049
|
}
|
|
962
1050
|
}
|
|
963
|
-
// The
|
|
964
|
-
// 恢复默认卡片 puts them: restoreDefaults).
|
|
1051
|
+
// The page's first-open note, while its map says so, its note of new default cards (put in as
|
|
1052
|
+
// 恢复默认卡片 puts them: restoreDefaults), and the middle of a blank page (an Agent writes it).
|
|
965
1053
|
if (map.hint) showHint(map, { hosted });
|
|
966
1054
|
if (map.news) showNews(map, { restore: restoreDefaults });
|
|
1055
|
+
if (map.blank) showBlank(map);
|
|
967
1056
|
// Its blocks may write from now on (the kit's context.canEdit, editable).
|
|
968
1057
|
dispatchEvent(new Event("doc-editable"));
|
|
969
1058
|
return { swap: wantSwap, undo, redo, idle: () => Promise.all([client.idle(), todos.idle()]), restoreDefaults, undoRestore, addCard };
|