fix: ekip panosu ve ust arayuzu rafine et
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import ShellFrame from "./components/ShellFrame.jsx";
|
||||
import SessionToolbar from "./components/SessionToolbar.jsx";
|
||||
import ChatStream from "./components/ChatStream.jsx";
|
||||
@@ -9,8 +9,9 @@ import { useSession } from "./hooks/useSession.js";
|
||||
|
||||
export default function App() {
|
||||
const { socket, connected } = useSocket();
|
||||
const { session, chat, error, startSession, stopSession, activateTeam, sendPrompt, clearError } = useSession(socket);
|
||||
const { session, chat, error, startSession, stopSession, sendPrompt, selectProject, clearError } = useSession(socket);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const autoStartedRef = useRef(false);
|
||||
|
||||
async function runAction(action) {
|
||||
setBusy(true);
|
||||
@@ -23,12 +24,28 @@ export default function App() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!connected || autoStartedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.status === "idle") {
|
||||
autoStartedRef.current = true;
|
||||
runAction(startSession).catch(() => {
|
||||
autoStartedRef.current = false;
|
||||
});
|
||||
}
|
||||
}, [connected, session.status]);
|
||||
|
||||
return (
|
||||
<main className="app-shell">
|
||||
<div className="app-shell__header">
|
||||
<div>
|
||||
<div className="app-shell__title">
|
||||
<p className="app-shell__eyebrow">1996 COMMAND CENTER</p>
|
||||
<h1>Retro Claude Team Console</h1>
|
||||
<p className="app-shell__project" title={session.currentProjectPath ?? "None"}>
|
||||
<span>Current Project:</span> {session.currentProjectPath ?? "None"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="app-shell__meta">
|
||||
<span>LINK: {connected ? "ONLINE" : "OFFLINE"}</span>
|
||||
@@ -54,14 +71,13 @@ export default function App() {
|
||||
<SessionToolbar
|
||||
session={session}
|
||||
busy={busy}
|
||||
onStart={() => runAction(startSession)}
|
||||
onActivate={() => runAction(activateTeam)}
|
||||
onStop={() => runAction(stopSession)}
|
||||
onSelectProject={() => runAction(selectProject)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<PromptComposer
|
||||
disabled={busy || session.status !== "running"}
|
||||
disabled={busy || session.status !== "running" || !session.teamActivated || !session.currentProjectPath}
|
||||
onSubmit={(prompt) => runAction(() => sendPrompt(prompt))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import PixelButton from "./PixelButton.jsx";
|
||||
|
||||
export default function SessionToolbar({ session, busy, onStart, onActivate, onStop }) {
|
||||
export default function SessionToolbar({ session, busy, onStop, onSelectProject }) {
|
||||
const isRunning = session.status === "running";
|
||||
const isStarting = session.status === "starting";
|
||||
|
||||
return (
|
||||
<div className="session-toolbar session-toolbar--inline">
|
||||
<PixelButton tone="green" disabled={busy || isRunning || isStarting} onClick={onStart}>
|
||||
Start Session
|
||||
</PixelButton>
|
||||
<PixelButton tone="cyan" disabled={busy || !isRunning} onClick={onActivate}>
|
||||
Activate Team
|
||||
</PixelButton>
|
||||
<PixelButton tone="red" disabled={busy || (!isRunning && session.status !== "starting")} onClick={onStop}>
|
||||
Stop Session
|
||||
</PixelButton>
|
||||
<PixelButton tone="amber" disabled={busy} onClick={onSelectProject}>
|
||||
Select Project
|
||||
</PixelButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ function TeamCard({ member }) {
|
||||
<span>NO SIGNAL YET</span>
|
||||
</div>
|
||||
) : (
|
||||
member.messages.slice(-4).map((message) => (
|
||||
[...member.messages].slice(-4).reverse().map((message) => (
|
||||
<article key={message.id} className="team-message">
|
||||
<span className="team-message__speaker">{message.speaker}:</span>
|
||||
<pre>{message.text}</pre>
|
||||
|
||||
@@ -69,8 +69,7 @@ function shouldBreakCurrentEntry(line) {
|
||||
/^[-=]{4,}$/.test(trimmed),
|
||||
/^>/.test(trimmed),
|
||||
/^Kullanici /i.test(trimmed),
|
||||
/^Mazlum nasilsin\?/i.test(trimmed),
|
||||
/^[A-Za-zÀ-ÿ]+,/.test(trimmed)
|
||||
/^Mazlum nasilsin\?/i.test(trimmed)
|
||||
].some(Boolean);
|
||||
}
|
||||
|
||||
@@ -94,11 +93,34 @@ function dedupeMessages(messages) {
|
||||
const result = [];
|
||||
|
||||
for (const message of messages) {
|
||||
const key = `${message.speaker}::${message.text}`;
|
||||
const normalizedText = String(message.text ?? "").replace(/\s+/g, " ").trim();
|
||||
const firstLine = normalizedText.split("\n")[0]?.trim() ?? "";
|
||||
const key = `${message.speaker}::${normalizedText}`;
|
||||
|
||||
if (seen.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const lastMessage = result[result.length - 1];
|
||||
if (lastMessage) {
|
||||
const lastNormalized = String(lastMessage.text ?? "").replace(/\s+/g, " ").trim();
|
||||
const lastFirstLine = lastNormalized.split("\n")[0]?.trim() ?? "";
|
||||
|
||||
if (
|
||||
lastMessage.speaker === message.speaker &&
|
||||
firstLine &&
|
||||
lastFirstLine === firstLine
|
||||
) {
|
||||
const mergedText = lastNormalized.length >= normalizedText.length ? lastMessage.text : message.text;
|
||||
result[result.length - 1] = {
|
||||
...lastMessage,
|
||||
text: mergedText
|
||||
};
|
||||
seen.add(key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
seen.add(key);
|
||||
result.push(message);
|
||||
}
|
||||
@@ -112,7 +134,7 @@ export function parseTeamFeed(chat) {
|
||||
|
||||
for (const rawLine of String(chat ?? "").split("\n")) {
|
||||
const line = rawLine.trim();
|
||||
const speakerMatch = line.match(/^[•*\-⏺]?\s*([A-Za-zÀ-ÿ]+):\s*(.*)$/);
|
||||
const speakerMatch = line.match(/^(?:[•*⏺]\s*)?([A-Za-zÀ-ÿ]+):\s*(.*)$/);
|
||||
|
||||
if (speakerMatch) {
|
||||
const member = memberMap.get(normalizeSpeaker(speakerMatch[1]));
|
||||
|
||||
@@ -35,6 +35,24 @@
|
||||
font-size: clamp(1.3rem, 2vw, 2rem);
|
||||
}
|
||||
|
||||
.app-shell__title {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.app-shell__project {
|
||||
margin: 10px 0 0;
|
||||
max-width: min(70vw, 760px);
|
||||
color: var(--text-dim);
|
||||
font-size: 0.78rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.app-shell__project span {
|
||||
color: var(--accent-amber);
|
||||
}
|
||||
|
||||
.app-shell__meta {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
@@ -107,13 +125,14 @@
|
||||
|
||||
.session-toolbar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.session-toolbar--inline {
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.pixel-button {
|
||||
@@ -123,17 +142,17 @@
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
background: transparent;
|
||||
min-width: 156px;
|
||||
min-width: 128px;
|
||||
}
|
||||
|
||||
.pixel-button span {
|
||||
display: block;
|
||||
padding: 14px 16px;
|
||||
padding: 12px 12px;
|
||||
border: 3px solid var(--border-dark);
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.06);
|
||||
font-family: var(--font-display);
|
||||
font-size: 0.62rem;
|
||||
letter-spacing: 0.14em;
|
||||
font-size: 0.56rem;
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
|
||||
.pixel-button:hover span {
|
||||
@@ -401,6 +420,10 @@
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.app-shell__project {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.shell-frame__screen {
|
||||
min-height: auto;
|
||||
padding: 12px;
|
||||
@@ -413,5 +436,6 @@
|
||||
|
||||
.session-toolbar--inline {
|
||||
justify-content: stretch;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user