Backend Go 1.23+ : - API REST + WebSocket (chi, gorilla/websocket) - Authentification PAM via SSH + JWT RS256 - Chiffrement AES-256-GCM pour secrets SQLite - Pool SSH, client Proxmox REST, hub WebSocket pub/sub - Système de modules compilés à initialisation conditionnelle - Audit log, migrations SQLite versionnées Frontend Vue 3 + Vite + TypeScript : - Thème Neumorphism sombre/clair (CSS custom properties) - Wizard d'installation, Dashboard drag-drop, Terminal xterm.js - Toutes les vues CORE + stubs modules optionnels - i18n EN/FR (vue-i18n v11) Infrastructure : - Docker multi-stage (Go → alpine, Node → nginx) - docker-compose.yml, .gitattributes, LICENSE MIT, README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
84 lines
2.2 KiB
TypeScript
84 lines
2.2 KiB
TypeScript
// Store UI — gère le thème (dark/light) et la position de la sidebar.
|
|
// Les préférences sont persistées localement et synchronisées avec le serveur.
|
|
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
|
|
export type Theme = 'dark' | 'light'
|
|
export type SidebarPosition = 'left' | 'right'
|
|
|
|
export const useUiStore = defineStore('ui', () => {
|
|
const theme = ref<Theme>('dark')
|
|
const sidebarPosition = ref<SidebarPosition>('left')
|
|
const sidebarCollapsed = ref(false)
|
|
const mobileMenuOpen = ref(false)
|
|
|
|
/**
|
|
* Initialise le thème depuis les préférences locales.
|
|
* Appelé au montage de App.vue.
|
|
*/
|
|
function initTheme(): void {
|
|
const savedTheme = localStorage.getItem('pxp_theme') as Theme | null
|
|
const savedSidebar = localStorage.getItem('pxp_sidebar') as SidebarPosition | null
|
|
|
|
if (savedTheme === 'dark' || savedTheme === 'light') {
|
|
theme.value = savedTheme
|
|
}
|
|
if (savedSidebar === 'left' || savedSidebar === 'right') {
|
|
sidebarPosition.value = savedSidebar
|
|
}
|
|
|
|
applyTheme(theme.value)
|
|
}
|
|
|
|
/**
|
|
* Bascule entre thème sombre et clair.
|
|
*/
|
|
function toggleTheme(): void {
|
|
theme.value = theme.value === 'dark' ? 'light' : 'dark'
|
|
localStorage.setItem('pxp_theme', theme.value)
|
|
applyTheme(theme.value)
|
|
}
|
|
|
|
/**
|
|
* Définit le thème explicitement.
|
|
*/
|
|
function setTheme(newTheme: Theme): void {
|
|
theme.value = newTheme
|
|
localStorage.setItem('pxp_theme', newTheme)
|
|
applyTheme(newTheme)
|
|
}
|
|
|
|
/**
|
|
* Définit la position de la sidebar.
|
|
*/
|
|
function setSidebarPosition(pos: SidebarPosition): void {
|
|
sidebarPosition.value = pos
|
|
localStorage.setItem('pxp_sidebar', pos)
|
|
}
|
|
|
|
/**
|
|
* Bascule l'état réduit de la sidebar.
|
|
*/
|
|
function toggleSidebarCollapse(): void {
|
|
sidebarCollapsed.value = !sidebarCollapsed.value
|
|
}
|
|
|
|
/**
|
|
* Applique le thème sur l'élément <html> via data-theme.
|
|
*/
|
|
function applyTheme(t: Theme): void {
|
|
document.documentElement.setAttribute('data-theme', t)
|
|
}
|
|
|
|
return {
|
|
theme,
|
|
sidebarPosition,
|
|
sidebarCollapsed,
|
|
mobileMenuOpen,
|
|
initTheme,
|
|
toggleTheme,
|
|
setTheme,
|
|
setSidebarPosition,
|
|
toggleSidebarCollapse,
|
|
}
|
|
})
|