mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-06-08 07:37:38 +00:00
Some checks are pending
/ release (push) Waiting to run
testing / test-e2e (push) Blocked by required conditions
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
The primary goal is to balance having the editor work as expected by developers (with Tab key affecting indentation) while also not impeding keyboard navigation.
* Tab indents, Shift+Tab unindents, but only when that indent would be valid. E.g. moving existing list items down or up one level.
* Indenting a selection always works.
* When an "invalid" indent is attempted, nothing happens and a toast is shown with a hint to press again to leave the editor.
* Attempting the same action again allows the textarea lose focus by allowing the browser's default key handler.
* Pressing Esc also loses focus immediately.
* No tab handling happens until the text editor has been interacted with (other than just having been focused).
* Changing indentation in block quotes adds or removes quote levels instead.
Screenshot of the toast being shown:
a6287d29
-4ce0-4977-aae8-ef1aff2ac89f
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6813
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: Danko Aleksejevs <danko@very.lv>
Co-committed-by: Danko Aleksejevs <danko@very.lv>
64 lines
1.9 KiB
JavaScript
64 lines
1.9 KiB
JavaScript
import {htmlEscape} from 'escape-goat';
|
|
import {svg} from '../svg.js';
|
|
import Toastify from 'toastify-js'; // don't use "async import", because when network error occurs, the "async import" also fails and nothing is shown
|
|
|
|
const levels = {
|
|
hint: {
|
|
icon: 'octicon-light-bulb',
|
|
background: 'var(--color-black-light)',
|
|
duration: 2500,
|
|
},
|
|
info: {
|
|
icon: 'octicon-check',
|
|
background: 'var(--color-green)',
|
|
duration: 2500,
|
|
},
|
|
warning: {
|
|
icon: 'gitea-exclamation',
|
|
background: 'var(--color-orange)',
|
|
duration: -1, // requires dismissal to hide
|
|
},
|
|
error: {
|
|
icon: 'gitea-exclamation',
|
|
background: 'var(--color-red)',
|
|
duration: -1, // requires dismissal to hide
|
|
},
|
|
};
|
|
|
|
// See https://github.com/apvarun/toastify-js#api for options
|
|
function showToast(message, level, {gravity, position, duration, useHtmlBody, ...other} = {}) {
|
|
const {icon, background, duration: levelDuration} = levels[level ?? 'info'];
|
|
const toast = Toastify({
|
|
text: `
|
|
<div class='toast-icon'>${svg(icon)}</div>
|
|
<div class='toast-body'>${useHtmlBody ? message : htmlEscape(message)}</div>
|
|
<button class='toast-close'>${svg('octicon-x')}</button>
|
|
`,
|
|
escapeMarkup: false,
|
|
gravity: gravity ?? 'top',
|
|
position: position ?? 'center',
|
|
duration: duration ?? levelDuration,
|
|
style: {background},
|
|
...other,
|
|
});
|
|
|
|
toast.showToast();
|
|
toast.toastElement.querySelector('.toast-close').addEventListener('click', () => toast.hideToast());
|
|
return toast;
|
|
}
|
|
|
|
export function showHintToast(message, opts) {
|
|
return showToast(message, 'hint', opts);
|
|
}
|
|
|
|
export function showInfoToast(message, opts) {
|
|
return showToast(message, 'info', opts);
|
|
}
|
|
|
|
export function showWarningToast(message, opts) {
|
|
return showToast(message, 'warning', opts);
|
|
}
|
|
|
|
export function showErrorToast(message, opts) {
|
|
return showToast(message, 'error', opts);
|
|
}
|