From f0802dc4711c4c51079a407510aee8b2b5011e29 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Thu, 25 Feb 2021 18:05:44 +0100 Subject: [PATCH] command palette control --- packages/web/public/bulma.css | 419 ++++++++++++++++++ packages/web/public/index.html | 1 + packages/web/src/Screen.svelte | 17 +- .../web/src/commands/CommandPalette.svelte | 84 ++++ packages/web/src/commands/registerCommand.ts | 39 ++ packages/web/src/commands/runCommand.ts | 9 + packages/web/src/commands/stdCommands.ts | 17 + packages/web/src/main.ts | 1 + packages/web/src/stores.ts | 3 + packages/web/src/utility/clickOutside.ts | 15 + packages/web/src/utility/keycodes.js | 99 +++++ .../web/src/widgets/WidgetIconPanel.svelte | 5 +- packages/web/tsconfig.json | 1 + 13 files changed, 706 insertions(+), 4 deletions(-) create mode 100644 packages/web/public/bulma.css create mode 100644 packages/web/src/commands/CommandPalette.svelte create mode 100644 packages/web/src/commands/registerCommand.ts create mode 100644 packages/web/src/commands/runCommand.ts create mode 100644 packages/web/src/commands/stdCommands.ts create mode 100644 packages/web/src/utility/clickOutside.ts create mode 100644 packages/web/src/utility/keycodes.js diff --git a/packages/web/public/bulma.css b/packages/web/public/bulma.css new file mode 100644 index 00000000..6492cd0c --- /dev/null +++ b/packages/web/public/bulma.css @@ -0,0 +1,419 @@ +.m-0 { + margin: 0 !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mr-0 { + margin-right: 0 !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.ml-0 { + margin-left: 0 !important; +} + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mr-1 { + margin-right: 0.25rem !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1 { + margin-left: 0.25rem !important; +} + +.mx-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mr-2 { + margin-right: 0.5rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2 { + margin-left: 0.5rem !important; +} + +.mx-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.m-3 { + margin: 0.75rem !important; +} + +.mt-3 { + margin-top: 0.75rem !important; +} + +.mr-3 { + margin-right: 0.75rem !important; +} + +.mb-3 { + margin-bottom: 0.75rem !important; +} + +.ml-3 { + margin-left: 0.75rem !important; +} + +.mx-3 { + margin-left: 0.75rem !important; + margin-right: 0.75rem !important; +} + +.my-3 { + margin-top: 0.75rem !important; + margin-bottom: 0.75rem !important; +} + +.m-4 { + margin: 1rem !important; +} + +.mt-4 { + margin-top: 1rem !important; +} + +.mr-4 { + margin-right: 1rem !important; +} + +.mb-4 { + margin-bottom: 1rem !important; +} + +.ml-4 { + margin-left: 1rem !important; +} + +.mx-4 { + margin-left: 1rem !important; + margin-right: 1rem !important; +} + +.my-4 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.m-5 { + margin: 1.5rem !important; +} + +.mt-5 { + margin-top: 1.5rem !important; +} + +.mr-5 { + margin-right: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 1.5rem !important; +} + +.ml-5 { + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; +} + +.my-5 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.m-6 { + margin: 3rem !important; +} + +.mt-6 { + margin-top: 3rem !important; +} + +.mr-6 { + margin-right: 3rem !important; +} + +.mb-6 { + margin-bottom: 3rem !important; +} + +.ml-6 { + margin-left: 3rem !important; +} + +.mx-6 { + margin-left: 3rem !important; + margin-right: 3rem !important; +} + +.my-6 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pr-0 { + padding-right: 0 !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pl-0 { + padding-left: 0 !important; +} + +.px-0 { + padding-left: 0 !important; + padding-right: 0 !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pr-1 { + padding-right: 0.25rem !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1 { + padding-left: 0.25rem !important; +} + +.px-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pr-2 { + padding-right: 0.5rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2 { + padding-left: 0.5rem !important; +} + +.px-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.p-3 { + padding: 0.75rem !important; +} + +.pt-3 { + padding-top: 0.75rem !important; +} + +.pr-3 { + padding-right: 0.75rem !important; +} + +.pb-3 { + padding-bottom: 0.75rem !important; +} + +.pl-3 { + padding-left: 0.75rem !important; +} + +.px-3 { + padding-left: 0.75rem !important; + padding-right: 0.75rem !important; +} + +.py-3 { + padding-top: 0.75rem !important; + padding-bottom: 0.75rem !important; +} + +.p-4 { + padding: 1rem !important; +} + +.pt-4 { + padding-top: 1rem !important; +} + +.pr-4 { + padding-right: 1rem !important; +} + +.pb-4 { + padding-bottom: 1rem !important; +} + +.pl-4 { + padding-left: 1rem !important; +} + +.px-4 { + padding-left: 1rem !important; + padding-right: 1rem !important; +} + +.py-4 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.p-5 { + padding: 1.5rem !important; +} + +.pt-5 { + padding-top: 1.5rem !important; +} + +.pr-5 { + padding-right: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 1.5rem !important; +} + +.pl-5 { + padding-left: 1.5rem !important; +} + +.px-5 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; +} + +.py-5 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.p-6 { + padding: 3rem !important; +} + +.pt-6 { + padding-top: 3rem !important; +} + +.pr-6 { + padding-right: 3rem !important; +} + +.pb-6 { + padding-bottom: 3rem !important; +} + +.pl-6 { + padding-left: 3rem !important; +} + +.px-6 { + padding-left: 3rem !important; + padding-right: 3rem !important; +} + +.py-6 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} diff --git a/packages/web/public/index.html b/packages/web/public/index.html index a2cb44ac..8dd8402c 100644 --- a/packages/web/public/index.html +++ b/packages/web/public/index.html @@ -11,6 +11,7 @@ + diff --git a/packages/web/src/Screen.svelte b/packages/web/src/Screen.svelte index db77a107..21a3ff5c 100644 --- a/packages/web/src/Screen.svelte +++ b/packages/web/src/Screen.svelte @@ -1,12 +1,13 @@ -
+
@@ -22,6 +23,11 @@ import TabContent from './TabContent.svelte';
+ {#if $visibleCommandPalette} +
+ +
+ {/if}
diff --git a/packages/web/src/commands/CommandPalette.svelte b/packages/web/src/commands/CommandPalette.svelte new file mode 100644 index 00000000..a5c94634 --- /dev/null +++ b/packages/web/src/commands/CommandPalette.svelte @@ -0,0 +1,84 @@ + + + + +
($visibleCommandPalette = false)}> + + {#each filteredItems as command, index} +
handleCommand(command)}> + {command.text} +
+ {/each} +
+ + diff --git a/packages/web/src/commands/registerCommand.ts b/packages/web/src/commands/registerCommand.ts new file mode 100644 index 00000000..90cca00f --- /dev/null +++ b/packages/web/src/commands/registerCommand.ts @@ -0,0 +1,39 @@ +import { commands } from '../stores'; + +export interface SubCommand { + text: string; + onClick: Function; +} + +export interface GlobalCommand { + id: string; + text: string; + getSubCommands?: () => SubCommand[]; + onClick?: Function; + enabledStore?: any; + icon?: string; + toolbar?: boolean; + enabled?: boolean; +} + +export default function registerCommand(command: GlobalCommand) { + const { enabledStore } = command; + commands.update(x => ({ + ...x, + [command.id]: { + ...command, + enabled: !enabledStore, + }, + })); + if (enabledStore) { + enabledStore.subscribe(value => { + commands.update(x => ({ + ...x, + [command.id]: { + ...x[command.id], + enabled: value, + }, + })); + }); + } +} diff --git a/packages/web/src/commands/runCommand.ts b/packages/web/src/commands/runCommand.ts new file mode 100644 index 00000000..26251c21 --- /dev/null +++ b/packages/web/src/commands/runCommand.ts @@ -0,0 +1,9 @@ +import { get } from 'svelte/store'; +import { commands } from '../stores'; +import { GlobalCommand } from './registerCommand'; + +export default function runCommand(commandId: string) { + const commandsValue = get(commands); + const command: GlobalCommand = commandsValue[commandId]; + if (command.enabled) command.onClick(); +} diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts new file mode 100644 index 00000000..a145d8f9 --- /dev/null +++ b/packages/web/src/commands/stdCommands.ts @@ -0,0 +1,17 @@ +import { currentTheme } from '../stores'; +import registerCommand from './registerCommand'; + +registerCommand({ + id: 'theme.changeTheme', + text: 'Theme: Change', + getSubCommands: () => [ + { + text: 'Light', + onClick: () => currentTheme.set('theme-light'), + }, + { + text: 'Dark', + onClick: () => currentTheme.set('theme-dark'), + }, + ], +}); diff --git a/packages/web/src/main.ts b/packages/web/src/main.ts index 4d5a7685..9f4a3a23 100644 --- a/packages/web/src/main.ts +++ b/packages/web/src/main.ts @@ -1,5 +1,6 @@ import App from './App.svelte'; import './utility/connectionsPinger'; +import './commands/stdCommands'; const app = new App({ target: document.body, diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 15f9e542..895f5081 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -25,5 +25,8 @@ export const openedConnections = writable([]); export const currentDatabase = writable(null); export const openedTabs = writableWithStorage([], 'openedTabs'); export const extensions = writable(null); +export const visibleCommandPalette = writable(false); +export const commands = writable({}); +export const currentTheme = writableWithStorage('theme-light', 'currentTheme'); // export const leftPanelWidth = writable(300); diff --git a/packages/web/src/utility/clickOutside.ts b/packages/web/src/utility/clickOutside.ts new file mode 100644 index 00000000..0e694f06 --- /dev/null +++ b/packages/web/src/utility/clickOutside.ts @@ -0,0 +1,15 @@ +export function clickOutside(node) { + const handleClick = event => { + if (node && !node.contains(event.target) && !event.defaultPrevented) { + node.dispatchEvent(new CustomEvent('clickOutside', node)); + } + }; + + document.addEventListener('click', handleClick, true); + + return { + destroy() { + document.removeEventListener('click', handleClick, true); + }, + }; +} diff --git a/packages/web/src/utility/keycodes.js b/packages/web/src/utility/keycodes.js new file mode 100644 index 00000000..4c02d1af --- /dev/null +++ b/packages/web/src/utility/keycodes.js @@ -0,0 +1,99 @@ +export default { + backspace: 8, + tab: 9, + enter: 13, + shift: 16, + ctrl: 17, + alt: 18, + pauseBreak: 19, + capsLock: 20, + escape: 27, + pageUp: 33, + pageDown: 34, + end: 35, + home: 36, + leftArrow: 37, + upArrow: 38, + rightArrow: 39, + downArrow: 40, + insert: 45, + delete: 46, + n0: 48, + n1: 49, + n2: 50, + n3: 51, + n4: 52, + n5: 53, + n6: 54, + n7: 55, + n8: 56, + n9: 57, + a: 65, + b: 66, + c: 67, + d: 68, + e: 69, + f: 70, + g: 71, + h: 72, + i: 73, + j: 74, + k: 75, + l: 76, + m: 77, + n: 78, + o: 79, + p: 80, + q: 81, + r: 82, + s: 83, + t: 84, + u: 85, + v: 86, + w: 87, + x: 88, + y: 89, + z: 90, + leftWindowKey: 91, + rightWindowKey: 92, + selectKey: 93, + numPad0: 96, + numPad1: 97, + numPad2: 98, + numPad3: 99, + numPad4: 100, + numPad5: 101, + numPad6: 102, + numPad7: 103, + numPad8: 104, + numPad9: 105, + multiply: 106, + add: 107, + subtract: 109, + decimalPoint: 110, + divide: 111, + f1: 112, + f2: 113, + f3: 114, + f4: 115, + f5: 116, + f6: 117, + f7: 118, + f8: 119, + f9: 120, + f10: 121, + f12: 123, + numLock: 144, + scrollLock: 145, + semiColon: 186, + equalSign: 187, + comma: 188, + dash: 189, + period: 190, + forwardSlash: 191, + graveAccent: 192, + openBracket: 219, + backSlash: 220, + closeBracket: 221, + singleQuote: 222, +}; diff --git a/packages/web/src/widgets/WidgetIconPanel.svelte b/packages/web/src/widgets/WidgetIconPanel.svelte index 19415f4a..0a6be95a 100644 --- a/packages/web/src/widgets/WidgetIconPanel.svelte +++ b/packages/web/src/widgets/WidgetIconPanel.svelte @@ -1,6 +1,6 @@ +
($visibleCommandPalette = true)}> + +
{#each widgets as item}
handleChangeWidget(item.name)}> diff --git a/packages/web/tsconfig.json b/packages/web/tsconfig.json index 265a2590..e7506e66 100644 --- a/packages/web/tsconfig.json +++ b/packages/web/tsconfig.json @@ -5,6 +5,7 @@ "exclude": ["node_modules/*", "public/*"], "compilerOptions": { + "moduleResolution": "node", "allowSyntheticDefaultImports": true, "esModuleInterop": true, "skipLibCheck": true,