feat: réécriture frontend Alpine.js + HTMX + Swup (branche frontend/alpine)
Remplace Vue 3 / Vite / TypeScript par une stack légère statique : - Alpine.js v3 : réactivité inline, stores auth/ui/i18n, composants par page - HTMX v2 : interactions serveur via attributs HTML - Swup v4 : transitions de page (bundlé via esbuild, IIFE browser-loadable) - xterm.js v5 : terminal PTY (bundlé via esbuild) Structure : HTML statiques + js/app.js + js/terminal.js + css/ + locales/ Build : esbuild (bundle Swup + xterm seulement) → dist/ → Nginx Dockerfile simplifié : node:22-alpine build → nginx:1.27-alpine serve Pages : index, install, login, dashboard, proxmox, updates, terminal, settings, modules URLs propres via nginx try_files $uri.html Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7ba0ff143c
commit
2098c80ec1
48 changed files with 2446 additions and 5317 deletions
131
frontend/login.html
Normal file
131
frontend/login.html
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ProxmoxPanel — Connexion</title>
|
||||
<link rel="stylesheet" href="/css/neu.css" />
|
||||
<link rel="stylesheet" href="/css/dark.css" />
|
||||
<link rel="stylesheet" href="/css/light.css" />
|
||||
<script src="/js/vendors/htmx.min.js"></script>
|
||||
<script src="/js/vendors/swup.iife.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/vendors/alpine.min.js" defer></script>
|
||||
</head>
|
||||
<body x-data>
|
||||
<div class="auth-layout" x-data="loginPage()" x-cloak>
|
||||
<div class="auth-card neu-card">
|
||||
<div class="auth-logo">
|
||||
<span class="logo-icon">⬡</span>
|
||||
<h1 class="auth-title">ProxmoxPanel</h1>
|
||||
<p class="auth-subtitle" x-text="t('login.subtitle')"></p>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="submit" class="auth-form">
|
||||
<div class="form-group">
|
||||
<label class="form-label" x-text="t('login.username')"></label>
|
||||
<input
|
||||
class="neu-input"
|
||||
type="text"
|
||||
x-model="username"
|
||||
:placeholder="t('login.usernamePlaceholder')"
|
||||
autocomplete="username"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" x-text="t('login.password')"></label>
|
||||
<input
|
||||
class="neu-input"
|
||||
type="password"
|
||||
x-model="password"
|
||||
:placeholder="t('login.passwordPlaceholder')"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-error" x-show="error" x-text="error" role="alert"></div>
|
||||
|
||||
<button class="neu-btn neu-btn--primary auth-submit" type="submit" :disabled="loading">
|
||||
<span x-show="!loading" x-text="t('login.submit')"></span>
|
||||
<span x-show="loading" class="spinner"></span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.auth-layout {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1rem;
|
||||
}
|
||||
.auth-card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
padding: 2rem;
|
||||
}
|
||||
.auth-logo {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.logo-icon {
|
||||
font-size: 3rem;
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
.auth-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin: 0.5rem 0 0.25rem;
|
||||
}
|
||||
.auth-subtitle {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
.auth-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.form-label {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.form-error {
|
||||
background: rgba(239,68,68,0.1);
|
||||
border: 1px solid var(--color-error, #ef4444);
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-error, #ef4444);
|
||||
}
|
||||
.auth-submit {
|
||||
width: 100%;
|
||||
padding: 0.875rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
.spinner {
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border: 2px solid transparent;
|
||||
border-top-color: currentColor;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
[x-cloak] { display: none !important; }
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue