Yuriy Evdokimov 2023-10-23 22:25:44 +05:00
parent f4afb98d37
commit 90682a9170
13 changed files with 101 additions and 38 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
VITE_REACT_APP_VERSION=$npm_package_version

View File

@ -1,7 +1,8 @@
{ {
"name": "vite-1", "name": "pinyindictation",
"author": {"email": "rurik19@yandex.ru", "name": "Yuriy Evdokimov"},
"private": true, "private": true,
"version": "0.0.0", "version": "1.0.2",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -60,3 +60,5 @@
.tone3 { color: rgb(85, 170, 0) } .tone3 { color: rgb(85, 170, 0) }
.tone4 { color: rgb(0, 0, 255) } .tone4 { color: rgb(0, 0, 255) }
.tone5 { color: rgb(50, 50, 50) } .tone5 { color: rgb(50, 50, 50) }
.cpr { color: gray}

View File

@ -1,14 +1,17 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import './App.css' import './App.css'
import { Button, ListGroup } from 'react-bootstrap'; import { Button, ListGroup } from 'react-bootstrap';
import { initials, finales } from './data'; import { initials, finales } from './pinyin';
import { BtnColor, Status, Tone } from './types'; import { BtnColor, Status, Tone } from './types';
import { strings } from './strings'; import { strings } from './strings';
import { useStateContext } from './store'; import { useStateContext } from './store';
import { Params } from './params'; import { Params } from './params';
import { ActionType, ToggleType } from './reducer'; import { ActionType, ToggleType } from './reducer';
import { ButtonSet } from './buttons'; import { ButtonSet } from './buttons';
import { getAudio } from './utils'; import { RenderTones } from './rendertones';
import { getAudio } from './audio';
import { Copyright } from './copyright';
import { SelectTones } from './selecttones';
function App() { function App() {
@ -65,23 +68,7 @@ const playPlayList = () => {
playlist[0].play() playlist[0].play()
} }
const playTone = (index: string) => { return (
getAudio(index).play()
}
const renderPlayList = () => {
return state.randomTones!.map(
(ton, i) => { return <span key={i}
className={`syllable tone${ton.num}`}
onClick = {()=>playTone(ton.tone)}
>
{i+1}{'. '}{ton.caption}{' '}
</span> }
)
}
return (
<> <>
<h1>{strings.mainHeader}</h1> <h1>{strings.mainHeader}</h1>
<ListGroup> <ListGroup>
@ -96,6 +83,11 @@ const renderPlayList = () => {
<ButtonSet source={finales} color={BtnColor.green} toggle={ToggleType.fin}/> <ButtonSet source={finales} color={BtnColor.green} toggle={ToggleType.fin}/>
</ListGroup.Item> </ListGroup.Item>
<ListGroup.Item disabled={status != Status.params}>
<h2>{strings.selectTones}</h2>
<SelectTones/>
</ListGroup.Item>
<ListGroup.Item disabled={status != Status.params}> <ListGroup.Item disabled={status != Status.params}>
<h2>{strings.params}</h2> <h2>{strings.params}</h2>
<Params/> <Params/>
@ -129,16 +121,16 @@ const renderPlayList = () => {
{ {
status == Status.showlist && status == Status.showlist &&
<> <>
<div>{renderPlayList()}</div> <RenderTones tones={state.randomTones!}/>
<br/> <br/>
<Button variant="success" onClick={()=> setStatus(Status.params)}>{strings.toBegin}</Button> <Button variant="success" onClick={()=> setStatus(Status.params)}>{strings.toBegin}</Button>
</> </>
} }
</ListGroup.Item> </ListGroup.Item>
<ListGroup.Item><Copyright/></ListGroup.Item>
</ListGroup> </ListGroup>
</> </>
) )
} }
export default App export default App

View File

@ -10,5 +10,8 @@ export const strings = {
selectInitAndFin: "Выберите инициали и финали", selectInitAndFin: "Выберите инициали и финали",
showSyllables: "Показать слоги", showSyllables: "Показать слоги",
playAgain: "Повторить", playAgain: "Повторить",
toBegin: "В начало" toBegin: "В начало",
version: "Версия",
cpr: "©",
selectTones: "Выберите тоны"
} }

View File

@ -1,4 +1,4 @@
import { syllables } from "./data" import { syllables } from "./pinyin"
import { BtnColor, SylPart, Syllable } from "./types" import { BtnColor, SylPart, Syllable } from "./types"
export const isEnabled = (arr: SylPart[], find: string): boolean => arr.some((str) => str.index==find) export const isEnabled = (arr: SylPart[], find: string): boolean => arr.some((str) => str.index==find)
@ -36,6 +36,3 @@ export const GetSyllablesByInitAndFin = (initiales:SylPart[], finales: SylPart[]
} }
export const Outlined = (color: BtnColor):string => `outline-${color}` export const Outlined = (color: BtnColor):string => `outline-${color}`
export const getAudioPath = (index: string):string => `/audio/${index}.mp3`
export const getAudio = (index: string):HTMLAudioElement => new Audio(getAudioPath(index))

View File

@ -3,7 +3,14 @@ export const playFile = (filename: string) => {
audio.play() audio.play()
} }
export const playTone = async (toneName: string) => { // export const playTone = async (toneName: string) => {
const audio = new Audio(`/src/assets/audio/${toneName}.mp3`) // const audio = new Audio(`/src/assets/audio/${toneName}.mp3`)
await audio.play() // await audio.play()
} // }
export const playTone = (index: string) => {
getAudio(index).play()
}
export const getAudioPath = (index: string):string => `/audio/${index}.mp3`
export const getAudio = (index: string):HTMLAudioElement => new Audio(getAudioPath(index))

