mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 12:11:09 +00:00
feat(webui): Infrastructure Setup (Prerequisites)
This commit is contained in:
parent
ec0586b135
commit
af76450dee
23 changed files with 4367 additions and 374 deletions
83
packages/webui/src/components/ui/Button.stories.tsx
Normal file
83
packages/webui/src/components/ui/Button.stories.tsx
Normal 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,
|
||||
},
|
||||
};
|
||||
68
packages/webui/src/components/ui/Tooltip.stories.tsx
Normal file
68
packages/webui/src/components/ui/Tooltip.stories.tsx
Normal 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>,
|
||||
},
|
||||
};
|
||||
89
packages/webui/src/context/PlatformContext.tsx
Normal file
89
packages/webui/src/context/PlatformContext.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
52
packages/webui/src/styles/variables.css
Normal file
52
packages/webui/src/styles/variables.css
Normal 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;
|
||||
}
|
||||
28
packages/webui/src/types/chat.ts
Normal file
28
packages/webui/src/types/chat.ts
Normal 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';
|
||||
}
|
||||
48
packages/webui/src/types/toolCall.ts
Normal file
48
packages/webui/src/types/toolCall.ts
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue