chore: commit inicial - projeto LineGestão frontend

This commit is contained in:
Eduardo 2025-12-09 00:46:58 -03:00
commit 3798a669c7
47 changed files with 11196 additions and 0 deletions

17
.editorconfig Normal file
View File

@ -0,0 +1,17 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
ij_typescript_use_double_quotes = false
[*.md]
max_line_length = off
trim_trailing_whitespace = false

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
__screenshots__/
# System files
.DS_Store
Thumbs.db

4
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"]
}

20
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,20 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
},
{
"name": "ng test",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html"
}
]
}

42
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,42 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "start",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
},
{
"type": "npm",
"script": "test",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "(.*?)"
},
"endsPattern": {
"regexp": "bundle generation complete"
}
}
}
}
]
}

59
README.md Normal file
View File

@ -0,0 +1,59 @@
# LineGestaoFrontend
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.10.
## Development server
To start a local development server, run:
```bash
ng serve
```
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
## Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
```bash
ng generate component component-name
```
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
```bash
ng generate --help
```
## Building
To build the project run:
```bash
ng build
```
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
## Running unit tests
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
```bash
ng test
```
## Running end-to-end tests
For end-to-end (e2e) testing, run:
```bash
ng e2e
```
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
## Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

104
angular.json Normal file
View File

@ -0,0 +1,104 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"line-gestao-frontend": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"server": "src/main.server.ts",
"outputMode": "server",
"ssr": {
"entry": "src/server.ts"
}
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "line-gestao-frontend:build:production"
},
"development": {
"buildTarget": "line-gestao-frontend:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular/build:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.scss"
]
}
}
}
}
}
}

9822
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

56
package.json Normal file
View File

@ -0,0 +1,56 @@
{
"name": "line-gestao-frontend",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"serve:ssr:line-gestao-frontend": "node dist/line-gestao-frontend/server/server.mjs"
},
"prettier": {
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
},
"private": true,
"dependencies": {
"@angular/common": "^20.3.0",
"@angular/compiler": "^20.3.0",
"@angular/core": "^20.3.0",
"@angular/forms": "^20.3.0",
"@angular/platform-browser": "^20.3.0",
"@angular/platform-server": "^20.3.0",
"@angular/router": "^20.3.0",
"@angular/ssr": "^20.3.10",
"bootstrap": "^5.3.8",
"bootstrap-icons": "^1.13.1",
"express": "^5.1.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular/build": "^20.3.10",
"@angular/cli": "^20.3.10",
"@angular/compiler-cli": "^20.3.0",
"@types/express": "^5.0.1",
"@types/jasmine": "~5.1.0",
"@types/node": "^20.17.19",
"jasmine-core": "~5.9.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.9.2"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -0,0 +1,12 @@
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering, withRoutes } from '@angular/ssr';
import { appConfig } from './app.config';
import { serverRoutes } from './app.routes.server';
const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering(withRoutes(serverRoutes))
]
};
export const config = mergeApplicationConfig(appConfig, serverConfig);

13
src/app/app.config.ts Normal file
View File

@ -0,0 +1,13 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes), provideClientHydration(withEventReplay())
]
};

5
src/app/app.html Normal file
View File

@ -0,0 +1,5 @@
<app-header></app-header>
<router-outlet />
<app-footer></app-footer>

View File

@ -0,0 +1,8 @@
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: '**',
renderMode: RenderMode.Prerender
}
];

6
src/app/app.routes.ts Normal file
View File

@ -0,0 +1,6 @@
import { Routes } from '@angular/router';
import { Home } from './pages/home/home';
export const routes: Routes = [
{ path: '', component: Home },
];

0
src/app/app.scss Normal file
View File

23
src/app/app.spec.ts Normal file
View File

@ -0,0 +1,23 @@
import { TestBed } from '@angular/core/testing';
import { App } from './app';
describe('App', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [App],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it('should render title', () => {
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, line-gestao-frontend');
});
});

16
src/app/app.ts Normal file
View File

@ -0,0 +1,16 @@
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Header } from './components/header/header';
import { Footer } from './components/footer/footer';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, Header, Footer],
templateUrl: './app.html',
styleUrl: './app.scss'
})
export class App {
protected readonly title = signal('line-gestao-frontend');
}

View File

