feat(webui): Infrastructure Setup (Prerequisites)

This commit is contained in:
yiliang114 2026-01-15 14:32:21 +08:00
parent ec0586b135
commit af76450dee
23 changed files with 4367 additions and 374 deletions

View file

@ -0,0 +1,83 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type { Meta, StoryObj } from '@storybook/react-vite';
import Button from './Button';
/**
* Button component for user interactions.
* Supports multiple variants and sizes.
*/
const meta: Meta<typeof Button> = {
title: 'UI/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'danger'],
description: 'Visual style variant',
},
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
description: 'Button size',
},
disabled: {
control: 'boolean',
description: 'Disabled state',
},
onClick: { action: 'clicked' },
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
children: 'Primary Button',
variant: 'primary',
},
};
export const Secondary: Story = {
args: {
children: 'Secondary Button',
variant: 'secondary',
},
};
export const Danger: Story = {
args: {
children: 'Danger Button',
variant: 'danger',
},
};
export const Small: Story = {
args: {
children: 'Small Button',
size: 'sm',
},
};
export const Large: Story = {
args: {
children: 'Large Button',
size: 'lg',
},
};
export const Disabled: Story = {
args: {
children: 'Disabled Button',
disabled: true,
},
};

View file

@ -0,0 +1,68 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type { Meta, StoryObj } from '@storybook/react-vite';
import Tooltip from './Tooltip';
import Button from './Button';
/**
* Tooltip component for displaying contextual information on hover.
* Supports four positions: top, right, bottom, left.
*/
const meta: Meta<typeof Tooltip> = {
title: 'UI/Tooltip',
component: Tooltip,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
position: {
control: 'select',
options: ['top', 'right', 'bottom', 'left'],
description: 'Tooltip position relative to trigger',
},
content: {
control: 'text',
description: 'Tooltip content text',
},
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Top: Story = {
args: {
content: 'Tooltip on top',
position: 'top',
children: <Button>Hover me</Button>,
},
};
export const Right: Story = {
args: {
content: 'Tooltip on right',
position: 'right',
children: <Button>Hover me</Button>,
},
};
export const Bottom: Story = {
args: {
content: 'Tooltip on bottom',
position: 'bottom',
children: <Button>Hover me</Button>,
},
};
export const Left: Story = {
args: {
content: 'Tooltip on left',
position: 'left',
children: <Button>Hover me</Button>,
},
};

View file

@ -0,0 +1,89 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { createContext, useContext } from 'react';
/**
* Platform types supported by the webui library
*/
export type PlatformType = 'vscode' | 'chrome' | 'web' | 'share';
/**
* Platform context interface for cross-platform component reuse.
* Each platform adapter implements this interface.
*/
export interface PlatformContextValue {
/** Current platform identifier */
platform: PlatformType;
/** Send message to platform host */
postMessage: (message: unknown) => void;
/** Subscribe to messages from platform host */
onMessage: (handler: (message: unknown) => void) => () => void;
/** Open a file in the platform's editor (optional) */
openFile?: (path: string) => void;
/** Trigger file attachment dialog (optional) */
attachFile?: () => void;
/** Trigger platform login flow (optional) */
login?: () => void;
/** Copy text to clipboard */
copyToClipboard?: (text: string) => Promise<void>;
/** Platform-specific feature flags */
features?: {
canOpenFile?: boolean;
canAttachFile?: boolean;
canLogin?: boolean;
canCopy?: boolean;
};
}
/**
* Default noop implementation for platforms without message support
*/
const defaultContext: PlatformContextValue = {
platform: 'web',
postMessage: () => {},
onMessage: () => () => {},
};
/**
* Platform context for accessing platform-specific capabilities
*/
export const PlatformContext =
createContext<PlatformContextValue>(defaultContext);
/**
* Hook to access platform context
*/
export function usePlatform(): PlatformContextValue {
return useContext(PlatformContext);
}
/**
* Provider component props
*/
export interface PlatformProviderProps {
children: React.ReactNode;
value: PlatformContextValue;
}
/**
* Platform context provider component
*/
export function PlatformProvider({ children, value }: PlatformProviderProps) {
return (
<PlatformContext.Provider value={value}>
{children}
</PlatformContext.Provider>
);
}

View file

@ -1,6 +1,18 @@
// Shared UI Components Export
// Export all shared components from this package
// Context
export {
PlatformContext,
PlatformProvider,
usePlatform,
} from './context/PlatformContext';
export type {
PlatformContextValue,
PlatformProviderProps,
PlatformType,
} from './context/PlatformContext';
// Layout components
export { default as Container } from './components/layout/Container';
export { default as Header } from './components/layout/Header';
@ -33,3 +45,10 @@ export { useLocalStorage } from './hooks/useLocalStorage';
// Types
export type { Theme } from './types/theme';
export type { MessageProps } from './types/messages';
export type { ChatMessage, MessageRole, PlanEntry } from './types/chat';
export type {
ToolCallStatus,
ToolCallLocation,
ToolCallContentItem,
ToolCallUpdate,
} from './types/toolCall';

View file

@ -0,0 +1,52 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Default CSS variables for @qwen-code/webui
* Consumers can override these variables to customize the theme.
*/
:root {
/* Primary colors */
--app-primary: #3b82f6;
--app-primary-hover: #2563eb;
--app-primary-foreground: #ffffff;
/* Background colors */
--app-background: #ffffff;
--app-background-secondary: #f3f4f6;
--app-background-tertiary: #e5e7eb;
/* Foreground/text colors */
--app-foreground: #111827;
--app-foreground-secondary: #6b7280;
--app-foreground-muted: #9ca3af;
/* Border colors */
--app-border: #e5e7eb;
--app-border-focus: #3b82f6;
/* Status colors */
--app-success: #10b981;
--app-warning: #f59e0b;
--app-error: #ef4444;
--app-info: #3b82f6;
/* Typography */
--app-font-sans: system-ui, -apple-system, sans-serif;
--app-font-mono: ui-monospace, monospace;
/* Border radius */
--app-radius-sm: 0.25rem;
--app-radius-md: 0.375rem;
--app-radius-lg: 0.5rem;
/* Spacing */
--app-spacing-xs: 0.25rem;
--app-spacing-sm: 0.5rem;
--app-spacing-md: 1rem;
--app-spacing-lg: 1.5rem;
--app-spacing-xl: 2rem;
}

View file

@ -0,0 +1,28 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Chat message role types
*/
export type MessageRole = 'user' | 'assistant' | 'system';
/**
* Basic chat message structure
*/
export interface ChatMessage {
role: MessageRole;
content: string;
timestamp: number;
}
/**
* Plan entry for task tracking
*/
export interface PlanEntry {
content: string;
priority?: 'high' | 'medium' | 'low';
status: 'pending' | 'in_progress' | 'completed';
}

View file

@ -0,0 +1,48 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Tool call status
*/
export type ToolCallStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
/**
* Tool call location reference
*/
export interface ToolCallLocation {
path: string;
line?: number | null;
}
/**
* Tool call content item
*/
export interface ToolCallContentItem {
type: 'content' | 'diff';
content?: {
type: string;
text?: string;
[key: string]: unknown;
};
path?: string;
oldText?: string | null;
newText?: string;
[key: string]: unknown;
}
/**
* Tool call update data
*/
export interface ToolCallUpdate {
toolCallId: string;
kind?: string;
title?: string;
status?: ToolCallStatus;
rawInput?: unknown;
content?: ToolCallContentItem[];
locations?: ToolCallLocation[];
timestamp?: number;
}