mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 23:39:40 +02:00
Move inactive projects out of active workspace: - bauntown (community website) - maerchenzauber (AI story generation) - memoro (voice memo app) - news (news aggregation) - nutriphi (nutrition tracking) - reader (reading app) - uload (URL shortener) - wisekeep (AI wisdom extraction) Update CLAUDE.md documentation: - Add presi to active projects - Document archived projects section - Update workspace configuration Archived apps can be re-activated by moving back to apps/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
274 lines
8 KiB
Text
274 lines
8 KiB
Text
---
|
|
|
|
---
|
|
|
|
<div class="fixed top-4 right-4 z-50 flex items-center gap-2">
|
|
<!-- Theme Selector -->
|
|
<div class="relative">
|
|
<button
|
|
id="theme-menu-button"
|
|
class="glass px-4 py-2 rounded-lg flex items-center gap-2 hover:bg-theme-surface-hover text-theme-text"
|
|
aria-label="Select theme"
|
|
>
|
|
<span id="theme-icon">🌊</span>
|
|
<span id="theme-name" class="hidden sm:inline">Ocean</span>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"
|
|
></path>
|
|
</svg>
|
|
</button>
|
|
|
|
<div
|
|
id="theme-menu"
|
|
class="absolute right-0 mt-2 w-48 glass rounded-lg shadow-theme-lg hidden opacity-0 transform scale-95 transition-all duration-200"
|
|
>
|
|
<div class="p-2">
|
|
<button
|
|
data-theme="ocean"
|
|
class="theme-option w-full px-4 py-2 rounded-md hover:bg-theme-surface-hover text-left flex items-center gap-3 text-theme-text"
|
|
>
|
|
<span>🌊</span> Ocean
|
|
</button>
|
|
<button
|
|
data-theme="forest"
|
|
class="theme-option w-full px-4 py-2 rounded-md hover:bg-theme-surface-hover text-left flex items-center gap-3 text-theme-text"
|
|
>
|
|
<span>🌲</span> Forest
|
|
</button>
|
|
<button
|
|
data-theme="sunset"
|
|
class="theme-option w-full px-4 py-2 rounded-md hover:bg-theme-surface-hover text-left flex items-center gap-3 text-theme-text"
|
|
>
|
|
<span>🌅</span> Sunset
|
|
</button>
|
|
<button
|
|
data-theme="monochrome"
|
|
class="theme-option w-full px-4 py-2 rounded-md hover:bg-theme-surface-hover text-left flex items-center gap-3 text-theme-text"
|
|
>
|
|
<span>⚫</span> Monochrome
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dark Mode Toggle -->
|
|
<button
|
|
id="dark-toggle"
|
|
class="glass p-2 rounded-lg hover:bg-theme-surface-hover text-theme-text"
|
|
aria-label="Toggle dark mode"
|
|
>
|
|
<svg id="sun-icon" class="w-5 h-5 hidden" fill="currentColor" viewBox="0 0 20 20">
|
|
<path
|
|
fill-rule="evenodd"
|
|
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
|
|
clip-rule="evenodd"></path>
|
|
</svg>
|
|
<svg id="moon-icon" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
const themes = {
|
|
ocean: { icon: '🌊', name: 'Ocean' },
|
|
forest: { icon: '🌲', name: 'Forest' },
|
|
sunset: { icon: '🌅', name: 'Sunset' },
|
|
monochrome: { icon: '⚫', name: 'Monochrome' },
|
|
};
|
|
|
|
class ThemeManager {
|
|
constructor() {
|
|
this.currentTheme = 'ocean';
|
|
this.isDark = false;
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
// Load saved preferences
|
|
this.loadPreferences();
|
|
|
|
// Apply theme immediately
|
|
this.applyTheme();
|
|
|
|
// Setup event listeners
|
|
this.setupEventListeners();
|
|
|
|
// Listen for system theme changes
|
|
this.watchSystemPreference();
|
|
}
|
|
|
|
loadPreferences() {
|
|
// Check localStorage first
|
|
const savedTheme = localStorage.getItem('theme');
|
|
const savedMode = localStorage.getItem('darkMode');
|
|
|
|
if (savedTheme && themes[savedTheme]) {
|
|
this.currentTheme = savedTheme;
|
|
}
|
|
|
|
if (savedMode !== null) {
|
|
this.isDark = savedMode === 'true';
|
|
} else {
|
|
// Check system preference if no saved preference
|
|
this.isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
}
|
|
}
|
|
|
|
savePreferences() {
|
|
localStorage.setItem('theme', this.currentTheme);
|
|
localStorage.setItem('darkMode', this.isDark.toString());
|
|
}
|
|
|
|
applyTheme() {
|
|
const html = document.documentElement;
|
|
|
|
// Set theme
|
|
html.setAttribute('data-theme', this.currentTheme);
|
|
|
|
// Set dark mode
|
|
if (this.isDark) {
|
|
html.classList.add('dark');
|
|
} else {
|
|
html.classList.remove('dark');
|
|
}
|
|
|
|
// Update UI
|
|
this.updateUI();
|
|
}
|
|
|
|
updateUI() {
|
|
// Update theme button
|
|
const themeIcon = document.getElementById('theme-icon');
|
|
const themeName = document.getElementById('theme-name');
|
|
if (themeIcon && themeName) {
|
|
themeIcon.textContent = themes[this.currentTheme].icon;
|
|
themeName.textContent = themes[this.currentTheme].name;
|
|
}
|
|
|
|
// Update dark mode toggle
|
|
const sunIcon = document.getElementById('sun-icon');
|
|
const moonIcon = document.getElementById('moon-icon');
|
|
if (sunIcon && moonIcon) {
|
|
if (this.isDark) {
|
|
sunIcon.classList.remove('hidden');
|
|
moonIcon.classList.add('hidden');
|
|
} else {
|
|
sunIcon.classList.add('hidden');
|
|
moonIcon.classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
// Update active theme in menu
|
|
document.querySelectorAll('.theme-option').forEach((btn) => {
|
|
const theme = btn.getAttribute('data-theme');
|
|
if (theme === this.currentTheme) {
|
|
btn.classList.add('bg-theme-primary/10', 'text-theme-primary');
|
|
} else {
|
|
btn.classList.remove('bg-theme-primary/10', 'text-theme-primary');
|
|
}
|
|
});
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Theme menu toggle
|
|
const menuButton = document.getElementById('theme-menu-button');
|
|
const menu = document.getElementById('theme-menu');
|
|
|
|
if (menuButton && menu) {
|
|
menuButton.addEventListener('click', () => {
|
|
const isHidden = menu.classList.contains('hidden');
|
|
if (isHidden) {
|
|
menu.classList.remove('hidden');
|
|
setTimeout(() => {
|
|
menu.classList.remove('opacity-0', 'scale-95');
|
|
menu.classList.add('opacity-100', 'scale-100');
|
|
}, 10);
|
|
} else {
|
|
menu.classList.remove('opacity-100', 'scale-100');
|
|
menu.classList.add('opacity-0', 'scale-95');
|
|
setTimeout(() => {
|
|
menu.classList.add('hidden');
|
|
}, 200);
|
|
}
|
|
});
|
|
|
|
// Close menu when clicking outside
|
|
document.addEventListener('click', (e) => {
|
|
if (!menuButton.contains(e.target) && !menu.contains(e.target)) {
|
|
menu.classList.remove('opacity-100', 'scale-100');
|
|
menu.classList.add('opacity-0', 'scale-95');
|
|
setTimeout(() => {
|
|
menu.classList.add('hidden');
|
|
}, 200);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Theme selection
|
|
document.querySelectorAll('.theme-option').forEach((btn) => {
|
|
btn.addEventListener('click', () => {
|
|
const theme = btn.getAttribute('data-theme');
|
|
if (theme && themes[theme]) {
|
|
this.currentTheme = theme;
|
|
this.applyTheme();
|
|
this.savePreferences();
|
|
|
|
// Close menu
|
|
const menu = document.getElementById('theme-menu');
|
|
if (menu) {
|
|
menu.classList.remove('opacity-100', 'scale-100');
|
|
menu.classList.add('opacity-0', 'scale-95');
|
|
setTimeout(() => {
|
|
menu.classList.add('hidden');
|
|
}, 200);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Dark mode toggle
|
|
const darkToggle = document.getElementById('dark-toggle');
|
|
if (darkToggle) {
|
|
darkToggle.addEventListener('click', () => {
|
|
this.isDark = !this.isDark;
|
|
this.applyTheme();
|
|
this.savePreferences();
|
|
});
|
|
}
|
|
|
|
// Keyboard shortcuts
|
|
document.addEventListener('keydown', (e) => {
|
|
// Alt/Option + T: Open theme menu
|
|
if (e.altKey && e.key === 't') {
|
|
e.preventDefault();
|
|
menuButton?.click();
|
|
}
|
|
|
|
// Alt/Option + D: Toggle dark mode
|
|
if (e.altKey && e.key === 'd') {
|
|
e.preventDefault();
|
|
darkToggle?.click();
|
|
}
|
|
});
|
|
}
|
|
|
|
watchSystemPreference() {
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
mediaQuery.addEventListener('change', (e) => {
|
|
// Only apply if user hasn't set a preference
|
|
if (localStorage.getItem('darkMode') === null) {
|
|
this.isDark = e.matches;
|
|
this.applyTheme();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Initialize theme manager when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', () => new ThemeManager());
|
|
} else {
|
|
new ThemeManager();
|
|
}
|
|
</script>
|