@ -0,0 +1,12 @@
<button
(click)="onClick()"
[style.width.px]="width"
[style.height.px]="height"
[style.background]="background"
[style.color]="color"
[style.font-size.px]="fontSize"
[style.font-weight]="fontWeight"
class="cta-button"
>
{{ label }}
</button>

View File

@ -0,0 +1,25 @@
.cta-button {
width: 360px;
height: 66px;
margin-top: 50px; /* Adiciona espaço entre os cards e o botão */
margin-bottom: 100px; /* Adiciona espaço após o botão */
background-color: rgba(201, 30, 181, 0.76);
color: #FFFFFF;
font-family: 'Poppins', sans-serif;
font-size: 18px;
font-weight: 700;
text-transform: uppercase;
cursor: pointer;
border: none;
border-radius: 4px;
transition: background-color 0.3s ease;
}
.cta-button:hover {
background-color: #C91EB5;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CtaButton } from './cta-button';
describe('CtaButton', () => {
let component: CtaButton;
let fixture: ComponentFixture<CtaButton>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CtaButton]
})
.compileComponents();
fixture = TestBed.createComponent(CtaButton);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
import { Component, EventEmitter, Output, Input } from '@angular/core';
@Component({
selector: 'app-cta-button',
templateUrl: './cta-button.html',
styleUrls: ['./cta-button.scss']
})
export class CtaButtonComponent {
@Input() label: string = 'COMEÇAR AGORA';
@Input() width: string = '250px';
@Input() height: string = '55px';
@Input() background: string = '#C91EB5';
@Input() color: string = '#FFFFFF';
@Input() fontSize: string = '18px';
@Input() fontWeight: string = '700';
@Output() clicked = new EventEmitter<void>();
onClick() {
this.clicked.emit();
}
}

View File

@ -0,0 +1,21 @@
<div class="feature-card-container">
<!-- Use [ngStyle] para aplicar o alinhamento a todo o bloco do card -->
<div class="feature-card"
(mouseenter)="isHovered = true"
(mouseleave)="isHovered = false"
[ngClass]="{'hover-state': isHovered}"
[ngStyle]="{'text-align': textAlign}"> <!-- 🎯 APLICA O ALINHAMENTO AQUI -->
<!-- Ícone e Título Principal (em rosa) -->
<h3 class="card-title">
<i class="card-icon {{ iconClass }}"></i>
{{ title }}
</h3>
<!-- Conteúdo/Descrição do Card -->
<p class="card-description">
<span [innerHTML]="description"></span>
</p>
</div>
</div>

View File

@ -0,0 +1,72 @@
.feature-card-container {
/* Garante que o container flexível do Bootstrap organize bem os cards */
padding: 10px;
}
/* Container principal do card */
.feature-card {
/* ... estilos anteriores ... */
border: 1px solid #000000;
background-color: #FFFFFF;
padding: 30px;
border-radius: 5px;
/* ❌ Remover: cursor: pointer; (ou definir como default) */
cursor: default;
/* 📐 DEFININDO TAMANHO FIXO DO FIGMA */
width: 365px; /* Largura EXATA solicitada */
height: 169px; /* Altura EXATA solicitada */
/* Permite que o texto quebre ou esconda se exceder o limite */
overflow: hidden;
/* Garante que o texto comece sempre do topo, mesmo com altura fixa */
display: flex;
flex-direction: column;
justify-content: flex-start;
transition: background-color 0.2s ease-in-out;
}
/* ... o restante do CSS se mantém ... */
/* Efeito de HOVER (Mouse passa por cima) */
.feature-card.hover-state {
background-color: #E1E1E1; /* Cor cinza #E1E1E1 ao passar o mouse */
}
/* --- TÍTULO DO CARD --- */
.card-title {
/* Propriedades do Figma: Inter, Bold, 21, #E33DCF */
font-family: 'Inter', sans-serif;
font-size: 20px;
font-weight: 700; /* Bold */
color: #E33DCF; /* Rosa */
margin-top: -15px;
margin-bottom: 10px;
display: flex; /* Para alinhar ícone e texto */
align-items: center;
justify-content: center
}
/* Estilização do Ícone */
.card-icon {
margin-right: 10px;
font-size: 24px; /* Tamanho ligeiramente maior que o texto */
}
/* --- DESCRIÇÃO/PARÁGRAFO DO CARD --- */
.card-description {
/* Propriedades do Figma: Inter, Mixed, 18, Preto */
font-family: 'Inter', sans-serif;
font-size: 17px;
color: #000000;
line-height: 1;
padding-left: 15px;
}
/* Garante que o começo da frase (em negrito) tenha o peso correto */
.card-description strong {
font-weight: 700; /* Bold */
}

