feat: Add keyboard shortcuts to tooltips
This commit is contained in:
@ -51,7 +51,7 @@ const Modal = ({
|
|||||||
<Content column>
|
<Content column>
|
||||||
{title && <h1>{title}</h1>}
|
{title && <h1>{title}</h1>}
|
||||||
<Close onClick={onRequestClose}>
|
<Close onClick={onRequestClose}>
|
||||||
<CloseIcon size={40} />
|
<CloseIcon size={40} color="currentColor" />
|
||||||
<Esc>esc</Esc>
|
<Esc>esc</Esc>
|
||||||
</Close>
|
</Close>
|
||||||
{children}
|
{children}
|
||||||
@ -98,8 +98,8 @@ const Close = styled.a`
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 16px;
|
top: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
opacity: 0.5;
|
opacity: 0.75;
|
||||||
color: ${props => props.theme.textSecondary};
|
color: ${props => props.theme.text};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import * as React from 'react';
|
|
||||||
import { observable } from 'mobx';
|
|
||||||
import { observer } from 'mobx-react';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { CloseIcon } from 'outline-icons';
|
|
||||||
import Tooltip from './Tooltip';
|
|
||||||
import Flex from 'shared/components/Flex';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
id: string,
|
|
||||||
children: React.Node,
|
|
||||||
disabled?: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
@observer
|
|
||||||
class Tip extends React.Component<Props> {
|
|
||||||
@observable
|
|
||||||
isHidden: boolean = window.localStorage.getItem(this.storageId) === 'hidden';
|
|
||||||
|
|
||||||
get storageId() {
|
|
||||||
return `tip-${this.props.id}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
hide = () => {
|
|
||||||
window.localStorage.setItem(this.storageId, 'hidden');
|
|
||||||
this.isHidden = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { children } = this.props;
|
|
||||||
if (this.props.disabled || this.isHidden) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Wrapper align="flex-start">
|
|
||||||
<span>{children}</span>
|
|
||||||
|
|
||||||
<Tooltip tooltip="Hide this message" placement="bottom">
|
|
||||||
<Close type="close" size={32} color="#000" onClick={this.hide} />
|
|
||||||
</Tooltip>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Close = styled(CloseIcon)`
|
|
||||||
margin-top: 8px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Wrapper = styled(Flex)`
|
|
||||||
background: ${props => props.theme.primary};
|
|
||||||
color: ${props => props.theme.text};
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-weight: 400;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default Tip;
|
|
@ -5,6 +5,7 @@ import Tippy from '@tippy.js/react';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
tooltip: React.Node,
|
tooltip: React.Node,
|
||||||
|
shortcut?: React.Node,
|
||||||
placement?: 'top' | 'bottom' | 'left' | 'right',
|
placement?: 'top' | 'bottom' | 'left' | 'right',
|
||||||
children: React.Node,
|
children: React.Node,
|
||||||
delay?: number,
|
delay?: number,
|
||||||
@ -19,6 +20,7 @@ class Tooltip extends React.Component<Props> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
shortcut,
|
||||||
tooltip,
|
tooltip,
|
||||||
delay = 50,
|
delay = 50,
|
||||||
children,
|
children,
|
||||||
@ -28,12 +30,22 @@ class Tooltip extends React.Component<Props> {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
const Component = block ? 'div' : 'span';
|
const Component = block ? 'div' : 'span';
|
||||||
|
|
||||||
|
let content = tooltip;
|
||||||
|
|
||||||
|
if (shortcut) {
|
||||||
|
content = (
|
||||||
|
<React.Fragment>
|
||||||
|
{tooltip} · <Shortcut>{shortcut}</Shortcut>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTippy
|
<StyledTippy
|
||||||
arrow
|
arrow
|
||||||
arrowType="round"
|
arrowType="round"
|
||||||
animation="shift-away"
|
animation="shift-away"
|
||||||
content={tooltip}
|
content={content}
|
||||||
delay={delay}
|
delay={delay}
|
||||||
duration={[200, 150]}
|
duration={[200, 150]}
|
||||||
inertia
|
inertia
|
||||||
@ -45,6 +57,21 @@ class Tooltip extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Shortcut = styled.kbd`
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 4px;
|
||||||
|
font: 10px 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier,
|
||||||
|
monospace;
|
||||||
|
line-height: 10px;
|
||||||
|
color: ${props => props.theme.tooltipBackground};
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: ${props => props.theme.tooltipText};
|
||||||
|
border-radius: 3px;
|
||||||
|
`;
|
||||||
|
|
||||||
const StyledTippy = styled(Tippy)`
|
const StyledTippy = styled(Tippy)`
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
background-color: ${props => props.theme.tooltipBackground};
|
background-color: ${props => props.theme.tooltipBackground};
|
||||||
|
@ -24,6 +24,7 @@ import Search from 'scenes/Search';
|
|||||||
import CollectionMenu from 'menus/CollectionMenu';
|
import CollectionMenu from 'menus/CollectionMenu';
|
||||||
import Actions, { Action, Separator } from 'components/Actions';
|
import Actions, { Action, Separator } from 'components/Actions';
|
||||||
import Heading from 'components/Heading';
|
import Heading from 'components/Heading';
|
||||||
|
import Tooltip from 'components/Tooltip';
|
||||||
import CenteredContent from 'components/CenteredContent';
|
import CenteredContent from 'components/CenteredContent';
|
||||||
import { ListPlaceholder } from 'components/LoadingPlaceholder';
|
import { ListPlaceholder } from 'components/LoadingPlaceholder';
|
||||||
import Mask from 'components/Mask';
|
import Mask from 'components/Mask';
|
||||||
@ -104,9 +105,16 @@ class CollectionScene extends React.Component<Props> {
|
|||||||
return (
|
return (
|
||||||
<Actions align="center" justify="flex-end">
|
<Actions align="center" justify="flex-end">
|
||||||
<Action>
|
<Action>
|
||||||
<Button onClick={this.onNewDocument} icon={<PlusIcon />}>
|
<Tooltip
|
||||||
New doc
|
tooltip="New document"
|
||||||
</Button>
|
shortcut="n"
|
||||||
|
delay={500}
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<Button onClick={this.onNewDocument} icon={<PlusIcon />}>
|
||||||
|
New doc
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</Action>
|
</Action>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Action>
|
<Action>
|
||||||
|
@ -19,6 +19,7 @@ import DocumentMenu from 'menus/DocumentMenu';
|
|||||||
import NewChildDocumentMenu from 'menus/NewChildDocumentMenu';
|
import NewChildDocumentMenu from 'menus/NewChildDocumentMenu';
|
||||||
import DocumentShare from 'scenes/DocumentShare';
|
import DocumentShare from 'scenes/DocumentShare';
|
||||||
import Button from 'components/Button';
|
import Button from 'components/Button';
|
||||||
|
import Tooltip from 'components/Tooltip';
|
||||||
import Modal from 'components/Modal';
|
import Modal from 'components/Modal';
|
||||||
import Badge from 'components/Badge';
|
import Badge from 'components/Badge';
|
||||||
import Collaborators from 'components/Collaborators';
|
import Collaborators from 'components/Collaborators';
|
||||||
@ -182,14 +183,21 @@ class Header extends React.Component<Props> {
|
|||||||
)}
|
)}
|
||||||
{canEdit && (
|
{canEdit && (
|
||||||
<Action>
|
<Action>
|
||||||
<Button
|
<Tooltip
|
||||||
icon={<EditIcon />}
|
tooltip="Edit document"
|
||||||
onClick={this.handleEdit}
|
shortcut="e"
|
||||||
neutral
|
delay={500}
|
||||||
small
|
placement="bottom"
|
||||||
>
|
>
|
||||||
Edit
|
<Button
|
||||||
</Button>
|
icon={<EditIcon />}
|
||||||
|
onClick={this.handleEdit}
|
||||||
|
neutral
|
||||||
|
small
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</Action>
|
</Action>
|
||||||
)}
|
)}
|
||||||
{canEdit &&
|
{canEdit &&
|
||||||
@ -198,9 +206,16 @@ class Header extends React.Component<Props> {
|
|||||||
<NewChildDocumentMenu
|
<NewChildDocumentMenu
|
||||||
document={document}
|
document={document}
|
||||||
label={
|
label={
|
||||||
<Button icon={<PlusIcon />} neutral>
|
<Tooltip
|
||||||
New doc
|
tooltip="New document"
|
||||||
</Button>
|
shortcut="n"
|
||||||
|
delay={500}
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<Button icon={<PlusIcon />} neutral>
|
||||||
|
New doc
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Action>
|
</Action>
|
||||||
|
@ -34,7 +34,13 @@ class KeyboardShortcutsButton extends React.Component<Props> {
|
|||||||
<KeyboardShortcuts />
|
<KeyboardShortcuts />
|
||||||
</Modal>
|
</Modal>
|
||||||
<Button onClick={this.handleOpenKeyboardShortcuts}>
|
<Button onClick={this.handleOpenKeyboardShortcuts}>
|
||||||
<Tooltip tooltip="Keyboard shortcuts" placement="left" block>
|
<Tooltip
|
||||||
|
tooltip="Keyboard shortcuts"
|
||||||
|
shortcut="?"
|
||||||
|
placement="left"
|
||||||
|
delay={500}
|
||||||
|
block
|
||||||
|
>
|
||||||
<KeyboardIcon />
|
<KeyboardIcon />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Button>
|
</Button>
|
||||||
|
Reference in New Issue
Block a user