UI: Implement unified dark theme across all components

This commit is contained in:
Primakov Alexandr Alexandrovich 2025-10-13 00:52:59 +03:00
parent 1185630616
commit 2ad11142ad
4 changed files with 121 additions and 30 deletions

View File

@ -29,13 +29,13 @@ function Navigation() {
]; ];
return ( return (
<nav className="bg-gray-900 border-b border-gray-800"> <nav className="bg-dark-card border-b border-dark-border shadow-lg">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16"> <div className="flex items-center justify-between h-16">
<div className="flex items-center gap-8"> <div className="flex items-center gap-8">
<Link to="/" className="flex items-center gap-2"> <Link to="/" className="flex items-center gap-2 hover:opacity-90 transition-opacity">
<span className="text-2xl">🤖</span> <span className="text-2xl">🤖</span>
<span className="text-xl font-bold text-white">AI Review Agent</span> <span className="text-xl font-bold text-dark-text-primary">AI Review Agent</span>
</Link> </Link>
<div className="flex gap-2"> <div className="flex gap-2">
@ -43,14 +43,14 @@ function Navigation() {
<Link <Link
key={link.path} key={link.path}
to={link.path} to={link.path}
className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-colors ${ className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-all duration-200 ${
location.pathname === link.path location.pathname === link.path
? 'bg-gray-800 text-white' ? 'bg-dark-hover text-dark-text-primary shadow-sm'
: 'text-gray-400 hover:text-white hover:bg-gray-800' : 'text-dark-text-secondary hover:text-dark-text-primary hover:bg-dark-hover/50'
}`} }`}
> >
<span>{link.icon}</span> <span>{link.icon}</span>
<span>{link.label}</span> <span className="font-medium">{link.label}</span>
</Link> </Link>
))} ))}
</div> </div>
@ -65,7 +65,7 @@ function Navigation() {
function AppContent() { function AppContent() {
return ( return (
<div className="min-h-screen bg-gray-900"> <div className="min-h-screen bg-dark-bg">
<Navigation /> <Navigation />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">

View File

@ -31,13 +31,13 @@ export const Modal: React.FC<ModalProps> = ({
const getIconAndColor = () => { const getIconAndColor = () => {
switch (type) { switch (type) {
case 'success': case 'success':
return { icon: '✅', color: 'text-green-600', bgColor: 'bg-green-50' }; return { icon: '✅', color: 'text-green-400', bgColor: 'bg-green-900/30 border-green-700' };
case 'error': case 'error':
return { icon: '❌', color: 'text-red-600', bgColor: 'bg-red-50' }; return { icon: '❌', color: 'text-red-400', bgColor: 'bg-red-900/30 border-red-700' };
case 'warning': case 'warning':
return { icon: '⚠️', color: 'text-yellow-600', bgColor: 'bg-yellow-50' }; return { icon: '⚠️', color: 'text-yellow-400', bgColor: 'bg-yellow-900/30 border-yellow-700' };
default: default:
return { icon: '', color: 'text-blue-600', bgColor: 'bg-blue-50' }; return { icon: '', color: 'text-blue-400', bgColor: 'bg-blue-900/30 border-blue-700' };
} }
}; };
@ -45,11 +45,11 @@ export const Modal: React.FC<ModalProps> = ({
return ( return (
<div <div
className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50" className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-70"
onClick={onClose} onClick={onClose}
> >
<div <div
className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4 animate-scale-in" className="bg-dark-card rounded-lg shadow-2xl max-w-md w-full mx-4 animate-scale-in border border-dark-border"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className={`${bgColor} px-6 py-4 rounded-t-lg border-b`}> <div className={`${bgColor} px-6 py-4 rounded-t-lg border-b`}>
@ -58,13 +58,13 @@ export const Modal: React.FC<ModalProps> = ({
{title} {title}
</h3> </h3>
</div> </div>
<div className="px-6 py-4"> <div className="px-6 py-4 text-dark-text-primary">
{children} {children}
</div> </div>
<div className="px-6 py-4 bg-gray-50 rounded-b-lg flex justify-end"> <div className="px-6 py-4 bg-dark-bg/50 rounded-b-lg flex justify-end border-t border-dark-border">
<button <button
onClick={onClose} onClick={onClose}
className="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700 transition-colors" className="px-4 py-2 bg-dark-hover text-dark-text-primary rounded-lg hover:bg-dark-hover/80 transition-colors font-medium"
> >
Закрыть Закрыть
</button> </button>
@ -102,11 +102,11 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = ({
const getIconAndColor = () => { const getIconAndColor = () => {
switch (type) { switch (type) {
case 'error': case 'error':
return { icon: '❌', color: 'text-red-600', bgColor: 'bg-red-50', btnColor: 'bg-red-600 hover:bg-red-700' }; return { icon: '❌', color: 'text-red-400', bgColor: 'bg-red-900/30 border-red-700', btnColor: 'bg-red-600 hover:bg-red-700' };
case 'info': case 'info':
return { icon: '', color: 'text-blue-600', bgColor: 'bg-blue-50', btnColor: 'bg-blue-600 hover:bg-blue-700' }; return { icon: '', color: 'text-blue-400', bgColor: 'bg-blue-900/30 border-blue-700', btnColor: 'bg-blue-600 hover:bg-blue-700' };
default: default:
return { icon: '⚠️', color: 'text-yellow-600', bgColor: 'bg-yellow-50', btnColor: 'bg-yellow-600 hover:bg-yellow-700' }; return { icon: '⚠️', color: 'text-yellow-400', bgColor: 'bg-yellow-900/30 border-yellow-700', btnColor: 'bg-yellow-600 hover:bg-yellow-700' };
} }
}; };
@ -114,11 +114,11 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = ({
return ( return (
<div <div
className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50" className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-70"
onClick={isLoading ? undefined : onClose} onClick={isLoading ? undefined : onClose}
> >
<div <div
className="bg-white rounded-lg shadow-xl max-w-md w-full mx-4 animate-scale-in" className="bg-dark-card rounded-lg shadow-2xl max-w-md w-full mx-4 animate-scale-in border border-dark-border"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className={`${bgColor} px-6 py-4 rounded-t-lg border-b`}> <div className={`${bgColor} px-6 py-4 rounded-t-lg border-b`}>
@ -128,20 +128,20 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = ({
</h3> </h3>
</div> </div>
<div className="px-6 py-4"> <div className="px-6 py-4">
<p className="text-gray-700">{message}</p> <p className="text-dark-text-primary">{message}</p>
</div> </div>
<div className="px-6 py-4 bg-gray-50 rounded-b-lg flex justify-end gap-3"> <div className="px-6 py-4 bg-dark-bg/50 rounded-b-lg flex justify-end gap-3 border-t border-dark-border">
<button <button
onClick={onClose} onClick={onClose}
disabled={isLoading} disabled={isLoading}
className="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" className="px-4 py-2 bg-dark-hover text-dark-text-secondary rounded-lg hover:bg-dark-hover/80 transition-colors disabled:opacity-50 disabled:cursor-not-allowed font-medium"
> >
{cancelText} {cancelText}
</button> </button>
<button <button
onClick={onConfirm} onClick={onConfirm}
disabled={isLoading} disabled={isLoading}
className={`px-4 py-2 text-white rounded transition-colors disabled:opacity-50 disabled:cursor-not-allowed ${btnColor}`} className={`px-4 py-2 text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed font-medium ${btnColor}`}
> >
{isLoading ? '⏳ Загрузка...' : confirmText} {isLoading ? '⏳ Загрузка...' : confirmText}
</button> </button>

View File

@ -22,9 +22,9 @@
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
color-scheme: light dark; color-scheme: dark;
color: rgba(255, 255, 255, 0.87); color: #F1F5F9;
background-color: #242424; background-color: #0F172A;
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
@ -36,9 +36,85 @@ body {
margin: 0; margin: 0;
min-width: 320px; min-width: 320px;
min-height: 100vh; min-height: 100vh;
background-color: #0F172A;
color: #F1F5F9;
} }
#root { #root {
min-height: 100vh; min-height: 100vh;
background-color: #0F172A;
}
/* Темная тема для всех элементов */
* {
scrollbar-width: thin;
scrollbar-color: #475569 #1E293B;
}
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
background: #1E293B;
}
*::-webkit-scrollbar-thumb {
background: #475569;
border-radius: 4px;
}
*::-webkit-scrollbar-thumb:hover {
background: #64748B;
}
/* Убрать светлые элементы из браузера */
input, textarea, select {
color-scheme: dark;
}
/* Темная тема для всех форм */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="url"],
input[type="number"],
textarea,
select {
@apply bg-dark-card border-dark-border text-dark-text-primary;
@apply focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20;
}
input[type="text"]:disabled,
input[type="email"]:disabled,
input[type="password"]:disabled,
input[type="url"]:disabled,
input[type="number"]:disabled,
textarea:disabled,
select:disabled {
@apply bg-dark-bg/50 text-dark-text-muted cursor-not-allowed;
}
input::placeholder,
textarea::placeholder {
@apply text-dark-text-muted;
}
/* Темная тема для checkbox и radio */
input[type="checkbox"],
input[type="radio"] {
@apply bg-dark-card border-dark-border;
@apply checked:bg-blue-600 checked:border-blue-600;
}
/* Темная тема для кнопок */
button {
@apply transition-colors duration-200;
}
/* Темная тема для ссылок */
a {
@apply transition-colors duration-200;
} }

View File

@ -4,8 +4,23 @@ export default {
"./index.html", "./index.html",
"./src/**/*.{js,ts,jsx,tsx}", "./src/**/*.{js,ts,jsx,tsx}",
], ],
darkMode: 'class',
theme: { theme: {
extend: {}, extend: {
colors: {
dark: {
bg: '#0F172A', // Основной фон
card: '#1E293B', // Карточки
border: '#334155', // Границы
hover: '#475569', // Hover эффекты
text: {
primary: '#F1F5F9', // Основной текст
secondary: '#94A3B8', // Вторичный текст
muted: '#64748B', // Приглушенный текст
}
}
}
},
}, },
plugins: [], plugins: [],
} }