From 8ca5d66204a0d6e9882372d83833f848c7564a0d Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 28 Nov 2022 15:30:50 -0800 Subject: [PATCH] Desktop improvements (#4492) * Update version to non-promise interface * History navigation in sidebar --- app/components/NudeButton.tsx | 2 + app/components/Sidebar/App.tsx | 3 + app/components/Sidebar/Settings.tsx | 2 + app/components/Sidebar/Sidebar.tsx | 2 +- app/components/Sidebar/components/Header.tsx | 2 + .../Sidebar/components/HeaderButton.tsx | 3 + .../Sidebar/components/HistoryNavigation.tsx | 81 +++++++++++++++++++ app/typings/window.d.ts | 12 ++- shared/i18n/locales/en_US/translation.json | 2 + 9 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 app/components/Sidebar/components/HistoryNavigation.tsx diff --git a/app/components/NudeButton.tsx b/app/components/NudeButton.tsx index ea87887dc..f5ecf8856 100644 --- a/app/components/NudeButton.tsx +++ b/app/components/NudeButton.tsx @@ -2,6 +2,7 @@ import styled from "styled-components"; import ActionButton, { Props as ActionButtonProps, } from "~/components/ActionButton"; +import { undraggableOnDesktop } from "~/styles"; type Props = ActionButtonProps & { width?: number | string; @@ -30,6 +31,7 @@ const NudeButton = styled(ActionButton).attrs((props: Props) => ({ cursor: var(--pointer); user-select: none; color: inherit; + ${undraggableOnDesktop()} `; export default NudeButton; diff --git a/app/components/Sidebar/App.tsx b/app/components/Sidebar/App.tsx index 2c38d6d8d..05c9bcc16 100644 --- a/app/components/Sidebar/App.tsx +++ b/app/components/Sidebar/App.tsx @@ -26,6 +26,7 @@ import Sidebar from "./Sidebar"; import ArchiveLink from "./components/ArchiveLink"; import Collections from "./components/Collections"; import HeaderButton, { HeaderButtonProps } from "./components/HeaderButton"; +import HistoryNavigation from "./components/HistoryNavigation"; import Section from "./components/Section"; import SidebarAction from "./components/SidebarAction"; import SidebarLink from "./components/SidebarLink"; @@ -57,6 +58,7 @@ function AppSidebar() { return ( + {dndArea && ( @@ -72,6 +74,7 @@ function AppSidebar() { /> } style={ + // Move the logo over to align with smaller size Desktop.hasInsetTitlebar() ? { paddingLeft: 8 } : undefined } showDisclosure diff --git a/app/components/Sidebar/Settings.tsx b/app/components/Sidebar/Settings.tsx index 1350e0dc4..fd9e63bec 100644 --- a/app/components/Sidebar/Settings.tsx +++ b/app/components/Sidebar/Settings.tsx @@ -13,6 +13,7 @@ import isCloudHosted from "~/utils/isCloudHosted"; import Sidebar from "./Sidebar"; import Header from "./components/Header"; import HeaderButton from "./components/HeaderButton"; +import HistoryNavigation from "./components/HistoryNavigation"; import Section from "./components/Section"; import SidebarLink from "./components/SidebarLink"; import Version from "./components/Version"; @@ -29,6 +30,7 @@ function SettingsSidebar() { return ( + } diff --git a/app/components/Sidebar/Sidebar.tsx b/app/components/Sidebar/Sidebar.tsx index eb55f4f06..17801e6de 100644 --- a/app/components/Sidebar/Sidebar.tsx +++ b/app/components/Sidebar/Sidebar.tsx @@ -253,7 +253,7 @@ const Container = styled(Flex)` z-index: ${depths.sidebar}; max-width: 70%; min-width: 280px; - padding-top: ${Desktop.hasInsetTitlebar() ? 24 : 0}px; + padding-top: ${Desktop.hasInsetTitlebar() ? 36 : 0}px; ${draggableOnDesktop()} ${fadeOnDesktopBackgrounded()} diff --git a/app/components/Sidebar/components/Header.tsx b/app/components/Sidebar/components/Header.tsx index 6dba528d6..610d8b47b 100644 --- a/app/components/Sidebar/components/Header.tsx +++ b/app/components/Sidebar/components/Header.tsx @@ -2,6 +2,7 @@ import { CollapsedIcon } from "outline-icons"; import * as React from "react"; import styled, { keyframes } from "styled-components"; import usePersistedState from "~/hooks/usePersistedState"; +import { undraggableOnDesktop } from "~/styles"; type Props = { /** Unique header id – if passed the header will become toggleable */ @@ -76,6 +77,7 @@ const Button = styled.button` border-radius: 4px; -webkit-appearance: none; transition: all 100ms ease; + ${undraggableOnDesktop()} &:not(:disabled):hover, &:not(:disabled):active { diff --git a/app/components/Sidebar/components/HeaderButton.tsx b/app/components/Sidebar/components/HeaderButton.tsx index 464a8623b..dbbb63ae1 100644 --- a/app/components/Sidebar/components/HeaderButton.tsx +++ b/app/components/Sidebar/components/HeaderButton.tsx @@ -2,6 +2,7 @@ import { ExpandedIcon, MoreIcon } from "outline-icons"; import * as React from "react"; import styled from "styled-components"; import Flex from "~/components/Flex"; +import { undraggableOnDesktop } from "~/styles"; export type HeaderButtonProps = React.ComponentProps & { title: React.ReactNode; @@ -26,6 +27,7 @@ const HeaderButton = React.forwardRef( ref ) => ( ` overflow: hidden; user-select: none; cursor: var(--pointer); + ${undraggableOnDesktop()} &:active, &:hover, diff --git a/app/components/Sidebar/components/HistoryNavigation.tsx b/app/components/Sidebar/components/HistoryNavigation.tsx new file mode 100644 index 000000000..6129eeb4e --- /dev/null +++ b/app/components/Sidebar/components/HistoryNavigation.tsx @@ -0,0 +1,81 @@ +import { ArrowIcon } from "outline-icons"; +import * as React from "react"; +import { useTranslation } from "react-i18next"; +import styled from "styled-components"; +import Flex from "~/components/Flex"; +import NudeButton from "~/components/NudeButton"; +import Tooltip from "~/components/Tooltip"; +import useKeyDown from "~/hooks/useKeyDown"; +import Desktop from "~/utils/Desktop"; +import { isMac } from "~/utils/browser"; + +function HistoryNavigation(props: React.ComponentProps) { + const { t } = useTranslation(); + const [back, setBack] = React.useState(false); + const [forward, setForward] = React.useState(false); + + useKeyDown( + (event) => + isMac() + ? event.metaKey && event.key === "[" + : event.altKey && event.key === "ArrowLeft", + () => { + setBack(true); + setTimeout(() => setBack(false), 100); + } + ); + + useKeyDown( + (event) => + isMac() + ? event.metaKey && event.key === "]" + : event.altKey && event.key === "ArrowRight", + () => { + setForward(true); + setTimeout(() => setForward(false), 100); + } + ); + + if (!Desktop.isMacApp()) { + return null; + } + + return ( + + + Desktop.bridge.goBack()}> + + + + + Desktop.bridge.goForward()}> + + + + + ); +} + +const Navigation = styled(Flex)` + position: absolute; + right: 12px; + top: 14px; +`; + +const Forward = styled(ArrowIcon)<{ $active: boolean }>` + color: ${(props) => props.theme.textTertiary}; + opacity: ${(props) => (props.$active ? 1 : 0.5)}; + transition: color 100ms ease-in-out; + + &:active, + &:hover { + opacity: 1; + } +`; + +const Back = styled(Forward)` + transform: rotate(180deg); + flex-shrink: 0; +`; + +export default HistoryNavigation; diff --git a/app/typings/window.d.ts b/app/typings/window.d.ts index 3c31e42e6..d746642d8 100644 --- a/app/typings/window.d.ts +++ b/app/typings/window.d.ts @@ -9,7 +9,7 @@ declare global { /** * The version of the loaded application. */ - version: () => Promise; + version: () => string; /** * Restarts the application. @@ -61,6 +61,16 @@ declare global { * Registers a callback to be called when the application is ready to update. */ updateDownloaded: (callback: () => void) => void; + + /** + * Go back in history, if possible + */ + goBack: () => void; + + /** + * Go forward in history, if possible + */ + goForward: () => void; }; } } diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json index 1df51dad6..0b0466700 100644 --- a/shared/i18n/locales/en_US/translation.json +++ b/shared/i18n/locales/en_US/translation.json @@ -191,6 +191,8 @@ "New nested document": "New nested document", "Document not supported – try Markdown, Plain text, HTML, or Word": "Document not supported – try Markdown, Plain text, HTML, or Word", "Empty": "Empty", + "Go back": "Go back", + "Go forward": "Go forward", "Starred documents could not be loaded": "Starred documents could not be loaded", "Starred": "Starred", "Show more": "Show more",