more fixes
This commit is contained in:
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -121,6 +121,12 @@ jobs:
|
|||||||
|
|
||||||
# Deploy with zero downtime
|
# Deploy with zero downtime
|
||||||
docker-compose --env-file .env.docker pull
|
docker-compose --env-file .env.docker pull
|
||||||
|
|
||||||
|
# Stop existing containers if they exist
|
||||||
|
if docker-compose --env-file .env.docker ps -q | grep -q .; then
|
||||||
|
docker-compose --env-file .env.docker down --remove-orphans
|
||||||
|
fi
|
||||||
|
|
||||||
docker-compose --env-file .env.docker up -d
|
docker-compose --env-file .env.docker up -d
|
||||||
|
|
||||||
# Cleanup old images
|
# Cleanup old images
|
||||||
|
|||||||
Binary file not shown.
19
.serena/memories/notification_animation_fix.md
Normal file
19
.serena/memories/notification_animation_fix.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Notification Animation Fix
|
||||||
|
|
||||||
|
Fixed the download notification display issue where notifications appeared strangely (first in corner, then stretched).
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
- `.tg-status-message` had conflicting width properties
|
||||||
|
- Complex positioning caused weird stretch animation
|
||||||
|
- Used `transform: translateX(-50%)` with multiple width calculations
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
- Simplified positioning: `left/right` with `var(--tg-spacing-lg)` margins
|
||||||
|
- Removed conflicting width properties (`max-width`, `width`, `min-width`)
|
||||||
|
- Changed position from `top: 80px` to `top: 20px`
|
||||||
|
- Updated animation from `tg-slide-in` to `tg-slide-down` for natural top-to-bottom appearance
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
- `public/style.css`: Updated `.tg-status-message` styles and animation keyframes
|
||||||
|
|
||||||
|
The notification now appears smoothly at the top of the screen without strange stretching effects.
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
<!-- Search results will appear here -->
|
<!-- Search results will appear here -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tg-placeholder tg-placeholder--secondary tg-hidden" id="noResults">
|
<div class="tg-placeholder tg-placeholder--secondary tg-hidden" id="noResults" style="display: none;">
|
||||||
<div class="tg-placeholder__icon">🔍</div>
|
<div class="tg-placeholder__icon">🔍</div>
|
||||||
<div class="tg-placeholder__title">Ничего не найдено</div>
|
<div class="tg-placeholder__title">Ничего не найдено</div>
|
||||||
<div class="tg-placeholder__description">Попробуйте изменить поисковый запрос</div>
|
<div class="tg-placeholder__description">Попробуйте изменить поисковый запрос</div>
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ class QuixoticApp {
|
|||||||
this.results = document.getElementById('results') as HTMLElement;
|
this.results = document.getElementById('results') as HTMLElement;
|
||||||
this.noResults = document.getElementById('noResults') as HTMLElement;
|
this.noResults = document.getElementById('noResults') as HTMLElement;
|
||||||
this.welcomePlaceholder = document.getElementById('welcomePlaceholder') as HTMLElement;
|
this.welcomePlaceholder = document.getElementById('welcomePlaceholder') as HTMLElement;
|
||||||
|
|
||||||
|
// Initialize proper state - only welcome should be visible
|
||||||
|
this.resetToWelcomeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bindEvents(): void {
|
private bindEvents(): void {
|
||||||
@@ -74,6 +77,30 @@ class QuixoticApp {
|
|||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Reset to welcome state when input is cleared
|
||||||
|
this.searchInput.addEventListener('input', () => {
|
||||||
|
if (this.searchInput.value.trim() === '') {
|
||||||
|
this.resetToWelcomeState();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetToWelcomeState(): void {
|
||||||
|
// Show only welcome placeholder
|
||||||
|
this.welcomePlaceholder.classList.remove('tg-hidden');
|
||||||
|
this.welcomePlaceholder.style.display = '';
|
||||||
|
|
||||||
|
// Hide all other states
|
||||||
|
this.loading.classList.add('tg-hidden');
|
||||||
|
this.loading.classList.remove('tg-spinner--visible');
|
||||||
|
this.results.classList.add('tg-hidden');
|
||||||
|
this.results.classList.remove('tg-list--visible');
|
||||||
|
this.noResults.classList.add('tg-hidden');
|
||||||
|
this.noResults.style.display = 'none';
|
||||||
|
|
||||||
|
// Enable search button
|
||||||
|
this.searchBtn.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async search(): Promise<void> {
|
private async search(): Promise<void> {
|
||||||
@@ -107,12 +134,26 @@ class QuixoticApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private showLoading(): void {
|
private showLoading(): void {
|
||||||
|
// Clear any existing status messages
|
||||||
|
const existingMessage = document.querySelector('.tg-status-message');
|
||||||
|
if (existingMessage) {
|
||||||
|
existingMessage.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide welcome immediately when loading starts
|
||||||
this.welcomePlaceholder.classList.add('tg-hidden');
|
this.welcomePlaceholder.classList.add('tg-hidden');
|
||||||
|
this.welcomePlaceholder.style.display = 'none';
|
||||||
|
|
||||||
|
// Show loading spinner
|
||||||
this.loading.classList.remove('tg-hidden');
|
this.loading.classList.remove('tg-hidden');
|
||||||
this.loading.classList.add('tg-spinner--visible');
|
this.loading.classList.add('tg-spinner--visible');
|
||||||
|
|
||||||
|
// Hide other elements
|
||||||
this.results.classList.add('tg-hidden');
|
this.results.classList.add('tg-hidden');
|
||||||
this.results.classList.remove('tg-list--visible');
|
this.results.classList.remove('tg-list--visible');
|
||||||
this.noResults.classList.add('tg-hidden');
|
this.noResults.classList.add('tg-hidden');
|
||||||
|
this.noResults.style.display = 'none';
|
||||||
|
|
||||||
this.searchBtn.disabled = true;
|
this.searchBtn.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +171,12 @@ class QuixoticApp {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide welcome and no results
|
||||||
|
this.welcomePlaceholder.classList.add('tg-hidden');
|
||||||
|
this.welcomePlaceholder.style.display = 'none';
|
||||||
|
this.noResults.classList.add('tg-hidden');
|
||||||
|
this.noResults.style.display = 'none';
|
||||||
|
|
||||||
this.results.innerHTML = videos.map(video => `
|
this.results.innerHTML = videos.map(video => `
|
||||||
<div class='tg-list-item' onclick='app.convertVideo("${video.id}", "${this.escapeHtml(video.title)}", "${this.escapeHtml(video.url)}")'>
|
<div class='tg-list-item' onclick='app.convertVideo("${video.id}", "${this.escapeHtml(video.title)}", "${this.escapeHtml(video.url)}")'>
|
||||||
<div class='tg-list-item__content'>
|
<div class='tg-list-item__content'>
|
||||||
@@ -150,14 +197,16 @@ class QuixoticApp {
|
|||||||
|
|
||||||
this.results.classList.remove('tg-hidden');
|
this.results.classList.remove('tg-hidden');
|
||||||
this.results.classList.add('tg-list--visible');
|
this.results.classList.add('tg-list--visible');
|
||||||
this.noResults.classList.add('tg-hidden');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private showNoResults(): void {
|
private showNoResults(): void {
|
||||||
this.hideLoading();
|
this.hideLoading();
|
||||||
|
this.welcomePlaceholder.classList.add('tg-hidden');
|
||||||
|
this.welcomePlaceholder.style.display = 'none';
|
||||||
this.results.classList.add('tg-hidden');
|
this.results.classList.add('tg-hidden');
|
||||||
this.results.classList.remove('tg-list--visible');
|
this.results.classList.remove('tg-list--visible');
|
||||||
this.noResults.classList.remove('tg-hidden');
|
this.noResults.classList.remove('tg-hidden');
|
||||||
|
this.noResults.style.display = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public async convertVideo(videoId: string, title: string, url: string): Promise<void> {
|
public async convertVideo(videoId: string, title: string, url: string): Promise<void> {
|
||||||
|
|||||||
@@ -198,9 +198,14 @@ body {
|
|||||||
|
|
||||||
/* Spinner component */
|
/* Spinner component */
|
||||||
.tg-spinner {
|
.tg-spinner {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: var(--tg-spacing-xxl);
|
padding: var(--tg-spacing-xxl);
|
||||||
display: none;
|
display: none;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tg-spinner.tg-spinner--visible {
|
.tg-spinner.tg-spinner--visible {
|
||||||
@@ -344,47 +349,45 @@ body {
|
|||||||
/* Status message */
|
/* Status message */
|
||||||
.tg-status-message {
|
.tg-status-message {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 80px;
|
top: 20px;
|
||||||
left: 50%;
|
left: var(--tg-spacing-lg);
|
||||||
transform: translateX(-50%);
|
right: var(--tg-spacing-lg);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
padding: var(--tg-spacing-md) var(--tg-spacing-lg);
|
padding: var(--tg-spacing-md) var(--tg-spacing-lg);
|
||||||
border-radius: var(--tg-border-radius);
|
border-radius: var(--tg-border-radius);
|
||||||
font-size: var(--tg-font-size-sm);
|
font-size: var(--tg-font-size-sm);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
animation: tg-slide-in 0.3s ease-out;
|
animation: tg-slide-down 0.3s ease-out;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--tg-spacing-sm);
|
gap: var(--tg-spacing-sm);
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25), 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
max-width: calc(100vw - 32px);
|
|
||||||
width: calc(100vw - 64px);
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tg-status-message--success {
|
.tg-status-message--success {
|
||||||
background: rgba(52, 199, 89, 0.1);
|
background: #34c759;
|
||||||
border: 1px solid rgba(52, 199, 89, 0.3);
|
border: 1px solid #2aa854;
|
||||||
color: #34c759;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tg-status-message--error {
|
.tg-status-message--error {
|
||||||
background: rgba(255, 59, 48, 0.1);
|
background: #ff3b30;
|
||||||
border: 1px solid rgba(255, 59, 48, 0.3);
|
border: 1px solid #d70015;
|
||||||
color: var(--tg-color-destructive);
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tg-status-message--info {
|
.tg-status-message--info {
|
||||||
background: rgba(0, 122, 255, 0.1);
|
background: #007aff;
|
||||||
border: 1px solid rgba(0, 122, 255, 0.3);
|
border: 1px solid #0056cc;
|
||||||
color: var(--tg-color-button);
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes tg-slide-in {
|
@keyframes tg-slide-down {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(-10px);
|
transform: translateY(-20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user