Skip to content

Commit dd8edf8

Browse files
committed
feat(ew): comments
1 parent eea1680 commit dd8edf8

57 files changed

Lines changed: 4864 additions & 224 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

blocks/browse/da-list/da-list.css

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -257,60 +257,6 @@ da-list-item.is-expanded::after {
257257
display: none;
258258
}
259259

260-
.da-list-status {
261-
position: fixed;
262-
inset: 0;
263-
background: rgb(255 255 255 / 60%);
264-
display: flex;
265-
justify-content: center;
266-
align-items: center;
267-
z-index: 500;
268-
}
269-
270-
.da-list-status-toast {
271-
width: 280px;
272-
background: var(--s2-blue-800);
273-
line-height: 48px;
274-
border-radius: 6px;
275-
filter: drop-shadow(rgb(0 0 0 / 15%) 0 1px 4px);
276-
justify-content: space-between;
277-
align-items: center;
278-
box-sizing: border-box;
279-
color: #fff;
280-
font-size: 14px;
281-
overflow: hidden;
282-
}
283-
284-
.da-list-status-title {
285-
font-weight: 700;
286-
padding: 0 12px 0 40px;
287-
margin: 0;
288-
}
289-
290-
.da-list-status-description {
291-
line-height: 1.6;
292-
padding: 6px 12px;
293-
margin: 0;
294-
background: rgb(255 255 255 / 10%);
295-
}
296-
297-
.da-list-status-type-info .da-list-status-title {
298-
background-color: var(--s2-blue-800);
299-
position: relative;
300-
}
301-
302-
.da-list-status-type-info .da-list-status-title::before {
303-
content: '';
304-
position: absolute;
305-
left: 12px;
306-
top: 50%;
307-
transform: translateY(-50%);
308-
width: 20px;
309-
height: 20px;
310-
background: url("/img/icons/s2-icon-infocircle-20-n.svg") center / contain no-repeat;
311-
filter: brightness(0) invert(1);
312-
}
313-
314260
/* Checkbox */
315261

