feat(ui): Refonte UI page Libraries - design moderne en cards
- Remplacement du tableau moche par des cards modernes
- Layout responsive en grille (grid-template-columns)
- Cards avec hover effects (ombre + léger déplacement)
- Stats visibles en boxes cliquables (Books/Series)
- Monitoring compact avec checkboxes côte à côte
- Badges pour Disabled et Watcher (⚡)
- Actions regroupées avec boutons colorés
- Formulaire d'ajout plus visible et stylisé
- CSS complet avec dark mode support
- MonitoringForm simplifié et compact
This commit is contained in:
@@ -34,10 +34,11 @@ export function MonitoringForm({ libraryId, monitorEnabled, scanMode, watcherEna
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form action={handleSubmit} className="monitoring-form">
|
<form action={handleSubmit} className="monitoring-form-compact">
|
||||||
<input type="hidden" name="id" value={libraryId} />
|
<input type="hidden" name="id" value={libraryId} />
|
||||||
<div className="monitor-options">
|
|
||||||
<label className={`monitor-toggle ${isPending ? 'pending' : ''}`}>
|
<div className="monitor-row">
|
||||||
|
<label className={`monitor-checkbox ${isPending ? 'pending' : ''}`}>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="monitor_enabled"
|
name="monitor_enabled"
|
||||||
@@ -45,9 +46,10 @@ export function MonitoringForm({ libraryId, monitorEnabled, scanMode, watcherEna
|
|||||||
defaultChecked={monitorEnabled}
|
defaultChecked={monitorEnabled}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
/>
|
/>
|
||||||
<span className="toggle-label">Auto-scan</span>
|
<span>Auto</span>
|
||||||
</label>
|
</label>
|
||||||
<label className={`monitor-toggle watcher-toggle ${isPending ? 'pending' : ''} ${watcherEnabled ? 'active' : ''}`}>
|
|
||||||
|
<label className={`monitor-checkbox watcher ${isPending ? 'pending' : ''} ${watcherEnabled ? 'active' : ''}`}>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="watcher_enabled"
|
name="watcher_enabled"
|
||||||
@@ -55,23 +57,25 @@ export function MonitoringForm({ libraryId, monitorEnabled, scanMode, watcherEna
|
|||||||
defaultChecked={watcherEnabled}
|
defaultChecked={watcherEnabled}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
/>
|
/>
|
||||||
<span className="toggle-label">Watcher</span>
|
<span title="Real-time file watcher">⚡</span>
|
||||||
<span className="toggle-hint" title="Detects file changes in real-time">⚡</span>
|
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<select
|
||||||
|
name="scan_mode"
|
||||||
|
defaultValue={scanMode}
|
||||||
|
disabled={isPending}
|
||||||
|
className="scan-mode-select"
|
||||||
|
>
|
||||||
|
<option value="manual">Manual</option>
|
||||||
|
<option value="hourly">Hourly</option>
|
||||||
|
<option value="daily">Daily</option>
|
||||||
|
<option value="weekly">Weekly</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="submit" className="save-btn" disabled={isPending}>
|
||||||
|
{isPending ? '...' : '✓'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<select
|
|
||||||
name="scan_mode"
|
|
||||||
defaultValue={scanMode}
|
|
||||||
disabled={isPending}
|
|
||||||
>
|
|
||||||
<option value="manual">Manual only</option>
|
|
||||||
<option value="hourly">Hourly</option>
|
|
||||||
<option value="daily">Daily</option>
|
|
||||||
<option value="weekly">Weekly</option>
|
|
||||||
</select>
|
|
||||||
<button type="submit" className="update-btn" disabled={isPending}>
|
|
||||||
{isPending ? '...' : 'Update'}
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1630,3 +1630,352 @@ tr.job-highlighted td {
|
|||||||
.view-btn:hover {
|
.view-btn:hover {
|
||||||
background: hsl(198 78% 37% / 0.2);
|
background: hsl(198 78% 37% / 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Libraries Grid - Modern Card Layout */
|
||||||
|
.libraries-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-card {
|
||||||
|
background: var(--card);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
transition: box-shadow 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-card:hover {
|
||||||
|
box-shadow: var(--shadow-2);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library Header */
|
||||||
|
.library-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-name {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--foreground);
|
||||||
|
line-height: 1.3;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-badges {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-disabled {
|
||||||
|
background: hsl(220 13% 80%);
|
||||||
|
color: hsl(220 13% 40%);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-watcher {
|
||||||
|
background: hsl(45 93% 90%);
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library Path */
|
||||||
|
.library-path {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
background: hsl(220 13% 95%);
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .library-path {
|
||||||
|
background: hsl(220 13% 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library Stats */
|
||||||
|
.library-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-box {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px;
|
||||||
|
background: hsl(198 52% 95%);
|
||||||
|
border-radius: 8px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-box:hover {
|
||||||
|
background: hsl(198 52% 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: hsl(198 78% 37%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-box {
|
||||||
|
background: hsl(198 52% 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-box:hover {
|
||||||
|
background: hsl(198 52% 25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-number {
|
||||||
|
color: hsl(198 78% 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library Monitoring */
|
||||||
|
.library-monitoring {
|
||||||
|
background: hsl(220 13% 97%);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .library-monitoring {
|
||||||
|
background: hsl(220 13% 18%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-status {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-status.active {
|
||||||
|
color: hsl(142 60% 45%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-status.inactive {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.next-scan-badge {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
background: hsl(198 52% 90%);
|
||||||
|
color: hsl(198 78% 37%);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .next-scan-badge {
|
||||||
|
background: hsl(198 52% 25%);
|
||||||
|
color: hsl(198 78% 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Library Actions */
|
||||||
|
.library-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-btn {
|
||||||
|
background: hsl(142 60% 45% / 0.15);
|
||||||
|
color: hsl(142 60% 35%);
|
||||||
|
border: 1px solid hsl(142 60% 45% / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-btn {
|
||||||
|
background: hsl(280 60% 45% / 0.15);
|
||||||
|
color: hsl(280 60% 45%);
|
||||||
|
border: 1px solid hsl(280 60% 45% / 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
background: hsl(2 72% 48% / 0.1);
|
||||||
|
color: hsl(2 72% 48%);
|
||||||
|
border: 1px solid hsl(2 72% 48% / 0.3);
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-form {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add Library Form */
|
||||||
|
.library-add-form {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-add-form h2 {
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-name-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-folder-select {
|
||||||
|
flex: 2;
|
||||||
|
min-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
padding: 10px 24px;
|
||||||
|
background: hsl(198 78% 37%);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn:hover {
|
||||||
|
background: hsl(198 78% 32%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.libraries-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-name-input,
|
||||||
|
.library-folder-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compact Monitoring Form */
|
||||||
|
.monitoring-form-compact {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background: hsl(220 13% 95%);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-checkbox:hover {
|
||||||
|
background: hsl(220 13% 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-checkbox input[type="checkbox"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-checkbox.watcher.active {
|
||||||
|
background: hsl(45 93% 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .monitor-checkbox {
|
||||||
|
background: hsl(220 13% 25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .monitor-checkbox:hover {
|
||||||
|
background: hsl(220 13% 30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .monitor-checkbox.watcher.active {
|
||||||
|
background: hsl(45 93% 25%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-mode-select {
|
||||||
|
flex: 1;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: hsl(198 78% 37%);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn:hover:not(:disabled) {
|
||||||
|
background: hsl(198 78% 32%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user