mirror of
https://github.com/EDeev/deev.space.git
synced 2026-06-15 11:01:10 +03:00
v. 1.3
This commit is contained in:
parent
9980762ae6
commit
5f2ebd8792
7 changed files with 525 additions and 264 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
@ -60,7 +64,20 @@ DATABASES = {
|
||||||
|
|
||||||
AUTH_USER_MODEL = 'main.CustomUser'
|
AUTH_USER_MODEL = 'main.CustomUser'
|
||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = []
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
LANGUAGE_CODE = 'ru-ru'
|
LANGUAGE_CODE = 'ru-ru'
|
||||||
TIME_ZONE = 'Europe/Moscow'
|
TIME_ZONE = 'Europe/Moscow'
|
||||||
|
|
@ -71,6 +88,10 @@ STATIC_URL = '/static/'
|
||||||
STATICFILES_DIRS = [BASE_DIR / 'static']
|
STATICFILES_DIRS = [BASE_DIR / 'static']
|
||||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||||
|
|
||||||
|
# Хеширование статических файлов в production
|
||||||
|
if not DEBUG:
|
||||||
|
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||||
|
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
MEDIA_ROOT = BASE_DIR / 'media'
|
MEDIA_ROOT = BASE_DIR / 'media'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -399,46 +399,273 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body {
|
.article-body {
|
||||||
font-size: 1.1rem;
|
font-size: 1.05rem;
|
||||||
line-height: 1.8;
|
line-height: 1.7;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
|
text-align: justify;
|
||||||
|
text-justify: inter-word;
|
||||||
|
hyphens: auto;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
-moz-hyphens: auto;
|
||||||
|
-ms-hyphens: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body p {
|
.article-body p {
|
||||||
margin-bottom: var(--space-lg);
|
margin-bottom: 1rem;
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body h2,
|
.article-body h2,
|
||||||
.article-body h3,
|
.article-body h3,
|
||||||
|
.article-body h4,
|
||||||
|
.article-body h5,
|
||||||
|
.article-body h6 {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body h2 {
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 2px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body h3 {
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
font-size: 1.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
.article-body h4 {
|
.article-body h4 {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
margin-top: var(--space-2xl);
|
margin-top: 1.5rem;
|
||||||
margin-bottom: var(--space-md);
|
margin-bottom: 0.75rem;
|
||||||
|
font-size: 1.15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body ul,
|
.article-body ul,
|
||||||
.article-body ol {
|
.article-body ol {
|
||||||
margin-bottom: var(--space-lg);
|
margin-bottom: 1.25rem;
|
||||||
padding-left: var(--space-xl);
|
margin-top: 0.75rem;
|
||||||
|
padding-left: 2rem;
|
||||||
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body li {
|
.article-body li {
|
||||||
margin-bottom: var(--space-sm);
|
margin-bottom: 0.5rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body li p {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body img {
|
.article-body img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
margin: var(--space-lg) 0;
|
margin: 1.5rem 0;
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body blockquote {
|
.article-body blockquote {
|
||||||
border-left: 4px solid var(--primary-color);
|
border-left: 4px solid var(--primary-color);
|
||||||
padding-left: var(--space-lg);
|
padding: 1rem 1.5rem;
|
||||||
margin: var(--space-lg) 0;
|
margin: 1.5rem 0;
|
||||||
font-style: italic;
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-style: normal;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body blockquote p {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body blockquote p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body hr {
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border-color);
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body th,
|
||||||
|
.article-body td {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body th {
|
||||||
|
background: var(--bg-elevated);
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body tr:hover {
|
||||||
|
background: var(--bg-elevated);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body code {
|
||||||
|
font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
|
||||||
|
background: var(--bg-elevated);
|
||||||
|
padding: 0.2em 0.5em;
|
||||||
|
border-radius: var(--radius-xs);
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--primary-light);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body pre {
|
||||||
|
position: relative;
|
||||||
|
background: var(--bg-darker);
|
||||||
|
padding: 1.25rem;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body pre code {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
color: #e0e0e0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body pre:hover .code-copy-btn {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.75rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
background: var(--bg-card);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 0.4rem 0.75rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--transition);
|
||||||
|
opacity: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy-btn:hover {
|
||||||
|
background: var(--primary-muted);
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy-btn.copied {
|
||||||
|
background: rgba(34, 197, 94, 0.15);
|
||||||
|
border-color: var(--success-color);
|
||||||
|
color: var(--success-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy-btn i {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background: var(--bg-elevated);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
border-radius: var(--radius-md) var(--radius-md) 0 0;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-language {
|
||||||
|
font-size: 0.75rem;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body pre.has-header {
|
||||||
|
border-radius: 0 0 var(--radius-md) var(--radius-md);
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body h2,
|
||||||
|
.article-body h3 {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-anchor {
|
||||||
|
position: absolute;
|
||||||
|
left: -1.5rem;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body h2:hover .header-anchor,
|
||||||
|
.article-body h3:hover .header-anchor {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-anchor:hover {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body pre,
|
||||||
|
.article-body pre code {
|
||||||
|
text-align: left;
|
||||||
|
hyphens: none;
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body table,
|
||||||
|
.article-body th,
|
||||||
|
.article-body td {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body figcaption,
|
||||||
|
.carousel-caption,
|
||||||
|
.collage-caption {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Article Footer */
|
/* Article Footer */
|
||||||
|
|
@ -689,7 +916,7 @@
|
||||||
gap: var(--space-md);
|
gap: var(--space-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment {
|
div.comment {
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: var(--radius-xl);
|
border-radius: var(--radius-xl);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
initBackToTop();
|
initBackToTop();
|
||||||
initMessages();
|
initMessages();
|
||||||
initContactForm();
|
initContactForm();
|
||||||
|
initCodeBlocks();
|
||||||
|
addHeaderAnchors();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===== AOS Animation =====
|
// ===== AOS Animation =====
|
||||||
|
|
@ -453,4 +455,98 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ===== Code Copy Functionality =====
|
||||||
|
function initCodeBlocks() {
|
||||||
|
const codeBlocks = document.querySelectorAll('.article-body pre');
|
||||||
|
|
||||||
|
codeBlocks.forEach((pre) => {
|
||||||
|
// Проверяем, не добавлена ли уже кнопка
|
||||||
|
if (pre.querySelector('.code-copy-btn')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeElement = pre.querySelector('code');
|
||||||
|
if (!codeElement) return;
|
||||||
|
|
||||||
|
// Создаём кнопку копирования
|
||||||
|
const copyButton = document.createElement('button');
|
||||||
|
copyButton.className = 'code-copy-btn';
|
||||||
|
copyButton.type = 'button';
|
||||||
|
copyButton.setAttribute('aria-label', 'Копировать код');
|
||||||
|
copyButton.innerHTML = '<i class="fas fa-copy"></i><span class="copy-text">Копировать</span>';
|
||||||
|
|
||||||
|
// Обработчик клика
|
||||||
|
copyButton.addEventListener('click', async function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Получаем текст кода без HTML-тегов
|
||||||
|
const codeText = codeElement.textContent || codeElement.innerText;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(codeText);
|
||||||
|
|
||||||
|
// Изменяем визуальное состояние кнопки
|
||||||
|
copyButton.innerHTML = '<i class="fas fa-check"></i><span class="copy-text">Сохранено!</span>';
|
||||||
|
copyButton.classList.add('copied');
|
||||||
|
|
||||||
|
// Возвращаем исходное состояние через 2 секунды
|
||||||
|
setTimeout(() => {
|
||||||
|
copyButton.innerHTML = '<i class="fas fa-copy"></i><span class="copy-text">Копировать</span>';
|
||||||
|
copyButton.classList.remove('copied');
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Ошибка при копировании:', err);
|
||||||
|
|
||||||
|
// Fallback для старых браузеров
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = codeText;
|
||||||
|
textArea.style.position = 'fixed';
|
||||||
|
textArea.style.left = '-999999px';
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
copyButton.innerHTML = '<i class="fas fa-check"></i><span class="copy-text">Сохранено!</span>';
|
||||||
|
copyButton.classList.add('copied');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
copyButton.innerHTML = '<i class="fas fa-copy"></i><span class="copy-text">Копировать</span>';
|
||||||
|
copyButton.classList.remove('copied');
|
||||||
|
}, 2000);
|
||||||
|
} catch (err2) {
|
||||||
|
showNotification('Не удалось скопировать код', 'error');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Добавляем кнопку в блок кода
|
||||||
|
pre.style.position = 'relative';
|
||||||
|
pre.appendChild(copyButton);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHeaderAnchors() {
|
||||||
|
const headers = document.querySelectorAll('.article-body h2, .article-body h3');
|
||||||
|
headers.forEach(header => {
|
||||||
|
const id = header.textContent
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-zа-яё0-9]+/g, '-')
|
||||||
|
.replace(/^-|-$/g, '');
|
||||||
|
|
||||||
|
header.id = id;
|
||||||
|
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.className = 'header-anchor';
|
||||||
|
anchor.href = `#${id}`;
|
||||||
|
anchor.innerHTML = '<i class="fas fa-link"></i>';
|
||||||
|
anchor.setAttribute('aria-label', 'Ссылка на раздел');
|
||||||
|
|
||||||
|
header.appendChild(anchor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
@ -6,9 +6,7 @@
|
||||||
<div class="auth-card" data-aos="fade-up">
|
<div class="auth-card" data-aos="fade-up">
|
||||||
<div class="auth-header">
|
<div class="auth-header">
|
||||||
<a href="{% url 'index' %}" class="logo">
|
<a href="{% url 'index' %}" class="logo">
|
||||||
<span class="logo-deev">deev</span>
|
<img src="{% static 'img/logo.png' %}" alt="deev.space" style="max-width: 130px; height: auto;">
|
||||||
<span class="logo-dot"></span>
|
|
||||||
<span class="logo-space">space</span>
|
|
||||||
</a>
|
</a>
|
||||||
<h1 class="auth-title">Вход в аккаунт</h1>
|
<h1 class="auth-title">Вход в аккаунт</h1>
|
||||||
<p class="auth-subtitle">Войдите, чтобы оставлять комментарии и оценивать статьи</p>
|
<p class="auth-subtitle">Войдите, чтобы оставлять комментарии и оценивать статьи</p>
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,7 @@
|
||||||
<div class="auth-card" data-aos="fade-up">
|
<div class="auth-card" data-aos="fade-up">
|
||||||
<div class="auth-header">
|
<div class="auth-header">
|
||||||
<a href="{% url 'index' %}" class="logo">
|
<a href="{% url 'index' %}" class="logo">
|
||||||
<span class="logo-deev">deev</span>
|
<img src="{% static 'img/logo.png' %}" alt="deev.space" style="max-width: 130px; height: auto;">
|
||||||
<span class="logo-dot"></span>
|
|
||||||
<span class="logo-space">space</span>
|
|
||||||
</a>
|
</a>
|
||||||
<h1 class="auth-title">Регистрация</h1>
|
<h1 class="auth-title">Регистрация</h1>
|
||||||
<p class="auth-subtitle">Создайте аккаунт для участия в обсуждениях</p>
|
<p class="auth-subtitle">Создайте аккаунт для участия в обсуждениях</p>
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@
|
||||||
|
|
||||||
<!-- Article Content -->
|
<!-- Article Content -->
|
||||||
<div class="article-body" data-aos="fade-up" data-aos-delay="300">
|
<div class="article-body" data-aos="fade-up" data-aos-delay="300">
|
||||||
{{ article.post|safe|linebreaks }}
|
{{ article.post|safe }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Image Gallery -->
|
<!-- Image Gallery -->
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
<meta property="og:description" content="{{ page_description|default:global_settings.site_description }}">
|
<meta property="og:description" content="{{ page_description|default:global_settings.site_description }}">
|
||||||
<meta property="og:type" content="{% block og_type %}website{% endblock %}">
|
<meta property="og:type" content="{% block og_type %}website{% endblock %}">
|
||||||
<meta property="og:url" content="https://deev.space{{ request.path }}">
|
<meta property="og:url" content="https://deev.space{{ request.path }}">
|
||||||
<meta property="og:image" content="{% block og_image %}{% static 'images/og-default.jpg' %}{% endblock %}">
|
|
||||||
<meta property="og:site_name" content="{{ global_settings.site_name }}">
|
<meta property="og:site_name" content="{{ global_settings.site_name }}">
|
||||||
<meta property="og:locale" content="ru_RU">
|
<meta property="og:locale" content="ru_RU">
|
||||||
|
|
||||||
|
|
@ -32,7 +31,6 @@
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta name="twitter:title" content="{{ page_title|default:global_settings.owner_name }}">
|
<meta name="twitter:title" content="{{ page_title|default:global_settings.owner_name }}">
|
||||||
<meta name="twitter:description" content="{{ page_description|default:global_settings.site_description }}">
|
<meta name="twitter:description" content="{{ page_description|default:global_settings.site_description }}">
|
||||||
<meta name="twitter:image" content="{% block twitter_image %}{% static 'images/og-default.jpg' %}{% endblock %}">
|
|
||||||
|
|
||||||
<!-- Canonical URL -->
|
<!-- Canonical URL -->
|
||||||
<link rel="canonical" href="https://deev.space{{ request.path }}">
|
<link rel="canonical" href="https://deev.space{{ request.path }}">
|
||||||
|
|
@ -56,6 +54,10 @@
|
||||||
<!-- AOS Animation -->
|
<!-- AOS Animation -->
|
||||||
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
|
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Prism.js для подсветки синтаксиса -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
|
||||||
|
|
||||||
<!-- Custom Styles -->
|
<!-- Custom Styles -->
|
||||||
<link rel="stylesheet" href="{% static 'css/variables.css' %}">
|
<link rel="stylesheet" href="{% static 'css/variables.css' %}">
|
||||||
<link rel="stylesheet" href="{% static 'css/base.css' %}">
|
<link rel="stylesheet" href="{% static 'css/base.css' %}">
|
||||||
|
|
@ -256,93 +258,6 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
<!-- <footer class="footer">
|
|
||||||
<div class="container">
|
|
||||||
<div class="footer-grid">
|
|
||||||
<div class="footer-brand">
|
|
||||||
<a href="{% url 'index' %}" class="logo">
|
|
||||||
|
|
||||||
</a>
|
|
||||||
<p>{{ global_settings.site_description|default:"Персональный сайт backend-разработчика. Создаю надёжные и масштабируемые решения на Python и Django." }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-nav">
|
|
||||||
<h4>Навигация</h4>
|
|
||||||
<ul class="footer-links">
|
|
||||||
<li><a href="{% url 'about' %}">Обо мне</a></li>
|
|
||||||
<li><a href="{% url 'projects' %}">Проекты</a></li>
|
|
||||||
<li><a href="{% url 'blog' %}">Блог</a></li>
|
|
||||||
<li><a href="{% url 'achievements' %}">Достижения</a></li>
|
|
||||||
<li><a href="{% url 'contacts' %}">Контакты</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-contact">
|
|
||||||
<h4>Контакты</h4>
|
|
||||||
<ul class="footer-links">
|
|
||||||
<li>
|
|
||||||
<a href="mailto:{{ global_settings.owner_email }}">
|
|
||||||
<i class="fas fa-envelope"></i>
|
|
||||||
{{ global_settings.owner_email }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% if global_settings.owner_phone %}
|
|
||||||
<li>
|
|
||||||
<a href="tel:{{ global_settings.owner_phone|cut:' '|cut:'('|cut:')'|cut:'-' }}">
|
|
||||||
<i class="fas fa-phone"></i>
|
|
||||||
{{ global_settings.owner_phone }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li>
|
|
||||||
<i class="fas fa-map-marker-alt"></i>
|
|
||||||
{{ global_settings.owner_city }}, Россия
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-social">
|
|
||||||
<h4>Социальные сети</h4>
|
|
||||||
<div class="footer-socials">
|
|
||||||
{% if global_settings.telegram_url %}
|
|
||||||
<a href="{{ global_settings.telegram_url }}" target="_blank" rel="noopener noreferrer" class="footer-social-link" aria-label="Telegram">
|
|
||||||
<i class="fab fa-telegram"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if global_settings.github_url %}
|
|
||||||
<a href="{{ global_settings.github_url }}" target="_blank" rel="noopener noreferrer" class="footer-social-link" aria-label="GitHub">
|
|
||||||
<i class="fab fa-github"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if global_settings.vk_url %}
|
|
||||||
<a href="{{ global_settings.vk_url }}" target="_blank" rel="noopener noreferrer" class="footer-social-link" aria-label="VKontakte">
|
|
||||||
<i class="fab fa-vk"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if global_settings.linkedin_url %}
|
|
||||||
<a href="{{ global_settings.linkedin_url }}" target="_blank" rel="noopener noreferrer" class="footer-social-link" aria-label="LinkedIn">
|
|
||||||
<i class="fab fa-linkedin"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="mailto:{{ global_settings.owner_email }}" class="footer-social-link" aria-label="Email">
|
|
||||||
<i class="fas fa-envelope"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="footer-bottom">
|
|
||||||
<p class="footer-copyright">
|
|
||||||
© 2024-{% now "Y" %} {{ global_settings.owner_name }}. Все права защищены.
|
|
||||||
</p>
|
|
||||||
<p class="footer-made">
|
|
||||||
Сделано с <i class="fas fa-heart" style="color: var(--primary-color);"></i> на Django
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer> -->
|
|
||||||
|
|
||||||
<!-- Back to Top -->
|
<!-- Back to Top -->
|
||||||
<button class="back-to-top" id="backToTop" aria-label="Наверх">
|
<button class="back-to-top" id="backToTop" aria-label="Наверх">
|
||||||
<i class="fas fa-chevron-up"></i>
|
<i class="fas fa-chevron-up"></i>
|
||||||
|
|
@ -352,6 +267,12 @@
|
||||||
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
|
||||||
<script src="{% static 'js/main.js' %}"></script>
|
<script src="{% static 'js/main.js' %}"></script>
|
||||||
|
|
||||||
|
<!-- Prism.js скрипты -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/normalize-whitespace/prism-normalize-whitespace.min.js"></script>
|
||||||
|
|
||||||
{% block extra_js %}{% endblock %}
|
{% block extra_js %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Add table
Reference in a new issue