Исправлены отступы в списке слов
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s

This commit is contained in:
poignatov
2026-01-20 21:33:23 +03:00
parent 2626722af9
commit e41f721106
12 changed files with 115 additions and 144 deletions

View File

@@ -1 +1 @@
3.24.1 3.24.2

View File

@@ -1,6 +1,6 @@
{ {
"name": "play-life-web", "name": "play-life-web",
"version": "3.24.1", "version": "3.24.2",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -765,7 +765,7 @@ function AppContent() {
}, [activeTab]) }, [activeTab])
// Определяем, нужно ли скрывать нижнюю панель (для fullscreen экранов) // Определяем, нужно ли скрывать нижнюю панель (для fullscreen экранов)
const isFullscreenTab = activeTab === 'test' || activeTab === 'add-words' || activeTab === 'task-form' || activeTab === 'wishlist-form' || activeTab === 'wishlist-detail' || activeTab === 'todoist-integration' || activeTab === 'telegram-integration' || activeTab === 'full' || activeTab === 'priorities' || activeTab === 'dictionaries' const isFullscreenTab = activeTab === 'test' || activeTab === 'add-words' || activeTab === 'task-form' || activeTab === 'wishlist-form' || activeTab === 'wishlist-detail' || activeTab === 'todoist-integration' || activeTab === 'telegram-integration' || activeTab === 'full' || activeTab === 'priorities' || activeTab === 'dictionaries' || activeTab === 'words'
// Определяем отступы для контейнера // Определяем отступы для контейнера
const getContainerPadding = () => { const getContainerPadding = () => {
@@ -788,6 +788,10 @@ function AppContent() {
if (activeTab === 'dictionaries') { if (activeTab === 'dictionaries') {
return 'px-4 md:px-8 py-0' return 'px-4 md:px-8 py-0'
} }
// Для экрана списка слов используем такие же отступы как для словарей
if (activeTab === 'words') {
return 'px-4 md:px-8 py-0'
}
// Для остальных fullscreen экранов без отступов // Для остальных fullscreen экранов без отступов
return 'p-0' return 'p-0'
} }

View File

@@ -89,30 +89,6 @@ function DictionaryList({ onNavigate, refreshTrigger = 0 }) {
setSelectedDictionary(null) setSelectedDictionary(null)
} }
// Показываем загрузку только при первой инициализации и если нет данных для отображения
const shouldShowLoading = loading && !isInitializedRef.current && dictionaries.length === 0
if (shouldShowLoading) {
return (
<div className="dictionary-list">
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
</div>
)
}
if (error) {
return (
<div className="dictionary-list">
<LoadingError onRetry={fetchDictionaries} />
</div>
)
}
return ( return (
<div className="dictionary-list"> <div className="dictionary-list">
{/* Кнопка закрытия */} {/* Кнопка закрытия */}
@@ -123,8 +99,18 @@ function DictionaryList({ onNavigate, refreshTrigger = 0 }) {
> >
</button> </button>
{/* Показываем загрузку только при первой инициализации и если нет данных для отображения */}
<div className="dictionaries-grid"> {loading && !isInitializedRef.current && dictionaries.length === 0 ? (
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
) : error ? (
<LoadingError onRetry={fetchDictionaries} />
) : (
<div className="dictionaries-grid">
{dictionaries.map((dict) => ( {dictionaries.map((dict) => (
<div <div
key={dict.id} key={dict.id}
@@ -151,7 +137,8 @@ function DictionaryList({ onNavigate, refreshTrigger = 0 }) {
<div className="add-dictionary-icon">+</div> <div className="add-dictionary-icon">+</div>
<div className="add-dictionary-text">Добавить</div> <div className="add-dictionary-text">Добавить</div>
</button> </button>
</div> </div>
)}
{selectedDictionary && ( {selectedDictionary && (
<div className="dictionary-modal-overlay" onClick={closeDictionaryModal}> <div className="dictionary-modal-overlay" onClick={closeDictionaryModal}>

View File

@@ -117,19 +117,7 @@ function FullStatistics({ selectedProject, onClearSelection, data, loading, erro
const chartData = processData() const chartData = processData()
// Показываем loading только если данных нет и идет загрузка if (error && !chartData && !loading) {
if (loading && !chartData) {
return (
<div className="fixed inset-0 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
)
}
if (error && !chartData) {
return <LoadingError onRetry={onRetry} /> return <LoadingError onRetry={onRetry} />
} }
@@ -194,13 +182,6 @@ function FullStatistics({ selectedProject, onClearSelection, data, loading, erro
}, },
} }
if (!chartData) {
return (
<div className="flex justify-center items-center py-16">
<div className="text-gray-500 text-lg">Нет данных для отображения</div>
</div>
)
}
return ( return (
<div className="max-w-2xl mx-auto"> <div className="max-w-2xl mx-auto">
@@ -213,10 +194,25 @@ function FullStatistics({ selectedProject, onClearSelection, data, loading, erro
</button> </button>
)} )}
<div style={{ height: '550px', paddingTop: '100px' }}> {loading && !chartData ? (
<Line data={chartData} options={chartOptions} /> <div className="fixed inset-0 flex justify-center items-center">
</div> <div className="flex flex-col items-center">
<WeekProgressChart data={data} allProjectsSorted={getAllProjectsSorted(data)} currentWeekData={currentWeekData} selectedProject={selectedProject} /> <div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
) : !chartData ? (
<div className="flex justify-center items-center py-16">
<div className="text-gray-500 text-lg">Нет данных для отображения</div>
</div>
) : (
<>
<div style={{ height: '550px', paddingTop: '100px' }}>
<Line data={chartData} options={chartOptions} />
</div>
<WeekProgressChart data={data} allProjectsSorted={getAllProjectsSorted(data)} currentWeekData={currentWeekData} selectedProject={selectedProject} />
</>
)}
</div> </div>
) )
} }

View File

@@ -705,7 +705,6 @@ function TaskDetail({ taskId, onClose, onRefresh, onTaskCompleted, onNavigate })
</div> </div>
</> </>
)} )}
</div>
</div> </div>
{toastMessage && ( {toastMessage && (
<Toast <Toast
@@ -715,7 +714,8 @@ function TaskDetail({ taskId, onClose, onRefresh, onTaskCompleted, onNavigate })
/> />
)} )}
</div> </div>
) </div>
)
} }
export default TaskDetail export default TaskDetail

View File

@@ -765,25 +765,21 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
} }
} }
if (loadingTask) { return (
return ( <div className="task-form">
<div className="task-form"> <button className="close-x-button" onClick={handleCancel}>
</button>
{loadingTask ? (
<div className="fixed inset-0 flex justify-center items-center"> <div className="fixed inset-0 flex justify-center items-center">
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div> <div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div> <div className="text-gray-600 font-medium">Загрузка...</div>
</div> </div>
</div> </div>
</div> ) : (
) <>
} <h2>{taskId ? 'Редактировать задачу' : 'Новая задача'}</h2>
return (
<div className="task-form">
<button className="close-x-button" onClick={handleCancel}>
</button>
<h2>{taskId ? 'Редактировать задачу' : 'Новая задача'}</h2>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="form-group"> <div className="form-group">
@@ -1196,14 +1192,17 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
)} )}
</div> </div>
</form> </form>
{toastMessage && ( {toastMessage && (
<Toast <Toast
message={toastMessage.text} message={toastMessage.text}
type={toastMessage.type} type={toastMessage.type}
onClose={() => setToastMessage(null)} onClose={() => setToastMessage(null)}
/> />
)} )}
</div> </>
)}
)}
</div>
) )
} }

