chore(ui): polish empty states + sidebar icon + i18n page titles

- AppSidebar: switch the inbounds icon from UserOutlined (a single
  person — wrong semantic) to ImportOutlined, matching the empty-state
  icon and reflecting the actual concept of an incoming entry point.
- usePageTitle: stop hardcoding English titles; resolve them through
  i18n (menu.* keys are already translated), so the browser tab now
  follows the active language.
- InboundList / NodeList: replace the bare "—" empty cell with a
  centered icon + t('noData') message (ImportOutlined for inbounds,
  ClusterOutlined for nodes), and swap opacity:0.4 for
  var(--ant-color-text-secondary) so the text stays readable on the
  light theme's tinted card background.
This commit is contained in:
MHSanaei
2026-05-27 15:06:57 +02:00
parent 2bba1d21d2
commit 6286bb8676
6 changed files with 54 additions and 20 deletions
+6 -2
View File
@@ -132,8 +132,12 @@
.card-empty {
text-align: center;
opacity: 0.4;
padding: 20px 0;
color: var(--ant-color-text-secondary);
padding: 24px 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
@media (max-width: 768px) {
+12 -1
View File
@@ -600,7 +600,10 @@ export default function InboundList({
{isMobile ? (
<div className="inbound-cards">
{sortedInbounds.length === 0 ? (
<div className="card-empty"></div>
<div className="card-empty">
<ImportOutlined style={{ fontSize: 28, opacity: 0.5 }} />
<div>{t('noData')}</div>
</div>
) : (
sortedInbounds.map((record) => (
<div key={record.id} className="inbound-card">
@@ -641,6 +644,14 @@ export default function InboundList({
scroll={{ x: 1000 }}
style={{ marginTop: 10 }}
size="small"
locale={{
emptyText: (
<div className="card-empty">
<ImportOutlined style={{ fontSize: 32, marginBottom: 8 }} />
<div>{t('noData')}</div>
</div>
),
}}
onChange={(_p, _f, sorter) => {
const single = Array.isArray(sorter) ? sorter[0] : sorter;
const colKey = (single?.columnKey || single?.field) as SortKey | undefined;
+6 -2
View File
@@ -135,6 +135,10 @@
.card-empty {
text-align: center;
opacity: 0.4;
padding: 20px 0;
color: var(--ant-color-text-secondary);
padding: 24px 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
+13 -1
View File
@@ -15,6 +15,7 @@ import {
import type { BadgeProps } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import {
ClusterOutlined,
DeleteOutlined,
EditOutlined,
ExclamationCircleOutlined,
@@ -279,7 +280,10 @@ export default function NodeList({
<>
<div className="node-cards">
{dataSource.length === 0 ? (
<div className="card-empty"></div>
<div className="card-empty">
<ClusterOutlined style={{ fontSize: 28, opacity: 0.5 }} />
<div>{t('noData')}</div>
</div>
) : (
dataSource.map((record) => (
<div key={record.id} className="node-card">
@@ -435,6 +439,14 @@ export default function NodeList({
scroll={{ x: 'max-content' }}
size="middle"
rowKey="id"
locale={{
emptyText: (
<div className="card-empty">
<ClusterOutlined style={{ fontSize: 32, marginBottom: 8 }} />
<div>{t('noData')}</div>
</div>
),
}}
expandable={{
expandedRowRender: (record) => <NodeHistoryPanel node={record} />,
}}