UI: Implement unified dark theme across all components
This commit is contained in:
parent
1185630616
commit
2ad11142ad
@ -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">
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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: [],
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user