View File

@@ -595,21 +595,7 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
) )
} }
// Показываем loading только если и доски и желания грузятся if (error && items.length === 0 && !boardsLoading && !loading) {
if (boardsLoading && loading) {
return (
<div className="wishlist">
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
</div>
)
}
if (error && items.length === 0) {
return ( return (
<div className="wishlist"> <div className="wishlist">
<BoardSelector <BoardSelector
@@ -638,7 +624,14 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
/> />
{/* Основной список */} {/* Основной список */}
{loading ? ( {boardsLoading && loading ? (
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
) : loading ? (
<div className="wishlist-loading"> <div className="wishlist-loading">
<div className="w-8 h-8 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin"></div> <div className="w-8 h-8 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin"></div>
</div> </div>

View File

@@ -298,24 +298,20 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId }) {
) )
} }
if (loadingWishlist) {
return (
<div className="wishlist-detail">
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
</div>
)
}
return ( return (
<div className="wishlist-detail"> <div className="wishlist-detail">
<button className="close-x-button" onClick={() => onNavigate?.('wishlist')}> <button className="close-x-button" onClick={() => onNavigate?.('wishlist')}>
</button> </button>
{loadingWishlist && (
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
)}
<h2>{wishlistItem ? wishlistItem.name : 'Желание'}</h2> <h2>{wishlistItem ? wishlistItem.name : 'Желание'}</h2>
<div className="wishlist-detail-content"> <div className="wishlist-detail-content">

View File

@@ -645,25 +645,21 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
} }
} }
if (loadingWishlist) {
return (
<div className="wishlist-form">
<div className="fixed inset-0 bottom-20 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
</div>
)
}
return ( return (
<div className="wishlist-form"> <div className="wishlist-form">
<button className="close-x-button" onClick={handleCancel}> <button className="close-x-button" onClick={handleCancel}>
</button> </button>
<h2>{wishlistId ? 'Редактировать желание' : 'Новое желание'}</h2> {loadingWishlist ? (
<div className="fixed inset-0 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
) : (
<>
<h2>{wishlistId ? 'Редактировать желание' : 'Новое желание'}</h2>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="form-group"> <div className="form-group">
@@ -855,14 +851,17 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
/> />
)} )}
{toastMessage && ( {toastMessage && (
<Toast <Toast
message={toastMessage.text} message={toastMessage.text}
type={toastMessage.type} type={toastMessage.type}
onClose={() => setToastMessage(null)} onClose={() => setToastMessage(null)}
/> />
)} )}
</div> </>
)}
)}
</div>
) )
} }

View File

@@ -1,5 +1,7 @@
.word-list { .word-list {
position: relative; position: relative;
max-width: 42rem; /* max-w-2xl = 672px */
margin: 0 auto;
} }
.close-x-button { .close-x-button {

View File

@@ -161,20 +161,7 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
// Show save button only if name is not empty and has changed // Show save button only if name is not empty and has changed
const showSaveButton = dictionaryName.trim() !== '' && dictionaryName.trim() !== originalDictionaryName const showSaveButton = dictionaryName.trim() !== '' && dictionaryName.trim() !== originalDictionaryName
if (loading) { if (error && !loading) {
return (
<div className="word-list">
<div className="fixed inset-0 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
</div>
)
}
if (error) {
return ( return (
<div className="word-list"> <div className="word-list">
<LoadingError onRetry={() => { <LoadingError onRetry={() => {
@@ -195,6 +182,14 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
> >
</button> </button>
{loading && (
<div className="fixed inset-0 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
)}
{/* Dictionary name input */} {/* Dictionary name input */}
<div className="dictionary-name-input-container"> <div className="dictionary-name-input-container">