diff --git a/angular.json b/angular.json index df96668..3cc2f9b 100644 --- a/angular.json +++ b/angular.json @@ -80,6 +80,9 @@ }, "serve": { "builder": "@angular/build:dev-server", + "options": { + "proxyConfig": "proxy.conf.json" + }, "configurations": { "production": { "buildTarget": "sentinent-frontend:build:production" @@ -113,4 +116,4 @@ } } } -} \ No newline at end of file +} diff --git a/proxy.conf.json b/proxy.conf.json new file mode 100644 index 0000000..e7c761e --- /dev/null +++ b/proxy.conf.json @@ -0,0 +1,7 @@ +{ + "/api": { + "target": "http://127.0.0.1:8080", + "secure": false, + "changeOrigin": true + } +} diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index df324c4..2f9e5b3 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,12 +1,11 @@ import { Routes } from '@angular/router'; import { Login } from './components/login/login'; -import { Signup } from './components/signup/signup'; import { authGuard } from './guards/auth-guard'; import { CreateWorkspace } from './components/workspace/create-workspace'; export const routes: Routes = [ { path: 'login', component: Login }, - { path: 'signup', component: Signup }, + { path: 'signup', component: Login }, { path: 'dashboard', loadComponent: () => import('./components/dashboard/dashboard').then(m => m.Dashboard), diff --git a/src/app/components/login/login.css b/src/app/components/login/login.css index e69de29..556a354 100644 --- a/src/app/components/login/login.css +++ b/src/app/components/login/login.css @@ -0,0 +1,398 @@ +:host { + display: block; + --bg: #fafafa; + --fg: #0a0a0a; + --subtle: rgba(10, 10, 10, 0.03); + --border: rgba(10, 10, 10, 0.12); + --muted: rgba(10, 10, 10, 0.6); + --error: #dc2626; + --success: #16a34a; + --font-sans: Inter, sans-serif; + --font-display: "Space Grotesk", sans-serif; +} + +:host-context(.dark) { + --bg: #050505; + --fg: #fafafa; + --subtle: rgba(250, 250, 250, 0.05); + --border: rgba(250, 250, 250, 0.12); + --muted: rgba(250, 250, 250, 0.5); +} + +* { + box-sizing: border-box; +} + +.noise { + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + opacity: 0.02; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); +} + +.theme-toggle { + position: fixed; + top: 20px; + right: 20px; + z-index: 50; + width: 40px; + height: 40px; + border-radius: 8px; + border: 1px solid var(--border); + background: var(--bg); + cursor: pointer; + display: grid; + place-items: center; +} + +.theme-toggle:hover { + border-color: var(--fg); +} + +.theme-glyph { + display: block; + width: 18px; + height: 18px; + border-radius: 50%; + border: 1px solid rgba(10, 10, 10, 0.45); + background: linear-gradient(90deg, #0a0a0a 50%, #ffffff 50%); + transition: transform 0.2s ease; +} + +.theme-glyph.dark-active { + transform: rotate(180deg); +} + +.split-layout { + min-height: 100vh; + display: grid; + grid-template-columns: 1fr 480px; + background: var(--bg); + color: var(--fg); + font-family: var(--font-sans); +} + +.brand-side { + position: relative; + overflow: hidden; + background: var(--fg); + color: var(--bg); + padding: 48px; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.brand-pattern { + position: absolute; + inset: 0; + opacity: 0.04; + background-image: radial-gradient(circle at 1px 1px, currentColor 1px, transparent 0); + background-size: 36px 36px; +} + +.brand-content, +.brand-footer { + position: relative; + z-index: 1; +} + +.brand-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 48px; +} + +.brand-icon { + width: 40px; + height: 40px; + border-radius: 10px; + background: var(--bg); + color: var(--fg); + display: grid; + place-items: center; +} + +.brand-name { + font-size: 28px; + font-weight: 700; + font-family: var(--font-display); +} + +h1 { + margin: 0 0 16px; + max-width: 560px; + font-family: var(--font-display); + font-size: 44px; + line-height: 1.12; +} + +.brand-copy { + margin: 0 0 36px; + max-width: 600px; + font-size: 18px; + line-height: 1.75; + opacity: 0.75; +} + +.trust-list { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: 10px; + font-size: 13px; + letter-spacing: 0.06em; + text-transform: uppercase; + opacity: 0.65; +} + +.trust-list li::before { + content: "•"; + margin-right: 8px; +} + +.brand-footer { + font-size: 12px; + opacity: 0.5; +} + +.auth-side { + position: relative; + z-index: 1; + display: grid; + place-items: center; + padding: 36px; + background: var(--bg); +} + +.auth-shell { + width: 100%; + max-width: 360px; +} + +.auth-header h2 { + margin: 0 0 8px; + font-size: 32px; + font-family: var(--font-display); +} + +.auth-header p { + margin: 0 0 24px; + color: var(--muted); + font-size: 14px; +} + +.auth-tabs { + display: flex; + background: var(--subtle); + border-radius: 10px; + padding: 4px; + gap: 6px; + margin-bottom: 20px; +} + +.auth-tab { + border: none; + background: transparent; + color: var(--muted); + border-radius: 8px; + padding: 8px 12px; + font-weight: 600; + cursor: pointer; + flex: 1; +} + +.auth-tab.active { + background: var(--bg); + color: var(--fg); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12); +} + +.form-section { + display: grid; + gap: 10px; + animation: fadeIn 0.25s ease; +} + +.input-label { + font-size: 13px; + color: var(--muted); + font-weight: 600; +} + +.input-field { + width: 100%; + border: 1px solid var(--border); + border-radius: 10px; + padding: 12px 14px; + background: var(--bg); + color: var(--fg); +} + +.input-field:focus { + outline: none; + border-color: var(--fg); + box-shadow: 0 0 0 3px var(--subtle); +} + +.input-field.error { + border-color: var(--error); +} + +.form-row { + margin: 2px 0 6px; + width: 100%; + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + gap: 10px; +} + +.checkbox-wrapper { + display: flex; + align-items: center; + gap: 8px; + color: var(--muted); + font-size: 13px; + white-space: nowrap; +} + +.checkbox-wrapper input { + margin: 0; + flex: 0 0 auto; +} + +.checkbox-wrapper span { + white-space: nowrap; +} + +.checkbox-wrapper.terms { + margin-top: 6px; +} + +.checkbox-wrapper a, +.text-link { + color: var(--fg); +} + +.text-link { + border: none; + background: none; + font-size: 13px; + cursor: pointer; + white-space: nowrap; + justify-self: end; +} + +.btn-primary { + width: 100%; + border: none; + border-radius: 10px; + padding: 12px 14px; + background: var(--fg); + color: var(--bg); + font-family: var(--font-display); + font-size: 14px; + font-weight: 700; + cursor: pointer; +} + +.btn-primary:disabled { + opacity: 0.6; + cursor: default; +} + +.subtle-copy { + margin: 0 0 6px; + color: var(--muted); + font-size: 13px; +} + +.error-text, +.global-error { + margin: 0; + color: var(--error); + font-size: 13px; +} + +.back-btn { + border: none; + background: none; + color: var(--muted); + font-size: 13px; + cursor: pointer; + padding-top: 4px; +} + +.success-message { + text-align: center; + padding: 24px 8px 8px; +} + +.success-icon { + width: 48px; + height: 48px; + border-radius: 50%; + display: grid; + place-items: center; + background: var(--success); + color: #fff; + margin: 0 auto 14px; + font-size: 22px; +} + +.success-message h3 { + margin: 0 0 8px; +} + +.success-message p { + margin: 0; + color: var(--muted); +} + +.spinner { + display: inline-block; + width: 14px; + height: 14px; + border: 2px solid currentColor; + border-top-color: transparent; + border-radius: 50%; + margin-left: 8px; + animation: spin 0.6s linear infinite; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@media (max-width: 1024px) { + .split-layout { + grid-template-columns: 1fr; + } + + .brand-side { + display: none; + } + + .auth-side { + min-height: 100vh; + padding: 24px; + } +} diff --git a/src/app/components/login/login.html b/src/app/components/login/login.html index 4bb93e0..8911f46 100644 --- a/src/app/components/login/login.html +++ b/src/app/components/login/login.html @@ -1,16 +1,110 @@ -