feat(frontend): configure vendor build scripts and fallback templates
Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
@@ -30,8 +30,8 @@
|
||||
{# Favicons #}<link rel="apple-touch-icon" sizes="180x180" href="{% static 'apple-touch-icon.png' %}" />
|
||||
{# Favicons #}<link rel="manifest" href="{% static 'site.webmanifest' %}" />
|
||||
{# Для ИИ #}<link rel="help" type="text/markdown" href="/llms.txt"/>
|
||||
{# Bootstrap 5 CSS #}<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
{# Bootstrap Icons #}<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"/>
|
||||
{# Bootstrap 5 CSS #}<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" onerror="this.onerror=null;this.href='{% static 'vendor/bootstrap/bootstrap.min.css' %}';"/>
|
||||
{# Bootstrap Icons #}<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" onerror="this.onerror=null;this.href='{% static 'vendor/bootstrap-icons/bootstrap-icons.min.css' %}';"/>
|
||||
<style>
|
||||
:root {
|
||||
--bg-image-text: url("{% static 'svg/logo-etpgrf-site-light-txt.svg' %}");
|
||||
@@ -46,8 +46,18 @@
|
||||
}
|
||||
</style>
|
||||
{# Custom CSS #}<link href="{% static 'css/etpgrf.css' %}" rel="stylesheet"/>
|
||||
{# HTMX #}<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
||||
{# Alpine.js #}<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
{# HTMX #}<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||
<script>window.htmx || document.write('<script src="{% static "vendor/htmx/htmx.min.js" %}"><\/script>')</script>
|
||||
{# Alpine.js #}<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js" onerror="this.onerror=null;var s=document.createElement('script');s.defer=true;s.src='{% static 'vendor/alpinejs/cdn.min.js' %}';document.head.appendChild(s);"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (!window.Alpine) {
|
||||
var s = document.createElement('script');
|
||||
s.src = "{% static 'vendor/alpinejs/cdn.min.js' %}";
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -106,7 +116,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Bootstrap JS #}<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
{# Bootstrap JS #}<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>window.bootstrap || document.write('<script src="{% static "vendor/bootstrap/bootstrap.bundle.min.js" %}"><\/script>')</script>
|
||||
{# Custom JS #}<script src="{% static 'js/base.js' %}" defer></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
{% block title %}ETPGRF — единая типографика для веба{% endblock %}
|
||||
|
||||
{% block description %}Бесплатный онлайн-типограф для подготовки текстов к публикации в вебе. Расставка неразрывных пробелов, правильных кавычек («ёлочки»), тире, спецсимволы, отбивка, компоновка, висячая пунктуация. Идеально для верстки сайтов, статей и постов.{% endblock %}
|
||||
{% block description %}Бесплатный онлайн-типограф для подготовки публикаций в вебе: кавычки «ёлочки», тире, неразрывные пробелы, спецсимволы, отбивка/компоновка, висячая пунктуация… Идеально для верстки сайтов, статей и постов.{% endblock %}
|
||||
|
||||
{% block keywords %}типограф, типографика, онлайн типограф, подготовка текста для веба, html типограф, неразрывные пробелы, кавычки елочки, длинное тире, очистка текста от мусора, интернет верстка, муравьев{% endblock %}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
from pathlib import Path
|
||||
from django.test import TestCase, Client, override_settings
|
||||
from django.urls import reverse
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class VendorAssetsAndFallbackTestCase(TestCase):
|
||||
"""
|
||||
Тестирование наличия вендорных ассетов и корректности подключения fallback в шаблоне base.html.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def test_vendor_static_files_exist(self):
|
||||
"""Проверяем, что все скомпилированные/скопированные локальные файлы присутствуют в статике."""
|
||||
static_dir = settings.BASE_DIR.parent / 'public' / 'static'
|
||||
|
||||
required_files = [
|
||||
'vendor/bootstrap/bootstrap.min.css',
|
||||
'vendor/bootstrap/bootstrap.bundle.min.js',
|
||||
'vendor/bootstrap-icons/bootstrap-icons.min.css',
|
||||
'vendor/bootstrap-icons/fonts/bootstrap-icons.woff2',
|
||||
'vendor/bootstrap-icons/fonts/bootstrap-icons.woff',
|
||||
'vendor/htmx/htmx.min.js',
|
||||
'vendor/alpinejs/cdn.min.js',
|
||||
'codemirror/editor.js',
|
||||
]
|
||||
|
||||
for rel_path in required_files:
|
||||
file_path = static_dir / rel_path
|
||||
self.assertTrue(
|
||||
file_path.exists(),
|
||||
f"Файл вендора не найден в статике: {rel_path} (ожидался по пути {file_path})"
|
||||
)
|
||||
self.assertGreater(
|
||||
file_path.stat().st_size,
|
||||
0,
|
||||
f"Файл вендора пуст: {rel_path}"
|
||||
)
|
||||
|
||||
def test_base_template_fallback_tags(self):
|
||||
"""Проверяем, что главная страница отдает теги с fallback-обработкой ошибок загрузки с CDN."""
|
||||
response = self.client.get(reverse('index'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
content = response.content.decode('utf-8')
|
||||
|
||||
# Проверка fallback для Bootstrap CSS
|
||||
self.assertIn('bootstrap.min.css', content)
|
||||
self.assertIn("vendor/bootstrap/bootstrap.min.css", content)
|
||||
|
||||
# Проверка fallback для Bootstrap Icons
|
||||
self.assertIn('bootstrap-icons.min.css', content)
|
||||
self.assertIn("vendor/bootstrap-icons/bootstrap-icons.min.css", content)
|
||||
|
||||
# Проверка fallback для HTMX
|
||||
self.assertIn('htmx.org', content)
|
||||
self.assertIn('window.htmx || document.write', content)
|
||||
self.assertIn('vendor/htmx/htmx.min.js', content)
|
||||
|
||||
# Проверка fallback для Alpine.js
|
||||
self.assertIn('alpinejs', content)
|
||||
self.assertIn('vendor/alpinejs/cdn.min.js', content)
|
||||
|
||||
# Проверка fallback для Bootstrap JS
|
||||
self.assertIn('bootstrap.bundle.min.js', content)
|
||||
self.assertIn('window.bootstrap || document.write', content)
|
||||
self.assertIn('vendor/bootstrap/bootstrap.bundle.min.js', content)
|
||||
|
||||
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class TypographViewsTestCase(TestCase):
|
||||
"""
|
||||
Базовые тесты функциональности представлений типографа.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def test_process_text_endpoint(self):
|
||||
"""Проверка эндпоинта типографирования текста."""
|
||||
response = self.client.post(
|
||||
reverse('process_text'),
|
||||
data={
|
||||
'text': 'Тест "кавычек" и предлога в тексте.',
|
||||
'langs': 'ru',
|
||||
'quotes': 'on',
|
||||
'unbreakables': 'on',
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('X-Processing-Time', response.headers)
|
||||
content = response.content.decode('utf-8')
|
||||
# Проверяем типографирование кавычек «ёлочки»
|
||||
self.assertIn('«кавычек»', content)
|
||||
|
||||
def test_stats_summary_endpoint(self):
|
||||
"""Проверка эндпоинта сводной статистики."""
|
||||
response = self.client.get(reverse('stats_summary'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
Reference in New Issue
Block a user