2 Commits

Author SHA1 Message Date
4600400ba6 Merge pull request 'fixes' (#3) from feature/personal-account into master
All checks were successful
Build and Publish Images / build-and-push (push) Successful in 12s
Reviewed-on: http://192.168.31.100:3847/Arrelin/family_budget/pulls/3
2026-01-23 14:02:50 +00:00
arrelin
471da855bf fixes 2026-01-23 17:01:47 +03:00
11 changed files with 194 additions and 68 deletions

View File

@@ -27,8 +27,8 @@ export default function ConfirmModal({
switch (variant) {
case 'danger':
return {
icon: 'bg-red-100 text-red-600',
confirmButton: 'bg-gradient-to-r from-red-500 to-red-600 hover:shadow-lg',
icon: 'btn-danger',
confirmButton: 'btn-danger hover:shadow-lg',
};
case 'warning':
return {
@@ -37,8 +37,8 @@ export default function ConfirmModal({
};
case 'info':
return {
icon: 'bg-blue-100 text-blue-600',
confirmButton: 'bg-gradient-to-r from-blue-500 to-blue-600 hover:shadow-lg',
icon: 'btn-primary',
confirmButton: 'btn-primary hover:shadow-lg',
};
}
};
@@ -47,10 +47,10 @@ export default function ConfirmModal({
return (
<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="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" />
</div>
<div className="flex-1">

View File

@@ -189,8 +189,8 @@ export default function ShoppingListModal({ familyId, onClose }: ShoppingListMod
return (
<>
<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="bg-gradient-to-r from-green-500 to-emerald-600 p-6 flex items-center justify-between">
<div className="glass-effect rounded-3xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-hidden flex flex-col">
<div className="btn-success p-6 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="p-3 bg-white/20 backdrop-blur-md rounded-2xl">
<ShoppingCart className="w-8 h-8 text-white" />
@@ -218,7 +218,7 @@ export default function ShoppingListModal({ familyId, onClose }: ShoppingListMod
/>
<button
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" />
<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">
<button
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" />
{t('shopping.allPurchased')}
</button>
<button
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" />
{t('shopping.clear')}

View File

@@ -159,6 +159,14 @@
"leaveConfirm": "Are you sure you want to leave the family?",
"leaving": "Leaving...",
"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": "Вы уверены, что хотите покинуть семью?",
"leaving": "Выход...",
"leaveError": "Ошибка при выходе из семьи",
"renameError": "Ошибка при переименовании семьи"
"renameError": "Ошибка при переименовании семьи",
"themes": {
"light": "Светлая",
"dark": "Тёмная",
"sunset": "Закат",
"ocean": "Океан",
"forest": "Лес",
"purple": "Фиолетовая"
}
}
}

View File

@@ -7,14 +7,32 @@
--glass-bg: rgba(255, 255, 255, 0.8);
--text-primary: #1f2937;
--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"] {
--gradient-start: #1f2937;
--gradient-end: #111827;
--glass-bg: rgba(31, 41, 55, 0.9);
--gradient-start: #000000;
--gradient-end: #000000;
--glass-bg: rgba(17, 17, 17, 0.95);
--text-primary: #f9fafb;
--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"] {
@@ -23,6 +41,15 @@
--glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937;
--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"] {
@@ -31,6 +58,15 @@
--glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937;
--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"] {
@@ -39,6 +75,15 @@
--glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937;
--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"] {
@@ -47,6 +92,15 @@
--glass-bg: rgba(255, 255, 255, 0.85);
--text-primary: #1f2937;
--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 {
@@ -67,10 +121,66 @@
}
.glass-effect {
background: rgb(255 255 255 / 0.8);
background: var(--glass-bg);
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 {
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="glass-effect rounded-2xl shadow-2xl p-6 sm:p-8 text-center">
<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" />
</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="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" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-gray-800">
@@ -174,7 +174,7 @@ export default function AdminPanel() {
</div>
<button
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" />
{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="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" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-gray-800">
@@ -194,8 +194,8 @@ export default function AdminPanel() {
{families.length === 0 ? (
<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">
<Users className="w-20 h-20 text-purple-400" />
<div className="inline-flex p-6 bg-gray-100 rounded-3xl mb-6">
<Users className="w-20 h-20 text-gray-400" />
</div>
<p className="text-gray-600 text-lg sm:text-xl mb-2 font-semibold">
{t('admin.noFamilies')}
@@ -209,10 +209,10 @@ export default function AdminPanel() {
{families.map((family) => (
<div
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="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" />
</div>
<span className="text-lg sm:text-xl font-bold text-gray-900">
@@ -221,7 +221,7 @@ export default function AdminPanel() {
</div>
<button
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" />
{t('common.delete')}

View File

@@ -308,7 +308,7 @@ export default function FamilyView() {
</div>
<button
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" />
{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 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" />
</div>
<h2 className="text-xl sm:text-2xl font-bold text-gray-900">
@@ -350,7 +350,7 @@ export default function FamilyView() {
{showAddExpense !== category.id && (
<button
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" />
<span className="hidden sm:inline">{t('category.addExpense')}</span>
@@ -407,7 +407,7 @@ export default function FamilyView() {
</div>
{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">
<h3 className="font-semibold text-gray-800 text-lg flex items-center gap-2">
<History className="w-5 h-5" />
@@ -458,7 +458,7 @@ export default function FamilyView() {
)}
{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">
{t('expense.addTitle')}
</h3>
@@ -490,7 +490,7 @@ export default function FamilyView() {
<div className="flex gap-3">
<button
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" />
{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="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" />
</div>
<h2 className="text-2xl sm:text-3xl font-bold text-gray-800">
@@ -521,7 +521,7 @@ export default function FamilyView() {
</div>
{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">
{t('category.newCategory')}
</h3>
@@ -543,7 +543,7 @@ export default function FamilyView() {
<div className="flex gap-3">
<button
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" />
{t('common.create')}
@@ -560,7 +560,7 @@ export default function FamilyView() {
) : (
<button
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" />
{t('category.addCategory')}
@@ -578,10 +578,10 @@ export default function FamilyView() {
{showInviteModal && (
<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 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" />
</div>
<h2 className="text-xl font-bold text-gray-800">{t('invite.title')}</h2>
@@ -602,7 +602,7 @@ export default function FamilyView() {
<button
onClick={handleCreateInviteLink}
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 ? (
<>
@@ -631,8 +631,8 @@ export default function FamilyView() {
onClick={handleCopyInviteLink}
className={`w-full flex items-center justify-center gap-2 px-6 py-4 rounded-2xl transition-all font-semibold ${
copied
? 'bg-green-500 text-white'
: 'bg-gradient-to-r from-purple-600 to-blue-600 text-white hover:shadow-xl'
? 'btn-success text-white'
: 'btn-primary text-white hover:shadow-xl'
}`}
>
{copied ? (

View File

@@ -109,15 +109,15 @@ export default function InvitePage() {
if (error) {
return (
<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="p-4 bg-red-100 rounded-2xl inline-block mb-6">
<AlertCircle className="w-12 h-12 text-red-500" />
<div className="glass-effect rounded-3xl shadow-2xl p-8 max-w-md w-full text-center">
<div className="p-4 btn-danger rounded-2xl inline-block mb-6">
<AlertCircle className="w-12 h-12 text-white" />
</div>
<h1 className="text-2xl font-bold text-gray-800 mb-4">{t('common.error')}</h1>
<p className="text-gray-600 mb-6">{error}</p>
<button
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')}
</button>
@@ -128,14 +128,14 @@ export default function InvitePage() {
return (
<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="p-4 bg-gradient-to-br from-purple-500 to-blue-500 rounded-2xl inline-block mb-6">
<div className="glass-effect rounded-3xl shadow-2xl p-8 max-w-md w-full text-center">
<div className="p-4 category-icon rounded-2xl inline-block mb-6">
<Users className="w-12 h-12 text-white" />
</div>
<h1 className="text-2xl font-bold text-gray-800 mb-2">
{t('invite.pageTitle')}
</h1>
<p className="text-3xl font-bold text-purple-600 mb-6">
<p className="text-3xl font-bold text-gray-800 mb-6">
{familyName}
</p>
<p className="text-gray-600 mb-8">
@@ -143,7 +143,7 @@ export default function InvitePage() {
</p>
<button
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" />
{t('invite.loginAndJoin')}

View File

@@ -27,7 +27,7 @@ export default function Login() {
<div className="w-full max-w-md">
<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="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" />
</div>
<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="glass-effect rounded-3xl shadow-2xl p-8 sm:p-10">
<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" />
</div>
<h1 className="text-2xl sm:text-3xl font-bold text-gray-900 mb-2">
@@ -186,7 +186,7 @@ export default function NoFamily() {
<button
type="submit"
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 ? (
<Loader2 className="w-5 h-5 animate-spin" />

View File

@@ -20,13 +20,13 @@ import {
X,
} from 'lucide-react';
const THEMES: { id: Theme; name: string; gradient: string }[] = [
{ id: 'light', name: '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: 'sunset', name: '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: 'forest', name: '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' },
const THEMES: { id: Theme; gradient: string }[] = [
{ id: 'light', gradient: 'bg-gradient-to-r from-gray-100 to-gray-200' },
{ id: 'dark', gradient: 'bg-gradient-to-r from-black to-gray-900' },
{ id: 'sunset', gradient: 'bg-gradient-to-r from-orange-400 to-pink-500' },
{ id: 'ocean', gradient: 'bg-gradient-to-r from-blue-400 to-cyan-500' },
{ id: 'forest', gradient: 'bg-gradient-to-r from-green-400 to-teal-500' },
{ id: 'purple', gradient: 'bg-gradient-to-r from-purple-500 to-pink-500' },
];
export default function Profile() {
@@ -140,7 +140,7 @@ export default function Profile() {
<div className="space-y-6">
<div className="glass-effect rounded-2xl shadow-lg p-6">
<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" />
</div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.info')}</h2>
@@ -160,7 +160,7 @@ export default function Profile() {
{selectedFamily && (
<div className="glass-effect rounded-2xl shadow-lg p-6">
<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" />
</div>
<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'}`}
>
<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()}
</div>
<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="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" />
</div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.settings')}</h2>
@@ -264,7 +264,7 @@ export default function Profile() {
onClick={() => handleLocaleChange('ru')}
className={`flex-1 py-3 px-4 rounded-xl font-medium transition-all ${
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'
}`}
>
@@ -276,7 +276,7 @@ export default function Profile() {
onClick={() => handleLocaleChange('en')}
className={`flex-1 py-3 px-4 rounded-xl font-medium transition-all ${
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'
}`}
>
@@ -304,7 +304,7 @@ export default function Profile() {
}`}
>
<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 && (
<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" />
@@ -320,7 +320,7 @@ export default function Profile() {
{selectedFamily && (
<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="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" />
</div>
<h2 className="text-xl font-bold text-gray-800">{t('profile.dangerZone')}</h2>
@@ -331,7 +331,7 @@ export default function Profile() {
<button
onClick={handleLeaveFamily}
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 ? (
<>