View File

@ -0,0 +1,27 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
// A classe importada deve ser o nome real do componente exportado
import { FeatureCardComponent } from './feature-card';
describe('FeatureCardComponent', () => {
// A variável do componente deve usar o nome correto
let component: FeatureCardComponent;
let fixture: ComponentFixture<FeatureCardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
// Importe o componente pelo nome correto
imports: [FeatureCardComponent]
})
.compileComponents();
// Crie o componente pelo nome correto
fixture = TestBed.createComponent(FeatureCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,24 @@
import { Component, Input, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common'; // <-- Importe aqui!
@Component({
selector: 'app-feature-card',
standalone: true, // <-- DEVE ser standalone
imports: [CommonModule], // <-- PRECISA do CommonModule para usar [ngClass]
templateUrl: './feature-card.html',
styleUrls: ['./feature-card.scss']
})
export class FeatureCardComponent implements OnInit {
// ... o restante da lógica ...
@Input() title: string = '';
@Input() description: string = '';
@Input() iconClass: string = '';
@Input() textAlign: 'left' | 'center' = 'left';
isHovered: boolean = false;
constructor() { }
ngOnInit(): void { }
}

View File

@ -0,0 +1,42 @@
<footer class="footer-container">
<!-- COLUNA ESQUERDA (TEXTOS) -->
<div class="footer-left">
<p>© 2024 Copyright | Line Móvel - Todos os Direitos Reservados</p>
<p><strong>Razão Social:</strong> LINE MÓVEL - SERVIÇOS E VENDAS EM TELECOMUNICAÇÕES</p>
<p><strong>CNPJ:</strong> 45.470.843/0001-90</p>
<p>Av. Luís Viana Filho, Nº 7532 - Sala 1008</p>
</div>
<div class="footer-right">
<div class="social-wrapper">
<div class="social-section">
<span class="social-label">Siga-nos</span>
<a href="#" class="social-icon">
<i class="bi bi-instagram"></i>
</a>
<a href="#" class="social-icon">
<i class="bi bi-linkedin"></i>
</a>
</div>
</div>
<div class="footer-button-wrapper">
<app-cta-button
label="Política de Privacidade"
width="248.84"
height="46.84"
background="rgba(201, 30, 181, 0.76)"
color="#FFFFFF"
fontSize="13"
fontWeight="700">
</app-cta-button>
</div>
</div>
</footer>

View File

@ -0,0 +1,83 @@
/* ===================================== */
/* FOOTER CONTAINER */
/* ===================================== */
.footer-container {
width: 100%;
background: rgba(3, 15, 170, 0.93);
padding: 25px 60px;
display: flex;
justify-content: space-between;
align-items: flex-start;
font-family: "Inter", sans-serif;
color: #FFFFFF;
}
/* ===================================== */
/* LADO ESQUERDO */
/* ===================================== */
.footer-left {
margin-top: 100px; /* move bloco todo sem mexer no espaçamento entre linhas */
}
.footer-left p {
margin: 0 0 4px 270px;
font-size: 14px; /* levemente menor como no exemplo */
font-weight: 600;
}
/* ===================================== */
/* LADO DIREITO */
/* ===================================== */
.footer-right {
display: flex;
flex-direction: column;
align-items: center; /* << alinhado igual sua segunda imagem */
margin-top: 100px; /* << move bloco da direita para baixo */
gap: 0px;
margin-right: 300px; /* ajuste como quiser */
}
/* Redes sociais */
.social-wrapper {
width: 100%;
display: flex;
justify-content: flex-start; /* joga pra esquerda */
margin-bottom: 0px; /* distância entre redes e botão */
}
.social-section {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 0px; /* aproxima do botão */
}
.social-label {
font-size: 14px;
font-weight: 500;
}
/* ÍCONES — agora brancos */
.social-icon i {
font-size: 22px;
color: #FFF; /* << branquinho */
cursor: pointer;
transition: 0.2s;
}
.social-icon i:hover {
opacity: 0.7;
}
/* Botão */
.footer-button-wrapper {
margin-top: 0; /* tiramos o espaço que empurrava demais */
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Footer } from './footer';
describe('Footer', () => {
let component: Footer;
let fixture: ComponentFixture<Footer>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Footer]
})
.compileComponents();
fixture = TestBed.createComponent(Footer);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,12 @@
import { Component } from '@angular/core';
import { CtaButtonComponent } from '../cta-button/cta-button';
@Component({
selector: 'app-footer',
imports: [CtaButtonComponent],
templateUrl: './footer.html',
styleUrl: './footer.scss',
})
export class Footer {
}

View File

@ -0,0 +1,35 @@
<header class="header-container">
<div class="header-top">
<!-- LOGO -->
<div class="logo-area">
<img src="logo.jpg" alt="Logo" class="logo">
<div class="logo-text ms-2">
<span class="line">Line</span><span class="gestao">Gestão</span>
</div>
</div>
<!-- MENU -->
<nav class="menu">
<a href="https://www.linemovel.com.br/sobrenos" class="menu-item" target="_blank">O que é a Line Móvel?</a>
<a href="https://www.linemovel.com.br/empresas" class="menu-item" target="_blank">Para sua empresa</a>
<a href="https://www.linemovel.com.br/proposta" class="menu-item" target="_blank">Solicite sua Proposta</a>
<a href="https://www.linemovel.com.br/indique" class="menu-item" target="_blank">Indique um amigo</a>
</nav>
<!-- BOTÕES -->
<div class="btn-area">
<button class="btn btn-cadastrar">Cadastre-se</button>
<button class="btn btn-login">Login</button>
</div>
</div>
<!-- FAIXA AZUL -->
<div class="header-bar">
<span class="header-bar-text">Somos a escolha certa para estar sempre conectado!</span>
</div>
</header>

View File

@ -0,0 +1,141 @@
/* ===================== */
/* HEADER PRINCIPAL */
/* ===================== */
.header-container {
width: 100%;
background: #ffffff;
font-family: 'Inter', sans-serif;
display: flex;
flex-direction: column; /* permite faixa azul abaixo */
}
/* Área do conteúdo superior do header */
.header-top {
width: 100%;
height: 72px;
padding: 0 32px;
display: flex;
align-items: center;
justify-content: flex-start;
gap: 40px;
}
/* ===================== */
/* LOGO */
/* ===================== */
.logo {
width: 44px;
height: 44px;
}
.logo-area {
margin-left: 50px;
display: flex;
align-items: center;
}
.logo-text .line {
color: #030FAA;
font-weight: 600;
font-size: 32px;
}
.logo-text .gestao {
color: #000000;
font-weight: 600;
font-size: 32px;
}
/* ===================== */
/* MENU */
/* ===================== */
.menu {
gap: 32px;
display: flex;
align-items: center;
margin-left: 150px; /* <-- aumentei para afastar do logo */
}
.menu-item {
font-size: 18px;
font-weight: 600;
color: #000 !important;
text-decoration: none !important;
}
.menu-item:hover {
color: #030FAA !important;
}
/* ===================== */
/* BOTÕES */
/* ===================== */
.btn-area {
display: flex;
align-items: center;
gap: 12px;
margin-left: 32px;
}
/* --- Botão Cadastre-se --- */
.btn-cadastrar {
width: 164px;
height: 41px;
background: #E1E1E1;
border-radius: 8px;
border: none !important;
color: #000;
font-size: 16px;
font-weight: 400;
transition: opacity 0.2s ease-in-out;
}
.btn-cadastrar:hover,
.btn-cadastrar:active,
.btn-cadastrar:focus {
background: #E1E1E1 !important;
opacity: 0.85;
box-shadow: none !important;
}
/* --- Botão Login --- */
/* Agora com a cor original **sem perder saturação** */
.btn-login {
width: 164px;
height: 41px;
background: #E33DCF; /* cor original sólida */
border-radius: 8px;
border: none !important;
color: #fff;
font-size: 16px;
font-weight: 400;
transition: opacity 0.2s ease-in-out;
}
.btn-login:hover,
.btn-login:active,
.btn-login:focus {
background: #E33DCF !important; /* mantém a mesma cor */
opacity: 0.85; /* apenas leve escurecida */
box-shadow: none !important;
}
/* ===================== */
/* FAIXA AZUL INFERIOR */
/* ===================== */
.header-bar {
width: 100%;
height: 38.41px;
background: rgba(3, 15, 170, 0.93); /* #030FAA 93% */
display: flex;
align-items: center;
justify-content: center;
}
.header-bar-text {
color: #ffffff;
font-size: 16px;
font-weight: 700;
font-family: 'Inter', sans-serif;
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Header } from './header';
describe('Header', () => {
let component: Header;
let fixture: ComponentFixture<Header>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Header]
})
.compileComponents();
fixture = TestBed.createComponent(Header);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-header',
imports: [],
templateUrl: './header.html',
styleUrl: './header.scss',
})
export class Header {
}

