-
Notifications
You must be signed in to change notification settings - Fork 14
feat: make keyboard shortcuts help page #2116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
12a6b01
fix: progress
astandrik d1d5ff2
feat: make keyboard shortcuts help page
astandrik 243db6d
Merge branch 'main' into astandrik.1344
astandrik 20d31c4
fix: styleling
astandrik 473d910
fix: enable in monaco editor
astandrik 0b4f2da
Merge branch 'main' into astandrik.1344
astandrik 33c3ba1
fix: better code
astandrik 3916cc7
fix: unused ternary
astandrik 7821fec
fix: unused classname
astandrik 186a641
fix: remove comments
astandrik 731dde2
fix: lint
astandrik 155ba88
fix: nanofix
astandrik 387cb0e
fix: nanofix
astandrik 6afa687
fix: better code
astandrik 2baf2ca
fix: better opening animations
astandrik d3b4b64
fix: update tests
astandrik fa659d3
Merge branch 'main' into astandrik.1344
astandrik 1b876d7
fix: review fixes
astandrik fa17559
fix: animation transition
astandrik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,4 +19,9 @@ | |
width: 300px; | ||
padding: 10px; | ||
} | ||
|
||
&__hotkeys-panel-title { | ||
display: flex; | ||
gap: var(--g-spacing-2); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,15 +2,18 @@ import React from 'react'; | |
|
||
import {CircleQuestion, Gear, Person} from '@gravity-ui/icons'; | ||
import type {MenuItem} from '@gravity-ui/navigation'; | ||
import {AsideHeader, FooterItem} from '@gravity-ui/navigation'; | ||
import {AsideHeader, FooterItem, HotkeysPanel} from '@gravity-ui/navigation'; | ||
import {Hotkey} from '@gravity-ui/uikit'; | ||
import type {IconData} from '@gravity-ui/uikit'; | ||
import hotkeys from 'hotkeys-js'; | ||
import {useHistory} from 'react-router-dom'; | ||
|
||
import {settingsManager} from '../../services/settings'; | ||
import {cn} from '../../utils/cn'; | ||
import {ASIDE_HEADER_COMPACT_KEY, LANGUAGE_KEY} from '../../utils/constants'; | ||
import {ASIDE_HEADER_COMPACT_KEY} from '../../utils/constants'; | ||
import {useSetting} from '../../utils/hooks'; | ||
|
||
import {InformationPopup} from './InformationPopup'; | ||
import {HOTKEYS, SHORTCUTS_HOTKEY} from './constants'; | ||
import i18n from './i18n'; | ||
|
||
import userSecret from '../../assets/icons/user-secret.svg'; | ||
|
@@ -62,26 +65,86 @@ export interface AsideNavigationProps { | |
|
||
enum Panel { | ||
UserSettings = 'UserSettings', | ||
Information = 'Information', | ||
Hotkeys = 'Hotkeys', | ||
} | ||
|
||
function getDocumentationLink() { | ||
// Use saved language from settings if it's present, otherwise use browser language | ||
const lang = settingsManager.readUserSettingsValue(LANGUAGE_KEY, navigator.language); | ||
/** | ||
* HotkeysPanelWrapper creates a render cycle separation between mounting and visibility change. | ||
* This is necessary for smooth animations as HotkeysPanel uses CSSTransition internally. | ||
* | ||
* When a component is both mounted and set to visible at once, CSSTransition can't | ||
* properly sequence its transition classes (panel → panel-active) because it's already active when mounted | ||
* and counts transition as it has already happened. | ||
* This wrapper ensures the component mounts first, then sets visible=true in a subsequent render cycle | ||
* to make transition actually happen. | ||
*/ | ||
function HotkeysPanelWrapper({ | ||
visiblePanel, | ||
closePanel, | ||
}: { | ||
visiblePanel?: Panel; | ||
closePanel: () => void; | ||
}) { | ||
const [visible, setVisible] = React.useState(false); | ||
|
||
React.useEffect(() => { | ||
setVisible(visiblePanel === Panel.Hotkeys); | ||
}, [visiblePanel]); | ||
|
||
if (lang === 'ru') { | ||
return 'https://ydb.tech/docs/ru/'; | ||
} | ||
|
||
return 'https://ydb.tech/docs/en/'; | ||
return ( | ||
<HotkeysPanel | ||
visible={visible} | ||
hotkeys={HOTKEYS} | ||
className={b('hotkeys-panel')} | ||
title={ | ||
<div className={b('hotkeys-panel-title')}> | ||
{i18n('help-center.footer.shortcuts')} | ||
<Hotkey value={SHORTCUTS_HOTKEY} /> | ||
</div> | ||
} | ||
onClose={closePanel} | ||
/> | ||
); | ||
} | ||
|
||
export function AsideNavigation(props: AsideNavigationProps) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, don't forget to make similar changes in internal version, there is a different navigation component there |
||
const history = useHistory(); | ||
|
||
const [visiblePanel, setVisiblePanel] = React.useState<Panel>(); | ||
|
||
const [informationPopupVisible, setInformationPopupVisible] = React.useState(false); | ||
const [compact, setIsCompact] = useSetting<boolean>(ASIDE_HEADER_COMPACT_KEY); | ||
|
||
const toggleInformationPopup = () => setInformationPopupVisible((prev) => !prev); | ||
|
||
const closeInformationPopup = React.useCallback(() => setInformationPopupVisible(false), []); | ||
|
||
const openHotkeysPanel = React.useCallback(() => { | ||
closeInformationPopup(); | ||
setVisiblePanel(Panel.Hotkeys); | ||
}, [closeInformationPopup]); | ||
|
||
const closePanel = React.useCallback(() => { | ||
setVisiblePanel(undefined); | ||
}, []); | ||
|
||
const renderInformationPopup = () => { | ||
return <InformationPopup onKeyboardShortcutsClick={openHotkeysPanel} />; | ||
}; | ||
|
||
React.useEffect(() => { | ||
// Register hotkey for keyboard shortcuts | ||
hotkeys(SHORTCUTS_HOTKEY, openHotkeysPanel); | ||
|
||
// Add listener for custom event from Monaco editor | ||
window.addEventListener('openKeyboardShortcutsPanel', openHotkeysPanel); | ||
|
||
return () => { | ||
hotkeys.unbind(SHORTCUTS_HOTKEY); | ||
window.removeEventListener('openKeyboardShortcutsPanel', openHotkeysPanel); | ||
}; | ||
}, [openHotkeysPanel]); | ||
|
||
return ( | ||
<React.Fragment> | ||
<AsideHeader | ||
|
@@ -100,13 +163,16 @@ export function AsideNavigation(props: AsideNavigationProps) { | |
<FooterItem | ||
compact={compact} | ||
item={{ | ||
id: 'documentation', | ||
title: i18n('navigation-item.documentation'), | ||
id: 'information', | ||
title: i18n('navigation-item.information'), | ||
icon: CircleQuestion, | ||
onItemClick: () => { | ||
window.open(getDocumentationLink(), '_blank', 'noreferrer'); | ||
}, | ||
current: informationPopupVisible, | ||
onItemClick: toggleInformationPopup, | ||
}} | ||
enableTooltip={!informationPopupVisible} | ||
popupVisible={informationPopupVisible} | ||
onClosePopup={closeInformationPopup} | ||
renderPopupContent={renderInformationPopup} | ||
/> | ||
|
||
<FooterItem | ||
|
@@ -137,10 +203,23 @@ export function AsideNavigation(props: AsideNavigationProps) { | |
visible: visiblePanel === Panel.UserSettings, | ||
content: props.settings, | ||
}, | ||
{ | ||
id: 'information', | ||
visible: visiblePanel === Panel.Information, | ||
}, | ||
{ | ||
id: 'hotkeys', | ||
visible: visiblePanel === Panel.Hotkeys, | ||
keepMounted: true, | ||
content: ( | ||
<HotkeysPanelWrapper | ||
visiblePanel={visiblePanel} | ||
closePanel={closePanel} | ||
/> | ||
), | ||
}, | ||
]} | ||
onClosePanel={() => { | ||
setVisiblePanel(undefined); | ||
}} | ||
onClosePanel={closePanel} | ||
/> | ||
</React.Fragment> | ||
); | ||
|
105 changes: 105 additions & 0 deletions
105
src/containers/AsideNavigation/InformationPopup/InformationPopup.scss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
@import '../../../styles/mixins.scss'; | ||
|
||
:root { | ||
--information-popup-padding: 16px; | ||
--information-popup-header-padding: 16px; | ||
} | ||
|
||
.information-popup { | ||
&__content { | ||
position: relative; | ||
|
||
display: flex; | ||
flex-direction: column; | ||
|
||
box-sizing: border-box; | ||
width: 280px; | ||
padding: var(--information-popup-header-padding) 0 0 0; | ||
} | ||
|
||
&__docs, | ||
&__footer { | ||
display: flex; | ||
flex-direction: column; | ||
flex-shrink: 0; | ||
} | ||
|
||
&__docs { | ||
padding-bottom: 8px; | ||
} | ||
|
||
&__footer { | ||
position: relative; | ||
|
||
padding: 12px 0 8px; | ||
|
||
border-top: 1px solid var(--g-color-line-generic); | ||
background-color: var(--g-color-base-generic); | ||
} | ||
|
||
&__title { | ||
flex-shrink: 0; | ||
|
||
margin-bottom: 4px; | ||
padding: 4px var(--information-popup-padding); | ||
} | ||
|
||
&__docs-list-wrap { | ||
display: flex; | ||
flex-direction: column; | ||
flex-shrink: 0; | ||
|
||
margin-bottom: 12px; | ||
|
||
&:last-child { | ||
margin-bottom: 0; | ||
} | ||
} | ||
|
||
&__docs-link, | ||
&__shortcuts-item { | ||
display: flex; | ||
flex-grow: 1; | ||
align-items: center; | ||
|
||
box-sizing: border-box; | ||
width: 100%; | ||
height: 100%; | ||
padding: 8px var(--information-popup-padding); | ||
|
||
line-height: var(--g-text-body-1-line-height); | ||
cursor: pointer; | ||
|
||
&:hover { | ||
background-color: var(--g-color-base-simple-hover); | ||
} | ||
} | ||
|
||
&__shortcuts-item { | ||
justify-content: space-between; | ||
} | ||
|
||
&__docs-link { | ||
&, | ||
&:hover, | ||
&:active, | ||
&:visited, | ||
&:focus { | ||
text-decoration: none; | ||
|
||
color: inherit; | ||
outline: none; | ||
} | ||
} | ||
|
||
&__item-icon-wrap { | ||
width: 16px; | ||
height: 16px; | ||
margin-right: 10px; | ||
} | ||
|
||
&__shortcuts-content { | ||
display: flex; | ||
align-items: center; | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
src/containers/AsideNavigation/InformationPopup/InformationPopup.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import {Keyboard} from '@gravity-ui/icons'; | ||
import {Flex, Hotkey, Icon, Link, List, Text} from '@gravity-ui/uikit'; | ||
|
||
import {settingsManager} from '../../../services/settings'; | ||
import {cn} from '../../../utils/cn'; | ||
import {LANGUAGE_KEY} from '../../../utils/constants'; | ||
import {SHORTCUTS_HOTKEY} from '../constants'; | ||
import i18n from '../i18n'; | ||
|
||
import './InformationPopup.scss'; | ||
|
||
const b = cn('information-popup'); | ||
|
||
export interface InformationPopupProps { | ||
onKeyboardShortcutsClick?: () => void; | ||
} | ||
|
||
export function InformationPopup({onKeyboardShortcutsClick}: InformationPopupProps) { | ||
const getDocumentationLink = () => { | ||
const lang = settingsManager.readUserSettingsValue(LANGUAGE_KEY, navigator.language); | ||
return lang === 'ru' ? 'https://ydb.tech/docs/ru/' : 'https://ydb.tech/docs/en/'; | ||
}; | ||
|
||
return ( | ||
<div className={b('content', {})}> | ||
<div className={b('docs')}> | ||
<Text variant="subheader-3" color="primary" className={b('title')}> | ||
Documentation | ||
</Text> | ||
<div className={b('docs-list-wrap')}> | ||
<List | ||
items={[ | ||
{ | ||
text: i18n('help-center.item.documentation'), | ||
url: getDocumentationLink(), | ||
}, | ||
]} | ||
filterable={false} | ||
virtualized={false} | ||
renderItem={({text, url}) => ( | ||
<Link | ||
className={b('docs-link')} | ||
rel="noopener" | ||
target="_blank" | ||
href={url} | ||
title={typeof text === 'string' ? text : undefined} | ||
> | ||
{text} | ||
</Link> | ||
)} | ||
itemClassName={b('item')} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div className={b('footer')}> | ||
<Flex | ||
justifyContent="space-between" | ||
className={b('shortcuts-item')} | ||
onClick={onKeyboardShortcutsClick} | ||
> | ||
<Flex alignItems="center"> | ||
<div className={b('item-icon-wrap')}> | ||
<Icon data={Keyboard} /> | ||
</div> | ||
{i18n('help-center.footer.shortcuts')} | ||
</Flex> | ||
<Hotkey value={SHORTCUTS_HOTKEY} /> | ||
</Flex> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export {InformationPopup} from './InformationPopup'; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add animation when open
Shortcuts
pane (like forSettings
pane).