chore: add sort imports plugin to prettier

This commit is contained in:
KaiyiWing
2023-04-18 16:23:56 +08:00
parent 5f2a0b2a37
commit 0b6eb085b7
45 changed files with 254 additions and 167 deletions

View File

@@ -71,6 +71,7 @@
"@types/react-dom": "^18.0.11",
"@types/react-router-dom": "^5.1.7",
"@vitejs/plugin-react": "^3.1.0",
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
"cross-env": "^7.0.3",
"eslint-config-prettier": "^8.7.0",
"eslint-config-react-app": "^7.0.1",

View File

@@ -1,17 +1,16 @@
import React, { useCallback } from 'react'
import InfoPanel from '@/components/InfoPanel'
import vscLogo from '@/assets/vsc-logo.svg'
import { recordOpenInfoPanelAction } from '@/utils'
import { InfoPanelType } from '@/typings'
import { useAtom } from 'jotai'
import { infoPanelStateAtom } from '@/store'
import alipay from '@/assets/alipay.jpg'
import redBookLogo from '@/assets/redBook-black-logo.svg'
import redBookCode from '@/assets/redBook-code.jpg'
import alipay from '@/assets/alipay.jpg'
import vscLogo from '@/assets/vsc-logo.svg'
import weChat from '@/assets/weChat.jpg'
import { IconBrandWechat, IconCoffee, IconTerminal2 } from '@tabler/icons-react'
import InfoPanel from '@/components/InfoPanel'
import { infoPanelStateAtom } from '@/store'
import { InfoPanelType } from '@/typings'
import { recordOpenInfoPanelAction } from '@/utils'
import { EnvelopeIcon } from '@heroicons/react/24/solid'
import { IconBrandWechat, IconCoffee, IconTerminal2 } from '@tabler/icons-react'
import { useAtom } from 'jotai'
import React, { useCallback } from 'react'
const Footer: React.FC = () => {
const [infoPanelState, setInfoPanelState] = useAtom(infoPanelStateAtom)

View File

@@ -1,6 +1,6 @@
import logo from '@/assets/logo.svg'
import React, { PropsWithChildren } from 'react'
import { NavLink } from 'react-router-dom'
import logo from '@/assets/logo.svg'
const Header: React.FC<PropsWithChildren> = ({ children }) => {
return (

View File

@@ -1,8 +1,8 @@
import React, { ElementType, Fragment } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import classNames from 'classnames'
import redBookLogo from '@/assets/redBook-color-logo.svg'
import { Dialog, Transition } from '@headlessui/react'
import type { TablerIconsProps } from '@tabler/icons-react'
import classNames from 'classnames'
import React, { ElementType, Fragment } from 'react'
type InfoPanelProps = {
openState: boolean

View File

@@ -1,5 +1,5 @@
import React from 'react'
import Footer from './Footer'
import React from 'react'
const Layout: React.FC<React.PropsWithChildren> = ({ children }) => (
<main className="flex h-screen w-full flex-col items-center pb-4">

View File

@@ -1,5 +1,5 @@
import React from 'react'
import style from './index.module.css'
import React from 'react'
export type LoadingProps = { message?: string }

View File

@@ -1,11 +1,11 @@
import { Transition } from '@headlessui/react'
import starBar from '@/assets/starBar.svg'
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react'
import { dismissStartCardDateAtom } from '@/store'
import { useSetAtom } from 'jotai'
import { recordStarAction } from '@/utils'
import { DISMISS_START_CARD_DATE_KEY } from '@/constants'
import { dismissStartCardDateAtom } from '@/store'
import { recordStarAction } from '@/utils'
import { Transition } from '@headlessui/react'
import { IconCircleX } from '@tabler/icons-react'
import { useSetAtom } from 'jotai'
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react'
export default function StarCard() {
const [countdown, setCountdown] = useState(5)

View File

@@ -1,5 +1,5 @@
import { ReactNode, useState } from 'react'
import { classNames } from '@/utils'
import { ReactNode, useState } from 'react'
const Tooltip = ({ children, content, className, placement = 'top' }: TooltipProps) => {
const [visible, setVisible] = useState(false)

View File

@@ -1,8 +1,8 @@
import { SOUND_URL_PREFIX } from '@/resources/soundResource'
import { keySoundsConfigAtom, hintSoundsConfigAtom } from '@/store'
import noop from '@/utils/noop'
import { useAtomValue } from 'jotai'
import useSound from 'use-sound'
import { SOUND_URL_PREFIX } from '@/resources/soundResource'
import noop from '@/utils/noop'
import { keySoundsConfigAtom, hintSoundsConfigAtom } from '@/store'
export type PlayFunction = ReturnType<typeof useSound>[0]

View File

@@ -1,12 +1,12 @@
import { useAtomValue } from 'jotai'
import { pronunciationConfigAtom } from '@/store'
import { PronunciationType } from '@/typings'
import { addHowlListener } from '@/utils'
import noop from '@/utils/noop'
import { Howl } from 'howler'
import { useAtomValue } from 'jotai'
import { useEffect, useMemo, useState } from 'react'
import useSound from 'use-sound'
import { HookOptions } from 'use-sound/dist/types'
import { addHowlListener } from '@/utils'
import noop from '@/utils/noop'
import { pronunciationConfigAtom } from '@/store'
import { PronunciationType } from '@/typings'
const pronunciationApi = 'https://dict.youdao.com/dictvoice?audio='
function generateWordSoundSrc(word: string, pronunciation: Exclude<PronunciationType, false>) {

View File

@@ -1,16 +1,16 @@
import React, { useEffect } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import 'react-app-polyfill/stable'
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import GalleryPage from './pages/Gallery'
import TypingPage from './pages/Typing'
import mixpanel from 'mixpanel-browser'
import { isOpenDarkModeAtom } from '@/store'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import { useAtomValue } from 'jotai'
import { isOpenDarkModeAtom } from '@/store'
import mixpanel from 'mixpanel-browser'
import process from 'process'
import React, { useEffect } from 'react'
import 'react-app-polyfill/stable'
import { createRoot } from 'react-dom/client'
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
if (process.env.NODE_ENV === 'production') {
// for prod

View File

@@ -1,7 +1,7 @@
import { useChapterStats } from './hooks/useChapterStats'
import useIntersectionObserver from '@/hooks/useIntersectionObserver'
import { CheckCircleIcon } from '@heroicons/react/20/solid'
import React, { useEffect, useRef } from 'react'
import { useChapterStats } from './hooks/useChapterStats'
export const ChapterButton: React.FC<ChapterButtonProps> = ({ index, selected, wordCount, onClick }) => {
const buttonRef = useRef<HTMLButtonElement>(null)

View File

@@ -1,9 +1,9 @@
import React from 'react'
import range from '@/utils/range'
import ChapterButton from './ChapterButton'
import { useAtom, useAtomValue } from 'jotai'
import { currentChapterAtom, currentDictInfoAtom } from '@/store'
import { CHAPTER_LENGTH } from '@/constants'
import { currentChapterAtom, currentDictInfoAtom } from '@/store'
import range from '@/utils/range'
import { useAtom, useAtomValue } from 'jotai'
import React from 'react'
const ChapterGroup: React.FC<ChapterGroupProps> = ({ totalWords }) => {
const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom)

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useRef } from 'react'
import { DictionaryResource } from '@/typings'
import { useAtom, useSetAtom } from 'jotai'
import { currentChapterAtom, currentDictIdAtom } from '@/store'
import { DictionaryResource } from '@/typings'
import { CheckCircleIcon } from '@heroicons/react/20/solid'
import { useAtom, useSetAtom } from 'jotai'
import React, { useEffect, useRef } from 'react'
const DictionaryCard: React.FC<DictionaryCardProps> = ({ dictionary }) => {
const buttonRef = useRef<HTMLButtonElement>(null)

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { DictionaryResource } from '@/typings'
import DictionaryCard from './DictionaryCard'
import { DictionaryResource } from '@/typings'
import React from 'react'
const DictionaryGroup: React.FC<DictionaryGroupProps> = ({ title, dictionaries }) => {
return (

View File

@@ -1,15 +1,15 @@
import React from 'react'
import Layout from '@/components/Layout'
import ChapterGroup from './ChapterGroup'
import DictionaryGroup from './DictionaryGroup'
import Header from '@/components/Header'
import { NavLink, useNavigate } from 'react-router-dom'
import groupBy from '@/utils/groupBy'
import { useHotkeys } from 'react-hotkeys-hook'
import ChapterGroup from './ChapterGroup'
import Layout from '@/components/Layout'
import Tooltip from '@/components/Tooltip'
import { dictionaries } from '@/resources/dictionary'
import { useAtomValue } from 'jotai'
import { currentDictInfoAtom } from '@/store'
import groupBy from '@/utils/groupBy'
import { useAtomValue } from 'jotai'
import React from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { NavLink, useNavigate } from 'react-router-dom'
const GalleryPage: React.FC = () => {
const currentDictInfo = useAtomValue(currentDictInfoAtom)

View File

@@ -1,8 +1,8 @@
import { useAtomValue } from 'jotai'
import { FormEvent, useMemo } from 'react'
import { currentDictInfoAtom } from '@/store'
import KeyEventHandler from '../KeyEventHandler'
import TextAreaHandler from '../TextAreaHandler'
import { currentDictInfoAtom } from '@/store'
import { useAtomValue } from 'jotai'
import { FormEvent, useMemo } from 'react'
export default function InputHandler({ updateInput }: { updateInput: (updateObj: WordUpdateAction) => void }) {
const dictInfo = useAtomValue(currentDictInfoAtom)

View File

@@ -1,7 +1,7 @@
import { WordUpdateAction } from '../InputHandler'
import { TypingContext } from '@/pages/Typing/store'
import { isChineseSymbol, isLegal } from '@/utils'
import { useCallback, useContext, useEffect } from 'react'
import { WordUpdateAction } from '../InputHandler'
export default function KeyEventHandler({ updateInput }: { updateInput: (updateObj: WordUpdateAction) => void }) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useState } from 'react'
import VolumeHighIcon from './volume-icons/VolumeHieghIcon'
import VolumeIcon from './volume-icons/VolumeIcon'
import VolumeLowIcon from './volume-icons/VolumeLowIcon'
import VolumeMediumIcon from './volume-icons/VolumeMediumIcon'
import VolumeHighIcon from './volume-icons/VolumeHieghIcon'
import React, { useEffect, useState } from 'react'
const volumeIcons = [VolumeIcon, VolumeLowIcon, VolumeMediumIcon, VolumeHighIcon]

View File

@@ -1,6 +1,6 @@
import { WordUpdateAction } from '../InputHandler'
import { TypingContext } from '@/pages/Typing/store'
import { FormEvent, useCallback, useContext, useEffect, useRef } from 'react'
import { WordUpdateAction } from '../InputHandler'
export default function TextAreaHandler({ updateInput }: { updateInput: (updateObj: WordUpdateAction) => void }) {
const textareaRef = useRef<HTMLTextAreaElement>(null)

View File

@@ -1,5 +1,5 @@
import React from 'react'
import { EXPLICIT_SPACE } from '@/constants'
import React from 'react'
export type LetterState = 'normal' | 'correct' | 'wrong'

View File

@@ -1,19 +1,19 @@
import { useEffect, useContext, useCallback } from 'react'
import InputHandler, { WordUpdateAction } from '../InputHandler'
import WordSound from '../WordSound'
import Letter from './Letter'
import useKeySounds from '@/hooks/useKeySounds'
import { LetterState } from './Letter'
import style from './index.module.css'
import WordSound from '../WordSound'
import { useAtomValue } from 'jotai'
import { isIgnoreCaseAtom, pronunciationIsOpenAtom } from '@/store'
import dayjs from 'dayjs'
import { EXPLICIT_SPACE } from '@/constants'
import useKeySounds from '@/hooks/useKeySounds'
import { TypingContext, TypingStateActionType } from '@/pages/Typing/store'
import InputHandler, { WordUpdateAction } from '../InputHandler'
import { useSaveWordRecord } from '@/utils/db'
import { useImmer } from 'use-immer'
import { LetterMistakes } from '@/utils/db/record'
import { isIgnoreCaseAtom, pronunciationIsOpenAtom } from '@/store'
import { useMixPanelWordLogUploader } from '@/utils'
import { useSaveWordRecord } from '@/utils/db'
import { LetterMistakes } from '@/utils/db/record'
import dayjs from 'dayjs'
import { useAtomValue } from 'jotai'
import { useEffect, useContext, useCallback } from 'react'
import { useImmer } from 'use-immer'
type WordState = {
displayWord: string

View File

@@ -1,11 +1,11 @@
import { SoundIcon, SoundIconProps } from '../SoundIcon'
import styles from './index.module.css'
import Tooltip from '@/components/Tooltip'
import usePronunciationSound from '@/hooks/usePronunciation'
import { pronunciationIsOpenAtom } from '@/store'
import { useAtomValue } from 'jotai'
import { useEffect, useCallback } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import styles from './index.module.css'
import { pronunciationIsOpenAtom } from '@/store'
const WordSound = ({ word, inputWord, ...rest }: WordSoundProps) => {
const { play, stop, isPlaying } = usePronunciationSound(word)

View File

@@ -1,11 +1,11 @@
import { phoneticConfigAtom } from '@/store'
import { Word } from '@/typings'
import { useAtomValue } from 'jotai'
import { useContext } from 'react'
import { TypingContext } from '../../store'
import Phonetic from './components/Phonetic'
import Translation from './components/Translation'
import { default as WordComponent } from './components/Word'
import { phoneticConfigAtom } from '@/store'
import { Word } from '@/typings'
import { useAtomValue } from 'jotai'
import { useContext } from 'react'
export default function CurrentWord({ word, onFinish }: { word: Word; onFinish: () => void }) {
const phoneticConfig = useAtomValue(phoneticConfigAtom)

View File

@@ -1,13 +1,13 @@
import { LANG_PRON_MAP } from '@/resources/soundResource'
import { useAtom, useAtomValue } from 'jotai'
import { currentDictInfoAtom, phoneticConfigAtom, pronunciationConfigAtom } from '@/store'
import { useCallback, useEffect, useMemo } from 'react'
import { Listbox } from '@headlessui/react'
import { PronunciationType, PRONUNCIATION_PHONETIC_MAP } from '@/typings'
import { Fragment } from 'react'
import { Popover, Transition, Switch } from '@headlessui/react'
import Tooltip from '@/components/Tooltip'
import { LANG_PRON_MAP } from '@/resources/soundResource'
import { currentDictInfoAtom, phoneticConfigAtom, pronunciationConfigAtom } from '@/store'
import { PronunciationType, PRONUNCIATION_PHONETIC_MAP } from '@/typings'
import { Listbox } from '@headlessui/react'
import { Popover, Transition, Switch } from '@headlessui/react'
import { IconChevronDown, IconCheck } from '@tabler/icons-react'
import { useAtom, useAtomValue } from 'jotai'
import { useCallback, useEffect, useMemo } from 'react'
import { Fragment } from 'react'
const PronunciationSwitcher = () => {
const currentDictInfo = useAtomValue(currentDictInfoAtom)

View File

@@ -1,5 +1,5 @@
import classNames from 'classnames'
import { HeartIcon, HandThumbUpIcon, ExclamationTriangleIcon } from '@heroicons/react/20/solid'
import classNames from 'classnames'
import { ElementType, SVGAttributes } from 'react'
type IconMapper = {

View File

@@ -1,6 +1,6 @@
import clamp from '@/utils/clamp'
import { useMemo } from 'react'
import classNames from 'classnames'
import { useMemo } from 'react'
export type RemarkRingProps = {
remark: string

View File

@@ -1,7 +1,7 @@
import { flip, offset, shift, useFloating, useHover, useInteractions, useRole } from '@floating-ui/react'
import { useCallback, useState } from 'react'
import usePronunciationSound from '@/hooks/usePronunciation'
import { Word } from '@/typings'
import { flip, offset, shift, useFloating, useHover, useInteractions, useRole } from '@floating-ui/react'
import { useCallback, useState } from 'react'
export default function WordChip({ word }: { word: Word }) {
const [showTranslation, setShowTranslation] = useState(false)

View File

@@ -1,18 +1,18 @@
import { Transition } from '@headlessui/react'
import Tooltip from '@/components/Tooltip'
import { useCallback, useContext, useMemo } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { TypingContext, TypingStateActionType } from '../../store'
import ShareButton from '../ShareButton'
import ConclusionBar from './ConclusionBar'
import RemarkRing from './RemarkRing'
import WordChip from './WordChip'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { currentChapterAtom, currentDictInfoAtom, infoPanelStateAtom, randomConfigAtom } from '@/store'
import { recordOpenInfoPanelAction } from '@/utils'
import { InfoPanelType } from '@/typings'
import { TypingContext, TypingStateActionType } from '../../store'
import ShareButton from '../ShareButton'
import redBookLogo from '@/assets/redBook-color-logo.svg'
import Tooltip from '@/components/Tooltip'
import { currentChapterAtom, currentDictInfoAtom, infoPanelStateAtom, randomConfigAtom } from '@/store'
import { InfoPanelType } from '@/typings'
import { recordOpenInfoPanelAction } from '@/utils'
import { Transition } from '@headlessui/react'
import { IconX } from '@tabler/icons-react'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { useCallback, useContext, useMemo } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
const ResultScreen = () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

View File

@@ -1,8 +1,8 @@
import styles from './index.module.css'
import { isIgnoreCaseAtom, randomConfigAtom } from '@/store'
import { Switch } from '@headlessui/react'
import { useAtom } from 'jotai'
import { useCallback } from 'react'
import styles from './index.module.css'
export default function AdvancedSetting() {
const [randomConfig, setRandomConfig] = useAtom(randomConfigAtom)

View File

@@ -1,9 +1,9 @@
import styles from './index.module.css'
import { hintSoundsConfigAtom, keySoundsConfigAtom, pronunciationConfigAtom } from '@/store'
import { Switch } from '@headlessui/react'
import { useCallback } from 'react'
import * as Slider from '@radix-ui/react-slider'
import { useAtom } from 'jotai'
import { hintSoundsConfigAtom, keySoundsConfigAtom, pronunciationConfigAtom } from '@/store'
import styles from './index.module.css'
import { useCallback } from 'react'
export default function SoundSetting() {
const [pronunciationConfig, setPronunciationConfig] = useAtom(pronunciationConfigAtom)

View File

@@ -1,11 +1,11 @@
import { TypingContext, TypingStateActionType } from '../../store'
import AdvancedSetting from './AdvancedSetting'
import SoundSetting from './SoundSetting'
import { Dialog, Tab, Transition } from '@headlessui/react'
import { Cog6ToothIcon } from '@heroicons/react/24/solid'
import { IconEar, IconAdjustmentsHorizontal, IconX } from '@tabler/icons-react'
import classNames from 'classnames'
import { Fragment, useContext, useState } from 'react'
import SoundSetting from './SoundSetting'
import AdvancedSetting from './AdvancedSetting'
import { TypingContext, TypingStateActionType } from '../../store'
import { IconEar, IconAdjustmentsHorizontal, IconX } from '@tabler/icons-react'
import { Cog6ToothIcon } from '@heroicons/react/24/solid'
export default function Setting() {
const [isOpen, setIsOpen] = useState(false)

View File

@@ -1,8 +1,4 @@
import { Dialog, Transition } from '@headlessui/react'
import { toPng } from 'html-to-image'
import { Fragment, useContext, useEffect, useMemo, useRef, useState } from 'react'
import { saveAs } from 'file-saver'
import keyboardSvg from '@/assets/sharePic/keyBackground.svg'
import { TypingContext } from '../../store'
import shareImage1 from '@/assets/sharePic/image-1.png'
import shareImage2 from '@/assets/sharePic/image-2.png'
import shareImage3 from '@/assets/sharePic/image-3.png'
@@ -12,11 +8,15 @@ import shareImage6 from '@/assets/sharePic/image-6.png'
import shareImage7 from '@/assets/sharePic/image-7.png'
import shareImage8 from '@/assets/sharePic/image-8.png'
import shareImage9 from '@/assets/sharePic/image-9.png'
import { TypingContext } from '../../store'
import { useAtomValue } from 'jotai'
import keyboardSvg from '@/assets/sharePic/keyBackground.svg'
import { currentChapterAtom, currentDictInfoAtom } from '@/store'
import { recordShareAction } from '@/utils'
import { Dialog, Transition } from '@headlessui/react'
import { XMarkIcon } from '@heroicons/react/24/solid'
import { saveAs } from 'file-saver'
import { toPng } from 'html-to-image'
import { useAtomValue } from 'jotai'
import { Fragment, useContext, useEffect, useMemo, useRef, useState } from 'react'
const PIC_RATIO = 3
const PIC_LIST = [shareImage1, shareImage2, shareImage3, shareImage4, shareImage5, shareImage6, shareImage7, shareImage8, shareImage9]

View File

@@ -1,8 +1,8 @@
import { recordShareAction } from '@/utils'
import { useCallback, useMemo, useState } from 'react'
import SharePicDialog from './SharePicDialog'
import { recordShareAction } from '@/utils'
import { flip, offset, shift, useFloating, useHover, useInteractions, useRole } from '@floating-ui/react'
import { IconShare2 } from '@tabler/icons-react'
import { useCallback, useMemo, useState } from 'react'
export default function ShareButton() {
const [isShowSharePanel, setIsShowSharePanel] = useState(false)

View File

@@ -1,8 +1,8 @@
import { Fragment, useCallback } from 'react'
import { Popover, Transition, Switch } from '@headlessui/react'
import { useAtom } from 'jotai'
import { keySoundsConfigAtom, hintSoundsConfigAtom } from '@/store'
import { Popover, Transition, Switch } from '@headlessui/react'
import { SpeakerWaveIcon } from '@heroicons/react/24/solid'
import { useAtom } from 'jotai'
import { Fragment, useCallback } from 'react'
export default function SoundSwitcher() {
const [keySoundsConfig, setKeySoundsConfig] = useAtom(keySoundsConfigAtom)

View File

@@ -1,6 +1,6 @@
import { useContext } from 'react'
import InfoBox from './InfoBox'
import { TypingContext } from '../../store'
import InfoBox from './InfoBox'
import { useContext } from 'react'
export default function Speed() {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

View File

@@ -1,13 +1,13 @@
import { TypingContext, TypingStateActionType } from '../../store'
import Setting from '../Setting'
import SoundSwitcher from '../SoundSwitcher'
import Tooltip from '@/components/Tooltip'
import { isLoopSingleWordAtom, isOpenDarkModeAtom } from '@/store'
import { SunIcon, MoonIcon, EyeIcon, EyeSlashIcon } from '@heroicons/react/24/solid'
import { IconRepeatOnce, IconRepeatOff, IconLanguage, IconLanguageOff } from '@tabler/icons-react'
import { useAtom } from 'jotai'
import { useContext } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import Tooltip from '@/components/Tooltip'
import { useAtom } from 'jotai'
import { isLoopSingleWordAtom, isOpenDarkModeAtom } from '@/store'
import { TypingContext, TypingStateActionType } from '../../store'
import SoundSwitcher from '../SoundSwitcher'
import Setting from '../Setting'
import { IconRepeatOnce, IconRepeatOff, IconLanguage, IconLanguageOff } from '@tabler/icons-react'
import { SunIcon, MoonIcon, EyeIcon, EyeSlashIcon } from '@heroicons/react/24/solid'
export default function Switcher() {
const [isOpenDarkMode, setIsOpenDarkMode] = useAtom(isOpenDarkModeAtom)

View File

@@ -1,9 +1,9 @@
import { CHAPTER_LENGTH } from '@/constants'
import { currentDictInfoAtom, currentChapterAtom } from '@/store'
import { Word } from '@/typings/index'
import { useAtom, useAtomValue } from 'jotai'
import { useMemo } from 'react'
import useSWR from 'swr'
import { Word } from '@/typings/index'
import { currentDictInfoAtom, currentChapterAtom } from '@/store'
import { CHAPTER_LENGTH } from '@/constants'
export type UseWordListResult = {
words: Word[] | undefined

View File

@@ -1,24 +1,24 @@
import React, { useCallback, useEffect, useState } from 'react'
import Header from '@/components/Header'
import Speed from './components/Speed'
import Loading from '@/components/Loading'
import Layout from '../../components/Layout'
import CurrentWord from './components/CurrentWord'
import Progress from './components/Progress'
import PronunciationSwitcher from './components/PronunciationSwitcher'
import { IsDesktop, isLegal } from '@/utils'
import { useHotkeys } from 'react-hotkeys-hook'
import ResultScreen from './components/ResultScreen'
import Speed from './components/Speed'
import Switcher from './components/Switcher'
import { useWordList } from './hooks/useWordList'
import Layout from '../../components/Layout'
import { NavLink } from 'react-router-dom'
import Tooltip from '@/components/Tooltip'
import Progress from './components/Progress'
import ResultScreen from './components/ResultScreen'
import CurrentWord from './components/CurrentWord'
import { useAtomValue } from 'jotai'
import { currentChapterAtom, currentDictInfoAtom, isLoopSingleWordAtom, randomConfigAtom } from '@/store'
import { useMixPanelChapterLogUploader } from '@/utils/mixpanel'
import StarCard from '@/components/StarCard'
import { initialState, TypingContext, typingReducer, TypingStateActionType } from './store'
import Header from '@/components/Header'
import Loading from '@/components/Loading'
import StarCard from '@/components/StarCard'
import Tooltip from '@/components/Tooltip'
import { currentChapterAtom, currentDictInfoAtom, isLoopSingleWordAtom, randomConfigAtom } from '@/store'
import { IsDesktop, isLegal } from '@/utils'
import { useSaveChapterRecord } from '@/utils/db'
import { useMixPanelChapterLogUploader } from '@/utils/mixpanel'
import { useAtomValue } from 'jotai'
import React, { useCallback, useEffect, useState } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { NavLink } from 'react-router-dom'
import { useImmerReducer } from 'use-immer'
const App: React.FC = () => {

View File

@@ -1,9 +1,9 @@
import { atomWithStorage } from 'jotai/utils'
import { atom } from 'jotai'
import { CHAPTER_LENGTH, DISMISS_START_CARD_DATE_KEY } from '@/constants'
import { idDictionaryMap } from '@/resources/dictionary'
import { keySoundResources, wrongSoundResources, correctSoundResources } from '@/resources/soundResource'
import { PronunciationType, PhoneticType, Dictionary, InfoPanelState } from '@/typings'
import { idDictionaryMap } from '@/resources/dictionary'
import { CHAPTER_LENGTH, DISMISS_START_CARD_DATE_KEY } from '@/constants'
import { atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
export const currentDictIdAtom = atomWithStorage('currentDict', 'cet4')
export const currentDictInfoAtom = atom<Dictionary>((get) => {

View File

@@ -1,9 +1,9 @@
import { WordRecord, ChapterRecord, IWordRecord, IChapterRecord, LetterMistakes } from './record'
import { TypingContext, TypingState, TypingStateActionType } from '@/pages/Typing/store'
import { currentChapterAtom, currentDictIdAtom } from '@/store'
import Dexie, { Table } from 'dexie'
import { useAtomValue } from 'jotai'
import { useCallback, useContext } from 'react'
import { WordRecord, ChapterRecord, IWordRecord, IChapterRecord, LetterMistakes } from './record'
class RecordDB extends Dexie {
wordRecords!: Table<IWordRecord, number>

View File

@@ -1,4 +1,5 @@
import { Howl } from 'howler'
export * from './mixpanel'
const bannedKeys = [

View File

@@ -1,9 +1,4 @@
import dayjs from 'dayjs'
import { InfoPanelType } from '@/typings'
import mixpanel from 'mixpanel-browser'
import { PronunciationType } from '@/typings'
import { TypingState } from '@/pages/Typing/store'
import { useAtomValue } from 'jotai'
import {
currentChapterAtom,
currentDictInfoAtom,
@@ -14,6 +9,11 @@ import {
pronunciationConfigAtom,
randomConfigAtom,
} from '@/store'
import { InfoPanelType } from '@/typings'
import { PronunciationType } from '@/typings'
import dayjs from 'dayjs'
import { useAtomValue } from 'jotai'
import mixpanel from 'mixpanel-browser'
import { useCallback } from 'react'
export type starAction = 'star' | 'dismiss'

View File

@@ -1,10 +1,10 @@
import { visualizer } from 'rollup-plugin-visualizer'
import { defineConfig, type PluginOption } from 'vite'
import react from '@vitejs/plugin-react'
import { getLastCommit } from 'git-last-commit'
import jotaiDebugLabel from 'jotai/babel/plugin-debug-label'
import jotaiReactRefresh from 'jotai/babel/plugin-react-refresh'
import path from 'node:path'
import { getLastCommit } from 'git-last-commit'
import { visualizer } from 'rollup-plugin-visualizer'
import { defineConfig, type PluginOption } from 'vite'
// https://vitejs.dev/config/
export default defineConfig(async () => {

View File

@@ -22,6 +22,13 @@
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/code-frame@^7.16.7":
version "7.21.4"
resolved "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39"
integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.1", "@babel/compat-data@^7.20.5":
version "7.21.0"
resolved "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298"
@@ -57,6 +64,25 @@
eslint-visitor-keys "^2.1.0"
semver "^6.3.0"
"@babel/generator@7.17.7":
version "7.17.7"
resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad"
integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==
dependencies:
"@babel/types" "^7.17.0"
jsesc "^2.5.1"
source-map "^0.5.0"
"@babel/generator@^7.17.3":
version "7.21.4"
resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.21.4.tgz#64a94b7448989f421f919d5239ef553b37bb26bc"
integrity sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==
dependencies:
"@babel/types" "^7.21.4"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/generator@^7.21.0", "@babel/generator@^7.21.1":
version "7.21.1"
resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd"
@@ -127,7 +153,7 @@
resolve "^1.14.2"
semver "^6.1.2"
"@babel/helper-environment-visitor@^7.18.9":
"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.9":
version "7.18.9"
resolved "https://registry.npmmirror.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
@@ -139,7 +165,7 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0":
"@babel/helper-function-name@^7.16.7", "@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0", "@babel/helper-function-name@^7.21.0":
version "7.21.0"
resolved "https://registry.npmmirror.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4"
integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==
@@ -147,7 +173,7 @@
"@babel/template" "^7.20.7"
"@babel/types" "^7.21.0"
"@babel/helper-hoist-variables@^7.18.6":
"@babel/helper-hoist-variables@^7.16.7", "@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
resolved "https://registry.npmmirror.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
@@ -230,7 +256,7 @@
dependencies:
"@babel/types" "^7.20.0"
"@babel/helper-split-export-declaration@^7.18.6":
"@babel/helper-split-export-declaration@^7.16.7", "@babel/helper-split-export-declaration@^7.18.6":
version "7.18.6"
resolved "https://registry.npmmirror.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
@@ -242,7 +268,7 @@
resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
@@ -280,6 +306,11 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.17.3", "@babel/parser@^7.20.5":
version "7.21.4"
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17"
integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==
"@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2":
version "7.21.2"
resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3"
@@ -1035,6 +1066,22 @@
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
"@babel/traverse@7.17.3":
version "7.17.3"
resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57"
integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==
dependencies:
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.17.3"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-hoist-variables" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/parser" "^7.17.3"
"@babel/types" "^7.17.0"
debug "^4.1.0"
globals "^11.1.0"
"@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2":
version "7.21.2"
resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75"
@@ -1051,6 +1098,23 @@
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@7.17.0":
version "7.17.0"
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@babel/types@^7.17.0", "@babel/types@^7.21.4":
version "7.21.4"
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4"
integrity sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==
dependencies:
"@babel/helper-string-parser" "^7.19.4"
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.4.4":
version "7.21.2"
resolved "https://registry.npmmirror.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1"
@@ -1503,6 +1567,18 @@
resolve "^1.20.0"
tmp "^0.2.1"
"@trivago/prettier-plugin-sort-imports@^4.1.1":
version "4.1.1"
resolved "https://registry.npmmirror.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.1.1.tgz#71c3c1ae770c3738b6fc85710714844477574ffd"
integrity sha512-dQ2r2uzNr1x6pJsuh/8x0IRA3CBUB+pWEW3J/7N98axqt7SQSm+2fy0FLNXvXGg77xEDC7KHxJlHfLYyi7PDcw==
dependencies:
"@babel/generator" "7.17.7"
"@babel/parser" "^7.20.5"
"@babel/traverse" "7.17.3"
"@babel/types" "7.17.0"
javascript-natural-sort "0.7.1"
lodash "^4.17.21"
"@types/file-saver@^2.0.5":
version "2.0.5"
resolved "https://registry.npmmirror.com/@types/file-saver/-/file-saver-2.0.5.tgz#9ee342a5d1314bb0928375424a2f162f97c310c7"
@@ -3534,6 +3610,11 @@ jake@^10.8.5:
filelist "^1.0.1"
minimatch "^3.0.4"
javascript-natural-sort@0.7.1:
version "0.7.1"
resolved "https://registry.npmmirror.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
jiti@^1.17.2:
version "1.18.2"
resolved "https://registry.npmmirror.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd"
@@ -4753,6 +4834,11 @@ source-map-explorer@^2.5.2:
resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map@^0.5.0:
version "0.5.7"
resolved "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
source-map@^0.6.1, source-map@~0.6.0:
version "0.6.1"
resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"