home page

This commit is contained in:
Betteloni 2024-10-23 18:48:28 -03:00
parent dd1b2763d8
commit 5608fa4184
18 changed files with 546 additions and 103 deletions

View file

@ -37,7 +37,8 @@
"node_modules/nebular-icons/scss/nebular-icons.scss", "node_modules/nebular-icons/scss/nebular-icons.scss",
"node_modules/pace-js/templates/pace-theme-flash.tmpl.css", "node_modules/pace-js/templates/pace-theme-flash.tmpl.css",
"node_modules/leaflet/dist/leaflet.css", "node_modules/leaflet/dist/leaflet.css",
"src/app/@theme/styles/styles.scss" "src/app/@theme/styles/styles.scss",
"node_modules/mdb-angular-ui-kit/assets/scss/mdb.scss"
], ],
"scripts": [ "scripts": [
"node_modules/pace-js/pace.min.js", "node_modules/pace-js/pace.min.js",

19
package-lock.json generated
View file

@ -40,6 +40,7 @@
"intl": "1.2.5", "intl": "1.2.5",
"ionicons": "2.0.1", "ionicons": "2.0.1",
"leaflet": "1.2.0", "leaflet": "1.2.0",
"mdb-angular-ui-kit": "^4.1.0",
"nebular-icons": "1.1.0", "nebular-icons": "1.1.0",
"ng2-ckeditor": "~1.2.9", "ng2-ckeditor": "~1.2.9",
"ng2-completer": "^9.0.1", "ng2-completer": "^9.0.1",
@ -1349,6 +1350,7 @@
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.10.tgz", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.2.10.tgz",
"integrity": "sha512-/TSnm/ZQML6A4lvunyN2tjTB5utuvk3d1Pnfyehp/FXtV6YfZm6+EZrOpKkKPCxTuAgW6c9KK4yQtt3RuNVpwQ==", "integrity": "sha512-/TSnm/ZQML6A4lvunyN2tjTB5utuvk3d1Pnfyehp/FXtV6YfZm6+EZrOpKkKPCxTuAgW6c9KK4yQtt3RuNVpwQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@angular-devkit/architect": "0.1502.10", "@angular-devkit/architect": "0.1502.10",
"@angular-devkit/core": "15.2.10", "@angular-devkit/core": "15.2.10",
@ -5949,6 +5951,7 @@
"integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -18654,6 +18657,22 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/mdb-angular-ui-kit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/mdb-angular-ui-kit/-/mdb-angular-ui-kit-4.1.0.tgz",
"integrity": "sha512-9W6JZDsizTq8aVIDucIQpPqdiw0p3ILYf25lH76u/9UfjNf5M1LchMfDc1PiL3FSEpU+OImZ0LbAMLzhGvZn9g==",
"license": "MIT",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/animations": "^15.0.0",
"@angular/cdk": "^15.0.0",
"@angular/common": "^15.0.0",
"@angular/core": "^15.0.0",
"@angular/forms": "^15.0.0"
}
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",

View file

@ -60,6 +60,7 @@
"intl": "1.2.5", "intl": "1.2.5",
"ionicons": "2.0.1", "ionicons": "2.0.1",
"leaflet": "1.2.0", "leaflet": "1.2.0",
"mdb-angular-ui-kit": "^4.1.0",
"nebular-icons": "1.1.0", "nebular-icons": "1.1.0",
"ng2-ckeditor": "~1.2.9", "ng2-ckeditor": "~1.2.9",
"ng2-completer": "^9.0.1", "ng2-completer": "^9.0.1",

View file

@ -1,36 +1,14 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { delay, map } from 'rxjs/operators';
import { Apollo } from 'apollo-angular'; import { Apollo } from 'apollo-angular';
import { FIND_UNIQUE_BANNER, LIST_BANNERS } from './graphql/queries'; import { FIND_UNIQUE_BANNER, LIST_BANNERS } from './graphql/queries';
import { Banner } from './banner.model'; import { Banner } from './banner.model';
import { CREATE_BANNER, UPDATE_BANNER } from './graphql/mutations'; import { CREATE_BANNER, UPDATE_BANNER } from './graphql/mutations';
const TOTAL_PAGES = 7;
export class NewsPost {
title: string;
link: string;
creator: string;
text: string;
}
@Injectable() @Injectable()
export class BannerService { export class BannerService {
constructor(private http: HttpClient, private readonly apollo: Apollo) {} constructor(private readonly apollo: Apollo) {}
load(page: number, pageSize: number): Observable<NewsPost[]> {
const startIndex = ((page - 1) % TOTAL_PAGES) * pageSize;
return this.http
.get<NewsPost[]>('assets/data/news.json')
.pipe(
map(news => news.splice(startIndex, pageSize)),
delay(1500),
);
}
listBanners(): Observable<any> { listBanners(): Observable<any> {
return this.apollo return this.apollo

View file

@ -5,6 +5,7 @@ export class Category {
name!: string; name!: string;
createdAt!: Date; createdAt!: Date;
updatedAt!: Date | null; updatedAt!: Date | null;
icon?: string | null;
//Products?: Array<Product>; //Products?: Array<Product>;
SubCategory?: Array<any>; //TODO: SubCategory?: Array<any>; //TODO:
_count?: CategoryCount; _count?: CategoryCount;

View file

@ -0,0 +1,37 @@
export class Product {
id!: string;
userId!: string;
categoryId!: string;
sub_categoryId!: string;
brandId!: string;
name!: string;
description!: string;
conditionId!: string;
price!: number;
countryId!: string | null;
stateId!: string | null;
cityId!: string | null;
neighbourhoodId!: string | null;
zip_code!: string | null;
createdAt!: Date;
approvedAt!: Date | null;
updatedAt!: Date | null;
isActive!: boolean;
isPromoted!: boolean;
viewCount!: number | null;
//user?: User;
//category?: Category;
//sub_category?: SubCategory;
//brand?: Brand;
//condition?: Condition;
//country?: Country | null;
//state?: State | null;
//city?: City | null;
//neighbourhood?: Neighbourhood | null;
//favorites?: Array<Favorite>;
//comments?: Array<Comment>;
//img_urls?: Array<ProductImg>;
//report?: Report | null;
//shares?: Array<Share>;
//_count?: ProductCount;
}

View file

@ -0,0 +1,23 @@
<mdb-carousel [indicators]="true" [animation]="'fade'">
<mdb-carousel-item>
<img
src="https://assets-portal-cms.olx.com.br/1576x300_38126a593d.webp"
class="d-block w-100"
alt="..."
/>
</mdb-carousel-item>
<mdb-carousel-item>
<img
src="https://assets-portal-cms.olx.com.br/1576x300_267d64821e.webp"
class="d-block w-100"
alt="..."
/>
</mdb-carousel-item>
<mdb-carousel-item>
<img
src="https://assets-portal-cms.olx.com.br/1576x300_cc8d61d4ca.webp"
class="d-block w-100"
alt="..."
/>
</mdb-carousel-item>
</mdb-carousel>

View file

@ -0,0 +1,20 @@
@import '../../../@theme/styles/themes';
@import 'bootstrap/scss/mixins/breakpoints';
@import '@nebular/theme/styles/global/breakpoints';
@include nb-install-component() {
.solar-card nb-card-header {
border: none;
padding-bottom: 0;
}
@include media-breakpoint-down(sm) {
ngx-traffic {
display: none;
}
}
}
mdb-carousel-item {
height: 320px;
}

View file

@ -0,0 +1,30 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import { Subject } from 'rxjs';
import { Banner } from '../../../admin/banner/banner.model';
interface CardSettings {
title: string;
iconClass: string;
type: string;
}
@Component({
selector: 'ngx-home-banner',
styleUrls: ['./banner.component.scss'],
templateUrl: './banner.component.html',
})
export class BannerHomeComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
banners: Banner[];
constructor() {}
ngOnInit(): void {
console.log('init');
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

View file

@ -1,3 +1,35 @@
<div class="row"> <div class="row">
Home <div class="col-12">
<ngx-home-banner></ngx-home-banner>
</div>
<div class="col-12">
<div class="category">
<a href="" *ngFor="let category of categories">
<div class="text-container">
<nb-icon [icon]="category.icon" pack="eva"></nb-icon>
<span class="title">{{category.name}}</span>
<i class="line"></i>
</div>
</a>
</div>
<div class="col-12 ad-row">
<div class="ad-container">
<div class="ad"><p>Publicidade</p></div>
</div>
</div>
<div class="col-12">
<div class="d-flex flex-col">
<h2>Anúncios patrocinados</h2>
</div>
<div class="d-flex flex-row flex-nowrap overflow-auto">
<div *ngFor="let product of products" class="card-col">
<ngx-home-product></ngx-home-product>
</div>
</div>
</div>
</div> </div>

View file

@ -1,6 +1,6 @@
@import '../../@theme/styles/themes'; @import "../../@theme/styles/themes";
@import 'bootstrap/scss/mixins/breakpoints'; @import "bootstrap/scss/mixins/breakpoints";
@import '@nebular/theme/styles/global/breakpoints'; @import "@nebular/theme/styles/global/breakpoints";
@include nb-install-component() { @include nb-install-component() {
.solar-card nb-card-header { .solar-card nb-card-header {
@ -14,3 +14,145 @@
} }
} }
} }
mdb-carousel-item {
height: 320px;
}
.row .col-12 {
margin-bottom: 20px;
}
@media (min-width: 1280px) {
.category
[_nghost-pwx-c109]
.settings-column[_ngcontent-pwx-c109]
ngd-page-tabs[_ngcontent-pwx-c109] {
margin-bottom: 1.5rem;
}
}
.category {
display: flex;
flex-wrap: wrap;
overflow: hidden;
max-width: 100%;
-webkit-flex-wrap: wrap;
height: 130px;
}
.category a {
display: flex;
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 1rem;
min-width: 120px;
height: 7.5rem;
font-size: 0.875rem;
text-decoration: none;
color: #8994a3;
margin-bottom: 1rem;
background: white;
color: #000000e0;
box-shadow: 0 8px 20px #dae0eb99;
margin-left: 10px;
margin-right: 10px;
}
.category a {
color: #36f;
text-decoration: none;
font-size: inherit;
font-style: inherit;
font-weight: inherit;
line-height: inherit;
}
.category a .text-container {
display: flex;
flex-direction: column;
align-items: center;
}
.category a nb-icon {
font-size: 1.875rem;
margin-bottom: 1rem;
}
.category nb-icon {
font-size: 1.25rem;
line-height: 1;
width: 1em;
height: 1em;
display: inline-block;
}
.category a .title {
padding-bottom: 0.75rem;
font-weight: 500;
text-align: center;
}
.category a .line {
display: none;
height: 0.1875rem;
width: 60%;
background: #3366ff;
border-radius: 1.5px;
}
.category a:hover .line {
display: block;
}
.ad-row {
display: flex;
justify-content: center;
}
.ad-container {
display: flex;
justify-content: center;
width: 970px;
height: 90px;
margin: 24px 12px;
border: 1px gray;
}
.ad {
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
background-color: #e1e1e1;
}
.ad p {
position: absolute;
width: 100px;
text-align: center;
}
.card-col {
flex: 1 0 calc(16.66% - 1rem);
margin: 0 0.5rem;
}
@media screen and (min-width: 1500px) {
.card-col {
flex: 0 0 calc(16.66% - 1rem);
}
}
@media screen and (min-width: 1200px) {
.card-col {
flex: 0 0 calc(20% - 1rem);
}
}
@media screen and (min-width: 840px) {
.card-col {
flex: 0 0 calc(16.66% - 1rem);
}
}

View file

@ -2,6 +2,10 @@ import {Component, OnDestroy} from '@angular/core';
import { NbThemeService } from '@nebular/theme'; import { NbThemeService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators' ; import { takeWhile } from 'rxjs/operators' ;
import { SolarData } from '../../@core/data/solar'; import { SolarData } from '../../@core/data/solar';
import { Banner } from '../../admin/banner/banner.model';
import { Subject } from 'rxjs';
import { Category } from '../../admin/category/category.model';
import { Product } from '../../admin/product/product';
interface CardSettings { interface CardSettings {
title: string; title: string;
@ -15,85 +19,108 @@ interface CardSettings {
templateUrl: './home.component.html', templateUrl: './home.component.html',
}) })
export class HomeComponent implements OnDestroy { export class HomeComponent implements OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
banners: Banner[];
categories: Category[];
products: any[];
private alive = true; constructor() {}
solarValue: number; ngOnInit(): void {
lightCard: CardSettings = { console.log('init');
title: 'Light',
iconClass: 'nb-lightbulb',
type: 'primary',
};
rollerShadesCard: CardSettings = {
title: 'Roller Shades',
iconClass: 'nb-roller-shades',
type: 'success',
};
wirelessAudioCard: CardSettings = {
title: 'Wireless Audio',
iconClass: 'nb-audio',
type: 'info',
};
coffeeMakerCard: CardSettings = {
title: 'Coffee Maker',
iconClass: 'nb-coffee-maker',
type: 'warning',
};
statusCards: string; this.categories = [
commonStatusCardsSet: CardSettings[] = [
this.lightCard,
this.rollerShadesCard,
this.wirelessAudioCard,
this.coffeeMakerCard,
];
statusCardsByThemes: {
default: CardSettings[];
cosmic: CardSettings[];
corporate: CardSettings[];
dark: CardSettings[];
} = {
default: this.commonStatusCardsSet,
cosmic: this.commonStatusCardsSet,
corporate: [
{ {
...this.lightCard, "name": "Nutrientes",
type: 'warning', "id": "Nutrientes",
}, "updatedAt": new Date(),
{ "createdAt": new Date(),
...this.rollerShadesCard, "icon": "arrow-ios-back-outline"
type: 'primary', },
}, {
{ "name": "Iluminação",
...this.wirelessAudioCard, "id": "Decoração",
type: 'danger', "updatedAt": new Date(),
}, "createdAt": new Date(),
{ "icon": "bulb-outline"
...this.coffeeMakerCard, },
type: 'info', {
}, "name": "Hidroponia",
], "id": "Hidroponia",
dark: this.commonStatusCardsSet, "updatedAt": new Date(),
}; "createdAt": new Date(),
"icon": "droplet-outline"
},
{
"name": "Irrigação",
"id": "Irrigação",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Colheita",
"id": "Colheita",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Pragas",
"id": "Pragas",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Potes e Vasos",
"id": "Potes e Vasos",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Substratos",
"id": "Substratos",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Controle",
"id": "Controle",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Clonagem",
"id": "Clonagem",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "copy-outline"
},
{
"name": "Tendas",
"id": "Tendas",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
{
"name": "Circulação",
"id": "Circulação",
"updatedAt": new Date(),
"createdAt": new Date(),
"icon": "arrow-ios-back-outline"
},
]
constructor(private themeService: NbThemeService, this.products = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
private solarService: SolarData) {
this.themeService.getJsTheme()
.pipe(takeWhile(() => this.alive))
.subscribe(theme => {
this.statusCards = this.statusCardsByThemes[theme.name];
});
this.solarService.getSolarData()
.pipe(takeWhile(() => this.alive))
.subscribe((data) => {
this.solarValue = data;
});
} }
ngOnDestroy() { ngOnDestroy() {
this.alive = false; this.destroy$.next();
this.destroy$.complete();
} }
} }

View file

@ -1,4 +1,4 @@
import { NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { import {
NbActionsModule, NbActionsModule,
NbButtonModule, NbButtonModule,
@ -15,6 +15,9 @@ import { NgxEchartsModule } from 'ngx-echarts';
import { ThemeModule } from '../../@theme/theme.module'; import { ThemeModule } from '../../@theme/theme.module';
import { HomeComponent } from './home.component'; import { HomeComponent } from './home.component';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { MdbCarouselModule } from 'mdb-angular-ui-kit/carousel';
import { BannerHomeComponent } from './banner/banner.component';
import { ProductHomeComponent } from './product/product.component';
@NgModule({ @NgModule({
imports: [ imports: [
@ -31,9 +34,13 @@ import { FormsModule } from '@angular/forms';
NbIconModule, NbIconModule,
NbButtonModule, NbButtonModule,
NgxEchartsModule, NgxEchartsModule,
MdbCarouselModule
], ],
declarations: [ declarations: [
HomeComponent HomeComponent,
BannerHomeComponent,
ProductHomeComponent
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}) })
export class HomeModule { } export class HomeModule { }

View file

@ -0,0 +1,23 @@
<nb-card>
<nb-card-header class="card-img-top">
<ul>
<li>
<img src="https://img.olx.com.br/images/89/890461810585731.webp" />
</li>
</ul>
<span class="badge">Destaque</span>
</nb-card-header>
<nb-card-body>
<h5 class="card-title">Bioledz 38400 - 800 watts</h5>
<p class="card-text">R$ 3.475,99</p>
</nb-card-body>
<ul class="list-group list-group-flush">
<li class="list-group-item">An item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
</ul>
<nb-card-footer>
<a href="#" class="card-link">Ver</a>
</nb-card-footer>
</nb-card>

View file

@ -0,0 +1,75 @@
@import '../../../@theme/styles/themes';
@import 'bootstrap/scss/mixins/breakpoints';
@import '@nebular/theme/styles/global/breakpoints';
.card-img-top {
font-size: 1.125rem;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
text-anchor: middle;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
overflow: hidden;
border-bottom: 0;
height: 180px;
padding: 0;
position: relative;
}
.card-img-top ul {
align-items: center;
display: flex;
height: 100%;
justify-content: flex-start;
margin: 0;
overflow: scroll hidden;
padding: 0;
scroll-snap-type: x mandatory;
scrollbar-width: none;
pointer-events: auto;
}
.card-img-top ul li {
align-items: center;
display: flex;
height: 100%;
justify-content: center;
list-style: none;
margin: 0;
min-width: 100%;
overflow: hidden;
padding: 0;
position: relative;
scroll-snap-align: start;
scroll-snap-stop: always;
}
.card-img-top ul li img, .card-img-top ul li svg {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
overflow-clip-margin: content-box;
overflow: clip;
}
.card-img-top span.badge {
align-items: center;
background: blue;
color:white;
font-weight: 600;
overflow: hidden;
white-space: nowrap;
border-radius: 4px;
font-size: 12px;
height: 24px;
left: 16px;
top: 16px;
max-width: calc(100% - 16px);
position: absolute;
z-index: 8;
display: block;
text-overflow: ellipsis;
padding: 4px 8px;
}

View file

@ -0,0 +1,24 @@
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import { Subject } from 'rxjs';
import { Product } from '../../../admin/product/product';
@Component({
selector: 'ngx-home-product',
styleUrls: ['./product.component.scss'],
templateUrl: './product.component.html',
})
export class ProductHomeComponent implements OnInit, OnDestroy {
private destroy$: Subject<void> = new Subject<void>();
@Input() product: Product;
constructor() {}
ngOnInit(): void {
console.log('init');
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

View file

@ -5,12 +5,14 @@ import { ThemeModule } from '../@theme/theme.module';
import { PublicComponent } from './public.component'; import { PublicComponent } from './public.component';
import { PublicRoutingModule } from './public-routing.module'; import { PublicRoutingModule } from './public-routing.module';
import { MiscellaneousModule } from './miscellaneous/miscellaneous.module'; import { MiscellaneousModule } from './miscellaneous/miscellaneous.module';
import { HomeModule } from './home/home.module';
@NgModule({ @NgModule({
imports: [ imports: [
PublicRoutingModule, PublicRoutingModule,
ThemeModule, ThemeModule,
NbMenuModule, NbMenuModule,
MiscellaneousModule MiscellaneousModule,
HomeModule
], ],
declarations: [ declarations: [
PublicComponent, PublicComponent,

View file

@ -9,6 +9,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png"> <link rel="icon" type="image/png" href="favicon.png">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<script defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCpVhQiwAllg1RAFaxMWSpQruuGARy0Y1k&libraries=places"></script> <script defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCpVhQiwAllg1RAFaxMWSpQruuGARy0Y1k&libraries=places"></script>
</head> </head>
<body> <body>