View File

@ -0,0 +1,58 @@
<section class="hero-text-section">
<h1 class="main-title">
<span class="first-line">Gerencie suas linhas móveis</span>
<span class="second-line">com <strong>inteligência e praticidade</strong></span>
</h1>
<p class="main-paragraph">
<strong class="brand-name">LineGestão</strong> é a solução completa para empresas que
<strong class="highlight">desejam controlar suas linhas móveis com eficiência e segurança</strong>.
Com recursos como <strong class="highlight">gerenciamento de clientes</strong>,
<strong class="highlight">importação de dados via Excel</strong> e
<strong class="highlight">monitoramento estratégico de contratos e linhas</strong>,
você <strong class="highlight">simplifica processos</strong>,
<strong class="highlight">reduz erros</strong> e
<strong class="highlight">ganha mais controle sobre seus recursos corporativos</strong>.
</p>
</section>
<div class="container my-5">
<div class="row justify-content-center feature-cards-row">
<div class="col-auto mb-4">
<app-feature-card
title="Monitoramento Completo"
[textAlign]="'center'"
iconClass="bi bi-laptop"
description="<strong>Acompanhe contratos, valores e suas linhas</strong> com visão estratégica, garantindo controle total sobre seus recursos móveis."
></app-feature-card>
</div>
<div class="col-auto mb-4">
<app-feature-card
title="Gerenciamento de Clientes"
[textAlign]="'center'"
iconClass="bi bi-people"
description="<strong>Organize e acompanhe seus clientes</strong> com praticidade e segurança, garantindo uma gestão eficiente."
></app-feature-card>
</div>
<div class="col-auto mb-4">
<app-feature-card
title="Importação via Excel"
[textAlign]="'center'"
iconClass="bi bi-table"
description="<strong>Integre dados rapidamente</strong> sem esforço manual, substituindo planilhas por uma solução moderna e automatizada."
></app-feature-card>
</div>
</div>
<div class="row justify-content-center button-section">
<div class="col-auto">
<app-cta-button label="COMEÇAR AGORA" (clicked)="iniciar()"></app-cta-button>
</div>
</div>
</div>

