diff --git a/app/client/components/DeprecatedCommands.ts b/app/client/components/DeprecatedCommands.ts index a66baa55..aef29912 100644 --- a/app/client/components/DeprecatedCommands.ts +++ b/app/client/components/DeprecatedCommands.ts @@ -63,28 +63,46 @@ export class DeprecatedCommands extends Disposable { } private _handleCommand(c: Command) { - const seenWarnings = this._gristDoc.docPageModel.appModel.deprecatedWarnings; if (!this._hasSeenWarning(c.name)) { - markAsSeen(seenWarnings, c.name); - this._showWarning(c.desc); + this._showWarning(c); return false; // Stop processing. } else { return true; // Continue processing. } } - private _showWarning(desc: string) { + private _showWarning(c: Command) { // Try to figure out where to show the message. If we have active view, we can try // to find the selected cell and show the message there. Otherwise, we show it in the // bottom right corner as a warning. const selectedCell = this._gristDoc.currentView.get()?.viewPane.querySelector(".selected_cursor"); + const seenWarnings = this._gristDoc.docPageModel.appModel.deprecatedWarnings; + function onClose(checked: boolean) { + if (checked) { + // For deprecated zoom commands we have the same messages, so mark them as seen. + const zoomCommands: DeprecationWarning[] = [ + 'deprecatedDeleteRecords', + 'deprecatedInsertRecordAfter', + 'deprecatedInsertRowBefore', + ]; + if (zoomCommands.includes(c.name as any)) { + zoomCommands.forEach((name) => markAsSeen(seenWarnings, name)); + } else { + markAsSeen(seenWarnings, c.name); + } + } + } if (!selectedCell) { - reportMessage(() => dom('div', this._createMessage(desc)), { + reportMessage(() => dom('div', this._createMessage(c.desc)), { level: 'info', key: 'deprecated-command', }); } else { - showDeprecatedWarning(selectedCell, this._createMessage(desc)); + showDeprecatedWarning( + selectedCell, + this._createMessage(c.desc), + onClose + ); } } @@ -103,7 +121,7 @@ export class DeprecatedCommands extends Disposable { if (part[0] === '{') { const otherCommand = commands.allCommands[part.slice(1, -1)]; if (otherCommand) { - elements.push(otherCommand.getKeysDom()); + elements.push(otherCommand.getKeysDom(() => dom('span', 'or'))); } } else { elements.push(cssTallerText(part)); diff --git a/app/client/components/commands.js b/app/client/components/commands.js index 38a91ec2..4cd6197f 100644 --- a/app/client/components/commands.js +++ b/app/client/components/commands.js @@ -159,9 +159,10 @@ Command.prototype.getDesc = function() { /** * Returns DOM for the keyboard shortcuts, wrapped in cute boxes that look like keyboard keys. */ -Command.prototype.getKeysDom = function() { +Command.prototype.getKeysDom = function(separator) { return dom('span.shortcut_keys', - this.humanKeys.map(key => dom('span.shortcut_key_image', key)) + separator ? this.humanKeys.map((key, i) => [i ? separator() : null, dom('span.shortcut_key_image', key)]) + : this.humanKeys.map(key => dom('span.shortcut_key_image', key)) ); }; diff --git a/app/client/components/modals.ts b/app/client/components/modals.ts index 94b683f8..a02e383e 100644 --- a/app/client/components/modals.ts +++ b/app/client/components/modals.ts @@ -35,16 +35,16 @@ export function buildConfirmDelete( dom('div', `Are you sure you want to delete ${single ? 'this' : 'these'} record${single ? '' : 's'}?`, dom.style('margin-bottom', '10px'), ), + dom('div', + labeledSquareCheckbox(remember, "Don't ask again.", testId('confirm-remember')), + dom.style('margin-bottom', '10px'), + ), cssButtons( - dom.style('margin-bottom', '12px'), primaryButton('Delete', testId('confirm-save'), dom.on('click', () => { onSave(remember.get()); ctl.close(); })), basicButton('Cancel', testId('confirm-cancel'), dom.on('click', () => ctl.close())) - ), - dom('div', - labeledSquareCheckbox(remember, "Don't ask again.", testId('confirm-remember')), ) ), {} ); @@ -60,21 +60,29 @@ export function buildConfirmDelete( export function showDeprecatedWarning( refElement: Element, - content: DomContents + content: DomContents, + onClose: (checked: boolean) => void, ) { + const remember = observable(false); const tooltip = modalTooltip(refElement, (ctl) => cssWideContainer( testId('popup-warning-deprecated'), elem => { FocusLayer.create(ctl, {defaultFocusElem: elem, pauseMousetrap: true}); }, dom.onKeyDown({ - Escape: () => ctl.close(), - Enter: () => ctl.close(), + Escape: () => { ctl.close(); onClose(remember.get()); }, + Enter: () => { ctl.close(); onClose(remember.get()); }, }), content, cssButtons( dom.style('margin-top', '12px'), - dom.style('justify-content', 'right'), - basicButton('Close', testId('confirm-cancel'), dom.on('click', () => ctl.close())) + dom.style('justify-content', 'space-between'), + dom.style('align-items', 'center'), + dom('div', + labeledSquareCheckbox(remember, "Don't show again.", testId('confirm-remember')), + ), + basicButton('Dismiss', testId('confirm-save'), + dom.on('click', () => { ctl.close(); onClose(remember.get()); }) + ) ), ) ); @@ -133,7 +141,7 @@ const cssButtons = styled('div', ` `); const cssContainer = styled(cssTheme, ` - max-width: 210px; + max-width: 270px; `); const cssWideContainer = styled(cssTheme, ` diff --git a/app/client/ui2018/modals.ts b/app/client/ui2018/modals.ts index b2d8f723..0ff59a34 100644 --- a/app/client/ui2018/modals.ts +++ b/app/client/ui2018/modals.ts @@ -9,6 +9,7 @@ import {waitGrainObs} from 'app/common/gutil'; import {IOpenController, IPopupDomCreator, IPopupOptions, PopupControl, popupOpen} from 'popweasel'; import {Computed, Disposable, dom, DomContents, DomElementArg, input, keyframes, MultiHolder, Observable, styled} from 'grainjs'; +import {cssMenuElem} from 'app/client/ui2018/menus'; // IModalControl is passed into the function creating the body of the modal. export interface IModalControl { @@ -492,11 +493,10 @@ export function modalTooltip( /* CSS styled components */ -const cssModalTooltip = styled('div', ` - padding: 16px; +const cssModalTooltip = styled(cssMenuElem, ` + padding: 16px 24px; background: ${theme.modalBg}; border-radius: 3px; - box-shadow: 0 2px 18px 0 ${theme.modalInnerShadow}, 0 0 1px 0 ${theme.modalOuterShadow}; outline: none; & > div { outline: none;