Skip to content

Commit 0ab5867

Browse files
committed
Improve settings UI: Convert tabs to vertical layout and enhance note styling
1 parent a182d92 commit 0ab5867

12 files changed

Lines changed: 886 additions & 54 deletions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import { Form, Card, Alert, Spin } from 'antd';
3+
import styled from 'styled-components';
4+
5+
const StyledCard = styled(Card)`
6+
margin-bottom: 1rem;
7+
border: none;
8+
box-shadow: none;
9+
`;
10+
11+
interface BaseSettingsPanelProps {
12+
title?: string;
13+
loading: boolean;
14+
error: Error | null;
15+
children: React.ReactNode;
16+
}
17+
18+
const BaseSettingsPanel: React.FC<BaseSettingsPanelProps> = ({
19+
title,
20+
loading,
21+
error,
22+
children,
23+
}) => {
24+
return (
25+
<StyledCard title={title}>
26+
{error && (
27+
<Alert
28+
message="Error"
29+
description={error.message}
30+
type="error"
31+
showIcon
32+
style={{ marginBottom: '1rem' }}
33+
/>
34+
)}
35+
36+
<Spin spinning={loading}>
37+
{children}
38+
</Spin>
39+
</StyledCard>
40+
);
41+
};
42+
43+
export default BaseSettingsPanel;