View File

@ -0,0 +1,62 @@
/* Container principal da seção de texto (sem limite de largura para acomodar o parágrafo de 985px) */
.hero-text-section {
text-align: center; /* Mantém o título e o parágrafo centralizados */
padding-top: 50px;
margin: 0 auto;
}
/* --- TÍTULO PRINCIPAL (AJUSTADO PARA DESALINHAMENTO) --- */
.main-title {
font-family: 'Inter', sans-serif;
font-size: 48px;
line-height: 1.2;
margin-bottom: 30px;
/* Importante: para mover o texto, o display precisa ser block/inline-block */
display: flex; /* Permite que os spans se alinhem e sejam manipulados */
flex-direction: column; /* Coloca os spans um abaixo do outro */
align-items: center; /* Centraliza visualmente o bloco de texto */
width: fit-content; /* Ajusta a largura do h1 ao conteúdo interno */
margin: 0 auto 80px auto; /* Centraliza o h1 na página */
}
.main-title .first-line {
color: #E33DCF;
font-weight: 500;
display: block; /* Garante que a transformação funcione */
/* 👈 Movimenta a primeira linha para a esquerda (ajuste o valor se necessário) */
transform: translateX(-70px);
}
.main-title .second-line {
color: #E33DCF;
font-weight: 500;
display: block; /* Garante que a transformação funcione */
/* 👉 Movimenta a segunda linha para a direita (ajuste o valor se necessário) */
transform: translateX(100px) translateY(-6px);
}
/* --- PARÁGRAFO CENTRAL (AJUSTADO PARA 985x132) --- */
.main-paragraph {
/* Propriedades de Layout ajustadas para proporção 985 x 132 */
width: 985px; /* Define a largura EXATA solicitada */
height: 132px; /* Define a altura EXATA solicitada */
margin: 0 auto 50px auto; /* Centraliza o bloco do parágrafo horizontalmente */
/* Propriedades de Texto (Do Figma: Poppins, Mixed, 24, #000000) */
font-family: 'Poppins', sans-serif;
font-size: 24px;
color: #000000;
line-height: 1;
font-weight: 400;
text-align: center;
}
/* --- DESTAQUES NO PARÁGRAFO --- */
.main-paragraph strong {
font-weight: 700; /* Todas as tags <strong> serão Bold */
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Home } from './home';
describe('Home', () => {
let component: Home;
let fixture: ComponentFixture<Home>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Home]
})
.compileComponents();
fixture = TestBed.createComponent(Home);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,34 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common'; // Importa CommonModule
import { FeatureCardComponent } from '../../components/feature-card/feature-card';
import { CtaButtonComponent } from '../../components/cta-button/cta-button';
@Component({
selector: 'app-home',
// 1. Marca o componente como autônomo
standalone: true,
// 2. Importa o que o template precisa:
imports: [
CommonModule, // Para usar diretivas comuns (ngClass, ngIf, etc.) no seu home.html
FeatureCardComponent, // Para usar o seletor <app-feature-card> no seu home.html
CtaButtonComponent
],
templateUrl: './home.html',
styleUrl: './home.scss',
})
export class Home {
// Seus dados dos cards podem ser definidos aqui para uso no home.html:
/*
cardsData = [
{ title: 'Monitoramento Completo', iconClass: 'bi bi-laptop', description: '...' },
// ...
];
*/
iniciar(): void {
console.log('Botão COMEÇAR AGORA clicado! Redirecionando ou abrindo modal...');
// Aqui você adicionaria sua lógica de navegação, como:
// this.router.navigate(['/cadastro']);
// Ou uma chamada para abrir um modal de registro.
}
}