316262
.checkbox-label {

blocks/browse/da-list/da-list.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default class DaList extends LitElement {
3030
_dropFiles: { state: true },
3131
_dropMessage: { state: true },
3232
_dropConflicts: { state: true },
33-
_status: { state: true },
33+
_toast: { state: true },
3434
_confirm: { state: true },
3535
_confirmText: { state: true },
3636
_unpublish: { state: true },
@@ -91,16 +91,17 @@ export default class DaList extends LitElement {
9191

9292
async firstUpdated() {
9393
await import('../../shared/da-dialog/da-dialog.js');
94+
await import('../../shared/da-toast/da-toast.js');
9495
await import('../da-actionbar/da-actionbar.js');
9596
this.setupObserver();
9697
}
9798

9899
setStatus(text, description, type = 'info') {
99100
if (!text) {
100-
this._status = null;
101+
this._toast = null;
101102
return;
102103
}
103-
this._status = { type, text, description };
104+
this._toast = { type, text, description, duration: 0 };
104105
}
105106

106107
handlePermissions(permissions) {
@@ -409,7 +410,7 @@ export default class DaList extends LitElement {
409410
return pasteItem;
410411
});
411412

412-
const showStatus = setTimeout(() => {
413+
const pasteStatusTimer = setTimeout(() => {
413414
this.setStatus('Pasting', 'Please be patient. Pasting items with many children can take time.');
414415
}, 2000);
415416

@@ -419,7 +420,7 @@ export default class DaList extends LitElement {
419420
await this.handleItemAction({ item, type });
420421
}));
421422

422-
clearTimeout(showStatus);
423+
clearTimeout(pasteStatusTimer);
423424

424425
this.setStatus();
425426
this.handleClear();
@@ -506,8 +507,7 @@ export default class DaList extends LitElement {
506507
}
507508

508509
handleShare() {
509-
this.setStatus('Copied', 'URLs have been copied to the clipboard.');
510-
setTimeout(() => { this.setStatus(); }, 3000);
510+
this._toast = { text: 'Copied', description: 'URLs have been copied to the clipboard.' };
511511
}
512512

513513
dragenter(e) {
@@ -793,13 +793,7 @@ export default class DaList extends LitElement {
793793
}
794794

795795
renderStatus() {
796-
return html`
797-
<div class="da-list-status">
798-
<div class="da-list-status-toast da-list-status-type-${this._status.type}">
799-
<p class="da-list-status-title">${this._status.text}</p>
800-
${this._status.description ? html`<p class="da-list-status-description">${this._status.description}</p>` : nothing}
801-
</div>
802-
</div>`;
796+
return html`<da-toast .toast=${this._toast} @close=${() => { this._toast = null; }}></da-toast>`;
803797
}
804798

805799
renderConfirm() {
@@ -1012,7 +1006,7 @@ export default class DaList extends LitElement {
10121006
currentPath="${this.fullpath}"
10131007
role="row"
10141008
data-visible="${this._selectedItems?.length > 0}"></da-actionbar>
1015-
${this._status ? this.renderStatus() : nothing}
1009+
${this._toast ? this.renderStatus() : nothing}
10161010
${this._confirm ? this.renderConfirm() : nothing}
10171011
${this._dropConflicts?.length ? this.renderDropConfirm() : nothing}
10181012
${!this._confirm && this._itemErrors.length ? this.renderErrors() : nothing}

blocks/browse/da-sites/da-sites.css

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -421,45 +421,3 @@ form button:hover {
421421
text-align: center;
422422
}
423423

424-
/* Handle Share */
425-
426-
.da-list-status {
427-
position: fixed;
428-
inset: 0;
429-
background: rgb(255 255 255 / 60%);
430-
display: flex;
431-
justify-content: center;
432-
align-items: center;
433-
z-index: 500;
434-
}
435-
436-
.da-list-status-toast {
437-
width: 280px;
438-
background: var(--s2-blue-800);
439-
line-height: 48px;
440-
border-radius: 6px;
441-
filter: drop-shadow(rgb(0 0 0 / 15%) 0 1px 4px);
442-
justify-content: space-between;
443-
align-items: center;
444-
box-sizing: border-box;
445-
color: #FFF;
446-
font-size: 14px;
447-
overflow: hidden;
448-
}
449-
450-
.da-list-status-title {
451-
font-weight: 700;
452-
padding: 0 12px 0 40px;
453-
margin: 0;
454-
}
455-
456-
.da-list-status-description {
457-
line-height: 1.6;
458-
padding: 6px 12px;
459-
margin: 0;
460-
background: rgb(255 255 255 / 10%);
461-
}
462-
463-
.da-list-status-type-info .da-list-status-title {
464-
background: var(--s2-blue-800) url('/blocks/browse/img/Smock_InfoOutline_18_N.svg') 12px 50% no-repeat;
465-
}

blocks/browse/da-sites/da-sites.js

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function getRandom() {
1313
export default class DaSites extends LitElement {
1414
static properties = {
1515
_recents: { state: true },
16-
_status: { state: true },
16+
_toast: { state: true },
1717
_urlError: { state: true },
1818
};
1919

@@ -26,6 +26,7 @@ export default class DaSites extends LitElement {
2626
super.connectedCallback();
2727
this.shadowRoot.adoptedStyleSheets = [styles];
2828
this._recents = this.getRecents();
29+
import('../../shared/da-toast/da-toast.js');
2930
}
3031

3132
getRecents() {
@@ -42,10 +43,6 @@ export default class DaSites extends LitElement {
4243
return null;
4344
}
4445

45-
setStatus(text, description, type = 'info') {
46-
this._status = text ? { type, text, description } : null;
47-
}
48-
4946
handleRemove(site) {
5047
// Get the index of the site to remove
5148
const idx = this._recents.findIndex((recent) => recent.name === site.name);
@@ -100,18 +97,7 @@ export default class DaSites extends LitElement {
10097
const data = [new ClipboardItem({ [blob.type]: blob })];
10198
navigator.clipboard.write(data);
10299

103-
this.setStatus('Copied', 'The link was copied to the clipboard.');
104-
setTimeout(() => { this.setStatus(); }, 3000);
105-
}
106-
107-
renderStatus() {
108-
return html`
109-
<div class="da-list-status">
110-
<div class="da-list-status-toast da-list-status-type-${this._status.type}">
111-
<p class="da-list-status-title">${this._status.text}</p>
112-
${this._status.description ? html`<p class="da-list-status-description">${this._status.description}</p>` : nothing}
113-
</div>
114-
</div>`;
100+
this._toast = { text: 'Copied', description: 'The link was copied to the clipboard.' };
115101
}
116102

117103
renderGo() {
@@ -230,7 +216,7 @@ export default class DaSites extends LitElement {
230216
</a>
231217
</div>
232218
</div>
233-
${this._status ? this.renderStatus() : nothing}
219+
<da-toast .toast=${this._toast} @close=${() => { this._toast = null; }}></da-toast>
234220
`;
235221
}
236222
}

blocks/canvas/canvas.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getNx } from '../../scripts/utils.js';
22
import { editorSelectChange } from './editor-utils/editor-utils.js';
3+
import { getCommentsBridge } from './editor-utils/comments-bridge.js';
34
import {
45
normalizeCanvasEditorView,
56
readInitialCanvasEditorView,
@@ -19,6 +20,14 @@ import { resolveEditorDocSession } from './ew-editor-doc/utils/load-editor-doc.j
1920
import { sourceUrlFromEditorCtx } from './ew-editor-doc/utils/ctx.js';
2021
import { SEL_BLOCK, SEL_ITEM, SEL_TEXT } from './ew-editor-doc/utils/selection.js';
2122

23+
export function handleCommentShortcut(event, { controller, openPanel }) {
24+
const isShortcut = (event.metaKey || event.ctrlKey) && event.altKey && event.code === 'KeyM';
25+
if (!isShortcut) return;
26+
event.preventDefault();
27+
controller?.requestCompose();
28+
openPanel();
29+
}
30+
2231
const { loadStyle, hashChange } = await import(`${getNx()}/utils/utils.js`);
2332
const { getPanelStore, openPanel } = await import(`${getNx()}/utils/panel.js`);
2433

@@ -217,6 +226,13 @@ export default async function decorate(block) {
217226
const { org, site } = hashState();
218227
const header = await installCanvasHeader(block, { org, site });
219228

229+
window.addEventListener('keydown', (event) => {
230+
handleCommentShortcut(event, {
231+
controller: getCommentsBridge().controller,
232+
openPanel: () => openCanvasPanel('after', { panelName: 'comments' }),
233+
});
234+
});
235+
220236
const mountRoot = canvasEditorMountRoot(block);
221237
mountRoot.classList.add('nx-canvas-editor-mount');
222238
syncEditorSplitLayout({ mountRoot, view: header.editorView });

blocks/canvas/editor-utils/command-defs.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
isImageNodeSelected,
2929
selectionHasLink,
3030
removeLink,
31+
requestComment,
32+
canComment,
3133
} from './command-helpers.js';
3234
import { openLinkDialog, openAltDialog, triggerAddImage } from './selection-toolbar.js';
3335

@@ -339,6 +341,16 @@ export const COMMANDS = [
339341
apply: triggerAddImage,
340342
},
341343

344+
// Toolbar: comment (end of the toolbar, after image)
345+
{
346+
id: 'add-comment',
347+
label: 'Comment',
348+
icon: iconName('comment'),
349+
showIn: ['toolbar-comment'],
350+
visible: canComment,
351+
apply: requestComment,
352+
},
353+
342354
// Slash menu: text section only
343355
{
344356
id: 'section-break',

blocks/canvas/editor-utils/command-helpers.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
splitCell,
1919
isInTable,
2020
} from 'da-y-wrapper';
21+
import { getCommentsBridge } from './comments-bridge.js';
22+
import { getSelectionData } from '../ew-comments/helpers/anchor.js';
2123

2224
/* ---- Apply factories ---- */
2325

@@ -274,6 +276,23 @@ export function removeLink(view) {
274276
view.dispatch(tr);
275277
}
276278

279+
/* ---- Comments ---- */
280+
281+
export function requestComment(_) {
282+
document.querySelector('ew-canvas-header')?.dispatchEvent(new CustomEvent('nx-canvas-open-panel', {
283+
bubbles: true,
284+
composed: true,
285+
detail: { position: 'after', panelName: 'comments' },
286+
}));
287+
getCommentsBridge().controller?.requestCompose();
288+
}
289+
290+
// Only show the comment action when the selection can be anchored to a comment
291+
// (non-empty text, or an image/table node selection).
292+
export function canComment(state) {
293+
return getSelectionData(state) != null;
294+
}
295+
277296
/* ---- Block-type picker value ---- */
278297

279298
const SCHEMA_NODE_TO_ID = new Map([
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const bridge = { controller: null };
2+
3+
export function getCommentsBridge() {
4+
return bridge;
5+
}
6+
7+
export function setCommentsController(controller) {
8+
bridge.controller = controller ?? null;
9+
document.dispatchEvent(new CustomEvent('nx-comments-controller-change', {
10+
bubbles: true,
11+
composed: true,
12+
detail: { controller: bridge.controller },
13+
}));
14+
}

0 commit comments

Comments
 (0)