Исправлены отступы в списке слов
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user