denisgay/script.js
2025-11-12 19:51:06 +07:00

266 lines
7.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class QuoteApp {
constructor() {
this.quotes = [];
this.author = "Денис Шулепов";
this.serverUrl = window.location.origin;
this.init();
}
init() {
this.bindEvents();
this.loadQuotes();
}
async loadQuotes() {
try {
const response = await fetch(`${this.serverUrl}/api/quotes`);
if (response.ok) {
this.quotes = await response.json();
this.renderQuotes();
} else {
throw new Error("Ошибка загрузки цитат");
}
} catch (error) {
console.error("Ошибка при загрузке цитат:", error);
this.showError("Не удалось загрузить цитаты с сервера");
this.showEmptyState();
}
}
bindEvents() {
// События удалены - только автоматическая публикация
}
showEmptyState() {
const quotesFeed = document.getElementById("quotesFeed");
quotesFeed.innerHTML = `
<div class="empty-state">
<h2>Добро пожаловать в гейский цитатник!</h2>
<p>Ожидаем первую автоматическую публикацию цитаты...</p>
</div>
`;
}
renderQuotes() {
const quotesFeed = document.getElementById("quotesFeed");
if (this.quotes.length === 0) {
this.showEmptyState();
return;
}
quotesFeed.innerHTML = this.quotes
.map((quote) => this.createQuoteCard(quote))
.join("");
this.bindQuoteActions();
}
createQuoteCard(quote) {
const date = new Date(quote.date).toLocaleDateString("ru-RU", {
day: "numeric",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
});
return `
<div class="quote-card" data-id="${quote.id}">
<div class="quote-header">
<img src="photo_2023-10-27_20-55-45.jpg" alt="${this.escapeHtml(
quote.author
)}" class="quote-avatar">
<div class="quote-author-info">
<div class="quote-author">${this.escapeHtml(
quote.author
)}</div>
<div class="quote-date">${date}</div>
</div>
</div>
<div class="quote-text">${this.escapeHtml(quote.text)}</div>
<div class="quote-actions">
<button class="quote-action-btn copy-btn" onclick="app.copyQuote('${
quote.id
}')">
📋 Копировать
</button>
</div>
</div>
`;
}
bindQuoteActions() {
// Дополнительные обработчики для карточек цитат
}
async generateNewQuote() {
const loading = document.getElementById("loading");
loading.style.display = "block";
try {
const response = await fetch(`${this.serverUrl}/api/quotes`, {
method: "POST",
});
if (response.ok) {
const newQuote = await response.json();
this.quotes.unshift(newQuote);
this.renderQuotes();
this.showSuccess("Новая цитата создана!");
} else {
throw new Error("Ошибка сервера");
}
} catch (error) {
console.error("Ошибка при генерации цитаты:", error);
this.showError(
"Не удалось сгенерировать цитату. Проверьте подключение к серверу."
);
} finally {
loading.style.display = "none";
}
}
async deleteQuote(id) {
if (confirm("Вы уверены, что хотите удалить эту цитату?")) {
try {
const response = await fetch(`${this.serverUrl}/api/quotes/${id}`, {
method: "DELETE",
});
if (response.ok) {
this.quotes = this.quotes.filter((q) => q.id !== id);
this.renderQuotes();
this.showSuccess("Цитата удалена!");
} else {
throw new Error("Ошибка сервера");
}
} catch (error) {
console.error("Ошибка при удалении цитаты:", error);
this.showError("Не удалось удалить цитату");
}
}
}
copyQuote(id) {
const quote = this.quotes.find((q) => q.id === id);
if (quote) {
const text = `"${quote.text}"\n${quote.author}`;
if (navigator.clipboard) {
navigator.clipboard
.writeText(text)
.then(() => {
this.showSuccess("Цитата скопирована в буфер обмена!");
})
.catch(() => {
this.fallbackCopyToClipboard(text);
});
} else {
this.fallbackCopyToClipboard(text);
}
}
}
fallbackCopyToClipboard(text) {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.position = "fixed";
textArea.style.left = "-999999px";
textArea.style.top = "-999999px";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand("copy");
this.showSuccess("Цитата скопирована в буфер обмена!");
} catch (err) {
console.error("Не удалось скопировать текст:", err);
this.showError("Не удалось скопировать цитату");
}
document.body.removeChild(textArea);
}
showError(message) {
this.showNotification(message, "error");
}
showSuccess(message) {
this.showNotification(message, "success");
}
showNotification(message, type = "info") {
const notification = document.createElement("div");
notification.className = `notification notification-${type}`;
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${
type === "error"
? "#e74c3c"
: type === "success"
? "#27ae60"
: "#ff6b9d"
};
color: white;
padding: 15px 20px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
z-index: 1000;
max-width: 300px;
font-size: 14px;
animation: slideIn 0.3s ease-out;
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.style.animation = "slideOut 0.3s ease-out";
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 3000);
}
escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
}
// Добавляем стили для анимаций уведомлений
const style = document.createElement("style");
style.textContent = `
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Инициализация приложения
const app = new QuoteApp();