adding randomness in the navigation plugin on the sidebar + new dracula theme
This commit is contained in:
1 parent
db00f99e85
commit
25dad8631e
3 files changed
+139
-26
No files matched your search
@@ -7,10 +7,11 @@ A clean, minimal theme for [Bludit](https://www.bludit.com) inspired by the
|
||||
|
||||
## Features
|
||||
|
||||
- 🌗 **Light / dark mode toggle** — remembers the visitor's choice and falls back to the OS preference.
|
||||
- 🧱 **Monochrome design** — restrained grayscale palette with crisp typography (Inter).
|
||||
- 🎨 **Four color themes** — the navbar button cycles **Light → Dark → Nord → Dracula**, remembering the visitor's choice (falls back to the OS preference).
|
||||
- 🧱 **Monochrome base design** — restrained grayscale palette with crisp typography (Inter).
|
||||
- 👤 **Profile hero** — circular avatar, site title, slogan and social links on the homepage.
|
||||
- 📚 **Right sidebar** — drop any Bludit sidebar plugin into it (categories, tags, search…).
|
||||
- 🔀 **Randomized navigation** — the Navigation/Pages plugin list is shuffled on each load.
|
||||
- ⏱️ **Reading time & dates** shown on the post list and single posts.
|
||||
- 🔗 **Social icons** in the navbar and hero, using SVG files in `img/` (GitHub, Mastodon, Bluesky, LinkedIn, and more).
|
||||
- 🏷️ **Tags & categories** rendered as pill badges.
|
||||
@@ -52,15 +53,24 @@ blowdit/
|
||||
└── languages/ Translations
|
||||
```
|
||||
|
||||
## Dark mode
|
||||
## Themes
|
||||
|
||||
The colour scheme is driven by CSS custom properties. Light mode lives in
|
||||
`:root`; dark mode overrides them under `[data-theme="dark"]`. The attribute is
|
||||
set on `<html>` before paint (in `php/head.php`) to avoid a flash, and the
|
||||
toggle button in the navbar persists the choice to `localStorage`.
|
||||
Each theme is just a set of CSS custom properties. Light lives in `:root`; the
|
||||
others override it under `[data-theme="dark"]`, `[data-theme="nord"]` and
|
||||
`[data-theme="dracula"]`. The attribute is set on `<html>` before paint (in
|
||||
`php/head.php`) to avoid a flash, and the navbar button cycles through them,
|
||||
persisting the choice to `localStorage`.
|
||||
|
||||
To tweak the palette, edit the variables at the top of
|
||||
[css/style.css](css/style.css).
|
||||
To tweak a palette or add your own theme, edit/duplicate the variable blocks at
|
||||
the top of [css/style.css](css/style.css) and add the theme name to the
|
||||
`THEMES` array in the toggle script in [index.php](index.php).
|
||||
|
||||
## Randomized navigation
|
||||
|
||||
If the **Navigation** (or **Pages**) plugin is in the sidebar, its list is
|
||||
shuffled on every page load by a small script in [index.php](index.php). The
|
||||
plugin's output is wrapped in `.js-random-nav`; if your plugin uses a different
|
||||
CSS class, adjust the detection in `index.php` accordingly.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+80
-12
@@ -61,6 +61,9 @@
|
||||
--font-size-sm: 0.875rem;
|
||||
--font-size-xs: 0.78rem;
|
||||
--line-height-base: 1.7;
|
||||
|
||||
/* Filter applied to the dark social SVG glyphs (none on light themes) */
|
||||
--social-icon-filter: none;
|
||||
}
|
||||
|
||||
/* ----------------------------------------
|
||||
@@ -85,7 +88,7 @@
|
||||
--border-color: #333333;
|
||||
--border-subtle: #2a2a2a;
|
||||
|
||||
--chrome-bg: #0f0f0f;
|
||||
--chrome-bg: #1f1f1f;
|
||||
--chrome-text: rgba(255, 255, 255, 0.88);
|
||||
--chrome-text-hover: #ffffff;
|
||||
|
||||
@@ -95,6 +98,80 @@
|
||||
|
||||
--code-bg: #262626;
|
||||
--code-text: #ededed;
|
||||
|
||||
--social-icon-filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* ----------------------------------------
|
||||
THEME TOKENS — Nord (arctic)
|
||||
---------------------------------------- */
|
||||
[data-theme="nord"] {
|
||||
color-scheme: dark;
|
||||
|
||||
--accent: #88c0d0;
|
||||
--accent-hover: #8fbcbb;
|
||||
--accent-contrast: #2e3440;
|
||||
|
||||
--bg-body: #2e3440;
|
||||
--bg-surface: #3b4252;
|
||||
--bg-subtle: #434c5e;
|
||||
--bg-hover: #4c566a;
|
||||
|
||||
--text-primary: #eceff4;
|
||||
--text-secondary: #d8dee9;
|
||||
--text-muted: #8b95a8;
|
||||
|
||||
--border-color: #434c5e;
|
||||
--border-subtle: #3b4252;
|
||||
|
||||
--chrome-bg: #3b4252;
|
||||
--chrome-text: rgba(236, 239, 244, 0.9);
|
||||
--chrome-text-hover: #eceff4;
|
||||
|
||||
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35);
|
||||
--shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.4);
|
||||
|
||||
--code-bg: #3b4252;
|
||||
--code-text: #eceff4;
|
||||
|
||||
--social-icon-filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* ----------------------------------------
|
||||
THEME TOKENS — Dracula
|
||||
---------------------------------------- */
|
||||
[data-theme="dracula"] {
|
||||
color-scheme: dark;
|
||||
|
||||
--accent: #bd93f9;
|
||||
--accent-hover: #caa6fa;
|
||||
--accent-contrast: #282a36;
|
||||
|
||||
--bg-body: #282a36;
|
||||
--bg-surface: #343746;
|
||||
--bg-subtle: #44475a;
|
||||
--bg-hover: #44475a;
|
||||
|
||||
--text-primary: #f8f8f2;
|
||||
--text-secondary: #c4c6d6;
|
||||
--text-muted: #6272a4;
|
||||
|
||||
--border-color: #44475a;
|
||||
--border-subtle: #383b4a;
|
||||
|
||||
--chrome-bg: #343746;
|
||||
--chrome-text: rgba(248, 248, 242, 0.9);
|
||||
--chrome-text-hover: #f8f8f2;
|
||||
|
||||
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35);
|
||||
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.45);
|
||||
|
||||
--code-bg: #21222c;
|
||||
--code-text: #f8f8f2;
|
||||
|
||||
--social-icon-filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -430,7 +507,8 @@ img.nav-svg-icon {
|
||||
.profile-social-icon {
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
opacity: 0.6;
|
||||
opacity: 0.65;
|
||||
filter: var(--social-icon-filter);
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
@@ -439,16 +517,6 @@ img.nav-svg-icon {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Dark mode: invert the dark SVG glyphs to light */
|
||||
[data-theme="dark"] .profile-social-icon {
|
||||
filter: brightness(0) invert(1);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .profile-social a:hover .profile-social-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.profile-avatar { width: 120px; height: 120px; }
|
||||
.profile-name { font-size: 1.7rem; }
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
if (strpos($out, 'plugin-search') !== false) {
|
||||
$sidebarSearchHtml .= $out;
|
||||
} else {
|
||||
// Mark the navigation / pages plugin so its list can be
|
||||
// shuffled client-side (see the script near the body end).
|
||||
if (strpos($out, 'plugin-navigation') !== false || strpos($out, 'plugin-pages') !== false) {
|
||||
$out = '<div class="js-random-nav">' . $out . '</div>';
|
||||
}
|
||||
$sidebarOtherHtml .= $out;
|
||||
}
|
||||
}
|
||||
@@ -74,10 +79,17 @@
|
||||
echo Theme::jsBootstrap();
|
||||
?>
|
||||
|
||||
<!-- Light / Dark theme toggle -->
|
||||
<!-- Theme rotation: light -> dark -> nord -> dracula -->
|
||||
<script>
|
||||
(function () {
|
||||
var STORAGE_KEY = 'blowdit-theme';
|
||||
var THEMES = ['light', 'dark', 'nord', 'dracula'];
|
||||
var ICONS = {
|
||||
light: 'bi-brightness-high',
|
||||
dark: 'bi-moon-stars',
|
||||
nord: 'bi-snow',
|
||||
dracula: 'bi-droplet'
|
||||
};
|
||||
var root = document.documentElement;
|
||||
var btn = document.getElementById('theme-toggle');
|
||||
|
||||
@@ -85,7 +97,7 @@
|
||||
if (!btn) return;
|
||||
var icon = btn.querySelector('i');
|
||||
if (!icon) return;
|
||||
icon.className = (theme === 'dark') ? 'bi bi-sun' : 'bi bi-moon-stars';
|
||||
icon.className = 'bi ' + (ICONS[theme] || 'bi-circle-half');
|
||||
}
|
||||
|
||||
function apply(theme) {
|
||||
@@ -95,12 +107,15 @@
|
||||
}
|
||||
|
||||
// Reflect the theme set by the inline head script.
|
||||
syncIcon(root.getAttribute('data-theme') || 'light');
|
||||
var current = root.getAttribute('data-theme') || 'light';
|
||||
if (THEMES.indexOf(current) === -1) current = 'light';
|
||||
syncIcon(current);
|
||||
|
||||
if (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var current = root.getAttribute('data-theme') || 'light';
|
||||
apply(current === 'dark' ? 'light' : 'dark');
|
||||
var cur = root.getAttribute('data-theme') || 'light';
|
||||
var i = THEMES.indexOf(cur);
|
||||
apply(THEMES[(i + 1) % THEMES.length]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,6 +131,26 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Randomise the order of the navigation / pages list on each load -->
|
||||
<script>
|
||||
(function () {
|
||||
function shuffle(arr) {
|
||||
for (var i = arr.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
var lists = document.querySelectorAll('.js-random-nav ul');
|
||||
Array.prototype.forEach.call(lists, function (ul) {
|
||||
var items = Array.prototype.filter.call(ul.children, function (el) {
|
||||
return el.tagName === 'LI';
|
||||
});
|
||||
shuffle(items).forEach(function (li) { ul.appendChild(li); });
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Load Bludit Plugins: Site Body End -->
|
||||
<?php Theme::plugins('siteBodyEnd'); ?>
|
||||
|
||||
|
||||
Reference in new issue
Block a user