refactor(PageHeader): standardize header component across various managers by adding icons for improved visual consistency and user experience
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m53s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m53s
This commit is contained in:
@@ -529,6 +529,7 @@ function ASNsNewManager() {
|
||||
|
||||
<PageHeader
|
||||
title="ASNs"
|
||||
icon={<IconHash size={24} />}
|
||||
meta={<LastSaved timestamp={lastModified} variant="compact" />}
|
||||
actions={
|
||||
<PageHeaderActions
|
||||
|
||||
@@ -276,6 +276,7 @@ function AutoUrlManager() {
|
||||
<div>
|
||||
<PageHeader
|
||||
title="Автоматические URL"
|
||||
icon={<IconLink size={24} />}
|
||||
actions={(
|
||||
<div className="d-flex align-items-center justify-content-between flex-wrap gap-2">
|
||||
<div className="btn-list">
|
||||
|
||||
@@ -576,6 +576,7 @@ function BillingManager() {
|
||||
{/* Заголовок */}
|
||||
<PageHeader
|
||||
title="Биллинг"
|
||||
icon={<IconCreditCard size={24} />}
|
||||
actions={
|
||||
<PageHeaderActions
|
||||
loading={loading}
|
||||
|
||||
@@ -350,16 +350,10 @@ function CommunitiesManager() {
|
||||
|
||||
return (
|
||||
<div className="page-wrapper">
|
||||
<div className="page-header d-print-none">
|
||||
<div className="container-xl">
|
||||
<div className="row g-2 align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title">
|
||||
<IconFilter className="icon me-2" />
|
||||
Справочник Community
|
||||
</h2>
|
||||
</div>
|
||||
<div className="col-auto ms-auto d-print-none">
|
||||
<PageHeader
|
||||
title="Справочник Community"
|
||||
icon={<IconFilter size={24} />}
|
||||
actions={
|
||||
<PageHeaderActions
|
||||
loading={loading}
|
||||
onRefresh={fetchItems}
|
||||
@@ -370,10 +364,8 @@ function CommunitiesManager() {
|
||||
onSave={handleSave}
|
||||
disableSave={loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="page-body">
|
||||
<div className="container-xl">
|
||||
|
||||
@@ -205,6 +205,7 @@ function Dashboard() {
|
||||
{/* Заголовок страницы */}
|
||||
<PageHeader
|
||||
title="Панель"
|
||||
icon={<IconCloud size={24} />}
|
||||
actions={(
|
||||
<div className="d-flex align-items-center gap-3">
|
||||
{lastFetchTime && (
|
||||
|
||||
@@ -518,6 +518,7 @@ function DomainsNewManager() {
|
||||
|
||||
<PageHeader
|
||||
title="Домены"
|
||||
icon={<IconWorld size={24} />}
|
||||
meta={<LastSaved timestamp={lastModified} variant="compact" />}
|
||||
actions={(
|
||||
<PageHeaderActions
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
IconChevronDown,
|
||||
IconChevronUp
|
||||
} from '@tabler/icons-react';
|
||||
import PageHeader from './components/PageHeader.jsx';
|
||||
|
||||
// Функция для получения флага по коду страны
|
||||
const countryToFlag = (code) => {
|
||||
@@ -495,17 +496,11 @@ function EasySwitchManager() {
|
||||
if (loading && servers.length === 0) {
|
||||
return (
|
||||
<div className="container-xl">
|
||||
<div className="page-header">
|
||||
<div className="row align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title">
|
||||
<IconWorld className="me-2" />
|
||||
Easy Switch
|
||||
</h2>
|
||||
<div className="text-muted mt-1">Быстрое переключение шлюзов</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
title="Easy Switch"
|
||||
icon={<IconWorld size={24} />}
|
||||
meta="Быстрое переключение шлюзов"
|
||||
/>
|
||||
|
||||
<div className="card">
|
||||
<div className="card-body text-center py-5">
|
||||
@@ -521,19 +516,11 @@ function EasySwitchManager() {
|
||||
|
||||
return (
|
||||
<div className="container-xl">
|
||||
{/* Заголовок */}
|
||||
<div className="page-header mb-3">
|
||||
<div className="row align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title">
|
||||
<IconWorld className="me-2" />
|
||||
Easy Switch
|
||||
</h2>
|
||||
<div className="text-muted mt-1">
|
||||
Быстрое переключение шлюзов • {servers.length} {servers.length === 1 ? 'сервер' : 'серверов'} • {communitiesDirectory.length} communities
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-auto">
|
||||
<PageHeader
|
||||
title="Easy Switch"
|
||||
icon={<IconWorld size={24} />}
|
||||
meta={`Быстрое переключение шлюзов • ${servers.length} ${servers.length === 1 ? 'сервер' : 'серверов'} • ${communitiesDirectory.length} communities`}
|
||||
actions={
|
||||
<div className="btn-list">
|
||||
{hasChanges && (
|
||||
<button
|
||||
@@ -553,9 +540,8 @@ function EasySwitchManager() {
|
||||
Обновить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Вкладки */}
|
||||
<div className="mb-3">
|
||||
|
||||
@@ -6,6 +6,7 @@ import FormModal from './components/FormModal.jsx';
|
||||
import ConfirmModal from './components/ConfirmModal.jsx';
|
||||
import FormField from './components/FormField.jsx';
|
||||
import Modal from './components/Modal.jsx';
|
||||
import PageHeader from './components/PageHeader.jsx';
|
||||
import {
|
||||
IconPlus,
|
||||
IconSearch,
|
||||
@@ -1755,15 +1756,11 @@ function FilterManager() {
|
||||
|
||||
return (
|
||||
<div className="page-wrapper">
|
||||
<div className="page-header d-print-none">
|
||||
<div className="container-xl">
|
||||
<div className="row g-2 align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title">Управление фильтрами frouting</h2>
|
||||
</div>
|
||||
<div className="col-auto ms-auto d-print-none">
|
||||
<PageHeader
|
||||
title="Управление фильтрами frouting"
|
||||
icon={<IconFilter size={24} />}
|
||||
actions={
|
||||
<div className="btn-list">
|
||||
{/* Dropdown выбора сервера */}
|
||||
<div className="dropdown">
|
||||
<button
|
||||
className="btn btn-primary dropdown-toggle"
|
||||
@@ -1839,7 +1836,6 @@ function FilterManager() {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedServer && (
|
||||
<>
|
||||
<button
|
||||
@@ -1878,10 +1874,8 @@ function FilterManager() {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="page-body">
|
||||
<div className="container-xl">
|
||||
|
||||
@@ -790,6 +790,7 @@ function IPRangesManager() {
|
||||
|
||||
<PageHeader
|
||||
title="IP-диапазоны"
|
||||
icon={<IconNetwork size={24} />}
|
||||
meta={<LastSaved timestamp={lastModified} variant="compact" />}
|
||||
actions={
|
||||
<PageHeaderActions
|
||||
|
||||
@@ -550,6 +550,7 @@ function MikrotikBackupsManager() {
|
||||
<div className="page">
|
||||
<PageHeader
|
||||
title="MikroTik Backups"
|
||||
icon={<IconDownload size={24} />}
|
||||
meta={`Текущий сервер: ${currentServerLabel}`}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
@@ -227,6 +227,7 @@ function MikrotikTools() {
|
||||
<div className="page">
|
||||
<PageHeader
|
||||
title="MikroTik Tools"
|
||||
icon={<IconRoute size={24} />}
|
||||
meta={`Текущий сервер: ${currentServerLabel}`}
|
||||
/>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useNotify } from './components/NotifyProvider.jsx';
|
||||
import FormModal from './components/FormModal.jsx';
|
||||
import FormField from './components/FormField.jsx';
|
||||
import ConfirmModal from './components/ConfirmModal.jsx';
|
||||
import PageHeader from './components/PageHeader.jsx';
|
||||
import ServerAutocompleteInput from './components/ServerAutocompleteInput.jsx';
|
||||
import GatewayAutocompleteInput from './components/GatewayAutocompleteInput.jsx';
|
||||
import Tooltip from './components/Tooltip.jsx';
|
||||
@@ -3231,18 +3232,11 @@ function NetworkConfigManager() {
|
||||
|
||||
return (
|
||||
<div className="network-config-manager">
|
||||
{/* Page Header */}
|
||||
<div className="page-header d-print-none mb-4">
|
||||
<div className="row align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title d-flex align-items-center">
|
||||
<IconNetwork className="me-2" size={28} />
|
||||
Сетевые настройки
|
||||
</h2>
|
||||
</div>
|
||||
<div className="col-auto ms-auto d-print-none">
|
||||
<PageHeader
|
||||
title="Сетевые настройки"
|
||||
icon={<IconNetwork size={24} />}
|
||||
actions={
|
||||
<div className="btn-list">
|
||||
{/* Tabs as button group */}
|
||||
<div className="btn-group me-2" role="group">
|
||||
<button
|
||||
className={`btn ${activeTab === 'gateways' ? 'btn-primary' : 'btn-outline-primary'}`}
|
||||
@@ -3290,7 +3284,6 @@ function NetworkConfigManager() {
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-secondary"
|
||||
@@ -3322,9 +3315,8 @@ function NetworkConfigManager() {
|
||||
Сохранить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Toolbar */}
|
||||
<div className="card mb-3">
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
ServerCard,
|
||||
ServerBulkActions
|
||||
} from './components/server/index.js';
|
||||
import PageHeader from './components/PageHeader.jsx';
|
||||
|
||||
const API_URL = '/api';
|
||||
|
||||
@@ -585,18 +586,11 @@ function ServerManager() {
|
||||
|
||||
return (
|
||||
<div className="server-manager-layout">
|
||||
{/* Header */}
|
||||
<div className="page-header d-print-none mb-3">
|
||||
<div className="row align-items-center">
|
||||
<div className="col">
|
||||
<h2 className="page-title d-flex align-items-center">
|
||||
<IconServer className="me-2" />
|
||||
Управление серверами
|
||||
</h2>
|
||||
</div>
|
||||
<div className="col-auto ms-auto d-print-none">
|
||||
<PageHeader
|
||||
title="Управление серверами"
|
||||
icon={<IconServer size={24} />}
|
||||
actions={
|
||||
<div className="btn-list">
|
||||
{/* Tabs */}
|
||||
<div className="btn-group me-2" role="group">
|
||||
<button
|
||||
className={`btn ${activeTab === 'servers' ? 'btn-primary' : 'btn-outline-primary'}`}
|
||||
@@ -613,8 +607,6 @@ function ServerManager() {
|
||||
Связи
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<button type="button" className="btn btn-outline-secondary" onClick={exportAllLinks} disabled={servers.length === 0}>
|
||||
<IconDownload size={16} className="me-1" /> Экспорт
|
||||
</button>
|
||||
@@ -625,9 +617,8 @@ function ServerManager() {
|
||||
<IconPlus size={16} className="me-1" /> Добавить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Offcanvas: фильтры (только для вкладки «Серверы») */}
|
||||
{activeTab === 'servers' && (
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import React from 'react'
|
||||
|
||||
/** Заголовок страницы в стиле Tabler (page-header + page-title + опционально actions справа) */
|
||||
function PageHeader({ title, pretitle, actions, meta }) {
|
||||
/**
|
||||
* Единый заголовок страницы в стиле Tabler UI.
|
||||
* Используется на всех страницах для одинакового UX.
|
||||
* @param {string} title - Заголовок страницы
|
||||
* @param {React.ReactNode} [icon] - Иконка слева от заголовка (например, <IconServer />)
|
||||
* @param {string} [pretitle] - Небольшая надпись над заголовком (page-pretitle)
|
||||
* @param {React.ReactNode} [meta] - Подзаголовок или мета-информация под заголовком
|
||||
* @param {React.ReactNode} [actions] - Кнопки/действия справа (btn-list, btn-group)
|
||||
*/
|
||||
function PageHeader({ title, icon, pretitle, actions, meta }) {
|
||||
return (
|
||||
<div className="page-header d-print-none mb-4">
|
||||
<div className="row align-items-center">
|
||||
@@ -9,7 +17,10 @@ function PageHeader({ title, pretitle, actions, meta }) {
|
||||
{pretitle && (
|
||||
<div className="page-pretitle">{pretitle}</div>
|
||||
)}
|
||||
<h1 className="page-title">{title}</h1>
|
||||
<h1 className="page-title d-flex align-items-center">
|
||||
{icon && <span className="me-2 d-flex align-items-center">{icon}</span>}
|
||||
{title}
|
||||
</h1>
|
||||
{meta && (
|
||||
<div className="text-muted small mt-1">{meta}</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user