diff --git a/blog/templates/blog/article_detail.html b/blog/templates/blog/article_detail.html index 030adea..37c8537 100644 --- a/blog/templates/blog/article_detail.html +++ b/blog/templates/blog/article_detail.html @@ -4,6 +4,7 @@ {% load seo_tags %} {% block extra_css %} + {% endblock %} diff --git a/programmer/static/blog/css/article.css b/programmer/static/blog/css/article.css index bf3fdac..4bd321f 100644 --- a/programmer/static/blog/css/article.css +++ b/programmer/static/blog/css/article.css @@ -173,9 +173,13 @@ margin-bottom: 0; } -/* --- Inline code --- */ +/* --- Inline code (not inside pre) --- */ +/* + * High specificity is fine here because this selector explicitly + * excludes pre > code, so it never touches hljs blocks. + */ -.content-card .card-content code { +.content-card .card-content :not(pre) > code { font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: 0.875em; background: var(--bg-tertiary); @@ -186,28 +190,39 @@ word-break: break-all; } -/* --- Code blocks (CKEditor generates
) --- */
+/* --- Code blocks (CKEditor generates ) --- */
+/*
+ * ALL pre and pre code rules use :where() — zero specificity.
+ * This guarantees hljs always wins on colors, background, and padding.
+ *
+ * Responsibility split:
+ * article.css → layout only: margin, border-radius, overflow, shadow
+ * hljs CSS → everything visual: background, color, padding, font-size
+ *
+ * font-size:0 on pre prevents inherited line-height:1.8 from inflating
+ * the spacing between lines (line-height is computed from font-size,
+ * so zeroing it on the wrapper element neutralises the inheritance).
+ * font-size is restored on pre code.
+ */
-.content-card .card-content pre {
+:where(.content-card .card-content) pre {
margin: 1.5rem 0;
- padding: 1.5rem;
- background: #1A1F2E;
+ padding: 0; /* hljs sets padding:1em on code.hljs — don't double it */
border-radius: var(--radius-md);
overflow-x: auto;
- border: 1px solid var(--border-dark);
box-shadow: var(--shadow-md);
+ font-size: 0; /* neutralise inherited line-height */
+ line-height: 1;
+ background: none; /* hljs controls background (#fff or #282c34) */
}
-.content-card .card-content pre code {
+:where(.content-card .card-content) pre code {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
- font-size: 0.9rem;
- background: transparent;
- color: #E2E8F0;
- padding: 0;
- border: none;
- border-radius: 0;
+ font-size: 0.9rem; /* restore font-size for hljs to work from */
+ line-height: 1.5;
word-break: normal;
white-space: pre;
+ /* NO color, NO background, NO padding — hljs owns these */
}
/* --- Tables --- */
@@ -414,9 +429,10 @@
margin: 1rem auto;
}
- .content-card .card-content pre {
- padding: 1rem;
- font-size: 0.8rem;
+ /* :where() keeps specificity at zero so hljs still wins on mobile */
+ :where(.content-card .card-content) pre {
+ box-shadow: none;
+ margin: 1rem 0;
}
.content-card .card-content th,
diff --git a/programmer/static/programmer/js/theme-switcher.js b/programmer/static/programmer/js/theme-switcher.js
index 6226fda..5386bbe 100644
--- a/programmer/static/programmer/js/theme-switcher.js
+++ b/programmer/static/programmer/js/theme-switcher.js
@@ -1,78 +1,72 @@
-// Theme Switcher Script
-document.addEventListener('DOMContentLoaded', function() {
- const themeToggle = document.getElementById('theme-toggle');
+// theme-switcher.js
+document.addEventListener('DOMContentLoaded', function () {
+
+ const themeToggle = document.getElementById('theme-toggle');
const mobileThemeToggle = document.getElementById('mobile-theme-toggle');
- const themeCSS1C = document.getElementById('theme-css-1c');
+ const themeCSS1C = document.getElementById('theme-css-1c');
+
+ // FIX: Derive the base path once so we never rely on the current href value.
+ // href.replace() was silently failing when the filename didn't match exactly.
+ const hljsBasePath = themeCSS1C
+ ? themeCSS1C.href.replace(/1c-(light|dark)\.min\.css$/, '')
+ : null;
+
+ // console.log('Initial href:', themeCSS1C?.href);
+ // console.log('Computed basePath:', hljsBasePath);
+
+ // ── Theme application ────────────────────────────────────────────────────
+
+ function applyTheme(isDark) {
+ if (isDark) {
+ document.body.classList.add('theme-dark');
+ if (themeCSS1C && hljsBasePath) {
+ themeCSS1C.href = hljsBasePath + '1c-dark.min.css';
+ }
+ } else {
+ document.body.classList.remove('theme-dark');
+ if (themeCSS1C && hljsBasePath) {
+ themeCSS1C.href = hljsBasePath + '1c-light.min.css';
+ }
+ }
+
+ // FIX: CSS defines checked = dark (moon icon).
+ // Previously the handlers were calling the wrong function on check/uncheck.
+ if (themeToggle) themeToggle.checked = isDark;
+ if (mobileThemeToggle) mobileThemeToggle.checked = isDark;
+
+ localStorage.setItem('theme', isDark ? 'dark' : 'light');
+ }
+
+ // ── Initialise from saved preference ────────────────────────────────────
- // Проверяем сохраненную тему в localStorage
const savedTheme = localStorage.getItem('theme');
+ applyTheme(savedTheme === 'dark');
- // Устанавливаем светлую тему по умолчанию
- if (savedTheme === 'dark') {
- switchToDarkTheme();
- } else {
- switchToLightTheme(); // Светлая тема по умолчанию
- }
+ // ── Event listeners ──────────────────────────────────────────────────────
- // Обработчик переключения темы для десктопного переключателя
+ // FIX: Both toggles now call the same applyTheme() — no duplicated logic,
+ // and both are always kept in sync with each other automatically.
if (themeToggle) {
- themeToggle.addEventListener('change', function() {
- if (this.checked) {
- switchToLightTheme();
- } else {
- switchToDarkTheme();
- }
+ themeToggle.addEventListener('change', function () {
+ applyTheme(this.checked);
});
}
- // Обработчик переключения темы для мобильного переключателя
if (mobileThemeToggle) {
- mobileThemeToggle.addEventListener('change', function() {
- if (this.checked) {
- switchToLightTheme();
- } else {
- switchToDarkTheme();
- }
- // Синхронизируем оба переключателя
- if (themeToggle) {
- themeToggle.checked = this.checked;
- }
+ mobileThemeToggle.addEventListener('change', function () {
+ applyTheme(this.checked);
});
}
- function switchToLightTheme() {
- document.body.classList.remove('theme-dark');
- if (themeCSS1C) {
- themeCSS1C.href = themeCSS1C.href.replace('1c-dark.min.css', '1c-light.min.css');
- }
- if (themeToggle) themeToggle.checked = true;
- if (mobileThemeToggle) mobileThemeToggle.checked = true;
- localStorage.setItem('theme', 'light');
- // 👇 Обновляем иконку ИКС
- updateIKSTheme();
+ // ── CSS error handling ───────────────────────────────────────────────────
+
+ // FIX: was referencing undefined variable `themeCSS` instead of `themeCSS1C`
+ if (themeCSS1C) {
+ themeCSS1C.onerror = function () {
+ console.error('Ошибка загрузки CSS файла темы подсветки кода');
+ // Fall back to light theme
+ applyTheme(false);
+ };
}
- function switchToDarkTheme() {
- document.body.classList.add('theme-dark');
- if (themeCSS1C) {
- themeCSS1C.href = themeCSS1C.href.replace('1c-light.min.css', '1c-dark.min.css');
- }
- if (themeToggle) themeToggle.checked = false;
- if (mobileThemeToggle) mobileThemeToggle.checked = false;
- localStorage.setItem('theme', 'dark');
- // 👇 Обновляем иконку ИКС
- updateIKSTheme();
- }
-
- // Синхронизация переключателей при загрузке
- if (themeToggle && mobileThemeToggle) {
- mobileThemeToggle.checked = themeToggle.checked;
- }
-
- // Обработка ошибок загрузки CSS
- themeCSS.onerror = function() {
- console.error('Ошибка загрузки CSS файла темы');
- // Восстанавливаем светлую тему по умолчанию при ошибке
- themeCSS1C.href = themeCSS1C.href.replace('1c-light.min.css', '1c-dark.min.css');
- };
});
\ No newline at end of file
diff --git a/programmer/templates/programmer/base.html b/programmer/templates/programmer/base.html
index 014fa39..b473f01 100644
--- a/programmer/templates/programmer/base.html
+++ b/programmer/templates/programmer/base.html
@@ -48,7 +48,8 @@
-
+
+