Merge pull request #4715 from h3poteto/iss-4653/shortcut
refs #4653 Add shortcut keys
This commit is contained in:
commit
1904d4669c
|
@ -25,6 +25,7 @@
|
|||
"flowbite-react": "^0.7.0",
|
||||
"megalodon": "^9.1.1",
|
||||
"react-blurhash": "^0.3.0",
|
||||
"react-hotkeys-hook": "^4.4.1",
|
||||
"react-icons": "^4.11.0",
|
||||
"react-intl": "^6.5.1",
|
||||
"react-virtuoso": "^4.6.2",
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
Textarea,
|
||||
ToggleSwitch
|
||||
} from 'flowbite-react'
|
||||
import { ChangeEvent, Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'
|
||||
import { ChangeEvent, Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
import { FaEnvelope, FaFaceLaughBeam, FaGlobe, FaListCheck, FaLock, FaLockOpen, FaPaperPlane, FaPaperclip, FaXmark } from 'react-icons/fa6'
|
||||
import { Entity, MegalodonInterface } from 'megalodon'
|
||||
|
@ -54,6 +54,7 @@ export default function Compose(props: Props) {
|
|||
const { formatMessage } = useIntl()
|
||||
const uploaderRef = useRef(null)
|
||||
const showToast = useToast()
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!cw) {
|
||||
|
@ -116,6 +117,23 @@ export default function Compose(props: Props) {
|
|||
setPoll(null)
|
||||
}
|
||||
|
||||
const handleKeyPress = useCallback(
|
||||
(event: KeyboardEvent) => {
|
||||
if (event.ctrlKey === true && event.key === 'Enter') {
|
||||
post()
|
||||
}
|
||||
},
|
||||
[post]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
textareaRef.current?.addEventListener('keydown', handleKeyPress)
|
||||
|
||||
return () => {
|
||||
textareaRef.current?.removeEventListener('keydown', handleKeyPress)
|
||||
}
|
||||
}, [handleKeyPress])
|
||||
|
||||
const selectFile = () => {
|
||||
if (uploaderRef.current) {
|
||||
uploaderRef.current.click()
|
||||
|
@ -188,6 +206,7 @@ export default function Compose(props: Props) {
|
|||
rows={3}
|
||||
value={body}
|
||||
onChange={ev => setBody(ev.target.value)}
|
||||
ref={textareaRef}
|
||||
/>
|
||||
<Flowbite theme={{ theme: customTheme }}>
|
||||
<Dropdown
|
||||
|
|
|
@ -9,6 +9,7 @@ import { FormattedMessage, useIntl } from 'react-intl'
|
|||
import generateNotification from '@/utils/notification'
|
||||
import generator, { Entity, WebSocketInterface } from 'megalodon'
|
||||
import { Context } from '@/utils/i18n'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
|
||||
type LayoutProps = {
|
||||
children: React.ReactNode
|
||||
|
@ -24,6 +25,15 @@ export default function Layout({ children }: LayoutProps) {
|
|||
const { formatMessage } = useIntl()
|
||||
const streamings = useRef<Array<WebSocketInterface>>([])
|
||||
|
||||
for (let i = 1; i < 9; i++) {
|
||||
useHotkeys(`ctrl+${i}`, () => {
|
||||
const acct = accounts[i - 1]
|
||||
if (acct && acct.id) {
|
||||
router.push(`/accounts/${acct.id}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadSettings()
|
||||
const fn = async () => {
|
||||
|
|
|
@ -8,6 +8,7 @@ import { FormattedMessage, useIntl } from 'react-intl'
|
|||
import Detail from '../detail/Detail'
|
||||
import { useRouter } from 'next/router'
|
||||
import Compose from '../compose/Compose'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
|
||||
const TIMELINE_STATUSES_COUNT = 30
|
||||
const TIMELINE_MAX_STATUSES = 2147483647
|
||||
|
@ -18,6 +19,7 @@ type Props = {
|
|||
client: MegalodonInterface
|
||||
setAttachment: Dispatch<SetStateAction<Entity.Attachment | null>>
|
||||
}
|
||||
|
||||
export default function Timeline(props: Props) {
|
||||
const [statuses, setStatuses] = useState<Array<Entity.Status>>([])
|
||||
const [unreads, setUnreads] = useState<Array<Entity.Status>>([])
|
||||
|
@ -29,6 +31,7 @@ export default function Timeline(props: Props) {
|
|||
const scrollerRef = useRef<HTMLElement | null>(null)
|
||||
const streaming = useRef<WebSocketInterface | null>(null)
|
||||
const composeRef = useRef<HTMLDivElement | null>(null)
|
||||
useHotkeys('ctrl+r', () => reload())
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new ResizeObserver(entries => {
|
||||
|
@ -130,6 +133,11 @@ export default function Timeline(props: Props) {
|
|||
return renew
|
||||
}
|
||||
|
||||
const reload = useCallback(async () => {
|
||||
const res = await loadTimeline(props.timeline, props.client)
|
||||
setStatuses(res)
|
||||
}, [props.timeline, props.client, setStatuses])
|
||||
|
||||
const loadMore = useCallback(async () => {
|
||||
console.debug('appending')
|
||||
const maxId = statuses[statuses.length - 1].id
|
||||
|
|
|
@ -7095,6 +7095,11 @@ react-dom@^18.2.0:
|
|||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.0"
|
||||
|
||||
react-hotkeys-hook@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz#1f7a7a1c9c21d4fa3280bf340fcca8fd77d81994"
|
||||
integrity sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==
|
||||
|
||||
react-icons@^4.11.0:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.12.0.tgz#54806159a966961bfd5cdb26e492f4dafd6a8d78"
|
||||
|
|
Loading…
Reference in New Issue