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) {
|
export default function Progress({percent, back}: ProgressProps) {
|
||||||
return <div className="flex gap-2 items-center">
|
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">
|
<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>}
|
{percent > 0 && <div className="absolute bg-green h-4 rounded-xl" style={{width: `${percent}%`}}></div>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -133,3 +133,55 @@ h1
|
|||||||
|
|
||||||
&.active
|
&.active
|
||||||
color: $c-green
|
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 Profile from "./pages/Profile";
|
||||||
import CollabLearning from './pages/CollabLearning';
|
import CollabLearning from './pages/CollabLearning';
|
||||||
import Review from './pages/Review';
|
import Review from './pages/Review';
|
||||||
import Speaking from './pages/Speaking';
|
import CharacterSelection from './pages/CharacterSelection';
|
||||||
|
import Character from './pages/Character';
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -39,12 +40,16 @@ const router = createBrowserRouter([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/speaking',
|
path: '/speaking',
|
||||||
element: <Speaking/>
|
element: <CharacterSelection/>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile',
|
path: '/profile',
|
||||||
element: <Profile/>
|
element: <Profile/>
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/character',
|
||||||
|
element: <Character/>
|
||||||
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
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