main
Yuriy Evdokimov 2023-09-29 23:49:48 +05:00
parent 0b927c2204
commit 5dd170683f
8 changed files with 2634 additions and 117 deletions

View File

@ -43,4 +43,5 @@
.btn {
margin-bottom: 5px;
margin-right: 5px;
}

View File

@ -2,82 +2,107 @@ import { useState } from 'react'
import './App.css'
import Accordion from 'react-bootstrap/Accordion';
import Form from 'react-bootstrap/Form';
import { Button, Modal } from 'react-bootstrap';
import { initials, finales, syllables } from './Data';
import { Btn, BtnSimple } from './Btn';
import { Badge, Button, Modal } from 'react-bootstrap';
import { initials, finales, syllables, tones } from './Data';
import { isEnabled, toggle } from './Utils';
import { Syllable } from './Types';
import { Found, Syllable, Tone } from './Types';
import { strings } from './Strings';
const defaultFoundState:Found = {
allfinales: false,
allInitiales: false,
finales: [],
initiales: [],
syllables: [],
tones: []
}
function App() {
const [ count, setCount ] = useState(10)
const [ pause, setPause ] = useState(3)
const [ allInitiales, setAllInitiales] = useState(false)
const [ allFinales, setAllFinales] = useState(false)
const [ enabledInitials, setInitialsState ] = useState([] as String[])
const toggleInitialsState = (caption: String) => setInitialsState(toggle(enabledInitials,caption))
const [ enabledFinals, setFinalsState ] = useState([] as String[])
const toggleFinalsState = (caption: String) => setFinalsState(toggle(enabledFinals,caption))
const [ found, setFound ] = useState(defaultFoundState)
const onchangepause = (e: React.ChangeEvent<HTMLInputElement> ) => setPause( Number(e.target.value) )
const onchangecount = (e: React.ChangeEvent<HTMLInputElement> ) => setCount( Number(e.target.value) )
//---------------- to found state
const toggleAllInitiales = () => {
setAllInitiales( !allInitiales )
if (!allInitiales) setInitialsState(initials)
else setInitialsState([])
setFound({...found,
allInitiales: !found.allInitiales,
initiales: found.allInitiales ? [] : initials
})
}
const toggleInitialsState = (caption: String) => setFound({...found,
initiales: toggle(found.initiales,caption)
})
const toggleInitiales = (captions: String[]) => setFound({...found,
initiales: [...found.initiales.filter( f => !captions.includes(f)),
...captions.filter( c => !found.initiales.includes(c))]
})
// let arr3 = [...arr1, ...arr2];
//uniqueItems = [...new Set(items)]
const toggleAllFinales = () => {
setAllFinales( !allFinales )
if (!allFinales) setFinalsState(finales.map((f)=>f.finale))
else setFinalsState([])
setFound({...found,
allfinales: !found.allfinales,
finales: found.allfinales ? [] : finales.map( f => f.finale)
})
}
const toggleFinalsState = (caption: String) => setFound({...found,
finales: toggle(found.finales,caption)
})
//----------------------
const foundSyllables = ():Syllable[] => syllables.filter( (syl) => ( enabledInitials.some( (i) => i == syl.initiale ) )
&& ( enabledFinals.some( (f) => f == syl.finale ) ) )
const foundSyllables = ():Syllable[] => syllables.filter( (syl) => ( found.initiales.some( (i) => i == syl.initiale ) )
&& ( found.finales.some( (f) => f == syl.finale ) ) )
const found = ():boolean => foundSyllables().length > 0
const isFound = ():boolean => foundSyllables().length > 0
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const foundTones = ():Tone[] => tones.filter( (t) => foundSyllables().some( (syl) => syl.tones.some( (st) => st===t.tone) ) )
// const randomTones = ( length:number, fromTones:Tone[]):Tone[] => {
// const ftones = foundTones();
// return ftones
// }
return (
<>
<h1>Диктант pīnyīn</h1>
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>Выберите инициали</Accordion.Header>
<Accordion.Header>{strings.selectInitiales}</Accordion.Header>
<Accordion.Body>
<Btn type="primary" text="Выбрать все" altText="Снять все" onclick={toggleAllInitiales}/>
{initials.map( (text, i) => <BtnSimple
key={i}
type="primary"
text={text}
enabled={isEnabled(enabledInitials, text)}
onclick={toggleInitialsState}/>
<Button variant={found.allInitiales ? "primary" : "outline-primary"}
onClick= {()=>toggleInitiales( found.allInitiales ? [] : initials )}>
{found.allInitiales ? strings.unselectAll : strings.selectAll}
</Button>
{initials.map( (text, i) => <Button variant={isEnabled(found.initiales, text) ? "primary" : "outline-primary"}
key={i} onClick={()=>toggleInitiales([text])}>
{text}
</Button>
)}
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="1">
<Accordion.Header>Выберите финали</Accordion.Header>
<Accordion.Header>{strings.selectFinales}</Accordion.Header>
<Accordion.Body>
<Btn type="success" text="Выбрать все" altText="Снять все" onclick={toggleAllFinales}/>
{finales.map( (fin, i) => <BtnSimple
key={i}
type="success"
text={fin.caption}
enabled={isEnabled(enabledFinals, fin.finale)}
onclick={toggleFinalsState}
search={fin.finale}/>
<Button variant={found.allfinales ? "success" : "outline-success"}
onClick= {toggleAllFinales}>
{found.allfinales ? strings.unselectAll : strings.selectAll}
</Button>
{finales.map( (fin, i) => <Button variant={isEnabled(found.finales, fin.finale) ? "success" : "outline-success"}
key={i} onClick={()=>toggleFinalsState(fin.finale)}>
{fin.caption}
</Button>
)}
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="2">
<Accordion.Header>Параметры</Accordion.Header>
<Accordion.Header>{strings.params}</Accordion.Header>
<Accordion.Body>
<Form.Label>Количество слогов {count}</Form.Label>
<Form.Range value={count} min={5} max={50} step={5} onChange={onchangecount}/>
@ -87,21 +112,24 @@ function App() {
</Accordion.Item>
</Accordion>
<div className="card">
Выбрано {enabledInitials.length} инициалей, {enabledFinals.length} финалей, количество слогов {count}, пауза между слогами {pause} секунд.
Выбрано {found.initiales.length} инициалей, {found.finales.length} финалей, количество слогов {count}, пауза между слогами {pause} секунд.
<br/>
Найдено {foundSyllables().length} слогов, { foundSyllables().reduce(
( p, c ) => p + c.tones.length , 0
) } тонов
<br/>
<Button variant={found() ? "success" : "secondary"} size="lg" onClick={handleShow} disabled={!found()}>
{found() ? "Поехали!" : "Выберите инициали и финали" }
<Button variant={isFound() ? "success" : "secondary"} size="lg" onClick={handleShow} disabled={!isFound()}>
{isFound() ? "Поехали!" : "Выберите инициали и финали" }
</Button>
</div>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you are reading this text in a modal!</Modal.Body>
<Modal.Body>
{foundTones().map( (t, i) => <><Badge key={i} bg="success" pill>{t.caption}</Badge>{' '}</>)}
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close

View File

@ -1,40 +0,0 @@
import { ReactElement, useState } from 'react'
import { Button } from 'react-bootstrap';
import { justproc, proc } from './Types';
interface IBtnProps {
type: String,
text: String,
altText?: String,
onclick?: justproc
}
interface IBtnSimpleProps {
type: String,
text: String,
enabled: Boolean,
onclick?: proc,
search?: String
}
export function Btn ({ type, text, altText, onclick }: IBtnProps): ReactElement {
const [enabled, toggleState] = useState(false)
const alttext = altText ?? text;
const onclicklocal = () => {
toggleState(!enabled)
if (onclick) onclick!()
}
return <><Button
variant={`${enabled ? "" : "outline-"}${type}`}
onClick={ onclicklocal }>{enabled ? alttext : text}
</Button>{' '}</>
}
export function BtnSimple ({ type, text, enabled, onclick, search }: IBtnSimpleProps): ReactElement {
const onclickdefault: proc = (caption: String) => {console.log(caption)}
const onclickinternal: proc = onclick ?? onclickdefault
return <>
<Button variant={`${enabled ? "" : "outline-"}${type}`} onClick={()=>onclickinternal(search ?? text)}>{text}</Button>
{' '}
</>
}

View File

@ -1,28 +0,0 @@
import { ReactElement, useState } from 'react'
import { Btn, BtnSimple } from './Btn'
import { isEnabled, toggle } from './Utils'
function BtnSet(captions: String[], type: String): ReactElement {
const [ enabledButtons, setButtonsState ] = useState([] as String[])
const [ selectedAll, toggleSelectAll ] = useState(false)
const toggleState = (caption: String) => setButtonsState(toggle(enabledButtons,caption))
const toggleAll = () => {
toggleSelectAll( !selectedAll )
if (!selectedAll) setButtonsState([... captions])
else setButtonsState([])
}
return <>
<Btn type={type} text="Выбрать все" altText="Снять все" onclick={toggleAll}/>
{captions.map( (text) => <BtnSimple
type={type}
text={text}
enabled={isEnabled(enabledButtons, text)}
onclick={toggleState}/>
)}
</>
}
export default BtnSet

File diff suppressed because it is too large Load Diff

7
src/Strings.ts Normal file
View File

@ -0,0 +1,7 @@
export const strings = {
selectInitiales: 'Выберите инициали',
selectFinales: 'Выберите финали',
selectAll: 'Выбрать все',
unselectAll: 'Снять все',
params: 'Параметры'
}

View File

@ -12,3 +12,17 @@ export type Finale = {
caption: String,
finale: String
}
export type Tone = {
tone: String,
caption: String
}
export type Found = {
initiales: String[],
finales: String[],
allInitiales: Boolean,
allfinales: Boolean,
syllables: Syllable[],
tones: Tone[]
}

1267
tones.txt Normal file

File diff suppressed because it is too large Load Diff