@heycys/gallery 0.1.0 → 0.1.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 +51 -1
- package/browser/editor/components/callout/index.mjs +40 -15
- package/browser/editor/components/columns/page.mjs +41 -28
- package/browser/editor/components/details/index.mjs +2 -1
- package/browser/editor/components/dialog/index.mjs +2 -1
- package/browser/editor/components/dialog/page.mjs +0 -18
- package/browser/editor/components/divider/index.mjs +1 -1
- package/browser/editor/components/figure/page.mjs +10 -1
- package/browser/editor/components/file/page.mjs +2 -2
- package/browser/editor/components/flowchart/add.mjs +2 -2
- package/browser/editor/components/heading/index.mjs +2 -0
- package/browser/editor/components/heading/page.mjs +6 -0
- package/browser/editor/components/highlight/index.mjs +4 -20
- package/browser/editor/components/icons.mjs +5 -2
- package/browser/editor/components/image/page.mjs +2 -2
- package/browser/editor/components/installed/index.mjs +71 -25
- package/browser/editor/components/installed/page.mjs +122 -21
- package/browser/editor/components/kit.mjs +3 -0
- package/browser/editor/components/media/page.mjs +44 -14
- package/browser/editor/components/pages.mjs +2 -2
- package/browser/editor/components/registry.mjs +56 -30
- package/browser/editor/components/section/index.mjs +2 -1
- package/browser/editor/components/set-apart.mjs +24 -0
- package/browser/editor/components/table/index.mjs +5 -3
- package/browser/editor/components/table/page.mjs +29 -18
- package/browser/editor/page/annotate/anchors.mjs +4 -3
- package/browser/editor/page/annotate/index.mjs +61 -34
- package/browser/editor/page/autosave.mjs +50 -4
- package/browser/editor/page/beside.mjs +5 -5
- package/browser/editor/page/block-menu/colors.mjs +3 -1
- package/browser/editor/page/block-menu/index.mjs +8 -6
- package/browser/editor/page/blocks.mjs +16 -7
- package/browser/editor/page/caret.mjs +4 -1
- package/browser/editor/page/changes/bar.mjs +102 -0
- package/browser/editor/page/changes/ghost.mjs +206 -0
- package/browser/editor/page/changes/gone-words.mjs +94 -0
- package/browser/editor/page/changes/index.mjs +447 -0
- package/browser/editor/page/changes/words.mjs +27 -0
- package/browser/editor/page/clipboard/import/colors.mjs +3 -3
- package/browser/editor/page/clipboard/index.mjs +32 -13
- package/browser/editor/page/clipboard/own/blocks.mjs +14 -5
- package/browser/editor/page/clipboard/own/describe.mjs +16 -7
- package/browser/editor/page/clipboard/own/export.mjs +6 -6
- package/browser/editor/page/clipboard/own/selection.mjs +2 -2
- package/browser/editor/page/clipboard/own/writers.mjs +0 -11
- package/browser/editor/page/columns/index.mjs +1 -1
- package/browser/editor/page/commit.mjs +19 -4
- package/browser/editor/page/conflicts.mjs +6 -26
- package/browser/editor/page/convert.mjs +8 -7
- package/browser/editor/page/core.mjs +55 -17
- package/browser/editor/page/drag/index.mjs +40 -24
- package/browser/editor/page/drag/preview.mjs +9 -4
- package/browser/editor/page/editor.mjs +70 -15
- package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
- package/browser/editor/page/emoji-picker/grid.mjs +7 -5
- package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
- package/browser/editor/page/emoji-picker/icons.mjs +0 -1
- package/browser/editor/page/emoji-picker/index.mjs +11 -9
- package/browser/editor/page/emoji-picker/styles.mjs +161 -2
- package/browser/editor/page/emoji-picker/support.mjs +6 -4
- package/browser/editor/page/emoji-picker/upload.mjs +12 -11
- package/browser/editor/page/fills.mjs +5 -3
- package/browser/editor/page/fold/index.mjs +348 -0
- package/browser/editor/page/fold/rule.mjs +125 -0
- package/browser/editor/page/folded.mjs +23 -0
- package/browser/editor/page/format-bar/bar.mjs +2 -1
- package/browser/editor/page/format-bar/index.mjs +1 -1
- package/browser/editor/page/geometry.mjs +8 -6
- package/browser/editor/page/handle/index.mjs +17 -6
- package/browser/editor/page/hints/index.mjs +1 -1
- package/browser/editor/page/insert/index.mjs +30 -17
- package/browser/editor/page/long-runs.mjs +75 -0
- package/browser/editor/page/look.mjs +15 -3
- package/browser/editor/page/margin.mjs +45 -24
- package/browser/editor/page/menu.mjs +69 -25
- package/browser/editor/page/merge.mjs +24 -0
- package/browser/editor/page/notices.mjs +1 -1
- package/browser/editor/page/offered.mjs +1 -1
- package/browser/editor/page/outline/folds.mjs +11 -10
- package/browser/editor/page/outline/index.mjs +131 -45
- package/browser/editor/page/outline/list.mjs +23 -11
- package/browser/editor/page/outline/read.mjs +1 -1
- package/browser/editor/page/outline/strip.mjs +7 -1
- package/browser/editor/page/panel.mjs +5 -4
- package/browser/editor/page/resize/index.mjs +1 -1
- package/browser/editor/page/selection/delete.mjs +8 -6
- package/browser/editor/page/selection/index.mjs +10 -3
- package/browser/editor/page/session.mjs +54 -3
- package/browser/editor/page/table/cell-bar.mjs +4 -1
- package/browser/editor/page/table/cells.mjs +1 -1
- package/browser/editor/page/table/icons.mjs +1 -1
- package/browser/editor/page/table/index.mjs +13 -8
- package/browser/editor/page/table/widths.mjs +9 -4
- package/browser/editor/page/text-select/index.mjs +18 -3
- package/browser/editor/page/tooltip.mjs +1 -1
- package/browser/editor/page/type-grid.mjs +4 -3
- package/browser/editor/page/typing/code-edges.mjs +63 -17
- package/browser/editor/page/typing/index.mjs +12 -6
- package/browser/editor/page/typing/leave.mjs +1 -1
- package/browser/shared/annotations.mjs +8 -10
- package/browser/shared/code-folds.mjs +5 -1
- package/browser/shared/colors.mjs +15 -13
- package/browser/shared/component-catalog.mjs +24 -10
- package/browser/shared/components/callout.mjs +4 -2
- package/browser/shared/components/index.mjs +61 -7
- package/browser/shared/components/installed.mjs +75 -5
- package/browser/shared/components/page.mjs +10 -1
- package/browser/shared/components/table.mjs +1 -1
- package/browser/shared/components/text.mjs +2 -2
- package/browser/shared/document-look.mjs +178 -0
- package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
- package/browser/shared/emoji/data/README.md +4 -2
- package/browser/shared/emoji/data/categories.json +1 -1
- package/browser/shared/emoji/data/keywords-en.json +1 -1
- package/browser/shared/emoji/data/keywords-zh.json +1 -1
- package/browser/shared/emoji/data/names.json +1 -1
- package/browser/shared/emoji/data/positions.json +1 -1
- package/browser/shared/emoji/data/twemoji-index.json +1 -1
- package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
- package/browser/shared/emoji/data.mjs +10 -12
- package/browser/shared/emoji/emoji.mjs +8 -7
- package/browser/shared/emoji/icon-value.mjs +4 -3
- package/browser/shared/html-tree.mjs +11 -5
- package/browser/shared/i18n/en.mjs +67 -8
- package/browser/shared/long-runs.mjs +39 -0
- package/browser/shared/new-names.mjs +5 -2
- package/browser/shared/outline.mjs +194 -0
- package/browser/shared/preferences.mjs +10 -4
- package/browser/shared/session.mjs +5 -4
- package/browser/shared/workspace-look.mjs +91 -0
- package/browser/shared/zoom.mjs +5 -5
- package/dist/chunk-3HIRPVLU.mjs +2 -0
- package/dist/chunk-4FS7Z7WR.mjs +2 -0
- package/dist/{chunk-LHTFLRB6.mjs → chunk-5MHMDLZD.mjs} +2 -2
- package/dist/{chunk-YXAUQPVK.mjs → chunk-5ZKJ3H4P.mjs} +3 -3
- package/dist/{chunk-ZBIM6ARY.mjs → chunk-64K7IPLO.mjs} +55 -16
- package/dist/{chunk-QYKCJ7FG.mjs → chunk-6QXGZM36.mjs} +1 -1
- package/dist/chunk-6RGJOMJP.mjs +16 -0
- package/dist/{chunk-EUX7IC5J.mjs → chunk-7DTINW6U.mjs} +2 -2
- package/dist/{chunk-6CYG3Z4V.mjs → chunk-AJ73XJF3.mjs} +1 -1
- package/dist/chunk-AUZGSZJH.mjs +13 -0
- package/dist/{chunk-7QQBR7PB.mjs → chunk-BFE45AKL.mjs} +1 -1
- package/dist/chunk-BGGDRNYQ.mjs +10 -0
- package/dist/{chunk-L4DVONOG.mjs → chunk-BXO2ZY5P.mjs} +1 -1
- package/dist/chunk-CEH4MRCC.mjs +2 -0
- package/dist/chunk-CY2FNNAB.mjs +16 -0
- package/dist/{chunk-LC7YNQFG.mjs → chunk-DFUDV4LX.mjs} +1 -1
- package/dist/chunk-DKXG4XDG.mjs +2 -0
- package/dist/chunk-E7LWZRXY.mjs +4 -0
- package/dist/chunk-EZQ34M3F.mjs +124 -0
- package/dist/chunk-FDLXYYG4.mjs +4 -0
- package/dist/chunk-FUKQNOQS.mjs +9 -0
- package/dist/{chunk-DB4WKGYF.mjs → chunk-GB5SOYQJ.mjs} +2 -2
- package/dist/{chunk-ACOPDCNB.mjs → chunk-IVDLMMBD.mjs} +1 -1
- package/dist/chunk-JPOSLGOC.mjs +6 -0
- package/dist/chunk-JVHHHGEA.mjs +3 -0
- package/dist/chunk-L3QKH4OK.mjs +26 -0
- package/dist/{chunk-B3VTYBYR.mjs → chunk-LCTHTZIL.mjs} +2 -2
- package/dist/chunk-LEF6DRCK.mjs +59 -0
- package/dist/chunk-LS4F7JUM.mjs +2 -0
- package/dist/chunk-NO5NJCHO.mjs +2 -0
- package/dist/{chunk-UNUEWH4S.mjs → chunk-NQPVAU63.mjs} +1 -1
- package/dist/chunk-O35FIXRB.mjs +2 -0
- package/dist/chunk-PL6GHLGD.mjs +15 -0
- package/dist/{chunk-G7TOXONE.mjs → chunk-QJIR2BLP.mjs} +1 -1
- package/dist/chunk-QUPLVPB2.mjs +7 -0
- package/dist/chunk-R7BNENLY.mjs +4 -0
- package/dist/chunk-S6O4UHLC.mjs +2 -0
- package/dist/{chunk-HMHK3EQ6.mjs → chunk-SGJWQKEI.mjs} +1 -1
- package/dist/chunk-SYGN7GLU.mjs +2 -0
- package/dist/chunk-TYK6VNAB.mjs +10 -0
- package/dist/{chunk-EVJ3BX3M.mjs → chunk-U6KNPJPR.mjs} +1 -1
- package/dist/{chunk-YZ5Z6H4W.mjs → chunk-UALRNVSE.mjs} +1 -1
- package/dist/chunk-UMHUSOPJ.mjs +2 -0
- package/dist/chunk-V3HXVQEM.mjs +2 -0
- package/dist/{chunk-UXUK4PMC.mjs → chunk-V5JTW2LH.mjs} +1 -1
- package/dist/chunk-V5VXUJKG.mjs +2 -0
- package/dist/chunk-VBXMADMP.mjs +2 -0
- package/dist/chunk-VNV55RUA.mjs +2 -0
- package/dist/chunk-VPD2PS35.mjs +2 -0
- package/dist/chunk-W3BGBJQW.mjs +2 -0
- package/dist/chunk-W4VKN3GF.mjs +7 -0
- package/dist/chunk-W5BXXPDJ.mjs +3 -0
- package/dist/{chunk-Z52HTUW7.mjs → chunk-XNROSH2T.mjs} +2 -2
- package/dist/chunk-XUNHRCOG.mjs +6 -0
- package/dist/{chunk-6U2SLSDN.mjs → chunk-Y6RLRPG3.mjs} +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/math.js +18 -2
- package/kit/report.css +248 -137
- package/kit/runtime.js +126 -51
- package/kit/tables.js +51 -1
- package/kit/ui.js +97 -0
- package/package.json +1 -1
- package/release.json +8 -8
- package/sdk/doc-kit.d.ts +9 -3
- package/skill/SKILL.md +22 -10
- package/skill/references/building-components.md +46 -6
- package/skill/references/example-report.html +1 -1
- package/skill/references/writing-html.md +4 -4
- package/skill/sdk/doc-kit.d.ts +9 -3
- package/web/assets/index-Bh74DfsV.css +1 -0
- package/web/assets/index-UW0RyFFt.js +13 -0
- package/web/index.html +2 -2
- package/browser/editor/components/callout/page.mjs +0 -13
- package/dist/chunk-2PBALTR3.mjs +0 -57
- package/dist/chunk-3LA3EMDE.mjs +0 -15
- package/dist/chunk-5FRMCDPY.mjs +0 -16
- package/dist/chunk-5LEK2CBS.mjs +0 -2
- package/dist/chunk-5OFN5AHC.mjs +0 -2
- package/dist/chunk-5SIYS5HN.mjs +0 -2
- package/dist/chunk-5TEK3RAD.mjs +0 -2
- package/dist/chunk-7GHT2UCA.mjs +0 -15
- package/dist/chunk-ATCJYAR4.mjs +0 -2
- package/dist/chunk-C7HWOBIF.mjs +0 -2
- package/dist/chunk-E7VYDG2X.mjs +0 -2
- package/dist/chunk-FQGQH4KM.mjs +0 -2
- package/dist/chunk-GPF4YWWB.mjs +0 -9
- package/dist/chunk-GYQV7Y4J.mjs +0 -120
- package/dist/chunk-HQQMJCQJ.mjs +0 -10
- package/dist/chunk-IERUOGC3.mjs +0 -6
- package/dist/chunk-ITNLYXXV.mjs +0 -3
- package/dist/chunk-NFIBI4IP.mjs +0 -26
- package/dist/chunk-O52JMOCZ.mjs +0 -2
- package/dist/chunk-QMQUXTU4.mjs +0 -12
- package/dist/chunk-QVWVFC5K.mjs +0 -6
- package/dist/chunk-QZY6Q64C.mjs +0 -2
- package/dist/chunk-TDQP3DKQ.mjs +0 -10
- package/dist/chunk-V4CPWKMZ.mjs +0 -2
- package/dist/chunk-VACRB2NE.mjs +0 -3
- package/dist/chunk-W63L7367.mjs +0 -7
- package/dist/chunk-W7CXPCRV.mjs +0 -6
- package/dist/chunk-XINNG4F2.mjs +0 -4
- package/dist/chunk-YL2DPWVS.mjs +0 -4
- package/web/assets/index-B6Ai3wsa.js +0 -13
- package/web/assets/index-SYPC3EZy.css +0 -1
|
@@ -11,8 +11,12 @@ import { element, mount } from "../ui.mjs";
|
|
|
11
11
|
// (theirs stay theirs, a chart's gradients among them). The page's own rules are brought in as one
|
|
12
12
|
// stylesheet (made once, applied at once: no unstyled first frame), and each copy stands in a frame
|
|
13
13
|
// of its ancestors as the page has them (shallow copies, display: contents), so a list item keeps its
|
|
14
|
-
// marker and its number, and a section's paragraph its section's look.
|
|
15
|
-
//
|
|
14
|
+
// marker and its number, and a section's paragraph its section's look. A frame draws nothing of its
|
|
15
|
+
// own (visibility: hidden, the copy visible): display: contents leaves an element's ::before and
|
|
16
|
+
// ::after and a <details>'s own summary drawn (Chrome's "▶ 详细信息" for one without a summary, an
|
|
17
|
+
// ancestor item's marker, a flowchart step's number, each at the window's left or top), which would
|
|
18
|
+
// follow the pointer (the user's report of 2026-11-06). At most MAX blocks, each at most TALL of the
|
|
19
|
+
// window (cut, fading out at the bottom).
|
|
16
20
|
|
|
17
21
|
const MAX = 12;
|
|
18
22
|
const TALL = 0.6;
|
|
@@ -72,9 +76,9 @@ function copyOf(part, rect, top) {
|
|
|
72
76
|
}
|
|
73
77
|
const cut = rect.height > innerHeight * TALL;
|
|
74
78
|
if (cut) copy.classList.add("ge-cut");
|
|
75
|
-
// Its own size, as it was on the page: no share of a row or of its box (the window is the box here); inline, so the page's rules for the block cannot undo it.
|
|
79
|
+
// Its own size, as it was on the page: no share of a row or of its box (the window is the box here); inline, so the page's rules for the block cannot undo it. Visible, in frames that are not.
|
|
76
80
|
Object.assign(copy.style, {
|
|
77
|
-
position: "absolute", margin: "0", maxWidth: "none", minWidth: "0", maxHeight: "none", flex: "none",
|
|
81
|
+
position: "absolute", margin: "0", maxWidth: "none", minWidth: "0", maxHeight: "none", flex: "none", visibility: "visible",
|
|
78
82
|
left: `${rect.left}px`, top: `${rect.top}px`, width: `${rect.width}px`,
|
|
79
83
|
height: `${cut ? Math.round(innerHeight * TALL) : rect.height}px`,
|
|
80
84
|
});
|
|
@@ -82,6 +86,7 @@ function copyOf(part, rect, top) {
|
|
|
82
86
|
for (let node = part.parentElement; node && node !== top.parentElement; node = node.parentElement) {
|
|
83
87
|
const shell = clean(node.cloneNode(false));
|
|
84
88
|
shell.style.display = "contents";
|
|
89
|
+
shell.style.visibility = "hidden"; // a frame lends the copy its rules and draws nothing of its own
|
|
85
90
|
shell.append(outer);
|
|
86
91
|
outer = shell;
|
|
87
92
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import "../../shared/renamed-storage.mjs";
|
|
4
4
|
import { OUTER, can, captureLayout, editableAhead, firstHost, isHost, limitText, markFrames, markKinds, matchesSource, newHost, newMention, ownHTML, plainText, prepareBlock, splitBlock, textEnd, tidyEmptied, unitElement, withLeads } from "./core.mjs";
|
|
5
5
|
import { createBlocks } from "./blocks.mjs";
|
|
6
|
+
import { hiddenByFold, reveal } from "./folded.mjs";
|
|
6
7
|
import { createFlags } from "./flags.mjs";
|
|
7
8
|
import { createFrame } from "./frame.mjs";
|
|
8
9
|
import { createHistory } from "./history.mjs";
|
|
@@ -14,6 +15,7 @@ import { createCommits, kindOf } from "./commit.mjs";
|
|
|
14
15
|
import { createConflicts, packageChanged, unfit } from "./conflicts.mjs";
|
|
15
16
|
import { checkLeft, createAutosave, keepWith, lostKey, pendingKey, readLost, recover, reloadView, setReloader, takeView, viewNow } from "./autosave.mjs";
|
|
16
17
|
import { SOLO, connectWorkbench } from "./session.mjs";
|
|
18
|
+
import { lookOfElement } from "../../shared/document-look.mjs";
|
|
17
19
|
import { belowTargets, convertBlock, convertGroup, groupParents, groupTargets, noTextToCarry, targetsOf, touchedBy, turnInto, turnParents, turnUnit, typeOf } from "./convert.mjs";
|
|
18
20
|
import { joinCode, rangeAt, rangeOffsets } from "./marks.mjs";
|
|
19
21
|
import { addStyle, button, copyAddress, element, layer } from "./ui.mjs";
|
|
@@ -26,7 +28,8 @@ import { bookmarkItems, connectViews, linkTitle, offerViews } from "./links/view
|
|
|
26
28
|
import { connectChipFills } from "./chip-fills.mjs";
|
|
27
29
|
import { connectFormula, dismissFormula, formulaBoxNode, loadKatex, openFormula } from "./formula/index.mjs";
|
|
28
30
|
import { settlePads } from "./pads.mjs";
|
|
29
|
-
import {
|
|
31
|
+
import { followLongRuns } from "./long-runs.mjs";
|
|
32
|
+
import { beforeDelete, codeArrow, codeClick, codePress, deletedBack, deletingBack, settleCodeEdge, takeEntry } from "./typing/code-edges.mjs";
|
|
30
33
|
import { createMarkdown } from "./markdown/index.mjs";
|
|
31
34
|
import { createResize } from "./resize/index.mjs";
|
|
32
35
|
import { connectPages, fieldOpen, keptByComponent, menuRow, modalOps, pageAt, pageIcon, pageObjects, pageOf, pageOfHost, pageOfType, pageOfUnit, panelOpen, typedAsIs } from "./page-objects.mjs";
|
|
@@ -42,6 +45,7 @@ import { createSelectAll, topStep } from "./select-all/index.mjs";
|
|
|
42
45
|
import { revealText } from "./find/index.mjs";
|
|
43
46
|
import { createOutline } from "./outline/index.mjs";
|
|
44
47
|
import { createAnnotate } from "./annotate/index.mjs";
|
|
48
|
+
import { createChanges as createAgentChanges } from "./changes/index.mjs";
|
|
45
49
|
import { BLOCK_TYPES, HOSTS, PLAIN_TEXT, TYPE_INFO, accepts, blankSaysOf, boxOwner, texOnly, textFilters } from "../components/registry.mjs";
|
|
46
50
|
import { createPages } from "../components/pages.mjs";
|
|
47
51
|
import { openMediaPicker } from "./emoji-picker/index.mjs";
|
|
@@ -77,6 +81,7 @@ import { language, t } from "../../shared/i18n/index.mjs";
|
|
|
77
81
|
// select-all/ Ctrl+A: the block's text, then its container's blocks, one level a press, then the page
|
|
78
82
|
// outline/ 目录: the page's headings at its right (the room there is margin.mjs's)
|
|
79
83
|
// annotate/ 批注: started from the format bar, a block's button or Ctrl+Alt+M; cards in the margin, with no room markers in the gutter and the card by the words
|
|
84
|
+
// changes/ the Agent's changes (设置 › 显示变更): what an Agent wrote since the reader last kept or reverted it, marked; the bar at the bottom
|
|
80
85
|
// blocks.mjs the block tools: handle/, block-menu/, selection/, drag/
|
|
81
86
|
//
|
|
82
87
|
// and the components' own editing (src/editor/components/<name>/page.mjs). Undo and redo are
|
|
@@ -103,6 +108,7 @@ let markdown = null; // Markdown shortcuts as the reader types (markdown/)
|
|
|
103
108
|
let selectAll = null; // Ctrl+A widening step by step (select-all/)
|
|
104
109
|
let outline = null; // the page's headings at its right (outline/), not on a page opened on its own (?solo)
|
|
105
110
|
let annotate = null; // 批注 (annotate/), on every page of a session
|
|
111
|
+
let agentChanges = null; // what an Agent changed, under review (changes/), on every page of a session
|
|
106
112
|
let editing = false;
|
|
107
113
|
let composing = false; // an input method is composing
|
|
108
114
|
// A composition ends with compositionend, which Chrome does not always send (a paste over the text
|
|
@@ -112,6 +118,7 @@ const compositionOver = (event) => {
|
|
|
112
118
|
if (composing && !event.isComposing && event.keyCode !== 229) composing = false;
|
|
113
119
|
};
|
|
114
120
|
let pressing = false; // the main button is down on the page (a click or a drag under way)
|
|
121
|
+
let pressedText = null; // the text block a press of the main button came down in (onPointerDown), for the click that ends it
|
|
115
122
|
let commits = null; // the page's commits (commit.mjs)
|
|
116
123
|
let autosave = null; // when they go (autosave.mjs)
|
|
117
124
|
let conflicts = null; // what the file refused, for the reader to decide (conflicts.mjs)
|
|
@@ -150,7 +157,8 @@ const STYLE = `
|
|
|
150
157
|
as the element's own outline. Selected blocks get a fill instead (selection/). */
|
|
151
158
|
/* Editable text has a text block's corners and, framed, a light fill under the pointer, unless its
|
|
152
159
|
component declares others: --ge-text-radius, and --ge-text-tint (none: plain, as Notion's and
|
|
153
|
-
Feishu's; a cell, a
|
|
160
|
+
Feishu's; a cell, a code block and its title, a disclosure's title, a media block's
|
|
161
|
+
caption, a card's title and caption). */
|
|
154
162
|
[data-ge-editing] [contenteditable="true"] { border-radius: var(--ge-text-radius, 3px); }
|
|
155
163
|
[data-ge-editing] [contenteditable="true"]:focus { outline: none; }
|
|
156
164
|
[data-ge-editing] [data-ge-round="box"] { border-radius: 8px; }
|
|
@@ -307,9 +315,10 @@ connectPages(createPages({
|
|
|
307
315
|
})); // what the engines ask of a component (page-objects.mjs)
|
|
308
316
|
|
|
309
317
|
const typing = createTyping({
|
|
310
|
-
struct, say, keepText: (node) => blocks.keepText(node), paragraphBefore: insert.paragraphBefore,
|
|
318
|
+
struct, say, keepText: (node) => blocks.keepText(node), paragraphBefore: insert.paragraphBefore, removeBlocks: (units) => blocks.remove(units), selectBlock: (unit) => blocks.select(unit),
|
|
311
319
|
adding: () => slash?.adding ?? null,
|
|
312
320
|
leave: createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }),
|
|
321
|
+
showHidden: (node) => blocks?.folds.showAround(node), // a folded heading's section opened before a join takes in its words (fold/)
|
|
313
322
|
});
|
|
314
323
|
// Selecting text across blocks: its listeners go before the editor's own keys and clipboard.
|
|
315
324
|
const crossText = createTextSelection({
|
|
@@ -411,6 +420,8 @@ function enter() {
|
|
|
411
420
|
});
|
|
412
421
|
layout = captureLayout(document, MAP);
|
|
413
422
|
markFrames(document, layout, hosts);
|
|
423
|
+
// A text block holding a long run (a path, a URL) breaks anywhere, judged now and as its text changes (long-runs.mjs).
|
|
424
|
+
followLongRuns(document.querySelector("main") ?? document.body);
|
|
414
425
|
commits = createCommits({ root: document, map: MAP, baselines, units, boxes, getLayout: () => layout, setLayout: (next) => (layout = next) });
|
|
415
426
|
// Commits wait while an input method composes, a formula is being edited (formula/), the "/" menu
|
|
416
427
|
// or the "@" menu stands on what is typed for it (half of it is no text of the file's) or a gap
|
|
@@ -433,6 +444,7 @@ function enter() {
|
|
|
433
444
|
conflicts = createConflicts({ act: decide, nodeOf: conflictNode, restorable, copyBlock: (node) => clipboard.copyBlocks([node]), say });
|
|
434
445
|
editing = true;
|
|
435
446
|
document.documentElement.setAttribute("data-ge-editing", "");
|
|
447
|
+
blocks?.folds.start(); // what was folded, folded again in this task: no frame shows it open (fold/)
|
|
436
448
|
refresh();
|
|
437
449
|
for (const page of pageObjects()) page.entered?.();
|
|
438
450
|
}
|
|
@@ -454,6 +466,7 @@ const keepsOverwrite = (asked) => !asked && [...overwrites.values()].some(({ lan
|
|
|
454
466
|
// A commit was taken in (commit.mjs): a block merged with someone else's words shows the merge;
|
|
455
467
|
// what the file refused is flagged and held back, the rest goes on.
|
|
456
468
|
function committed({ conflicts: held, merged, outdated, forced = [] }, receipt) {
|
|
469
|
+
agentChanges?.committed(receipt);
|
|
457
470
|
for (const host of merged) history.merged(host);
|
|
458
471
|
for (const unit of forced) {
|
|
459
472
|
const written = overwrites.get(unit);
|
|
@@ -757,7 +770,7 @@ function convertUnit(unit, type, { loaded = false } = {}) {
|
|
|
757
770
|
if (!made || !onCreated(type, result.focus)) {
|
|
758
771
|
if (emptied && isHost(result.focus)) caretAt(result.focus, "start");
|
|
759
772
|
else {
|
|
760
|
-
// What it is now: the new highlight block a block went into, as a disclosure (notion-lite's
|
|
773
|
+
// What it is now: the new highlight block or callout a block went into, as a disclosure (notion-lite's
|
|
761
774
|
// transformBlocks selects the callout), the flowchart a block or a list went into (a container
|
|
762
775
|
// of a type that takes a block as it is, no `wraps`), else the block holding the text.
|
|
763
776
|
const { container, wraps } = BLOCK_TYPES[type];
|
|
@@ -946,6 +959,18 @@ function onBeforeInput(event) {
|
|
|
946
959
|
} else if (type === "insertLineBreak" && can(host, "plain")) {
|
|
947
960
|
event.preventDefault();
|
|
948
961
|
say(limitText(host, "split"));
|
|
962
|
+
} else if (/^delete[A-Za-z]+(Backward|Forward)$/.test(type) && !event.isComposing && textFilters(host)) {
|
|
963
|
+
// Backspace or Delete beside a component's entry whose keydown onKeydown passed by (an input
|
|
964
|
+
// method's, keyCode 229): the whole entry, as there (typing/code-edges.mjs takeEntry). A
|
|
965
|
+
// deletion backward the browser does: the caret kept outside inline code it comes to (deletedBack).
|
|
966
|
+
const back = type.endsWith("Backward");
|
|
967
|
+
const before = type === "deleteContentBackward" || type === "deleteContentForward" ? ownHTML(host) : null;
|
|
968
|
+
const removed = before !== null ? takeEntry(host, back) : undefined;
|
|
969
|
+
if (removed) {
|
|
970
|
+
event.preventDefault();
|
|
971
|
+
recordStep(host, before);
|
|
972
|
+
say(removed);
|
|
973
|
+
} else if (back) deletingBack(host);
|
|
949
974
|
} else if (type.startsWith("format")) {
|
|
950
975
|
event.preventDefault(); // formatting goes through format-bar/: the kit's markup only
|
|
951
976
|
} else if (type === "insertFromDrop" || type === "deleteByDrag") {
|
|
@@ -974,6 +999,7 @@ function onInput(event) {
|
|
|
974
999
|
}
|
|
975
1000
|
// What stood between two pieces of inline code deleted: they are one (marks.mjs joinCode).
|
|
976
1001
|
if (event.inputType.startsWith("delete") && textFilters(host)) joinCode(host);
|
|
1002
|
+
if (event.inputType.startsWith("delete") && event.inputType.endsWith("Backward") && textFilters(host)) deletedBack(host);
|
|
977
1003
|
pageOf(host)?.typed?.(host);
|
|
978
1004
|
recordText(host);
|
|
979
1005
|
markdown.typed(host, event.data);
|
|
@@ -1012,6 +1038,7 @@ function onPointerDown(event) {
|
|
|
1012
1038
|
hideHint();
|
|
1013
1039
|
endArrowRun();
|
|
1014
1040
|
if (event.button === 0) pressing = true;
|
|
1041
|
+
pressedText = event.button === 0 && editing ? editable(event.target) : null;
|
|
1015
1042
|
// What the press came down on may take it, by its component's `press`: code opens for editing, a
|
|
1016
1043
|
// display formula goes into the formula editor, and no caret goes in.
|
|
1017
1044
|
if (editing && event.button === 0 && pageAt(event.target)?.press?.(event)) return;
|
|
@@ -1033,6 +1060,9 @@ function onSelectionChange() {
|
|
|
1033
1060
|
formatting.schedule();
|
|
1034
1061
|
if (!composing) formatting.moved();
|
|
1035
1062
|
const selection = getSelection();
|
|
1063
|
+
// The caret, or an end of a text selection, in what a folded heading hides (undo put it back there):
|
|
1064
|
+
// the fold opens (fold/).
|
|
1065
|
+
for (const end of [selection.anchorNode, selection.focusNode]) if (end && hiddenByFold(end)) blocks?.folds.showAround(end);
|
|
1036
1066
|
const host = selection.rangeCount ? editable(selection.anchorNode) : null;
|
|
1037
1067
|
// A text block no step named, one a block made on the page came with: what the caret finds there is
|
|
1038
1068
|
// what the first change of it undoes to, as a change is only seen once made.
|
|
@@ -1173,7 +1203,10 @@ const COMMANDS = {
|
|
|
1173
1203
|
},
|
|
1174
1204
|
// 搜索文档 opened the report at a hit: its words scrolled into view and marked for a moment (find/).
|
|
1175
1205
|
async reveal(message) {
|
|
1176
|
-
return revealText(message, (node) =>
|
|
1206
|
+
return revealText(message, (node) => {
|
|
1207
|
+
blocks?.folds.showAround(node); // a folded heading's section opened (fold/)
|
|
1208
|
+
return modalOps().show(node);
|
|
1209
|
+
});
|
|
1177
1210
|
},
|
|
1178
1211
|
// A link or an address opened the report at a block.
|
|
1179
1212
|
async "reveal-block"({ block }) {
|
|
@@ -1222,11 +1255,12 @@ const COMMANDS = {
|
|
|
1222
1255
|
// ---------- links to blocks and documents ----------
|
|
1223
1256
|
|
|
1224
1257
|
// The block of this id, once the page is drawn (what its charts move is moved by then), or an element
|
|
1225
|
-
// of this id (an address may name a heading's): what hides it opened (
|
|
1226
|
-
// detail card that does not hold it closed, a
|
|
1227
|
-
//
|
|
1228
|
-
//
|
|
1229
|
-
// then, so it is brought there again before it is
|
|
1258
|
+
// of this id (an address may name a heading's): what hides it opened (a folded heading's section,
|
|
1259
|
+
// folded.mjs reveal, then the kit's DocKit.reveal: a detail card that does not hold it closed, a
|
|
1260
|
+
// disclosure, a tab, the card it is in), in the middle of the window and selected, as notion-lite's
|
|
1261
|
+
// revealBlock, and the keys are the page's. What was just shown lays itself out in the frames after (a
|
|
1262
|
+
// tab's tables) and a card closed gives the focus back then, so it is brought there again before it is
|
|
1263
|
+
// selected. A block that is gone is said, unless
|
|
1230
1264
|
// `quiet`, the page staying as it is; #top with no such element is the top of the page, as for a browser.
|
|
1231
1265
|
// A later step (a link, the way back or forth, an address) started past its waits leaves it there.
|
|
1232
1266
|
async function revealBlock(id, { quiet = false } = {}) {
|
|
@@ -1239,7 +1273,7 @@ async function revealBlock(id, { quiet = false } = {}) {
|
|
|
1239
1273
|
else if (!quiet) say(t("这个块已经不在了。"));
|
|
1240
1274
|
return { ok: false, reason: "missing" };
|
|
1241
1275
|
}
|
|
1242
|
-
|
|
1276
|
+
reveal(block); // a fold over it too (fold/)
|
|
1243
1277
|
block.scrollIntoView({ block: "center" });
|
|
1244
1278
|
await painted();
|
|
1245
1279
|
await painted();
|
|
@@ -1418,7 +1452,10 @@ function handOff() {
|
|
|
1418
1452
|
// The workbench around the page, if any: it hears the page's state and notices, and asks it to save,
|
|
1419
1453
|
// close and show the report again.
|
|
1420
1454
|
function connect() {
|
|
1421
|
-
|
|
1455
|
+
// The look the page shows (字体与布局: its <html>'s, src/shared/document-look.mjs), which the workbench's
|
|
1456
|
+
// 更多 marks as chosen; told again when it changes (the kit's ui.js, doc-look-change).
|
|
1457
|
+
workbench = connectWorkbench({ slug: MAP.slug, snapshot: () => ({ title: currentTitle(), icon: pageIcon(), look: lookOfElement(document.documentElement), state: sessionState(), annotations: annotate?.count() }), commands: COMMANDS, modals: modalOps() });
|
|
1458
|
+
addEventListener("doc-look-change", () => workbench?.update());
|
|
1422
1459
|
relayTo(workbench ? workbench.notice : null, workbench ? workbench.noticeRoom : null); // the workbench shows the page's notices, above the page's bottom panels
|
|
1423
1460
|
handOff();
|
|
1424
1461
|
// A page on its own in a frame (?solo: the 写作偏好 dialog's, which no session asks to save) is saved
|
|
@@ -1471,6 +1508,7 @@ async function start() {
|
|
|
1471
1508
|
else if (typeof state.docBlock === "string") revealBlock(state.docBlock, { quiet: true });
|
|
1472
1509
|
});
|
|
1473
1510
|
annotate?.start();
|
|
1511
|
+
agentChanges?.start();
|
|
1474
1512
|
const open = await openTabs();
|
|
1475
1513
|
if (open.has(TAB)) { // a duplicated tab: its own id from now on
|
|
1476
1514
|
TAB = newTab();
|
|
@@ -1569,7 +1607,7 @@ function boot() {
|
|
|
1569
1607
|
atMenu = createAtMenu({ composing: () => composing, page: thisPage, recordText, recordStep });
|
|
1570
1608
|
markdown = createMarkdown({ slash, at: atMenu, convert: convertHost, recordStep });
|
|
1571
1609
|
blocks = createBlocks({
|
|
1572
|
-
units, boxes, active, struct, look: lookStep, say, edit: editBlock, turnInto, convert: convertUnit, turnIntoAll: groupTargets, convertAll, add: insert.addAfter, after: insert.paragraphAfter,
|
|
1610
|
+
slug: MAP.slug, units, boxes, active, struct, look: lookStep, say, edit: editBlock, turnInto, convert: convertUnit, turnIntoAll: groupTargets, convertAll, add: insert.addAfter, after: insert.paragraphAfter,
|
|
1573
1611
|
below: insertBelow, belowTypes: belowTargets,
|
|
1574
1612
|
blank: insert.clickBlank, nest: (units, delta) => pageObjects().some((page) => page.nestBlocks?.(units, delta)),
|
|
1575
1613
|
keepsHandle: (node) => tables?.holds(node) ?? false,
|
|
@@ -1605,14 +1643,30 @@ function boot() {
|
|
|
1605
1643
|
changed: () => workbench?.update(),
|
|
1606
1644
|
removed: (items) => workbench?.annotationsRemoved(items),
|
|
1607
1645
|
});
|
|
1646
|
+
// Read at once, drawn once the page is ready; commits and autosave are made as the page edits (enter).
|
|
1647
|
+
if (!SOLO) agentChanges = createAgentChanges({
|
|
1648
|
+
slug: MAP.slug, token: MAP.token, commits: () => commits, autosave: () => autosave, say, session,
|
|
1649
|
+
across: crossText, // a selection across blocks, kept on its words as the marks go and come
|
|
1650
|
+
flush: async () => {
|
|
1651
|
+
checkAll();
|
|
1652
|
+
return (await autosave?.flush()) ?? "nothing";
|
|
1653
|
+
},
|
|
1654
|
+
});
|
|
1608
1655
|
document.addEventListener("pointerup", (event) => {
|
|
1609
1656
|
pressing = false;
|
|
1610
1657
|
formatting.released();
|
|
1611
|
-
// A click at an edge of inline code: the caret on the side it was made on
|
|
1658
|
+
// A click at an edge of inline code or an entry: the caret on the side it was made on, when the
|
|
1659
|
+
// press came down on that text; a press elsewhere that put the caret there (a card's backdrop,
|
|
1660
|
+
// which closed it and put the caret at its entry; the page's empty space) leaves it at the stop
|
|
1661
|
+
// it is at.
|
|
1612
1662
|
const selection = getSelection();
|
|
1613
1663
|
const host = editing && event.button === 0 && selection.rangeCount && selection.isCollapsed ? editable(selection.anchorNode) : null;
|
|
1664
|
+
const pressed = pressedText;
|
|
1665
|
+
pressedText = null;
|
|
1614
1666
|
if (host && outOfAtom(event.clientX)) return; // a click beside a formula that put the caret in it
|
|
1615
|
-
if (host
|
|
1667
|
+
if (!host || !textFilters(host)) return;
|
|
1668
|
+
if (pressed && (pressed === host || pressed.contains(host))) codeClick(host, event.clientX);
|
|
1669
|
+
else settleCodeEdge(host);
|
|
1616
1670
|
}, true);
|
|
1617
1671
|
document.addEventListener("focusin", passTab, true);
|
|
1618
1672
|
document.addEventListener("compositionstart", (event) => {
|
|
@@ -1711,6 +1765,7 @@ function boot() {
|
|
|
1711
1765
|
checkAll();
|
|
1712
1766
|
autosave?.leave();
|
|
1713
1767
|
annotate?.leave();
|
|
1768
|
+
agentChanges?.leave();
|
|
1714
1769
|
});
|
|
1715
1770
|
document.addEventListener("visibilitychange", () => {
|
|
1716
1771
|
if (!document.hidden || !autosave) return;
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
// Taken over from notion-lite (its src/ui/media-picker/emoji-tab.js)
|
|
2
|
-
// Gallery's own (support.mjs, src/shared/emoji/)
|
|
1
|
+
// Taken over from notion-lite (its src/ui/media-picker/emoji-tab.js): its structure and behaviour as
|
|
2
|
+
// there, what it imports Gallery's own (support.mjs, src/shared/emoji/), and since 2026-11 (the user's
|
|
3
|
+
// word) its look Gallery's own (styles.mjs: the editor's palette, no blue), no 旗帜 group (the data holds
|
|
4
|
+
// no flag: src/shared/emoji/data/README.md), every emoji a Twemoji picture on every system, the skin
|
|
5
|
+
// button's hand too (the system's font only for one the pack lacks), and a group's title sticking to
|
|
6
|
+
// the list's top. Its notes, below, are notion-lite's, those changes written in.
|
|
3
7
|
/* “表情符号”页签(943244 EmojiPicker、885963 选肤色、625478 格子和肤色变体;尺寸是线上实测)。
|
|
4
|
-
* 分组:最近(筛选词为空时)、标注(从标注打开时,固定 26
|
|
8
|
+
* 分组:最近(筛选词为空时)、标注(从标注打开时,固定 26 个)、人物、动物与自然、食物与饮料、活动、旅行与地点、物品、符号(没有旗帜:Gallery 整组去掉)、
|
|
5
9
|
* 自定义(本机的自定义表情,按名字排;第一个格子是“添加表情符号”的圆形加号)
|
|
6
|
-
* 每行 (408 − 24) / 32 = 12 个;标题 12px / 500
|
|
10
|
+
* 每行 (408 − 24) / 32 = 12 个;标题 12px / 500、高 28,滚动时钉在列表顶上;格子 32×32、圆角 6、表情 24(Twemoji 图,../emoji/emoji.js)
|
|
7
11
|
* 筛选(943244 W):按关键词打分——筛选词里有这个表情 > “:筛选词” > 关键词等于 > 关键词开头 > 多个词都对上 > 包含,常用的加分;
|
|
8
12
|
* 自定义表情的关键词是它的名字(871871 g)。结果(连同加号)超过 12 × 12 / 2 = 72 个时仍按分组显示,否则拍平成一组按分数排
|
|
9
13
|
* (加号排最后);只剩加号时显示“无结果”和“添加表情符号”按钮
|
|
10
|
-
* 底部分类栏(943244 y):上边一条 --
|
|
11
|
-
*
|
|
14
|
+
* 底部分类栏(943244 y):上边一条 --ge-line,内边距 6 12 8;按钮 28×28、图标 18;当前滚到的分组按钮有底色;
|
|
15
|
+
* 没有表情的分组按钮半透明不可点(“自定义”“添加”总能点);悬停提示分组名(左对齐、在下方);点了把那一组(连同组名)滚到顶上,
|
|
12
16
|
* “添加”打开“添加表情符号”浮层。筛选结果拍平时不显示
|
|
13
|
-
* 最近(943244 F):常用表情按次数、时间排,取 2
|
|
17
|
+
* 最近(943244 F):常用表情按次数、时间排,取 2 行,只取数据还认得的和自定义表情(以前用过的旗不再出现);打开时读一次;
|
|
18
|
+
* 选中一个表情记一次(../emoji/data.js recordEmojiUse)
|
|
14
19
|
* 格子(625478):没设过肤色时点有肤色变体的表情,先弹出一排变体(选了正好 5 个变体的就记下肤色);
|
|
15
20
|
* 自定义表情(758388)24×24、contain,提示是它的名字
|
|
16
|
-
* 右边按钮(885963):选肤色,28×28
|
|
21
|
+
* 右边按钮(885963):选肤色,28×28、18 的“✋”(Twemoji 图,设过就是那个肤色的手;数据到了再画),点开一排六只手
|
|
17
22
|
* 随机(859941):活动 / 物品 / 旅行与地点里随便一个,选上但不关菜单
|
|
18
23
|
* 添加表情符号(943244 Y → 757573 → 749527 tM):在加号 / 底栏按钮 / 无结果按钮下面打开 ./upload.js 的浮层;
|
|
19
24
|
* 存好以后交给 env.uploaded(选上这个表情、关菜单)
|
|
@@ -52,7 +57,6 @@ const CATEGORIES = [
|
|
|
52
57
|
{ id: 'travel', category: 'Travel & Places', title: t("旅行与地点"), icon: 'airplane' },
|
|
53
58
|
{ id: 'objects', category: 'Objects', title: t("物品"), icon: 'lightBulbBright' },
|
|
54
59
|
{ id: 'symbols', category: 'Symbols', title: t("符号"), icon: 'checkmarkCircle' },
|
|
55
|
-
{ id: 'flags', category: 'Flags', title: t("旗帜"), icon: 'flag' },
|
|
56
60
|
{ id: 'custom', title: t("自定义"), icon: 'squareGrid2X2' },
|
|
57
61
|
{ id: 'add', title: ADD_LABEL, icon: 'plusCircle' },
|
|
58
62
|
];
|
|
@@ -89,7 +93,7 @@ function rank(emoji, filter, splitFilter) {
|
|
|
89
93
|
|
|
90
94
|
/* 943244 W:分好组、切成一行行。返回 { categorized, rows: [{ id, title?, emojis }] };只剩加号时 rows 是 [{ emojis: [ADD] }] */
|
|
91
95
|
function buildRows(rawFilter, isCallout, recent) {
|
|
92
|
-
const cats = [!rawFilter.trim() ? CATEGORY.recent : null, isCallout ? CATEGORY.callout : null, ...CATEGORIES.
|
|
96
|
+
const cats = [!rawFilter.trim() ? CATEGORY.recent : null, isCallout ? CATEGORY.callout : null, ...CATEGORIES.filter(c => c.category), CATEGORY.custom].filter(Boolean);
|
|
93
97
|
const filter = normalizeFilter(rawFilter) ?? '';
|
|
94
98
|
const split = rawFilter.split(' ').filter(Boolean);
|
|
95
99
|
const rows = [];
|
|
@@ -152,7 +156,7 @@ export function createEmojiTab(env) {
|
|
|
152
156
|
el.className = 'nmm-body';
|
|
153
157
|
el.innerHTML = `<div class="nmm-scroller notion-scroller vertical"><div role="grid" class="nmm-grid"></div></div><div class="nmm-categories"></div>`;
|
|
154
158
|
const grid = el.querySelector('.nmm-grid'), scroller = el.querySelector('.nmm-scroller'), bar = el.querySelector('.nmm-categories');
|
|
155
|
-
|
|
159
|
+
let recent = null; // read once, when the data is in (render; Notion's: not reordered while open)
|
|
156
160
|
let view = { categorized: true, rows: [] }, lastFilter = '', addPopup = null;
|
|
157
161
|
const focus = createGridFocus({ scroller, grid, rows: () => view.rows.map(r => r.emojis.length) });
|
|
158
162
|
|
|
@@ -174,6 +178,10 @@ export function createEmojiTab(env) {
|
|
|
174
178
|
function render(filter) {
|
|
175
179
|
lastFilter = filter;
|
|
176
180
|
if (!emojiDataLoaded()) { grid.innerHTML = ''; bar.hidden = true; view = { categorized: true, rows: [] }; return; } // 数据加载完再画
|
|
181
|
+
if (recent === null) { // 数据到了:最近(只要还认得的,去掉的旗不再出现)读一次,选肤色的手画成 Twemoji 图
|
|
182
|
+
recent = recentEmojis(PER_ROW, e => isCustomEmojiString(e) || Boolean(emojiInfo(e)));
|
|
183
|
+
paintSkin();
|
|
184
|
+
}
|
|
177
185
|
view = buildRows(filter, env.isCallout, recent);
|
|
178
186
|
const { rows } = view;
|
|
179
187
|
let html = '';
|
|
@@ -205,7 +213,7 @@ export function createEmojiTab(env) {
|
|
|
205
213
|
const present = new Set(view.rows.map(r => r.id));
|
|
206
214
|
const enabled = c => c.id === 'custom' || c.id === 'add' || present.has(c.id);
|
|
207
215
|
bar.innerHTML = CATEGORIES.filter(c => c.id !== 'callout').map(c =>
|
|
208
|
-
`<div role="button" tabindex="-1" class="nmm-category${enabled(c) ? '' : ' disabled'}" data-category="${c.id}" aria-label="${t("跳转到类别:{0}", esc(c.category ?? c.id))}" aria-pressed="false"${enabled(c) ? '' : ' aria-disabled="true"'}>${icon(c.icon,
|
|
216
|
+
`<div role="button" tabindex="-1" class="nmm-category${enabled(c) ? '' : ' disabled'}" data-category="${c.id}" aria-label="${t("跳转到类别:{0}", esc(c.category ?? c.id))}" aria-pressed="false"${enabled(c) ? '' : ' aria-disabled="true"'}>${icon(c.icon, 18)}</div>`).join('');
|
|
209
217
|
for (const b of bar.children) hoverTooltip(b, CATEGORY[b.dataset.category].title, { placement: 'bottom', align: 'start' });
|
|
210
218
|
updateBarFocus();
|
|
211
219
|
}
|
|
@@ -258,7 +266,8 @@ export function createEmojiTab(env) {
|
|
|
258
266
|
right.className = 'nmm-skin-wrap';
|
|
259
267
|
right.innerHTML = `<div role="button" tabindex="0" class="nmm-skin" data-act="skin"></div>`;
|
|
260
268
|
const skinBtn = right.firstElementChild;
|
|
261
|
-
|
|
269
|
+
// The hand as a Twemoji picture (a placeholder of its size until the data is in: render paints it again then).
|
|
270
|
+
function paintSkin() { skinBtn.innerHTML = emojiHTML(SKIN_TONE_HANDS[getSkinTone() ?? 0], { size: 18 }); }
|
|
262
271
|
paintSkin();
|
|
263
272
|
hoverTooltip(skinBtn, t("选择肤色"), { placement: 'bottom' });
|
|
264
273
|
skinBtn.addEventListener('click', () => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
// Taken over from notion-lite (its src/ui/media-picker/grid.js)
|
|
2
|
-
//
|
|
1
|
+
// Taken over from notion-lite (its src/ui/media-picker/grid.js): what it imports is Gallery's own
|
|
2
|
+
// (support.mjs, src/shared/emoji/), its look too (styles.mjs: a deeper gray, no blue ring), and a cell the
|
|
3
|
+
// keys reach stays below a group's title stuck at the list's top. Its notes, below, are notion-lite's.
|
|
3
4
|
/* 表情 / 图标格子共用的焦点(558045 Grid + 625478 / 485357 H 的提示):
|
|
4
|
-
*
|
|
5
|
+
* 鼠标悬停和方向键共用一个焦点(有底色);方向键不绕回,上下按列对齐(短的一行取最后一个);键盘移动时焦点格是更深的灰底、
|
|
5
6
|
* 滚进视野,并且一直显示名字(forceVisibleState);鼠标悬停 150ms 后在下方显示名字(closeDelay 0)。
|
|
6
7
|
* 懒加载:格子里 img[data-src] / img[data-svg](表情包里的码点)滚到附近才换成 src(../emoji/emoji.js lazySrc;矢量表情一千多张,一次全做太慢)。
|
|
7
8
|
* 格子是 .nmm-cell[data-r][data-c],提示文字在 data-tip(没有就用 aria-label)。
|
|
@@ -25,8 +26,9 @@ export function createGridFocus({ scroller, grid, rows }) {
|
|
|
25
26
|
cell.classList.add('focused');
|
|
26
27
|
if (!byKeyboard) return;
|
|
27
28
|
cell.classList.add('focus-visible');
|
|
28
|
-
const
|
|
29
|
-
|
|
29
|
+
const cover = grid.querySelector('.nmm-section-title')?.offsetHeight ?? 0; // a group's title stays at the top (styles.mjs: sticky); a flat search has none
|
|
30
|
+
const cr = cell.getBoundingClientRect(), sr = scroller.getBoundingClientRect(), top = sr.top + cover;
|
|
31
|
+
if (cr.top < top) scroller.scrollTop -= top - cr.top;
|
|
30
32
|
else if (cr.bottom > sr.bottom) scroller.scrollTop += cr.bottom - sr.bottom;
|
|
31
33
|
if (tipOf(cell)) showTooltip(cell.getBoundingClientRect(), tipOf(cell), { placement: 'bottom' });
|
|
32
34
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The 图标 tab (notion-lite's src/ui/media-picker/icon-tab.js, its grid
|
|
1
|
+
// The 图标 tab (notion-lite's src/ui/media-picker/icon-tab.js, its grid and behaviour as there, its look Gallery's own: styles.mjs),
|
|
2
2
|
// its icons Gallery's own: two open-source sets of the same 443 things, MingCute and Tabler, and
|
|
3
3
|
// Tabler's 40 numbers, in 12 categories (src/shared/emoji/glyphs.mjs). Its notes, below, are
|
|
4
4
|
// notion-lite's, the icons' own changed.
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* 数字只有 Tabler 有:切换时不动,选中的也总是 Tabler 的值(提示里写明 Tabler)
|
|
14
14
|
* 颜色(icon_picker_color):设了就直接用这个颜色插入、格子也显示这个颜色;没设(“每次询问”)时格子显示默认灰色,
|
|
15
15
|
* 点一下先弹出 10 种颜色(两行各 5 个、行内边距 2、间距 1,贴在格子下面)再选
|
|
16
|
-
* 右边按钮(q):选图标颜色——28×28
|
|
17
|
-
* 菜单
|
|
16
|
+
* 右边按钮(q):选图标颜色——28×28 无框,圆圈图标描边 / 填充是当前颜色(没设时描边浅灰、填充 --ge-ico3);
|
|
17
|
+
* 菜单 160 宽:两行色块(26×26、圆角 6,没设颜色时这两行半透明)+ 分隔线下“每次询问”开关(开是中性灰,不用蓝)
|
|
18
18
|
* 随机:随便一组里这一套的图标,颜色用设好的,没设就随便一种;选上但不关菜单
|
|
19
19
|
* 选中一个图标:记进最近(按组记,两套共用),值是 `/icons/<名字>_<颜色>.svg`(MingCute)或 `/icons/tabler/<名字>_<颜色>.svg`(数字总是这个)。
|
|
20
20
|
* createIconTab(env) → { el, left, right, load(), render(filter), move(key), activateFocused(), random() }
|
|
@@ -178,7 +178,7 @@ export function createIconTab(env) {
|
|
|
178
178
|
function paintColor() {
|
|
179
179
|
const color = getIconColor(), values = ICON_COLOR_BY_THEME[theme()];
|
|
180
180
|
colorBtn.setAttribute('aria-label', t("选择图标颜色,已选定 {0}", color ? colorWord(color) : t("无颜色")));
|
|
181
|
-
colorBtn.innerHTML = `<svg viewBox="0 0 16 16" aria-hidden="true" style="width:14px;height:14px;display:block;stroke:${color ? values[color] : values.lightgray};fill:${color ? values[color] : 'var(--
|
|
181
|
+
colorBtn.innerHTML = `<svg viewBox="0 0 16 16" aria-hidden="true" style="width:14px;height:14px;display:block;stroke:${color ? values[color] : values.lightgray};fill:${color ? values[color] : 'var(--ge-ico3)'}">${CIRCLE_16}</svg>`;
|
|
182
182
|
}
|
|
183
183
|
paintColor();
|
|
184
184
|
hoverTooltip(colorBtn, t("选择图标颜色"), { placement: 'bottom' });
|
|
@@ -13,7 +13,6 @@ const ICONS = {
|
|
|
13
13
|
airplane: svg('<path d="M17.25 10c0-.9-.8-1.5-1.7-1.5H11L7.5 3.5H5.75l1.75 5H4.25L3 7H2l.75 3L2 13h1l1.25-1.5H7.5l-1.75 5H7.5L11 11.5h4.55c.9 0 1.7-.6 1.7-1.5z"/>'),
|
|
14
14
|
lightBulbBright: svg('<path d="M10 2.75a5 5 0 0 0-3 9c.6.5 1 1.2 1 2v.5h4v-.5c0-.8.4-1.5 1-2a5 5 0 0 0-3-9z"/><path d="M8.25 16.5h3.5"/>'),
|
|
15
15
|
checkmarkCircle: svg('<circle cx="10" cy="10" r="7.25"/><path d="m6.75 10.25 2.4 2.4 4.1-4.9"/>'),
|
|
16
|
-
flag: svg('<path d="M5.25 17V3.75"/><path d="M5.25 4.75c2.5-1.5 4.5 1.5 7 0 1-.6 2-.8 2.75-.7v6.5c-.75-.1-1.75.1-2.75.7-2.5 1.5-4.5-1.5-7 0"/>'),
|
|
17
16
|
squareGrid2X2: svg('<rect x="3.5" y="3.5" width="5" height="5" rx="1.25"/><rect x="11.5" y="3.5" width="5" height="5" rx="1.25"/><rect x="3.5" y="11.5" width="5" height="5" rx="1.25"/><rect x="11.5" y="11.5" width="5" height="5" rx="1.25"/>'),
|
|
18
17
|
plusCircle: svg('<circle cx="10" cy="10" r="7.25"/><path d="M10 6.75v6.5M6.75 10h6.5"/>'),
|
|
19
18
|
xMarkCircle: svg('<circle cx="10" cy="10" r="7.25"/><path d="m7.75 7.75 4.5 4.5m0-4.5-4.5 4.5"/>'),
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
// Taken over from notion-lite (its src/ui/media-picker/index.js)
|
|
2
|
-
// Gallery's own (support.mjs, src/shared/emoji/)
|
|
1
|
+
// Taken over from notion-lite (its src/ui/media-picker/index.js): its structure and behaviour as there,
|
|
2
|
+
// what it imports Gallery's own (support.mjs, src/shared/emoji/), and since 2026-11 (the user's word) its
|
|
3
|
+
// look Gallery's own (styles.mjs: the editor's palette, text tabs as the formula editor's, no blue). Its
|
|
4
|
+
// notes, below, are notion-lite's, the look's changed.
|
|
3
5
|
/* 图标选择器(Notion 485357 MediaPicker,页签由 569553 m 给:表情符号 / 图标 / 上传;尺寸、颜色是线上实测):标注图标、选项卡图标、页面图标共用。
|
|
4
6
|
* 宽 408(569553 popupWidth);“表情符号”“图标”页签高 390(tabHeight),“上传”页签没给高度,随内容。
|
|
5
|
-
* 页签栏(eU
|
|
7
|
+
* 页签栏(eU):上下 6、左右 8、底下一条 --ge-line;“表情符号 / 图标 / 上传”是文字页签,当前的一块灰底(没有下划线);右边“移除”(灰色文字按钮)。
|
|
6
8
|
* 打开时当前图标是 Notion 图标就在“图标”页签,否则在“表情符号”(569553 d;Notion 的当前页签只记在内存里)
|
|
7
|
-
* 筛选行(ec
|
|
8
|
-
* + “随机”(28×28
|
|
9
|
+
* 筛选行(ec):只有“表情符号”“图标”页签有。8 12 6:输入框(放大镜、“筛选…”、有字时的清除按钮;聚焦时灰色内框)
|
|
10
|
+
* + “随机”(28×28,无框)+ 页签自己的按钮(表情:选肤色;图标:选图标颜色),两个页签共用同一个筛选词(onFilterChange 同时改两边)
|
|
9
11
|
* “上传”页签(569553 custom → 963369,./upload.js):上传 / 拖进来 / 粘贴一张图片或图片链接,“保存”就用它当图标;
|
|
10
12
|
* 勾上“添加到表情符号库”再起个名字,就同时存成自定义表情(以后在“表情符号”页签的“自定义”里)
|
|
11
13
|
* 随机:选上但不关菜单(keepVisible)
|
|
@@ -53,9 +55,9 @@ export function openMediaPicker({ origin, value, isCallout = false, onPick, only
|
|
|
53
55
|
`<div class="nmm-header">` +
|
|
54
56
|
`<div class="nmm-tabbar">` +
|
|
55
57
|
`<div role="tablist" class="nmm-tabs">` +
|
|
56
|
-
`<div class="nmm-tab-wrap"><div role="tab" class="nmm-tab" data-tab="emoji">${t("表情符号")}</div
|
|
57
|
-
`<div class="nmm-tab-wrap"><div role="tab" class="nmm-tab" data-tab="icon">${t("图标")}</div
|
|
58
|
-
`<div class="nmm-tab-wrap"><div role="tab" class="nmm-tab" data-tab="upload">${t("上传")}</div
|
|
58
|
+
`<div class="nmm-tab-wrap"><div role="tab" class="nmm-tab" data-tab="emoji">${t("表情符号")}</div></div>` +
|
|
59
|
+
`<div class="nmm-tab-wrap"><div role="tab" class="nmm-tab" data-tab="icon">${t("图标")}</div></div>` +
|
|
60
|
+
`<div class="nmm-tab-wrap"><div role="tab" class="nmm-tab" data-tab="upload">${t("上传")}</div></div>` +
|
|
59
61
|
`</div>` +
|
|
60
62
|
`<div class="nmm-tabbar-right"><div role="button" tabindex="0" class="nmm-text-button" data-act="remove">${t("移除")}</div></div>` +
|
|
61
63
|
`</div>` +
|
|
@@ -63,7 +65,7 @@ export function openMediaPicker({ origin, value, isCallout = false, onPick, only
|
|
|
63
65
|
`<div class="nmm-input"><div class="nmm-input-icon">${icon('magnifyingGlassSmall', 16)}</div>` +
|
|
64
66
|
`<input type="text" role="combobox" placeholder="${t("筛选…")}" autocomplete="off" spellcheck="false" aria-autocomplete="list" aria-haspopup="grid" aria-expanded="true">` +
|
|
65
67
|
`<div role="button" tabindex="0" aria-label="${t("清除输入")}" class="nmm-clear" data-act="clear" hidden>${icon('xMarkCircle', 20)}</div></div>` +
|
|
66
|
-
`<div class="nmm-filter-right"><div class="nmm-tab-left"></div><div role="button" tabindex="0" aria-label="${t("随机")}" class="nmm-random" data-act="random">${icon('arrowIntersectRightSmall',
|
|
68
|
+
`<div class="nmm-filter-right"><div class="nmm-tab-left"></div><div role="button" tabindex="0" aria-label="${t("随机")}" class="nmm-random" data-act="random">${icon('arrowIntersectRightSmall', 16)}</div><div class="nmm-tab-button"></div></div>` +
|
|
67
69
|
`</div></div>` +
|
|
68
70
|
`</div>` +
|
|
69
71
|
`<div class="nmm-content"></div>`;
|