Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions blocks/canvas/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ export default async function decorate(block) {
syncEditorSplitLayout({ mountRoot, view: header.editorView });
installEditorSplitDrag(mountRoot);

mountRoot.addEventListener('nx-canvas-merge-conflicts', (e) => {
header.hasUnresolvedMergeConflicts = e.detail?.hasMergeConflicts ?? false;
if (header.hasUnresolvedMergeConflicts) header.setEditorView('content');
});

mountRoot.addEventListener('nx-editor-undo-state', (e) => {
header.undoAvailable = e.detail?.canUndo ?? false;
header.redoAvailable = e.detail?.canRedo ?? false;
Expand Down
20 changes: 20 additions & 0 deletions blocks/canvas/editor-utils/prose-merge-conflicts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Plugin } from 'da-y-wrapper';
import { checkForLocNodes } from '../../edit/prose/diff/diff-utils.js';
import { debounce } from '../../edit/utils/helpers.js';

export function createMergeConflictsPlugin(onMergeConflictsChange) {
const debouncedCheck = debounce((view) => {
onMergeConflictsChange?.(checkForLocNodes(view));
}, 500);

return new Plugin({
view(editorView) {
debouncedCheck(editorView);
return {
update(view, prevState) {
if (view.state.doc !== prevState.doc) debouncedCheck(view);
},
};
},
});
}
9 changes: 9 additions & 0 deletions blocks/canvas/ew-canvas-header/ew-canvas-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class EWCanvasHeader extends LitElement {
undoAvailable: { type: Boolean },
redoAvailable: { type: Boolean },
authorized: { type: Boolean },
hasUnresolvedMergeConflicts: { type: Boolean },
_chatDisabled: { state: true },
};

Expand All @@ -32,6 +33,7 @@ class EWCanvasHeader extends LitElement {
this.undoAvailable = false;
this.redoAvailable = false;
this.authorized = true;
this.hasUnresolvedMergeConflicts = false;
}

connectedCallback() {
Expand Down Expand Up @@ -82,7 +84,12 @@ class EWCanvasHeader extends LitElement {
);
}

setEditorView(view) {
this._setEditorView(view);
}

_setEditorView(view) {
if (this.hasUnresolvedMergeConflicts && view !== 'content') return;
if (!EDITOR_VIEWS.includes(view) || view === this.editorView) return;
this.editorView = view;
this.dispatchEvent(
Expand Down Expand Up @@ -130,6 +137,7 @@ class EWCanvasHeader extends LitElement {
type="button"
class="segment ${this.editorView === 'layout' ? 'is-selected' : ''}"
aria-pressed=${this.editorView === 'layout'}
?disabled=${this.hasUnresolvedMergeConflicts}
@click=${() => this._setEditorView('layout')}
>Layout</button>
<button
Expand All @@ -144,6 +152,7 @@ class EWCanvasHeader extends LitElement {
aria-pressed=${this.editorView === 'split'}
aria-label="Split view"
title="Split view"
?disabled=${this.hasUnresolvedMergeConflicts}
@click=${() => this._setEditorView('split')}
>${this._renderIcon('gridCompare')}</button>
</div>
Expand Down
138 changes: 138 additions & 0 deletions blocks/canvas/ew-editor-doc/ew-editor-doc-diff.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/* stylelint-disable selector-class-pattern */

.loc-tabbed-container {
background: var(--s2-gray-25);
box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
border-radius: var(--s2-corner-radius-400);
}

.diff-tab-content {
background: var(--s2-gray-25);
}

.da-diff-btn-base {
border-radius: var(--s2-corner-radius-400);
height: 32px;
}

.da-diff-btn-base-element {
font-size: var(--s2-component-s-regular-font-size, 0.875rem);
font-weight: 600;

&:focus-visible {
outline: 2px solid var(--s2-blue-800);
outline-offset: 2px;
}
}

.da-diff-btn .confirm-btn::before,
.da-diff-btn-3part .diff-accept::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
background-color: currentcolor;
mask: no-repeat center / 16px url('/img/icons/s2-icon-checkmark-20-n.svg');
}

.da-diff-btn-3part .diff-delete::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
background-color: currentcolor;
mask: no-repeat center / 16px url('/img/icons/s2-icon-close-20-n.svg');
}

.da-diff-btn:is(.is-local, .is-upstream, .is-diff) .switch-btn,
.da-diff-btn-3part:is(.is-local, .is-upstream) .diff-label {
background: var(--s2-gray-100);
color: var(--s2-gray-800);
}

.da-diff-btn:is(.is-local, .is-upstream, .is-diff) .confirm-btn,
.da-diff-btn-3part:is(.is-local, .is-upstream) .diff-accept,
.da-diff-btn-3part:is(.is-local, .is-upstream) .diff-delete {
background: var(--s2-gray-800);
color: var(--s2-gray-25);
}

.da-diff-btn .confirm-btn:hover,
.da-diff-btn-3part .diff-accept:hover,
.da-diff-btn-3part .diff-delete:hover {
color: var(--s2-gray-25);
filter: brightness(1.1);
}

.da-diff-btn.is-active {
border-color: var(--s2-gray-900);
}

.da-diff-btn.is-active .switch-btn,
.da-diff-btn.is-active .confirm-btn {
color: var(--s2-gray-25);
}

.diff-tooltip {
background: var(--s2-gray-1000);
color: var(--s2-gray-25);
font-weight: 500;
border: none;
border-radius: var(--s2-corner-radius-400);
box-shadow: 0 2px 6px rgb(0 0 0 / 15%);
backdrop-filter: none;
}

.diff-tooltip::before {
display: none;
}

.diff-tooltip::after {
border-top-color: var(--s2-gray-1000);
filter: none;
}

.diff-tab-pane del.diffdel,
.diff-tab-pane del.diffmod {
background-color: var(--s2-red-200);
color: var(--s2-red-900);
border: none;
}

.diff-tab-pane ins.diffins,
.diff-tab-pane ins.diffmod {
background-color: var(--s2-green-200);
color: var(--s2-green-900);
border: none;
}

.loc-color-overlay.loc-regional {
background-color: color-mix(in srgb, var(--s2-green-200) 60%, transparent) !important;
}

.loc-color-overlay.loc-langstore {
background-color: color-mix(in srgb, var(--s2-red-200) 60%, transparent) !important;
}

.diff-bg-local {
background-color: color-mix(in srgb, var(--s2-green-200) 60%, transparent);
}

.diff-bg-upstream {
background-color: color-mix(in srgb, var(--s2-red-200) 60%, transparent);
}

.diff-bg-diff {
background-color: color-mix(in srgb, var(--s2-gray-100) 60%, transparent);
}

.da-regional-edits-overlay {
padding: var(--s2-spacing-200);
border-radius: var(--s2-corner-radius-400);
background: var(--s2-gray-25);
box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
}

.da-regional-edits-actions {
gap: var(--s2-spacing-200);
}
9 changes: 9 additions & 0 deletions blocks/canvas/ew-editor-doc/ew-editor-doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ export class EwEditorDoc extends LitElement {
}));
}

_emitMergeConflictsState(hasMergeConflicts) {
this.dispatchEvent(new CustomEvent('nx-canvas-merge-conflicts', {
bubbles: true,
composed: true,
detail: { hasMergeConflicts },
}));
}

_observeUndoManager(mgr) {
this._stopObservingUndoManager();
if (!mgr) return;
Expand Down Expand Up @@ -231,6 +239,7 @@ export class EwEditorDoc extends LitElement {
permissions,
setEditable: (editable) => this._setEditable(editable),
getToken: () => token,
onMergeConflictsChange: (hasConflicts) => this._emitMergeConflictsState(hasConflicts),
extraPlugins: [
createExtensionsBridgePlugin(),
createTrackingPlugin(
Expand Down
23 changes: 21 additions & 2 deletions blocks/canvas/ew-editor-doc/prose.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ import { getNx } from '../../../scripts/utils.js';
import { getAuthToken } from '../../shared/utils.js';
import { generateColor, getCollabIdentity } from './utils/collab.js';
import { checkBlockLibraryConfigured } from '../editor-utils/block-slash.js';
import { getDiffClass, addActiveView } from '../../edit/prose/diff/diff-utils.js';
import { initDaMetadata } from '../../edit/utils/helpers.js';
import { createMergeConflictsPlugin } from '../editor-utils/prose-merge-conflicts.js';

const { DA_ADMIN, DA_COLLAB, hashChange } = await import(`${getNx()}/utils/utils.js`);

Expand Down Expand Up @@ -82,7 +85,7 @@ function checkLibraryConfiguredOnSync(wsProvider, canWrite) {

export default async function initProse({
path, permissions, setEditable, getToken,
extraPlugins = [],
extraPlugins = [], onMergeConflictsChange,
}) {
const editor = document.createElement('div');
editor.className = 'da-prose-mirror';
Expand Down Expand Up @@ -211,19 +214,35 @@ export default async function initProse({

if (canWrite) {
plugins.unshift(createSlashMenuPlugin(), createSelectionToolbarPlugin());
plugins.push(imageFocalPoint());
plugins.push(imageFocalPoint(), createMergeConflictsPlugin(onMergeConflictsChange));
}

let state = EditorState.create({ schema, plugins });

const fix = fixTables(state);
if (fix) state = state.apply(fix.setMeta('addToHistory', false));

const diffNodeViews = canWrite ? {
diff_added(node, view, getPos) {
const MergeConflictsAddedView = getDiffClass('da-diff-added', getSchema, () => {}, { isUpstream: false });
return new MergeConflictsAddedView(node, view, getPos);
},
diff_deleted(node, view, getPos) {
const MergeConflictsDeletedView = getDiffClass('da-diff-deleted', getSchema, () => {}, { isUpstream: true });
return new MergeConflictsDeletedView(node, view, getPos);
},
} : undefined;

viewRef = new EditorView(editor, {
state,
editable() { return canWrite; },
nodeViews: diffNodeViews,
});

if (canWrite) addActiveView(viewRef);

initDaMetadata(ydoc.getMap('daMetadata'));

const undoManager = yUndoPluginKey.getState(viewRef.state)?.undoManager ?? null;

return { proseEl: editor, wsProvider, view: viewRef, ydoc, undoManager };
Expand Down
3 changes: 3 additions & 0 deletions blocks/canvas/ew-editor-doc/utils/teardown.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { removeActiveView } from '../../../edit/prose/diff/diff-utils.js';

export function teardownEditorDocResources({
clearPortHandler,
awarenessOff,
Expand All @@ -14,6 +16,7 @@ export function teardownEditorDocResources({
wsProvider.disconnect({ data: 'unmount' });
}
if (view) {
removeActiveView(view);
view.destroy();
}
if (proseEl?.parentNode) {
Expand Down
21 changes: 21 additions & 0 deletions blocks/canvas/ew-editor-wysiwyg/ew-editor-wysiwyg.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,35 @@ export class EwEditorWysiwyg extends LitElement {
this._syncCanvasVisibility();
};
this.parentElement?.addEventListener('nx-canvas-editor-active', this._onCanvasEditorActive);
this._onMergeConflictsChange = (e) => {
const hasMergeConflicts = e.detail?.hasMergeConflicts ?? false;
if (hasMergeConflicts) {
this._hadMergeConflicts = true;
} else if (this._hadMergeConflicts) {
this._hadMergeConflicts = false;
this._reloadIframe();
}
};
this.parentElement?.addEventListener('nx-canvas-merge-conflicts', this._onMergeConflictsChange);
this._syncCanvasVisibility();
}

disconnectedCallback() {
this.parentElement?.removeEventListener('nx-canvas-editor-active', this._onCanvasEditorActive);
this.parentElement?.removeEventListener('nx-canvas-merge-conflicts', this._onMergeConflictsChange);
this._clearQuickEditRetry();
super.disconnectedCallback();
}

_reloadIframe() {
const iframe = this.shadowRoot?.querySelector('iframe');
try {
iframe?.contentWindow?.location.reload();
} catch {
/* ignore — cross-origin reload should be allowed, but don't let this throw */
}
}

get _iframeSrc() {
const { org, repo, path } = this.ctx ?? {};
if (!org || !repo || !path || !this._cookieReady) return null;
Expand Down Expand Up @@ -106,6 +126,7 @@ export class EwEditorWysiwyg extends LitElement {
_resetCookieStateForCtxChange() {
this._clearQuickEditRetry();
this._cookieReady = false;
this._hadMergeConflicts = false;
}

updated(changed) {
Expand Down
Loading
Loading