This commit is contained in:
arrelin
2026-01-23 17:01:47 +03:00
parent b18f69ea62
commit 471da855bf
11 changed files with 194 additions and 68 deletions

View File

@@ -27,8 +27,8 @@ export default function ConfirmModal({
switch (variant) { switch (variant) {
case 'danger': case 'danger':
return { return {
icon: 'bg-red-100 text-red-600', icon: 'btn-danger',
confirmButton: 'bg-gradient-to-r from-red-500 to-red-600 hover:shadow-lg', confirmButton: 'btn-danger hover:shadow-lg',
}; };
case 'warning': case 'warning':
return { return {
@@ -37,8 +37,8 @@ export default function ConfirmModal({
}; };
case 'info': case 'info':
return { return {
icon: 'bg-blue-100 text-blue-600', icon: 'btn-primary',
confirmButton: 'bg-gradient-to-r from-blue-500 to-blue-600 hover:shadow-lg', confirmButton: 'btn-primary hover:shadow-lg',
}; };
} }
}; };
@@ -47,10 +47,10 @@ export default function ConfirmModal({
return ( return (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-[60] p-4"> <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-[60] p-4">
<div className="bg-white rounded-3xl shadow-2xl max-w-md w-full overflow-hidden animate-scale-in"> <div className="glass-effect rounded-3xl shadow-2xl max-w-md w-full overflow-hidden animate-scale-in">
<div className="p-6"> <div className="p-6">
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
<div className={`p-3 rounded-2xl ${styles.icon}`}> <div className={`p-3 rounded-2xl ${styles.icon} text-white`}>
<AlertTriangle className="w-6 h-6" /> <AlertTriangle className="w-6 h-6" />
</div> </div>
<div className="flex-1"> <div className="flex-1">

View File

@@ -189,8 +189,8 @@ export default function ShoppingListModal({ familyId, onClose }: ShoppingListMod
return ( return (
<> <>
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4"> <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-3xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-hidden flex flex-col"> <div className="glass-effect rounded-3xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-hidden flex flex-col">
<div className="bg-gradient-to-r from-green-500 to-emerald-600 p-6 flex items-center justify-between"> <div className="btn-success p-6 flex items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 bg-white/20 backdrop-blur-md rounded-2xl"> <div className="p-3 bg-white/20 backdrop-blur-md rounded-2xl">
<ShoppingCart className="w-8 h-8 text-white" /> <ShoppingCart className="w-8 h-8 text-white" />
@@ -218,7 +218,7 @@ export default function ShoppingListModal({ familyId, onClose }: ShoppingListMod
/> />
<button <button
onClick={handleAddItem} onClick={handleAddItem}
className="px-6 py-3 bg-gradient-to-r from-green-500 to-green-600 text-white rounded-2xl hover:shadow-lg transition-all font-semibold flex items-center gap-2" className="px-6 py-3 btn-success text-white rounded-2xl hover:shadow-lg transition-all font-semibold flex items-center gap-2"
> >
<Plus className="w-5 h-5" /> <Plus className="w-5 h-5" />
<span className="hidden sm:inline">{t('common.add')}</span> <span className="hidden sm:inline">{t('common.add')}</span>
@@ -342,14 +342,14 @@ export default function ShoppingListModal({ familyId, onClose }: ShoppingListMod
<div className="flex gap-3"> <div className="flex gap-3">
<button <button
onClick={handleMarkAllPurchased} onClick={handleMarkAllPurchased}
className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-green-500 to-green-600 text-white rounded-2xl hover:shadow-lg transition-all font-semibold" className="flex-1 flex items-center justify-center gap-2 px-4 py-3 btn-success text-white rounded-2xl hover:shadow-lg transition-all font-semibold"
> >
<Check className="w-5 h-5" /> <Check className="w-5 h-5" />
{t('shopping.allPurchased')} {t('shopping.allPurchased')}
</button> </button>
<button <button
onClick={handleClearAll} onClick={handleClearAll}
className="flex-1 flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-red-500 to-red-600 text-white rounded-2xl hover:shadow-lg transition-all font-semibold" className="flex-1 flex items-center justify-center gap-2 px-4 py-3 btn-danger text-white rounded-2xl hover:shadow-lg transition-all font-semibold"
> >
<Trash2 className="w-5 h-5" /> <Trash2 className="w-5 h-5" />
{t('shopping.clear')} {t('shopping.clear')}

View File

@@ -159,6 +159,14 @@
"leaveConfirm": "Are you sure you want to leave the family?", "leaveConfirm": "Are you sure you want to leave the family?",
"leaving": "Leaving...", "leaving": "Leaving...",
"leaveError": "Error leaving family", "leaveError": "Error leaving family",
"renameError": "Error renaming family" "renameError": "Error renaming family",
"themes": {
"light": "Light",
"dark": "Dark",
"sunset": "Sunset",
"ocean": "Ocean",
"forest": "Forest",
"purple": "Purple"
}
} }
} }

View File

@@ -159,6 +159,14 @@
"leaveConfirm": "Вы уверены, что хотите покинуть семью?", "leaveConfirm": "Вы уверены, что хотите покинуть семью?",
"leaving": "Выход...", "leaving": "Выход...",
"leaveError": "Ошибка при выходе из семьи", "leaveError": "Ошибка при выходе из семьи",
"renameError": "Ошибка при переименовании семьи" "renameError": "Ошибка при переименовании семьи",
"themes": {
"light": "Светлая",
"dark": "Тёмная",
"sunset": "Закат",
"ocean": "Океан",
"forest": "Лес",
"purple": "Фиолетовая"
}
} }
} }

View File

@@ -7,14 +7,32 @@
--glass-bg: rgba(255, 255, 255, 0.8); --glass-bg: rgba(255, 255, 255, 0.8);
--text-primary: #1f2937; --text-primary: #1f2937;
--text-secondary: #6b7280; --text-secondary: #6b7280;
--category-from: #8b5cf6;
--category-to: #3b82f6;
--btn-primary-from: #8b5cf6;
--btn-primary-to: #6366f1;
--btn-success-from: #22c55e;
--btn-success-to: #16a34a;
--btn-danger-from: #ef4444;
--btn-danger-to: #ec4899;
--card-bg: rgba(255, 255, 255, 0.8);
} }
[data-theme="dark"] { [data-theme="dark"] {
--gradient-start: #1f2937; --gradient-start: #000000;
--gradient-end: #111827; --gradient-end: #000000;
--glass-bg: rgba(31, 41, 55, 0.9); --glass-bg: rgba(17, 17, 17, 0.95);
--text-primary: #f9fafb; --text-primary: #f9fafb;
--text-secondary: #d1d5db; --text-secondary: #d1d5db;
--category-from: #6366f1;
--category-to: #8b5cf6;
--btn-primary-from: #6366f1;
--btn-primary-to: #8b5cf6;
--btn-success-from: #059669;
--btn-success-to: #10b981;
--btn-danger-from: #dc2626;
--btn-danger-to: #be185d;
--card-bg: rgba(31, 31, 31, 0.9);
} }
[data-theme="sunset"] { [data-theme="sunset"] {
@@ -23,6 +41,15 @@
--glass-bg: rgba(255, 255, 255, 0.85); --glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937; --text-primary: #1f2937;
--text-secondary: #6b7280; --text-secondary: #6b7280;
--category-from: #f97316;
--category-to: #ec4899;
--btn-primary-from: #f97316;
--btn-primary-to: #ea580c;
--btn-success-from: #22c55e;
--btn-success-to: #16a34a;
--btn-danger-from: #ef4444;
--btn-danger-to: #dc2626;
--card-bg: rgba(255, 255, 255, 0.85);
} }
[data-theme="ocean"] { [data-theme="ocean"] {
@@ -31,6 +58,15 @@
--glass-bg: rgba(255, 255, 255, 0.85); --glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937; --text-primary: #1f2937;
--text-secondary: #6b7280; --text-secondary: #6b7280;
--category-from: #3b82f6;
--category-to: #06b6d4;
--btn-primary-from: #3b82f6;
--btn-primary-to: #2563eb;
--btn-success-from: #22c55e;
--btn-success-to: #16a34a;
--btn-danger-from: #ef4444;
--btn-danger-to: #dc2626;
--card-bg: rgba(255, 255, 255, 0.85);
} }
[data-theme="forest"] { [data-theme="forest"] {
@@ -39,6 +75,15 @@
--glass-bg: rgba(255, 255, 255, 0.85); --glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937; --text-primary: #1f2937;
--text-secondary: #6b7280; --text-secondary: #6b7280;
--category-from: #22c55e;
--category-to: #14b8a6;
--btn-primary-from: #22c55e;
--btn-primary-to: #16a34a;
--btn-success-from: #22c55e;
--btn-success-to: #16a34a;
--btn-danger-from: #ef4444;
--btn-danger-to: #dc2626;
--card-bg: rgba(255, 255, 255, 0.85);
} }
[data-theme="purple"] { [data-theme="purple"] {
@@ -47,6 +92,15 @@
--glass-bg: rgba(255, 255, 255, 0.85); --glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937; --text-primary: #1f2937;
--text-secondary: #6b7280; --text-secondary: #6b7280;
--category-from: #8b5cf6;
--category-to: #ec4899;
--btn-primary-from: #8b5cf6;
--btn-primary-to: #7c3aed;
--btn-success-from: #22c55e;
--btn-success-to: #16a34a;
--btn-danger-from: #ef4444;
--btn-danger-to: #dc2626;
--card-bg: rgba(255, 255, 255, 0.85);
} }
.gradient-bg { .gradient-bg {
@@ -67,10 +121,66 @@
} }
.glass-effect { .glass-effect {
background: rgb(255 255 255 / 0.8); background: var(--glass-bg);
backdrop-filter: blur(12px); backdrop-filter: blur(12px);
} }
.category-icon {
background: linear-gradient(135deg, var(--category-from) 0%, var(--category-to) 100%);
}
.btn-primary {
background: linear-gradient(135deg, var(--btn-primary-from) 0%, var(--btn-primary-to) 100%);
}
.btn-success {
background: linear-gradient(135deg, var(--btn-success-from) 0%, var(--btn-success-to) 100%);
}
.btn-danger {
background: linear-gradient(135deg, var(--btn-danger-from) 0%, var(--btn-danger-to) 100%);
}
[data-theme="dark"] .glass-effect {
color: var(--text-primary);
}
[data-theme="dark"] .text-gray-800,
[data-theme="dark"] .text-gray-900 {
color: var(--text-primary);
}
[data-theme="dark"] .text-gray-600,
[data-theme="dark"] .text-gray-500 {
color: var(--text-secondary);
}
[data-theme="dark"] .bg-gray-100,
[data-theme="dark"] .bg-gray-50 {
background-color: rgba(55, 55, 55, 0.5);
}
[data-theme="dark"] .bg-gray-200 {
background-color: rgba(75, 75, 75, 0.5);
}
[data-theme="dark"] .border-gray-200,
[data-theme="dark"] .border-gray-300 {
border-color: rgba(75, 75, 75, 0.8);
}
[data-theme="dark"] input,
[data-theme="dark"] textarea {
background-color: rgba(40, 40, 40, 0.9);
color: var(--text-primary);
border-color: rgba(75, 75, 75, 0.8);
}
[data-theme="dark"] input::placeholder,
[data-theme="dark"] textarea::placeholder {
color: var(--text-secondary);
}
.animate-fadeIn { .animate-fadeIn {
animation: fadeIn 0.2s ease-in-out; animation: fadeIn 0.2s ease-in-out;
} }

View File

@@ -81,7 +81,7 @@ export default function AdminPanel() {
<div className="max-w-md w-full"> <div className="max-w-md w-full">
<div className="glass-effect rounded-2xl shadow-2xl p-6 sm:p-8 text-center"> <div className="glass-effect rounded-2xl shadow-2xl p-6 sm:p-8 text-center">
<div className="flex items-center justify-center mb-6"> <div className="flex items-center justify-center mb-6">
<div className="p-4 bg-linear-to-br from-red-500 to-orange-500 text-white rounded-2xl"> <div className="p-4 btn-danger text-white rounded-2xl">
<Shield className="w-10 h-10 sm:w-12 sm:h-12" /> <Shield className="w-10 h-10 sm:w-12 sm:h-12" />
</div> </div>
</div> </div>
@@ -137,7 +137,7 @@ export default function AdminPanel() {
<div className="glass-effect rounded-3xl shadow-xl p-6 sm:p-10 mb-6 max-w-2xl mx-auto"> <div className="glass-effect rounded-3xl shadow-xl p-6 sm:p-10 mb-6 max-w-2xl mx-auto">
<div className="flex items-center justify-center gap-3 mb-8"> <div className="flex items-center justify-center gap-3 mb-8">
<div className="p-3 bg-linear-to-br from-green-500 to-green-600 rounded-2xl"> <div className="p-3 btn-success rounded-2xl">
<Plus className="w-8 h-8 text-white" /> <Plus className="w-8 h-8 text-white" />
</div> </div>
<h2 className="text-2xl sm:text-3xl font-bold text-gray-800"> <h2 className="text-2xl sm:text-3xl font-bold text-gray-800">
@@ -174,7 +174,7 @@ export default function AdminPanel() {
</div> </div>
<button <button
onClick={handleCreateFamily} onClick={handleCreateFamily}
className="w-full flex items-center justify-center gap-2 px-6 py-4 bg-linear-to-r from-green-500 to-green-600 text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold text-lg" className="w-full flex items-center justify-center gap-2 px-6 py-4 btn-success text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold text-lg"
> >
<Plus className="w-6 h-6" /> <Plus className="w-6 h-6" />
{t('admin.createButton')} {t('admin.createButton')}
@@ -184,7 +184,7 @@ export default function AdminPanel() {
<div className="glass-effect rounded-3xl shadow-xl p-6 sm:p-10 max-w-3xl mx-auto"> <div className="glass-effect rounded-3xl shadow-xl p-6 sm:p-10 max-w-3xl mx-auto">
<div className="flex items-center justify-center gap-3 mb-8"> <div className="flex items-center justify-center gap-3 mb-8">
<div className="p-3 bg-linear-to-br from-purple-500 to-blue-500 rounded-2xl"> <div className="p-3 category-icon rounded-2xl">
<Users className="w-8 h-8 text-white" /> <Users className="w-8 h-8 text-white" />
</div> </div>
<h2 className="text-2xl sm:text-3xl font-bold text-gray-800"> <h2 className="text-2xl sm:text-3xl font-bold text-gray-800">
@@ -194,8 +194,8 @@ export default function AdminPanel() {
{families.length === 0 ? ( {families.length === 0 ? (
<div className="text-center py-16 sm:py-20"> <div className="text-center py-16 sm:py-20">
<div className="inline-flex p-6 bg-linear-to-br from-purple-100 to-blue-100 rounded-3xl mb-6"> <div className="inline-flex p-6 bg-gray-100 rounded-3xl mb-6">
<Users className="w-20 h-20 text-purple-400" /> <Users className="w-20 h-20 text-gray-400" />
</div> </div>
<p className="text-gray-600 text-lg sm:text-xl mb-2 font-semibold"> <p className="text-gray-600 text-lg sm:text-xl mb-2 font-semibold">
{t('admin.noFamilies')} {t('admin.noFamilies')}
@@ -209,10 +209,10 @@ export default function AdminPanel() {
{families.map((family) => ( {families.map((family) => (
<div <div
key={family.id} key={family.id}
className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-5 bg-linear-to-r from-purple-50 to-blue-50 rounded-2xl border-2 border-purple-200 card-hover" className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-5 bg-gray-50 rounded-2xl border-2 border-gray-200 card-hover"
> >
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 bg-linear-to-br from-purple-500 to-blue-500 text-white rounded-xl shadow-md"> <div className="p-3 category-icon text-white rounded-xl shadow-md">
<Users className="w-6 h-6" /> <Users className="w-6 h-6" />
</div> </div>
<span className="text-lg sm:text-xl font-bold text-gray-900"> <span className="text-lg sm:text-xl font-bold text-gray-900">
@@ -221,7 +221,7 @@ export default function AdminPanel() {
</div> </div>
<button <button
onClick={() => handleDeleteFamily(family.id)} onClick={() => handleDeleteFamily(family.id)}
className="w-full sm:w-auto flex items-center justify-center gap-2 px-5 py-3 bg-red-500 hover:bg-red-600 text-white rounded-xl transition-all font-semibold shadow-md hover:shadow-lg" className="w-full sm:w-auto flex items-center justify-center gap-2 px-5 py-3 btn-danger text-white rounded-xl transition-all font-semibold shadow-md hover:shadow-lg"
> >
<Trash2 className="w-5 h-5" /> <Trash2 className="w-5 h-5" />
{t('common.delete')} {t('common.delete')}

View File

@@ -308,7 +308,7 @@ export default function FamilyView() {
</div> </div>
<button <button
onClick={() => setShowShoppingList(true)} onClick={() => setShowShoppingList(true)}
className="w-full flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-green-500 to-emerald-600 text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold" className="w-full flex items-center justify-center gap-2 px-6 py-3 btn-success text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold"
> >
<ShoppingCart className="w-5 h-5" /> <ShoppingCart className="w-5 h-5" />
{t('family.shoppingList')} {t('family.shoppingList')}
@@ -339,7 +339,7 @@ export default function FamilyView() {
> >
<div className="flex items-center justify-between gap-3 mb-4"> <div className="flex items-center justify-between gap-3 mb-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-2 bg-linear-to-br from-purple-500 to-blue-500 text-white rounded-xl shadow-lg"> <div className="p-2 category-icon text-white rounded-xl shadow-lg">
<Tag className="w-6 h-6" /> <Tag className="w-6 h-6" />
</div> </div>
<h2 className="text-xl sm:text-2xl font-bold text-gray-900"> <h2 className="text-xl sm:text-2xl font-bold text-gray-900">
@@ -350,7 +350,7 @@ export default function FamilyView() {
{showAddExpense !== category.id && ( {showAddExpense !== category.id && (
<button <button
onClick={() => setShowAddExpense(category.id)} onClick={() => setShowAddExpense(category.id)}
className="flex items-center gap-2 px-4 py-2 bg-linear-to-r from-red-500 to-pink-500 text-white rounded-xl hover:shadow-lg transition-all duration-300 font-semibold whitespace-nowrap text-sm" className="flex items-center gap-2 px-4 py-2 btn-danger text-white rounded-xl hover:shadow-lg transition-all duration-300 font-semibold whitespace-nowrap text-sm"
> >
<TrendingDown className="w-4 h-4" /> <TrendingDown className="w-4 h-4" />
<span className="hidden sm:inline">{t('category.addExpense')}</span> <span className="hidden sm:inline">{t('category.addExpense')}</span>
@@ -407,7 +407,7 @@ export default function FamilyView() {
</div> </div>
{showHistory === category.id && ( {showHistory === category.id && (
<div className="mt-4 bg-linear-to-br from-blue-50 to-purple-50 p-4 rounded-2xl border-2 border-blue-200"> <div className="mt-4 glass-effect p-4 rounded-2xl border-2 border-gray-200">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h3 className="font-semibold text-gray-800 text-lg flex items-center gap-2"> <h3 className="font-semibold text-gray-800 text-lg flex items-center gap-2">
<History className="w-5 h-5" /> <History className="w-5 h-5" />
@@ -458,7 +458,7 @@ export default function FamilyView() {
)} )}
{showAddExpense === category.id && ( {showAddExpense === category.id && (
<div className="bg-linear-to-br from-purple-50 to-blue-50 p-6 rounded-2xl border-2 border-purple-200"> <div className="glass-effect p-6 rounded-2xl border-2 border-gray-200 mt-4">
<h3 className="font-semibold text-gray-800 mb-4 text-center"> <h3 className="font-semibold text-gray-800 mb-4 text-center">
{t('expense.addTitle')} {t('expense.addTitle')}
</h3> </h3>
@@ -490,7 +490,7 @@ export default function FamilyView() {
<div className="flex gap-3"> <div className="flex gap-3">
<button <button
onClick={() => handleAddExpense(category.id)} onClick={() => handleAddExpense(category.id)}
className="flex-1 flex items-center justify-center gap-2 px-5 py-3 bg-linear-to-r from-green-500 to-green-600 text-white rounded-2xl hover:shadow-xl transition-all font-semibold" className="flex-1 flex items-center justify-center gap-2 px-5 py-3 btn-success text-white rounded-2xl hover:shadow-xl transition-all font-semibold"
> >
<Plus className="w-5 h-5" /> <Plus className="w-5 h-5" />
{t('common.add')} {t('common.add')}
@@ -512,7 +512,7 @@ export default function FamilyView() {
<div className="glass-effect rounded-3xl shadow-xl p-6 sm:p-8 max-w-3xl mx-auto"> <div className="glass-effect rounded-3xl shadow-xl p-6 sm:p-8 max-w-3xl mx-auto">
<div className="flex items-center justify-center gap-3 mb-8"> <div className="flex items-center justify-center gap-3 mb-8">
<div className="p-3 bg-linear-to-br from-purple-500 to-blue-500 rounded-2xl"> <div className="p-3 category-icon rounded-2xl">
<DollarSign className="w-8 h-8 text-white" /> <DollarSign className="w-8 h-8 text-white" />
</div> </div>
<h2 className="text-2xl sm:text-3xl font-bold text-gray-800"> <h2 className="text-2xl sm:text-3xl font-bold text-gray-800">
@@ -521,7 +521,7 @@ export default function FamilyView() {
</div> </div>
{showAddCategory ? ( {showAddCategory ? (
<div className="mb-8 p-6 bg-linear-to-br from-purple-50 to-blue-50 rounded-2xl border-2 border-purple-200"> <div className="mb-8 p-6 glass-effect rounded-2xl border-2 border-gray-200">
<h3 className="font-bold text-gray-800 mb-5 text-center text-lg"> <h3 className="font-bold text-gray-800 mb-5 text-center text-lg">
{t('category.newCategory')} {t('category.newCategory')}
</h3> </h3>
@@ -543,7 +543,7 @@ export default function FamilyView() {
<div className="flex gap-3"> <div className="flex gap-3">
<button <button
onClick={handleAddCategory} onClick={handleAddCategory}
className="flex-1 flex items-center justify-center gap-2 px-6 py-4 bg-linear-to-r from-green-500 to-green-600 text-white rounded-2xl hover:shadow-xl transition-all font-semibold" className="flex-1 flex items-center justify-center gap-2 px-6 py-4 btn-success text-white rounded-2xl hover:shadow-xl transition-all font-semibold"
> >
<Plus className="w-5 h-5" /> <Plus className="w-5 h-5" />
{t('common.create')} {t('common.create')}
@@ -560,7 +560,7 @@ export default function FamilyView() {
) : ( ) : (
<button <button
onClick={() => setShowAddCategory(true)} onClick={() => setShowAddCategory(true)}
className="w-full flex items-center justify-center gap-2 px-6 py-4 bg-linear-to-r from-purple-600 to-blue-600 text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold" className="w-full flex items-center justify-center gap-2 px-6 py-4 btn-primary text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold"
> >
<Plus className="w-5 h-5" /> <Plus className="w-5 h-5" />
{t('category.addCategory')} {t('category.addCategory')}
@@ -578,10 +578,10 @@ export default function FamilyView() {
{showInviteModal && ( {showInviteModal && (
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4"> <div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-3xl shadow-2xl w-full max-w-md p-6 sm:p-8"> <div className="glass-effect rounded-3xl shadow-2xl w-full max-w-md p-6 sm:p-8">
<div className="flex items-center justify-between mb-6"> <div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="p-3 bg-gradient-to-br from-purple-500 to-blue-500 rounded-2xl"> <div className="p-3 category-icon rounded-2xl">
<UserPlus className="w-6 h-6 text-white" /> <UserPlus className="w-6 h-6 text-white" />
</div> </div>
<h2 className="text-xl font-bold text-gray-800">{t('invite.title')}</h2> <h2 className="text-xl font-bold text-gray-800">{t('invite.title')}</h2>
@@ -602,7 +602,7 @@ export default function FamilyView() {
<button <button
onClick={handleCreateInviteLink} onClick={handleCreateInviteLink}
disabled={inviteLoading} disabled={inviteLoading}
className="w-full flex items-center justify-center gap-2 px-6 py-4 bg-gradient-to-r from-purple-600 to-blue-600 text-white rounded-2xl hover:shadow-xl transition-all font-semibold disabled:opacity-50" className="w-full flex items-center justify-center gap-2 px-6 py-4 btn-primary text-white rounded-2xl hover:shadow-xl transition-all font-semibold disabled:opacity-50"
> >
{inviteLoading ? ( {inviteLoading ? (
<> <>
@@ -631,8 +631,8 @@ export default function FamilyView() {
onClick={handleCopyInviteLink} onClick={handleCopyInviteLink}
className={`w-full flex items-center justify-center gap-2 px-6 py-4 rounded-2xl transition-all font-semibold ${ className={`w-full flex items-center justify-center gap-2 px-6 py-4 rounded-2xl transition-all font-semibold ${
copied copied
? 'bg-green-500 text-white' ? 'btn-success text-white'
: 'bg-gradient-to-r from-purple-600 to-blue-600 text-white hover:shadow-xl' : 'btn-primary text-white hover:shadow-xl'
}`} }`}
> >
{copied ? ( {copied ? (

View File

@@ -109,15 +109,15 @@ export default function InvitePage() {
if (error) { if (error) {
return ( return (
<div className="min-h-screen flex items-center justify-center gradient-bg px-4"> <div className="min-h-screen flex items-center justify-center gradient-bg px-4">
<div className="bg-white rounded-3xl shadow-2xl p-8 max-w-md w-full text-center"> <div className="glass-effect rounded-3xl shadow-2xl p-8 max-w-md w-full text-center">
<div className="p-4 bg-red-100 rounded-2xl inline-block mb-6"> <div className="p-4 btn-danger rounded-2xl inline-block mb-6">
<AlertCircle className="w-12 h-12 text-red-500" /> <AlertCircle className="w-12 h-12 text-white" />
</div> </div>
<h1 className="text-2xl font-bold text-gray-800 mb-4">{t('common.error')}</h1> <h1 className="text-2xl font-bold text-gray-800 mb-4">{t('common.error')}</h1>
<p className="text-gray-600 mb-6">{error}</p> <p className="text-gray-600 mb-6">{error}</p>
<button <button
onClick={() => navigate('/')} onClick={() => navigate('/')}
className="px-6 py-3 bg-gradient-to-r from-purple-600 to-blue-600 text-white rounded-2xl font-semibold hover:shadow-xl transition-all" className="px-6 py-3 btn-primary text-white rounded-2xl font-semibold hover:shadow-xl transition-all"
> >
{t('common.toHome')} {t('common.toHome')}
</button> </button>
@@ -128,14 +128,14 @@ export default function InvitePage() {
return ( return (
<div className="min-h-screen flex items-center justify-center gradient-bg px-4"> <div className="min-h-screen flex items-center justify-center gradient-bg px-4">
<div className="bg-white rounded-3xl shadow-2xl p-8 max-w-md w-full text-center"> <div className="glass-effect rounded-3xl shadow-2xl p-8 max-w-md w-full text-center">
<div className="p-4 bg-gradient-to-br from-purple-500 to-blue-500 rounded-2xl inline-block mb-6"> <div className="p-4 category-icon rounded-2xl inline-block mb-6">
<Users className="w-12 h-12 text-white" /> <Users className="w-12 h-12 text-white" />
</div> </div>
<h1 className="text-2xl font-bold text-gray-800 mb-2"> <h1 className="text-2xl font-bold text-gray-800 mb-2">
{t('invite.pageTitle')} {t('invite.pageTitle')}
</h1> </h1>
<p className="text-3xl font-bold text-purple-600 mb-6"> <p className="text-3xl font-bold text-gray-800 mb-6">
{familyName} {familyName}
</p> </p>
<p className="text-gray-600 mb-8"> <p className="text-gray-600 mb-8">
@@ -143,7 +143,7 @@ export default function InvitePage() {
</p> </p>
<button <button
onClick={handleGoogleLogin} onClick={handleGoogleLogin}
className="w-full flex items-center justify-center gap-3 px-6 py-4 bg-gradient-to-r from-purple-600 to-blue-600 text-white rounded-2xl font-semibold hover:shadow-xl transition-all" className="w-full flex items-center justify-center gap-3 px-6 py-4 btn-primary text-white rounded-2xl font-semibold hover:shadow-xl transition-all"
> >
<UserPlus className="w-5 h-5" /> <UserPlus className="w-5 h-5" />
{t('invite.loginAndJoin')} {t('invite.loginAndJoin')}

View File

@@ -27,7 +27,7 @@ export default function Login() {
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="glass-effect rounded-3xl shadow-2xl p-8 sm:p-10"> <div className="glass-effect rounded-3xl shadow-2xl p-8 sm:p-10">
<div className="flex flex-col items-center text-center mb-8"> <div className="flex flex-col items-center text-center mb-8">
<div className="p-4 bg-linear-to-br from-purple-500 to-blue-500 text-white rounded-2xl mb-4 shadow-lg"> <div className="p-4 category-icon text-white rounded-2xl mb-4 shadow-lg">
<Wallet className="w-12 h-12" /> <Wallet className="w-12 h-12" />
</div> </div>
<h1 className="text-3xl sm:text-4xl font-bold text-gray-900 mb-2"> <h1 className="text-3xl sm:text-4xl font-bold text-gray-900 mb-2">

View File

@@ -118,7 +118,7 @@ export default function NoFamily() {
<div className="w-full max-w-md"> <div className="w-full max-w-md">
<div className="glass-effect rounded-3xl shadow-2xl p-8 sm:p-10"> <div className="glass-effect rounded-3xl shadow-2xl p-8 sm:p-10">
<div className="flex flex-col items-center text-center mb-6"> <div className="flex flex-col items-center text-center mb-6">
<div className="p-4 bg-linear-to-br from-purple-500 to-blue-500 text-white rounded-2xl mb-4 shadow-lg"> <div className="p-4 category-icon text-white rounded-2xl mb-4 shadow-lg">
<Users className="w-12 h-12" /> <Users className="w-12 h-12" />
</div> </div>
<h1 className="text-2xl sm:text-3xl font-bold text-gray-900 mb-2"> <h1 className="text-2xl sm:text-3xl font-bold text-gray-900 mb-2">
@@ -186,7 +186,7 @@ export default function NoFamily() {
<button <button
type="submit" type="submit"
disabled={loading || !familyName.trim()} disabled={loading || !familyName.trim()}
className="w-full flex items-center justify-center gap-2 px-6 py-4 bg-linear-to-r from-purple-600 to-blue-600 text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold disabled:opacity-50 disabled:cursor-not-allowed" className="w-full flex items-center justify-center gap-2 px-6 py-4 btn-primary text-white rounded-2xl hover:shadow-xl transition-all duration-300 font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
> >
{loading ? ( {loading ? (
<Loader2 className="w-5 h-5 animate-spin" /> <Loader2 className="w-5 h-5 animate-spin" />

View File

@@ -20,13 +20,13 @@ import {
X, X,
} from 'lucide-react'; } from 'lucide-react';
const THEMES: { id: Theme; name: string; gradient: string }[] = [ const THEMES: { id: Theme; gradient: string }[] = [
{ id: 'light', name: 'Light', gradient: 'bg-gradient-to-r from-gray-100 to-gray-200' }, { id: 'light', gradient: 'bg-gradient-to-r from-gray-100 to-gray-200' },
{ id: 'dark', name: 'Dark', gradient: 'bg-gradient-to-r from-gray-800 to-gray-900' }, { id: 'dark', gradient: 'bg-gradient-to-r from-black to-gray-900' },
{ id: 'sunset', name: 'Sunset', gradient: 'bg-gradient-to-r from-orange-400 to-pink-500' }, { id: 'sunset', gradient: 'bg-gradient-to-r from-orange-400 to-pink-500' },
{ id: 'ocean', name: 'Ocean', gradient: 'bg-gradient-to-r from-blue-400 to-cyan-500' }, { id: 'ocean', gradient: 'bg-gradient-to-r from-blue-400 to-cyan-500' },
{ id: 'forest', name: 'Forest', gradient: 'bg-gradient-to-r from-green-400 to-teal-500' }, { id: 'forest', gradient: 'bg-gradient-to-r from-green-400 to-teal-500' },
{ id: 'purple', name: 'Purple', gradient: 'bg-gradient-to-r from-purple-500 to-pink-500' }, { id: 'purple', gradient: 'bg-gradient-to-r from-purple-500 to-pink-500' },
]; ];
export default function Profile() { export default function Profile() {
@@ -140,7 +140,7 @@ export default function Profile() {
<div className="space-y-6"> <div className="space-y-6">
<div className="glass-effect rounded-2xl shadow-lg p-6"> <div className="glass-effect rounded-2xl shadow-lg p-6">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-gradient-to-br from-blue-500 to-purple-500 text-white rounded-xl"> <div className="p-2 category-icon text-white rounded-xl">
<UserIcon className="w-6 h-6" /> <UserIcon className="w-6 h-6" />
</div> </div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.info')}</h2> <h2 className="text-xl font-bold text-gray-800">{t('profile.info')}</h2>
@@ -160,7 +160,7 @@ export default function Profile() {
{selectedFamily && ( {selectedFamily && (
<div className="glass-effect rounded-2xl shadow-lg p-6"> <div className="glass-effect rounded-2xl shadow-lg p-6">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-gradient-to-br from-green-500 to-teal-500 text-white rounded-xl"> <div className="p-2 btn-success text-white rounded-xl">
<Users className="w-6 h-6" /> <Users className="w-6 h-6" />
</div> </div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.family')}</h2> <h2 className="text-xl font-bold text-gray-800">{t('profile.family')}</h2>
@@ -220,7 +220,7 @@ export default function Profile() {
className={`flex items-center justify-between p-3 rounded-xl ${member.id === user?.id ? 'bg-purple-50 border border-purple-200' : 'bg-gray-50'}`} className={`flex items-center justify-between p-3 rounded-xl ${member.id === user?.id ? 'bg-purple-50 border border-purple-200' : 'bg-gray-50'}`}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="w-8 h-8 bg-gradient-to-br from-purple-400 to-blue-400 rounded-full flex items-center justify-center text-white text-sm font-medium"> <div className="w-8 h-8 category-icon rounded-full flex items-center justify-center text-white text-sm font-medium">
{(member.username || member.email || '?')[0].toUpperCase()} {(member.username || member.email || '?')[0].toUpperCase()}
</div> </div>
<span className="font-medium text-gray-800"> <span className="font-medium text-gray-800">
@@ -247,7 +247,7 @@ export default function Profile() {
<div className="glass-effect rounded-2xl shadow-lg p-6"> <div className="glass-effect rounded-2xl shadow-lg p-6">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-gradient-to-br from-purple-500 to-pink-500 text-white rounded-xl"> <div className="p-2 btn-primary text-white rounded-xl">
<Settings className="w-6 h-6" /> <Settings className="w-6 h-6" />
</div> </div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.settings')}</h2> <h2 className="text-xl font-bold text-gray-800">{t('profile.settings')}</h2>
@@ -264,7 +264,7 @@ export default function Profile() {
onClick={() => handleLocaleChange('ru')} onClick={() => handleLocaleChange('ru')}
className={`flex-1 py-3 px-4 rounded-xl font-medium transition-all ${ className={`flex-1 py-3 px-4 rounded-xl font-medium transition-all ${
preferences.locale === 'ru' preferences.locale === 'ru'
? 'bg-purple-500 text-white shadow-lg' ? 'btn-primary text-white shadow-lg'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`} }`}
> >
@@ -276,7 +276,7 @@ export default function Profile() {
onClick={() => handleLocaleChange('en')} onClick={() => handleLocaleChange('en')}
className={`flex-1 py-3 px-4 rounded-xl font-medium transition-all ${ className={`flex-1 py-3 px-4 rounded-xl font-medium transition-all ${
preferences.locale === 'en' preferences.locale === 'en'
? 'bg-purple-500 text-white shadow-lg' ? 'btn-primary text-white shadow-lg'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`} }`}
> >
@@ -304,7 +304,7 @@ export default function Profile() {
}`} }`}
> >
<div className={`h-12 rounded-lg ${theme.gradient}`} /> <div className={`h-12 rounded-lg ${theme.gradient}`} />
<span className="text-xs text-gray-600 mt-1 block">{theme.name}</span> <span className="text-xs text-gray-600 mt-1 block">{t(`profile.themes.${theme.id}`)}</span>
{preferences.theme === theme.id && ( {preferences.theme === theme.id && (
<div className="absolute top-2 right-2 w-5 h-5 bg-white rounded-full flex items-center justify-center shadow"> <div className="absolute top-2 right-2 w-5 h-5 bg-white rounded-full flex items-center justify-center shadow">
<Check className="w-3 h-3 text-purple-600" /> <Check className="w-3 h-3 text-purple-600" />
@@ -320,7 +320,7 @@ export default function Profile() {
{selectedFamily && ( {selectedFamily && (
<div className="glass-effect rounded-2xl shadow-lg p-6 border-2 border-red-200"> <div className="glass-effect rounded-2xl shadow-lg p-6 border-2 border-red-200">
<div className="flex items-center gap-3 mb-4"> <div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-gradient-to-br from-red-500 to-orange-500 text-white rounded-xl"> <div className="p-2 btn-danger text-white rounded-xl">
<AlertTriangle className="w-6 h-6" /> <AlertTriangle className="w-6 h-6" />
</div> </div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.dangerZone')}</h2> <h2 className="text-xl font-bold text-gray-800">{t('profile.dangerZone')}</h2>
@@ -331,7 +331,7 @@ export default function Profile() {
<button <button
onClick={handleLeaveFamily} onClick={handleLeaveFamily}
disabled={leavingFamily} disabled={leavingFamily}
className="w-full flex items-center justify-center gap-2 px-6 py-3 bg-red-500 hover:bg-red-600 text-white rounded-xl transition-all font-semibold disabled:opacity-50" className="w-full flex items-center justify-center gap-2 px-6 py-3 btn-danger text-white rounded-xl transition-all font-semibold disabled:opacity-50"
> >
{leavingFamily ? ( {leavingFamily ? (
<> <>