@formicoidea/labre-core 0.59.0 → 0.61.0
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/architecture/code.c4 +111 -104
- package/architecture/domain.c4 +4 -4
- package/dist/_pkgs/affine-block-attachment/asset-picker.d.ts +8 -0
- package/dist/_pkgs/affine-block-attachment/asset-picker.js +25 -1
- package/dist/_pkgs/affine-block-attachment/attachment-block.js +9 -7
- package/dist/_pkgs/affine-block-database/database-block.js +4 -5
- package/dist/_pkgs/affine-block-database/service/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-database/service/index.js +1 -0
- package/dist/_pkgs/affine-block-database/service/initial-view.d.ts +33 -0
- package/dist/_pkgs/affine-block-database/service/initial-view.js +20 -0
- package/dist/_pkgs/affine-block-database/utils/current-view.d.ts +7 -0
- package/dist/_pkgs/affine-block-database/utils/current-view.js +14 -0
- package/dist/_pkgs/affine-block-embed/common/render-linked-doc.js +2 -0
- package/dist/_pkgs/affine-block-embed-doc/common/child-card.d.ts +25 -0
- package/dist/_pkgs/affine-block-embed-doc/common/child-card.js +27 -0
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/commands/insert-embed-linked-doc.js +6 -1
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/new-doc.js +2 -2
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-linked-doc-block.js +2 -6
- package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.js +2 -3
- package/dist/_pkgs/affine-block-embed-doc/page-drop/page-drop.js +3 -3
- package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/extensions/index.js +1 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend-label.d.ts +11 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend-label.js +16 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +1 -11
- package/dist/_pkgs/affine-block-surface/extensions/legend.js +2 -11
- package/dist/_pkgs/affine-block-surface/extensions/toolbox.d.ts +62 -0
- package/dist/_pkgs/affine-block-surface/extensions/toolbox.js +1 -0
- package/dist/_pkgs/affine-block-surface/interchange-headless.d.ts +2 -0
- package/dist/_pkgs/affine-block-surface/interchange-headless.js +2 -0
- package/dist/_pkgs/affine-components/icons/loading.d.ts +6 -0
- package/dist/_pkgs/affine-components/icons/loading.js +16 -12
- package/dist/_pkgs/affine-fragment-doc-title/title-band/show-here.js +2 -2
- package/dist/_pkgs/affine-fragment-doc-title/title-band/title-band.d.ts +8 -0
- package/dist/_pkgs/affine-fragment-doc-title/title-band/title-band.js +35 -13
- package/dist/_pkgs/affine-fragment-doc-title/translations.d.ts +1 -1
- package/dist/_pkgs/affine-fragment-doc-title/translations.js +1 -1
- package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.d.ts +12 -0
- package/dist/_pkgs/affine-gfx-mindmap/toolbar/basket-elements.js +44 -5
- package/dist/_pkgs/affine-gfx-mindmap/toolbar/senior-tool.d.ts +3 -2
- package/dist/_pkgs/affine-gfx-mindmap/toolbar/senior-tool.js +3 -2
- package/dist/_pkgs/affine-gfx-template/builtin/slides/build.js +10 -10
- package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.d.ts +48 -64
- package/dist/_pkgs/affine-gfx-template/builtin/slides/consts.js +24 -21
- package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.d.ts +1 -2
- package/dist/_pkgs/affine-gfx-template/builtin/slides/masks.js +0 -34
- package/dist/_pkgs/affine-inline-reference/reference-node/configs/toolbar.js +2 -1
- package/dist/_pkgs/affine-model/elements/c4/board.d.ts +0 -22
- package/dist/_pkgs/affine-model/elements/c4/board.js +1 -22
- package/dist/_pkgs/affine-model/elements/c4/consts.d.ts +29 -0
- package/dist/_pkgs/affine-model/elements/c4/consts.js +29 -0
- package/dist/_pkgs/affine-model/elements/c4/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/c4/index.js +1 -0
- package/dist/_pkgs/affine-model/headless.d.ts +1 -0
- package/dist/_pkgs/affine-model/headless.js +1 -0
- package/dist/_pkgs/affine-shared/consts/index.d.ts +9 -0
- package/dist/_pkgs/affine-shared/consts/index.js +9 -0
- package/dist/_pkgs/affine-shared/services/asset-picker-service.d.ts +7 -6
- package/dist/_pkgs/affine-shared/services/asset-picker-service.js +5 -5
- package/dist/_pkgs/affine-shared/services/title-band-service.d.ts +19 -0
- package/dist/_pkgs/data-view/core/component/cell-status/cell-status-css.d.ts +1 -1
- package/dist/_pkgs/data-view/core/component/cell-status/cell-status-css.js +10 -10
- package/dist/_pkgs/data-view/core/component/cell-status/cell-status.d.ts +1 -1
- package/dist/_pkgs/data-view/core/component/cell-status/cell-status.js +7 -5
- package/dist/_pkgs/data-view/property-presets/number/cell-renderer.d.ts +18 -0
- package/dist/_pkgs/data-view/property-presets/number/cell-renderer.js +51 -10
- package/dist/_pkgs/data-view/property-presets/text/cell-renderer.d.ts +23 -1
- package/dist/_pkgs/data-view/property-presets/text/cell-renderer.js +56 -15
- package/dist/_pkgs/data-view/property-presets/typing-commit.d.ts +16 -0
- package/dist/_pkgs/data-view/property-presets/typing-commit.js +27 -0
- package/dist/_pkgs/data-view/view-presets/list/list-view.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
|
2
2
|
import { html } from 'lit';
|
|
3
|
+
/**
|
|
4
|
+
* The library's spinner. Rotated by SMIL, not by a `<style>` inside the
|
|
5
|
+
* SVG: that sheet was global in light DOM (any `.spinner` of the page
|
|
6
|
+
* spun), and a binding after it fails to render under happy-dom, so no
|
|
7
|
+
* unit spec could mount a view that draws it.
|
|
8
|
+
*/
|
|
3
9
|
export const LoadingIcon = ({ size = '1em', progress = 0.2, ringColor = cssVarV2('loading/background'), strokeColor = cssVarV2('loading/foreground'), } = {}) => html `<svg
|
|
4
10
|
width="${size}"
|
|
5
11
|
height="${size}"
|
|
@@ -7,17 +13,6 @@ export const LoadingIcon = ({ size = '1em', progress = 0.2, ringColor = cssVarV2
|
|
|
7
13
|
xmlns="http://www.w3.org/2000/svg"
|
|
8
14
|
fill="none"
|
|
9
15
|
>
|
|
10
|
-
<style>
|
|
11
|
-
.spinner {
|
|
12
|
-
transform-origin: center;
|
|
13
|
-
animation: spinner_animate 0.75s infinite linear;
|
|
14
|
-
}
|
|
15
|
-
@keyframes spinner_animate {
|
|
16
|
-
100% {
|
|
17
|
-
transform: rotate(360deg);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
</style>
|
|
21
16
|
<circle cx="12" cy="12" r="8" stroke="${ringColor}" stroke-width="4" />
|
|
22
17
|
<circle
|
|
23
18
|
class="spinner"
|
|
@@ -31,5 +26,14 @@ export const LoadingIcon = ({ size = '1em', progress = 0.2, ringColor = cssVarV2
|
|
|
31
26
|
Math.PI *
|
|
32
27
|
8 *
|
|
33
28
|
(1 - progress)}"
|
|
34
|
-
|
|
29
|
+
>
|
|
30
|
+
<animateTransform
|
|
31
|
+
attributeName="transform"
|
|
32
|
+
type="rotate"
|
|
33
|
+
from="0 12 12"
|
|
34
|
+
to="360 12 12"
|
|
35
|
+
dur="0.75s"
|
|
36
|
+
repeatCount="indefinite"
|
|
37
|
+
/>
|
|
38
|
+
</circle>
|
|
35
39
|
</svg>`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EdgelessCRUDIdentifier } from '../../affine-block-surface/index.js';
|
|
2
|
-
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '../../affine-shared/consts/index.js';
|
|
2
|
+
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, LINKED_DOC_NOTE_STYLE, } from '../../affine-shared/consts/index.js';
|
|
3
3
|
import { TelemetryProvider } from '../../affine-shared/services/index.js';
|
|
4
4
|
import { getLastNoteBlock } from '../../affine-shared/utils/index.js';
|
|
5
5
|
import { Bound } from '../../global/gfx/index.js';
|
|
@@ -45,7 +45,7 @@ function insertInPage(std, pageId) {
|
|
|
45
45
|
if (!root)
|
|
46
46
|
return null;
|
|
47
47
|
const noteId = getLastNoteBlock(store)?.id ?? store.addBlock('affine:note', {}, root.id);
|
|
48
|
-
return store.addBlock(LINKED_DOC, { pageId }, noteId);
|
|
48
|
+
return store.addBlock(LINKED_DOC, { pageId, style: LINKED_DOC_NOTE_STYLE }, noteId);
|
|
49
49
|
}
|
|
50
50
|
function insertOnCanvas(std, pageId) {
|
|
51
51
|
const gfx = std.get(GfxControllerIdentifier);
|
|
@@ -62,8 +62,16 @@ export declare class TitleBand extends TitleBand_base {
|
|
|
62
62
|
private _cellFor;
|
|
63
63
|
private readonly _openPanel;
|
|
64
64
|
private readonly _onChip;
|
|
65
|
+
/** The host's menu for the property, under its name (`configure`). */
|
|
66
|
+
private _onNameContextMenu;
|
|
65
67
|
private _renderFallback;
|
|
66
68
|
private _renderChip;
|
|
69
|
+
/**
|
|
70
|
+
* `withAdd: false` on the collapsed row: a "+" there added a property the
|
|
71
|
+
* reader could not see (recette 3, P3-x), so it only shows once the chips
|
|
72
|
+
* it adds to are drawn. A page with no property has nothing to collapse
|
|
73
|
+
* and keeps its "+".
|
|
74
|
+
*/
|
|
67
75
|
private _renderTools;
|
|
68
76
|
private _renderSheet;
|
|
69
77
|
private _renderNotShown;
|
|
@@ -32,6 +32,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
+
import { LoadingIcon } from '../../affine-components/icons/index.js';
|
|
35
36
|
import { RefNodeSlotsProvider } from '../../affine-inline-reference/index.js';
|
|
36
37
|
import { DOC_UNTITLED, FeatureFlagService, formatLocale, PropertiesPanelProvider, TitleBandProvider, translateKey, } from '../../affine-shared/services/index.js';
|
|
37
38
|
import { stopPropagation } from '../../affine-shared/utils/index.js';
|
|
@@ -224,12 +225,11 @@ let TitleBand = (() => {
|
|
|
224
225
|
color: var(--affine-placeholder-color);
|
|
225
226
|
}
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
background-color: var(--affine-hover-color);
|
|
228
|
+
/* The host's rule: a spinner centred in what loads, never a skeleton
|
|
229
|
+
(recette 3; ADR-0057 on the Labre side). */
|
|
230
|
+
.labre-title-band-row.labre-title-band-loading {
|
|
231
|
+
justify-content: center;
|
|
232
|
+
font-size: 16px;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
.labre-title-band-not-shown-label {
|
|
@@ -423,6 +423,18 @@ let TitleBand = (() => {
|
|
|
423
423
|
sources.cells.set(id, { type, optionsWritable, cell });
|
|
424
424
|
return cell;
|
|
425
425
|
}
|
|
426
|
+
/** The host's menu for the property, under its name (`configure`). */
|
|
427
|
+
_onNameContextMenu(sources, prop, event) {
|
|
428
|
+
const configure = sources.service.configure;
|
|
429
|
+
if (!configure || this._readonly)
|
|
430
|
+
return;
|
|
431
|
+
// A touch long-press is the browser's (text selection), as before.
|
|
432
|
+
if (event.pointerType === 'touch')
|
|
433
|
+
return;
|
|
434
|
+
event.preventDefault();
|
|
435
|
+
event.stopPropagation();
|
|
436
|
+
configure.call(sources.service, sources.docId, prop.id, event.currentTarget);
|
|
437
|
+
}
|
|
426
438
|
_renderFallback(prop) {
|
|
427
439
|
const text = formatPropertyValue(prop, this._locale);
|
|
428
440
|
return html `<span
|
|
@@ -460,7 +472,12 @@ let TitleBand = (() => {
|
|
|
460
472
|
this._onChip(event, false);
|
|
461
473
|
}}
|
|
462
474
|
>
|
|
463
|
-
<span
|
|
475
|
+
<span
|
|
476
|
+
class="labre-title-band-chip-name"
|
|
477
|
+
data-testid="title-band-chip-name"
|
|
478
|
+
@contextmenu=${(event) => this._onNameContextMenu(sources, prop, event)}
|
|
479
|
+
>${prop.name}</span
|
|
480
|
+
>
|
|
464
481
|
${cell
|
|
465
482
|
? html `<dv-standalone-cell
|
|
466
483
|
class="labre-title-band-chip-value"
|
|
@@ -474,8 +491,14 @@ let TitleBand = (() => {
|
|
|
474
491
|
: this._renderFallback(prop)}
|
|
475
492
|
</div>`;
|
|
476
493
|
}
|
|
477
|
-
|
|
478
|
-
|
|
494
|
+
/**
|
|
495
|
+
* `withAdd: false` on the collapsed row: a "+" there added a property the
|
|
496
|
+
* reader could not see (recette 3, P3-x), so it only shows once the chips
|
|
497
|
+
* it adds to are drawn. A page with no property has nothing to collapse
|
|
498
|
+
* and keeps its "+".
|
|
499
|
+
*/
|
|
500
|
+
_renderTools(sources, hasPanel, withAdd = true) {
|
|
501
|
+
const canAdd = withAdd && !!sources.service.add && !this._readonly;
|
|
479
502
|
return html `${canAdd
|
|
480
503
|
? html `<button
|
|
481
504
|
class="labre-title-band-icon-button"
|
|
@@ -509,14 +532,13 @@ let TitleBand = (() => {
|
|
|
509
532
|
const state = sources.sheet$.value;
|
|
510
533
|
if (state.status === 'loading') {
|
|
511
534
|
return html `<div
|
|
512
|
-
class="labre-title-band-row"
|
|
535
|
+
class="labre-title-band-row labre-title-band-loading"
|
|
513
536
|
role="status"
|
|
514
537
|
aria-busy="true"
|
|
515
538
|
aria-label=${this._t(TITLE_BAND_LOADING)}
|
|
516
539
|
data-testid="title-band-loading"
|
|
517
540
|
>
|
|
518
|
-
|
|
519
|
-
<span class="labre-title-band-skeleton"></span>
|
|
541
|
+
${LoadingIcon()}
|
|
520
542
|
</div>`;
|
|
521
543
|
}
|
|
522
544
|
if (state.status !== 'ready')
|
|
@@ -545,7 +567,7 @@ let TitleBand = (() => {
|
|
|
545
567
|
>${this._t(TITLE_BAND_EXPAND, properties.length)}</span
|
|
546
568
|
>
|
|
547
569
|
</button>
|
|
548
|
-
${this._renderTools(sources, hasPanel)}
|
|
570
|
+
${this._renderTools(sources, hasPanel, false)}
|
|
549
571
|
</div>`;
|
|
550
572
|
}
|
|
551
573
|
return html `<div
|
|
@@ -21,7 +21,7 @@ export declare const TITLE_BAND_OPEN_PANEL: ChromeWording;
|
|
|
21
21
|
export declare const TITLE_BAND_COLLAPSE: ChromeWording;
|
|
22
22
|
/** The folded band's only button; `count` is the number of chips. */
|
|
23
23
|
export declare const TITLE_BAND_EXPAND: ChromeWording;
|
|
24
|
-
/** The accessible name of the
|
|
24
|
+
/** The accessible name of the spinner drawn while the sheet loads. */
|
|
25
25
|
export declare const TITLE_BAND_LOADING: ChromeWording;
|
|
26
26
|
/**
|
|
27
27
|
* The row of child pages the document holds but does not display, under the
|
|
@@ -42,7 +42,7 @@ export const TITLE_BAND_EXPAND = [
|
|
|
42
42
|
'com.labre.title-band.expand',
|
|
43
43
|
'Properties ({{count}})',
|
|
44
44
|
];
|
|
45
|
-
/** The accessible name of the
|
|
45
|
+
/** The accessible name of the spinner drawn while the sheet loads. */
|
|
46
46
|
export const TITLE_BAND_LOADING = [
|
|
47
47
|
'com.labre.title-band.loading',
|
|
48
48
|
'Loading properties',
|
|
@@ -18,5 +18,17 @@ export declare const mindmapConfig: ToolConfig;
|
|
|
18
18
|
export declare const mediaConfig: ToolConfig;
|
|
19
19
|
export declare const getMindmapRender: (mindmapStyle: MindmapStyle) => DraggableTool["render"];
|
|
20
20
|
export declare const textRender: DraggableTool['render'];
|
|
21
|
+
/**
|
|
22
|
+
* The canvas's "Add file" (the promoted senior tool, and the media item of the
|
|
23
|
+
* mind map basket): the host's asset dialog when there is one
|
|
24
|
+
* (`AssetPickerProvider`, `kind: 'file'`, one ref), the system file chooser
|
|
25
|
+
* otherwise. Either way an image lands as an image block and anything else as
|
|
26
|
+
* an attachment card, at `bound`'s corner.
|
|
27
|
+
*
|
|
28
|
+
* It used to call the file chooser unconditionally, so with the seam present
|
|
29
|
+
* the canvas's image and file buttons of the note menu opened the dialog
|
|
30
|
+
* while this one, the most visible, still opened the system chooser (labre
|
|
31
|
+
* recette of 2026-10-28).
|
|
32
|
+
*/
|
|
21
33
|
export declare const mediaRender: DraggableTool['render'];
|
|
22
34
|
export declare const toolConfig2StyleObj: (config: ToolConfig) => Record<string, string>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { addAttachments } from '../../affine-block-attachment/index.js';
|
|
2
|
-
import { addImages } from '../../affine-block-image/index.js';
|
|
1
|
+
import { addAttachments, addAttachmentsFromAssets, } from '../../affine-block-attachment/index.js';
|
|
2
|
+
import { addImages, addImagesFromAssets } from '../../affine-block-image/index.js';
|
|
3
3
|
import { CanvasElementType, EdgelessCRUDIdentifier, } from '../../affine-block-surface/index.js';
|
|
4
4
|
import { insertEdgelessTextCommand, mountTextElementEditor, } from '../../affine-gfx-text/index.js';
|
|
5
5
|
import { MAX_IMAGE_WIDTH, TextElementModel, } from '../../affine-model/index.js';
|
|
6
|
-
import { FeatureFlagService, TelemetryProvider, translateKey, } from '../../affine-shared/services/index.js';
|
|
6
|
+
import { AssetPickerProvider, FeatureFlagService, TelemetryProvider, translateKey, } from '../../affine-shared/services/index.js';
|
|
7
7
|
import { openSingleFileWith } from '../../affine-shared/utils/index.js';
|
|
8
8
|
import { Bound } from '../../global/gfx/index.js';
|
|
9
9
|
import * as Y from 'yjs';
|
|
@@ -105,7 +105,48 @@ export const textRender = async (bound, edgeless) => {
|
|
|
105
105
|
});
|
|
106
106
|
return id;
|
|
107
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* The canvas's "Add file" (the promoted senior tool, and the media item of the
|
|
110
|
+
* mind map basket): the host's asset dialog when there is one
|
|
111
|
+
* (`AssetPickerProvider`, `kind: 'file'`, one ref), the system file chooser
|
|
112
|
+
* otherwise. Either way an image lands as an image block and anything else as
|
|
113
|
+
* an attachment card, at `bound`'s corner.
|
|
114
|
+
*
|
|
115
|
+
* It used to call the file chooser unconditionally, so with the seam present
|
|
116
|
+
* the canvas's image and file buttons of the note menu opened the dialog
|
|
117
|
+
* while this one, the most visible, still opened the system chooser (labre
|
|
118
|
+
* recette of 2026-10-28).
|
|
119
|
+
*/
|
|
108
120
|
export const mediaRender = async (bound, edgeless) => {
|
|
121
|
+
const std = edgeless.std;
|
|
122
|
+
const point = [bound.x, bound.y];
|
|
123
|
+
const picker = std.getOptional(AssetPickerProvider);
|
|
124
|
+
if (picker) {
|
|
125
|
+
let asset;
|
|
126
|
+
try {
|
|
127
|
+
[asset] =
|
|
128
|
+
(await picker.pick({
|
|
129
|
+
kind: 'file',
|
|
130
|
+
mode: 'insert',
|
|
131
|
+
multiple: false,
|
|
132
|
+
docId: std.store.id,
|
|
133
|
+
})) ?? [];
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
console.error(e);
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
if (!asset)
|
|
140
|
+
return null;
|
|
141
|
+
const [id] = asset.type.startsWith('image/')
|
|
142
|
+
? await addImagesFromAssets(std, [asset], {
|
|
143
|
+
point,
|
|
144
|
+
maxWidth: MAX_IMAGE_WIDTH,
|
|
145
|
+
shouldTransformPoint: false,
|
|
146
|
+
})
|
|
147
|
+
: addAttachmentsFromAssets(std, [asset], point, false);
|
|
148
|
+
return id ?? null;
|
|
149
|
+
}
|
|
109
150
|
let file = null;
|
|
110
151
|
try {
|
|
111
152
|
file = await openSingleFileWith();
|
|
@@ -117,8 +158,6 @@ export const mediaRender = async (bound, edgeless) => {
|
|
|
117
158
|
if (!file)
|
|
118
159
|
return null;
|
|
119
160
|
const files = [file];
|
|
120
|
-
const std = edgeless.std;
|
|
121
|
-
const point = [bound.x, bound.y];
|
|
122
161
|
// image
|
|
123
162
|
if (file.type.startsWith('image/')) {
|
|
124
163
|
const [id] = await addImages(std, files, {
|
|
@@ -7,7 +7,8 @@ export declare const mindMapSeniorTool: import("../../store/index.js").Extension
|
|
|
7
7
|
export declare const textSeniorTool: import("../../store/index.js").ExtensionType;
|
|
8
8
|
/**
|
|
9
9
|
* Standalone "Add file" tool. Promoted out of the former "Others" submenu: a
|
|
10
|
-
* single tap opens the
|
|
11
|
-
* viewport center. Reuses the
|
|
10
|
+
* single tap opens the host's asset dialog (or the file picker without one)
|
|
11
|
+
* and inserts the image/attachment at the viewport center. Reuses the
|
|
12
|
+
* submenu's `mediaRender` action.
|
|
12
13
|
*/
|
|
13
14
|
export declare const mediaSeniorTool: import("../../store/index.js").ExtensionType;
|
|
@@ -66,8 +66,9 @@ export const textSeniorTool = SeniorToolExtension('edgeless-text', ({ block, gfx
|
|
|
66
66
|
}));
|
|
67
67
|
/**
|
|
68
68
|
* Standalone "Add file" tool. Promoted out of the former "Others" submenu: a
|
|
69
|
-
* single tap opens the
|
|
70
|
-
* viewport center. Reuses the
|
|
69
|
+
* single tap opens the host's asset dialog (or the file picker without one)
|
|
70
|
+
* and inserts the image/attachment at the viewport center. Reuses the
|
|
71
|
+
* submenu's `mediaRender` action.
|
|
71
72
|
*/
|
|
72
73
|
export const mediaSeniorTool = SeniorToolExtension('edgeless-media', ({ block, gfx }) => ({
|
|
73
74
|
name: 'Add file',
|
|
@@ -4,7 +4,7 @@ import * as Y from 'yjs';
|
|
|
4
4
|
import { makeTemplateSnapshot, surfaceText, } from '../../make-snapshot.js';
|
|
5
5
|
import { SLIDE_SEED_FOOTER, SLIDE_SEED_IMAGE } from '../../translations.js';
|
|
6
6
|
import { tr } from '../other.js';
|
|
7
|
-
import { SLIDE_FOOTER_Y, SLIDE_HAIRLINE_WIDTH, SLIDE_HEIGHT, SLIDE_LINE_HEIGHT, SLIDE_MARGIN,
|
|
7
|
+
import { SLIDE_FOOTER_Y, SLIDE_HAIRLINE_WIDTH, SLIDE_HEIGHT, SLIDE_LINE_HEIGHT, SLIDE_MARGIN, SLIDE_PALETTE, SLIDE_RADIUS, SLIDE_TYPE, SLIDE_WIDTH, SLIDE_ZONE_STROKE_WIDTH, } from './consts.js';
|
|
8
8
|
/**
|
|
9
9
|
* The one builder of the slide masks: a mask declaration (`masks.ts`) in, a
|
|
10
10
|
* template snapshot (one 1600 x 900 frame and the elements it holds) and a
|
|
@@ -43,7 +43,7 @@ function shapeElement(x, y, w, h, opts) {
|
|
|
43
43
|
type: 'shape',
|
|
44
44
|
shapeType: opts.shapeType,
|
|
45
45
|
filled: opts.fill !== null,
|
|
46
|
-
fillColor: opts.fill ??
|
|
46
|
+
fillColor: opts.fill ?? SLIDE_PALETTE.paper,
|
|
47
47
|
strokeColor: opts.stroke,
|
|
48
48
|
strokeWidth: opts.dash ? SLIDE_ZONE_STROKE_WIDTH : SLIDE_HAIRLINE_WIDTH,
|
|
49
49
|
strokeStyle: opts.dash ? StrokeStyle.Dash : StrokeStyle.Solid,
|
|
@@ -89,7 +89,7 @@ function zoneElement(zone, palette, std) {
|
|
|
89
89
|
return shapeElement(zone.x, zone.y, zone.w, zone.h, {
|
|
90
90
|
shapeType: zone.shape ?? 'rect',
|
|
91
91
|
fill: zone.filled ? palette.hairline : null,
|
|
92
|
-
stroke: zone.stroke === 'muted' ? palette.
|
|
92
|
+
stroke: zone.stroke === 'muted' ? palette.rule : palette.hairline,
|
|
93
93
|
dash: false,
|
|
94
94
|
radius: SLIDE_RADIUS,
|
|
95
95
|
label: zone.label ? tr(std, zone.label, zone.params) : undefined,
|
|
@@ -108,7 +108,7 @@ function zoneElement(zone, palette, std) {
|
|
|
108
108
|
return {
|
|
109
109
|
type: 'connector',
|
|
110
110
|
mode: ConnectorMode.Straight,
|
|
111
|
-
stroke: palette.
|
|
111
|
+
stroke: palette.rule,
|
|
112
112
|
strokeWidth: SLIDE_HAIRLINE_WIDTH,
|
|
113
113
|
strokeStyle: StrokeStyle.Solid,
|
|
114
114
|
frontEndpointStyle: PointStyle.None,
|
|
@@ -120,7 +120,7 @@ function zoneElement(zone, palette, std) {
|
|
|
120
120
|
}
|
|
121
121
|
/** The elements of one mask, footer and slide number last, in paint order. */
|
|
122
122
|
export function slideElements(mask, std) {
|
|
123
|
-
const palette =
|
|
123
|
+
const palette = SLIDE_PALETTE;
|
|
124
124
|
const elements = {};
|
|
125
125
|
mask.zones.forEach((zone, i) => {
|
|
126
126
|
elements[`z${i}`] = zoneElement(zone, palette, std);
|
|
@@ -164,7 +164,7 @@ function slideFrame(mask, elements, std) {
|
|
|
164
164
|
'$blocksuite:internal:text$': true,
|
|
165
165
|
delta: [{ insert: name }],
|
|
166
166
|
},
|
|
167
|
-
background:
|
|
167
|
+
background: SLIDE_PALETTE.paper,
|
|
168
168
|
xywh: xywh(0, 0, SLIDE_WIDTH, SLIDE_HEIGHT),
|
|
169
169
|
index: 'a0',
|
|
170
170
|
childElementIds: Object.fromEntries(Object.keys(elements).map(id => [id, true])),
|
|
@@ -246,7 +246,7 @@ function previewZone(zone, palette) {
|
|
|
246
246
|
const filled = zone.kind === 'image' || (zone.kind === 'card' && zone.filled);
|
|
247
247
|
const fill = filled ? light(palette.hairline) : 'none';
|
|
248
248
|
const stroke = light(zone.kind === 'card' && zone.stroke === 'muted'
|
|
249
|
-
? palette.
|
|
249
|
+
? palette.rule
|
|
250
250
|
: zone.kind === 'image'
|
|
251
251
|
? palette.zoneStroke
|
|
252
252
|
: palette.hairline);
|
|
@@ -259,7 +259,7 @@ function previewZone(zone, palette) {
|
|
|
259
259
|
case 'dot':
|
|
260
260
|
return `<circle cx="${zone.x + zone.size / 2}" cy="${zone.y + zone.size / 2}" r="${zone.size / 2}" fill="${light(palette.ink)}"/>`;
|
|
261
261
|
case 'line':
|
|
262
|
-
return `<path d="M${zone.from[0]} ${zone.from[1]} L${zone.to[0]} ${zone.to[1]}" stroke="${light(palette.
|
|
262
|
+
return `<path d="M${zone.from[0]} ${zone.from[1]} L${zone.to[0]} ${zone.to[1]}" stroke="${light(palette.rule)}" stroke-width="6"/>`;
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
/**
|
|
@@ -270,7 +270,7 @@ function previewZone(zone, palette) {
|
|
|
270
270
|
* panel.
|
|
271
271
|
*/
|
|
272
272
|
export function slidePreview(mask) {
|
|
273
|
-
const palette =
|
|
273
|
+
const palette = SLIDE_PALETTE;
|
|
274
274
|
const body = mask.zones.map(zone => previewZone(zone, palette)).join('');
|
|
275
|
-
return `<svg width="100%" height="100%" viewBox="-20 -20 ${SLIDE_WIDTH + 40} ${SLIDE_HEIGHT + 40}" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="${SLIDE_WIDTH}" height="${SLIDE_HEIGHT}" rx="16" fill="${light(palette.paper)}" stroke="${light(
|
|
275
|
+
return `<svg width="100%" height="100%" viewBox="-20 -20 ${SLIDE_WIDTH + 40} ${SLIDE_HEIGHT + 40}" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="${SLIDE_WIDTH}" height="${SLIDE_HEIGHT}" rx="16" fill="${light(palette.paper)}" stroke="${light(palette.hairline)}" stroke-width="8"/>${body}</svg>`;
|
|
276
276
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Color, FontWeight } from '../../../affine-model/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* The slide masks' one system: geometry, typography and the
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* The slide masks' one system: geometry, typography and the one paper.
|
|
4
|
+
* Every mask in `masks.ts` reads these and restates none of them, so a size
|
|
5
|
+
* or a colour changes here, once, for the whole set.
|
|
6
6
|
*/
|
|
7
7
|
/** A 16:9 slide, the frame menu's own `16:9` preset (1600 × 900). */
|
|
8
8
|
export declare const SLIDE_WIDTH = 1600;
|
|
@@ -47,78 +47,62 @@ export type SlidePalette = {
|
|
|
47
47
|
paper: Color;
|
|
48
48
|
/** Titles, headings, body text, key figures. */
|
|
49
49
|
ink: Color;
|
|
50
|
-
/** Eyebrows, captions, footer, slide number, axis labels. */
|
|
50
|
+
/** Eyebrows, captions, footer, slide number, axis labels, details. */
|
|
51
51
|
muted: Color;
|
|
52
|
+
/** Rules, arrows and the outlines meant to be seen (a Venn circle). */
|
|
53
|
+
rule: Color;
|
|
52
54
|
/** Hairlines, card outlines, the fill of a placeholder. */
|
|
53
55
|
hairline: Color;
|
|
54
56
|
/** The dashed outline of a fill zone. */
|
|
55
57
|
zoneStroke: Color;
|
|
56
58
|
};
|
|
57
59
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
60
|
+
* One paper for every mask: white, turning dark grey on a dark canvas. The
|
|
61
|
+
* set once had an `inverse` black slide (section, statement, quote); the PO
|
|
62
|
+
* wants every slide of a deck on white (recette of 0.60), so a deck reads as
|
|
63
|
+
* one sheet and prints as one.
|
|
64
|
+
*
|
|
65
|
+
* Words reach WCAG AA (4.5:1) on both sides of the paper, which the base
|
|
66
|
+
* palette's medium grey does not (`#929292` on white is 3.1:1): secondary
|
|
67
|
+
* words are set in ink, and their tone is carried by their role's size.
|
|
68
|
+
* The medium grey stays for rules and outlines, where 3:1 is the bar.
|
|
69
|
+
*
|
|
70
|
+
* ponytail: `muted` is the ink pair, so a muted line looks like an ink one
|
|
71
|
+
* at the same size. The ceiling is a deck with no tonal step between a
|
|
72
|
+
* heading and its detail; the upgrade is a darker grey `{ light, dark }`
|
|
73
|
+
* pair in the base palette (one AA on white and on `#252525`), set here.
|
|
61
74
|
*/
|
|
62
|
-
export declare const
|
|
63
|
-
readonly paper:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
light: string;
|
|
86
|
-
};
|
|
75
|
+
export declare const SLIDE_PALETTE: {
|
|
76
|
+
readonly paper: Color;
|
|
77
|
+
readonly ink: string | {
|
|
78
|
+
normal: string;
|
|
79
|
+
} | {
|
|
80
|
+
dark: string;
|
|
81
|
+
light: string;
|
|
82
|
+
};
|
|
83
|
+
readonly muted: string | {
|
|
84
|
+
normal: string;
|
|
85
|
+
} | {
|
|
86
|
+
dark: string;
|
|
87
|
+
light: string;
|
|
88
|
+
};
|
|
89
|
+
readonly rule: string | {
|
|
90
|
+
normal: string;
|
|
91
|
+
} | {
|
|
92
|
+
dark: string;
|
|
93
|
+
light: string;
|
|
94
|
+
};
|
|
95
|
+
readonly hairline: {
|
|
96
|
+
dark: string;
|
|
97
|
+
light: string;
|
|
87
98
|
};
|
|
88
|
-
readonly
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
light: string;
|
|
94
|
-
};
|
|
95
|
-
readonly ink: string | {
|
|
96
|
-
normal: string;
|
|
97
|
-
} | {
|
|
98
|
-
dark: string;
|
|
99
|
-
light: string;
|
|
100
|
-
};
|
|
101
|
-
readonly muted: string | {
|
|
102
|
-
normal: string;
|
|
103
|
-
} | {
|
|
104
|
-
dark: string;
|
|
105
|
-
light: string;
|
|
106
|
-
};
|
|
107
|
-
readonly hairline: string | {
|
|
108
|
-
normal: string;
|
|
109
|
-
} | {
|
|
110
|
-
dark: string;
|
|
111
|
-
light: string;
|
|
112
|
-
};
|
|
113
|
-
readonly zoneStroke: string | {
|
|
114
|
-
normal: string;
|
|
115
|
-
} | {
|
|
116
|
-
dark: string;
|
|
117
|
-
light: string;
|
|
118
|
-
};
|
|
99
|
+
readonly zoneStroke: string | {
|
|
100
|
+
normal: string;
|
|
101
|
+
} | {
|
|
102
|
+
dark: string;
|
|
103
|
+
light: string;
|
|
119
104
|
};
|
|
120
105
|
};
|
|
121
|
-
export type SlideVariant = keyof typeof SLIDE_PALETTES;
|
|
122
106
|
/** Stroke widths, model units. */
|
|
123
107
|
export declare const SLIDE_HAIRLINE_WIDTH = 2;
|
|
124
108
|
export declare const SLIDE_ZONE_STROKE_WIDTH = 2;
|
|
@@ -2,9 +2,9 @@ import { DefaultTheme, FontWeight } from '../../../affine-model/index.js';
|
|
|
2
2
|
import { HEADING_SCALE } from '../../../affine-shared/consts/index.js';
|
|
3
3
|
import { darkThemeV2, lightThemeV2 } from '@toeverything/theme/v2';
|
|
4
4
|
/**
|
|
5
|
-
* The slide masks' one system: geometry, typography and the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* The slide masks' one system: geometry, typography and the one paper.
|
|
6
|
+
* Every mask in `masks.ts` reads these and restates none of them, so a size
|
|
7
|
+
* or a colour changes here, once, for the whole set.
|
|
8
8
|
*/
|
|
9
9
|
/** A 16:9 slide, the frame menu's own `16:9` preset (1600 × 900). */
|
|
10
10
|
export const SLIDE_WIDTH = 1600;
|
|
@@ -74,25 +74,28 @@ const NOTE_GREY = {
|
|
|
74
74
|
light: lightThemeV2['edgeless/note/grey'],
|
|
75
75
|
};
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
77
|
+
* One paper for every mask: white, turning dark grey on a dark canvas. The
|
|
78
|
+
* set once had an `inverse` black slide (section, statement, quote); the PO
|
|
79
|
+
* wants every slide of a deck on white (recette of 0.60), so a deck reads as
|
|
80
|
+
* one sheet and prints as one.
|
|
81
|
+
*
|
|
82
|
+
* Words reach WCAG AA (4.5:1) on both sides of the paper, which the base
|
|
83
|
+
* palette's medium grey does not (`#929292` on white is 3.1:1): secondary
|
|
84
|
+
* words are set in ink, and their tone is carried by their role's size.
|
|
85
|
+
* The medium grey stays for rules and outlines, where 3:1 is the bar.
|
|
86
|
+
*
|
|
87
|
+
* ponytail: `muted` is the ink pair, so a muted line looks like an ink one
|
|
88
|
+
* at the same size. The ceiling is a deck with no tonal step between a
|
|
89
|
+
* heading and its detail; the upgrade is a darker grey `{ light, dark }`
|
|
90
|
+
* pair in the base palette (one AA on white and on `#252525`), set here.
|
|
80
91
|
*/
|
|
81
|
-
export const
|
|
82
|
-
paper:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
89
|
-
inverse: {
|
|
90
|
-
paper: DefaultTheme.black,
|
|
91
|
-
ink: DefaultTheme.white,
|
|
92
|
-
muted: MEDIUM_GREY,
|
|
93
|
-
hairline: MEDIUM_GREY,
|
|
94
|
-
zoneStroke: MEDIUM_GREY,
|
|
95
|
-
},
|
|
92
|
+
export const SLIDE_PALETTE = {
|
|
93
|
+
paper: DefaultTheme.NoteBackgroundColorMap['White'],
|
|
94
|
+
ink: DefaultTheme.black,
|
|
95
|
+
muted: DefaultTheme.black,
|
|
96
|
+
rule: MEDIUM_GREY,
|
|
97
|
+
hairline: NOTE_GREY,
|
|
98
|
+
zoneStroke: MEDIUM_GREY,
|
|
96
99
|
};
|
|
97
100
|
/** Stroke widths, model units. */
|
|
98
101
|
export const SLIDE_HAIRLINE_WIDTH = 2;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ChromeWording, TranslationParams } from '../../../affine-shared/services/index.js';
|
|
2
|
-
import { type SlideTextRole
|
|
2
|
+
import { type SlideTextRole } from './consts.js';
|
|
3
3
|
/**
|
|
4
4
|
* The slide masks, as DATA: a mask is the list of its zones, and one builder
|
|
5
5
|
* (`build.ts`) projects every mask into a frame, its elements and its preview.
|
|
@@ -76,7 +76,6 @@ export type SlideMask = {
|
|
|
76
76
|
name: ChromeWording;
|
|
77
77
|
/** Plain English search words besides the name (`Template.keywords`). */
|
|
78
78
|
keywords: string[];
|
|
79
|
-
variant: SlideVariant;
|
|
80
79
|
zones: SlideZone[];
|
|
81
80
|
};
|
|
82
81
|
/** Every mask, in the panel's order: a deck reads top to bottom. */
|