init commit,
@@ -0,0 +1,68 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
range_list: number[];
|
||||
}
|
||||
|
||||
const AttentiveEarsProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, range_list }) => {
|
||||
let test_value = value;
|
||||
let scale = [];
|
||||
|
||||
for (let i = 0; i < range_list.length; i++) {
|
||||
let scale_full_range = range_list[i];
|
||||
let scale_range = i > 0 ? scale_full_range - range_list[i - 1] : scale_full_range;
|
||||
|
||||
let fill = 0;
|
||||
if (test_value > scale_full_range) {
|
||||
fill = scale_full_range;
|
||||
} else {
|
||||
if (i > 0) {
|
||||
fill = Math.max(0, test_value - range_list[i - 1]);
|
||||
} else {
|
||||
fill = test_value;
|
||||
}
|
||||
}
|
||||
let fill_pct = Math.min(fill / scale_range, 1);
|
||||
scale.push([fill_pct]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
{scale.map((item: any, index: number) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `calc( 100% / ${range_list.length} )`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.5rem' }}>{range_list[index]}</div>
|
||||
<div
|
||||
className={`audioSeekBar playBar_t__seek`}
|
||||
style={{
|
||||
// border: '1px solid #000',
|
||||
borderTop: '1px solid #000',
|
||||
borderBottom: '1px solid #000',
|
||||
borderLeft: index == 0 ? '1px solid #000' : '',
|
||||
borderRight: index == scale.length - 1 ? '1px solid #000' : '',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: `${item * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AttentiveEarsProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
import { IonButton, IonContent, IonModal, useIonRouter } from '@ionic/react';
|
||||
import { useRef } from 'react';
|
||||
import { COLOR_TEXT } from '../../constants';
|
||||
import { useAppStateContext } from '../../contexts/AppState';
|
||||
import { useMyIonQuizContext } from '../../contexts/MyIonQuiz';
|
||||
|
||||
function ConfirmUserExit() {
|
||||
let {
|
||||
setTabActive,
|
||||
show_confirm_user_exit,
|
||||
setShowConfirmUserExit,
|
||||
url_push_after_user_confirm,
|
||||
setListeningPracticeInProgress,
|
||||
setConnectiveRevisionInProgress,
|
||||
setMatchingFrenzyInProgress,
|
||||
} = useAppStateContext();
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const router = useIonRouter();
|
||||
const { resetListeningPracticeCorrectionList } = useMyIonQuizContext();
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
isOpen={show_confirm_user_exit}
|
||||
ref={modal}
|
||||
// trigger='open-modal'
|
||||
initialBreakpoint={0.25}
|
||||
breakpoints={[0, 0.25, 0.5, 0.75]}
|
||||
onDidDismiss={() => setShowConfirmUserExit(false)}
|
||||
>
|
||||
<IonContent className="ion-padding">
|
||||
<div style={{ margin: '2rem', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||
<div style={{ color: COLOR_TEXT }}>Are you sure want to quit ?</div>
|
||||
<div
|
||||
style={{
|
||||
margin: '2rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
gap: '3rem',
|
||||
}}
|
||||
>
|
||||
<IonButton
|
||||
color="dark"
|
||||
shape={'round'}
|
||||
style={{ minWidth: '80px' }}
|
||||
onClick={() => setShowConfirmUserExit(false)}
|
||||
>
|
||||
No
|
||||
</IonButton>
|
||||
<IonButton
|
||||
fill="outline"
|
||||
shape={'round'}
|
||||
style={{ minWidth: '80px', color: COLOR_TEXT }}
|
||||
color="dark"
|
||||
onClick={() => {
|
||||
setShowConfirmUserExit(false);
|
||||
setListeningPracticeInProgress(false);
|
||||
setMatchingFrenzyInProgress(false);
|
||||
setConnectiveRevisionInProgress(false);
|
||||
//
|
||||
resetListeningPracticeCorrectionList();
|
||||
//
|
||||
setTabActive(url_push_after_user_confirm);
|
||||
//
|
||||
router.push(url_push_after_user_confirm, 'none', 'replace');
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</IonButton>
|
||||
</div>
|
||||
</div>
|
||||
</IonContent>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ConfirmUserExit;
|
@@ -0,0 +1,86 @@
|
||||
import { IonButton, IonContent, IonModal, useIonRouter } from '@ionic/react';
|
||||
import { Dispatch, FunctionComponent, SetStateAction, useRef } from 'react';
|
||||
import { COLOR_TEXT } from '../../constants';
|
||||
import { useAppStateContext } from '../../contexts/AppState';
|
||||
import { useMyIonQuizContext } from '../../contexts/MyIonQuiz';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
show_confirm_user_exit: boolean;
|
||||
setShowConfirmUserExit: Dispatch<SetStateAction<boolean>>;
|
||||
url_push_after_user_confirm: string;
|
||||
}
|
||||
|
||||
const ConfirmUserQuitQuiz: FunctionComponent<AudioSeekBarProps> = ({
|
||||
show_confirm_user_exit,
|
||||
setShowConfirmUserExit,
|
||||
//
|
||||
url_push_after_user_confirm,
|
||||
}) => {
|
||||
let { setListeningPracticeInProgress, setConnectiveRevisionInProgress, setMatchingFrenzyInProgress } =
|
||||
useAppStateContext();
|
||||
let { setTabActive } = useAppStateContext();
|
||||
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const router = useIonRouter();
|
||||
const { resetListeningPracticeCorrectionList } = useMyIonQuizContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
isOpen={show_confirm_user_exit}
|
||||
ref={modal}
|
||||
// trigger='open-modal'
|
||||
initialBreakpoint={0.25}
|
||||
breakpoints={[0, 0.25, 0.5, 0.75]}
|
||||
onDidDismiss={() => setShowConfirmUserExit(false)}
|
||||
>
|
||||
<IonContent className="ion-padding">
|
||||
<div style={{ margin: '2rem', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||
<div style={{ color: COLOR_TEXT }}>Are you sure want to quit ?</div>
|
||||
<div
|
||||
style={{
|
||||
margin: '2rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
gap: '3rem',
|
||||
}}
|
||||
>
|
||||
<IonButton
|
||||
color="dark"
|
||||
shape={'round'}
|
||||
style={{ minWidth: '80px' }}
|
||||
onClick={() => setShowConfirmUserExit(false)}
|
||||
>
|
||||
No
|
||||
</IonButton>
|
||||
<IonButton
|
||||
fill="outline"
|
||||
shape={'round'}
|
||||
style={{ minWidth: '80px', color: COLOR_TEXT }}
|
||||
color="dark"
|
||||
onClick={() => {
|
||||
setShowConfirmUserExit(false);
|
||||
setListeningPracticeInProgress(false);
|
||||
setMatchingFrenzyInProgress(false);
|
||||
setConnectiveRevisionInProgress(false);
|
||||
//
|
||||
resetListeningPracticeCorrectionList();
|
||||
//
|
||||
setTabActive(url_push_after_user_confirm);
|
||||
//
|
||||
router.push(url_push_after_user_confirm, 'none', 'replace');
|
||||
}}
|
||||
>
|
||||
Yes
|
||||
</IonButton>
|
||||
</div>
|
||||
</div>
|
||||
</IonContent>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmUserQuitQuiz;
|
@@ -0,0 +1,68 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
range_list: number[];
|
||||
}
|
||||
|
||||
const ConnectivesConquerorProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, range_list }) => {
|
||||
let test_value = value;
|
||||
let scale = [];
|
||||
|
||||
for (let i = 0; i < range_list.length; i++) {
|
||||
let scale_full_range = range_list[i];
|
||||
let scale_range = i > 0 ? scale_full_range - range_list[i - 1] : scale_full_range;
|
||||
|
||||
let fill = 0;
|
||||
if (test_value > scale_full_range) {
|
||||
fill = scale_full_range;
|
||||
} else {
|
||||
if (i > 0) {
|
||||
fill = Math.max(0, test_value - range_list[i - 1]);
|
||||
} else {
|
||||
fill = test_value;
|
||||
}
|
||||
}
|
||||
let fill_pct = Math.min(fill / scale_range, 1);
|
||||
scale.push([fill_pct]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
{scale.map((item: any, index: number) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `calc( 100% / ${range_list.length} )`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.5rem' }}>{range_list[index]}</div>
|
||||
<div
|
||||
className={`audioSeekBar playBar_t__seek`}
|
||||
style={{
|
||||
// border: '1px solid #000',
|
||||
borderTop: '1px solid #000',
|
||||
borderBottom: '1px solid #000',
|
||||
borderLeft: index == 0 ? '1px solid #000' : '',
|
||||
borderRight: index == scale.length - 1 ? '1px solid #000' : '',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: `${item * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConnectivesConquerorProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
import { IonToast } from '@ionic/react';
|
||||
import './style.css';
|
||||
import { CORRECT_ANSWER_MESSAGE } from '../../constants';
|
||||
import { useAppStateContext } from '../../contexts/AppState';
|
||||
|
||||
interface QuestionCardProps {
|
||||
isOpen: boolean;
|
||||
dismiss: () => void;
|
||||
}
|
||||
|
||||
const CorrectAnswerToast: React.FC<QuestionCardProps> = ({ isOpen, dismiss }) => {
|
||||
const { CORRECT_ANS_TOAST_APPEAR_TIMEOUT_S } = useAppStateContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonToast
|
||||
className="correct-answer-toast"
|
||||
isOpen={isOpen}
|
||||
message={CORRECT_ANSWER_MESSAGE}
|
||||
onDidDismiss={() => dismiss()}
|
||||
duration={CORRECT_ANS_TOAST_APPEAR_TIMEOUT_S * 1000}
|
||||
color="success"
|
||||
></IonToast>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CorrectAnswerToast;
|
@@ -0,0 +1,9 @@
|
||||
ion-toast.correct-answer-toast::part(message) {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
ion-toast.correct-answer-toast::part(container) {
|
||||
bottom: 100px;
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
import { IonBackdrop } from '@ionic/react';
|
||||
import { useAppStateContext } from '../../contexts/AppState';
|
||||
|
||||
export function DisableUserTap({ children }: { children: React.ReactNode }) {
|
||||
const { disable_user_tap } = useAppStateContext();
|
||||
return (
|
||||
<>
|
||||
{disable_user_tap ? <IonBackdrop visible={true}></IonBackdrop> : null}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
After Width: | Height: | Size: 12 KiB |
21
002_source/ionic_mobile/src/components/ExitButton/index.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { App } from '@capacitor/app';
|
||||
import { IonButton, IonIcon } from '@ionic/react';
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
import { exitOutline } from 'ionicons/icons';
|
||||
|
||||
const ExitButton: FunctionComponent = () => {
|
||||
const handleExitOnClick = () => {
|
||||
App.exitApp();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonButton color="clear" fill="clear" shape="round" onClick={handleExitOnClick}>
|
||||
<IonIcon slot={'icon-only'} color={'dark'} size={'large'} icon={exitOutline} />
|
||||
</IonButton>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExitButton;
|
29
002_source/ionic_mobile/src/components/ExitButton/style.css
Normal file
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
24
002_source/ionic_mobile/src/components/ExploreContainer.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.container strong {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.container p {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container a {
|
||||
text-decoration: none;
|
||||
}
|
43
002_source/ionic_mobile/src/components/ExploreContainer.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import './ExploreContainer.css';
|
||||
import React from 'react';
|
||||
import Markdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
|
||||
interface ContainerProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const markdown = `
|
||||
Just a link: www.nasa.gov.
|
||||
- [ ] helloworld
|
||||
__bold__
|
||||
# h1
|
||||
## h2
|
||||
### h3
|
||||
#### h4
|
||||
##### h5
|
||||
###### h6
|
||||
|
||||
| test | test | test |
|
||||
| --- | --- | --- |
|
||||
| 1 | 1 | 1 |
|
||||
`;
|
||||
|
||||
const ExploreContainer: React.FC<ContainerProps> = ({ name }) => {
|
||||
return (
|
||||
<div className="container">
|
||||
<strong>{name}</strong>
|
||||
<p>
|
||||
Explore{' '}
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">
|
||||
UI Components
|
||||
</a>
|
||||
</p>
|
||||
<div>
|
||||
<Markdown remarkPlugins={[remarkGfm]}>{markdown}</Markdown>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExploreContainer;
|
@@ -0,0 +1,109 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
range_list: number[];
|
||||
}
|
||||
|
||||
const GeniusProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, range_list }) => {
|
||||
let test_value = value;
|
||||
let scale = [];
|
||||
|
||||
for (let i = 0; i < range_list.length; i++) {
|
||||
let scale_full_range = range_list[i];
|
||||
let scale_range = i > 0 ? scale_full_range - range_list[i - 1] : scale_full_range;
|
||||
|
||||
let fill = 0;
|
||||
if (test_value > scale_full_range) {
|
||||
fill = scale_full_range;
|
||||
} else {
|
||||
if (i > 0) {
|
||||
fill = Math.max(0, test_value - range_list[i - 1]);
|
||||
} else {
|
||||
fill = Math.max(0, test_value);
|
||||
}
|
||||
}
|
||||
let fill_pct = Math.min(fill / scale_range, 1);
|
||||
scale.push([fill_pct]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', width: '100%' }}>
|
||||
<div style={{ width: '100%', display: 'flex', flexDirection: 'row' }}>
|
||||
{scale.map((item: any, index: number) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
width: `calc( 100% / ${range_list.length} )`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.5rem' }}>{range_list[index]}</div>
|
||||
<div
|
||||
className={`audioSeekBar playBar_t__seek`}
|
||||
style={{
|
||||
// border: '1px solid #000',
|
||||
borderTop: '1px solid #000',
|
||||
borderBottom: '1px solid #000',
|
||||
borderLeft: index == 0 ? '1px solid #000' : '',
|
||||
borderRight: index == scale.length - 1 ? '1px solid #000' : '',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: `${item * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ backgroundColor: 'gold' }}>
|
||||
<div>helloworld</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
{scale.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `calc( 100% / ${range_list.length} )`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.5rem' }}>{range_list[index]}</div>
|
||||
<div
|
||||
className={`audioSeekBar playBar_t__seek`}
|
||||
style={{ borderTop: '1px solid #000', borderBottom: '1px solid #000' }}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: `${item * 100}%`,
|
||||
borderLeft: index == 0 ? '1px solid #000' : '',
|
||||
borderRight: index == 6 ? '1px solid #000' : '',
|
||||
}}
|
||||
className="audioSeekBar__tick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GeniusProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
range_list: number[];
|
||||
}
|
||||
|
||||
const HardWorkerProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, range_list }) => {
|
||||
let test_value = value;
|
||||
let scale = [];
|
||||
|
||||
for (let i = 0; i < range_list.length; i++) {
|
||||
let scale_full_range = range_list[i];
|
||||
let scale_range = i > 0 ? scale_full_range - range_list[i - 1] : scale_full_range;
|
||||
|
||||
let fill = 0;
|
||||
if (test_value > scale_full_range) {
|
||||
fill = scale_full_range;
|
||||
} else {
|
||||
if (i > 0) {
|
||||
fill = Math.max(0, test_value - range_list[i - 1]);
|
||||
} else {
|
||||
fill = test_value;
|
||||
}
|
||||
}
|
||||
let fill_pct = Math.min(fill / scale_range, 1);
|
||||
scale.push([fill_pct]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', width: '100%' }}>
|
||||
<div style={{ width: '100%', display: 'flex', flexDirection: 'row' }}>
|
||||
{scale.map((item: any, index: number) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
width: `calc( 100% / ${range_list.length} )`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.5rem' }}>{range_list[index]}</div>
|
||||
<div
|
||||
className={`audioSeekBar playBar_t__seek`}
|
||||
style={{
|
||||
// border: '1px solid #000',
|
||||
borderTop: '1px solid #000',
|
||||
borderBottom: '1px solid #000',
|
||||
borderLeft: index == 0 ? '1px solid #000' : '',
|
||||
borderRight: index == scale.length - 1 ? '1px solid #000' : '',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: `${item * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HardWorkerProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
BIN
002_source/ionic_mobile/src/components/HelloworldImage/image.jpg
Normal file
After Width: | Height: | Size: 194 KiB |
@@ -0,0 +1,9 @@
|
||||
import ImageJpg from './image.jpg';
|
||||
|
||||
function HelloworldImage() {
|
||||
return (
|
||||
<div style={{ width: '100%', height: '100%', backgroundImage: `url(${ImageJpg})`, backgroundSize: 'cover' }}></div>
|
||||
);
|
||||
}
|
||||
|
||||
export { HelloworldImage };
|
@@ -0,0 +1,26 @@
|
||||
import { IonContent, IonPage, IonSpinner } from '@ionic/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function LoadingScreen() {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
return (
|
||||
<IonPage>
|
||||
<IonContent fullscreen>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
gap: '1rem',
|
||||
//
|
||||
marginTop: '33vh',
|
||||
}}
|
||||
>
|
||||
<IonSpinner></IonSpinner>
|
||||
<div>{t('Loading')}</div>
|
||||
</div>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
}
|
34
002_source/ionic_mobile/src/components/MarkRating/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { IonIcon } from '@ionic/react';
|
||||
import './style.css';
|
||||
import { star, starOutline } from 'ionicons/icons';
|
||||
|
||||
interface ContainerProps {
|
||||
num_rating: number;
|
||||
max_rating?: number;
|
||||
}
|
||||
|
||||
const MarkRating: React.FC<ContainerProps> = ({ num_rating, max_rating = 3 }) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '0.5rem' }}>
|
||||
{Array.from({ length: max_rating }, (_, index) => {
|
||||
if (index < num_rating) {
|
||||
return (
|
||||
<div style={{ width: '10vw', height: '10vw' }}>
|
||||
<IonIcon size="large" color="warning" icon={star}></IonIcon>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div style={{ width: '10vw', height: '10vw' }}>
|
||||
<IonIcon size="large" color="warning" style={{ opacity: '0.3' }} icon={starOutline}></IonIcon>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MarkRating;
|
@@ -0,0 +1,68 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
range_list: number[];
|
||||
}
|
||||
|
||||
const MatchmakingProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, range_list }) => {
|
||||
let test_value = value;
|
||||
let scale = [];
|
||||
|
||||
for (let i = 0; i < range_list.length; i++) {
|
||||
let scale_full_range = range_list[i];
|
||||
let scale_range = i > 0 ? scale_full_range - range_list[i - 1] : scale_full_range;
|
||||
|
||||
let fill = 0;
|
||||
if (test_value > scale_full_range) {
|
||||
fill = scale_full_range;
|
||||
} else {
|
||||
if (i > 0) {
|
||||
fill = Math.max(0, test_value - range_list[i - 1]);
|
||||
} else {
|
||||
fill = test_value;
|
||||
}
|
||||
}
|
||||
let fill_pct = Math.min(fill / scale_range, 1);
|
||||
scale.push([fill_pct]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
{scale.map((item: any, index: number) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `calc( 100% / ${range_list.length} )`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: '0.5rem' }}>{range_list[index]}</div>
|
||||
<div
|
||||
className={`audioSeekBar playBar_t__seek`}
|
||||
style={{
|
||||
// border: '1px solid #000',
|
||||
borderTop: '1px solid #000',
|
||||
borderBottom: '1px solid #000',
|
||||
borderLeft: index == 0 ? '1px solid #000' : '',
|
||||
borderRight: index == scale.length - 1 ? '1px solid #000' : '',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: `${item * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MatchmakingProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { COLOR_TEXT, CONNECTIVE_CONQUEROR_STAGES, DEBUG } from '../../../../constants';
|
||||
import './style.css';
|
||||
import { useConnectivesRevisionCorrectCount } from '../../../../contexts/MyIonMetric/ConnectivesRevisionCorrectCount';
|
||||
|
||||
function CongratConnectiveConqueror({}: {}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const message = '';
|
||||
const [message, setMessage] = useState('');
|
||||
const [openCongratListeningProgress, setOpenCongratListeningProgress] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [count_to_prompt, setCountToPrompt] = useState(0);
|
||||
|
||||
const {
|
||||
myIonMetricGetConnectivesRevisionCorrectCount,
|
||||
myIonMetricGetConnectivesRevisionCorrectCountIgnore,
|
||||
myIonMetricSetConnectivesRevisionCorrectCountIgnore,
|
||||
} = useConnectivesRevisionCorrectCount();
|
||||
|
||||
const dismiss_modal = () => {
|
||||
myIonMetricSetConnectivesRevisionCorrectCountIgnore(count_to_prompt);
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
async function promptProgress(count_to_prompt: number) {
|
||||
if (count_to_prompt == (await myIonMetricGetConnectivesRevisionCorrectCountIgnore()).count) return;
|
||||
// setCountPrompted(count_to_prompt);
|
||||
setMessage('You scored full marks ' + count_to_prompt + ' times.');
|
||||
// setOpenedCongraFullmarkTimes(true);
|
||||
setOpened(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const prompt_list = CONNECTIVE_CONQUEROR_STAGES;
|
||||
const b_prompt_list = Array(prompt_list.length).fill(false);
|
||||
|
||||
for (let i = 0; i < prompt_list.length; i++) {
|
||||
if (progress > prompt_list[i]) {
|
||||
b_prompt_list[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let lastTrueIndex = -1;
|
||||
for (let i = b_prompt_list.length - 1; i >= 0; i--) {
|
||||
if (b_prompt_list[i]) {
|
||||
lastTrueIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTrueIndex == -1) {
|
||||
DEBUG ? console.log('prompt ignored') : '';
|
||||
} else {
|
||||
setCountToPrompt(prompt_list[lastTrueIndex]);
|
||||
promptProgress(prompt_list[lastTrueIndex]);
|
||||
}
|
||||
}, [progress]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let temp = await myIonMetricGetConnectivesRevisionCorrectCount();
|
||||
setProgress(temp.count);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="congratulation-listening-progress-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
// 008_remove_achievement_announcement, hide congratulation modal
|
||||
isOpen={false}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
{DEBUG ? <span className={'debug'}>congratulation connectives conqueror</span> : <></>}
|
||||
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratConnectiveConqueror;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { COLOR_TEXT, DEBUG, GENIUS_STAGES } from '../../../../constants';
|
||||
import './style.css';
|
||||
import { useAppStateContext } from '../../../../contexts/AppState';
|
||||
import { useFullmarkCount } from '../../../../contexts/MyIonMetric/FullmarkCount';
|
||||
|
||||
function CongratGenius({}: {}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const message = '';
|
||||
const [message, setMessage] = useState('');
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [count_to_prompt, setCountToPrompt] = useState(0);
|
||||
|
||||
const { myIonMetricGetFullMarkCount, myIonMetricGetFullMarkIgnore, myIonMetricSetFullMarkIgnore } =
|
||||
useFullmarkCount();
|
||||
|
||||
const dismiss_modal = () => {
|
||||
myIonMetricSetFullMarkIgnore(count_to_prompt);
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
async function promptGeniusProgress(count_to_prompt: number) {
|
||||
if (count_to_prompt == (await myIonMetricGetFullMarkIgnore()).count) return;
|
||||
// setCountPrompted(count_to_prompt);
|
||||
setMessage('You scored full marks ' + count_to_prompt + ' times.');
|
||||
// setOpenedCongraFullmarkTimes(true);
|
||||
setOpened(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const prompt_list = GENIUS_STAGES;
|
||||
const b_prompt_list = Array(prompt_list.length).fill(false);
|
||||
|
||||
for (let i = 0; i < prompt_list.length; i++) {
|
||||
if (progress >= prompt_list[i]) {
|
||||
b_prompt_list[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let lastTrueIndex = -1;
|
||||
for (let i = b_prompt_list.length - 1; i >= 0; i--) {
|
||||
if (b_prompt_list[i]) {
|
||||
lastTrueIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTrueIndex == -1) {
|
||||
DEBUG ? console.log('prompt ignored') : '';
|
||||
} else {
|
||||
console.log({ progress });
|
||||
setCountToPrompt(prompt_list[lastTrueIndex]);
|
||||
promptGeniusProgress(prompt_list[lastTrueIndex]);
|
||||
}
|
||||
}, [progress]);
|
||||
|
||||
let { tab_active } = useAppStateContext();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let temp = await myIonMetricGetFullMarkCount();
|
||||
setProgress(temp.count);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="congratulation-listening-progress-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
// 008_remove_achievement_announcement, hide congratulation modal
|
||||
isOpen={false}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
{DEBUG ? <span className={'debug'}>congratulation genius</span> : <></>}
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratGenius;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { COLOR_TEXT, DEBUG, HARDWORKER_STAGES } from '../../../../constants';
|
||||
import './style.css';
|
||||
import { useAppUseTime } from '../../../../contexts/MyIonMetric/AppUseTime';
|
||||
|
||||
function CongratHardworker({}: {}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const message = '';
|
||||
const [message, setMessage] = useState('');
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [count_to_prompt, setCountToPrompt] = useState(0);
|
||||
|
||||
const {
|
||||
//
|
||||
myIonMetricGetAppUseTime,
|
||||
myIonMetricSetAppUseTimeIgnore,
|
||||
myIonMetricGetAppUseTimeIgnore,
|
||||
} = useAppUseTime();
|
||||
|
||||
const dismiss_modal = () => {
|
||||
myIonMetricSetAppUseTimeIgnore(count_to_prompt);
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
async function promptHardworkerProgress(count_to_prompt: number) {
|
||||
if (count_to_prompt == (await myIonMetricGetAppUseTimeIgnore()).time_spent_s) return;
|
||||
// setCountPrompted(count_to_prompt);
|
||||
setMessage('You scored full marks ' + count_to_prompt + ' times.');
|
||||
// setOpenedCongraFullmarkTimes(true);
|
||||
setOpened(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const prompt_list = HARDWORKER_STAGES;
|
||||
const b_prompt_list = Array(prompt_list.length).fill(false);
|
||||
|
||||
for (let i = 0; i < prompt_list.length; i++) {
|
||||
if (progress >= prompt_list[i]) {
|
||||
b_prompt_list[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let lastTrueIndex = -1;
|
||||
for (let i = b_prompt_list.length - 1; i >= 0; i--) {
|
||||
if (b_prompt_list[i]) {
|
||||
lastTrueIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTrueIndex == -1) {
|
||||
DEBUG ? console.log('prompt ignored') : '';
|
||||
} else {
|
||||
console.log({ progress });
|
||||
setCountToPrompt(prompt_list[lastTrueIndex]);
|
||||
promptHardworkerProgress(prompt_list[lastTrueIndex]);
|
||||
}
|
||||
}, [progress]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let temp = await myIonMetricGetAppUseTime();
|
||||
|
||||
setProgress(Math.floor(temp.time_spent_s / 60));
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="congratulation-listening-progress-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
// 008_remove_achievement_announcement, hide congratulation modal
|
||||
isOpen={false}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
{DEBUG ? <span className={'debug'}>congratulation hardworker</span> : <></>}
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratHardworker;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { COLOR_TEXT } from '../../../../constants';
|
||||
import './style.css';
|
||||
|
||||
function CongratHelloworld({}: {}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const message = '';
|
||||
const [message, setMessage] = useState('');
|
||||
const [openCongratListeningProgress, setOpenCongratListeningProgress] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [count_to_prompt, setCountToPrompt] = useState(0);
|
||||
|
||||
const dismiss_modal = () => {
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
useEffect(() => {}, [progress]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="congratulation-listening-progress-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
isOpen={opened}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratHelloworld;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { ATTENTIVE_EARS_STAGES, COLOR_TEXT, DEBUG } from '../../../../constants';
|
||||
import { useListeningPracticeTimeSpent } from '../../../../contexts/MyIonMetric/ListeningPracticeTimeSpent';
|
||||
import './style.css';
|
||||
|
||||
function CongratListeningProgress({}: {}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const message = '';
|
||||
const [message, setMessage] = useState('');
|
||||
const [openCongratListeningProgress, setOpenCongratListeningProgress] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [count_to_prompt, setCountToPrompt] = useState(0);
|
||||
|
||||
const {
|
||||
myIonMetricGetListeningPracticeTimeSpent,
|
||||
myIonMetricGetListeningPracticeProgressIgnore,
|
||||
myIonMetricSetListeningPracticeProgressIgnore,
|
||||
} = useListeningPracticeTimeSpent();
|
||||
|
||||
const dismiss_modal = () => {
|
||||
myIonMetricSetListeningPracticeProgressIgnore(count_to_prompt);
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
async function promptListeningPracticeProgress(count_to_prompt: number) {
|
||||
if (count_to_prompt == (await myIonMetricGetListeningPracticeProgressIgnore()).time_spent_s) return;
|
||||
// setCountPrompted(count_to_prompt);
|
||||
setMessage('You scored full marks ' + count_to_prompt + ' times.');
|
||||
// setOpenedCongraFullmarkTimes(true);
|
||||
setOpened(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const prompt_list = ATTENTIVE_EARS_STAGES;
|
||||
const b_prompt_list = Array(prompt_list.length).fill(false);
|
||||
|
||||
for (let i = 0; i < prompt_list.length; i++) {
|
||||
if (progress > prompt_list[i]) {
|
||||
b_prompt_list[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let lastTrueIndex = -1;
|
||||
for (let i = b_prompt_list.length - 1; i >= 0; i--) {
|
||||
if (b_prompt_list[i]) {
|
||||
lastTrueIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTrueIndex == -1) {
|
||||
DEBUG ? console.log('prompt ignored') : '';
|
||||
} else {
|
||||
setCountToPrompt(prompt_list[lastTrueIndex]);
|
||||
promptListeningPracticeProgress(prompt_list[lastTrueIndex]);
|
||||
}
|
||||
}, [progress]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let temp = await myIonMetricGetListeningPracticeTimeSpent();
|
||||
setProgress(temp.time_spent_s / 60);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="congratulation-listening-progress-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
// 008_remove_achievement_announcement, hide congratulation modal
|
||||
isOpen={false}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
{DEBUG ? <span className={'debug'}>congratulation listening progress</span> : <></>}
|
||||
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratListeningProgress;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { COLOR_TEXT, DEBUG, MATCHMAKING_STAGES } from '../../../../constants';
|
||||
import './style.css';
|
||||
import { useMatchingFrenzyCorrectCount } from '../../../../contexts/MyIonMetric/MatchingFrenzyCorrectCount';
|
||||
|
||||
function CongratMatchmaking({}: {}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const message = '';
|
||||
const [message, setMessage] = useState('');
|
||||
const [openCongratListeningProgress, setOpenCongratListeningProgress] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [count_to_prompt, setCountToPrompt] = useState(0);
|
||||
|
||||
const {
|
||||
myIonMetricGetMatchingFrenzyCorrectCount,
|
||||
myIonMetricGetMatchingFrenzyCorrectCountIgnore,
|
||||
myIonMetricSetMatchingFrenzyCorrectCountIgnore,
|
||||
} = useMatchingFrenzyCorrectCount();
|
||||
|
||||
const dismiss_modal = () => {
|
||||
myIonMetricSetMatchingFrenzyCorrectCountIgnore(count_to_prompt);
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
async function promptProgress(count_to_prompt: number) {
|
||||
if (count_to_prompt == (await myIonMetricGetMatchingFrenzyCorrectCountIgnore()).count) return;
|
||||
// setCountPrompted(count_to_prompt);
|
||||
setMessage('You scored full marks ' + count_to_prompt + ' times.');
|
||||
// setOpenedCongraFullmarkTimes(true);
|
||||
setOpened(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const prompt_list = MATCHMAKING_STAGES;
|
||||
const b_prompt_list = Array(prompt_list.length).fill(false);
|
||||
|
||||
for (let i = 0; i < prompt_list.length; i++) {
|
||||
if (progress > prompt_list[i]) {
|
||||
b_prompt_list[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
let lastTrueIndex = -1;
|
||||
for (let i = b_prompt_list.length - 1; i >= 0; i--) {
|
||||
if (b_prompt_list[i]) {
|
||||
lastTrueIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTrueIndex == -1) {
|
||||
DEBUG ? console.log('prompt ignored') : '';
|
||||
} else {
|
||||
setCountToPrompt(prompt_list[lastTrueIndex]);
|
||||
promptProgress(prompt_list[lastTrueIndex]);
|
||||
}
|
||||
}, [progress]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let temp = await myIonMetricGetMatchingFrenzyCorrectCount();
|
||||
setProgress(temp.count);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="congratulation-listening-progress-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
// 008_remove_achievement_announcement, hide congratulation modal
|
||||
isOpen={false}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
{DEBUG ? <span className={'debug'}>congratulation matchmaking</span> : <></>}
|
||||
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratMatchmaking;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#congratulation-listening-progress-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useRef } from 'react';
|
||||
import { COLOR_TEXT } from '../../../constants';
|
||||
import { useFullmarkCount } from '../../../contexts/MyIonMetric/FullmarkCount';
|
||||
|
||||
function CongratulationAchievementModal({
|
||||
opened,
|
||||
setOpened,
|
||||
count_prompted,
|
||||
message = 'hello message',
|
||||
}: {
|
||||
message?: string;
|
||||
opened: boolean;
|
||||
count_prompted: number;
|
||||
setOpened: (opened: boolean) => void;
|
||||
}) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
|
||||
const { myIonMetricSetFullMarkIgnore } = useFullmarkCount();
|
||||
const dismiss_modal = () => {
|
||||
myIonMetricSetFullMarkIgnore(count_prompted);
|
||||
setOpened(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonModal
|
||||
id="example-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onIonModalWillDismiss={() => dismiss_modal()}
|
||||
isOpen={opened}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>{message}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => dismiss_modal()}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CongratulationAchievementModal;
|
@@ -0,0 +1,58 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useRef, useState } from 'react';
|
||||
import { COLOR_TEXT } from '../../../constants';
|
||||
|
||||
function HelloworldModal() {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
const [opened, setOpened] = useState(true);
|
||||
|
||||
return (
|
||||
<>
|
||||
<IonButton onClick={() => setOpened(true)}>Open</IonButton>
|
||||
<IonModal isOpen={opened} id="example-modal" ref={modal} trigger="open-custom-dialog">
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<h1>Congratulation!</h1>
|
||||
</div>
|
||||
|
||||
<div>{'Genius'}</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div>You scored full</div>
|
||||
<div>marks {'1000'} times!</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{ position: 'absolute', top: '5px', right: '5px' }}
|
||||
onClick={() => setOpened(false)}
|
||||
>
|
||||
<IonIcon slot="icon-only" icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default HelloworldModal;
|
@@ -0,0 +1,87 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
full_range: number;
|
||||
}
|
||||
|
||||
const MyProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, full_range }) => {
|
||||
let test_value = value;
|
||||
|
||||
let first_scale_full_range = 10;
|
||||
let first_scale = test_value > first_scale_full_range ? first_scale_full_range : test_value;
|
||||
//
|
||||
let second_scale_full_range = 50;
|
||||
let second_scale_range = second_scale_full_range - first_scale_full_range;
|
||||
let second_scale =
|
||||
test_value >= second_scale_full_range ? second_scale_full_range : Math.max(0, test_value - first_scale_full_range);
|
||||
|
||||
let third_scale_full_range = 100;
|
||||
let third_scale_range = third_scale_full_range - second_scale_full_range;
|
||||
let third_scale =
|
||||
test_value >= third_scale_full_range ? third_scale_full_range : Math.max(0, test_value - second_scale_full_range);
|
||||
let forth_scale_full_range = 300;
|
||||
let forth_scale_range = forth_scale_full_range - third_scale_full_range;
|
||||
let forth_scale =
|
||||
test_value >= forth_scale_full_range ? forth_scale_full_range : Math.max(0, test_value - third_scale_full_range);
|
||||
let fifth_scale_full_range = 700;
|
||||
let fifth_scale_range = fifth_scale_full_range - forth_scale_full_range;
|
||||
let fifth_scale =
|
||||
test_value >= fifth_scale_full_range ? fifth_scale_full_range : Math.max(0, test_value - forth_scale_full_range);
|
||||
|
||||
let sixth_scale_full_range = 1000;
|
||||
let sixth_scale_range = sixth_scale_full_range - fifth_scale_full_range;
|
||||
let sixth_scale =
|
||||
test_value >= sixth_scale_full_range ? sixth_scale_full_range : Math.max(0, test_value - fifth_scale_full_range);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||
<div style={{ width: 'calc( 100% / 6 )', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||
<div style={{ fontSize: '0.5rem' }}>{first_scale_full_range}</div>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(first_scale / first_scale_full_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ width: 'calc( 100% / 6 )', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||
<div style={{ fontSize: '0.5rem' }}>{second_scale_full_range}</div>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(second_scale / second_scale_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ width: 'calc( 100% / 6 )', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||
<div style={{ fontSize: '0.5rem' }}>{third_scale_full_range}</div>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(third_scale / third_scale_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ width: 'calc( 100% / 6 )', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||
<div style={{ fontSize: '0.5rem' }}>{forth_scale_full_range}</div>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(forth_scale / forth_scale_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ width: 'calc( 100% / 6 )', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||
<div style={{ fontSize: '0.5rem' }}>{fifth_scale_full_range}</div>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(fifth_scale / fifth_scale_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ width: 'calc( 100% / 6 )', display: 'flex', flexDirection: 'column', alignItems: 'flex-end' }}>
|
||||
<div style={{ fontSize: '0.5rem' }}>{sixth_scale_full_range}</div>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(sixth_scale / sixth_scale_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: rgb(56, 182, 255);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 0px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
/* border-radius: 12px; */
|
||||
margin-right: 0px;
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
import { FunctionComponent } from 'react';
|
||||
import './style.css';
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
value: number;
|
||||
full_range: number;
|
||||
}
|
||||
|
||||
const MyProgressBar: FunctionComponent<AudioSeekBarProps> = ({ value, full_range }) => {
|
||||
return (
|
||||
<>
|
||||
<div className={`audioSeekBar playBar_t__seek`}>
|
||||
<div style={{ width: `${(value / full_range) * 100}%` }} className="audioSeekBar__tick" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyProgressBar;
|
@@ -0,0 +1,29 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.audioSeekBar__tick {
|
||||
background-color: #999900;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.playBar_t {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 25px 50px;
|
||||
}
|
||||
|
||||
.playBar_t__seek {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
border-radius: 12px;
|
||||
margin-right: 10px;
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="649.3779"
|
||||
height="727.77798"
|
||||
viewBox="0 0 649.3779 727.77798"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
role="img"
|
||||
artist="Katerina Limpitsouni"
|
||||
source="https://undraw.co/"
|
||||
><path
|
||||
d="M648.20033,259.05824h-3.99878V149.51291A63.40187,63.40187,0,0,0,580.79976,86.111H348.713a63.40184,63.40184,0,0,0-63.402,63.4017V750.48713A63.40181,63.40181,0,0,0,348.71284,813.889H580.79945a63.40185,63.40185,0,0,0,63.402-63.40167V337.0345h3.99884Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M583.3578,102.606h-30.295a22.49485,22.49485,0,0,1-20.82715,30.99053H399.2762a22.49484,22.49484,0,0,1-20.82715-30.99061H350.15346a47.34781,47.34781,0,0,0-47.34784,47.34774V750.04628a47.34781,47.34781,0,0,0,47.34777,47.34784H583.3578a47.34781,47.34781,0,0,0,47.34784-47.34778h0V149.95371A47.34777,47.34777,0,0,0,583.3578,102.606Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
id="f3818c68-126c-4685-b4e0-2450731ccc2a-761"
|
||||
data-name="a2804879-ded6-4045-b20f-1f1dde9b938b"
|
||||
d="M611.46248,573.92982h-279.619a5.184,5.184,0,0,1-5.178-5.178v-69.361a5.184,5.184,0,0,1,5.178-5.178h279.619a5.184,5.184,0,0,1,5.178,5.178v69.362A5.184,5.184,0,0,1,611.46248,573.92982Zm-279.619-77.646a3.11,3.11,0,0,0-3.107,3.107v69.362a3.11,3.11,0,0,0,3.107,3.107h279.619a3.11,3.11,0,0,0,3.107-3.107v-69.362a3.11,3.11,0,0,0-3.107-3.107Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><circle
|
||||
id="abdb74b7-e321-430b-89c2-b563f66442fc"
|
||||
data-name="b9ad11c9-d8a0-4df6-8741-900b9ec46a35"
|
||||
cx="82.77841"
|
||||
cy="447.95985"
|
||||
r="21.74799"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="addd02b1-b85b-481a-baea-1b0ba5ed9f4a-762"
|
||||
data-name="bd261eec-7ae0-49b0-bf26-57ff03972605"
|
||||
d="M418.31746,519.57286a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.13989-7.24866l-.02087-.00033q-.05943-.001-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="a42dc2a4-5fb2-4ea8-b2b3-ce81bc256782-763"
|
||||
data-name="e80b4447-8c34-435b-ba6c-5300a190ab24"
|
||||
d="M418.31746,541.32087a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.119-7.249q-.05943-.00092-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="b84687c4-e3b4-4975-8361-bf73c33c9ee5-764"
|
||||
data-name="e55fcb7d-3a3b-45d8-b167-72fb2263dd92"
|
||||
d="M611.46248,689.91981h-279.619a5.184,5.184,0,0,1-5.178-5.178v-69.361a5.184,5.184,0,0,1,5.178-5.178h279.619a5.184,5.184,0,0,1,5.178,5.178v69.362A5.184,5.184,0,0,1,611.46248,689.91981Zm-279.619-77.646a3.11,3.11,0,0,0-3.107,3.107v69.362a3.11,3.11,0,0,0,3.107,3.107h279.619a3.11,3.11,0,0,0,3.107-3.107v-69.362a3.11,3.11,0,0,0-3.107-3.107Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><circle
|
||||
id="fe3713e7-4e14-41f8-af1d-48b338e5371c"
|
||||
data-name="a50d232f-7710-43e4-8fa9-6ef0443fc454"
|
||||
cx="82.77841"
|
||||
cy="563.94987"
|
||||
r="21.74799"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="e34cf46a-1d6c-4c41-b5e1-331fa5bf8d4c-765"
|
||||
data-name="e49b4965-a9e9-4371-9134-194e44e65c31"
|
||||
d="M418.31746,635.56288a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.119-7.249q-.05943-.001-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="e105039f-b7a6-49c8-8f81-87505f1b0ae5-766"
|
||||
data-name="abc4586a-ac92-4255-aae6-84f53baad571"
|
||||
d="M418.31746,657.31086a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.119-7.249q-.05943-.00092-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="ad9187ec-89e0-4b9d-a4fb-dc654c09bafe-767"
|
||||
data-name="a9e593af-a319-4e97-9065-f0c2c04624d5"
|
||||
d="M465.76845,429.99485a98.343,98.343,0,0,1-98.384-98.30194v-.08206c0-.206,0-.423.012-.629.3-53.879,44.432-97.756,98.372-97.756a98.384,98.384,0,0,1,.0224,196.768h-.0224Zm0-194.7a96.519,96.519,0,0,0-96.3,95.749c-.011.22-.011.4-.011.564a96.325,96.325,0,1,0,96.337-96.313h-.026Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><circle cx="315.11393" cy="422.84174" r="40" fill="#fff" /><path
|
||||
d="M586.53265,526.94884c-.06861,0-.13721-.00049-.20606-.00195h-21.5a10.39761,10.39761,0,0,1-.0083-20.79248h21.51807c.10547-.00195.22021-.00195.334,0a10.39771,10.39771,0,0,1-.13769,20.79443Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><rect x="325.3453" y="725.34374" width="324.03261" height="2.24072" fill="#3f3d56" /><path
|
||||
d="M630.6207,621.842a6.56111,6.56111,0,0,1-.62973-1.259l-5.16339-13.82657a6.50779,6.50779,0,0,1,3.81532-8.36324l115.24228-43.03187a6.50621,6.50621,0,0,1,8.363,3.81491l5.16283,13.82751a6.49951,6.49951,0,0,1-3.81558,8.36283l-115.2412,43.03174a6.5067,6.5067,0,0,1-7.73351-2.55634Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M743.51834,551.78826l-46.86323,18.68723a6,6,0,0,0-4.093,7.1996l5.43852,21.77515a6,6,0,0,0,8.37642,3.97481l46.99241-22.1188a6.0109,6.0109,0,0,0,3.52446-7.717l-5.64883-18.27558A6.01072,6.01072,0,0,0,743.51834,551.78826Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M829.28044,687.45a6.50671,6.50671,0,0,1-6.89226-4.34039l-40.114-116.289a6.49951,6.49951,0,0,1,4.02482-8.26416l13.95295-4.81352a6.50408,6.50408,0,0,1,8.26373,4.02536l40.11465,116.2899a6.50779,6.50779,0,0,1-4.02531,8.26422l-13.95257,4.8125A6.56115,6.56115,0,0,1,829.28044,687.45Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M811.5058,555.77814l15.39577,48.04524a6,6,0,0,1-2.95088,7.73816l-20.26024,9.657a6,6,0,0,1-8.39566-3.934l-12.83035-50.328a6.0109,6.0109,0,0,1,3.71178-7.62871l17.694-7.26835A6.01071,6.01071,0,0,1,811.5058,555.77814Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M764.89068,812.11413H750.13141a6.50753,6.50753,0,0,1-6.5-6.5V682.59948a6.50753,6.50753,0,0,1,6.5-6.5h14.75927a6.50753,6.50753,0,0,1,6.5,6.5V805.61413A6.50753,6.50753,0,0,1,764.89068,812.11413Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M794.08307,812.11413H779.3233a6.50753,6.50753,0,0,1-6.5-6.5V682.59948a6.50753,6.50753,0,0,1,6.5-6.5h14.75977a6.50753,6.50753,0,0,1,6.5,6.5V805.61413A6.50753,6.50753,0,0,1,794.08307,812.11413Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M806.2467,697.06158H739.1842a7.00787,7.00787,0,0,1-7-7V581.11725a40.53125,40.53125,0,0,1,81.0625,0V690.06158A7.00786,7.00786,0,0,1,806.2467,697.06158Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#ccc"
|
||||
/><path
|
||||
d="M816.34118,723.711h-34V531.55621l.6316.17236a45.38181,45.38181,0,0,1,33.3684,43.6875Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M760.32629,723.711h-34V575.41607a45.38226,45.38226,0,0,1,33.36841-43.6875l.63159-.17236Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><circle cx="486.89704" cy="378.42061" r="53.51916" fill="#6c63ff" /><path
|
||||
d="M832.71545,452.21s3-83-36-56c0,0-22.5-75.5-77.5,37.5l-16,16s72-10,139,21Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M773.02436,491.03636c-3.30591-.09179-7.42029-.20654-10.59-2.522a8.13272,8.13272,0,0,1-3.20008-6.07275,5.47091,5.47091,0,0,1,1.86035-4.49317c1.65552-1.39892,4.073-1.727,6.67823-.96142l-2.69922-19.72559,1.98144-.27148,3.17322,23.18994-1.65466-.75928c-1.91834-.87988-4.55164-1.32764-6.188.05518a3.51513,3.51513,0,0,0-1.15271,2.8955,6.14685,6.14685,0,0,0,2.38123,4.52783c2.46667,1.80176,5.74621,2.03418,9.46582,2.13819Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><rect x="459.19183" y="372.85162" width="10.77161" height="2" fill="#2f2e41" /><rect
|
||||
x="493.19183"
|
||||
y="372.85162"
|
||||
width="10.77161"
|
||||
height="2"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M652.88209,626.94393a6.00014,6.00014,0,0,1-7.96794-2.91753l-34.511-74.38406a6,6,0,0,1,10.88547-5.0504l34.511,74.38406A6.00012,6.00012,0,0,1,652.88209,626.94393Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#3f3d56"
|
||||
/><path
|
||||
d="M617.425,546.90538a4,4,0,0,1-4-4V491.95275h-50a4,4,0,0,1,0-8h54a4,4,0,0,1,4,4v54.95263A4,4,0,0,1,617.425,546.90538Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M618.371,552.55988a48,48,0,1,1,23.34031-63.74348A48.05437,48.05437,0,0,1,618.371,552.55988Zm-35.35277-76.19831a36,36,0,1,0,47.80761,17.50523A36.04072,36.04072,0,0,0,583.01827,476.36157Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#3f3d56"
|
||||
/></svg>
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,94 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useRef } from 'react';
|
||||
import MissingSvg from './image.svg';
|
||||
import './style.css';
|
||||
import { COLOR_TEXT } from '../../constants';
|
||||
|
||||
export interface NoFavoriteVocabModalProps {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
function NoFavoriteVocabModal({ open, setOpen }: NoFavoriteVocabModalProps) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
|
||||
function dismiss() {
|
||||
modal.current?.dismiss();
|
||||
}
|
||||
|
||||
return (
|
||||
<IonModal
|
||||
id="no-favorite-connectives-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
isOpen={open}
|
||||
onIonModalDidDismiss={() => setOpen(false)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: '1rem',
|
||||
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '33vw',
|
||||
width: '33vw',
|
||||
backgroundImage: `url(${MissingSvg})`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
></div>
|
||||
<div style={{ marginTop: '1rem' }}>You have currently no favorite</div>
|
||||
<div> Vocabulary</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{
|
||||
width: '1rem',
|
||||
height: '1rem',
|
||||
|
||||
position: 'absolute',
|
||||
top: '0.5rem',
|
||||
right: '0.5rem',
|
||||
}}
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<IonIcon slot={'icon-only'} icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</div>
|
||||
</IonModal>
|
||||
);
|
||||
}
|
||||
|
||||
export default NoFavoriteVocabModal;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#no-favorite-connectives-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#no-favorite-connectives-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#no-favorite-connectives-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="649.3779"
|
||||
height="727.77798"
|
||||
viewBox="0 0 649.3779 727.77798"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
role="img"
|
||||
artist="Katerina Limpitsouni"
|
||||
source="https://undraw.co/"
|
||||
><path
|
||||
d="M648.20033,259.05824h-3.99878V149.51291A63.40187,63.40187,0,0,0,580.79976,86.111H348.713a63.40184,63.40184,0,0,0-63.402,63.4017V750.48713A63.40181,63.40181,0,0,0,348.71284,813.889H580.79945a63.40185,63.40185,0,0,0,63.402-63.40167V337.0345h3.99884Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M583.3578,102.606h-30.295a22.49485,22.49485,0,0,1-20.82715,30.99053H399.2762a22.49484,22.49484,0,0,1-20.82715-30.99061H350.15346a47.34781,47.34781,0,0,0-47.34784,47.34774V750.04628a47.34781,47.34781,0,0,0,47.34777,47.34784H583.3578a47.34781,47.34781,0,0,0,47.34784-47.34778h0V149.95371A47.34777,47.34777,0,0,0,583.3578,102.606Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
id="f3818c68-126c-4685-b4e0-2450731ccc2a-761"
|
||||
data-name="a2804879-ded6-4045-b20f-1f1dde9b938b"
|
||||
d="M611.46248,573.92982h-279.619a5.184,5.184,0,0,1-5.178-5.178v-69.361a5.184,5.184,0,0,1,5.178-5.178h279.619a5.184,5.184,0,0,1,5.178,5.178v69.362A5.184,5.184,0,0,1,611.46248,573.92982Zm-279.619-77.646a3.11,3.11,0,0,0-3.107,3.107v69.362a3.11,3.11,0,0,0,3.107,3.107h279.619a3.11,3.11,0,0,0,3.107-3.107v-69.362a3.11,3.11,0,0,0-3.107-3.107Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><circle
|
||||
id="abdb74b7-e321-430b-89c2-b563f66442fc"
|
||||
data-name="b9ad11c9-d8a0-4df6-8741-900b9ec46a35"
|
||||
cx="82.77841"
|
||||
cy="447.95985"
|
||||
r="21.74799"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="addd02b1-b85b-481a-baea-1b0ba5ed9f4a-762"
|
||||
data-name="bd261eec-7ae0-49b0-bf26-57ff03972605"
|
||||
d="M418.31746,519.57286a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.13989-7.24866l-.02087-.00033q-.05943-.001-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="a42dc2a4-5fb2-4ea8-b2b3-ce81bc256782-763"
|
||||
data-name="e80b4447-8c34-435b-ba6c-5300a190ab24"
|
||||
d="M418.31746,541.32087a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.119-7.249q-.05943-.00092-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="b84687c4-e3b4-4975-8361-bf73c33c9ee5-764"
|
||||
data-name="e55fcb7d-3a3b-45d8-b167-72fb2263dd92"
|
||||
d="M611.46248,689.91981h-279.619a5.184,5.184,0,0,1-5.178-5.178v-69.361a5.184,5.184,0,0,1,5.178-5.178h279.619a5.184,5.184,0,0,1,5.178,5.178v69.362A5.184,5.184,0,0,1,611.46248,689.91981Zm-279.619-77.646a3.11,3.11,0,0,0-3.107,3.107v69.362a3.11,3.11,0,0,0,3.107,3.107h279.619a3.11,3.11,0,0,0,3.107-3.107v-69.362a3.11,3.11,0,0,0-3.107-3.107Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><circle
|
||||
id="fe3713e7-4e14-41f8-af1d-48b338e5371c"
|
||||
data-name="a50d232f-7710-43e4-8fa9-6ef0443fc454"
|
||||
cx="82.77841"
|
||||
cy="563.94987"
|
||||
r="21.74799"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="e34cf46a-1d6c-4c41-b5e1-331fa5bf8d4c-765"
|
||||
data-name="e49b4965-a9e9-4371-9134-194e44e65c31"
|
||||
d="M418.31746,635.56288a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.119-7.249q-.05943-.001-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="e105039f-b7a6-49c8-8f81-87505f1b0ae5-766"
|
||||
data-name="abc4586a-ac92-4255-aae6-84f53baad571"
|
||||
d="M418.31746,657.31086a3.625,3.625,0,0,0,0,7.249h170.878a3.625,3.625,0,0,0,.119-7.249q-.05943-.00092-.119,0Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
id="ad9187ec-89e0-4b9d-a4fb-dc654c09bafe-767"
|
||||
data-name="a9e593af-a319-4e97-9065-f0c2c04624d5"
|
||||
d="M465.76845,429.99485a98.343,98.343,0,0,1-98.384-98.30194v-.08206c0-.206,0-.423.012-.629.3-53.879,44.432-97.756,98.372-97.756a98.384,98.384,0,0,1,.0224,196.768h-.0224Zm0-194.7a96.519,96.519,0,0,0-96.3,95.749c-.011.22-.011.4-.011.564a96.325,96.325,0,1,0,96.337-96.313h-.026Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#e6e6e6"
|
||||
/><circle cx="315.11393" cy="422.84174" r="40" fill="#fff" /><path
|
||||
d="M586.53265,526.94884c-.06861,0-.13721-.00049-.20606-.00195h-21.5a10.39761,10.39761,0,0,1-.0083-20.79248h21.51807c.10547-.00195.22021-.00195.334,0a10.39771,10.39771,0,0,1-.13769,20.79443Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><rect x="325.3453" y="725.34374" width="324.03261" height="2.24072" fill="#3f3d56" /><path
|
||||
d="M630.6207,621.842a6.56111,6.56111,0,0,1-.62973-1.259l-5.16339-13.82657a6.50779,6.50779,0,0,1,3.81532-8.36324l115.24228-43.03187a6.50621,6.50621,0,0,1,8.363,3.81491l5.16283,13.82751a6.49951,6.49951,0,0,1-3.81558,8.36283l-115.2412,43.03174a6.5067,6.5067,0,0,1-7.73351-2.55634Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M743.51834,551.78826l-46.86323,18.68723a6,6,0,0,0-4.093,7.1996l5.43852,21.77515a6,6,0,0,0,8.37642,3.97481l46.99241-22.1188a6.0109,6.0109,0,0,0,3.52446-7.717l-5.64883-18.27558A6.01072,6.01072,0,0,0,743.51834,551.78826Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M829.28044,687.45a6.50671,6.50671,0,0,1-6.89226-4.34039l-40.114-116.289a6.49951,6.49951,0,0,1,4.02482-8.26416l13.95295-4.81352a6.50408,6.50408,0,0,1,8.26373,4.02536l40.11465,116.2899a6.50779,6.50779,0,0,1-4.02531,8.26422l-13.95257,4.8125A6.56115,6.56115,0,0,1,829.28044,687.45Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M811.5058,555.77814l15.39577,48.04524a6,6,0,0,1-2.95088,7.73816l-20.26024,9.657a6,6,0,0,1-8.39566-3.934l-12.83035-50.328a6.0109,6.0109,0,0,1,3.71178-7.62871l17.694-7.26835A6.01071,6.01071,0,0,1,811.5058,555.77814Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M764.89068,812.11413H750.13141a6.50753,6.50753,0,0,1-6.5-6.5V682.59948a6.50753,6.50753,0,0,1,6.5-6.5h14.75927a6.50753,6.50753,0,0,1,6.5,6.5V805.61413A6.50753,6.50753,0,0,1,764.89068,812.11413Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M794.08307,812.11413H779.3233a6.50753,6.50753,0,0,1-6.5-6.5V682.59948a6.50753,6.50753,0,0,1,6.5-6.5h14.75977a6.50753,6.50753,0,0,1,6.5,6.5V805.61413A6.50753,6.50753,0,0,1,794.08307,812.11413Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M806.2467,697.06158H739.1842a7.00787,7.00787,0,0,1-7-7V581.11725a40.53125,40.53125,0,0,1,81.0625,0V690.06158A7.00786,7.00786,0,0,1,806.2467,697.06158Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#ccc"
|
||||
/><path
|
||||
d="M816.34118,723.711h-34V531.55621l.6316.17236a45.38181,45.38181,0,0,1,33.3684,43.6875Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M760.32629,723.711h-34V575.41607a45.38226,45.38226,0,0,1,33.36841-43.6875l.63159-.17236Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><circle cx="486.89704" cy="378.42061" r="53.51916" fill="#6c63ff" /><path
|
||||
d="M832.71545,452.21s3-83-36-56c0,0-22.5-75.5-77.5,37.5l-16,16s72-10,139,21Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M773.02436,491.03636c-3.30591-.09179-7.42029-.20654-10.59-2.522a8.13272,8.13272,0,0,1-3.20008-6.07275,5.47091,5.47091,0,0,1,1.86035-4.49317c1.65552-1.39892,4.073-1.727,6.67823-.96142l-2.69922-19.72559,1.98144-.27148,3.17322,23.18994-1.65466-.75928c-1.91834-.87988-4.55164-1.32764-6.188.05518a3.51513,3.51513,0,0,0-1.15271,2.8955,6.14685,6.14685,0,0,0,2.38123,4.52783c2.46667,1.80176,5.74621,2.03418,9.46582,2.13819Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#2f2e41"
|
||||
/><rect x="459.19183" y="372.85162" width="10.77161" height="2" fill="#2f2e41" /><rect
|
||||
x="493.19183"
|
||||
y="372.85162"
|
||||
width="10.77161"
|
||||
height="2"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M652.88209,626.94393a6.00014,6.00014,0,0,1-7.96794-2.91753l-34.511-74.38406a6,6,0,0,1,10.88547-5.0504l34.511,74.38406A6.00012,6.00012,0,0,1,652.88209,626.94393Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#3f3d56"
|
||||
/><path
|
||||
d="M617.425,546.90538a4,4,0,0,1-4-4V491.95275h-50a4,4,0,0,1,0-8h54a4,4,0,0,1,4,4v54.95263A4,4,0,0,1,617.425,546.90538Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M618.371,552.55988a48,48,0,1,1,23.34031-63.74348A48.05437,48.05437,0,0,1,618.371,552.55988Zm-35.35277-76.19831a36,36,0,1,0,47.80761,17.50523A36.04072,36.04072,0,0,0,583.01827,476.36157Z"
|
||||
transform="translate(-285.31105 -86.11101)"
|
||||
fill="#3f3d56"
|
||||
/></svg>
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,95 @@
|
||||
import { IonButton, IonIcon, IonModal } from '@ionic/react';
|
||||
import { closeOutline } from 'ionicons/icons';
|
||||
import { useRef } from 'react';
|
||||
import MissingSvg from './image.svg';
|
||||
import './style.css';
|
||||
import { COLOR_TEXT } from '../../constants';
|
||||
|
||||
export interface NoFavoriteVocabModalProps {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
function NoFavoriteConnectivesModal({ open, setOpen }: NoFavoriteVocabModalProps) {
|
||||
const modal = useRef<HTMLIonModalElement>(null);
|
||||
|
||||
function dismiss() {
|
||||
modal.current?.dismiss();
|
||||
}
|
||||
|
||||
return (
|
||||
<IonModal
|
||||
id="no-favorite-vocalbulary-modal"
|
||||
ref={modal}
|
||||
trigger="open-custom-dialog"
|
||||
onWillDismiss={() => setOpen(false)}
|
||||
onIonModalDidDismiss={() => setOpen(false)}
|
||||
isOpen={open}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: '1rem',
|
||||
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '1rem',
|
||||
color: COLOR_TEXT,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '33vw',
|
||||
width: '33vw',
|
||||
backgroundImage: `url(${MissingSvg})`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
></div>
|
||||
<div style={{ marginTop: '1rem' }}>You have currently no favorite</div>
|
||||
<div>Connectives</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<IonButton
|
||||
color="light"
|
||||
shape="round"
|
||||
style={{
|
||||
width: '1rem',
|
||||
height: '1rem',
|
||||
|
||||
position: 'absolute',
|
||||
top: '0.5rem',
|
||||
right: '0.5rem',
|
||||
}}
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<IonIcon slot={'icon-only'} icon={closeOutline}></IonIcon>
|
||||
</IonButton>
|
||||
</div>
|
||||
</IonModal>
|
||||
);
|
||||
}
|
||||
|
||||
export default NoFavoriteConnectivesModal;
|
@@ -0,0 +1,21 @@
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ion-modal#no-favorite-vocalbulary-modal {
|
||||
--height: 33%;
|
||||
--width: 80%;
|
||||
--border-radius: 16px;
|
||||
--box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
ion-modal#no-favorite-vocalbulary-modal::part(backdrop) {
|
||||
/* background: rgba(209, 213, 219); */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-modal#no-favorite-vocalbulary-modal ion-toolbar {
|
||||
/* --background: rgb(14 116 144); */
|
||||
/* --color: white; */
|
||||
--color: black;
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
import { checkmarkOutline } from 'ionicons/icons';
|
||||
import './style.css';
|
||||
import { IonButton, IonIcon } from '@ionic/react';
|
||||
|
||||
interface ContainerProps {
|
||||
num_rating: number;
|
||||
num_full_rating: number;
|
||||
}
|
||||
|
||||
const QuestionProgress: React.FC<ContainerProps> = ({ num_rating = 0, num_full_rating = 2 }) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '0.15rem' }}>
|
||||
{Array.from({ length: num_rating }, (_, index) => (
|
||||
<IonButton shape="round" fill="outline" size="small" color="success">
|
||||
<IonIcon slot="icon-only" icon={checkmarkOutline}></IonIcon>
|
||||
</IonButton>
|
||||
))}
|
||||
{Array.from({ length: num_full_rating - num_rating }, (_, index) => (
|
||||
<IonButton shape="round" fill="outline" size="small" color="medium">
|
||||
<IonIcon slot="icon-only"></IonIcon>
|
||||
</IonButton>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuestionProgress;
|
@@ -0,0 +1,3 @@
|
||||
.quizzes_main_menu_container {
|
||||
text-align: center;
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
import { IonButton, useIonRouter } from '@ionic/react';
|
||||
import './QuizzesMainMenuContainer.css';
|
||||
import { COLOR_TEXT, CONNECTIVE_REVISION_LINK, LISTENING_PRACTICE_LINK, MATCHING_FRENZY_LINK } from '../constants';
|
||||
|
||||
interface ContainerProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const QuizzesMainMenuContainer: React.FC<ContainerProps> = ({ name }) => {
|
||||
const router = useIonRouter();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="quizzes_main_menu_container"
|
||||
style={{
|
||||
display: 'column',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<div style={{ margin: '1rem 1rem' }}>
|
||||
<IonButton
|
||||
expand="block"
|
||||
// href={LISTENING_PRACTICE_LINK}
|
||||
onClick={() => {
|
||||
router.push(LISTENING_PRACTICE_LINK, undefined, 'replace');
|
||||
}}
|
||||
fill="clear"
|
||||
>
|
||||
<div style={{ padding: '1rem' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '60vw',
|
||||
height: '30vw',
|
||||
backgroundImage: `url('/data/Lesson/images/quiz_listening_practice.jpg')`,
|
||||
backgroundSize: 'cover',
|
||||
borderRadius: '1rem',
|
||||
}}
|
||||
></div>
|
||||
<div style={{ marginTop: '2rem', color: COLOR_TEXT }}>Listening Practice</div>
|
||||
</div>
|
||||
</IonButton>
|
||||
</div>
|
||||
<div style={{ margin: '1rem 1rem' }}>
|
||||
<IonButton
|
||||
expand="block"
|
||||
// href={MATCHING_FRENZY_LINK}
|
||||
onClick={() => {
|
||||
router.push(MATCHING_FRENZY_LINK, undefined, 'replace');
|
||||
}}
|
||||
fill="clear"
|
||||
>
|
||||
<div style={{ padding: '1rem' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '60vw',
|
||||
height: '30vw',
|
||||
backgroundImage: `url('/data/Lesson/images/quiz_matching_frenzy.jpg')`,
|
||||
backgroundSize: 'cover',
|
||||
borderRadius: '1rem',
|
||||
}}
|
||||
></div>
|
||||
<div style={{ marginTop: '0.5rem', color: COLOR_TEXT }}>Matching Frenzy</div>
|
||||
</div>
|
||||
</IonButton>
|
||||
</div>
|
||||
<div style={{ margin: '1rem 1rem' }}>
|
||||
<IonButton
|
||||
expand="block"
|
||||
// href={CONNECTIVE_REVISION_LINK}
|
||||
onClick={() => {
|
||||
router.push(CONNECTIVE_REVISION_LINK, undefined, 'replace');
|
||||
}}
|
||||
fill="clear"
|
||||
>
|
||||
<div style={{ padding: '1rem' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '60vw',
|
||||
height: '30vw',
|
||||
backgroundImage: `url('/data/Lesson/images/quiz_connectives_revision.jpg')`,
|
||||
backgroundSize: 'cover',
|
||||
borderRadius: '1rem',
|
||||
}}
|
||||
></div>
|
||||
<div style={{ marginTop: '0.5rem', color: COLOR_TEXT }}>Connectives Revision</div>
|
||||
</div>
|
||||
</IonButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuizzesMainMenuContainer;
|
@@ -0,0 +1,24 @@
|
||||
import { IonToast } from '@ionic/react';
|
||||
import React from 'react';
|
||||
import './style.css';
|
||||
import { THE_WORD_REMOVED, THE_WORD_REMOVED_DISMISS_TIMEOUT } from '../../constants';
|
||||
|
||||
const RemoveFavoritePrompt: React.FC<{ open: boolean; setIsOpen: (isOpen: boolean) => void }> = ({
|
||||
open,
|
||||
setIsOpen,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<IonToast
|
||||
className="remove-favorite-prompt-toast"
|
||||
isOpen={open}
|
||||
message={THE_WORD_REMOVED}
|
||||
onDidDismiss={() => setIsOpen(false)}
|
||||
color="success"
|
||||
duration={THE_WORD_REMOVED_DISMISS_TIMEOUT}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RemoveFavoritePrompt;
|
@@ -0,0 +1,11 @@
|
||||
ion-toast.remove-favorite-prompt-toast::part(message) {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
/*
|
||||
ion-toast.remove-favorite-prompt-toast::part(container) {
|
||||
bottom: 100px;
|
||||
}
|
||||
*/
|
24
002_source/ionic_mobile/src/components/SettingContainer.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.container strong {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.container p {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container a {
|
||||
text-decoration: none;
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="845.87074"
|
||||
height="569.98927"
|
||||
viewBox="0 0 845.87074 569.98927"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
role="img"
|
||||
artist="Katerina Limpitsouni"
|
||||
source="https://undraw.co/"
|
||||
><polygon
|
||||
points="760.114 287.832 752.997 294.857 762.452 319.527 775.643 292.177 797.249 168.007 764.02 167.081 760.114 287.832"
|
||||
fill="#9f616a"
|
||||
/><polygon
|
||||
points="705.966 547.714 687.966 547.714 673.966 388.714 708.966 388.714 705.966 547.714"
|
||||
fill="#9f616a"
|
||||
/><polygon
|
||||
points="773.966 547.714 755.966 547.714 741.966 388.714 776.966 388.714 773.966 547.714"
|
||||
fill="#9f616a"
|
||||
/><path
|
||||
d="M937.09032,733.461l-26.27966-.13983a10.60246,10.60246,0,0,1-5.18583-13.20591h0a10.60249,10.60249,0,0,1,8.18437-6.73544l4.96424-.82737,4.32555-5.50525a8.19029,8.19029,0,0,1,10.758-2.00034c4.14944,2.63357,9.90449,3.511,17,2.92223l5.52291,13.4861c1.09439,7.29591-3.90074,12.10883-11.188,13.25945h0A13.43132,13.43132,0,0,1,937.09032,733.461Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M869.09032,733.461l-26.27966-.13983a10.60246,10.60246,0,0,1-5.18583-13.20591h0a10.60249,10.60249,0,0,1,8.18437-6.73544l4.96424-.82737,4.80952-6.12121a7.45937,7.45937,0,0,1,10.01669-1.55131c4.16748,2.7633,10.01393,3.69017,17.25728,3.08916l5.52291,13.4861c1.09439,7.29591-3.90074,12.10883-11.188,13.25945h0A13.43132,13.43132,0,0,1,869.09032,733.461Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#2f2e41"
|
||||
/><circle cx="710.9656" cy="55.71363" r="27" fill="#9f616a" /><path
|
||||
d="M927.03023,272.719l-44,3c.15576-14.2391-.46558-27.13579-4-35l31-10C910.3279,243.25667,916.90486,257.50461,927.03023,272.719Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#9f616a"
|
||||
/><path
|
||||
d="M954.03023,467.719l-113-9c15.0769-50.26016,10.35876-116.07391-5-165.41577a28.4717,28.4717,0,0,1,18.28887-26.58848L883.03023,255.719l36,4,30.356,15.178a27.71585,27.71585,0,0,1,15.31608,25.30937C953.29231,345.83844,951.91774,404.51285,954.03023,467.719Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M869.03023,344.719l-51-9L822.42,301.69848a42.20258,42.20258,0,0,1,30.84455-35.34011l9.76571-2.63938Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><polygon
|
||||
points="661.966 292.714 667.966 300.714 658.966 325.714 645.966 294.714 642.966 168.714 675.966 172.714 661.966 292.714"
|
||||
fill="#9f616a"
|
||||
/><path
|
||||
d="M925.03023,346.719l51-9-4.38975-34.02051a42.20256,42.20256,0,0,0-30.84455-35.34011l-9.7657-2.63938Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M957.03023,558.719l-41.83858,2-12.16142-59-14.76772,55-44.23228,1-8.8417-71.06584a41.09716,41.09716,0,0,1,8.84169-30.93414v0l110,5Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#2f2e41"
|
||||
/><path
|
||||
d="M890.53023,250.219l20.19008-3.82345,12.0114-20.51949a27.28013,27.28013,0,0,0-3.19387-31.95038l0,0a27.28016,27.28016,0,0,0-24.2073-8.837l-26.16686,3.73812a17.27884,17.27884,0,0,0-14.64408,19.66833l17.62513,2.99868Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#2f2e41"
|
||||
/><ellipse cx="701.4656" cy="63.21363" rx="5" ry="6" fill="#9f616a" /><path
|
||||
d="M303.53023,177.219a11.01245,11.01245,0,0,0-11,11v201a11.01245,11.01245,0,0,0,11,11h5a11.01245,11.01245,0,0,0,11-11v-201a11.01245,11.01245,0,0,0-11-11Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M303.53023,181.719a6.50753,6.50753,0,0,0-6.5,6.5v201a6.50752,6.50752,0,0,0,6.5,6.5h5a6.50753,6.50753,0,0,0,6.5-6.5v-201a6.50753,6.50753,0,0,0-6.5-6.5Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
d="M385.53023,177.219a11.01245,11.01245,0,0,0-11,11v201a11.01245,11.01245,0,0,0,11,11h5a11.01245,11.01245,0,0,0,11-11v-201a11.01245,11.01245,0,0,0-11-11Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M385.53023,181.719a6.50753,6.50753,0,0,0-6.5,6.5v201a6.50752,6.50752,0,0,0,6.5,6.5h5a6.50753,6.50753,0,0,0,6.5-6.5v-201a6.50753,6.50753,0,0,0-6.5-6.5Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
d="M467.53023,177.219a11.01245,11.01245,0,0,0-11,11v201a11.01245,11.01245,0,0,0,11,11h5a11.01245,11.01245,0,0,0,11-11v-201a11.01245,11.01245,0,0,0-11-11Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M467.53023,181.719a6.50753,6.50753,0,0,0-6.5,6.5v201a6.50752,6.50752,0,0,0,6.5,6.5h5a6.50753,6.50753,0,0,0,6.5-6.5v-201a6.50753,6.50753,0,0,0-6.5-6.5Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
d="M549.53023,177.219a11.01245,11.01245,0,0,0-11,11v201a11.01245,11.01245,0,0,0,11,11h5a11.01245,11.01245,0,0,0,11-11v-201a11.01245,11.01245,0,0,0-11-11Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M549.53023,181.719a6.50753,6.50753,0,0,0-6.5,6.5v201a6.50752,6.50752,0,0,0,6.5,6.5h5a6.50753,6.50753,0,0,0,6.5-6.5v-201a6.50753,6.50753,0,0,0-6.5-6.5Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
d="M631.53023,177.219a11.01245,11.01245,0,0,0-11,11v201a11.01245,11.01245,0,0,0,11,11h5a11.01245,11.01245,0,0,0,11-11v-201a11.01245,11.01245,0,0,0-11-11Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M631.53023,181.719a6.50753,6.50753,0,0,0-6.5,6.5v201a6.50752,6.50752,0,0,0,6.5,6.5h5a6.50753,6.50753,0,0,0,6.5-6.5v-201a6.50753,6.50753,0,0,0-6.5-6.5Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
d="M322.2878,242.2493H290.77265a10.25379,10.25379,0,0,1-10.24242-10.24243v-1.57576a10.25379,10.25379,0,0,1,10.24242-10.24242H322.2878a10.25379,10.25379,0,0,1,10.24243,10.24242v1.57576A10.25379,10.25379,0,0,1,322.2878,242.2493Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M406.2878,275.2493H374.77265a10.25379,10.25379,0,0,1-10.24242-10.24243v-1.57576a10.25379,10.25379,0,0,1,10.24242-10.24242H406.2878a10.25379,10.25379,0,0,1,10.24243,10.24242v1.57576A10.25379,10.25379,0,0,1,406.2878,275.2493Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M486.2878,340.2493H454.77265a10.25379,10.25379,0,0,1-10.24242-10.24243v-1.57576a10.25379,10.25379,0,0,1,10.24242-10.24242H486.2878a10.25379,10.25379,0,0,1,10.24243,10.24242v1.57576A10.25379,10.25379,0,0,1,486.2878,340.2493Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M568.2878,222.2493H536.77265a10.25379,10.25379,0,0,1-10.24242-10.24243v-1.57576a10.25379,10.25379,0,0,1,10.24242-10.24242H568.2878a10.25379,10.25379,0,0,1,10.24243,10.24242v1.57576A10.25379,10.25379,0,0,1,568.2878,222.2493Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M650.2878,300.2493H618.77265a10.25379,10.25379,0,0,1-10.24242-10.24243v-1.57576a10.25379,10.25379,0,0,1,10.24242-10.24242H650.2878a10.25379,10.25379,0,0,1,10.24243,10.24242v1.57576A10.25379,10.25379,0,0,1,650.2878,300.2493Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/><polygon
|
||||
points="845.475 569.989 578.074 569.989 578.074 567.804 845.871 567.804 845.475 569.989"
|
||||
fill="#3f3d56"
|
||||
/><circle cx="129.4656" cy="275.21363" r="13" fill="#e6e6e6" /><circle
|
||||
cx="211.4656"
|
||||
cy="275.21363"
|
||||
r="13"
|
||||
fill="#e6e6e6"
|
||||
/><circle cx="293.4656" cy="275.21363" r="13" fill="#e6e6e6" /><circle
|
||||
cx="375.4656"
|
||||
cy="275.21363"
|
||||
r="13"
|
||||
fill="#e6e6e6"
|
||||
/><circle cx="457.4656" cy="275.21363" r="13" fill="#e6e6e6" /><path
|
||||
d="M205.86092,165.00536a28.79631,28.79631,0,1,0,28.79632,28.79629A28.79629,28.79629,0,0,0,205.86092,165.00536Zm0,53.33839a24.54208,24.54208,0,1,1,24.5421-24.5421A24.54208,24.54208,0,0,1,205.86092,218.34375Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#e6e6e6"
|
||||
/><path
|
||||
d="M204.26992,203.64975a1.51846,1.51846,0,0,1-1.07424-.44513L194.99111,195a1.5192,1.5192,0,0,1,2.14848-2.14847l6.95228,6.95228,12.32319-16.80442a1.51945,1.51945,0,0,1,2.45057,1.79712l-13.37042,18.23239a1.52072,1.52072,0,0,1-1.10955.61665C204.34708,203.64856,204.3082,203.64975,204.26992,203.64975Z"
|
||||
transform="translate(-177.06463 -165.00536)"
|
||||
fill="#6c63ff"
|
||||
/></svg>
|
After Width: | Height: | Size: 8.1 KiB |
@@ -0,0 +1,50 @@
|
||||
import { IonButton, IonIcon, useIonRouter } from '@ionic/react';
|
||||
import { arrowBack } from 'ionicons/icons';
|
||||
import { LESSON_LINK, VERSIONS } from '../../constants';
|
||||
import SettingSvg from './image.svg';
|
||||
|
||||
interface ContainerProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const SettingContainer: React.FC<ContainerProps> = ({ name }) => {
|
||||
const router = useIonRouter();
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '85%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: `url(${SettingSvg})`,
|
||||
height: '33vh',
|
||||
width: '33vh',
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
></div>
|
||||
<div>
|
||||
<p>T.B.A.</p>
|
||||
</div>
|
||||
<div>{VERSIONS}</div>
|
||||
<IonButton
|
||||
onClick={() => {
|
||||
router.push(LESSON_LINK, undefined, 'replace');
|
||||
}}
|
||||
style={{ marginTop: '1rem' }}
|
||||
>
|
||||
<IonIcon slot="start" icon={arrowBack}></IonIcon>
|
||||
Back
|
||||
</IonButton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingContainer;
|
BIN
002_source/ionic_mobile/src/components/SpeakerImage/image.jpg
Normal file
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,90 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="863.91732"
|
||||
height="364.20537"
|
||||
viewBox="0 0 863.91732 364.20537"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
role="img"
|
||||
artist="Katerina Limpitsouni"
|
||||
source="https://undraw.co/"
|
||||
><polygon
|
||||
points="311.959 119.745 0 119.745 0 222.156 11.817 222.156 11.817 248.941 38.601 222.156 311.959 222.156 311.959 119.745"
|
||||
fill="#f0f0f0"
|
||||
/><rect x="8.66553" y="129.71814" width="294.62811" height="81.92868" fill="#fff" /><rect
|
||||
x="34.72148"
|
||||
y="154.42552"
|
||||
width="141.85589"
|
||||
height="4.30497"
|
||||
fill="#f0f0f0"
|
||||
/><rect x="34.72148" y="169.31777" width="247.24292" height="4.30497" fill="#f0f0f0" /><rect
|
||||
x="34.72148"
|
||||
y="184.21003"
|
||||
width="247.00081"
|
||||
height="4.30497"
|
||||
fill="#f0f0f0"
|
||||
/><path
|
||||
d="M692.07274,618.96676s1.487-31.15875,31.97119-27.537"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#f0f0f0"
|
||||
/><circle cx="515.41796" cy="306.16087" r="15.2571" fill="#f0f0f0" /><rect
|
||||
x="512.9354"
|
||||
y="331.85294"
|
||||
width="4.30672"
|
||||
height="30.14703"
|
||||
fill="#f0f0f0"
|
||||
/><circle cx="666.92952" cy="180.07338" r="123.29665" fill="#3f3d56" /><path
|
||||
d="M757.348,457.86815a32.62688,32.62688,0,0,1,50.081,0,36.26372,36.26372,0,1,0-51.27085-1.18987Q756.73918,457.28694,757.348,457.86815Z"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#fff"
|
||||
/><path
|
||||
d="M855.26,457.86815a32.627,32.627,0,0,1,50.08092,0,36.26371,36.26371,0,1,0-51.2708-1.18987Q854.65117,457.28694,855.26,457.86815Z"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#fff"
|
||||
/><circle cx="601.97649" cy="151.39215" r="12.47434" fill="#3f3d56" /><circle
|
||||
cx="699.88499"
|
||||
cy="151.39215"
|
||||
r="12.47434"
|
||||
fill="#3f3d56"
|
||||
/><circle cx="578.08341" cy="210.89752" r="14.50548" fill="#6c63ff" /><circle
|
||||
cx="744.8965"
|
||||
cy="210.89752"
|
||||
r="14.5055"
|
||||
fill="#6c63ff"
|
||||
/><polygon points="661.49 181.886 650.611 229.029 668.742 210.898 661.49 181.886" fill="#6c63ff" /><polygon
|
||||
points="717.39 363.205 705.038 352.839 705.326 363.205 701.49 363.205 701.183 352.244 684.507 363.205 677.526 363.205 701.059 347.737 700.147 315.258 699.466 290.728 703.293 290.623 703.984 315.258 704.894 347.708 723.354 363.205 717.39 363.205"
|
||||
fill="#3f3d56"
|
||||
/><polygon
|
||||
points="659.363 363.205 647.012 352.839 647.3 363.205 643.474 363.205 643.167 352.244 626.49 363.205 619.509 363.205 643.033 347.737 642.122 315.258 641.441 290.728 645.276 290.623 645.967 315.258 646.868 347.708 665.328 363.205 659.363 363.205"
|
||||
fill="#3f3d56"
|
||||
/><path
|
||||
d="M836.784,315.60813c-3.3831,0-6.36764,2.628-8.36294,6.66445-1.75872-6.06969-5.45374-10.29078-9.7689-10.29078a6.56326,6.56326,0,0,0-.87094.1463c-1.65871-6.4805-5.51368-11.02542-10.00816-11.02542-6.00841,0-10.8791,8.118-10.8791,18.13187s4.87073,18.13187,10.8791,18.13187a6.56119,6.56119,0,0,0,.87093-.14629c1.65871,6.4805,5.51369,11.02541,10.00817,11.02541,3.3831,0,6.36764-2.62795,8.36294-6.66444,1.75876,6.06971,5.45374,10.29077,9.7689,10.29077,6.00841,0,10.8791-8.118,10.8791-18.13187S842.79244,315.60813,836.784,315.60813Z"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#3f3d56"
|
||||
/><path
|
||||
d="M718.72328,451.807l-67.92039-11.01653c-3.42269-.55515-6.90789-1.11141-10.34147-.6282s-6.87069,2.1737-8.62107,5.16688a8.651,8.651,0,0,0,9.14985,12.853c-3.70741-.12023-7.60411-.19978-10.894,1.51369s-5.61946,5.87559-4.01553,9.22024a8.27667,8.27667,0,0,0,1.91922,2.4289,17.60582,17.60582,0,0,0,18.52289,3.14128c-2.50047,3.58582-7.46212,4.11838-11.7541,4.94866s-9.25362,3.258-9.41312,7.62664c-.17922,4.90869,5.66264,7.51763,10.47189,8.51687A137.41687,137.41687,0,0,0,712.648,489.3171a30.98,30.98,0,0,0,7.737-3.95049,17.43266,17.43266,0,0,0-7.05356-30.96345"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#3f3d56"
|
||||
/><path
|
||||
d="M1011.89005,507.47917a137.41884,137.41884,0,0,0-51.17256-57.63676,30.97519,30.97519,0,0,0-7.80737-3.80966,17.43272,17.43272,0,0,0-20.50879,24.24615l-5.31525-2.74921Q943.09323,497.98314,959.1,528.43656c1.61312,3.06929,3.26318,6.18918,5.71292,8.64309s5.86648,4.18514,9.31075,3.78525a8.6006,8.6006,0,0,0,6.77916-12.2999,16.64264,16.64264,0,0,0,5.752,5.05979c3.34648,1.59972,8.07321.9603,9.7823-2.33177a8.27455,8.27455,0,0,0,.78809-2.99368,17.60592,17.60592,0,0,0-8.62117-16.69248c4.36853-.1565,7.77622,3.48909,11.01912,6.42052,3.24327,2.93143,8.1652,5.43808,11.75289,2.94008C1015.40712,518.16062,1013.98161,511.92354,1011.89005,507.47917Z"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#3f3d56"
|
||||
/><polygon
|
||||
points="55.757 0 506 0 506 147.807 488.945 147.807 488.945 186.463 450.289 147.807 55.757 147.807 55.757 0"
|
||||
fill="#cacaca"
|
||||
/><rect x="68.26381" y="14.39335" width="425.22943" height="118.24561" fill="#fff" /><rect
|
||||
x="102.45877"
|
||||
y="48.91591"
|
||||
width="204.73707"
|
||||
height="6.21326"
|
||||
fill="#6c63ff"
|
||||
/><rect x="102.45877" y="70.40954" width="356.83952" height="6.21326" fill="#6c63ff" /><rect
|
||||
x="102.45877"
|
||||
y="91.90316"
|
||||
width="356.49009"
|
||||
height="6.21326"
|
||||
fill="#6c63ff"
|
||||
/><path
|
||||
d="M1030.95866,632.10268h-381a1,1,0,0,1,0-2h381a1,1,0,0,1,0,2Z"
|
||||
transform="translate(-168.04134 -267.89732)"
|
||||
fill="#cacaca"
|
||||
/></svg>
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,18 @@
|
||||
import ImageSvg from './image.svg';
|
||||
|
||||
function SpeakerImage() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundImage: `url(${ImageSvg})`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
export { SpeakerImage };
|
@@ -0,0 +1,44 @@
|
||||
import { IonToast } from '@ionic/react';
|
||||
import { WRONG_ANSWER_MESSAGE } from '../../constants';
|
||||
import './style.css';
|
||||
import { useAppStateContext } from '../../contexts/AppState';
|
||||
|
||||
interface QuestionCardProps {
|
||||
isOpen: boolean;
|
||||
dismiss: () => void;
|
||||
correct_answer?: string;
|
||||
}
|
||||
|
||||
const WrongAnswerToast: React.FC<QuestionCardProps> = ({ isOpen, dismiss, correct_answer = '' }) => {
|
||||
const { WRONG_ANS_TOAST_APPEAR_TIMEOUT_S } = useAppStateContext();
|
||||
|
||||
if (correct_answer != '') {
|
||||
return (
|
||||
<>
|
||||
<IonToast
|
||||
className="wrong-answer-toast"
|
||||
isOpen={isOpen}
|
||||
message={`${WRONG_ANSWER_MESSAGE}. The correct answer is "${correct_answer}"`}
|
||||
onDidDismiss={() => dismiss()}
|
||||
duration={WRONG_ANS_TOAST_APPEAR_TIMEOUT_S * 1000}
|
||||
color="danger"
|
||||
></IonToast>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<IonToast
|
||||
className="wrong-answer-toast"
|
||||
isOpen={isOpen}
|
||||
message={`${WRONG_ANSWER_MESSAGE}`}
|
||||
onDidDismiss={() => dismiss()}
|
||||
duration={WRONG_ANS_TOAST_APPEAR_TIMEOUT_S * 1000}
|
||||
color="danger"
|
||||
></IonToast>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default WrongAnswerToast;
|
@@ -0,0 +1,10 @@
|
||||
ion-toast.wrong-answer-toast::part(message) {
|
||||
/* text-align: center; */
|
||||
font-size: 1.5rem;
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
ion-toast.wrong-answer-toast::part(container) {
|
||||
bottom: 100px;
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
import { IonToast } from '@ionic/react';
|
||||
import { WRONG_ANSWER_MESSAGE } from '../../constants';
|
||||
import './style.css';
|
||||
import { useAppStateContext } from '../../contexts/AppState';
|
||||
|
||||
interface QuestionCardProps {
|
||||
isOpen: boolean;
|
||||
dismiss: () => void;
|
||||
correct_answer: string;
|
||||
}
|
||||
|
||||
const WrongAnswerToastWithoutCorrectAnswer: React.FC<QuestionCardProps> = ({
|
||||
isOpen,
|
||||
dismiss,
|
||||
correct_answer = '',
|
||||
}) => {
|
||||
const { WRONG_ANS_TOAST_APPEAR_TIMEOUT_S } = useAppStateContext();
|
||||
|
||||
if (correct_answer != '') {
|
||||
return (
|
||||
<>
|
||||
<IonToast
|
||||
className="wrong-answer-toast"
|
||||
isOpen={isOpen}
|
||||
message={`${WRONG_ANSWER_MESSAGE}. The correct answer is "${correct_answer}"`}
|
||||
onDidDismiss={() => dismiss()}
|
||||
duration={WRONG_ANS_TOAST_APPEAR_TIMEOUT_S * 1000}
|
||||
color="danger"
|
||||
></IonToast>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<IonToast
|
||||
className="wrong-answer-toast"
|
||||
isOpen={isOpen}
|
||||
message={`${WRONG_ANSWER_MESSAGE}`}
|
||||
onDidDismiss={() => dismiss()}
|
||||
duration={WRONG_ANS_TOAST_APPEAR_TIMEOUT_S * 1000}
|
||||
color="danger"
|
||||
></IonToast>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default WrongAnswerToastWithoutCorrectAnswer;
|
@@ -0,0 +1,10 @@
|
||||
ion-toast.wrong-answer-toast::part(message) {
|
||||
/* text-align: center; */
|
||||
font-size: 1.5rem;
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
ion-toast.wrong-answer-toast::part(container) {
|
||||
bottom: 100px;
|
||||
}
|