View File

@ -12,8 +12,8 @@ export interface IBtnSerProps {
} }
export const ButtonSet = (props: IBtnSerProps) => { export const ButtonSet = (props: IBtnSerProps) => {
const { state, dispatch } = useStateContext(); const { state, dispatch } = useStateContext()
const { source, color, toggle } = props; const { source, color, toggle } = props
return <> return <>
<Button variant={ state.allEnabled!(toggle) ? color : Outlined(color) } <Button variant={ state.allEnabled!(toggle) ? color : Outlined(color) }
onClick= {()=>dispatch({type: ActionType.toggleAll, payload: toggle})}> onClick= {()=>dispatch({type: ActionType.toggleAll, payload: toggle})}>

5
src/copyright.tsx Normal file
View File

@ -0,0 +1,5 @@
import { ReactElement } from "react";
import { strings } from "./strings";
import { author } from '../package.json'
export const Copyright = ():ReactElement => <div className="cpr">{strings.version} {import.meta.env.VITE_REACT_APP_VERSION} {strings.cpr}{author.name}</div>

View File

@ -1,4 +1,4 @@
import { finales, initials, tones } from "./data"; import { finales, initials, tones } from "./pinyin";
import { IState } from "./store"; import { IState } from "./store";
import { SylPart, Syllable, Tone } from "./types"; import { SylPart, Syllable, Tone } from "./types";
import { GetSyllablesByInitAndFin, getRandomArray, toggle } from "./utils"; import { GetSyllablesByInitAndFin, getRandomArray, toggle } from "./utils";

20
src/rendertones.tsx Normal file
View File

@ -0,0 +1,20 @@
import { ReactElement } from "react";
import { playTone } from "./audio";
import { Tone } from "./types";
interface IRenderTonesProps {
tones: Tone[]
}
export const RenderTones = (props:IRenderTonesProps):ReactElement => {
const { tones } = props
return <div>
{ tones!.map(
(ton, i) => { return <span key={i}
className={`syllable tone${ton.num}`}
onClick={() => playTone(ton.tone)}
>
{i + 1}{'. '}{ton.caption}{' '}
</span> } ) }
</div>
}

35
src/selecttones.tsx Normal file
View File

@ -0,0 +1,35 @@
import { useStateContext } from "./store"
import { Form } from "react-bootstrap";
export const SelectTones = () => {
// const { state, dispatch } = useStateContext()
return <>
<Form>
<Form.Check // prettier-ignore
inline
type="switch"
id="first-switch"
label="Первый"
/>
<Form.Check // prettier-ignore
inline
type="switch"
label="Второй"
id="second-switch"
/>
</Form><Form>
<Form.Check // prettier-ignore
inline
type="switch"
id="third-switch"
label="Третий"
/>
<Form.Check // prettier-ignore
inline
type="switch"
label="Четвёртый"
id="fourth-switch"
/>
</Form>
</>
}