Integrate project classroom with teacher and friend consultations

This commit is contained in:
鲨鱼辣椒
2026-09-22 15:50:18 +08:00
parent e5d271bc45
commit 68e676cb62
28 changed files with 957 additions and 314 deletions

View File

@@ -40,6 +40,7 @@ export interface AgentBrowserPanelProps {
projectId: string | null;
open: boolean;
onOpenChange(open: boolean): void;
embedded?: boolean;
}
const EVENT_METHODS = [
@@ -86,10 +87,11 @@ function browserIsActive(snapshot: AgentBrowserSnapshot | null): boolean {
function modalOccludesBrowser(): boolean {
return Array.from(
document.querySelectorAll<HTMLElement>('[role="dialog"], [role="alertdialog"]'),
document.querySelectorAll<HTMLElement>('[role="dialog"], [role="alertdialog"], #coding-consultation-dock'),
).some((element) => {
if (element.hidden || element.getAttribute('data-state') === 'closed') return false;
const style = window.getComputedStyle(element);
if (element.id === 'coding-consultation-dock' && style.position !== 'absolute' && style.position !== 'fixed') return false;
return style.display !== 'none' && style.visibility !== 'hidden';
});
}
@@ -118,6 +120,7 @@ export function AgentBrowserPanel({
projectId,
open,
onOpenChange,
embedded = false,
}: AgentBrowserPanelProps) {
const [snapshot, setSnapshot] = useState<AgentBrowserSnapshot | null>(null);
const [address, setAddress] = useState('');
@@ -214,12 +217,14 @@ export function AgentBrowserPanel({
const wasOpen = wasOpenRef.current;
wasOpenRef.current = open;
if (!wasOpen || open || !projectId) return;
// Switching the central workspace tab must preserve the running work page.
if (embedded) return;
setSnapshot(null);
setDiagnosticsOpen(false);
setEvents([]);
eventCursorRef.current = 0;
void closeAgentBrowser(projectId).catch(() => undefined);
}, [open, projectId]);
}, [embedded, open, projectId]);
useEffect(() => () => {
if (projectId) void closeAgentBrowser(projectId).catch(() => undefined);
@@ -237,6 +242,7 @@ export function AgentBrowserPanel({
}
const update = () => setOccluded(modalOccludesBrowser());
update();
window.addEventListener('resize', update);
const observer = new MutationObserver(update);
observer.observe(document.body, {
attributes: true,
@@ -244,7 +250,10 @@ export function AgentBrowserPanel({
childList: true,
subtree: true,
});
return () => observer.disconnect();
return () => {
observer.disconnect();
window.removeEventListener('resize', update);
};
}, [open]);
useEffect(() => {
@@ -390,14 +399,14 @@ export function AgentBrowserPanel({
return (
<aside
className="relative flex w-[400px] min-w-[300px] max-w-[48vw] shrink-0 flex-col overflow-hidden border-l border-border/80 bg-background shadow-[-16px_0_32px_hsl(220_20%_16%_/_0.06)] max-[900px]:fixed max-[900px]:inset-y-10 max-[900px]:right-0 max-[900px]:z-40 max-[900px]:max-w-[min(92vw,420px)]"
className={cn(embedded ? 'relative flex min-h-0 w-full min-w-0 flex-1 flex-col overflow-hidden bg-background' : 'relative flex w-[400px] min-w-[300px] max-w-[48vw] shrink-0 flex-col overflow-hidden border-l border-border/80 bg-background shadow-[-16px_0_32px_hsl(220_20%_16%_/_0.06)] max-[900px]:fixed max-[900px]:inset-y-10 max-[900px]:right-0 max-[900px]:z-40 max-[900px]:max-w-[min(92vw,420px)]')}
data-testid="agent-browser-panel"
>
<div className="flex h-10 shrink-0 items-center gap-2 border-b border-border/70 px-2.5">
<span className="flex h-6 w-6 items-center justify-center rounded-md bg-brand-soft text-brand">
<Globe2 className="h-3.5 w-3.5" aria-hidden="true" />
</span>
<h2 className="min-w-0 flex-1 truncate text-xs font-semibold">开发浏览器</h2>
<h2 className="min-w-0 flex-1 truncate text-xs font-semibold">{embedded ? '作品预览' : '开发浏览器'}</h2>
<Button
type="button"
variant="ghost"
@@ -426,7 +435,7 @@ export function AgentBrowserPanel({
onChange={(event) => setAddress(event.target.value)}
aria-label="网页地址"
className="h-7 min-w-0 flex-1 rounded-lg border border-border/90 bg-surface-input px-2.5 text-[11px] font-medium outline-none focus:border-brand/40 focus:ring-2 focus:ring-brand/15"
placeholder="输入 URL"
placeholder={embedded ? '作品运行后,在这里打开它的地址' : '输入 URL'}
spellCheck={false}
/>
</form>
@@ -448,8 +457,8 @@ export function AgentBrowserPanel({
<span className="flex h-12 w-12 items-center justify-center rounded-xl border border-border/70 bg-background shadow-soft">
<Globe2 className="h-5 w-5" aria-hidden="true" />
</span>
<p className="text-[13px] font-semibold text-foreground">开始浏览</p>
<p className="text-[11px]">输入 URL,或等待智能体打开调试页面</p>
<p className="text-[13px] font-semibold text-foreground">{embedded ? '作品会在这里展开' : '开始浏览'}</p>
<p className="text-xs leading-6">{embedded ? '先在操作对话里制作作品,再打开它的预览地址。' : '输入 URL,或等待智能体打开调试页面'}</p>
</div>
) : null}
</div>