feat(vscode-ide-companion): add Tailwind CSS demo components

添加 Tailwind CSS 示例组件和重构的 PermissionDrawer:
- TailwindDemo: 展示 Tailwind CSS 基础用法
- PermissionDrawer.tailwind: 使用 Tailwind CSS 重构的权限抽屉组件
This commit is contained in:
yiliang114
2025-11-23 16:41:09 +08:00
parent 36a96a7b5c
commit 9899d872a2
2 changed files with 232 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*
* PermissionDrawer component using Tailwind CSS
*/
import type React from 'react';
import { useEffect } from 'react';
import {
PermissionRequest,
type PermissionOption,
type ToolCall,
} from './PermissionRequest.js';
import { buttonClasses, commonClasses } from '../../lib/tailwindUtils.js';
interface PermissionDrawerProps {
isOpen: boolean;
options: PermissionOption[];
toolCall: ToolCall;
onResponse: (optionId: string) => void;
onClose?: () => void;
}
/**
* Permission drawer component - displays permission requests in a bottom sheet
* Uses Tailwind CSS for styling
* @param isOpen - Whether the drawer is open
* @param options - Permission options to display
* @param toolCall - Tool call information
* @param onResponse - Callback when user responds
* @param onClose - Optional callback when drawer closes
*/
export const PermissionDrawerTailwind: React.FC<PermissionDrawerProps> = ({
isOpen,
options,
toolCall,
onResponse,
onClose,
}) => {
// Close drawer on Escape key
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (!isOpen) {
return;
}
// Close on Escape
if (e.key === 'Escape' && onClose) {
onClose();
return;
}
// Quick select with number keys (1-9)
const numMatch = e.key.match(/^[1-9]$/);
if (numMatch) {
const index = parseInt(e.key, 10) - 1;
if (index < options.length) {
e.preventDefault();
onResponse(options[index].optionId);
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [isOpen, onClose, options, onResponse]);
if (!isOpen) {
return null;
}
return (
<>
{/* Backdrop */}
<div
className="fixed inset-0 bg-black bg-opacity-75 z-[998] animate-fadeIn"
onClick={onClose}
/>
{/* Drawer */}
<div className="flex flex-col p-2 bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-large max-h-[70vh] outline-0 relative mb-1.5 z-[999] animate-slideUpFromBottom">
<div className="bg-white dark:bg-gray-900 rounded-large absolute inset-0"></div>
<div className="relative flex items-center justify-between p-7 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 rounded-t-2xl shadow-sm flex-shrink-0">
<h3 className="font-bold text-gray-900 dark:text-white mb-1">Permission Required</h3>
{onClose && (
<button
className={buttonClasses('icon')}
onClick={onClose}
aria-label="Close drawer"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2 2L14 14M2 14L14 2"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
</button>
)}
</div>
<div className="text-lg text-gray-900 dark:text-white flex flex-col min-h-0 z-10 flex-1 overflow-y-auto p-0 min-h-0">
<PermissionRequest
options={options}
toolCall={toolCall}
onResponse={onResponse}
/>
</div>
</div>
</>
);
};

View File

@@ -0,0 +1,111 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*
* Demo page showing how to use Tailwind components alongside existing CSS
* This demonstrates the progressive adoption approach
*/
import type React from 'react';
import { Button } from './ui/Button';
import { Card } from './ui/Card';
/**
* Demo component showing how to use Tailwind components
* alongside existing CSS-based components
*/
export const TailwindDemo: React.FC = () => {
return (
<div className="p-4 max-w-2xl mx-auto">
<h1 className="text-2xl font-bold mb-6 text-gray-900 dark:text-white">
Tailwind CSS Progressive Adoption Demo
</h1>
<p className="mb-6 text-gray-700 dark:text-gray-300">
This page demonstrates how to gradually adopt Tailwind CSS in an existing project
while maintaining compatibility with existing CSS styles.
</p>
{/* Example 1: Using new Tailwind components */}
<Card className="mb-6">
<Card.Header>
<h2 className="text-xl font-semibold">New Components with Tailwind</h2>
</Card.Header>
<Card.Content>
<p className="mb-4 text-gray-600 dark:text-gray-400">
These are new components built with Tailwind CSS:
</p>
<div className="flex flex-wrap gap-3">
<Button variant="primary">Primary Button</Button>
<Button variant="secondary">Secondary Button</Button>
<Button variant="ghost">Ghost Button</Button>
</div>
</Card.Content>
</Card>
{/* Example 2: Hybrid approach - mixing Tailwind with existing styles */}
<div className="permission-request-card mb-6 p-4 rounded-lg border border-gray-200 dark:border-gray-700">
<h2 className="text-xl font-semibold mb-4">Hybrid Approach</h2>
<p className="mb-4 text-gray-600 dark:text-gray-400">
This card uses existing CSS classes but enhances them with Tailwind utilities:
</p>
<div className="flex flex-wrap gap-3">
<button className="permission-confirm-button bg-qwen-orange hover:bg-qwen-clay-orange text-qwen-ivory px-4 py-2 rounded">
Enhanced Button
</button>
<button className="permission-option bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700 px-4 py-2 rounded">
Hybrid Option
</button>
</div>
</div>
{/* Example 3: Utility-first approach */}
<div className="mb-6 p-6 bg-white dark:bg-gray-800 rounded-lg shadow-md border border-gray-200 dark:border-gray-700">
<h2 className="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Utility-First Approach</h2>
<p className="mb-4 text-gray-600 dark:text-gray-400">
This section uses Tailwind's utility-first approach:
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<h3 className="font-medium text-blue-800 dark:text-blue-200">Feature 1</h3>
<p className="mt-2 text-sm text-blue-600 dark:text-blue-300">
Description of feature 1
</p>
</div>
<div className="p-4 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800">
<h3 className="font-medium text-green-800 dark:text-green-200">Feature 2</h3>
<p className="mt-2 text-sm text-green-600 dark:text-green-300">
Description of feature 2
</p>
</div>
<div className="p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg border border-purple-200 dark:border-purple-800">
<h3 className="font-medium text-purple-800 dark:text-purple-200">Feature 3</h3>
<p className="mt-2 text-sm text-purple-600 dark:text-purple-300">
Description of feature 3
</p>
</div>
</div>
</div>
{/* Example 4: Responsive design */}
<div className="p-6 bg-gradient-to-r from-qwen-orange to-qwen-clay-orange rounded-lg text-white">
<h2 className="text-xl font-semibold mb-2">Responsive Design</h2>
<p className="mb-4 opacity-90">
Tailwind makes responsive design easy with breakpoint prefixes:
</p>
<div className="flex flex-col sm:flex-row gap-4">
<div className="flex-1 p-4 bg-black/10 rounded">
<p className="text-center">Column 1</p>
</div>
<div className="flex-1 p-4 bg-black/10 rounded">
<p className="text-center">Column 2</p>
</div>
<div className="flex-1 p-4 bg-black/10 rounded">
<p className="text-center">Column 3</p>
</div>
</div>
</div>
</div>
);
};