(core) Updating flow and UI for shortcut warnings

Summary:
- Popup looks different (better shadow, order and alignment)
- Warnings need to be dismissed by checking "Don't show again" button, pressing
  Esc/Enter or clicking away just hides the popup, but it will be opened once again.
- Dismissing one warning popup (about zoom keys), dismisses them all

Test Plan: Updated

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3683
This commit is contained in:
Jarosław Sadziński 2022-10-25 21:04:23 +02:00
parent 64710b60f3
commit fb16c3de56
4 changed files with 49 additions and 22 deletions

View File

@ -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));

View File

@ -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))
);
};

View File

@ -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, `

View File

@ -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;