src/components/settings/GeneralSettings.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,15 @@ const GeneralSettings: React.FC = () => {
161161
</Form.Item>
162162

163163
<Form.Item>
164-
<p style={{ color: 'rgba(0, 0, 0, 0.45)' }}>
165-
Note: Changing these settings may require a restart of the relay server to take effect.
164+
<p style={{
165+
color: 'rgba(255, 255, 255, 0.8)',
166+
fontSize: '0.9em',
167+
padding: '0.75rem',
168+
backgroundColor: 'rgba(0, 0, 0, 0.1)',
169+
borderLeft: '3px solid rgba(82, 196, 255, 0.8)',
170+
borderRadius: '0 4px 4px 0'
171+
}}>
172+
<span style={{ color: 'rgba(82, 196, 255, 1)' }}>Note:</span> Changing these settings may require a restart of the relay server to take effect.
166173
The private key should be kept secure and not shared with others.
167174
</p>
168175
</Form.Item>

src/components/settings/QueryCacheSettings.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,15 @@ const QueryCacheSettings: React.FC = () => {
202202
</Form.Item>
203203

204204
<Form.Item>
205-
<p style={{ color: 'rgba(0, 0, 0, 0.45)' }}>
206-
Note: These settings affect how the relay caches query results. Improper configuration may impact performance.
205+
<p style={{
206+
color: 'rgba(255, 255, 255, 0.8)',
207+
fontSize: '0.9em',
208+
padding: '0.75rem',
209+
backgroundColor: 'rgba(0, 0, 0, 0.1)',
210+
borderLeft: '3px solid rgba(82, 196, 255, 0.8)',
211+
borderRadius: '0 4px 4px 0'
212+
}}>
213+
<span style={{ color: 'rgba(82, 196, 255, 1)' }}>Note:</span> These settings affect how the relay caches query results. Improper configuration may impact performance.
207214
Consult the documentation for recommended values.
208215
</p>
209216
</Form.Item>

src/components/settings/RelayInfoSettings.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,15 @@ const RelayInfoSettings: React.FC = () => {
218218
</Form.Item>
219219

220220
<Form.Item>
221-
<p style={{ color: 'rgba(0, 0, 0, 0.45)' }}>
222-
Note: This information will be publicly available to clients connecting to your relay.
221+
<p style={{
222+
color: 'rgba(255, 255, 255, 0.8)',
223+
fontSize: '0.9em',
224+
padding: '0.75rem',
225+
backgroundColor: 'rgba(0, 0, 0, 0.1)',
226+
borderLeft: '3px solid rgba(82, 196, 255, 0.8)',
227+
borderRadius: '0 4px 4px 0'
228+
}}>
229+
<span style={{ color: 'rgba(82, 196, 255, 1)' }}>Note:</span> This information will be publicly available to clients connecting to your relay.
223230
It helps users understand the capabilities and ownership of your relay.
224231
</p>
225232
</Form.Item>

src/components/settings/SettingsNavigation.tsx

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import React from 'react';
2-
import { Tabs } from 'antd';
1+
import React, { useState, useEffect } from 'react';
2+
import { Collapse } from 'antd';
33
import { useNavigate, useLocation } from 'react-router-dom';
44
import styled from 'styled-components';
55
import {
6-
SettingOutlined,
76
FilterOutlined,
87
PictureOutlined,
98
ApiOutlined,
@@ -15,10 +14,51 @@ import {
1514
DatabaseOutlined
1615
} from '@ant-design/icons';
1716

18-
const { TabPane } = Tabs;
17+
const { Panel } = Collapse;
1918

20-
const StyledTabs = styled(Tabs)`
19+
const StyledCollapse = styled(Collapse)`
2120
margin-bottom: 1.5rem;
21+
22+
.ant-collapse-header {
23+
display: flex;
24+
align-items: center;
25+
padding: 12px 16px !important;
26+
27+
.ant-collapse-arrow {
28+
right: 16px;
29+
left: auto !important;
30+
}
31+
}
32+
33+
.ant-collapse-content-box {
34+
padding: 0 !important;
35+
}
36+
37+
.panel-icon {
38+
margin-right: 12px;
39+
font-size: 16px;
40+
}
41+
`;
42+
43+
const NavigationItem = styled.div`
44+
padding: 12px 16px;
45+
cursor: pointer;
46+
transition: all 0.3s;
47+
display: flex;
48+
align-items: center;
49+
50+
&:hover {
51+
background-color: rgba(255, 255, 255, 0.1);
52+
}
53+
54+
&.active {
55+
background-color: rgba(255, 255, 255, 0.05);
56+
}
57+
58+
.item-icon {
59+
margin-right: 12px;
60+
font-size: 16px;
61+
}
2262
`;
2363

2464
interface SettingsTab {
@@ -32,95 +72,104 @@ const settingsTabs: SettingsTab[] = [
3272
{
3373
key: 'image_moderation',
3474
label: 'Image Moderation',
35-
icon: <PictureOutlined />,
75+
icon: <PictureOutlined className="item-icon" />,
3676
path: '/settings/image-moderation'
3777
},
3878
{
3979
key: 'content_filter',
4080
label: 'Content Filter',
41-
icon: <FilterOutlined />,
81+
icon: <FilterOutlined className="item-icon" />,
4282
path: '/settings/content-filter'
4383
},
4484
{
4585
key: 'nest_feeder',
4686
label: 'Nest Feeder',
47-
icon: <ApiOutlined />,
87+
icon: <ApiOutlined className="item-icon" />,
4888
path: '/settings/nest-feeder'
4989
},
5090
{
5191
key: 'ollama',
5292
label: 'Ollama',
53-
icon: <RobotOutlined />,
93+
icon: <RobotOutlined className="item-icon" />,
5494
path: '/settings/ollama'
5595
},
5696
{
5797
key: 'xnostr',
5898
label: 'XNostr',
59-
icon: <TwitterOutlined />,
99+
icon: <TwitterOutlined className="item-icon" />,
60100
path: '/settings/xnostr'
61101
},
62102
{
63103
key: 'relay_info',
64104
label: 'Relay Info',
65-
icon: <InfoCircleOutlined />,
105+
icon: <InfoCircleOutlined className="item-icon" />,
66106
path: '/settings/relay-info'
67107
},
68108
{
69109
key: 'wallet',
70110
label: 'Wallet',
71-
icon: <WalletOutlined />,
111+
icon: <WalletOutlined className="item-icon" />,
72112
path: '/settings/wallet'
73113
},
74114
{
75115
key: 'general',
76116
label: 'General',
77-
icon: <GlobalOutlined />,
117+
icon: <GlobalOutlined className="item-icon" />,
78118
path: '/settings/general'
79119
},
80120
{
81121
key: 'query_cache',
82122
label: 'Query Cache',
83-
icon: <DatabaseOutlined />,
123+
icon: <DatabaseOutlined className="item-icon" />,
84124
path: '/settings/query-cache'
85125
}
86126
];
87127

88128
const SettingsNavigation: React.FC = () => {
89129
const navigate = useNavigate();
90130
const location = useLocation();
131+
const [activeKey, setActiveKey] = useState<string | undefined>(undefined);
91132

92133
// Determine active tab based on current path
93-
const getActiveKey = () => {
134+
useEffect(() => {
94135
const path = location.pathname;
95136
const tab = settingsTabs.find(tab => tab.path === path);
96-
return tab ? tab.key : 'general';
97-
};
98-
99-
const handleTabChange = (key: string) => {
100-
const tab = settingsTabs.find(tab => tab.key === key);
101137
if (tab) {
102-
navigate(tab.path);
138+
setActiveKey(tab.key);
103139
}
140+
}, [location.pathname]);
141+
142+
const handleItemClick = (tab: SettingsTab) => {
143+
navigate(tab.path);
144+
setActiveKey(tab.key);
104145
};
105146

106147
return (
107-
<StyledTabs
108-
activeKey={getActiveKey()}
109-
onChange={handleTabChange}
110-
type="card"
111-
size="large"
148+
<StyledCollapse
149+
accordion
150+
expandIconPosition="end"
151+
ghost
152+
activeKey={activeKey}
153+
onChange={(key) => setActiveKey(key as string | undefined)}
112154
>
113155
{settingsTabs.map(tab => (
114-
<TabPane
115-
tab={
156+
<Panel
157+
key={tab.key}
158+
header={
116159
<span>
117-
{tab.icon} {tab.label}
160+
{React.cloneElement(tab.icon as React.ReactElement, { className: 'panel-icon' })} {tab.label}
118161
</span>
119162
}
120-
key={tab.key}
121-
/>
163+
>
164+
<NavigationItem
165+
className={activeKey === tab.key ? 'active' : ''}
166+
onClick={() => handleItemClick(tab)}
167+
>
168+
{tab.label}
169+
</NavigationItem>
170+
</Panel>
122171
))}
123-
</StyledTabs>
172+
</StyledCollapse>
124173
);
125174
};
126175

0 commit comments

Comments
 (0)