ДобавлениеÐ Яндекс верификации
This commit is contained in:
parent
aa40fac43b
commit
2e892cccfb
17 changed files with 190 additions and 205 deletions
|
|
@ -3,7 +3,8 @@ import { MONTHS } from "@lib/constants";
|
||||||
import NumberedContent from "./NumberedContent.astro";
|
import NumberedContent from "./NumberedContent.astro";
|
||||||
import AuthorConsultation from "./AuthorConsultation.astro";
|
import AuthorConsultation from "./AuthorConsultation.astro";
|
||||||
|
|
||||||
export interface Props {
|
// Определяем интерфейс пропсов
|
||||||
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
excerpt: string;
|
excerpt: string;
|
||||||
author: {
|
author: {
|
||||||
|
|
@ -30,6 +31,7 @@ function formatDate(dateInput: string | Date): string {
|
||||||
return `${date.getDate()} ${MONTHS[date.getMonth()]} ${date.getFullYear()} года`;
|
return `${date.getDate()} ${MONTHS[date.getMonth()]} ${date.getFullYear()} года`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Деструктуризация пропсов через Astro.props с явной типизацией
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
excerpt,
|
excerpt,
|
||||||
|
|
@ -43,9 +45,9 @@ const {
|
||||||
postId,
|
postId,
|
||||||
likes = 0,
|
likes = 0,
|
||||||
dislikes = 0,
|
dislikes = 0,
|
||||||
} = Astro.props;
|
} = Astro.props as Props;
|
||||||
|
|
||||||
// дата поста
|
// Дата поста
|
||||||
const formattedPublishDate = typeof publishDate === "string"
|
const formattedPublishDate = typeof publishDate === "string"
|
||||||
? publishDate
|
? publishDate
|
||||||
: formatDate(publishDate);
|
: formatDate(publishDate);
|
||||||
|
|
@ -304,8 +306,6 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Инициализация виджета голосования
|
// Инициализация виджета голосования
|
||||||
(function() {
|
(function() {
|
||||||
|
|
@ -320,22 +320,20 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
|
|
||||||
let likes = parseInt(widget.getAttribute('data-initial-likes') || '0');
|
let likes = parseInt(widget.getAttribute('data-initial-likes') || '0');
|
||||||
let dislikes = parseInt(widget.getAttribute('data-initial-dislikes') || '0');
|
let dislikes = parseInt(widget.getAttribute('data-initial-dislikes') || '0');
|
||||||
let userVote = null;
|
let userVote: string | null = null;
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isDisabled = false; // Блокировка кнопок
|
let isDisabled = false;
|
||||||
|
|
||||||
console.log('[PostLikes] Инициализация:', { postId, likes, dislikes });
|
console.log('[PostLikes] Инициализация:', { postId, likes, dislikes });
|
||||||
|
|
||||||
// Блокировка/разблокировка кнопок
|
function setButtonsDisabled(disabled: boolean) {
|
||||||
function setButtonsDisabled(disabled) {
|
|
||||||
isDisabled = disabled;
|
isDisabled = disabled;
|
||||||
if (likeBtn) likeBtn.disabled = disabled;
|
if (likeBtn) (likeBtn as HTMLButtonElement).disabled = disabled;
|
||||||
if (dislikeBtn) dislikeBtn.disabled = disabled;
|
if (dislikeBtn) (dislikeBtn as HTMLButtonElement).disabled = disabled;
|
||||||
widget.style.opacity = disabled ? '0.6' : '1';
|
(widget as HTMLElement).style.opacity = disabled ? '0.6' : '1';
|
||||||
widget.style.pointerEvents = disabled ? 'none' : 'auto';
|
(widget as HTMLElement).style.pointerEvents = disabled ? 'none' : 'auto';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Загрузка реальных данных
|
|
||||||
async function loadVotes() {
|
async function loadVotes() {
|
||||||
if (!postId) return;
|
if (!postId) return;
|
||||||
|
|
||||||
|
|
@ -344,7 +342,7 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
console.log('[PostLikes] Ответ API:', response.status);
|
console.log('[PostLikes] Ответ API:', response.status);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json() as { likes: number; dislikes: number; userVote: string | null };
|
||||||
console.log('[PostLikes] Данные:', data);
|
console.log('[PostLikes] Данные:', data);
|
||||||
|
|
||||||
likes = data.likes || 0;
|
likes = data.likes || 0;
|
||||||
|
|
@ -357,9 +355,7 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Голосование
|
async function handleVote(action: 'like' | 'dislike') {
|
||||||
async function handleVote(action) {
|
|
||||||
// Двойная проверка блокировки
|
|
||||||
if (isLoading || isDisabled) {
|
if (isLoading || isDisabled) {
|
||||||
console.log('[PostLikes] Заблокировано, пропускаем');
|
console.log('[PostLikes] Заблокировано, пропускаем');
|
||||||
return;
|
return;
|
||||||
|
|
@ -369,11 +365,9 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
|
|
||||||
if (!postId) return;
|
if (!postId) return;
|
||||||
|
|
||||||
// Блокируем кнопки СРАЗУ
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
setButtonsDisabled(true);
|
setButtonsDisabled(true);
|
||||||
|
|
||||||
// Оптимистичное обновление
|
|
||||||
if (action === 'like') {
|
if (action === 'like') {
|
||||||
if (userVote === 'like') {
|
if (userVote === 'like') {
|
||||||
likes = Math.max(0, likes - 1);
|
likes = Math.max(0, likes - 1);
|
||||||
|
|
@ -409,38 +403,34 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
body: JSON.stringify({ post_id: postId, vote_type: action }),
|
body: JSON.stringify({ post_id: postId, vote_type: action }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json() as { error?: string; likes?: number; dislikes?: number; userVote?: string | null };
|
||||||
console.log('[PostLikes] Ответ сервера:', response.status, data);
|
console.log('[PostLikes] Ответ сервера:', response.status, data);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
alert('Для голосования необходимо войти в систему');
|
alert('Для голосования необходимо войти в систему');
|
||||||
loadVotes(); // Откат
|
loadVotes();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new Error(data.error || 'Ошибка');
|
throw new Error(data.error || 'Ошибка');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обновляем реальными данными с сервера
|
|
||||||
likes = data.likes || 0;
|
likes = data.likes || 0;
|
||||||
dislikes = data.dislikes || 0;
|
dislikes = data.dislikes || 0;
|
||||||
userVote = data.userVote;
|
userVote = data.userVote || null;
|
||||||
updateUI();
|
updateUI();
|
||||||
|
|
||||||
console.log('[PostLikes] Успешно:', { likes, dislikes, userVote });
|
console.log('[PostLikes] Успешно:', { likes, dislikes, userVote });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[PostLikes] Ошибка:', error);
|
console.error('[PostLikes] Ошибка:', error);
|
||||||
alert('Не удалось сохранить голос');
|
alert('Не удалось сохранить голос');
|
||||||
loadVotes(); // Откат
|
loadVotes();
|
||||||
} finally {
|
} finally {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
// НЕ разблокируем кнопки - голосование окончено
|
|
||||||
// Кнопки остаются заблокированными для повторного голосования
|
|
||||||
console.log('[PostLikes] Голосование завершено');
|
console.log('[PostLikes] Голосование завершено');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обновление UI
|
|
||||||
function updateUI() {
|
function updateUI() {
|
||||||
if (likeCount) likeCount.textContent = likes.toString();
|
if (likeCount) likeCount.textContent = likes.toString();
|
||||||
if (dislikeCount) dislikeCount.textContent = dislikes.toString();
|
if (dislikeCount) dislikeCount.textContent = dislikes.toString();
|
||||||
|
|
@ -459,20 +449,15 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработчики
|
|
||||||
likeBtn?.addEventListener('click', () => handleVote('like'));
|
likeBtn?.addEventListener('click', () => handleVote('like'));
|
||||||
dislikeBtn?.addEventListener('click', () => handleVote('dislike'));
|
dislikeBtn?.addEventListener('click', () => handleVote('dislike'));
|
||||||
|
|
||||||
// Загружаем реальные данные
|
|
||||||
loadVotes();
|
loadVotes();
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Боковой блок -->
|
|
||||||
<aside class="lg:col-span-4">
|
<aside class="lg:col-span-4">
|
||||||
<AuthorConsultation author={author} />
|
<AuthorConsultation author={author} />
|
||||||
</aside>
|
</aside>
|
||||||
|
|
@ -517,7 +502,6 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Лайк */
|
|
||||||
.vote-btn.like-btn:hover {
|
.vote-btn.like-btn:hover {
|
||||||
border-color: #86efac;
|
border-color: #86efac;
|
||||||
background: #f0fdf4;
|
background: #f0fdf4;
|
||||||
|
|
@ -530,7 +514,6 @@ const formattedPublishDate = typeof publishDate === "string"
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Дизлайк */
|
|
||||||
.vote-btn.dislike-btn:hover {
|
.vote-btn.dislike-btn:hover {
|
||||||
border-color: #fca5a5;
|
border-color: #fca5a5;
|
||||||
background: #fef2f2;
|
background: #fef2f2;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ interface Props {
|
||||||
pagePath?: string;
|
pagePath?: string;
|
||||||
blogPostTitle?: string;
|
blogPostTitle?: string;
|
||||||
bodyClass?: string;
|
bodyClass?: string;
|
||||||
noContainer?: boolean; // Новый проп для отключения контейнера
|
noContainer?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = Astro.props || {};
|
const props = Astro.props || {};
|
||||||
|
|
@ -46,6 +46,8 @@ if (Astro.request) {
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
{description ? <meta name="description" content={description} /> : null}
|
{description ? <meta name="description" content={description} /> : null}
|
||||||
{canonicalLink ? <link rel="canonical" href={canonicalLink} /> : null}
|
{canonicalLink ? <link rel="canonical" href={canonicalLink} /> : null}
|
||||||
|
<!-- yandex verification -->
|
||||||
|
<meta name="yandex-verification" content="b10d32bf1e46a882" />
|
||||||
</head>
|
</head>
|
||||||
<body class={`${props.bodyClass || "bg-gray-50"}`}>
|
<body class={`${props.bodyClass || "bg-gray-50"}`}>
|
||||||
<Header />
|
<Header />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue