Files
sales-trainer/frontend/src/views/Login.vue
Macky a04bc2add8 fix(ui): widen login/setup forms so inputs don't truncate text; line icons
- Login card 360->460px (max-width:100%), wider inputs (46px, 15px, more padding),
  mobile side padding; eye-toggles -> lucide Eye/EyeOff line icons (no emoji).
- Setup card 380->460px (max-width:100%), wider inputs, Lock line icon instead of emoji.
Rebuilt dist.
2026-08-08 17:00:09 +07:00

84 lines
2.8 KiB
Vue

<template>
<div class="login-wrap">
<div class="card login-card">
<h1>{{ i18n.t('app') }}</h1>
<p class="muted" style="margin-top:-8px">Sales training simulator</p>
<label>{{ i18n.t('username') }}</label>
<input v-model="username" type="text" autocomplete="username" placeholder="username" class="wide" @keyup.enter="submit" />
<label>{{ i18n.t('password') }}</label>
<div class="pw-wrap">
<input v-model="password" :type="showPw ? 'text' : 'password'" autocomplete="current-password" placeholder="••••••••" class="wide" @keyup.enter="submit" />
<button type="button" class="pw-toggle" @click="showPw = !showPw" :aria-label="showPw ? 'Hide password' : 'Show password'">
<EyeOff v-if="showPw" :size="20" :stroke-width="1.8" />
<Eye v-else :size="20" :stroke-width="1.8" />
</button>
</div>
<div class="error" role="alert" v-if="error">{{ error }}</div>
<button class="primary" style="width:100%;margin-top:18px" :disabled="loading || !username || !password" @click="submit">
<span v-if="loading" class="spinner"></span>
<span v-else>{{ i18n.t('login') }}</span>
</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Eye, EyeOff } from 'lucide-vue-next'
import { auth } from '../store/auth'
import { i18n } from '../i18n'
const route = useRoute()
const router = useRouter()
const username = ref('')
const password = ref('')
const showPw = ref(false)
const error = ref('')
const loading = ref(false)
async function submit() {
error.value = ''
loading.value = true
try {
await auth.login(username.value.trim(), password.value)
// First-time admin setup is mandatory before using the app.
if (auth.mustSetup) {
router.push({ path: '/setup' })
} else {
router.push(route.query.redirect || '/')
}
} catch (e) {
error.value = i18n.t('loginError')
} finally {
loading.value = false
}
}
</script>
<style scoped>
.login-wrap {
display: flex;
justify-content: center;
padding-top: 8vh;
padding-left: 16px;
padding-right: 16px;
}
/* Wider card so inputs don't truncate / cut text */
.login-card { width: 460px; max-width: 100%; padding: 28px 30px; }
h1 { margin-top: 0; font-size: 24px; }
/* Full-width, uncramped inputs (global input already width:100%) */
.wide { width: 100%; min-height: 46px; font-size: 15px; padding: 12px 14px; }
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 48px; }
.pw-toggle {
position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
background: transparent; border: none; padding: 8px; min-height: 40px; cursor: pointer;
color: var(--muted);
}
.pw-toggle:hover { color: var(--ink); }
</style>