Skip to content

Improve sidebar UX #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 66 additions & 40 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import ChartContainer from './components/ChartContainer';
import { ComparisonControls } from './components/ComparisonControls';
import { Header } from './components/Header';
import { FileConfigModal } from './components/FileConfigModal';
import CollapsibleSection from './components/CollapsibleSection';
import { ChevronLeft, ChevronRight } from 'lucide-react';

function App() {
const [uploadedFiles, setUploadedFiles] = useState([]);

const [sidebarVisible, setSidebarVisible] = useState(true);

// 全局解析配置状态
const [globalParsingConfig, setGlobalParsingConfig] = useState({
Expand Down Expand Up @@ -231,17 +235,25 @@ function App() {
)}

<div className="w-full px-3 py-3">
<main

<main
id="main-content"
className="grid grid-cols-1 xl:grid-cols-5 gap-3"
className="grid grid-cols-1 xl:grid-cols-5 gap-3 h-[calc(100vh-2rem)]"
role="main"
>
<aside
className="xl:col-span-1 space-y-3"
role="complementary"
aria-label="控制面板"
>
{sidebarVisible && (
<aside
className="xl:col-span-1 space-y-3 overflow-y-auto pr-2"
role="complementary"
aria-label="控制面板"
>
<button
onClick={() => setSidebarVisible(false)}
className="absolute -right-3 top-3 bg-white border rounded-r px-1 py-0.5 shadow"
aria-label="隐藏侧边栏"
>
<ChevronLeft size={14} />
</button>
{/* 标题信息 */}
<div className="bg-white rounded-lg shadow-md p-3">
<div className="flex items-center gap-2 mb-2">
Expand Down Expand Up @@ -282,38 +294,43 @@ function App() {
</div>
</div>

<FileUpload onFilesUploaded={handleFilesUploaded} />

<RegexControls
globalParsingConfig={globalParsingConfig}
onGlobalParsingConfigChange={handleGlobalParsingConfigChange}
uploadedFiles={uploadedFiles}
xRange={xRange}
onXRangeChange={setXRange}
maxStep={maxStep}
/>

<FileList
files={uploadedFiles}
onFileRemove={handleFileRemove}
onFileToggle={handleFileToggle}
onFileConfig={handleFileConfig}
/>
<CollapsibleSection id="file-list" title="📋 已加载文件" defaultCollapsed={false}>
<FileList
files={uploadedFiles}
onFileRemove={handleFileRemove}
onFileToggle={handleFileToggle}
onFileConfig={handleFileConfig}
showTitle={false}
/>
</CollapsibleSection>

{uploadedFiles.filter(file => file.enabled).length === 2 && (
<ComparisonControls
compareMode={compareMode}
onCompareModeChange={setCompareMode}
<CollapsibleSection id="file-upload" title="📁 文件上传" defaultCollapsed={true}>
<FileUpload onFilesUploaded={handleFilesUploaded} showTitle={false} />
</CollapsibleSection>

<CollapsibleSection id="regex-controls" title="⚙️ 数据解析配置" defaultCollapsed={true}>
<RegexControls
globalParsingConfig={globalParsingConfig}
onGlobalParsingConfigChange={handleGlobalParsingConfigChange}
uploadedFiles={uploadedFiles}
xRange={xRange}
onXRangeChange={setXRange}
maxStep={maxStep}
showTitle={false}
/>
</CollapsibleSection>

{uploadedFiles.filter(file => file.enabled).length === 2 && (
<CollapsibleSection id="comparison-controls" title="⚖️ 对比模式" defaultCollapsed={true}>
<ComparisonControls
compareMode={compareMode}
onCompareModeChange={setCompareMode}
showTitle={false}
/>
</CollapsibleSection>
)}

<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="display-options-heading">
<h3
id="display-options-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
🎛️ 显示选项
</h3>
<CollapsibleSection id="display-options-heading" title="🎛️ 显示选项" defaultCollapsed={true}>
<div className="space-y-3">
<div>
<h4 className="text-xs font-medium text-gray-700 mb-2">📊 图表显示</h4>
Expand Down Expand Up @@ -375,11 +392,11 @@ function App() {
</div>
</div>
</div>
</section>
</aside>
</CollapsibleSection>
</aside>)}

<section
className="xl:col-span-4"
<section
className={`${sidebarVisible ? 'xl:col-span-4' : 'xl:col-span-5'} overflow-y-auto`}
role="region"
aria-label="图表显示区域"
>
Expand All @@ -395,6 +412,15 @@ function App() {
/>
</section>
</main>
{!sidebarVisible && (
<button
onClick={() => setSidebarVisible(true)}
className="fixed left-0 top-1/2 -translate-y-1/2 bg-white border rounded-r px-1 py-0.5 shadow z-10"
aria-label="显示侧边栏"
>
<ChevronRight size={14} />
</button>
)}
</div>

<FileConfigModal
Expand Down
27 changes: 27 additions & 0 deletions src/components/CollapsibleSection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useState } from 'react';
import { ChevronDown, ChevronRight } from 'lucide-react';

export default function CollapsibleSection({ id, title, defaultCollapsed = false, children }) {
const [collapsed, setCollapsed] = useState(defaultCollapsed);

return (
<section className="bg-white rounded-lg shadow-md" aria-labelledby={id}>
<header className="flex items-center justify-between p-3">
<h3 id={id} className="text-base font-semibold text-gray-800">
{title}
</h3>
<button
onClick={() => setCollapsed(!collapsed)}
className="text-gray-600 hover:text-gray-800 focus:outline-none"
aria-expanded={!collapsed}
aria-controls={`${id}-content`}
>
{collapsed ? <ChevronRight size={16} /> : <ChevronDown size={16} />}
</button>
</header>
<div id={`${id}-content`} className={`${collapsed ? 'hidden' : 'p-3 border-t'}`}>
{children}
</div>
</section>
);
}
35 changes: 19 additions & 16 deletions src/components/ComparisonControls.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import { BarChart2 } from 'lucide-react';

export function ComparisonControls({
compareMode,
onCompareModeChange
export function ComparisonControls({
compareMode,
onCompareModeChange,
showTitle = true
}) {
const modes = [
{ value: 'normal', label: '📊 Normal', description: '原始差值' },
Expand All @@ -13,19 +14,21 @@ export function ComparisonControls({

return (
<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="comparison-controls-heading">
<div className="flex items-center gap-2 mb-2">
<BarChart2
size={16}
className="text-gray-600"
aria-hidden="true"
/>
<h3
id="comparison-controls-heading"
className="text-base font-semibold text-gray-800"
>
⚖️ 对比模式
</h3>
</div>
{showTitle && (
<div className="flex items-center gap-2 mb-2">
<BarChart2
size={16}
className="text-gray-600"
aria-hidden="true"
/>
<h3
id="comparison-controls-heading"
className="text-base font-semibold text-gray-800"
>
⚖️ 对比模式
</h3>
</div>
)}

<fieldset className="space-y-2">
<legend className="sr-only">选择数据对比模式</legend>
Expand Down
30 changes: 17 additions & 13 deletions src/components/FileList.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import React from 'react';
import { FileText, X, Settings } from 'lucide-react';

export function FileList({ files, onFileRemove, onFileToggle, onFileConfig }) {
export function FileList({ files, onFileRemove, onFileToggle, onFileConfig, showTitle = true }) {
if (files.length === 0) {
return (
<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="file-list-heading">
<h3
id="file-list-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
📋 已加载文件
</h3>
{showTitle && (
<h3
id="file-list-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
📋 已加载文件
</h3>
)}
<p className="text-gray-500 text-center py-4 text-sm" role="status">
📂 暂无文件
</p>
Expand All @@ -20,12 +22,14 @@ export function FileList({ files, onFileRemove, onFileToggle, onFileConfig }) {

return (
<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="file-list-heading">
<h3
id="file-list-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
📋 已加载文件 ({files.length})
</h3>
{showTitle && (
<h3
id="file-list-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
📋 已加载文件 ({files.length})
</h3>
)}
<ul className="space-y-2" role="list" aria-label={`已加载 ${files.length} 个文件`}>
{files.map((file, index) => (
<li
Expand Down
16 changes: 9 additions & 7 deletions src/components/FileUpload.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useCallback, useState } from 'react';
import { Upload, FileText } from 'lucide-react';

export function FileUpload({ onFilesUploaded }) {
export function FileUpload({ onFilesUploaded, showTitle = true }) {
const [isDragOver, setIsDragOver] = useState(false);

const processFiles = useCallback((files) => {
Expand Down Expand Up @@ -64,12 +64,14 @@ export function FileUpload({ onFilesUploaded }) {

return (
<div className="bg-white rounded-lg shadow-md p-3">
<h3
id="file-upload-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
📁 文件上传
</h3>
{showTitle && (
<h3
id="file-upload-heading"
className="text-base font-semibold text-gray-800 mb-2"
>
📁 文件上传
</h3>
)}
<div
className={`drag-area border-2 border-dashed rounded-lg p-4 text-center cursor-pointer ${
isDragOver ? 'border-blue-500 bg-blue-50' : 'border-gray-300 hover:border-gray-400'
Expand Down
35 changes: 19 additions & 16 deletions src/components/RegexControls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ export function RegexControls({
uploadedFiles = [],
xRange,
onXRangeChange,
maxStep
maxStep,
showTitle = true
}) {
const [showPreview, setShowPreview] = useState(false);
const [previewResults, setPreviewResults] = useState({});
Expand Down Expand Up @@ -413,20 +414,21 @@ export function RegexControls({

return (
<section className="bg-white rounded-lg shadow-md p-3" aria-labelledby="regex-controls-heading">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Settings
size={16}
className="text-gray-600"
aria-hidden="true"
/>
<h3
id="regex-controls-heading"
className="text-base font-semibold text-gray-800"
>
数据解析配置
</h3>
</div>
{showTitle && (
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Settings
size={16}
className="text-gray-600"
aria-hidden="true"
/>
<h3
id="regex-controls-heading"
className="text-base font-semibold text-gray-800"
>
数据解析配置
</h3>
</div>

<div className="flex items-center gap-1">
{uploadedFiles.length > 0 && (
Expand All @@ -446,7 +448,8 @@ export function RegexControls({
<Eye size={14} />
</button>
</div>
</div>
</div>
)}

<div className="space-y-4">
{globalParsingConfig.metrics.map((cfg, idx) => (
Expand Down