Add keyboard shortcuts: new, escape, and hard break (#552)

* Add keyboard shortcuts: new, escape, and hard break

* Add preferences modal

* Remove code accidentally re-added due to rebase

* Fix incorrect copy and lint

* Put stuff back so diffs are clearer

* Re-add invite codes to settings

* Address comments

* Tune the copy

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
zio/stable
Ollie H 2023-05-02 21:00:18 -07:00 committed by GitHub
parent af905947bc
commit 95f8360d19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 26 deletions

View File

@ -49,6 +49,7 @@
"@sentry/react-native": "4.13.0",
"@tiptap/core": "^2.0.0-beta.220",
"@tiptap/extension-document": "^2.0.0-beta.220",
"@tiptap/extension-hard-break": "^2.0.3",
"@tiptap/extension-history": "^2.0.3",
"@tiptap/extension-link": "^2.0.0-beta.220",
"@tiptap/extension-mention": "^2.0.0-beta.220",
@ -58,6 +59,7 @@
"@tiptap/pm": "^2.0.0-beta.220",
"@tiptap/react": "^2.0.0-beta.220",
"@tiptap/suggestion": "^2.0.0-beta.220",
"@types/node": "^18.16.2",
"@zxing/text-encoding": "^0.9.0",
"await-lock": "^2.2.2",
"base64-js": "^1.5.1",

View File

@ -11,6 +11,7 @@ export interface ConfirmModal {
title: string
message: string | (() => JSX.Element)
onPressConfirm: () => void | Promise<void>
onPressCancel?: () => void | Promise<void>
}
export interface EditProfileModal {
@ -86,10 +87,10 @@ export interface ContentFilteringSettingsModal {
export type Modal =
// Account
| AddAppPasswordModal
| ChangeHandleModal
| DeleteAccountModal
| EditProfileModal
| AddAppPasswordModal
// Curation
| ContentFilteringSettingsModal

View File

@ -88,6 +88,30 @@ export const ComposePost = observer(function ComposePost({
autocompleteView.setup()
}, [autocompleteView])
const onEscape = useCallback(
(e: KeyboardEvent) => {
if (e.key === 'Escape') {
store.shell.openModal({
name: 'confirm',
title: 'Cancel draft',
onPressConfirm: onClose,
onPressCancel: () => {
store.shell.closeModal()
},
message: "Are you sure you'd like to cancel this draft?",
})
}
},
[store.shell, onClose],
)
useEffect(() => {
if (isDesktopWeb) {
window.addEventListener('keydown', onEscape)
return () => window.removeEventListener('keydown', onEscape)
}
}, [onEscape])
const onPressAddLinkCard = useCallback(
(uri: string) => {
setExtLink({uri, isLoading: true})

View File

@ -4,6 +4,7 @@ import {RichText} from '@atproto/api'
import {useEditor, EditorContent, JSONContent} from '@tiptap/react'
import {Document} from '@tiptap/extension-document'
import History from '@tiptap/extension-history'
import Hardbreak from '@tiptap/extension-hard-break'
import {Link} from '@tiptap/extension-link'
import {Mention} from '@tiptap/extension-mention'
import {Paragraph} from '@tiptap/extension-paragraph'
@ -72,6 +73,7 @@ export const TextInput = React.forwardRef(
}),
Text,
History,
Hardbreak,
],
editorProps: {
attributes: {

View File

@ -34,8 +34,8 @@ export function Component({altText}: Props) {
testID="altTextImageSaveBtn"
onPress={onPress}
accessibilityRole="button"
accessibilityLabel="Save"
accessibilityHint="Save alt text">
accessibilityLabel="Done"
accessibilityHint="Closes alt text modal">
<LinearGradient
colors={[gradients.blueLight.start, gradients.blueLight.end]}
start={{x: 0, y: 0}}

View File

@ -19,10 +19,12 @@ export function Component({
title,
message,
onPressConfirm,
onPressCancel,
}: {
title: string
message: string | (() => JSX.Element)
onPressConfirm: () => void | Promise<void>
onPressCancel?: () => void | Promise<void>
}) {
const pal = usePalette('default')
const store = useStores()
@ -69,12 +71,23 @@ export function Component({
style={[styles.btn]}
accessibilityRole="button"
accessibilityLabel="Confirm"
// TODO: This needs to be updated so that modal roles are clear;
// Currently there is only one usage for the confirm modal: post deletion
accessibilityHint="Confirms a potentially destructive action">
accessibilityHint="">
<Text style={[s.white, s.bold, s.f18]}>Confirm</Text>
</TouchableOpacity>
)}
{onPressCancel === undefined ? null : (
<TouchableOpacity
testID="cancelBtn"
onPress={onPressCancel}
style={[styles.btnCancel, s.mt10]}
accessibilityRole="button"
accessibilityLabel="Cancel"
accessibilityHint="">
<Text type="button-lg" style={pal.textLight}>
Cancel
</Text>
</TouchableOpacity>
)}
</View>
)
}
@ -104,4 +117,12 @@ const styles = StyleSheet.create({
marginHorizontal: 44,
backgroundColor: colors.blue3,
},
btnCancel: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 32,
padding: 14,
marginHorizontal: 20,
},
})

View File

@ -142,9 +142,11 @@ export function ToggleButton({
]}
/>
</View>
<Text type="button" style={[labelStyle, styles.label]}>
{label}
</Text>
{label === '' ? null : (
<Text type="button" style={[labelStyle, styles.label]}>
{label}
</Text>
)}
</View>
</Button>
)
@ -154,6 +156,7 @@ const styles = StyleSheet.create({
outer: {
flexDirection: 'row',
alignItems: 'center',
gap: 10,
},
circle: {
width: 42,
@ -161,7 +164,6 @@ const styles = StyleSheet.create({
borderRadius: 15,
padding: 4,
borderWidth: 1,
marginRight: 10,
},
circleFill: {
width: 16,

View File

@ -34,8 +34,8 @@ import {useCustomPalette} from 'lib/hooks/useCustomPalette'
import {AccountData} from 'state/models/session'
import {useAnalytics} from 'lib/analytics'
import {NavigationProp} from 'lib/routes/types'
import {pluralize} from 'lib/strings/helpers'
import {isDesktopWeb} from 'platform/detection'
import {pluralize} from 'lib/strings/helpers'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
export const SettingsScreen = withAuthRequired(
@ -54,6 +54,7 @@ export const SettingsScreen = withAuthRequired(
light: {color: colors.blue3},
dark: {color: colors.blue2},
})
const dangerBg = useCustomPalette<ViewStyle>({
light: {backgroundColor: colors.red1},
dark: {backgroundColor: colors.red7},
@ -140,13 +141,12 @@ export const SettingsScreen = withAuthRequired(
}, [store])
return (
<View style={s.hContentRegion} testID="settingsScreen">
<View style={[s.hContentRegion]} testID="settingsScreen">
<ViewHeader title="Settings" />
<ScrollView
style={s.hContentRegion}
style={[s.hContentRegion]}
contentContainerStyle={!isDesktopWeb && pal.viewLight}
scrollIndicatorInsets={{right: 1}}>
<View style={styles.spacer20} />
<View style={[s.flexRow, styles.heading]}>
<Text type="xl-bold" style={pal.text}>
Signed in as
@ -161,9 +161,7 @@ export const SettingsScreen = withAuthRequired(
<Link
href={`/profile/${store.me.handle}`}
title="Your profile"
noFeedback
accessibilityLabel={`Signed in as ${store.me.handle}`}
accessibilityHint="Double tap to sign out">
noFeedback>
<View style={[pal.view, styles.linkCard]}>
<View style={styles.avi}>
<UserAvatar size={40} avatar={store.me.avatar} />
@ -231,9 +229,7 @@ export const SettingsScreen = withAuthRequired(
Add account
</Text>
</TouchableOpacity>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Invite a friend
</Text>
@ -301,9 +297,7 @@ export const SettingsScreen = withAuthRequired(
Blocked accounts
</Text>
</Link>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Advanced
</Text>
@ -338,9 +332,7 @@ export const SettingsScreen = withAuthRequired(
Change my handle
</Text>
</TouchableOpacity>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Danger zone
</Text>
@ -355,16 +347,14 @@ export const SettingsScreen = withAuthRequired(
<FontAwesomeIcon
icon={['far', 'trash-can']}
style={dangerText as FontAwesomeIconStyle}
size={21}
size={18}
/>
</View>
<Text type="lg" style={dangerText}>
Delete my account
</Text>
</TouchableOpacity>
<View style={styles.spacer20} />
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Developer tools
</Text>

View File

@ -4433,6 +4433,11 @@
dependencies:
tippy.js "^6.3.7"
"@tiptap/extension-hard-break@^2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.3.tgz#aa7805d825e5244bdccc508da18c781e231b2859"
integrity sha512-RCln6ARn16jvKTjhkcAD5KzYXYS0xRMc0/LrHeV8TKdCd4Yd0YYHe0PU4F9gAgAfPQn7Dgt4uTVJLN11ICl8sQ==
"@tiptap/extension-history@^2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.3.tgz#8936c15aa46f2ddeada1c3d9abe2888d58d08c30"
@ -4820,6 +4825,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.3.tgz#6bda7819aae6ea0b386ebc5b24bdf602f1b42b01"
integrity sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==
"@types/node@^18.16.2":
version "18.16.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.2.tgz#2f610ea71034b3971c312192377f8a7178eb57f1"
integrity sha512-GQW/JL/5Fz/0I8RpeBG9lKp0+aNcXEaVL71c0D2Q0QHDTFvlYKT7an0onCUXj85anv7b4/WesqdfchLc0jtsCg==
"@types/object.omit@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/object.omit/-/object.omit-3.0.0.tgz#0d31e1208eac8fe2ad5c9499a1016a8273bbfafc"