ci: add Gitea Actions workflows and placeholder tests
Some checks failed
Deploy Production / deploy (push) Failing after 1m45s
CI / ci (push) Failing after 30s

This commit is contained in:
Cosmo
2026-03-01 00:04:14 +00:00
parent b7ce5ab1fb
commit ec6993de98
53 changed files with 65421 additions and 1263 deletions

View File

@@ -28,11 +28,8 @@ export default function Habits() {
enabled: showArchived,
})
// Загружаем статистику для каждой привычки
useEffect(() => {
if (habits.length > 0) {
loadStats()
}
if (habits.length > 0) loadStats()
}, [habits])
const loadStats = async () => {
@@ -41,9 +38,7 @@ export default function Habits() {
try {
const stats = await habitsApi.getHabitStats(habit.id)
statsMap[habit.id] = stats
} catch (e) {
console.error('Error loading stats for habit', habit.id, e)
}
} catch (e) {}
}))
setHabitStats(statsMap)
}
@@ -63,9 +58,8 @@ export default function Habits() {
const days = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
return habit.target_days.map(d => days[d - 1]).join(', ')
}
if (habit.frequency === 'custom') {
return `Каждые ${habit.target_count} дн.`
}
if (habit.frequency === 'interval') return `Каждые ${habit.target_count} дн.`
if (habit.frequency === 'custom') return `Каждые ${habit.target_count} дн.`
return habit.frequency
}
@@ -73,17 +67,14 @@ export default function Habits() {
const archivedList = habits.filter(h => h.is_archived)
return (
<div className="min-h-screen bg-surface-50 gradient-mesh pb-24">
<header className="bg-white/70 backdrop-blur-xl border-b border-gray-100/50 sticky top-0 z-10">
<div className="min-h-screen bg-surface-50 dark:bg-gray-950 gradient-mesh pb-24 transition-colors duration-300">
<header className="bg-white/70 dark:bg-gray-900/70 backdrop-blur-xl border-b border-gray-100/50 dark:border-gray-800 sticky top-0 z-10">
<div className="max-w-lg mx-auto px-4 py-4 flex items-center justify-between">
<div>
<h1 className="text-xl font-display font-bold text-gray-900">Мои привычки</h1>
<p className="text-sm text-gray-500">{activeHabits.length} активных</p>
<h1 className="text-xl font-display font-bold text-gray-900 dark:text-white">Мои привычки</h1>
<p className="text-sm text-gray-500 dark:text-gray-400">{activeHabits.length} активных</p>
</div>
<button
onClick={() => setShowCreateModal(true)}
className="btn btn-primary flex items-center gap-2"
>
<button onClick={() => setShowCreateModal(true)} className="btn btn-primary flex items-center gap-2">
<Plus size={18} />
Новая
</button>
@@ -96,37 +87,29 @@ export default function Habits() {
{[1, 2, 3].map((i) => (
<div key={i} className="card p-5 animate-pulse">
<div className="flex items-center gap-4">
<div className="w-14 h-14 rounded-2xl bg-gray-200" />
<div className="w-14 h-14 rounded-2xl bg-gray-200 dark:bg-gray-700" />
<div className="flex-1">
<div className="h-5 bg-gray-200 rounded-lg w-1/2 mb-2" />
<div className="h-4 bg-gray-200 rounded-lg w-1/3" />
<div className="h-5 bg-gray-200 dark:bg-gray-700 rounded-lg w-1/2 mb-2" />
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded-lg w-1/3" />
</div>
</div>
</div>
))}
</div>
) : activeHabits.length === 0 && !showArchived ? (
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="card p-10 text-center"
>
<div className="w-20 h-20 rounded-3xl bg-gradient-to-br from-primary-100 to-accent-100 flex items-center justify-center mx-auto mb-5">
<Plus className="w-10 h-10 text-primary-600" />
<motion.div initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} className="card p-10 text-center">
<div className="w-20 h-20 rounded-3xl bg-gradient-to-br from-primary-100 to-accent-100 dark:from-primary-900/30 dark:to-accent-900/30 flex items-center justify-center mx-auto mb-5">
<Plus className="w-10 h-10 text-primary-600 dark:text-primary-400" />
</div>
<h3 className="text-xl font-display font-bold text-gray-900 mb-2">Нет привычек</h3>
<p className="text-gray-500 mb-6">Создай свою первую привычку!</p>
<button
onClick={() => setShowCreateModal(true)}
className="btn btn-primary"
>
<h3 className="text-xl font-display font-bold text-gray-900 dark:text-white mb-2">Нет привычек</h3>
<p className="text-gray-500 dark:text-gray-400 mb-6">Создай свою первую привычку!</p>
<button onClick={() => setShowCreateModal(true)} className="btn btn-primary">
<Plus size={20} className="mr-2" />
Создать привычку
</button>
</motion.div>
) : (
<>
{/* Активные привычки */}
<div className="space-y-3">
<AnimatePresence>
{activeHabits.map((habit, index) => (
@@ -143,32 +126,17 @@ export default function Habits() {
</AnimatePresence>
</div>
{/* Архивные привычки */}
{archivedList.length > 0 && (
<div className="mt-8">
<button
onClick={() => setShowArchived(!showArchived)}
className="flex items-center gap-2 text-gray-500 hover:text-gray-700 mb-4"
>
<button onClick={() => setShowArchived(!showArchived)} className="flex items-center gap-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 mb-4">
<Archive size={18} />
<span className="font-medium">Архив ({archivedList.length})</span>
<ChevronRight
size={18}
className={clsx(
'transition-transform',
showArchived && 'rotate-90'
)}
/>
<ChevronRight size={18} className={clsx('transition-transform', showArchived && 'rotate-90')} />
</button>
<AnimatePresence>
{showArchived && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="space-y-3"
>
<motion.div initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: 'auto' }} exit={{ opacity: 0, height: 0 }} className="space-y-3">
{archivedList.map((habit, index) => (
<motion.div
key={habit.id}
@@ -178,21 +146,14 @@ export default function Habits() {
className="card p-4 opacity-60"
>
<div className="flex items-center gap-4">
<div
className="w-12 h-12 rounded-xl flex items-center justify-center text-xl"
style={{ backgroundColor: habit.color + '20' }}
>
<div className="w-12 h-12 rounded-xl flex items-center justify-center text-xl" style={{ backgroundColor: habit.color + '20' }}>
{habit.icon || '✨'}
</div>
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-600 truncate">{habit.name}</h3>
<p className="text-sm text-gray-400">{getFrequencyLabel(habit)}</p>
<h3 className="font-semibold text-gray-600 dark:text-gray-400 truncate">{habit.name}</h3>
<p className="text-sm text-gray-400 dark:text-gray-500">{getFrequencyLabel(habit)}</p>
</div>
<button
onClick={() => archiveMutation.mutate({ id: habit.id, archived: false })}
className="p-2 text-gray-400 hover:text-green-500 hover:bg-green-50 rounded-xl transition-all"
title="Восстановить"
>
<button onClick={() => archiveMutation.mutate({ id: habit.id, archived: false })} className="p-2 text-gray-400 hover:text-green-500 hover:bg-green-50 dark:hover:bg-green-900/20 rounded-xl transition-all" title="Восстановить">
<ArchiveRestore size={20} />
</button>
</div>
@@ -208,17 +169,8 @@ export default function Habits() {
</main>
<Navigation />
<CreateHabitModal
open={showCreateModal}
onClose={() => setShowCreateModal(false)}
/>
<EditHabitModal
open={!!editingHabit}
onClose={() => setEditingHabit(null)}
habit={editingHabit}
/>
<CreateHabitModal open={showCreateModal} onClose={() => setShowCreateModal(false)} />
<EditHabitModal open={!!editingHabit} onClose={() => setEditingHabit(null)} habit={editingHabit} />
</div>
)
}
@@ -234,20 +186,14 @@ function HabitListItem({ habit, index, stats, frequencyLabel, onEdit, onArchive
className="card p-4 cursor-pointer hover:shadow-lg transition-all"
>
<div className="flex items-center gap-4">
<div
className="w-14 h-14 rounded-2xl flex items-center justify-center text-2xl flex-shrink-0"
style={{ backgroundColor: habit.color + '15' }}
>
<div className="w-14 h-14 rounded-2xl flex items-center justify-center text-2xl flex-shrink-0" style={{ backgroundColor: habit.color + '15' }}>
{habit.icon || '✨'}
</div>
<div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 truncate">{habit.name}</h3>
<h3 className="font-semibold text-gray-900 dark:text-white truncate">{habit.name}</h3>
<div className="flex items-center gap-3 mt-1">
<span
className="text-xs font-medium px-2 py-0.5 rounded-full"
style={{ backgroundColor: habit.color + '15', color: habit.color }}
>
<span className="text-xs font-medium px-2 py-0.5 rounded-full" style={{ backgroundColor: habit.color + '15', color: habit.color }}>
{frequencyLabel}
</span>
{stats && stats.current_streak > 0 && (
@@ -262,11 +208,11 @@ function HabitListItem({ habit, index, stats, frequencyLabel, onEdit, onArchive
<div className="flex items-center gap-2">
{stats && (
<div className="text-right">
<p className="text-sm font-semibold text-gray-900">{stats.this_month}</p>
<p className="text-xs text-gray-400">в месяц</p>
<p className="text-sm font-semibold text-gray-900 dark:text-white">{stats.this_month}</p>
<p className="text-xs text-gray-400 dark:text-gray-500">в месяц</p>
</div>
)}
<ChevronRight size={20} className="text-gray-300" />
<ChevronRight size={20} className="text-gray-300 dark:text-gray-600" />
</div>
</div>
</motion.div>