Implemented actions for header menu
This commit is contained in:
parent
a9a7c78128
commit
54249b4ba6
6 changed files with 149 additions and 87 deletions
|
|
@ -143,4 +143,83 @@
|
|||
border-radius: 1rem;
|
||||
background-color: var(--foreground-color-c);
|
||||
margin: 0.5rem auto;
|
||||
}
|
||||
|
||||
.Header-menu {
|
||||
display: flex;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown {
|
||||
display: block;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
padding: 0 0.5rem;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown:hover, .Header-menu .Dropdown:focus-visible {
|
||||
background-color: rgba(255, 255, 255, 5%);
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown > .Label {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown-arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
padding: 0.35rem;
|
||||
background-color: var(--background-color-b);
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
border-bottom-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown:not(.Active) .Dropdown-content {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.Header-menu .Button {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
outline: none;
|
||||
font-size: 0.85rem;
|
||||
text-align: start;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Header-menu .Button:hover, .Header-menu .Button:focus-visible {
|
||||
background-color: hsla(var(--background-color-a-hsl), 75%);
|
||||
}
|
||||
|
||||
.Header-menu .Dropdown > .Label > p, .Header-menu .Button > .Label > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Header-menu .Shortcut {
|
||||
color: var(--foreground-color-b);
|
||||
margin: 0;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import { useScreenBounds } from "../../hooks/_utils/screen";
|
|||
export const STYLES = {
|
||||
CONTEXT_MENU: styles["Context-menu"],
|
||||
SHORTCUTS_LISTENER: styles["Shortcuts-listener"],
|
||||
HEADER_MENU: styles["Header-menu"]
|
||||
};
|
||||
|
||||
export interface ActionProps {
|
||||
|
|
@ -63,12 +64,13 @@ export function Actions({ children, className, onAnyTrigger, triggerParams, avoi
|
|||
if (isListener) {
|
||||
return iterateOverChildren((child.props as ActionProps).children);
|
||||
}
|
||||
|
||||
|
||||
return cloneElement(child, {
|
||||
...child.props,
|
||||
actionId,
|
||||
children: iterateOverChildren((child.props as ActionProps).children),
|
||||
onTrigger: (event, ...args) => {
|
||||
console.log(event);
|
||||
onAnyTrigger?.(event, triggerParams, ...args);
|
||||
onTrigger?.(event, triggerParams, ...args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,28 +3,39 @@ import styles from "../Actions.module.css";
|
|||
import { faCaretRight, IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
||||
import { ReactElement, useState } from "react";
|
||||
import { ActionProps } from "../Actions";
|
||||
import OutsideClickListener from "../../../hooks/_utils/outsideClick";
|
||||
|
||||
export function DropdownAction({ label, icon, children }: ActionProps): ReactElement {
|
||||
interface DropdownActionProps extends ActionProps {
|
||||
showOnHover?: boolean;
|
||||
}
|
||||
|
||||
export function DropdownAction({ label, icon, children, showOnHover = true }: DropdownActionProps): ReactElement {
|
||||
const [showContent, setShowContent] = useState(false);
|
||||
|
||||
const classNames = [styles.Dropdown];
|
||||
if (showContent)
|
||||
classNames.push(styles.Active);
|
||||
|
||||
return <div
|
||||
key={label}
|
||||
className={classNames.join(" ")}
|
||||
tabIndex={0}
|
||||
onMouseEnter={() => { setShowContent(true); }}
|
||||
onMouseLeave={() => { setShowContent(false); }}
|
||||
>
|
||||
<span className={styles.Label}>
|
||||
{icon && <div className={styles.Icon}><FontAwesomeIcon icon={icon as IconDefinition}/></div>}
|
||||
<p>{label}</p>
|
||||
</span>
|
||||
<div className={styles["Dropdown-arrow"]}><FontAwesomeIcon icon={faCaretRight}/></div>
|
||||
<div className={styles["Dropdown-content"]}>
|
||||
{children}
|
||||
return <OutsideClickListener onOutsideClick={() => {
|
||||
if (!showOnHover)
|
||||
setShowContent(false);
|
||||
}}>
|
||||
<div
|
||||
key={label}
|
||||
className={classNames.join(" ")}
|
||||
tabIndex={0}
|
||||
onMouseEnter={showOnHover ? () => { setShowContent(true); } : null}
|
||||
onMouseLeave={showOnHover ? () => { setShowContent(false); } : null}
|
||||
onClick={!showOnHover ? () => { setShowContent(!showContent); } : null}
|
||||
>
|
||||
<span className={styles.Label}>
|
||||
{icon && <div className={styles.Icon}><FontAwesomeIcon icon={icon as IconDefinition}/></div>}
|
||||
<p>{label}</p>
|
||||
</span>
|
||||
<div className={styles["Dropdown-arrow"]}><FontAwesomeIcon icon={faCaretRight}/></div>
|
||||
<div className={styles["Dropdown-content"]}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
</OutsideClickListener>;
|
||||
}
|
||||
|
|
@ -2,5 +2,6 @@
|
|||
display: flex;
|
||||
width: 100%;
|
||||
height: 1.5rem;
|
||||
min-height: 1.5rem;
|
||||
background-color: var(--background-color-a);
|
||||
}
|
||||
|
|
@ -1,20 +1,11 @@
|
|||
import { useShortcuts } from "../../../../hooks/_utils/keyboard";
|
||||
import { DropdownButton } from "../../../_utils/dropdown-button/DropdownButton";
|
||||
import styles from "./HeaderMenu.module.css";
|
||||
import { ActionsProps, Actions, STYLES } from "../../../actions/Actions";
|
||||
|
||||
interface HeaderMenuProps {
|
||||
options: Record<string, Record<string, Function>> | Record<string, Function>;
|
||||
shortcuts: Record<string, Record<string, string[]>> | Record<string, string[]>;
|
||||
}
|
||||
|
||||
export function HeaderMenu({ options, shortcuts }: HeaderMenuProps) {
|
||||
useShortcuts({ options, shortcuts });
|
||||
|
||||
return (
|
||||
<div className={styles.Container}>
|
||||
{Object.entries(options).map(([key, value]) =>
|
||||
<DropdownButton key={key} label={key} options={value} shortcuts={shortcuts[key]}/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
export function HeaderMenu({ children, ...props }: ActionsProps) {
|
||||
return <div className={styles.Container}>
|
||||
<Actions className={STYLES.HEADER_MENU} {...props}>
|
||||
{children}
|
||||
</Actions>
|
||||
</div>;
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@ import { FileSelector } from "../../modals/file-selector/FileSelector";
|
|||
import { SELECTOR_MODE } from "../../../config/apps/fileExplorer.config";
|
||||
import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile";
|
||||
import { WindowProps } from "../../windows/WindowView";
|
||||
import { DropdownAction } from "../../actions/actions/DropdownAction";
|
||||
import { ClickAction } from "../../actions/actions/ClickAction";
|
||||
|
||||
const OVERRIDES = {
|
||||
a: MarkdownLink,
|
||||
|
|
@ -125,60 +127,36 @@ export function TextEditor({ file, setTitle, setIconUrl, close, mode, app, modal
|
|||
|
||||
return (
|
||||
<div className={styles.Container} style={{ fontSize: zoom }}>
|
||||
<HeaderMenu
|
||||
options={{
|
||||
"File": {
|
||||
"New": newText,
|
||||
"Open": () => {
|
||||
openWindowedModal({
|
||||
size: DEFAULT_FILE_SELECTOR_SIZE,
|
||||
Modal: (props) => <FileSelector
|
||||
type={SELECTOR_MODE.SINGLE}
|
||||
onFinish={(file: VirtualFile) => {
|
||||
setCurrentFile(file);
|
||||
setUnsavedChanges(false);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
});
|
||||
},
|
||||
"Save": saveText,
|
||||
// "Save As": saveTextAs,
|
||||
"Quit": () => {
|
||||
close();
|
||||
},
|
||||
},
|
||||
"View": {
|
||||
[currentMode === "view" ? "Edit mode" : "Preview mode"]: () => {
|
||||
setCurrentMode(currentMode === "view" ? "edit" : "view");
|
||||
},
|
||||
"Zoom In": () => {
|
||||
setZoom(zoom + ZOOM_FACTOR);
|
||||
},
|
||||
"Zoom Out": () => {
|
||||
setZoom(zoom - ZOOM_FACTOR);
|
||||
},
|
||||
"Reset Zoom": () => {
|
||||
setZoom(DEFAULT_ZOOM);
|
||||
}
|
||||
}
|
||||
}}
|
||||
shortcuts={{
|
||||
"File": {
|
||||
"New": ["Control", "e"],
|
||||
"Open": ["Control", "o"],
|
||||
"Save": ["Control", "s"],
|
||||
"Quit": ["Control", "q"],
|
||||
},
|
||||
"View": {
|
||||
"Zoom In": ["Control", "+"],
|
||||
"Zoom Out": ["Control", "-"],
|
||||
"Reset Zoom": ["Control", "0"],
|
||||
"Edit mode": ["Control v"],
|
||||
"Preview mode": ["Control v"],
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<HeaderMenu onAnyTrigger={(event) => {
|
||||
console.log(event);
|
||||
}}>
|
||||
<DropdownAction label="File" showOnHover={false}>
|
||||
<ClickAction label="New" onTrigger={() => { newText(); }} shortcut={["Control", "e"]}/>
|
||||
<ClickAction label="Open" onTrigger={() => {
|
||||
openWindowedModal({
|
||||
size: DEFAULT_FILE_SELECTOR_SIZE,
|
||||
Modal: (props) => <FileSelector
|
||||
type={SELECTOR_MODE.SINGLE}
|
||||
onFinish={(file: VirtualFile) => {
|
||||
setCurrentFile(file);
|
||||
setUnsavedChanges(false);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
});
|
||||
}} shortcut={["Control", "o"]}/>
|
||||
<ClickAction label="Save" onTrigger={() => { saveText(); }} shortcut={["Control", "s"]}/>
|
||||
<ClickAction label="Quit" onTrigger={() => { close(); }} shortcut={["Control", "q"]}/>
|
||||
</DropdownAction>
|
||||
<DropdownAction label="View" showOnHover={false}>
|
||||
<ClickAction label={currentMode === "view" ? "Edit mode" : "Preview mode"} onTrigger={() => {
|
||||
setCurrentMode(currentMode === "view" ? "edit" : "view");
|
||||
}} shortcut={["Control", "v"]}/>
|
||||
<ClickAction label="Zoom in" onTrigger={() => { setZoom(zoom + ZOOM_FACTOR); }} shortcut={["Control", "+"]}/>
|
||||
<ClickAction label="Zoom out" onTrigger={() => { setZoom(zoom - ZOOM_FACTOR); }} shortcut={["Control", "-"]}/>
|
||||
<ClickAction label="Reset Zoom" onTrigger={() => { setZoom(DEFAULT_ZOOM); }} shortcut={["Control", "0"]}/>
|
||||
</DropdownAction>
|
||||
</HeaderMenu>
|
||||
{currentMode === "view"
|
||||
? CODE_FORMATS.includes(currentFile?.extension)
|
||||
? <SyntaxHighlighter
|
||||
|
|
|
|||
Loading…
Reference in a new issue