Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .yarn/install-state.gz
Binary file not shown.
4 changes: 2 additions & 2 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import tailwindcss from '@tailwindcss/vite';
// https://astro.build/config
export default defineConfig({
server: { port: 9000 },
site: 'https://jostvim.github.io',
base: '/jostvim.org',
site: 'https://luxvim.github.io',
base: '/luxvim.org',
vite: {
plugins: [tailwindcss()]
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "jostvim.org",
"name": "luxvim.org",
"type": "module",
"version": "0.0.1",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Navbar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const {

<!-- Brand Name -->
<span class="text-xl font-bold bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 text-transparent bg-clip-text group-hover:from-purple-300 group-hover:via-pink-400 group-hover:to-red-400 transition-all duration-300">
JostVim
LuxVim
</span>
</a>

Expand Down
91 changes: 42 additions & 49 deletions src/components/ThemeToggle.astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,65 +7,58 @@
<button
id="themeToggle"
type="button"
aria-label="Toggle dark mode"
aria-pressed="false"
class="theme-switch relative inline-flex h-12 w-20 items-center justify-center rounded-full border-2 border-indigo-200 dark:border-indigo-500/40 bg-indigo-100 dark:bg-slate-800/80 backdrop-blur-sm transition-all duration-300 hover:bg-indigo-200 dark:hover:bg-slate-700/80 hover:border-purple-400 dark:hover:border-purple-400/60 focus:outline-none focus:ring-2 focus:ring-purple-400/50 focus:border-purple-400 dark:focus:border-purple-400"
>
<!-- Switch Track with Icons -->
<!-- Background Track -->
<div class="absolute inset-1 rounded-full bg-gradient-to-r from-indigo-200/80 to-indigo-300/80 dark:from-slate-700/80 dark:to-slate-600/80 transition-all duration-300"></div>

<!-- Sun Icon (left side - visible in light mode) -->
<span class="absolute left-3 text-lg z-5 transition-all duration-300">☀️</span>

<!-- Moon Icon (right side - visible in dark mode) -->
<span class="absolute right-3 text-lg z-5 transition-all duration-300">🌙</span>

<!-- Switch Thumb (covers one icon) -->
<div class="switch-thumb relative z-10 h-8 w-8 rounded-full bg-white dark:bg-slate-900 shadow-lg transition-all duration-300 border border-indigo-300 dark:border-indigo-400/60"></div>

<!-- Sliding Thumb with Icon -->
<div class="switch-thumb relative z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white dark:bg-slate-900 shadow-lg transition-transform duration-300 border border-indigo-300 dark:border-indigo-400/60">
<span class="current-theme-icon text-lg">☀️</span>
</div>
</button>
</div>

<script is:inline>
const theme = (() => {
const localStorageTheme = localStorage?.getItem("theme") ?? '';
if (['dark', 'light'].includes(localStorageTheme)) {
return localStorageTheme;
}
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
})();
const themeButton = document.getElementById('themeToggle');
const thumb = themeButton.querySelector('.switch-thumb');
const icon = themeButton.querySelector('.current-theme-icon');
const htmlEl = document.documentElement;

if (theme === 'light') {
document.documentElement.classList.remove('dark');
} else {
document.documentElement.classList.add('dark');
}
// Determine initial theme
const storedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const initialTheme = (storedTheme === 'dark' || storedTheme === 'light')
? storedTheme
: prefersDark ? 'dark' : 'light';

window.localStorage.setItem('theme', theme);
htmlEl.classList.toggle('dark', initialTheme === 'dark');
localStorage.setItem('theme', initialTheme);

const handleToggleClick = (event) => {
const element = document.documentElement;
element.classList.toggle("dark");
// Update thumb position, icon, and ARIA state
const updateUI = () => {
const isDark = htmlEl.classList.contains('dark');
// Slide the thumb via inline style for consistent positioning
thumb.style.transform = isDark ? 'translateX(16px)' : 'translateX(-16px)';
// Swap the icon inside the thumb
icon.textContent = isDark ? '🌙' : '☀️';
// Update aria-pressed to reflect current state
themeButton.setAttribute('aria-pressed', isDark);
};

const isDark = element.classList.contains("dark");
localStorage.setItem("theme", isDark ? "dark" : "light");

// Remove focus after animation completes
setTimeout(() => {
event.target.blur();
}, 300);
}
updateUI();

const handleMouseLeave = (event) => {
// Small delay to avoid conflicts with click
setTimeout(() => {
event.target.blur();
}, 100);
}
// Toggle handler
const toggleTheme = (event) => {
htmlEl.classList.toggle('dark');
localStorage.setItem('theme', htmlEl.classList.contains('dark') ? 'dark' : 'light');
updateUI();
// Remove focus after animation
setTimeout(() => themeButton.blur(), 300);
};

const themeButton = document.getElementById("themeToggle");
if (themeButton) {
themeButton.addEventListener("click", handleToggleClick);
themeButton.addEventListener("mouseleave", handleMouseLeave);
}
</script>
themeButton.addEventListener('click', toggleTheme);
themeButton.addEventListener('mouseleave', () => setTimeout(() => themeButton.blur(), 100));
</script>
Loading