@panphora/clayjs 1.17.0 → 1.18.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/dist/all.js +1 -1
- package/dist/clay-dom.js +1 -1
- package/dist/clay-events.js +1 -1
- package/dist/clay-internals.js +1 -1
- package/dist/clay-options.js +1 -1
- package/dist/clay-router.js +1 -1
- package/dist/clay-ui.js +1 -1
- package/dist/clay-utils.js +1 -1
- package/dist/clay.js +1 -1
- package/dist/clay.standalone.js +72474 -62090
- package/dist/m/attrs/{save-freeze-MYNVXREN.js → save-freeze-LWGF6XUN.js} +1 -1
- package/dist/m/c-2GRUM77Q.js +30 -0
- package/dist/m/c-2KIEGNC4.js +1 -0
- package/dist/m/{c-AMSNPOCX.js → c-2KL3BD52.js} +1 -1
- package/dist/m/c-2ZZBC45O.js +1 -0
- package/dist/m/c-372N6H3B.js +1 -0
- package/dist/m/{c-4WKFKEKF.js → c-3G2DGZUP.js} +1 -1
- package/dist/m/c-3LDGIBMN.js +1 -0
- package/dist/m/c-3O7OBDCM.js +1 -0
- package/dist/m/c-4ASQPRQL.js +1 -0
- package/dist/m/c-4TXNLX4K.js +6 -0
- package/dist/m/c-4YU3BR4D.js +6 -0
- package/dist/m/c-5734MF2P.js +1 -0
- package/dist/m/c-57XDY6HC.js +1 -0
- package/dist/m/{c-KAU6E43D.js → c-5B4YBZXC.js} +1 -1
- package/dist/m/c-5ONTYIUI.js +1 -0
- package/dist/m/c-5OOVFCJM.js +1 -0
- package/dist/m/{c-3XIRD4NU.js → c-5T6NZHNM.js} +1 -1
- package/dist/m/{c-74MGYWZF.js → c-5ZQV7KC4.js} +1 -1
- package/dist/m/{c-7OLLJPWP.js → c-6DB2OLRJ.js} +1 -1
- package/dist/m/c-6DNRCPNM.js +1 -0
- package/dist/m/c-6UGWFMQC.js +2 -0
- package/dist/m/c-7K4SCQB7.js +1 -0
- package/dist/m/c-7MG5RU63.js +1 -0
- package/dist/m/c-7PRJCA3E.js +1 -0
- package/dist/m/c-A6L3FMUS.js +1 -0
- package/dist/m/c-AMU3BPPR.js +4 -0
- package/dist/m/{c-Y5HBBIQ4.js → c-AMYEFA2E.js} +1 -1
- package/dist/m/c-AQYCG7QW.js +1 -0
- package/dist/m/c-ATKAOH23.js +1 -0
- package/dist/m/c-B5CS55WR.js +1 -0
- package/dist/m/c-B5UJQT7W.js +1 -0
- package/dist/m/c-B7J4K2AE.js +3 -0
- package/dist/m/c-BHZYSHW4.js +1 -0
- package/dist/m/{c-VHM5XQHK.js → c-BIJALSRD.js} +1 -1
- package/dist/m/c-BJ7YQ5QZ.js +1 -0
- package/dist/m/{c-KIPQJX4B.js → c-BRLCTNMC.js} +1 -1
- package/dist/m/{c-VE6ZMYMC.js → c-BUAYFEV5.js} +1 -1
- package/dist/m/c-C6IPRG34.js +1 -0
- package/dist/m/{c-KU3ZFADW.js → c-CAS3NND4.js} +1 -1
- package/dist/m/{c-PS5ARVWR.js → c-CCQ25GFY.js} +1 -1
- package/dist/m/c-CJFDLD43.js +1 -0
- package/dist/m/c-COPTL5WB.js +1 -0
- package/dist/m/c-D3E4WJ4M.js +166 -0
- package/dist/m/c-D5IKEKXW.js +7 -0
- package/dist/m/c-DHBRA6DL.js +1 -0
- package/dist/m/c-DKLS74XB.js +72 -0
- package/dist/m/c-DVYGFTSK.js +3 -0
- package/dist/m/c-E3ZXARWA.js +1 -0
- package/dist/m/c-EK63G3CG.js +1 -0
- package/dist/m/c-ERQSNR6K.js +13 -0
- package/dist/m/c-EVYAISP3.js +1 -0
- package/dist/m/c-EXKHPOVC.js +3 -0
- package/dist/m/{c-QJ4OM3G6.js → c-FWKHM4E7.js} +1 -1
- package/dist/m/{c-4Q2XTQ2N.js → c-GBKB5WDL.js} +1 -1
- package/dist/m/c-GNDL3TKB.js +1 -0
- package/dist/m/c-GRWMD6O5.js +1 -0
- package/dist/m/c-GRXHHFPO.js +1 -0
- package/dist/m/c-HG2C77BM.js +4 -0
- package/dist/m/c-HHGJBU4D.js +1 -0
- package/dist/m/c-HMV6P4RX.js +1 -0
- package/dist/m/c-HMYWIHFG.js +1 -0
- package/dist/m/c-HT2DKBV2.js +1 -0
- package/dist/m/c-I2SCCUEW.js +1 -0
- package/dist/m/{c-TJ6WOJL3.js → c-ICJYHABF.js} +2 -2
- package/dist/m/c-IMZCWYHR.js +7 -0
- package/dist/m/c-IVMD3FEM.js +1 -0
- package/dist/m/{c-WDC5GVKU.js → c-IVTRVENZ.js} +1 -1
- package/dist/m/c-JKZJIUIP.js +1 -0
- package/dist/m/{c-UDUUJPFZ.js → c-JNLX3RJB.js} +1 -1
- package/dist/m/c-K3ADYNLU.js +1 -0
- package/dist/m/c-KGHVFRR3.js +1 -0
- package/dist/m/{c-5QWQ7A5L.js → c-KJJPV77R.js} +1 -1
- package/dist/m/{c-CZUSOB7V.js → c-KNPDOMDY.js} +1 -1
- package/dist/m/{c-EZU56NQV.js → c-KP64LT2A.js} +2 -2
- package/dist/m/c-KQ7E3PYY.js +1 -0
- package/dist/m/c-L3F5ZLIV.js +1 -0
- package/dist/m/{c-3RUU4TPX.js → c-L42OLXWM.js} +3 -2
- package/dist/m/c-L5VFATT6.js +1 -0
- package/dist/m/c-L7JL5TL3.js +3 -0
- package/dist/m/c-LKSL4AUJ.js +1 -0
- package/dist/m/c-M6FNQCTQ.js +1 -0
- package/dist/m/c-MCOOHCSG.js +1 -0
- package/dist/m/c-MHI3GYKF.js +1 -0
- package/dist/m/c-MWXFLW4J.js +1 -0
- package/dist/m/{c-5RJFTLSF.js → c-NEL7HQW3.js} +1 -1
- package/dist/m/{c-DCXOXBF3.js → c-NQJRVJ56.js} +1 -1
- package/dist/m/c-NWX3MFT4.js +1 -0
- package/dist/m/{c-HPURYVZS.js → c-OJYM642Q.js} +1 -1
- package/dist/m/c-OKXI52N7.js +1 -0
- package/dist/m/{c-R3L7ZJGB.js → c-OPLUZR3A.js} +1 -1
- package/dist/m/{c-GSFIGKOP.js → c-OTMKN2OO.js} +1 -1
- package/dist/m/{c-6NC5I2TV.js → c-OYRZ7XG2.js} +1 -1
- package/dist/m/{c-EVCQ3BKA.js → c-P3OFYUMA.js} +1 -1
- package/dist/m/c-PLN76GF3.js +6 -0
- package/dist/m/c-PLP4JKFC.js +1 -0
- package/dist/m/c-Q26MME6N.js +1 -0
- package/dist/m/{c-S7H2DRCB.js → c-Q3XOWZEV.js} +1 -1
- package/dist/m/{c-FRLHSY7E.js → c-QIKT6SKM.js} +1 -1
- package/dist/m/c-QIXT3Q7C.js +28 -0
- package/dist/m/c-QO4HNGCQ.js +1 -0
- package/dist/m/{c-JU3NK25H.js → c-R27DWQKX.js} +1 -1
- package/dist/m/{c-RSMOODDU.js → c-R2XUODVY.js} +1 -1
- package/dist/m/{c-QNKREOL6.js → c-R7LBFMF5.js} +1 -1
- package/dist/m/c-RND3G2S2.js +1 -0
- package/dist/m/{c-Q622NS2Y.js → c-S2U6NJU4.js} +1 -1
- package/dist/m/c-SPZPGD3R.js +1 -0
- package/dist/m/c-SW4YEG2D.js +8 -0
- package/dist/m/c-T637T7SN.js +1 -0
- package/dist/m/c-TJAXGIRV.js +1 -0
- package/dist/m/{c-RYUXUUBX.js → c-TNEM3RNM.js} +1 -1
- package/dist/m/c-TTB5EK4S.js +32 -0
- package/dist/m/c-U7SHNWDH.js +1 -0
- package/dist/m/c-UDHIVLYH.js +20 -0
- package/dist/m/{c-BBVGTQG7.js → c-UGNV5MFB.js} +1 -1
- package/dist/m/{c-QICP2YR5.js → c-UORXLSD3.js} +1 -1
- package/dist/m/c-UPD33ZPE.js +1 -0
- package/dist/m/c-URSMSFCB.js +1 -0
- package/dist/m/c-UY4QX42B.js +1 -0
- package/dist/m/c-V44KWI2L.js +4 -0
- package/dist/m/c-VILENZTD.js +1 -0
- package/dist/m/{c-HDDEEL77.js → c-VJYEVRYK.js} +1 -1
- package/dist/m/{c-SMBZG5X4.js → c-VR2BJ4AN.js} +1 -1
- package/dist/m/c-W4JCVLAB.js +1 -0
- package/dist/m/c-W6DQSHXI.js +135 -0
- package/dist/m/c-WBGWGOM7.js +1 -0
- package/dist/m/{c-4L3BTFRK.js → c-WCXLG3MV.js} +1 -1
- package/dist/m/c-WGW764WX.js +1 -0
- package/dist/m/c-WMRJKQ2V.js +5 -0
- package/dist/m/c-WNTYKCDG.js +1 -0
- package/dist/m/c-WQWIRWO3.js +72 -0
- package/dist/m/c-X5LNHET5.js +1 -0
- package/dist/m/{c-I2ZATQCD.js → c-X5TSXZYJ.js} +2 -2
- package/dist/m/c-XGH4GS2T.js +1 -0
- package/dist/m/c-Y6F2FORL.js +1 -0
- package/dist/m/c-YBKHUAK7.js +10 -0
- package/dist/m/c-YBSS55KU.js +20 -0
- package/dist/m/c-YCLU4UNT.js +2 -0
- package/dist/m/c-YVZ2L7CE.js +1 -0
- package/dist/m/c-ZK4GIZH2.js +1 -0
- package/dist/m/c-ZRXJD4G6.js +1 -0
- package/dist/m/c-ZWBI4HYK.js +1 -0
- package/dist/m/core/{admin-attrs-QHOKPJ7W.js → admin-attrs-YY7T5FGU.js} +1 -1
- package/dist/m/core/autosave-S6OMNDCK.js +1 -0
- package/dist/m/core/conflict-notice-IWHMHH43.js +1 -0
- package/dist/m/core/{host-permission-FNXVEFNE.js → host-permission-6EVJGNPL.js} +1 -1
- package/dist/m/core/is-edit-mode-GCX6767E.js +1 -0
- package/dist/m/core/{persist-JFYRHMRJ.js → persist-UKXV5KLA.js} +1 -1
- package/dist/m/core/recovery-DRFZRJED.js +1 -0
- package/dist/m/core/save-LYY7K6U7.js +1 -0
- package/dist/m/core/save-core-MKRPSEEO.js +1 -0
- package/dist/m/core/snapshot-NU3YM6GR.js +1 -0
- package/dist/m/core/unsaved-warning-7QTKEN7Z.js +1 -0
- package/dist/m/internals/{index-PVXGPUDA.js → index-TGLQINN3.js} +1 -1
- package/dist/m/loader-3BBNZZGM.js +1 -0
- package/dist/m/manifest-26C55578.js +1 -0
- package/dist/m/manifest-edit-4396A009.js +1 -0
- package/dist/m/manifest.json +2111 -1573
- package/dist/m/page/{editor-NNJA4OKD.js → editor-6LRB3GE4.js} +123 -21
- package/dist/m/plugins/ai-edit-UTV7YO2I.js +6 -0
- package/dist/m/plugins/{cms-HP3LSTPN.js → cms-LRAOZHT7.js} +9 -9
- package/dist/m/plugins/{demo-RM5IR6AO.js → demo-OYO5GCAO.js} +1 -1
- package/dist/m/plugins/{derive-UAAA4V4S.js → derive-FRE5JJQE.js} +1 -1
- package/dist/m/plugins/indicator-4VDXWYTD.js +1 -0
- package/dist/m/plugins/live-AD4H6XSL.js +1 -0
- package/dist/m/plugins/menu-M5WW7DBF.js +1 -0
- package/dist/m/plugins/page-MD3T2ZX3.js +2 -0
- package/dist/m/plugins/page-view-PAWVZNFY.js +1 -0
- package/dist/m/plugins/{people-SGPJKANK.js → people-JCHVPF7P.js} +1 -1
- package/dist/m/plugins/quickcrop-BQ5YYFCH.js +26 -0
- package/dist/m/plugins/{richclay-NRQDSWX6.js → richclay-KLGETK77.js} +2 -2
- package/dist/m/plugins/sortable-4S6SQC3D.js +1 -0
- package/dist/m/plugins/source-TJXOIOYY.js +1 -0
- package/dist/m/plugins/undo-NLPGCJQY.js +1 -0
- package/dist/m/plugins/{unsent-HJFLQJ2O.js → unsent-OA4RGBUT.js} +1 -1
- package/dist/m/plugins/upgrade-HSUNDNJD.js +1 -0
- package/dist/m/plugins/{upload-WLYKK6TL.js → upload-NHGJXZK2.js} +1 -1
- package/dist/m/plugins/visitor-drafts-BW43DGY3.js +20 -0
- package/dist/m/plugins/visitor-drafts-owner-7ODQG7JX.js +1 -0
- package/dist/m/plugins/{wire-4N6GYAF6.js → wire-VBWXEXU2.js} +1 -1
- package/dist/m/reader-core-4W2KYEWQ.js +77 -0
- package/dist/m/route/route-62CHXL5B.js +1 -0
- package/dist/m/sync/live-sync-MO5DH33W.js +1 -0
- package/dist/m/ui/index-IVWN2QC4.js +1 -0
- package/dist/m/vendor/sap-core.vendor-RN4ZVY4X.js +6 -0
- package/dist/offline-manifest.json +1367 -930
- package/dist/page/themes/light-1.css +8 -7
- package/dist/server/core.cjs +1440 -288
- package/dist/server/offline-runtime.cjs +63 -63
- package/dist/server/offline-runtime.mjs +63 -63
- package/dist/server/page-compaction-worker.cjs +3710 -0
- package/dist/server/rooms.mjs +5 -0
- package/docs/guide.md +653 -101
- package/entries/sap.js +5 -5
- package/package.json +1 -1
- package/src/core/admin-contenteditable.js +5 -2
- package/src/core/admin-inputs.js +1 -0
- package/src/core/admin-onclick.js +2 -1
- package/src/core/conflict-notice-ui.js +4 -7
- package/src/core/download.js +2 -2
- package/src/core/host-meta.js +38 -0
- package/src/core/is-edit-mode.js +17 -1
- package/src/core/mode-key.js +125 -19
- package/src/core/mode-support.js +5 -0
- package/src/core/mode-transition.js +20 -6
- package/src/core/preserve-authored.js +4 -4
- package/src/core/recovery.js +121 -33
- package/src/core/save-accepted.js +33 -0
- package/src/core/save-core.js +106 -31
- package/src/core/save-job.js +108 -0
- package/src/core/save-prepare.js +53 -0
- package/src/core/save-size-notice.js +3 -1
- package/src/core/save-slices.js +15 -0
- package/src/core/save.js +557 -127
- package/src/core/serialize-steps.js +109 -0
- package/src/core/snapshot.js +170 -39
- package/src/core/source-map.js +83 -38
- package/src/core/stale-host-notice.js +1 -0
- package/src/core/upgrade-run.js +59 -8
- package/src/dom/active-element.js +5 -0
- package/src/lib/assets.js +1 -0
- package/src/lib/slice.js +65 -0
- package/src/lib/uimotion.js +774 -0
- package/src/lib/unsaved-state.js +2 -2
- package/src/live/fast-lane.js +10 -3
- package/src/live/local-lane.js +202 -11
- package/src/live/ops.js +16 -0
- package/src/live/page-compaction.js +162 -0
- package/src/live/server-lane.js +1 -0
- package/src/live/store.js +11 -3
- package/src/loader-logic.js +3 -1
- package/src/loader.js +14 -4
- package/src/page/adopt-boot.js +2 -1
- package/src/page/awareness.js +33 -2
- package/src/page/blocks.js +89 -27
- package/src/page/boot-pack.js +1 -1
- package/src/page/chart-tables.js +21 -3
- package/src/page/chart.js +406 -63
- package/src/page/checklist.js +10 -135
- package/src/page/checkpoint-proof.js +7 -1
- package/src/page/chrome.js +250 -51
- package/src/page/clipboard-shape.js +126 -0
- package/src/page/drag.js +33 -3
- package/src/page/editor.js +136 -25
- package/src/page/export-assets.js +357 -0
- package/src/page/export-html.js +209 -0
- package/src/page/export-markdown.js +361 -0
- package/src/page/features/checklist.js +428 -0
- package/src/page/features/export-html.js +189 -0
- package/src/page/features/export-markdown.js +169 -0
- package/src/page/features/import-markdown.js +349 -0
- package/src/page/features/media.js +61 -5
- package/src/page/features/registry.js +18 -0
- package/src/page/features/table.js +373 -83
- package/src/page/features/title-cover.js +331 -0
- package/src/page/features/title-icon.js +213 -0
- package/src/page/features/toc.js +87 -0
- package/src/page/format-command.js +25 -1
- package/src/page/format-gate.js +68 -18
- package/src/page/format-host.js +17 -0
- package/src/page/format-native-commands.js +21 -5
- package/src/page/image-actions.js +64 -0
- package/src/page/import-markdown.js +262 -0
- package/src/page/items.js +135 -17
- package/src/page/markdown.js +6 -2
- package/src/page/media.js +35 -119
- package/src/page/placeholder.js +14 -1
- package/src/page/projection.js +98 -10
- package/src/page/recover.js +10 -12
- package/src/page/recovery-ui.js +464 -0
- package/src/page/rich/chart.js +63 -7
- package/src/page/save-projection.js +28 -0
- package/src/page/save-states.js +13 -3
- package/src/page/schema.js +19 -3
- package/src/page/table-paste.js +3 -1
- package/src/page/table-style.js +4 -4
- package/src/page/table.js +44 -2
- package/src/page/themes/light-1.css +8 -7
- package/src/page/themes/light-1.source.css +8 -7
- package/src/page/toc-link.js +31 -0
- package/src/page/toc.js +5 -0
- package/src/page/view-hooks.js +38 -12
- package/src/page/view.js +13 -0
- package/src/page/ybind/binding.js +88 -5
- package/src/page/ybind/bridge.js +187 -20
- package/src/page/ybind/containment.js +162 -0
- package/src/page/ybind/doc.js +17 -9
- package/src/page/ybind/file-debt.js +63 -0
- package/src/page/ybind/layout.js +7 -2
- package/src/page/ybind/marks.js +1 -1
- package/src/page/ybind/moves.js +5 -4
- package/src/page/ybind/origins.js +106 -4
- package/src/page/ybind/parts.js +8 -1
- package/src/page/ybind/provider.js +113 -17
- package/src/page/ybind/recovery-proof.js +32 -9
- package/src/page/ybind/recovery-replay.js +558 -15
- package/src/page/ybind/recovery.js +174 -45
- package/src/page/ybind/table.js +67 -11
- package/src/page/ybind/walk-delta.js +258 -0
- package/src/page/ybind/walk.js +54 -29
- package/src/page/ybind/writer.js +1 -1
- package/src/plugins/ai-edit.js +13 -9
- package/src/plugins/indicator-chip.js +91 -0
- package/src/plugins/indicator.js +13 -80
- package/src/plugins/live.js +89 -14
- package/src/plugins/menu/actions.js +196 -0
- package/src/plugins/menu/people.js +279 -0
- package/src/plugins/menu/placement.js +121 -0
- package/src/plugins/menu/preferences.js +9 -0
- package/src/plugins/menu/seo.js +316 -397
- package/src/plugins/menu/style.js +171 -0
- package/src/plugins/menu/variants.js +296 -0
- package/src/plugins/menu.js +186 -183
- package/src/plugins/page-view.js +3 -2
- package/src/plugins/page.js +249 -44
- package/src/plugins/sortable.js +8 -1
- package/src/plugins/source.js +6 -0
- package/src/plugins/upgrade.js +51 -17
- package/src/plugins/upload-ui.js +12 -17
- package/src/plugins/visitor-drafts/bottom-ui.js +12 -4
- package/src/plugins/visitor-drafts/intro-style.js +7 -2
- package/src/plugins/visitor-drafts/intro.js +5 -3
- package/src/plugins/visitor-drafts/owner-chip.js +8 -12
- package/src/plugins/visitor-drafts/prompt.js +11 -9
- package/src/plugins/visitor-drafts/source.js +4 -3
- package/src/plugins/visitor-drafts/store.js +138 -9
- package/src/plugins/visitor-drafts/ui-memory.js +2 -2
- package/src/plugins/visitor-drafts-owner.js +4 -6
- package/src/plugins/visitor-drafts.js +5 -3
- package/src/recovery/store.js +1 -1
- package/src/route/route.js +4 -0
- package/src/server/rooms/index.js +5 -1
- package/src/server/rooms/live-data-rooms.js +302 -50
- package/src/server/rooms/page-compaction-worker.js +12 -0
- package/src/server/rooms/page-compactor.js +92 -0
- package/src/server/rooms/page-room-conformance.js +461 -0
- package/src/source/parse-steps.js +94 -0
- package/src/source/session.js +233 -57
- package/src/sync/editing-sender.js +12 -0
- package/src/sync/live-sync-edit.js +22 -2
- package/src/sync/live-sync.js +150 -23
- package/src/sync/page-relay.js +52 -0
- package/src/sync/presence-store.js +44 -4
- package/src/sync/presence.js +6 -3
- package/src/sync/saved-stream.js +11 -6
- package/src/ui/bevel-controls.js +1 -0
- package/src/ui/bevel-dialog.js +5 -2
- package/src/ui/editor-ui.js +77 -0
- package/src/ui/page-colour.js +281 -0
- package/src/ui/toast.js +16 -7
- package/src/vendor/hyper-html-api-upgrade.vendor.js +2 -2
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +9 -9
- package/src/vendor/parse5.vendor.js +2 -2
- package/src/vendor/sap-core.vendor.js +5 -5
- package/dist/m/c-2SPVQSHC.js +0 -1
- package/dist/m/c-336SGU5W.js +0 -1
- package/dist/m/c-3H6BZDNJ.js +0 -6
- package/dist/m/c-4DFEJ2PO.js +0 -3
- package/dist/m/c-56QRZTZH.js +0 -1
- package/dist/m/c-5J4E7O4Y.js +0 -4
- package/dist/m/c-5LKDWQTL.js +0 -19
- package/dist/m/c-5V3MOVJT.js +0 -1
- package/dist/m/c-6AZOGAPE.js +0 -1
- package/dist/m/c-6CRUUXOX.js +0 -5
- package/dist/m/c-6HMB24EV.js +0 -1
- package/dist/m/c-6KEVEQ7L.js +0 -1
- package/dist/m/c-A3E3NIMC.js +0 -1
- package/dist/m/c-BQ6LOBEE.js +0 -1
- package/dist/m/c-BTDI4Y23.js +0 -1
- package/dist/m/c-CJ3A7ZKE.js +0 -1
- package/dist/m/c-CQHPGKX2.js +0 -1
- package/dist/m/c-DFS4XZJV.js +0 -2
- package/dist/m/c-DNENWY4O.js +0 -1
- package/dist/m/c-E4LIR5X5.js +0 -1
- package/dist/m/c-FDNHHZY5.js +0 -1
- package/dist/m/c-FROJUZMV.js +0 -1
- package/dist/m/c-G2JPKCTP.js +0 -1
- package/dist/m/c-GB6TU7WV.js +0 -1
- package/dist/m/c-GFJJEBTU.js +0 -1
- package/dist/m/c-GJAEGGXY.js +0 -1
- package/dist/m/c-GOWBDM6J.js +0 -1
- package/dist/m/c-HFKUVACH.js +0 -1
- package/dist/m/c-HHDFCNHV.js +0 -1
- package/dist/m/c-IEM4NTCS.js +0 -1
- package/dist/m/c-JDCX26UP.js +0 -25
- package/dist/m/c-KGVGROZT.js +0 -1
- package/dist/m/c-KQ6TYJAP.js +0 -135
- package/dist/m/c-LFPHCXY3.js +0 -1
- package/dist/m/c-LRPUO2MX.js +0 -1
- package/dist/m/c-LWLBHLVC.js +0 -3
- package/dist/m/c-M2L47S2X.js +0 -7
- package/dist/m/c-MFP2ZWD4.js +0 -1
- package/dist/m/c-MKSQ4Y57.js +0 -1
- package/dist/m/c-NUFFJVVJ.js +0 -1
- package/dist/m/c-NUHSPT5P.js +0 -1
- package/dist/m/c-O72HVYSA.js +0 -1
- package/dist/m/c-OIBUTDXI.js +0 -1
- package/dist/m/c-OW5QIGG3.js +0 -1
- package/dist/m/c-PGRCK73F.js +0 -1
- package/dist/m/c-Q7NQD65V.js +0 -1
- package/dist/m/c-QH63LQOS.js +0 -1
- package/dist/m/c-R7IWVINQ.js +0 -1
- package/dist/m/c-RM7J7BV2.js +0 -1
- package/dist/m/c-S4ZEH46B.js +0 -9
- package/dist/m/c-SDAXDM2D.js +0 -1
- package/dist/m/c-SMGU7RT3.js +0 -235
- package/dist/m/c-SPIORRYS.js +0 -1
- package/dist/m/c-SWLRT66R.js +0 -1
- package/dist/m/c-TCJTVAFN.js +0 -1
- package/dist/m/c-TQEMVJCS.js +0 -1
- package/dist/m/c-TYLXX4NF.js +0 -21
- package/dist/m/c-U62OB4BT.js +0 -1
- package/dist/m/c-U6YWUAR3.js +0 -8
- package/dist/m/c-UDCSU5G5.js +0 -2
- package/dist/m/c-VI5RMSVY.js +0 -1
- package/dist/m/c-VRZN56XY.js +0 -1
- package/dist/m/c-W5MCHEGA.js +0 -1
- package/dist/m/c-WNYBLIOZ.js +0 -1
- package/dist/m/c-WWXIDH4O.js +0 -28
- package/dist/m/c-XCNTK76U.js +0 -1
- package/dist/m/c-XMS6DPBR.js +0 -1
- package/dist/m/c-ZUCOKOHT.js +0 -1
- package/dist/m/c-ZVPVXTJF.js +0 -4
- package/dist/m/c-ZVRKXKM7.js +0 -1
- package/dist/m/core/autosave-HRYGUWV6.js +0 -1
- package/dist/m/core/conflict-notice-6MROJN2L.js +0 -1
- package/dist/m/core/is-edit-mode-KTWA3O5N.js +0 -1
- package/dist/m/core/recovery-FLTCC2OC.js +0 -1
- package/dist/m/core/save-HQZ4S667.js +0 -1
- package/dist/m/core/save-core-KGQWFUNH.js +0 -1
- package/dist/m/core/snapshot-EGQZNT45.js +0 -1
- package/dist/m/core/unsaved-warning-IDJLD66H.js +0 -1
- package/dist/m/loader-S4I7GKXR.js +0 -1
- package/dist/m/manifest-4C419D67.js +0 -1
- package/dist/m/manifest-edit-B077F288.js +0 -1
- package/dist/m/plugins/ai-edit-QN4PMMNL.js +0 -6
- package/dist/m/plugins/indicator-URDBBOQO.js +0 -1
- package/dist/m/plugins/live-HFWD4OIH.js +0 -1
- package/dist/m/plugins/menu-3HIEQSI6.js +0 -138
- package/dist/m/plugins/page-JOKB6XPR.js +0 -2
- package/dist/m/plugins/page-view-NXOJHNW6.js +0 -1
- package/dist/m/plugins/quickcrop-QNY3PKLD.js +0 -26
- package/dist/m/plugins/sortable-GWT4PWDV.js +0 -1
- package/dist/m/plugins/source-4ZRSAIYM.js +0 -1
- package/dist/m/plugins/undo-VDA5P7FH.js +0 -1
- package/dist/m/plugins/upgrade-W7FG5VFG.js +0 -1
- package/dist/m/plugins/visitor-drafts-LIDY7NH6.js +0 -21
- package/dist/m/plugins/visitor-drafts-owner-ZXCKBZE7.js +0 -1
- package/dist/m/reader-core-DXYCURFF.js +0 -68
- package/dist/m/route/route-KOCZSEGN.js +0 -1
- package/dist/m/sync/live-sync-J7VMYTKS.js +0 -1
- package/dist/m/ui/index-3JLVI27O.js +0 -1
- package/dist/m/vendor/sap-core.vendor-A7BMUYZT.js +0 -6
- /package/dist/m/{c-FILLTJA7.js → c-QTTJYJMA.js} +0 -0
- /package/dist/m/plugins/{quickcrop-QNY3PKLD.js.LEGAL.txt → quickcrop-BQ5YYFCH.js.LEGAL.txt} +0 -0
- /package/dist/m/plugins/{richclay-NRQDSWX6.js.LEGAL.txt → richclay-KLGETK77.js.LEGAL.txt} +0 -0
package/src/plugins/menu/seo.js
CHANGED
|
@@ -3,288 +3,117 @@
|
|
|
3
3
|
// the saved file, a sync frame, the dirty check or undo. Nothing is written until
|
|
4
4
|
// Apply: opening and cancelling change only the sheet.
|
|
5
5
|
import { applyHead, FIELDS, readHead } from "./seo-head.js";
|
|
6
|
+
import { lookAt } from "../../ui/page-colour.js";
|
|
7
|
+
import MENU_CSS, { MENU_SURFACE } from "./style.js";
|
|
8
|
+
import { mountEditorUI } from "../../ui/editor-ui.js";
|
|
9
|
+
import { deepActiveElement } from "../../dom/active-element.js";
|
|
6
10
|
import { hostMeta } from "../../core/host-meta.js";
|
|
7
11
|
import { documentTitle } from "../../page/document-title.js";
|
|
8
12
|
import { registerUnsavedState } from "../../lib/unsaved-state.js";
|
|
9
13
|
import { modeRefusalText } from "../../core/mode-refusal.js";
|
|
14
|
+
import { dismissPersistent, toastPersistent } from "../../ui/toast-lazy.js";
|
|
10
15
|
|
|
11
|
-
const STYLE_ID = "clay-seo-style";
|
|
12
16
|
const REOPEN_KEY = "reopen-seo";
|
|
13
|
-
const LABEL = "SEO
|
|
17
|
+
const LABEL = "SEO and social sharing";
|
|
18
|
+
const UNDO_LABEL = "SEO settings";
|
|
19
|
+
const APPLIED_TEXT = "SEO settings applied";
|
|
14
20
|
const SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
15
21
|
const ROBOTS_NOTE =
|
|
16
22
|
"This site is hidden from search engines in your account settings, so this page stays hidden whatever you choose here.";
|
|
17
23
|
const PUBLIC_NOTE = "Uploaded images are public to anyone with the link.";
|
|
18
24
|
const PASTE_NOTE = "Paste the address of an image on the web.";
|
|
19
25
|
|
|
20
|
-
const
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
.clay-seo-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
.clay-seo-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
.clay-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
font-size:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
.clay-seo-
|
|
105
|
-
.clay-seo-
|
|
106
|
-
.clay-seo-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
border: 1px solid rgba(23, 28, 36, .16);
|
|
112
|
-
border-radius: 8px;
|
|
113
|
-
}
|
|
114
|
-
.clay-seo-preview-image {
|
|
115
|
-
flex: none;
|
|
116
|
-
width: 88px;
|
|
117
|
-
height: 62px;
|
|
118
|
-
border-radius: 6px;
|
|
119
|
-
object-fit: cover;
|
|
120
|
-
}
|
|
121
|
-
.clay-seo-preview-text { min-width: 0; }
|
|
122
|
-
.clay-seo-preview-title {
|
|
123
|
-
margin: 0;
|
|
124
|
-
font-weight: 600;
|
|
125
|
-
overflow: hidden;
|
|
126
|
-
text-overflow: ellipsis;
|
|
127
|
-
white-space: nowrap;
|
|
128
|
-
}
|
|
129
|
-
.clay-seo-preview-description,
|
|
130
|
-
.clay-seo-preview-host {
|
|
131
|
-
margin: 2px 0 0;
|
|
132
|
-
font-size: 12px;
|
|
133
|
-
opacity: .8;
|
|
134
|
-
}
|
|
135
|
-
.clay-seo-group {
|
|
136
|
-
margin: 0 0 14px;
|
|
137
|
-
padding: 0;
|
|
138
|
-
border: 0;
|
|
139
|
-
}
|
|
140
|
-
.clay-seo-legend {
|
|
141
|
-
padding: 0;
|
|
142
|
-
margin-bottom: 6px;
|
|
143
|
-
font-size: 12px;
|
|
144
|
-
font-weight: 600;
|
|
145
|
-
letter-spacing: .04em;
|
|
146
|
-
text-transform: uppercase;
|
|
147
|
-
opacity: .7;
|
|
148
|
-
}
|
|
149
|
-
.clay-seo-row {
|
|
150
|
-
display: block;
|
|
151
|
-
margin-bottom: 8px;
|
|
152
|
-
}
|
|
153
|
-
.clay-seo-caption {
|
|
154
|
-
display: block;
|
|
155
|
-
margin-bottom: 4px;
|
|
156
|
-
font-size: 12px;
|
|
157
|
-
opacity: .8;
|
|
158
|
-
}
|
|
159
|
-
.clay-seo-row-check {
|
|
160
|
-
display: flex;
|
|
161
|
-
align-items: center;
|
|
162
|
-
gap: 8px;
|
|
163
|
-
}
|
|
164
|
-
.clay-seo-row-check .clay-seo-caption { margin-bottom: 0; }
|
|
165
|
-
.clay-seo-input {
|
|
166
|
-
box-sizing: border-box;
|
|
167
|
-
width: 100%;
|
|
168
|
-
margin: 0;
|
|
169
|
-
padding: 7px 9px;
|
|
170
|
-
border: 1px solid rgba(23, 28, 36, .24);
|
|
171
|
-
border-radius: 6px;
|
|
172
|
-
font: inherit;
|
|
173
|
-
color: inherit;
|
|
174
|
-
background: rgba(250, 251, 252, .7);
|
|
175
|
-
}
|
|
176
|
-
.clay-seo-input:focus-visible { outline: 2px solid var(--clay-ui-accent, #2F6FEB); outline-offset: 1px; }
|
|
177
|
-
textarea.clay-seo-input { min-height: 64px; resize: vertical; }
|
|
178
|
-
.clay-seo-note {
|
|
179
|
-
margin: 4px 0 0;
|
|
180
|
-
font-size: 12px;
|
|
181
|
-
opacity: .8;
|
|
182
|
-
}
|
|
183
|
-
.clay-seo-error {
|
|
184
|
-
margin: 4px 0 0;
|
|
185
|
-
font-size: 12px;
|
|
186
|
-
color: #A63A2B;
|
|
187
|
-
}
|
|
188
|
-
.clay-seo-derived {
|
|
189
|
-
margin: 4px 0 0;
|
|
190
|
-
padding: 0;
|
|
191
|
-
border: 0;
|
|
192
|
-
font: inherit;
|
|
193
|
-
font-size: 12px;
|
|
194
|
-
color: var(--clay-ui-accent, #2F6FEB);
|
|
195
|
-
background: none;
|
|
196
|
-
text-decoration: underline;
|
|
197
|
-
cursor: pointer;
|
|
198
|
-
}
|
|
199
|
-
.clay-seo-conflict {
|
|
200
|
-
margin: 6px 0 0;
|
|
201
|
-
padding: 8px;
|
|
202
|
-
border: 1px solid rgba(23, 28, 36, .16);
|
|
203
|
-
border-radius: 6px;
|
|
204
|
-
font-size: 12px;
|
|
205
|
-
}
|
|
206
|
-
.clay-seo-conflict p { margin: 0 0 6px; }
|
|
207
|
-
.clay-seo-upload {
|
|
208
|
-
display: flex;
|
|
209
|
-
flex-wrap: wrap;
|
|
210
|
-
align-items: center;
|
|
211
|
-
gap: 8px;
|
|
212
|
-
margin: 4px 0 8px;
|
|
213
|
-
}
|
|
214
|
-
.clay-seo-upload .clay-seo-note { flex: 1 1 100%; margin: 0; }
|
|
215
|
-
.clay-seo-actions {
|
|
216
|
-
display: flex;
|
|
217
|
-
justify-content: flex-end;
|
|
218
|
-
gap: 8px;
|
|
219
|
-
margin-top: 12px;
|
|
220
|
-
}
|
|
221
|
-
.clay-seo-actions button {
|
|
222
|
-
padding: 8px 14px;
|
|
223
|
-
border: 1px solid rgba(23, 28, 36, .24);
|
|
224
|
-
border-radius: 6px;
|
|
225
|
-
font: inherit;
|
|
226
|
-
color: inherit;
|
|
227
|
-
background: none;
|
|
228
|
-
cursor: pointer;
|
|
229
|
-
}
|
|
230
|
-
.clay-seo-actions button:hover,
|
|
231
|
-
.clay-seo-actions button:focus-visible { outline: none; background: rgba(23, 28, 36, .08); }
|
|
232
|
-
.clay-seo-apply,
|
|
233
|
-
.clay-seo-edit {
|
|
234
|
-
border-color: transparent;
|
|
235
|
-
color: #F7F8FA;
|
|
236
|
-
background: var(--clay-ui-accent, #2F6FEB);
|
|
237
|
-
}
|
|
238
|
-
.clay-seo-actions .clay-seo-apply:hover,
|
|
239
|
-
.clay-seo-actions .clay-seo-apply:focus-visible,
|
|
240
|
-
.clay-seo-actions .clay-seo-edit:hover,
|
|
241
|
-
.clay-seo-actions .clay-seo-edit:focus-visible { background: var(--clay-ui-accent, #2F6FEB); opacity: .9; }
|
|
242
|
-
.clay-seo-upload-button {
|
|
243
|
-
padding: 6px 10px;
|
|
244
|
-
border: 1px solid rgba(23, 28, 36, .24);
|
|
245
|
-
border-radius: 6px;
|
|
246
|
-
font: inherit;
|
|
247
|
-
font-size: 12px;
|
|
248
|
-
color: inherit;
|
|
249
|
-
background: none;
|
|
250
|
-
cursor: pointer;
|
|
251
|
-
}
|
|
252
|
-
@media (min-width: 600px) {
|
|
253
|
-
.clay-seo {
|
|
254
|
-
width: 560px;
|
|
255
|
-
margin: 0 auto;
|
|
256
|
-
padding: 16px;
|
|
257
|
-
border: 1px solid rgba(23, 28, 36, .16);
|
|
258
|
-
border-top: 0;
|
|
259
|
-
border-radius: 0 0 12px 12px;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
@media (pointer: coarse) {
|
|
263
|
-
.clay-seo-actions button,
|
|
264
|
-
.clay-seo-upload-button { min-height: 44px; }
|
|
265
|
-
}
|
|
266
|
-
@media (prefers-color-scheme: dark) {
|
|
267
|
-
.clay-seo {
|
|
268
|
-
color: var(--clay-ui-fg, #E9E9EC);
|
|
269
|
-
background: var(--clay-ui-bg, #26282C);
|
|
270
|
-
border-color: rgba(233, 233, 236, .16);
|
|
271
|
-
}
|
|
272
|
-
.clay-seo-preview { border-color: rgba(233, 233, 236, .16); }
|
|
273
|
-
.clay-seo-input {
|
|
274
|
-
border-color: rgba(233, 233, 236, .16);
|
|
275
|
-
background: rgba(233, 233, 236, .08);
|
|
276
|
-
}
|
|
277
|
-
.clay-seo-x:hover,
|
|
278
|
-
.clay-seo-x:focus-visible,
|
|
279
|
-
.clay-seo-actions button:hover,
|
|
280
|
-
.clay-seo-actions button:focus-visible { background: rgba(233, 233, 236, .12); }
|
|
281
|
-
.clay-seo-actions button { border-color: rgba(233, 233, 236, .24); }
|
|
282
|
-
.clay-seo-conflict { border-color: rgba(233, 233, 236, .16); }
|
|
283
|
-
.clay-seo-error { color: #F0A192; }
|
|
284
|
-
}
|
|
285
|
-
@media (prefers-reduced-motion: reduce) {
|
|
286
|
-
.clay-seo { animation: none; }
|
|
287
|
-
}`;
|
|
26
|
+
const FIELD = {
|
|
27
|
+
title: { label: "Title", kind: "text", full: true, count: 60 },
|
|
28
|
+
description: { label: "Description", kind: "textarea", full: true, count: 160 },
|
|
29
|
+
ogTitle: { label: "Preview title", note: "Open Graph", kind: "text" },
|
|
30
|
+
ogDescription: { label: "Preview description", note: "Open Graph", kind: "textarea", short: true },
|
|
31
|
+
ogImage: { label: "Preview image", note: "Open Graph", kind: "text", full: true },
|
|
32
|
+
canonical: { label: "Canonical URL", kind: "text" },
|
|
33
|
+
lang: { label: "Language", kind: "text" },
|
|
34
|
+
ogImageAlt: { label: "Image alt text", kind: "text" },
|
|
35
|
+
siteName: { label: "Site name", kind: "text" },
|
|
36
|
+
twitterSite: { label: "Social handle", kind: "text", placeholder: "@yourname" },
|
|
37
|
+
index: { label: "Show in search results", kind: "checkbox" },
|
|
38
|
+
follow: { label: "Let search engines follow links", kind: "checkbox" },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const BASE_KEYS = ["title", "description", "ogTitle", "ogDescription", "ogImage"];
|
|
42
|
+
const MORE_KEYS = ["canonical", "lang", "ogImageAlt", "siteName", "twitterSite"];
|
|
43
|
+
const CHECK_KEYS = ["index", "follow"];
|
|
44
|
+
|
|
45
|
+
const SHEET_CSS = `.clay-seo { box-sizing: border-box; width: 100%; border-bottom: 1px solid var(--bevel-line-3); background: var(--bevel-surface); box-shadow: var(--clay-sheet-shadow); font-size: 13px; line-height: 1.45; container-type: inline-size; animation: clay-seo-in .2s ease-out; position: relative; z-index: 2147482001; grid-column: 1 / -1; flex: 0 0 100%; max-height: 85vh; max-height: 85dvh; overflow-y: auto; overscroll-behavior: contain; }
|
|
46
|
+
@keyframes clay-seo-in { from { margin-top: -40px; opacity: 0; } to { margin-top: 0; opacity: 1; } }
|
|
47
|
+
.clay-seo-inner { max-width: 1120px; margin: 0 auto; padding: 14px 20px 18px; }
|
|
48
|
+
.clay-seo-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-bottom: 10px; margin-bottom: 12px; border-bottom: 1px solid var(--bevel-line-2); }
|
|
49
|
+
.clay-seo-heading { margin: 0; font: 500 19px/1.15 var(--bevel-font-serif); letter-spacing: -.01em; }
|
|
50
|
+
.clay-seo-actions { display: flex; gap: 8px; }
|
|
51
|
+
.clay-seo-grid { display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(260px, .9fr); gap: 22px; align-items: start; }
|
|
52
|
+
.clay-seo-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; }
|
|
53
|
+
.clay-seo-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
|
|
54
|
+
.clay-seo-field.is-full { grid-column: 1 / -1; }
|
|
55
|
+
.clay-seo-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 12.5px; font-weight: 500; color: var(--bevel-ink-2); }
|
|
56
|
+
.clay-seo-label-row label span { font-weight: 400; color: var(--bevel-muted); }
|
|
57
|
+
.clay-seo-field:has([aria-invalid="true"]) .clay-seo-label-row { color: var(--bevel-ox); }
|
|
58
|
+
.clay-seo-aside { display: inline-flex; align-items: baseline; gap: 10px; }
|
|
59
|
+
.clay-seo-count { font: 500 11px/1 var(--bevel-font-mono); color: var(--bevel-muted); font-variant-numeric: tabular-nums; }
|
|
60
|
+
.clay-seo-count[data-over] { color: var(--bevel-ox); }
|
|
61
|
+
.clay-seo-derived { padding: 0; border: 0; background: none; color: var(--bevel-brass); font: 500 12px/1.3 var(--bevel-font-sans); text-decoration: underline; text-decoration-color: var(--bevel-line-3); text-underline-offset: 2px; cursor: pointer; }
|
|
62
|
+
.clay-seo-input { box-sizing: border-box; width: 100%; min-height: 32px; padding: 6px 9px; border: 1px solid var(--bevel-line-2); background: var(--bevel-ground); color: var(--bevel-ink); font: 400 13px/1.45 var(--bevel-font-sans); }
|
|
63
|
+
textarea.clay-seo-input { min-height: 52px; resize: vertical; }
|
|
64
|
+
textarea.clay-seo-input.is-short { min-height: 32px; }
|
|
65
|
+
.clay-seo-input::placeholder { color: var(--bevel-faint); opacity: 1; }
|
|
66
|
+
.clay-seo-input:hover { border-color: var(--bevel-faint); }
|
|
67
|
+
.clay-seo-input:focus-visible { outline: 2px solid var(--bevel-brass); outline-offset: 1px; border-color: var(--bevel-brass); }
|
|
68
|
+
.clay-seo-input[aria-invalid="true"] { border-color: var(--bevel-ox); background: color-mix(in srgb, var(--bevel-ox-soft) 40%, var(--bevel-ground)); }
|
|
69
|
+
.clay-seo-error { margin: 0; font-size: 12px; font-weight: 500; color: var(--bevel-ox); }
|
|
70
|
+
.clay-seo-upload { display: flex; gap: 8px; }
|
|
71
|
+
.clay-seo-upload .clay-seo-input { flex: 1; min-width: 0; }
|
|
72
|
+
.clay-seo-note { margin: 0; font-size: 12px; color: var(--bevel-muted); }
|
|
73
|
+
.clay-seo-more { grid-column: 1 / -1; border: 1px solid var(--bevel-line-2); background: var(--bevel-surface); }
|
|
74
|
+
.clay-seo-more > summary { position: relative; display: flex; align-items: center; gap: 9px; padding: 6px 10px 6px 8px; list-style: none; font-size: 12.5px; font-weight: 500; cursor: pointer; user-select: none; }
|
|
75
|
+
.clay-seo-more > summary::-webkit-details-marker { display: none; }
|
|
76
|
+
.clay-seo-more > summary::before { content: ""; box-sizing: border-box; width: 20px; height: 20px; border: 2px solid; border-color: var(--bevel-edge-hi) var(--bevel-edge-lo) var(--bevel-edge-lo) var(--bevel-edge-hi); background: var(--bevel-face); }
|
|
77
|
+
.clay-seo-more > summary::after { content: ""; position: absolute; left: 15px; top: 50%; width: 5px; height: 5px; border-right: 1.5px solid var(--bevel-ink); border-bottom: 1.5px solid var(--bevel-ink); transform: translateY(-50%) rotate(-45deg); }
|
|
78
|
+
.clay-seo-more[open] > summary { border-bottom: 1px solid var(--bevel-line); }
|
|
79
|
+
.clay-seo-more[open] > summary::before { background: var(--bevel-face-in); border-color: var(--bevel-edge-in) var(--bevel-edge-in-hi) var(--bevel-edge-in-hi) var(--bevel-edge-in); }
|
|
80
|
+
.clay-seo-more[open] > summary::after { transform: translate(1px, -65%) rotate(45deg); }
|
|
81
|
+
.clay-seo-more-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; padding: 10px; background: var(--bevel-sunk); }
|
|
82
|
+
.clay-seo-checks { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 8px 18px; }
|
|
83
|
+
.clay-seo-check { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; }
|
|
84
|
+
.clay-seo-check input { appearance: none; -webkit-appearance: none; position: relative; box-sizing: border-box; flex: none; width: 16px; height: 16px; margin: 0; border: 2px solid; border-color: var(--bevel-edge-hi) var(--bevel-edge-lo) var(--bevel-edge-lo) var(--bevel-edge-hi); background: var(--bevel-face); cursor: pointer; }
|
|
85
|
+
.clay-seo-check input:checked { background: var(--bevel-face-in); border-color: var(--bevel-edge-in) var(--bevel-edge-in-hi) var(--bevel-edge-in-hi) var(--bevel-edge-in); }
|
|
86
|
+
.clay-seo-check input:checked::after { content: ""; position: absolute; left: 3px; top: 0; width: 4px; height: 8px; border-right: 1.8px solid var(--bevel-ink); border-bottom: 1.8px solid var(--bevel-ink); transform: rotate(42deg); }
|
|
87
|
+
.clay-seo-check input:focus-visible { outline: 2px solid var(--bevel-brass); outline-offset: 2px; }
|
|
88
|
+
.clay-seo-preview { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
89
|
+
.clay-seo-preview-head { display: flex; justify-content: space-between; align-items: baseline; font-size: 12.5px; font-weight: 500; color: var(--bevel-ink-2); }
|
|
90
|
+
.clay-seo-preview-head span { font: 400 11px/1 var(--bevel-font-mono); color: var(--bevel-muted); }
|
|
91
|
+
.clay-og { border: 1px solid var(--bevel-line-2); background: var(--bevel-ground); overflow: hidden; }
|
|
92
|
+
.clay-og-image { position: relative; display: flex; align-items: flex-end; aspect-ratio: 1.91 / 1; max-height: 160px; width: 100%; padding: 10px 12px; box-sizing: border-box; overflow: hidden; background: var(--og-image, var(--bevel-brass-soft)); border-bottom: 1px solid var(--bevel-line-2); }
|
|
93
|
+
.clay-og-image[hidden] { display: none; }
|
|
94
|
+
.clay-og-image span { position: relative; font: 500 10.5px/1.3 var(--bevel-font-mono); padding: 2px 7px; border: 1px solid var(--bevel-line-2); background: var(--bevel-surface); color: var(--bevel-ink); }
|
|
95
|
+
.clay-og-body { display: flex; flex-direction: column; gap: 2px; padding: 9px 12px 11px; }
|
|
96
|
+
.clay-og-host { font: 400 11px/1.3 var(--bevel-font-mono); color: var(--bevel-muted); }
|
|
97
|
+
.clay-og-title { font: 600 14px/1.3 var(--bevel-font-sans); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
98
|
+
.clay-og-desc { font-size: 12.5px; line-height: 1.4; color: var(--bevel-ink-2); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
99
|
+
.clay-seo-cardsize { margin: 0; font: 400 11px/1.3 var(--bevel-font-mono); color: var(--bevel-muted); }
|
|
100
|
+
|
|
101
|
+
@container (max-width: 680px) {
|
|
102
|
+
.clay-seo-inner { padding: 12px 14px 16px; }
|
|
103
|
+
.clay-seo-grid, .clay-seo-fields, .clay-seo-more-grid { grid-template-columns: 1fr; }
|
|
104
|
+
.clay-seo-input { font-size: 16px; min-height: 40px; }
|
|
105
|
+
textarea.clay-seo-input { min-height: 96px; }
|
|
106
|
+
textarea.clay-seo-input.is-short { min-height: 40px; }
|
|
107
|
+
.clay-seo-check { font-size: 15px; }
|
|
108
|
+
}
|
|
109
|
+
.clay-og-image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
|
|
110
|
+
.clay-seo-check > .clay-seo-check { display: inline-block; }
|
|
111
|
+
.clay-seo-conflict { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 12px; color: var(--bevel-muted); }
|
|
112
|
+
.clay-seo-conflict[hidden] { display: none; }
|
|
113
|
+
.clay-seo-conflict p { margin: 0; flex-basis: 100%; }
|
|
114
|
+
.clay-seo-title-mode { margin: 0; font-size: 12px; color: var(--bevel-muted); }
|
|
115
|
+
@media (pointer: coarse), (max-width: 680px) { .clay-seo .clay-menu-btn { min-height: 40px; } .clay-seo :is(input, textarea, select) { font-size: 16px; } }
|
|
116
|
+
@media (prefers-reduced-motion: reduce) { .clay-seo { animation: none; transition: none; } }`;
|
|
288
117
|
|
|
289
118
|
const text = (value) => (value == null ? "" : String(value));
|
|
290
119
|
|
|
@@ -295,15 +124,6 @@ function element(tag, className, content) {
|
|
|
295
124
|
return el;
|
|
296
125
|
}
|
|
297
126
|
|
|
298
|
-
function stylesOnce() {
|
|
299
|
-
if (document.getElementById(STYLE_ID)) return;
|
|
300
|
-
const style = document.createElement("style");
|
|
301
|
-
style.id = STYLE_ID;
|
|
302
|
-
style.setAttribute("clay", "editor-ui");
|
|
303
|
-
style.textContent = SHEET_CSS;
|
|
304
|
-
document.head.append(style);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
127
|
const parseUrl = (value) => {
|
|
308
128
|
try {
|
|
309
129
|
return new URL(value);
|
|
@@ -416,23 +236,40 @@ function showValue(key, value) {
|
|
|
416
236
|
return raw || "(empty)";
|
|
417
237
|
}
|
|
418
238
|
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
239
|
+
function save() {
|
|
240
|
+
if (!document.documentElement.hasAttribute("autosave") && typeof window.clay?.save === "function") window.clay.save();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// `readHead` hands back what `applyHead` takes: a field's read and its write speak the
|
|
244
|
+
// same shape, booleans for index and follow and "custom"/"derived" for the title mode.
|
|
245
|
+
const restoreOf = (before) => ({ ...before });
|
|
246
|
+
|
|
247
|
+
function offerUndo(before) {
|
|
248
|
+
toastPersistent(APPLIED_TEXT, "success", {
|
|
249
|
+
actions: [
|
|
250
|
+
{
|
|
251
|
+
label: "Undo",
|
|
252
|
+
onClick: () => {
|
|
253
|
+
dismissPersistent(APPLIED_TEXT);
|
|
254
|
+
applyHead(document, restoreOf(before));
|
|
255
|
+
save();
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
});
|
|
423
260
|
}
|
|
424
261
|
|
|
425
|
-
export function open() {
|
|
426
|
-
if (document.querySelector(
|
|
427
|
-
stylesOnce();
|
|
262
|
+
export function open({ returnFocus } = {}) {
|
|
263
|
+
if (document.querySelector('clay-editor-ui[data-clay-ui="seo"]')) return;
|
|
428
264
|
|
|
429
265
|
const opened = readHead(document).values;
|
|
430
|
-
const restoreTo =
|
|
266
|
+
const restoreTo = returnFocus ?? deepActiveElement();
|
|
431
267
|
const inputs = new Map();
|
|
432
268
|
const errors = new Map();
|
|
433
269
|
const conflicts = new Map();
|
|
434
270
|
const chosen = new Set();
|
|
435
271
|
let closed = false;
|
|
272
|
+
let ui = null;
|
|
436
273
|
let uploadAvailable = false;
|
|
437
274
|
let pendingTitleMode = "";
|
|
438
275
|
|
|
@@ -447,125 +284,170 @@ export function open() {
|
|
|
447
284
|
|
|
448
285
|
const root = element("div", "clay-seo");
|
|
449
286
|
root.setAttribute("clay", "editor-ui");
|
|
450
|
-
root.setAttribute("role", "
|
|
451
|
-
root.setAttribute("aria-modal", "true");
|
|
287
|
+
root.setAttribute("role", "region");
|
|
452
288
|
root.setAttribute("aria-labelledby", "clay-seo-heading");
|
|
453
289
|
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
closeButton.type = "button";
|
|
458
|
-
closeButton.setAttribute("aria-label", "Close");
|
|
459
|
-
const top = element("div", "clay-seo-top");
|
|
460
|
-
top.append(title, closeButton);
|
|
290
|
+
const derivedButton = element("button", "clay-seo-derived", "Use the first heading");
|
|
291
|
+
derivedButton.type = "button";
|
|
292
|
+
derivedButton.hidden = true;
|
|
461
293
|
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
|
|
294
|
+
const uploadButton = element("button", "clay-seo-upload-button clay-menu-btn", "Upload image");
|
|
295
|
+
uploadButton.type = "button";
|
|
296
|
+
const fileInput = element("input", "clay-seo-file");
|
|
297
|
+
fileInput.type = "file";
|
|
298
|
+
fileInput.accept = "image/*";
|
|
299
|
+
fileInput.hidden = true;
|
|
300
|
+
fileInput.tabIndex = -1;
|
|
301
|
+
const publicNote = element("p", "clay-seo-note", PUBLIC_NOTE);
|
|
302
|
+
publicNote.hidden = true;
|
|
303
|
+
const pasteNote = element("p", "clay-seo-note", PASTE_NOTE);
|
|
304
|
+
const uploadRow = element("div", "clay-seo-upload");
|
|
471
305
|
|
|
472
|
-
const form = element("div", "clay-seo-form");
|
|
473
306
|
const robotNote = element("p", "clay-seo-note");
|
|
474
307
|
robotNote.hidden = true;
|
|
475
|
-
const cardSize = element("p", "clay-seo-note");
|
|
308
|
+
const cardSize = element("p", "clay-seo-cardsize clay-seo-note");
|
|
476
309
|
|
|
477
|
-
|
|
310
|
+
const previewImage = element("img");
|
|
311
|
+
previewImage.alt = "";
|
|
312
|
+
const previewImageBox = element("div", "clay-og-image");
|
|
313
|
+
previewImageBox.hidden = true;
|
|
314
|
+
previewImageBox.append(previewImage);
|
|
315
|
+
const previewHost = element("span", "clay-og-host");
|
|
316
|
+
const previewTitle = element("span", "clay-og-title");
|
|
317
|
+
const previewDescription = element("span", "clay-og-desc");
|
|
318
|
+
const ogBody = element("div", "clay-og-body");
|
|
319
|
+
ogBody.append(previewHost, previewTitle, previewDescription);
|
|
320
|
+
const ogCard = element("div", "clay-og");
|
|
321
|
+
ogCard.append(previewImageBox, ogBody);
|
|
322
|
+
const previewState = element("span");
|
|
323
|
+
const previewHead = element("div", "clay-seo-preview-head");
|
|
324
|
+
previewHead.append("Link preview", previewState);
|
|
325
|
+
const preview = element("div", "clay-seo-preview");
|
|
326
|
+
preview.append(previewHead, ogCard, cardSize);
|
|
327
|
+
|
|
328
|
+
const form = element("div", "clay-seo-fields");
|
|
329
|
+
const counters = new Map();
|
|
330
|
+
|
|
331
|
+
function buildField(key) {
|
|
332
|
+
const spec = FIELD[key];
|
|
333
|
+
const id = `clay-seo-${key}`;
|
|
478
334
|
const wrap = element("div", "clay-seo-field");
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const input =
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
335
|
+
if (spec.full) wrap.classList.add("is-full");
|
|
336
|
+
|
|
337
|
+
const input = element(
|
|
338
|
+
spec.kind === "checkbox" ? "input" : spec.kind === "textarea" ? "textarea" : "input",
|
|
339
|
+
spec.kind === "checkbox" ? "clay-seo-check" : "clay-seo-input",
|
|
340
|
+
);
|
|
341
|
+
if (spec.kind === "checkbox") {
|
|
485
342
|
input.type = "checkbox";
|
|
486
|
-
input.checked = opened[
|
|
487
|
-
row.append(input, caption);
|
|
343
|
+
input.checked = opened[key] !== false;
|
|
488
344
|
} else {
|
|
489
|
-
if (
|
|
490
|
-
|
|
491
|
-
|
|
345
|
+
if (spec.kind !== "textarea") input.type = "text";
|
|
346
|
+
if (spec.short) {
|
|
347
|
+
input.rows = 1;
|
|
348
|
+
input.classList.add("is-short");
|
|
349
|
+
}
|
|
350
|
+
input.value = text(opened[key]);
|
|
492
351
|
}
|
|
493
|
-
input.
|
|
494
|
-
|
|
495
|
-
|
|
352
|
+
if (spec.placeholder) input.placeholder = spec.placeholder;
|
|
353
|
+
input.id = id;
|
|
354
|
+
input.dataset.key = key;
|
|
355
|
+
if (window.clay && window.clay.unsent) input.setAttribute("unsent", `seo-${key}`);
|
|
356
|
+
inputs.set(key, input);
|
|
496
357
|
|
|
497
358
|
const error = element("p", "clay-seo-error");
|
|
498
359
|
error.hidden = true;
|
|
499
|
-
errors.set(
|
|
360
|
+
errors.set(key, error);
|
|
500
361
|
|
|
501
362
|
const conflict = element("div", "clay-seo-conflict");
|
|
502
363
|
conflict.hidden = true;
|
|
503
364
|
const theirsLine = element("p");
|
|
504
365
|
const theirs = element("span", "clay-seo-theirs");
|
|
505
366
|
theirsLine.append("Changed elsewhere: ", theirs);
|
|
506
|
-
const theirsButton = element("button", "clay-seo-theirs-button", "Use theirs");
|
|
367
|
+
const theirsButton = element("button", "clay-menu-btn clay-menu-btn-small clay-seo-theirs-button", "Use theirs");
|
|
507
368
|
theirsButton.type = "button";
|
|
508
|
-
const mineButton = element("button", "clay-seo-mine-button", "Keep mine");
|
|
369
|
+
const mineButton = element("button", "clay-menu-btn clay-menu-btn-small clay-seo-mine-button", "Keep mine");
|
|
509
370
|
mineButton.type = "button";
|
|
510
371
|
conflict.append(theirsLine, theirsButton, mineButton);
|
|
511
|
-
conflicts.set(
|
|
372
|
+
conflicts.set(key, { row: conflict, theirs });
|
|
512
373
|
|
|
513
374
|
theirsButton.addEventListener("click", () => {
|
|
514
|
-
const value = readHead(document).values[
|
|
515
|
-
if (
|
|
375
|
+
const value = readHead(document).values[key];
|
|
376
|
+
if (spec.kind === "checkbox") input.checked = value !== false;
|
|
516
377
|
else input.value = text(value);
|
|
517
|
-
chosen.add(
|
|
378
|
+
chosen.add(key);
|
|
518
379
|
conflict.hidden = true;
|
|
519
380
|
refresh();
|
|
520
381
|
});
|
|
521
382
|
mineButton.addEventListener("click", () => {
|
|
522
|
-
chosen.add(
|
|
383
|
+
chosen.add(key);
|
|
523
384
|
conflict.hidden = true;
|
|
524
385
|
});
|
|
525
386
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
387
|
+
if (spec.kind === "checkbox") {
|
|
388
|
+
const label = element("label", "clay-seo-check");
|
|
389
|
+
label.append(input, spec.label);
|
|
390
|
+
wrap.append(label, error, conflict);
|
|
391
|
+
return wrap;
|
|
392
|
+
}
|
|
529
393
|
|
|
530
|
-
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
|
|
394
|
+
const row = element("div", "clay-seo-label-row");
|
|
395
|
+
const label = element("label");
|
|
396
|
+
label.htmlFor = id;
|
|
397
|
+
label.append(spec.label);
|
|
398
|
+
if (spec.note) label.append(" ", element("span", null, `(${spec.note})`));
|
|
399
|
+
row.append(label);
|
|
400
|
+
if (spec.count) {
|
|
401
|
+
const count = element("span", "clay-seo-count");
|
|
402
|
+
counters.set(key, { el: count, max: spec.count });
|
|
403
|
+
const aside = element("span", "clay-seo-aside");
|
|
404
|
+
if (key === "title") aside.append(derivedButton);
|
|
405
|
+
aside.append(count);
|
|
406
|
+
row.append(aside);
|
|
407
|
+
}
|
|
408
|
+
wrap.append(row);
|
|
409
|
+
if (key === "ogImage") {
|
|
410
|
+
uploadRow.append(input, uploadButton, fileInput);
|
|
411
|
+
wrap.append(uploadRow, pasteNote, publicNote);
|
|
412
|
+
} else {
|
|
413
|
+
wrap.append(input);
|
|
414
|
+
}
|
|
415
|
+
wrap.append(error, conflict);
|
|
416
|
+
return wrap;
|
|
537
417
|
}
|
|
538
418
|
|
|
539
|
-
|
|
540
|
-
derivedButton.type = "button";
|
|
541
|
-
derivedButton.hidden = true;
|
|
542
|
-
inputs.get("title").closest(".clay-seo-field").append(derivedButton);
|
|
419
|
+
for (const key of BASE_KEYS) form.append(buildField(key));
|
|
543
420
|
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const pasteNote = element("p", "clay-seo-note", PASTE_NOTE);
|
|
555
|
-
const uploadRow = element("div", "clay-seo-upload");
|
|
556
|
-
uploadRow.append(uploadButton, fileInput, pasteNote, publicNote);
|
|
557
|
-
imageInput.closest(".clay-seo-field").append(uploadRow);
|
|
421
|
+
const more = element("details", "clay-seo-more");
|
|
422
|
+
more.append(element("summary", null, "More search and social fields"));
|
|
423
|
+
const moreGrid = element("div", "clay-seo-more-grid");
|
|
424
|
+
for (const key of MORE_KEYS) moreGrid.append(buildField(key));
|
|
425
|
+
const checks = element("div", "clay-seo-checks");
|
|
426
|
+
for (const key of CHECK_KEYS) checks.append(buildField(key));
|
|
427
|
+
checks.append(robotNote);
|
|
428
|
+
moreGrid.append(checks);
|
|
429
|
+
more.append(moreGrid);
|
|
430
|
+
form.append(more);
|
|
558
431
|
|
|
559
|
-
const editButton = element("button", "clay-seo-edit", "Edit these settings");
|
|
432
|
+
const editButton = element("button", "clay-seo-edit clay-menu-btn", "Edit these settings");
|
|
560
433
|
editButton.type = "button";
|
|
561
|
-
const cancelButton = element("button", "clay-seo-cancel", "Cancel");
|
|
434
|
+
const cancelButton = element("button", "clay-seo-cancel clay-menu-btn", "Cancel");
|
|
562
435
|
cancelButton.type = "button";
|
|
563
|
-
const applyButton = element("button", "clay-seo-apply", "
|
|
436
|
+
const applyButton = element("button", "clay-seo-apply clay-menu-btn clay-menu-btn-primary", "Done");
|
|
564
437
|
applyButton.type = "button";
|
|
565
438
|
const actions = element("div", "clay-seo-actions");
|
|
566
439
|
actions.append(editButton, cancelButton, applyButton);
|
|
567
440
|
|
|
568
|
-
|
|
441
|
+
const heading = element("h2", "clay-seo-heading", LABEL);
|
|
442
|
+
heading.id = "clay-seo-heading";
|
|
443
|
+
const bar = element("div", "clay-seo-bar");
|
|
444
|
+
bar.append(heading, actions);
|
|
445
|
+
|
|
446
|
+
const grid = element("div", "clay-seo-grid");
|
|
447
|
+
grid.append(form, preview);
|
|
448
|
+
const inner = element("div", "clay-seo-inner");
|
|
449
|
+
inner.append(bar, grid);
|
|
450
|
+
root.append(inner);
|
|
569
451
|
|
|
570
452
|
const readField = (key) => {
|
|
571
453
|
const input = inputs.get(key);
|
|
@@ -595,6 +477,13 @@ export function open() {
|
|
|
595
477
|
inputs.get("ogTitle").placeholder = titleValue;
|
|
596
478
|
inputs.get("ogDescription").placeholder = descriptionValue;
|
|
597
479
|
|
|
480
|
+
for (const [key, entry] of counters) {
|
|
481
|
+
const length = text(readField(key)).trim().length;
|
|
482
|
+
entry.el.textContent = `${length} / ${entry.max}`;
|
|
483
|
+
if (length > entry.max) entry.el.dataset.over = "";
|
|
484
|
+
else delete entry.el.dataset.over;
|
|
485
|
+
}
|
|
486
|
+
|
|
598
487
|
const image = imageSrc();
|
|
599
488
|
if (image) {
|
|
600
489
|
previewImage.src = image;
|
|
@@ -603,12 +492,14 @@ export function open() {
|
|
|
603
492
|
previewImage.removeAttribute("src");
|
|
604
493
|
previewImage.hidden = true;
|
|
605
494
|
}
|
|
495
|
+
previewImageBox.hidden = previewImage.hidden;
|
|
606
496
|
previewTitle.textContent = text(readField("ogTitle")).trim() || titleValue || "Untitled page";
|
|
607
497
|
const description = text(readField("ogDescription")).trim() || descriptionValue;
|
|
608
498
|
previewDescription.textContent = description;
|
|
609
499
|
previewDescription.hidden = !description;
|
|
610
500
|
previewHost.textContent = hostOf(readField("canonical")) || location.host || "";
|
|
611
|
-
|
|
501
|
+
previewState.textContent = image ? "Large image card \u00b7 1.91:1" : "Summary card";
|
|
502
|
+
cardSize.textContent = image ? "Shared links show the large image." : "Add an image for the large card.";
|
|
612
503
|
derivedButton.hidden = !(isDocumentPage() && FIELDS.titleMode.read(document) === "custom");
|
|
613
504
|
}
|
|
614
505
|
|
|
@@ -646,15 +537,29 @@ export function open() {
|
|
|
646
537
|
return found;
|
|
647
538
|
}
|
|
648
539
|
|
|
540
|
+
function revealMore(found) {
|
|
541
|
+
for (const key of Object.keys(found)) {
|
|
542
|
+
const input = inputs.get(key);
|
|
543
|
+
if (input && more.contains(input)) {
|
|
544
|
+
more.open = true;
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
649
550
|
function showProblems(found) {
|
|
551
|
+
revealMore(found);
|
|
650
552
|
for (const [key, el] of errors) {
|
|
651
553
|
const message = found[key] || "";
|
|
652
554
|
el.textContent = message;
|
|
653
555
|
el.hidden = !message;
|
|
556
|
+
if (message) inputs.get(key)?.setAttribute("aria-invalid", "true");
|
|
557
|
+
else inputs.get(key)?.removeAttribute("aria-invalid");
|
|
654
558
|
}
|
|
655
559
|
}
|
|
656
560
|
|
|
657
561
|
function showConflicts(found) {
|
|
562
|
+
revealMore(found);
|
|
658
563
|
for (const [key, entry] of conflicts) {
|
|
659
564
|
const current = found[key];
|
|
660
565
|
const visible = current !== undefined;
|
|
@@ -664,6 +569,10 @@ export function open() {
|
|
|
664
569
|
}
|
|
665
570
|
|
|
666
571
|
function apply() {
|
|
572
|
+
if (!(window.clay && window.clay.mode === "edit")) {
|
|
573
|
+
close();
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
667
576
|
const wanted = changes();
|
|
668
577
|
const documentPage = isDocumentPage();
|
|
669
578
|
const marker = documentPage ? pendingTitleMode || ("title" in wanted ? "custom" : "") : "";
|
|
@@ -683,14 +592,26 @@ export function open() {
|
|
|
683
592
|
showConflicts(found);
|
|
684
593
|
return;
|
|
685
594
|
}
|
|
686
|
-
|
|
595
|
+
const next = marker ? { ...wanted, titleMode: marker } : wanted;
|
|
596
|
+
const undo = window.clay && window.clay.undo;
|
|
597
|
+
if (undo && typeof undo.commit === "function") {
|
|
598
|
+
undo.commit(UNDO_LABEL, () => applyHead(document, next));
|
|
599
|
+
} else {
|
|
600
|
+
const before = readHead(document).values;
|
|
601
|
+
applyHead(document, next);
|
|
602
|
+
offerUndo(before);
|
|
603
|
+
}
|
|
687
604
|
close();
|
|
605
|
+
// Apply is an explicit save of these settings: a page that does not autosave its markup
|
|
606
|
+
// (the page editor saves only its own stores) would otherwise keep them until edit ends.
|
|
607
|
+
save();
|
|
688
608
|
}
|
|
689
609
|
|
|
690
610
|
function applyUploadVisibility() {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
611
|
+
const editing = !!(window.clay && window.clay.mode === "edit");
|
|
612
|
+
uploadButton.hidden = !uploadAvailable || !editing;
|
|
613
|
+
pasteNote.hidden = uploadAvailable || !editing;
|
|
614
|
+
publicNote.hidden = !uploadAvailable || !editing || !/(^|\.)hyperclay\.com$/i.test(location.hostname);
|
|
694
615
|
}
|
|
695
616
|
|
|
696
617
|
function layout() {
|
|
@@ -701,15 +622,16 @@ export function open() {
|
|
|
701
622
|
}
|
|
702
623
|
editButton.hidden = editing;
|
|
703
624
|
cancelButton.hidden = !editing;
|
|
704
|
-
applyButton.hidden = !editing;
|
|
705
|
-
uploadRow.hidden = !editing || !uploadAvailable;
|
|
706
625
|
applyUploadVisibility();
|
|
707
626
|
}
|
|
708
627
|
|
|
709
628
|
// A live entry commits edit without this page going anywhere, so the sheet's own
|
|
710
629
|
// read-only layout has to follow the mode rather than the mode it opened in.
|
|
711
630
|
function followMode() {
|
|
712
|
-
if (
|
|
631
|
+
if (closed) return;
|
|
632
|
+
layout();
|
|
633
|
+
// Uploads load with edit, so a sheet opened in view asks again once edit is live.
|
|
634
|
+
if (!uploadAvailable) checkUploads();
|
|
713
635
|
}
|
|
714
636
|
|
|
715
637
|
function close() {
|
|
@@ -717,7 +639,9 @@ export function open() {
|
|
|
717
639
|
closed = true;
|
|
718
640
|
pending.dispose();
|
|
719
641
|
document.removeEventListener("clay:modechange", followMode);
|
|
720
|
-
|
|
642
|
+
if (heightObserver) heightObserver.disconnect();
|
|
643
|
+
heightVars.remove();
|
|
644
|
+
ui?.remove();
|
|
721
645
|
if (restoreTo && restoreTo.isConnected && typeof restoreTo.focus === "function") restoreTo.focus();
|
|
722
646
|
}
|
|
723
647
|
|
|
@@ -749,12 +673,6 @@ export function open() {
|
|
|
749
673
|
layout();
|
|
750
674
|
}
|
|
751
675
|
|
|
752
|
-
function focusables() {
|
|
753
|
-
return Array.from(root.querySelectorAll("button, input, textarea")).filter(
|
|
754
|
-
(el) => !el.disabled && !el.hidden && el.tabIndex >= 0 && !el.closest("[hidden]"),
|
|
755
|
-
);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
676
|
form.addEventListener("input", () => {
|
|
759
677
|
refresh();
|
|
760
678
|
pending.changed();
|
|
@@ -794,7 +712,6 @@ export function open() {
|
|
|
794
712
|
|
|
795
713
|
applyButton.addEventListener("click", apply);
|
|
796
714
|
cancelButton.addEventListener("click", close);
|
|
797
|
-
closeButton.addEventListener("click", close);
|
|
798
715
|
|
|
799
716
|
editButton.addEventListener("click", async () => {
|
|
800
717
|
const clay = window.clay;
|
|
@@ -815,32 +732,34 @@ export function open() {
|
|
|
815
732
|
if (reloading) return;
|
|
816
733
|
if (storage) storage.remove(REOPEN_KEY);
|
|
817
734
|
const refusal = modeRefusalText(result);
|
|
818
|
-
if (refusal) window.clay?.toast?.(refusal, "error");
|
|
735
|
+
if (refusal) (window.clay?.menu?.note || window.clay?.toast)?.(refusal, "error");
|
|
819
736
|
if (result && result.ok !== false) layout();
|
|
820
737
|
});
|
|
821
738
|
|
|
739
|
+
const heightVars = document.createElement("style");
|
|
740
|
+
heightVars.id = "clay-seo-vars";
|
|
741
|
+
heightVars.setAttribute("clay", "editor-ui");
|
|
742
|
+
document.head.append(heightVars);
|
|
743
|
+
let heightObserver = null;
|
|
744
|
+
|
|
745
|
+
function writeHeight() {
|
|
746
|
+
heightVars.textContent = `:root { --clay-seo-height: ${Math.ceil(root.getBoundingClientRect().height)}px; }`;
|
|
747
|
+
}
|
|
748
|
+
|
|
822
749
|
root.addEventListener("keydown", (event) => {
|
|
823
|
-
if (event.key
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
return;
|
|
827
|
-
}
|
|
828
|
-
if (event.key !== "Tab") return;
|
|
829
|
-
const all = focusables();
|
|
830
|
-
if (!all.length) return;
|
|
831
|
-
const first = all[0];
|
|
832
|
-
const last = all[all.length - 1];
|
|
833
|
-
if (event.shiftKey && document.activeElement === first) {
|
|
834
|
-
event.preventDefault();
|
|
835
|
-
last.focus();
|
|
836
|
-
} else if (!event.shiftKey && document.activeElement === last) {
|
|
837
|
-
event.preventDefault();
|
|
838
|
-
first.focus();
|
|
839
|
-
}
|
|
750
|
+
if (event.key !== "Escape") return;
|
|
751
|
+
event.preventDefault();
|
|
752
|
+
close();
|
|
840
753
|
});
|
|
841
754
|
|
|
842
755
|
document.addEventListener("clay:modechange", followMode);
|
|
843
|
-
|
|
756
|
+
lookAt(root, { x: 0, y: 0, width: innerWidth, height: Math.min(200, innerHeight) }, MENU_SURFACE);
|
|
757
|
+
ui = mountEditorUI({ name: "seo", content: root, css: [MENU_CSS, SHEET_CSS], before: document.body.firstChild });
|
|
758
|
+
writeHeight();
|
|
759
|
+
if (typeof ResizeObserver === "function") {
|
|
760
|
+
heightObserver = new ResizeObserver(writeHeight);
|
|
761
|
+
heightObserver.observe(root);
|
|
762
|
+
}
|
|
844
763
|
refresh();
|
|
845
764
|
layout();
|
|
846
765
|
inputs.get("title").focus();
|