Files
space-booking/frontend/src/views/Login.vue
Claude Agent 0bf3e6a7e2 feat: complete UI redesign with dark mode, sidebar navigation, and modern design system
Implemented comprehensive UI overhaul with three-layer architecture:

Layer 1 - Theme System:
- CSS variables for light/dark themes (theme.css)
- Theme composable with light/dark/auto mode (useTheme.ts)
- Sidebar state management composable (useSidebar.ts)
- Refactored main.css to use CSS variables throughout

Layer 2 - Core Components:
- AppSidebar with collapsible navigation (desktop) and overlay (mobile)
- CollapsibleSection reusable component for expandable cards
- Restructured App.vue with new sidebar layout
- Integrated Lucide icons library (lucide-vue-next)

Layer 3 - Views & Components:
- Updated all 14 views with CSS variables and responsive design
- Replaced inline SVG with Lucide icon components
- Added collapsible sections to Dashboard, Admin pages, UserProfile
- Updated 3 shared components (BookingForm, SpaceCalendar, AttachmentsList)

Features:
- Dark/light/auto theme with persistent preference
- Collapsible sidebar (icons-only on desktop, overlay on mobile)
- Consistent color palette using CSS variables
- Full responsive design across all pages
- Modern minimalist aesthetic with Indigo accent color

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 21:27:05 +00:00

159 lines
3.3 KiB
Vue

<template>
<div class="login-container">
<div class="login-card card">
<h2>Space Booking</h2>
<p class="subtitle">Sign in to your account</p>
<form @submit.prevent="handleLogin">
<div class="form-group">
<label for="email">Email</label>
<input
id="email"
v-model="email"
type="email"
required
placeholder="your@email.com"
autocomplete="email"
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
id="password"
v-model="password"
type="password"
required
placeholder="Enter your password"
autocomplete="current-password"
/>
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<button type="submit" class="btn btn-primary btn-block" :disabled="loading">
{{ loading ? 'Logging in...' : 'Login' }}
</button>
</form>
<p class="register-link">
Don't have an account? <router-link to="/register">Register</router-link>
</p>
<div class="demo-accounts">
<p class="demo-title">Demo Accounts:</p>
<p><strong>Admin:</strong> admin@example.com / adminpassword</p>
<p><strong>User:</strong> user@example.com / userpassword</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { handleApiError } from '@/services/api'
const router = useRouter()
const authStore = useAuthStore()
const email = ref('')
const password = ref('')
const error = ref('')
const loading = ref(false)
const handleLogin = async () => {
error.value = ''
loading.value = true
try {
await authStore.login({
email: email.value,
password: password.value
})
router.push('/dashboard')
} catch (err) {
error.value = handleApiError(err)
} finally {
loading.value = false
}
}
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 1rem;
}
.login-card {
width: 100%;
max-width: 400px;
}
h2 {
text-align: center;
margin-bottom: 0.5rem;
color: var(--color-text-primary);
}
.subtitle {
text-align: center;
color: var(--color-text-secondary);
margin-bottom: 2rem;
}
.btn-block {
width: 100%;
margin-top: 1rem;
}
.register-link {
text-align: center;
margin-top: 1.5rem;
color: var(--color-text-secondary);
}
.register-link a {
color: var(--color-accent);
text-decoration: none;
}
.register-link a:hover {
text-decoration: underline;
}
.demo-accounts {
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid var(--color-border);
font-size: 0.9rem;
color: var(--color-text-secondary);
}
.demo-title {
font-weight: 600;
margin-bottom: 0.5rem;
color: var(--color-text-primary);
}
.demo-accounts p {
margin: 0.25rem 0;
}
.error {
margin-top: 1rem;
padding: 0.75rem;
background: color-mix(in srgb, var(--color-danger) 10%, transparent);
border-left: 3px solid var(--color-danger);
border-radius: var(--radius-sm);
color: var(--color-danger);
}
</style>