150 lines
10 KiB
CSS
150 lines
10 KiB
CSS
/*
|
||
tailwind-custom.css — кастомные Tailwind-директивы проекта lpon.ru
|
||
(c) 2026, Sergei Erjemin, https://lpon.ru
|
||
{% comment %}
|
||
ВНИМАНИЕ: этот файл не просто CSS! Это Django-шаблон, который подключается через
|
||
include-тег в инлайновый блок <style type="text/tailwindcss"> шаблона _base.html.
|
||
|
||
ВАЖНО: этот файл содержит ТОЛЬКО директивы @theme/@layer, которые обязаны
|
||
пройти через компилятор Tailwind, поэтому подключать его напрямую через
|
||
<link rel="stylesheet"> НЕЛЬЗЯ — обычный браузерный CSS-парсер не понимает
|
||
@theme/@apply и просто отбросит эти правила (проверено на практике: именно
|
||
так "молчал" прежний lpon.css).
|
||
|
||
ОЧЕНЬ ВАЖНО: Так как этот CSS-файл сам является Django-шаблоном (подключается
|
||
инлайн через include-тег движка шаблонов), то внутри него НЕЛЬЗЯ писать буквенные
|
||
примеры Django-тегов вида "открыть-процент include ... процент-закрыть" —
|
||
движок шаблонов исполнит их по-настоящему, даже внутри CSS-комментария.
|
||
Это может привести к бесконечным рекурсиям (файл случайно подключал
|
||
сам себя) и другим непредсказуемым последствиям.
|
||
Если использовать комментарии для шаблонов Django, как здесь, то это безопасно.
|
||
|
||
Файл используется в ДВУХ местах одновременно:
|
||
1. В dev — подключается инклюд-тегом движка шаблонов Django ВНУТРИ
|
||
инлайнового блока <style type="text/tailwindcss"> в _base.html.
|
||
Именно этот блок сканирует и компилирует CDN-скрипт
|
||
@tailwindcss/browser прямо в браузере (он видит только финальный DOM,
|
||
а не внешние .css-файлы, подключённые через <link>).
|
||
2. В prod — подключается через нативный CSS @import из
|
||
frontend-assembly/tailwind/input.css в сборщике scripts/build-tailwind.sh.
|
||
Результат Tailwind CLI собирает в public/static/css/tailwind.min.css
|
||
(см. frontend-assembly/tailwind/package.json).
|
||
|
||
Поэтому здесь НЕТ строки `@import "tailwindcss";` — её добавляет каждый
|
||
"потребитель" данного файла САМ, непосредственно перед подключением этого
|
||
файла: инлайновый блок в _base.html (в dev) и input.css (в prod). Без
|
||
этого импорта директива @apply внутри @layer base ниже не сможет найти
|
||
используемые в ней стандартные классы (border-slate-500 и т.п.) и упадёт
|
||
с ошибкой "Cannot apply unknown utility class" — при этом в dev это ломает
|
||
ВООБЩЕ ВСЮ генерацию Tailwind CSS на странице (проверено на практике).
|
||
{% endcomment %} */
|
||
@theme { /* -- Кастомные переменные цветов -- {% comment %}
|
||
@theme задаёт кастомные токены цвета, которые можно использовать
|
||
в Tailwind-классах через синтаксис, например, text-(--color-link)
|
||
Это позволяет менять стили глобально, не бегая по шаблонам и не меняя конкретные
|
||
классы, а просто перекрашивая токены цвета в одном месте. {% endcomment %} */
|
||
--color-link: var(--color-slate-500);
|
||
--color-link-hover: var(--color-indigo-800);
|
||
}
|
||
|
||
@layer base { /* -- СЛОЙ BASE для Tailwind v4.0+ — см. https://tailwindcss.com/docs/layer-directive --{% comment %}
|
||
Типовой стиль ссылки "по умолчанию" для всего проекта.
|
||
|
||
Поэтому обычную текстовую ссылку теперь можно писать в шаблоне вообще без
|
||
class="..." (просто тег a с href и текстом внутри, без единого класса) —
|
||
и она сразу получит фирменный вид сайта (пунктирное подчёркивание,
|
||
типовой цвет и ховер). Именно так сделано в block/breadcrumbs.html.
|
||
|
||
ВАЖНЫЙ НЮАНС для ссылок, которые НЕ должны выглядеть как "типовая
|
||
текстовая ссылка" (например, пункты меню-кнопок в block/header.html —
|
||
там ссылка визуально оформлена как кнопка, а не как подчёркнутый текст):
|
||
Tailwind v4 использует настоящие CSS cascade layers (@layer base,
|
||
components, utilities...), и по их правилам слой `utilities` ВСЕГДА
|
||
побеждает слой `base` независимо от специфичности селектора — НО только
|
||
для тех CSS-свойств, которые реально заданы в utilities-классе на этом
|
||
элементе. Если у пункта меню нет своего класса для color/border (как
|
||
сейчас в header.html — там заданы только фон и отступы через
|
||
hover:bg-gray-200, px-4 и т.п.), то свойства color/border-bottom он
|
||
"унаследует" именно отсюда, а не из своего блочного оформления —
|
||
родительский text-slate-900 на <menu> тут не поможет, т.к. у самого
|
||
<a> появится СВОЙ явный color.
|
||
Поэтому такие ссылки-кнопки должны явно "отключать" типовой стиль:
|
||
добавить border-0 (убирает пунктир) и свой text-slate-900 dark:text-
|
||
slate-100 (задаёт свой цвет вместо цвета типовой ссылки) — это и сделано
|
||
в block/header.html.{% endcomment %} */
|
||
a {
|
||
@apply border-b border-dotted border-slate-500 dark:border-slate-300
|
||
text-(--color-link) dark:text-slate-300
|
||
hover:text-(--color-link-hover) dark:hover:text-indigo-200
|
||
hover:border-solid transition-colors;
|
||
}
|
||
}
|
||
|
||
@layer components { /* -- СЛОЙ COMPONENTS для компонентов и HTML-контента из БД -- {% comment %}
|
||
Стили для форматированного HTML-контента статей (из БД).
|
||
|
||
Поскольку HTML-текст статьи (s_article_content_html) приходит из CodeMirror-редактора
|
||
и с высокой вероятностью не содержит явных Tailwind-классов на каждом p, h2, ul, blockquote,
|
||
мы оборачиваем контент в шаблонный контейнер <div class="article-content">...</div>,
|
||
а здесь через @apply и каскадные селекторы задаем правила оформления элементов.
|
||
{% endcomment %} */
|
||
|
||
/* Контейнер форматированного текста статьи */
|
||
.article-content {
|
||
@apply text-slate-800 dark:text-slate-200 leading-relaxed text-base md:text-lg;
|
||
|
||
/* Заголовки внутри контента статьи */
|
||
h1, h2, h3, h4 {
|
||
@apply font-bold text-slate-900 dark:text-slate-100 mt-8 mb-4 leading-snug;
|
||
}
|
||
h1 { @apply text-3xl md:text-4xl border-b border-slate-200 dark:border-slate-800 pb-2; }
|
||
h2 { @apply text-2xl md:text-3xl; }
|
||
h3 { @apply text-xl md:text-2xl; }
|
||
h4 { @apply text-lg md:text-xl; }
|
||
h5 { @apply text-base md:text-lg text-slate-700 dark:text-slate-300; }
|
||
|
||
/* Параграфы и текстовые блоки */
|
||
p {
|
||
@apply my-4 leading-relaxed;
|
||
}
|
||
|
||
/* Списки (маркированные и нумерованные) */
|
||
ul {
|
||
@apply list-disc list-outside space-y-2 pl-4 ml-4;
|
||
}
|
||
ol {
|
||
@apply list-decimal list-outside space-y-2 pl-4 ml-4;
|
||
}
|
||
li {
|
||
@apply leading-normal;
|
||
}
|
||
|
||
/* Цитаты и выделенные блоки */
|
||
blockquote {
|
||
@apply border-l-4 border-indigo-500 bg-slate-100 dark:bg-slate-900/80
|
||
px-4 py-3 my-6 italic text-slate-700 dark:text-slate-300 rounded-r-lg;
|
||
}
|
||
|
||
/* Изображения внутри контента */
|
||
img {
|
||
@apply my-6 rounded-xl border border-slate-200 dark:border-slate-800 h-auto max-w-full mx-auto;
|
||
}
|
||
|
||
/* Инлайновый код и блоки кода */
|
||
code {
|
||
@apply bg-slate-200 dark:bg-slate-800 text-indigo-700 dark:text-indigo-300
|
||
px-1.5 py-0.5 rounded text-sm font-mono;
|
||
}
|
||
pre {
|
||
@apply bg-slate-900 text-slate-100 p-4 rounded-xl my-6 overflow-x-auto text-sm font-mono;
|
||
}
|
||
pre code {
|
||
@apply bg-transparent text-inherit p-0;
|
||
}
|
||
|
||
/* Горизонтальный разделитель */
|
||
hr {
|
||
@apply my-8 border-t border-slate-200 dark:border-slate-800;
|
||
}
|
||
}
|
||
} |