17
src/index.html Normal file
View File

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>LineGestaoFrontend</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@400;700&display=swap" rel="stylesheet">
<!-- Dentro de index.html, na seção <head> -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<body>
<app-root></app-root>
</body>
</html>

8
src/main.server.ts Normal file
View File

@ -0,0 +1,8 @@
import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
import { config } from './app/app.config.server';
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(App, config, context);
export default bootstrap;

7
src/main.ts Normal file
View File

@ -0,0 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));

68
src/server.ts Normal file
View File

@ -0,0 +1,68 @@
import {
AngularNodeAppEngine,
createNodeRequestHandler,
isMainModule,
writeResponseToNodeResponse,
} from '@angular/ssr/node';
import express from 'express';
import { join } from 'node:path';
const browserDistFolder = join(import.meta.dirname, '../browser');
const app = express();
const angularApp = new AngularNodeAppEngine();
/**
* Example Express Rest API endpoints can be defined here.
* Uncomment and define endpoints as necessary.
*
* Example:
* ```ts
* app.get('/api/{*splat}', (req, res) => {
* // Handle API request
* });
* ```
*/
/**
* Serve static files from /browser
*/
app.use(
express.static(browserDistFolder, {
maxAge: '1y',
index: false,
redirect: false,
}),
);
/**
* Handle all other requests by rendering the Angular application.
*/
app.use((req, res, next) => {
angularApp
.handle(req)
.then((response) =>
response ? writeResponseToNodeResponse(response, res) : next(),
)
.catch(next);
});
/**
* Start the server if this module is the main entry point, or it is ran via PM2.
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
*/
if (isMainModule(import.meta.url) || process.env['pm_id']) {
const port = process.env['PORT'] || 4000;
app.listen(port, (error) => {
if (error) {
throw error;
}
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
/**
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.
*/
export const reqHandler = createNodeRequestHandler(app);

5
src/styles.scss Normal file
View File

@ -0,0 +1,5 @@
@import "bootstrap-icons/font/bootstrap-icons.css";
body {
background: #EFEFEF !important;
}

17
tsconfig.app.json Normal file
View File

@ -0,0 +1,17 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": [
"node"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"src/**/*.spec.ts"
]
}

34
tsconfig.json Normal file
View File

@ -0,0 +1,34 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"compileOnSave": false,
"compilerOptions": {
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"isolatedModules": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "ES2022",
"module": "preserve"
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"typeCheckHostBindings": true,
"strictTemplates": true
},
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

15
tsconfig.spec.json Normal file
View File

@ -0,0 +1,15 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
]
},
"include": [
"src/**/*.d.ts",
"src/**/*.spec.ts"
]
}