mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
beginning of my ideases
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
||||||
<title>Roomba Rover</title>
|
<title>Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-DqqTkkpY.js"></script>
|
<script type="module" crossorigin src="/assets/index-4eskKUF4.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-v8lmO81Z.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-B8wCAHw2.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ export default function ButtonBoxPanel() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="panel-section space-y-0.5 text-base">
|
<section className="panel-section space-y-0.5 text-base">
|
||||||
<header className="panel-muted text-center text-sm">
|
<header className="panel-title-row">
|
||||||
<p>Button Box</p>
|
<p className="panel-title-text">Button Box</p>
|
||||||
</header>
|
</header>
|
||||||
<div className="grid grid-cols-4 gap-0.5">
|
<div className="grid grid-cols-4 gap-0.5">
|
||||||
{buttons.map((button) => {
|
{buttons.map((button) => {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default function ChatPanel({
|
|||||||
hideSpectatorNotice = false,
|
hideSpectatorNotice = false,
|
||||||
fillHeight = false,
|
fillHeight = false,
|
||||||
allowSpectatorInput = false,
|
allowSpectatorInput = false,
|
||||||
|
title = 'Chat',
|
||||||
}) {
|
}) {
|
||||||
const role = useSessionSelector((state) => state.session?.role || null);
|
const role = useSessionSelector((state) => state.session?.role || null);
|
||||||
const currentRoverId = useSessionSelector((state) => state.session?.assignment?.roverId || null);
|
const currentRoverId = useSessionSelector((state) => state.session?.assignment?.roverId || null);
|
||||||
@@ -106,6 +107,11 @@ export default function ChatPanel({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`panel-section space-y-0.5 text-base ${fillHeight ? 'flex h-full flex-col overflow-hidden' : ''}`}>
|
<section className={`panel-section space-y-0.5 text-base ${fillHeight ? 'flex h-full flex-col overflow-hidden' : ''}`}>
|
||||||
|
{title ? (
|
||||||
|
<div className="panel-title-row">
|
||||||
|
<span className="panel-title-text">{title}</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<div className={`surface overflow-y-auto space-y-0.5 px-0 ${listClass}`} ref={listRef}>
|
<div className={`surface overflow-y-auto space-y-0.5 px-0 ${listClass}`} ref={listRef}>
|
||||||
{sorted.length === 0 && typingRows.length === 0 ? (
|
{sorted.length === 0 && typingRows.length === 0 ? (
|
||||||
<p className="text-sm text-slate-500">No messages yet.</p>
|
<p className="text-sm text-slate-500">No messages yet.</p>
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ export default function HomeAssistantControls() {
|
|||||||
if (!ha?.enabled) {
|
if (!ha?.enabled) {
|
||||||
return (
|
return (
|
||||||
<section className="panel-section space-y-0.5 text-sm text-slate-400">
|
<section className="panel-section space-y-0.5 text-sm text-slate-400">
|
||||||
<p className="text-slate-300">Room Controls</p>
|
<p className="panel-title-text">Room Controls</p>
|
||||||
<p className="text-slate-500">Not configured on the server.</p>
|
<p className="text-slate-500">Not configured on the server.</p>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
@@ -265,7 +265,7 @@ export default function HomeAssistantControls() {
|
|||||||
if (entities.length === 0) {
|
if (entities.length === 0) {
|
||||||
return (
|
return (
|
||||||
<section className="panel-section space-y-0.5 text-sm text-slate-400">
|
<section className="panel-section space-y-0.5 text-sm text-slate-400">
|
||||||
<p className="text-slate-300">Room Controls</p>
|
<p className="panel-title-text">Room Controls</p>
|
||||||
<p className="text-slate-500">No lights or switches configured.</p>
|
<p className="text-slate-500">No lights or switches configured.</p>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
@@ -275,23 +275,25 @@ export default function HomeAssistantControls() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="panel-section space-y-0.5 text-base">
|
<section className="panel-section space-y-0.5 text-base">
|
||||||
<header className="flex items-center justify-between gap-0.5 text-sm text-slate-400">
|
<header className="panel-title-row">
|
||||||
<div className="flex items-center gap-0.5">
|
<div className="panel-title-left">
|
||||||
<p>Room Controls</p>
|
<p className="panel-title-text">Room Controls</p>
|
||||||
<span className="text-xs text-slate-500">{entities.length}</span>
|
<span className="panel-title-meta">{entities.length}</span>
|
||||||
{controlsLocked ? <StatusBadge label={lockState === 'off' ? 'Locked Off' : 'Locked On'} tone="warn" /> : null}
|
</div>
|
||||||
<div className="flex items-center gap-0.5 text-xs text-slate-300 background-black">
|
<div className="panel-title-right">
|
||||||
|
<div className="panel-title-actions">
|
||||||
<span className="flex items-center gap-0.5">
|
<span className="flex items-center gap-0.5">
|
||||||
<span>On</span>
|
<span className="panel-title-meta">On</span>
|
||||||
{onKeyLabel ? <KeyPill label={onKeyLabel} /> : null}
|
{onKeyLabel ? <KeyPill label={onKeyLabel} /> : null}
|
||||||
</span>
|
</span>
|
||||||
<span className="flex items-center gap-0.5">
|
<span className="flex items-center gap-0.5">
|
||||||
<span>Off</span>
|
<span className="panel-title-meta">Off</span>
|
||||||
{offKeyLabel ? <KeyPill label={offKeyLabel} /> : null}
|
{offKeyLabel ? <KeyPill label={offKeyLabel} /> : null}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{controlsLocked ? <StatusBadge label={lockState === 'off' ? 'Locked Off' : 'Locked On'} tone="warn" /> : null}
|
||||||
|
<StatusBadge label={connected ? 'Connected' : 'Offline'} tone={connected ? 'success' : 'warn'} />
|
||||||
</div>
|
</div>
|
||||||
<StatusBadge label={connected ? 'Connected' : 'Offline'} tone={connected ? 'success' : 'warn'} />
|
|
||||||
</header>
|
</header>
|
||||||
{controlsLocked ? (
|
{controlsLocked ? (
|
||||||
<p className="rounded border border-amber-600/60 bg-amber-900/40 px-1 py-0.5 text-xs text-amber-100">
|
<p className="rounded border border-amber-600/60 bg-amber-900/40 px-1 py-0.5 text-xs text-amber-100">
|
||||||
@@ -319,5 +321,5 @@ export default function HomeAssistantControls() {
|
|||||||
|
|
||||||
function KeyPill({ label }) {
|
function KeyPill({ label }) {
|
||||||
if (!label) return null;
|
if (!label) return null;
|
||||||
return <span className="rounded border border-white/40 px-1 text-[0.7rem] text-white">{label}</span>;
|
return <span className="rounded border border-slate-600 px-1 text-[0.65rem] text-slate-300">{label}</span>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ export default function LogPanel() {
|
|||||||
const rendered = useMemo(() => logs.slice().reverse(), [logs]);
|
const rendered = useMemo(() => logs.slice().reverse(), [logs]);
|
||||||
return (
|
return (
|
||||||
<div className="panel-section space-y-0.5 text-base">
|
<div className="panel-section space-y-0.5 text-base">
|
||||||
<div className="flex items-center justify-between text-sm text-slate-400">
|
<div className="panel-title-row">
|
||||||
<span>Server logs</span>
|
<span className="panel-title-text">Server logs</span>
|
||||||
<span>{logs.length}</span>
|
<span className="panel-title-meta">{logs.length}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="surface h-64 overflow-y-auto font-mono text-xs">
|
<div className="surface h-64 overflow-y-auto font-mono text-xs">
|
||||||
{logs.length === 0 ? (
|
{logs.length === 0 ? (
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ export default function OverseerPreferencePanel() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="surface p-1 text-xs text-slate-200 text-center">
|
<section className="surface p-1 text-xs text-slate-200 text-center">
|
||||||
<div className="text-[0.65rem] text-slate-400">Overseer vote</div>
|
<div className="panel-title-row">
|
||||||
|
<span className="panel-title-text">Overseer vote</span>
|
||||||
|
</div>
|
||||||
<label
|
<label
|
||||||
className={`flex items-center justify-center gap-1.5 rounded px-1 py-0.5 ${
|
className={`flex items-center justify-center gap-1.5 rounded px-1 py-0.5 ${
|
||||||
enabled ? 'bg-emerald-600/80 text-emerald-50' : 'bg-slate-600/70 text-slate-100'
|
enabled ? 'bg-emerald-600/80 text-emerald-50' : 'bg-slate-600/70 text-slate-100'
|
||||||
|
|||||||
@@ -76,9 +76,9 @@ export default function RawUserPilePanel({
|
|||||||
|
|
||||||
<div className={`space-y-0.5 ${fillHeight ? 'flex flex-1 min-h-0 flex-col' : ''}`}>
|
<div className={`space-y-0.5 ${fillHeight ? 'flex flex-1 min-h-0 flex-col' : ''}`}>
|
||||||
{!hideHeader && (
|
{!hideHeader && (
|
||||||
<div className={`flex items-center justify-between text-sm text-slate-400 ${compact ? 'text-xs' : ''}`}>
|
<div className="panel-title-row">
|
||||||
<span>Users</span>
|
<span className="panel-title-text">Users</span>
|
||||||
<span className="text-xs text-slate-500">{sorted.length}</span>
|
<span className="panel-title-meta">{sorted.length}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -151,9 +151,9 @@ export default function ReplaySourcesPanel({ panelId = 'replay-sources', fillHei
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={`panel-section p-0.75 text-sm ${containerClass}`}>
|
<section className={`panel-section p-0.75 text-sm ${containerClass}`}>
|
||||||
<header className="panel-muted flex items-center justify-between text-xs">
|
<header className="panel-title-row">
|
||||||
<span>Replay Sources</span>
|
<span className="panel-title-text">Replay Sources</span>
|
||||||
<span>{sources.length}</span>
|
<span className="panel-title-meta">{sources.length}</span>
|
||||||
</header>
|
</header>
|
||||||
<div className={`grid gap-0.5 md:grid-cols-2 ${listWrapClass}`}>
|
<div className={`grid gap-0.5 md:grid-cols-2 ${listWrapClass}`}>
|
||||||
<GroupList title="Rovers" items={grouped.rovers} selected={selected} onToggle={toggleKey} />
|
<GroupList title="Rovers" items={grouped.rovers} selected={selected} onToggle={toggleKey} />
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ function DriveDockPanel() {
|
|||||||
value={value}
|
value={value}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
|
label="Camera tilt"
|
||||||
disabled={cameraDisabled}
|
disabled={cameraDisabled}
|
||||||
onChange={setServoAngle}
|
onChange={setServoAngle}
|
||||||
keyDownLabel={downLabel}
|
keyDownLabel={downLabel}
|
||||||
|
|||||||
@@ -69,15 +69,15 @@ export default function RoomCameraPanel({
|
|||||||
return (
|
return (
|
||||||
<section className="panel-section space-y-0.5 text-base">
|
<section className="panel-section space-y-0.5 text-base">
|
||||||
{!hideHeader && (
|
{!hideHeader && (
|
||||||
<header className="flex flex-wrap items-center justify-between gap-0.5 text-sm text-slate-400">
|
<header className="panel-title-row">
|
||||||
<div className="flex items-center gap-0.5">
|
<div className="panel-title-left">
|
||||||
<p>Room cameras</p>
|
<p className="panel-title-text">Room cameras</p>
|
||||||
<span className="text-xs text-slate-500">{cameras.length}</span>
|
<span className="panel-title-meta">{cameras.length}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-wrap items-center gap-0.5 text-xs">
|
<div className="panel-title-right">
|
||||||
{showLayoutToggle && (
|
{showLayoutToggle && (
|
||||||
<div className="flex items-center gap-0.5">
|
<div className="panel-title-actions">
|
||||||
<span className="text-slate-500">Layout:</span>
|
<span className="panel-title-meta">Layout</span>
|
||||||
<div className="inline-flex overflow-hidden rounded border border-slate-700">
|
<div className="inline-flex overflow-hidden rounded border border-slate-700">
|
||||||
{ORIENTATIONS.map((option) => (
|
{ORIENTATIONS.map((option) => (
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -97,7 +97,11 @@ export default function RoverQueuesPanel({ title = 'Rovers' }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-0.5 text-sm">
|
<div className="space-y-0.5 text-sm">
|
||||||
{title && <p className="text-sm text-slate-400">{title}</p>}
|
{title && (
|
||||||
|
<div className="panel-title-row">
|
||||||
|
<p className="panel-title-text">{title}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{rosterItems.length === 0 ? (
|
{rosterItems.length === 0 ? (
|
||||||
<p className="text-sm text-slate-500">No rovers registered.</p>
|
<p className="text-sm text-slate-500">No rovers registered.</p>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ function SensorDetails({ sensors, dockState }) {
|
|||||||
function DetailCard({ title, children }) {
|
function DetailCard({ title, children }) {
|
||||||
return (
|
return (
|
||||||
<div className="surface space-y-0.5 p-1 text-sm">
|
<div className="surface space-y-0.5 p-1 text-sm">
|
||||||
<div className="text-[0.8rem] uppercase tracking-wide text-slate-400">{title}</div>
|
<div className="panel-title-text">{title}</div>
|
||||||
<div className="space-y-0.5">{children}</div>
|
<div className="space-y-0.5">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export function NicknameEntryPanel({ compact = false }) {
|
|||||||
export function LinkButtonsPanel() {
|
export function LinkButtonsPanel() {
|
||||||
return (
|
return (
|
||||||
<section className="panel-section flex h-full min-h-0 flex-col gap-0.5 text-base">
|
<section className="panel-section flex h-full min-h-0 flex-col gap-0.5 text-base">
|
||||||
|
<div className="panel-title-row">
|
||||||
|
<span className="panel-title-text">Socials</span>
|
||||||
|
</div>
|
||||||
<SocialButtonsGrid className="flex-1 min-h-0" />
|
<SocialButtonsGrid className="flex-1 min-h-0" />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -71,6 +71,30 @@ body {
|
|||||||
@apply text-sm text-slate-400 rounded-md;
|
@apply text-sm text-slate-400 rounded-md;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-title-row {
|
||||||
|
@apply flex items-center justify-between gap-0.5 rounded-md bg-slate-900 px-0.5 py-0.5 text-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-text {
|
||||||
|
@apply text-[0.78rem] font-semibold tracking-normal text-slate-200 leading-none text-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-meta {
|
||||||
|
@apply text-[0.68rem] font-medium tracking-normal text-slate-400 leading-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-left {
|
||||||
|
@apply flex min-w-0 items-center gap-0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-right {
|
||||||
|
@apply flex flex-wrap items-center justify-end gap-0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-actions {
|
||||||
|
@apply flex items-center gap-0.5 text-[0.68rem] text-slate-400 leading-none;
|
||||||
|
}
|
||||||
|
|
||||||
.surface {
|
.surface {
|
||||||
@apply bg-neutral-800 text-white px-0.5 py-0.5 rounded-md;
|
@apply bg-neutral-800 text-white px-0.5 py-0.5 rounded-md;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user