chore: combined some branches, improved style

This demo branch contains code from multiple different branches. DO NOT MERGE this branch because it looks like I'm the author of all these changes.
This commit is contained in:
Twirre Meulenbelt
2025-10-01 22:56:03 +02:00
parent 96053e798a
commit 10522b71c3
16 changed files with 1251 additions and 116 deletions

View File

@@ -4,3 +4,9 @@
.card {
padding: 2em;
}
.links {
display: flex;
flex-direction: column;
gap: 1em;
}

View File

@@ -1,47 +1,20 @@
//import { useState } from 'react'
import { Link } from 'react-router'
import reactLogo from '../../assets/react.svg'
import viteLogo from '../../assets/vite.svg'
import pepperLogo from '../../assets/pepper_transp2_small.svg'
import style from './Home.module.css'
import Counter from '../../components/components.tsx'
import styles from './Home.module.css'
function Home() {
return (
<>
<div>
<div className = "logoPepperScaling">
<a href="https://git.science.uu.nl/ics/sp/2025/n25b" target="_blank">
<img src={pepperLogo} className="logopepper" alt="Pepper logo" />
</a>
</div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
<div className="logoPepperScaling">
<a href="https://git.science.uu.nl/ics/sp/2025/n25b" target="_blank">
<img src={pepperLogo} className="logopepper" alt="Pepper logo" />
</a>
</div>
<h1>Vite + React</h1>
<Counter />
<Link to = '/ServerComms'>
<button className='movePage right' onClick={() : void => {}}>
Page Cool --{'>'}
</button>
</Link>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
<p className={style.read_the_docs}>
Click on the Vite and React logos to learn more
</p>
<div className={styles.links}>
<Link to={"/ServerComms"}>Robot interaction </Link>
<Link to={"/visprog"}>Node editor </Link>
<Link to={"/logging"}>Logs </Link>
</div>
</>
)
}

View File

@@ -0,0 +1,17 @@
.DivToScroll{
background-color: color-mix(in srgb, canvas, #000 5%);
border: 1px solid color-mix(in srgb, canvas, #000 15%);
border-radius: 4px 0 4px 0;
color: #3B3C3E;
font-size: 12px;
font-weight: bold;
left: -1px;
padding: 10px 7px 5px;
}
.DivWithScroll{
height:50vh;
width:100vh;
overflow:scroll;
overflow-x:hidden;
}

View File

@@ -0,0 +1,78 @@
import { useState } from 'react';
import { DATA } from "../../assets/data";
import styles from './Logging.module.css';
// const dataType = DATA as { id: string; level: "debug"|"info"|"warn"|"error"; msg: string; timestamp?: string };
type Level = "debug" | "info" | "warn" | "error";
// make optional fields optional
type LogEntry = {
id: string;
level: Level;
timestamp?: string;
msg?: string;
type?: "speech" | "sensor" | "system" | string;
};
function getLevelColor(level: Level) {
switch (level) {
case "debug":
return "gray";
case "info":
return "blue";
case "warn":
return "red";
case "error":
return "red";
default:
return "black";
}
}
function Logging() {
const [logs, setLogs] = useState<LogEntry[]>([]);
const logDiv = (
<div className={styles.DivToScroll}>
<div className={styles.DivWithScroll}>
{logs.map((log) => (
<div
key={log.id}
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
padding: "4px 0",
}}
>
<span style={{ color: "darkgrey", minWidth: 120, textAlign: "left" }}>
[{log.timestamp}]
</span>
<span style={{ flex: 1, textAlign: "center" }}>
{log.msg ? log.msg : "No message"}
</span>
<span style={{ color: getLevelColor(log.level), minWidth: 80, textAlign: "right" }}>
({log.level})
</span>
</div>
))}
</div>
</div>
)
return (
<>
<h1>Log Screen</h1>
{ logDiv }
<div className="card">
<button onClick={() => setLogs(DATA)}>
Load sample logs
</button>
</div>
</>
)
}
export default Logging

