Finished Speaking UI
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
|
||||
const CharacterBadge = ({ name, image, onClick }: { name: string, image: string, onClick: () => void }) => (
|
||||
<div className="character" onClick={onClick}>
|
||||
<img src={image} alt={name} />
|
||||
<p>{name}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default CharacterBadge;
|
||||
@@ -8,7 +8,7 @@ interface ProgressProps {
|
||||
|
||||
export default function Progress({percent, back}: ProgressProps) {
|
||||
return <div className="flex gap-2 items-center">
|
||||
{back != null && <Icon icon="mdi:arrow-left" className="text-gray-400 text-2xl" onClick={back}/>}
|
||||
{back != null && <Icon icon="mdi:arrow-left" className="back-button" onClick={back}/>}
|
||||
<div className="relative bg-gray-200 h-4 rounded-xl flex-1">
|
||||
{percent > 0 && <div className="absolute bg-green h-4 rounded-xl" style={{width: `${percent}%`}}></div>}
|
||||
</div>
|
||||
|
||||
@@ -133,3 +133,55 @@ h1
|
||||
|
||||
&.active
|
||||
color: $c-green
|
||||
|
||||
.character
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
gap: 1em
|
||||
|
||||
img
|
||||
width: 150px
|
||||
height: 150px
|
||||
border-radius: 50%
|
||||
object-fit: cover
|
||||
background: $c-green
|
||||
|
||||
p
|
||||
font-size: 0.9em
|
||||
font-weight: 800
|
||||
|
||||
.back-button
|
||||
color: #a0aec0
|
||||
font-size: 1.5rem
|
||||
|
||||
.record-btn
|
||||
position: fixed
|
||||
bottom: 20px
|
||||
left: 50%
|
||||
transform: translateX(-50%)
|
||||
width: calc(100% - 40px)
|
||||
padding: 10px 16px
|
||||
|
||||
.chat-area
|
||||
display: flex
|
||||
flex-direction: column
|
||||
width: 100%
|
||||
max-width: 600px
|
||||
margin: 20px auto
|
||||
|
||||
.message
|
||||
margin: 10px
|
||||
padding: 10px
|
||||
border-radius: 5px
|
||||
color: white
|
||||
|
||||
.message.me
|
||||
align-self: flex-end
|
||||
background-color: $c-blue
|
||||
border-radius: 20px 0 20px 20px
|
||||
|
||||
.message.other
|
||||
align-self: flex-start
|
||||
background-color: $c-green
|
||||
border-radius: 0 20px 20px 20px
|
||||
@@ -10,7 +10,8 @@ import Course from "./pages/Course";
|
||||
import Profile from "./pages/Profile";
|
||||
import CollabLearning from './pages/CollabLearning';
|
||||
import Review from './pages/Review';
|
||||
import Speaking from './pages/Speaking';
|
||||
import CharacterSelection from './pages/CharacterSelection';
|
||||
import Character from './pages/Character';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -39,12 +40,16 @@ const router = createBrowserRouter([
|
||||
},
|
||||
{
|
||||
path: '/speaking',
|
||||
element: <Speaking/>
|
||||
element: <CharacterSelection/>
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
element: <Profile/>
|
||||
},
|
||||
{
|
||||
path: '/character',
|
||||
element: <Character/>
|
||||
}
|
||||
])
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { Icon } from '@iconify/react';
|
||||
import CharacterBadge from '../components/CharacterBadge';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function Character() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { name, image } = location.state;
|
||||
|
||||
const [messages, setMessages] = useState([
|
||||
{ text: 'Hello!', sender: 'me' },
|
||||
{ text: 'Hi!', sender: 'other' },
|
||||
// Add more messages here
|
||||
]);
|
||||
|
||||
function handleRecord() {
|
||||
// handle the recording
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="v-layout p-10">
|
||||
<Icon icon="mdi:arrow-left" className="back-button" onClick={() => navigate(-1)} />
|
||||
<h1 className="text-center">Talk With...</h1>
|
||||
<CharacterBadge name={name} image={image} onClick={() => {}}/>
|
||||
<div className="chat-area">
|
||||
{messages.map((message, index) => (
|
||||
<div key={index} className={`message ${message.sender}`}>
|
||||
<p>{message.text}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="record-btn" onClick={handleRecord}>Record</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import NavBar from "../components/NavBar"
|
||||
import Ash from "../assets/img/ash.png"
|
||||
import C3PO from "../assets/img/c3po.png"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import CharacterBadge from "../components/CharacterBadge"
|
||||
|
||||
export default function CharacterSelection() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const characters = [
|
||||
{ name: 'Ash', image: Ash },
|
||||
{ name: 'C3PO', image: C3PO },
|
||||
// Add more characters here
|
||||
];
|
||||
|
||||
const handleCharacterClick = (characterName: string, characterImage: string) => {
|
||||
navigate('/character', { state: { name: characterName, image: characterImage } });
|
||||
}
|
||||
|
||||
return (
|
||||
<div >
|
||||
<div className="v-layout p-10">
|
||||
<h1 className="text-center">Talk With...</h1>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{characters.map(character => (
|
||||
<CharacterBadge
|
||||
key={character.name}
|
||||
name={character.name}
|
||||
image={character.image}
|
||||
onClick={() => handleCharacterClick(character.name, character.image)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<NavBar />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import NavBar from "../components/NavBar"
|
||||
|
||||
export default function Speaking() {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen">
|
||||
<div className="flex flex-col flex-1">
|
||||
<h1>Speaking Page</h1>
|
||||
</div>
|
||||
<NavBar />
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user