Shortcut menu instead of buttons
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { ActionButton, Notification } from "../types";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ShortcutItem, Notification } from "../types";
|
||||
|
||||
function prettyName(s: string | undefined): string {
|
||||
if (!s) {
|
||||
@@ -11,7 +12,7 @@ export function TopBar({
|
||||
pageName,
|
||||
unsavedChanges,
|
||||
notifications,
|
||||
actionButtons,
|
||||
shortcutItems,
|
||||
onClick,
|
||||
lhs,
|
||||
rhs,
|
||||
@@ -19,11 +20,25 @@ export function TopBar({
|
||||
pageName?: string;
|
||||
unsavedChanges: boolean;
|
||||
notifications: Notification[];
|
||||
actionButtons: ActionButton[];
|
||||
shortcutItems: ShortcutItem[];
|
||||
onClick: () => void;
|
||||
lhs?: React.ReactNode;
|
||||
rhs?: React.ReactNode;
|
||||
}) {
|
||||
const [menuExpanded, setMenuExpanded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
function closer() {
|
||||
setMenuExpanded(false);
|
||||
}
|
||||
|
||||
document.addEventListener("click", closer);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("click", closer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div id="top" onClick={onClick}>
|
||||
{lhs}
|
||||
@@ -42,18 +57,33 @@ export function TopBar({
|
||||
</div>
|
||||
)}
|
||||
<div className="actions">
|
||||
{actionButtons.map((actionButton, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
actionButton.run();
|
||||
}}
|
||||
title={actionButton.tooltip}
|
||||
>
|
||||
{actionButton.label}
|
||||
</button>
|
||||
))}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
setMenuExpanded(!menuExpanded);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
...
|
||||
</button>
|
||||
{menuExpanded && (
|
||||
<ul>
|
||||
{shortcutItems.map((actionButton, idx) => (
|
||||
<li key={idx}>
|
||||
<a
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setMenuExpanded(false);
|
||||
actionButton.run();
|
||||
}}
|
||||
>
|
||||
{actionButton.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -127,11 +127,11 @@ export class Editor {
|
||||
// Command hook
|
||||
this.commandHook = new CommandHook();
|
||||
this.commandHook.on({
|
||||
commandsUpdated: (commandMap, actionButtons) => {
|
||||
commandsUpdated: (commandMap, shortcutItems) => {
|
||||
this.viewDispatch({
|
||||
type: "update-commands",
|
||||
commands: commandMap,
|
||||
actionButtons: actionButtons,
|
||||
shortcutItems: shortcutItems,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -669,15 +669,15 @@ export class Editor {
|
||||
pageName={viewState.currentPage}
|
||||
notifications={viewState.notifications}
|
||||
unsavedChanges={viewState.unsavedChanges}
|
||||
actionButtons={[
|
||||
shortcutItems={[
|
||||
{
|
||||
label: "⚡️",
|
||||
label: "Run command",
|
||||
orderId: 0,
|
||||
run: () => {
|
||||
this.viewDispatch({ type: "show-palette" });
|
||||
},
|
||||
},
|
||||
...viewState.actionButtons,
|
||||
...viewState.shortcutItems,
|
||||
]}
|
||||
onClick={() => {
|
||||
dispatch({ type: "start-navigate" });
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Hook, Manifest } from "@plugos/plugos/types";
|
||||
import { System } from "@plugos/plugos/system";
|
||||
import { EventEmitter } from "@plugos/plugos/event";
|
||||
import { ActionButton } from "../types";
|
||||
import { ShortcutItem } from "../types";
|
||||
|
||||
export type CommandDef = {
|
||||
name: string;
|
||||
@@ -12,13 +12,12 @@ export type CommandDef = {
|
||||
key?: string;
|
||||
mac?: string;
|
||||
|
||||
// Action button
|
||||
button?: ButtonDef;
|
||||
// Shortcuts in UI
|
||||
shortcut?: ShortcutDef;
|
||||
};
|
||||
|
||||
export type ButtonDef = {
|
||||
export type ShortcutDef = {
|
||||
label: string;
|
||||
tooltip?: string;
|
||||
};
|
||||
|
||||
export type AppCommand = {
|
||||
@@ -33,7 +32,7 @@ export type CommandHookT = {
|
||||
export type CommandHookEvents = {
|
||||
commandsUpdated(
|
||||
commandMap: Map<string, AppCommand>,
|
||||
appButtons: ActionButton[]
|
||||
appButtons: ShortcutItem[]
|
||||
): void;
|
||||
};
|
||||
|
||||
@@ -42,11 +41,11 @@ export class CommandHook
|
||||
implements Hook<CommandHookT>
|
||||
{
|
||||
editorCommands = new Map<string, AppCommand>();
|
||||
actionButtons: ActionButton[] = [];
|
||||
shortcutItems: ShortcutItem[] = [];
|
||||
|
||||
buildAllCommands(system: System<CommandHookT>) {
|
||||
this.editorCommands.clear();
|
||||
this.actionButtons = [];
|
||||
this.shortcutItems = [];
|
||||
for (let plug of system.loadedPlugs.values()) {
|
||||
for (const [name, functionDef] of Object.entries(
|
||||
plug.manifest!.functions
|
||||
@@ -61,10 +60,9 @@ export class CommandHook
|
||||
return plug.invoke(name, []);
|
||||
},
|
||||
});
|
||||
if (cmd.button) {
|
||||
this.actionButtons.push({
|
||||
label: cmd.button.label,
|
||||
tooltip: cmd.button.tooltip,
|
||||
if (cmd.shortcut) {
|
||||
this.shortcutItems.push({
|
||||
label: cmd.shortcut.label,
|
||||
run: () => {
|
||||
return plug.invoke(name, []);
|
||||
},
|
||||
@@ -72,7 +70,7 @@ export class CommandHook
|
||||
}
|
||||
}
|
||||
}
|
||||
this.emit("commandsUpdated", this.editorCommands, this.actionButtons);
|
||||
this.emit("commandsUpdated", this.editorCommands, this.shortcutItems);
|
||||
}
|
||||
|
||||
apply(system: System<CommandHookT>): void {
|
||||
|
||||
@@ -76,7 +76,7 @@ export default function reducer(
|
||||
return {
|
||||
...state,
|
||||
commands: action.commands,
|
||||
actionButtons: action.actionButtons,
|
||||
shortcutItems: action.shortcutItems,
|
||||
};
|
||||
case "show-notification":
|
||||
return {
|
||||
|
||||
@@ -58,12 +58,12 @@ body {
|
||||
#top {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
z-index: 20;
|
||||
|
||||
height: $top-bar-height;
|
||||
background-color: rgb(213, 213, 213);
|
||||
border-bottom: rgb(193, 193, 193) 1px solid;
|
||||
color: rgb(55, 55, 55);
|
||||
|
||||
.main {
|
||||
flex: 2;
|
||||
|
||||
@@ -73,6 +73,10 @@ body {
|
||||
font-size: 28px;
|
||||
padding: 10px 20px;
|
||||
|
||||
@media (max-width: $max-editor-width) {
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
.status {
|
||||
position: absolute;
|
||||
font-family: "iA-Mono";
|
||||
@@ -90,6 +94,14 @@ body {
|
||||
.current-page {
|
||||
font-family: var(--ui-font);
|
||||
font-weight: bold;
|
||||
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-right: 40px;
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
direction: rtl;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@@ -107,15 +119,36 @@ body {
|
||||
}
|
||||
.actions {
|
||||
float: right;
|
||||
text-align: right;
|
||||
margin-top: -35px;
|
||||
|
||||
button {
|
||||
border: 0;
|
||||
// border-radius: 5px;
|
||||
// background-color: rgba(77,141,255,0.07);
|
||||
background-color: transparent;
|
||||
padding: 3px;
|
||||
font-family: "IA-Mono", "Menlo";
|
||||
font-size: 80%;
|
||||
ul {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
list-style: none;
|
||||
background: #fff;
|
||||
border: #000 1px solid;
|
||||
text-align: left;
|
||||
|
||||
a {
|
||||
padding: 3px;
|
||||
font-family: var(--ui-font);
|
||||
font-size: 50%;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
background-color: #4d8dff12;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,8 @@ export type Notification = {
|
||||
date: Date;
|
||||
};
|
||||
|
||||
export type ActionButton = {
|
||||
export type ShortcutItem = {
|
||||
label: string;
|
||||
tooltip?: string;
|
||||
orderId?: number;
|
||||
run: () => void;
|
||||
};
|
||||
@@ -35,7 +34,7 @@ export type AppViewState = {
|
||||
allPages: Set<PageMeta>;
|
||||
commands: Map<string, AppCommand>;
|
||||
notifications: Notification[];
|
||||
actionButtons: ActionButton[];
|
||||
shortcutItems: ShortcutItem[];
|
||||
recentCommands: Map<string, Date>;
|
||||
|
||||
showFilterBox: boolean;
|
||||
@@ -61,7 +60,7 @@ export const initialViewState: AppViewState = {
|
||||
commands: new Map(),
|
||||
recentCommands: new Map(),
|
||||
notifications: [],
|
||||
actionButtons: [],
|
||||
shortcutItems: [],
|
||||
showFilterBox: false,
|
||||
filterBoxHelpText: "",
|
||||
filterBoxLabel: "",
|
||||
@@ -80,7 +79,7 @@ export type Action =
|
||||
| {
|
||||
type: "update-commands";
|
||||
commands: Map<string, AppCommand>;
|
||||
actionButtons: ActionButton[];
|
||||
shortcutItems: ShortcutItem[];
|
||||
}
|
||||
| { type: "show-palette"; context?: string }
|
||||
| { type: "hide-palette" }
|
||||
|
||||
Reference in New Issue
Block a user