Files
portal/app/resources/js/layouts/AuthLayout.vue
T
Дмитрий e909a95a8d phase2(login): vue-router 4 + AuthLayout + LoginView - первый реальный экран
- vue-router@^4.6.4 (--legacy-peer-deps из-за Histoire vs Vite 8 peerDep).
- resources/js/router/index.ts: createWebHistory + lazy-imports + meta.layout.
  Маршрут / -> /login, /login -> LoginView (meta.layout=auth).
- resources/js/layouts/AuthLayout.vue: двухпанельный (brand-pane тёмный с
  radial-gradient акцентами + form-pane warm ivory). На mobile brand-pane скрыт.
- resources/js/views/auth/LoginView.vue: форма Vuetify по v8_login.html
  секция #form-login - email/password (autocomplete + eye-icon), primary submit,
  Yandex 360 SSO, RouterLink на /register и /forgot.
- AppShell.vue: layout-mapper по route.meta.layout (default/auth).
- routes/web.php: явные Route::view для 6 SPA-путей (НЕ catch-all - он перехватывал
  /_test/* в Pest beforeEach и валил 5 SetTenantContextTest).
- Vitest: +LoginView.spec.ts (5), +router.spec.ts (2), AppShell.spec.ts переписан (3).
  Vitest 10/10 за 3.01s.
- LoginView.story.vue для Histoire. Setup расширен memory-router'ом.
- cspell-words.txt: рендерят, коммиты, Лидерру.
- Регресс: lint:vue OK, type-check OK, format:check OK, vitest 10/10,
  vite build 212 модулей за 383ms (LoginView lazy-chunk 43.5KB JS / 51.7KB CSS),
  story:build 2/2 за 29.94s, Pest 48/48 за 4.86s.

CLAUDE.md v1.18->v1.19, реестр Открытых_вопросов v1.27->v1.28.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:59:00 +03:00

145 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
/**
* Двухпанельный layout для экранов аутентификации (login/register/2fa/forgot/recovery).
*
* Источник дизайна: liderra_v8_handoff/concepts/v8_login.html (CSS .layout grid 1fr 1fr,
* .brand-pane слева тёмный теало-нуар + radial-gradient'ы, .form-pane справа warm ivory).
*
* Структура:
* - <v-row no-gutters> с двумя колонками 50/50 на desktop, на mobile — brand-pane скрыт.
* - Слева: brand mark "Лидерра.", цитата с акцентом, footer с ссылками на оферту/политику.
* - Справа: <RouterView /> рендерит конкретный auth-экран (LoginView и т.п.).
*/
import { RouterView } from 'vue-router';
</script>
<template>
<v-app>
<v-main>
<v-row no-gutters class="auth-layout">
<v-col cols="12" md="6" class="brand-pane d-none d-md-flex">
<div class="brand-pane-inner">
<div class="bp-brand">
<span class="mark" aria-hidden="true">
<svg viewBox="0 0 48 48" width="24" height="24">
<path
d="M16 14 L16 34 L32 34"
stroke="#012019"
stroke-width="4.5"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"
/>
<circle cx="32" cy="34" r="3.5" fill="#0F6E56" />
</svg>
</span>
<span>Лидерра<span class="dot">.</span></span>
</div>
<p class="bp-quote">
Поток лидов <em>под контролем</em>.<br />
Pay-per-lead, прозрачно каждый рубль <em>в дело</em>.
</p>
<div class="bp-foot">
<span>v8 · Forest</span>
<a href="/legal/offer">Оферта</a>
<a href="/legal/privacy">Политика</a>
</div>
</div>
</v-col>
<v-col cols="12" md="6" class="form-pane d-flex align-center justify-center">
<RouterView />
</v-col>
</v-row>
</v-main>
</v-app>
</template>
<style scoped>
.auth-layout {
min-height: 100vh;
}
.brand-pane {
background: #012019;
color: #fff;
padding: 56px 60px;
position: relative;
overflow: hidden;
}
.brand-pane::before {
content: '';
position: absolute;
inset: 0;
background-image:
radial-gradient(circle at 80% 20%, rgba(50, 200, 169, 0.08) 0%, transparent 40%),
radial-gradient(circle at 20% 80%, rgba(15, 110, 86, 0.1) 0%, transparent 40%);
pointer-events: none;
}
.brand-pane-inner {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
}
.bp-brand {
display: flex;
align-items: center;
gap: 10px;
font-weight: 600;
font-size: 16px;
letter-spacing: -0.01em;
font-variation-settings: 'opsz' 18;
}
.bp-brand .mark {
width: 24px;
height: 24px;
border-radius: 5px;
background: #fff;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
overflow: hidden;
}
.bp-brand .dot {
color: #32c8a9;
}
.bp-quote {
font-size: 30px;
font-weight: 500;
font-variation-settings: 'opsz' 28;
letter-spacing: -0.02em;
line-height: 1.18;
max-width: 440px;
margin: 0;
}
.bp-quote em {
color: #32c8a9;
font-style: normal;
}
.bp-foot {
font-size: 12px;
color: #7a8c87;
font-family: 'JetBrains Mono', ui-monospace, monospace;
display: flex;
gap: 14px;
}
.bp-foot a {
color: inherit;
text-decoration: none;
}
.bp-foot a:hover {
color: #fff;
}
.form-pane {
background: #f6f3ec;
padding: 40px 32px 56px;
}
</style>