补充css修改
This commit is contained in:
@@ -14,9 +14,7 @@ function App() {
|
||||
{/* 主内容容器 */}
|
||||
<div className="main-container">
|
||||
{/* 左侧栏 - 预设面板 */}
|
||||
<div className="sidebar-left">
|
||||
<SideBarLeft />
|
||||
</div>
|
||||
|
||||
{/* 中间栏:聊天框 */}
|
||||
<div className="chat-area">
|
||||
@@ -24,9 +22,7 @@ function App() {
|
||||
</div>
|
||||
|
||||
{/* 右侧栏 */}
|
||||
<div className="sidebar-right">
|
||||
<SideBarRight />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
16
frontend-react/src/Store/Slices/SideBarLeftSlice.jsx
Normal file
16
frontend-react/src/Store/Slices/SideBarLeftSlice.jsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
const useSideBarLeftStore = create((set) => ({
|
||||
activeTab: 'gallery',
|
||||
|
||||
tabs: [
|
||||
{ id: 'gallery', label: '🖼️ 画廊' },
|
||||
{ id: 'api', label: '🔌 API' },
|
||||
{ id: 'presets', label: '📋 预设' },
|
||||
{ id: 'worldbook', label: '🌍 世界书' }
|
||||
],
|
||||
|
||||
setActiveTab: (tab) => set({ activeTab: tab })
|
||||
}));
|
||||
|
||||
export default useSideBarLeftStore;
|
||||
34
frontend-react/src/Store/Slices/SideBarRightSlice.jsx
Normal file
34
frontend-react/src/Store/Slices/SideBarRightSlice.jsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
const useSideBarRightStore = create((set) => ({
|
||||
selectedTabs: ['dice', 'macros'],
|
||||
|
||||
allTabs: [
|
||||
{ id: 'dice', label: '🎲 骰子与工具', component: null },
|
||||
{ id: 'debug', label: '🔍 上下文调试', component: null },
|
||||
{ id: 'macros', label: '🔧 快捷宏', component: null },
|
||||
{ id: 'table', label: '📊 动态表格', component: null }
|
||||
],
|
||||
|
||||
handleTabClick: (tabId) => set((state) => {
|
||||
if (state.selectedTabs.includes(tabId)) {
|
||||
// 如果已选中,则取消选中
|
||||
return { selectedTabs: state.selectedTabs.filter(id => id !== tabId) };
|
||||
} else if (state.selectedTabs.length < 2) {
|
||||
// 如果未选中且少于2个,则添加
|
||||
return { selectedTabs: [...state.selectedTabs, tabId] };
|
||||
} else {
|
||||
// 如果已有2个,则替换最早选中的
|
||||
return { selectedTabs: [...state.selectedTabs.slice(1), tabId] };
|
||||
}
|
||||
}),
|
||||
|
||||
// 设置特定标签的组件
|
||||
setTabComponent: (tabId, component) => set((state) => ({
|
||||
allTabs: state.allTabs.map(tab =>
|
||||
tab.id === tabId ? { ...tab, component } : tab
|
||||
)
|
||||
}))
|
||||
}));
|
||||
|
||||
export default useSideBarRightStore;
|
||||
@@ -1,2 +1,5 @@
|
||||
// frontend-react/src/store/index.js
|
||||
export { default as useRoleSelectorStore } from './roleSelectorStore';
|
||||
export { default as useRoleSelectorStore } from './Slices/RoleSelectorSlice';
|
||||
export { default as useSideBarLeftStore } from './Slices/SideBarLeftSlice';
|
||||
export { default as useSideBarRightStore } from './Slices/SideBarRightSlice';
|
||||
export { default as useChatBoxStore } from './Slices/ChatBoxSlice';
|
||||
@@ -145,7 +145,7 @@
|
||||
flex-direction: column;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
overflow: hidden;
|
||||
min-height: 140px;
|
||||
height: 200px; /* 设置固定高度 */
|
||||
position: relative;
|
||||
/* 添加微妙的边框效果 */
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
@@ -167,7 +167,8 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
flex: 0 0 auto; /* 不再自动伸缩,使用固定高度 */
|
||||
height: 60px; /* 设置固定高度 */
|
||||
}
|
||||
|
||||
.role-header .role-name {
|
||||
@@ -177,12 +178,16 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 80%; /* 限制名称最大宽度 */
|
||||
}
|
||||
|
||||
|
||||
.role-item.active .role-header .role-name {
|
||||
color: #667eea;
|
||||
font-size: 16px; /* 激活状态时字体稍大 */
|
||||
}
|
||||
|
||||
|
||||
.role-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
@@ -191,8 +196,10 @@
|
||||
right: 12px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
z-index: 10; /* 确保操作按钮在最上层 */
|
||||
}
|
||||
|
||||
|
||||
.role-item:hover .role-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -227,13 +234,17 @@
|
||||
border-top: 1px solid #f0f0f0;
|
||||
padding: 8px 0;
|
||||
background-color: #fafbfc;
|
||||
max-height: 140px;
|
||||
height: 120px; /* 设置固定高度 */
|
||||
overflow-y: auto;
|
||||
/* 自定义滚动条样式 */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cbd5e1 transparent;
|
||||
flex: 1; /* 让聊天列表占据剩余空间 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
/* Webkit浏览器滚动条样式 */
|
||||
.chat-list::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
|
||||
@@ -1,42 +1,91 @@
|
||||
/* frontend-react/src/components/SideBarLeft/SideBarLeft.css */
|
||||
.sidebar-left {
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05);
|
||||
border-right: 1px solid #e8e8e8;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
background-color: #fafafa;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
flex: 1;
|
||||
padding: 10px 5px;
|
||||
padding: 12px 5px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.tab-button:hover {
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tab-button.active {
|
||||
border-bottom: 2px solid #4a90e2;
|
||||
font-weight: bold;
|
||||
color: #4a90e2;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab-button.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background-color: #4a90e2;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
.sidebar-content::-webkit-scrollbar,
|
||||
.tab-content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.sidebar-content::-webkit-scrollbar-track,
|
||||
.tab-content::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.sidebar-content::-webkit-scrollbar-thumb,
|
||||
.tab-content::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.sidebar-content::-webkit-scrollbar-thumb:hover,
|
||||
.tab-content::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
// frontend-react/src/components/SideBarLeft/SideBarLeft.jsx
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import './SideBarLeft.css';
|
||||
import { useSideBarLeftStore } from '../../Store/indexStore';
|
||||
import useSideBarRightStore from '../../Store/Slices/SideBarLeftSlice';
|
||||
|
||||
const SideBarLeft = () => {
|
||||
const [activeTab, setActiveTab] = useState('gallery');
|
||||
|
||||
const handleTabChange = (tab) => {
|
||||
setActiveTab(tab);
|
||||
};
|
||||
const { activeTab, tabs, setActiveTab } = useSideBarLeftStore();
|
||||
|
||||
return (
|
||||
<div className="sidebar-left">
|
||||
<div className="sidebar-tabs">
|
||||
<button
|
||||
className={`tab-button ${activeTab === 'gallery' ? 'active' : ''}`}
|
||||
onClick={() => handleTabChange('gallery')}
|
||||
>
|
||||
🖼️ 画廊
|
||||
</button>
|
||||
<button
|
||||
className={`tab-button ${activeTab === 'config' ? 'active' : ''}`}
|
||||
onClick={() => handleTabChange('config')}
|
||||
>
|
||||
⚙️ 配置
|
||||
</button>
|
||||
<button
|
||||
className={`tab-button ${activeTab === 'worldbook' ? 'active' : ''}`}
|
||||
onClick={() => handleTabChange('worldbook')}
|
||||
>
|
||||
🌍 世界书
|
||||
</button>
|
||||
{tabs.map(tab => (
|
||||
<button
|
||||
key={tab.id}
|
||||
className={`tab-button ${activeTab === tab.id ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="sidebar-content">
|
||||
{activeTab === 'gallery' && <div className="tab-content">画廊内容</div>}
|
||||
{activeTab === 'config' && <div className="tab-content">配置内容</div>}
|
||||
{activeTab === 'api' && <div className="tab-content">API配置内容</div>}
|
||||
{activeTab === 'presets' && <div className="tab-content">预设配置内容</div>}
|
||||
{activeTab === 'worldbook' && <div className="tab-content">世界书内容</div>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,56 +1,102 @@
|
||||
/* frontend-react/src/components/SideBarRight/SideBarRight.css */
|
||||
.sidebar-right {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.right-top, .right-bottom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.right-top {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.right-bottom {
|
||||
height: 200px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.05);
|
||||
border-left: 1px solid #e8e8e8;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
flex-shrink: 0;
|
||||
background-color: #fafafa;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
flex: 1;
|
||||
padding: 10px 5px;
|
||||
padding: 12px 5px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.tab-button:hover {
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tab-button.active {
|
||||
border-bottom: 2px solid #4a90e2;
|
||||
font-weight: bold;
|
||||
color: #4a90e2;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab-button.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background-color: #4a90e2;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
|
||||
.tab-content:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tab-content.full-height {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
.sidebar-content::-webkit-scrollbar,
|
||||
.tab-content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.sidebar-content::-webkit-scrollbar-track,
|
||||
.tab-content::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.sidebar-content::-webkit-scrollbar-thumb,
|
||||
.tab-content::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.sidebar-content::-webkit-scrollbar-thumb:hover,
|
||||
.tab-content::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +1,41 @@
|
||||
// frontend-react/src/components/SideBarRight/SideBarRight.jsx
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import './SideBarRight.css';
|
||||
import DicePanel from '../DicePanel/DicePanel';
|
||||
import ImageDisplay from '../ImageDisplay/ImageDisplay';
|
||||
import useSideBarRightStore from '../../Store/Slices/SideBarRightSlice';
|
||||
|
||||
const SideBarRight = () => {
|
||||
const [topActiveTab, setTopActiveTab] = useState('dice');
|
||||
const [bottomActiveTab, setBottomActiveTab] = useState('macros');
|
||||
const { selectedTabs, allTabs, handleTabClick, setTabComponent } = useSideBarRightStore();
|
||||
|
||||
const handleTopTabChange = (tab) => {
|
||||
setTopActiveTab(tab);
|
||||
};
|
||||
|
||||
const handleBottomTabChange = (tab) => {
|
||||
setBottomActiveTab(tab);
|
||||
};
|
||||
// 设置标签组件
|
||||
useEffect(() => {
|
||||
setTabComponent('dice', DicePanel);
|
||||
// 可以在这里设置其他标签的组件
|
||||
}, [setTabComponent]);
|
||||
|
||||
return (
|
||||
<div className="sidebar-right">
|
||||
<div className="right-top">
|
||||
<div className="sidebar-tabs">
|
||||
<div className="sidebar-tabs">
|
||||
{allTabs.map(tab => (
|
||||
<button
|
||||
className={`tab-button ${topActiveTab === 'dice' ? 'active' : ''}`}
|
||||
onClick={() => handleTopTabChange('dice')}
|
||||
key={tab.id}
|
||||
className={`tab-button ${selectedTabs.includes(tab.id) ? 'active' : ''}`}
|
||||
onClick={() => handleTabClick(tab.id)}
|
||||
>
|
||||
🎲 骰子与工具
|
||||
{tab.label}
|
||||
</button>
|
||||
<button
|
||||
className={`tab-button ${topActiveTab === 'debug' ? 'active' : ''}`}
|
||||
onClick={() => handleTopTabChange('debug')}
|
||||
>
|
||||
🔍 上下文调试
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="sidebar-content">
|
||||
{topActiveTab === 'dice' && <DicePanel />}
|
||||
{topActiveTab === 'debug' && <div className="tab-content">上下文调试内容</div>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="right-bottom">
|
||||
<div className="sidebar-tabs">
|
||||
<button
|
||||
className={`tab-button ${bottomActiveTab === 'macros' ? 'active' : ''}`}
|
||||
onClick={() => handleBottomTabChange('macros')}
|
||||
>
|
||||
🔧 快捷宏
|
||||
</button>
|
||||
<button
|
||||
className={`tab-button ${bottomActiveTab === 'table' ? 'active' : ''}`}
|
||||
onClick={() => handleBottomTabChange('table')}
|
||||
>
|
||||
📊 动态表格
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="sidebar-content">
|
||||
{bottomActiveTab === 'macros' && <div className="tab-content">快捷宏内容</div>}
|
||||
{bottomActiveTab === 'table' && <div className="tab-content">动态表格内容</div>}
|
||||
</div>
|
||||
<div className="sidebar-content">
|
||||
{selectedTabs.map(tabId => {
|
||||
const tab = allTabs.find(t => t.id === tabId);
|
||||
return (
|
||||
<div key={tabId} className={`tab-content ${selectedTabs.length === 1 ? 'full-height' : ''}`}>
|
||||
{tab.component ? <tab.component /> : <div className="tab-content">{tab.label}内容</div>}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ const Toolbar = () => {
|
||||
<div className="toolbar-icons">
|
||||
<div
|
||||
className="toolbar-icon"
|
||||
title="当前角色"
|
||||
title="玩家角色"
|
||||
onClick={() => handlePanelToggle('currentRole')}
|
||||
>
|
||||
👤
|
||||
@@ -82,11 +82,11 @@ const Toolbar = () => {
|
||||
<div className="toolbar-icons">
|
||||
<div
|
||||
className={`toolbar-icon ${activePanel === 'role' ? 'active' : ''}`}
|
||||
title="角色管理"
|
||||
title="ai角色"
|
||||
onClick={() => handlePanelToggle('role')}
|
||||
>
|
||||
🎭
|
||||
<span className="icon-label">全局世界书</span>
|
||||
<span className="icon-label">角色管理</span>
|
||||
</div>
|
||||
<div className="toolbar-display-box">
|
||||
{truncateText(getDisplayText())}
|
||||
|
||||
@@ -1,76 +1,21 @@
|
||||
/* frontend-react/src/index.css */
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 重置样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body, .app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 左侧栏 */
|
||||
.sidebar-left {
|
||||
width: 250px;
|
||||
width: 22.5%; /* 修改为30% */
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 中间聊天区域 */
|
||||
.chat-area {
|
||||
flex: 1;
|
||||
flex: 55%; /* 修改为0.4 */
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 右侧栏 */
|
||||
.sidebar-right {
|
||||
width: 300px;
|
||||
width: 22.5%; /* 修改为30% */
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
height: 60px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user