View File

@@ -1,15 +1,12 @@
import { useState, useEffect } from 'react'
import { Link } from 'react-router'
//import Counter from '../../components/components.tsx'
import { useState, useEffect, useRef } from 'react'
//this is your css file where you can style your buttons and such
//you can still use css parts from App.css, but also overwrite them
function ServerComms() {
export default function ServerComms() {
const [message, setMessage] = useState('');
const [sseMessage, setSseMessage] = useState('');
const [spoken, setSpoken] = useState<string>("");
const [listening, setListening] = useState(false);
const [conversation, setConversation] = useState<{"role": "user" | "assistant", "content": string}[]>([])
const conversationRef = useRef<HTMLDivElement | null>(null);
const [conversationIndex, setConversationIndex] = useState(0);
const sendMessage = async () => {
try {
@@ -31,22 +28,31 @@ function ServerComms() {
const eventSource = new EventSource("http://localhost:8000/sse");
eventSource.onmessage = (event) => {
setSseMessage(event.data);
try {
const data = JSON.parse(event.data);
if (data.speech) setSpoken(data.speech);
} catch {}
if ("voice_active" in data) setListening(data.voice_active);
if ("speech" in data) setConversation(conversation => [...conversation, {"role": "user", "content": data.speech}]);
if ("llm_response" in data) setConversation(conversation => [...conversation, {"role": "assistant", "content": data.llm_response}]);
} catch {
console.log("Unparsable SSE message:", event.data);
}
};
return () => {
eventSource.close();
};
}, []);
}, [conversationIndex]);
useEffect(() => {
if (!conversationRef || !conversationRef.current) return;
conversationRef.current.scrollTop = conversationRef.current.scrollHeight;
}, [conversation]);
return (
<div className="App">
<div>
<div>
<h1>Robot interaction</h1>
<h2>Force robot speech</h2>
<div className={"flex-row gap-md justify-center"}>
<input
type="text"
value={message}
@@ -54,27 +60,35 @@ function ServerComms() {
onKeyDown={(e) => e.key === "Enter" && sendMessage().then(() => setMessage(""))}
placeholder="Enter a message"
/>
<button onClick={sendMessage}>Send Message to Backend</button>
<button onClick={sendMessage}>Speak</button>
</div>
<div>
<h2>Message from Server (SSE):</h2>
<p>{sseMessage}</p>
</div>
<div>
<h2>Spoken text (SSE):</h2>
<p>{spoken}</p>
</div>
<div>
<Link to = {"/"}> {/* here you link to the homepage, in App.tsx you can link new pages */}
<button className= 'movePage left' onClick={() :void => {}}>
Page {'<'}-- Go Home
</button>
</Link>
<div className={"flex-col gap-lg"}>
<h2>Conversation</h2>
<p>Listening {listening ? "🟢" : "🔴"}</p>
<div style={{ maxHeight: "200px", maxWidth: "600px", overflowY: "auto"}} ref={conversationRef}>
{conversation.map((item) => (
<p
style={{
backgroundColor: item["role"] == "user"
? "color-mix(in oklab, canvas, blue 20%)"
: "color-mix(in oklab, canvas, gray 20%)",
whiteSpace: "pre-line",
}}
className={"round-md padding-md"}
>{item["content"]}</p>
))}
</div>
<div className={"flex-row gap-md justify-center"}>
<button onClick={() => {
setConversationIndex((conversationIndex) => conversationIndex + 1)
setConversation([])
}}>Reset</button>
<button onClick={() => {
setConversationIndex((conversationIndex) => conversationIndex == -1 ? 0 : -1)
setConversation([])
}}>{conversationIndex == -1 ? "Start" : "Stop"}</button>
</div>
</div>
</div>
);
}
export default ServerComms

View File

@@ -0,0 +1,11 @@
import VisProgUI from "../../visualProgrammingUI/VisProgUI.tsx";
function VisProgPage() {
return (
<>
<VisProgUI />
</>
)
}
export default VisProgPage