mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
Add SettingsSidebar and SettingsSearch components to AdminSettings
- Introduced SettingsSidebar for improved navigation and organization. - Added SettingsSearch and its mobile variant for enhanced search functionality. - Updated AdminSettings to utilize new components, streamlining the layout and improving user experience.
This commit is contained in:
@@ -4,10 +4,10 @@ import { SearchIcon, CloseIcon } from './icons'
|
||||
interface SettingsSearchProps {
|
||||
searchQuery: string
|
||||
setSearchQuery: (query: string) => void
|
||||
resultsCount: number
|
||||
resultsCount?: number
|
||||
}
|
||||
|
||||
export function SettingsSearch({ searchQuery, setSearchQuery, resultsCount }: SettingsSearchProps) {
|
||||
export function SettingsSearch({ searchQuery, setSearchQuery }: SettingsSearchProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,6 +7,8 @@ export * from './BrandingTab'
|
||||
export * from './ThemeTab'
|
||||
export * from './FavoritesTab'
|
||||
export * from './SettingsTab'
|
||||
export * from './SettingsSidebar'
|
||||
export * from './SettingsSearch'
|
||||
|
||||
// Constants and utils
|
||||
export * from './constants'
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { adminSettingsApi, SettingDefinition } from '../api/adminSettings'
|
||||
import { themeColorsApi } from '../api/themeColors'
|
||||
import { useFavoriteSettings } from '../hooks/useFavoriteSettings'
|
||||
import {
|
||||
BackIcon,
|
||||
SearchIcon,
|
||||
StarIcon,
|
||||
CloseIcon,
|
||||
MenuIcon,
|
||||
MENU_SECTIONS,
|
||||
MenuItem
|
||||
MenuItem,
|
||||
formatSettingKey
|
||||
} from '../components/admin'
|
||||
import { BrandingTab } from '../components/admin/BrandingTab'
|
||||
import { ThemeTab } from '../components/admin/ThemeTab'
|
||||
import { FavoritesTab } from '../components/admin/FavoritesTab'
|
||||
import { SettingsTab } from '../components/admin/SettingsTab'
|
||||
import { SettingsSidebar } from '../components/admin/SettingsSidebar'
|
||||
import { SettingsSearch, SettingsSearchMobile, SettingsSearchResults } from '../components/admin/SettingsSearch'
|
||||
|
||||
export default function AdminSettings() {
|
||||
const { t } = useTranslation()
|
||||
@@ -72,15 +70,6 @@ export default function AdminSettings() {
|
||||
}))
|
||||
}, [currentMenuItem, allSettings, t])
|
||||
|
||||
// Helper to format setting key for translation lookup
|
||||
const formatSettingKey = (name: string): string => {
|
||||
return name
|
||||
.replace(/_/g, ' ')
|
||||
.split(' ')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
// Filter settings for search - GLOBAL search across all settings
|
||||
const filteredSettings = useMemo(() => {
|
||||
if (!allSettings || !Array.isArray(allSettings) || !searchQuery) return []
|
||||
@@ -172,63 +161,13 @@ export default function AdminSettings() {
|
||||
)}
|
||||
|
||||
{/* Sidebar */}
|
||||
<aside className={`
|
||||
fixed lg:sticky lg:top-0 inset-y-0 left-0 z-50
|
||||
w-64 h-screen bg-dark-900 border-r border-dark-700/50 flex-shrink-0
|
||||
transform transition-transform duration-200 ease-in-out
|
||||
${mobileMenuOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'}
|
||||
`}>
|
||||
{/* Header */}
|
||||
<div className="p-4 border-b border-dark-700/50">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link to="/admin" className="p-2 rounded-xl bg-dark-800 hover:bg-dark-700 transition-colors">
|
||||
<BackIcon />
|
||||
</Link>
|
||||
<h1 className="text-lg font-bold text-dark-100">{t('admin.settings.title')}</h1>
|
||||
<button
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
className="ml-auto p-2 rounded-xl bg-dark-800 hover:bg-dark-700 transition-colors lg:hidden"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Menu */}
|
||||
<nav className="p-2 space-y-1 overflow-y-auto max-h-[calc(100vh-80px)]">
|
||||
{MENU_SECTIONS.map((section, sectionIdx) => (
|
||||
<div key={section.id}>
|
||||
{sectionIdx > 0 && <div className="my-3 border-t border-dark-700/50" />}
|
||||
{section.items.map((item) => {
|
||||
const isActive = activeSection === item.id
|
||||
const hasIcon = item.iconType === 'star'
|
||||
return (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => {
|
||||
setActiveSection(item.id)
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-xl transition-all ${
|
||||
isActive
|
||||
? 'bg-accent-500/10 text-accent-400'
|
||||
: 'text-dark-400 hover:text-dark-200 hover:bg-dark-800/50'
|
||||
}`}
|
||||
>
|
||||
{hasIcon && <StarIcon filled={isActive && item.id === 'favorites'} />}
|
||||
<span className="font-medium">{t(`admin.settings.${item.id}`)}</span>
|
||||
{item.id === 'favorites' && favorites.length > 0 && (
|
||||
<span className="ml-auto px-2 py-0.5 text-xs rounded-full bg-warning-500/20 text-warning-400">
|
||||
{favorites.length}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</aside>
|
||||
<SettingsSidebar
|
||||
activeSection={activeSection}
|
||||
setActiveSection={setActiveSection}
|
||||
mobileMenuOpen={mobileMenuOpen}
|
||||
setMobileMenuOpen={setMobileMenuOpen}
|
||||
favoritesCount={favorites.length}
|
||||
/>
|
||||
|
||||
{/* Main content */}
|
||||
<main className="flex-1 min-w-0">
|
||||
@@ -248,64 +187,22 @@ export default function AdminSettings() {
|
||||
|
||||
<div className="flex-1" />
|
||||
|
||||
{/* Search - desktop */}
|
||||
<div className="relative hidden sm:block">
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder={t('admin.settings.searchPlaceholder')}
|
||||
className="w-48 lg:w-64 pl-10 pr-10 py-2 rounded-xl bg-dark-800 border border-dark-700 text-dark-100 placeholder-dark-500 focus:outline-none focus:border-accent-500 text-sm"
|
||||
<SettingsSearch
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
resultsCount={filteredSettings.length}
|
||||
/>
|
||||
<div className="absolute left-3 top-1/2 -translate-y-1/2 text-dark-500">
|
||||
<SearchIcon />
|
||||
</div>
|
||||
{searchQuery && (
|
||||
<button
|
||||
onClick={() => setSearchQuery('')}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-dark-500 hover:text-dark-300 transition-colors"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search - mobile */}
|
||||
<div className="relative mt-3 sm:hidden">
|
||||
<input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder={t('admin.settings.searchPlaceholder')}
|
||||
className="w-full pl-10 pr-10 py-2 rounded-xl bg-dark-800 border border-dark-700 text-dark-100 placeholder-dark-500 focus:outline-none focus:border-accent-500 text-sm"
|
||||
<SettingsSearchMobile
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
/>
|
||||
<div className="absolute left-3 top-1/2 -translate-y-1/2 text-dark-500">
|
||||
<SearchIcon />
|
||||
</div>
|
||||
{searchQuery && (
|
||||
<button
|
||||
onClick={() => setSearchQuery('')}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-dark-500 hover:text-dark-300 transition-colors"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Search results count */}
|
||||
{searchQuery.trim() && (
|
||||
<div className="mt-3 flex items-center gap-2 text-sm">
|
||||
<span className="text-dark-400">
|
||||
{filteredSettings.length > 0
|
||||
? `Найдено: ${filteredSettings.length}`
|
||||
: 'Ничего не найдено'}
|
||||
</span>
|
||||
{filteredSettings.length > 0 && (
|
||||
<span className="text-dark-500">по запросу «{searchQuery}»</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<SettingsSearchResults
|
||||
searchQuery={searchQuery}
|
||||
resultsCount={filteredSettings.length}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
|
||||
Reference in New Issue
Block a user