diff --git a/angular.json b/angular.json index 5ab386a..2452635 100644 --- a/angular.json +++ b/angular.json @@ -26,13 +26,14 @@ ], "styles": [ "src/styles.css", - "node_modules/bootstrap/dist/css/bootstrap.min.css", - "node_modules/normalize.css/normalize.css", - "node_modules/cookieconsent/build/cookieconsent.min.css" + "node_modules/bootstrap/dist/css/bootstrap.css", + "node_modules/cookieconsent/build/cookieconsent.min.css", + "node_modules/@glidejs/glide/dist/css/glide.core.css", + "node_modules/@glidejs/glide/dist/css/glide.theme.css" ], "scripts": [ "node_modules/jquery/dist/jquery.min.js", - "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js", + "node_modules/bootstrap/dist/js/bootstrap.bundle.js", "node_modules/cookieconsent/build/cookieconsent.min.js" ], "serviceWorker": true, diff --git a/package-lock.json b/package-lock.json index f8569a3..c9e31e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@fortawesome/free-brands-svg-icons": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1", + "@glidejs/glide": "^3.6.0", "bootstrap": "^4.6.2", "cookieconsent": "^3.1.1", "cors": "^2.8.5", @@ -32,6 +33,7 @@ "jquery": "^3.6.0", "ngx-cookie-service": "^16.0.1", "ngx-cookieconsent": "^4.0.2", + "ngx-glide": "^16.0.0", "normalize.css": "^8.0.1", "rxjs": "~7.5.0", "ts-interface-checker": "^1.0.2", @@ -778,12 +780,12 @@ "dev": true }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "engines": { @@ -977,22 +979,36 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name/node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -1154,9 +1170,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1200,12 +1216,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -1214,9 +1230,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz", - "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -2491,19 +2507,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", - "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.11", - "@babel/types": "^7.22.11", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2512,12 +2528,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -2527,13 +2543,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", - "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3102,6 +3118,11 @@ "node": ">=6" } }, + "node_modules/@glidejs/glide": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@glidejs/glide/-/glide-3.6.0.tgz", + "integrity": "sha512-47Aa+JmYjY4xTFpTtYCwrqirmI1arnp1UZETwtWpbTPisXUAuxrdJxKJLH8KHFWMsSrLi9+AcfyfzDIuO75rEA==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -12068,6 +12089,19 @@ "rxjs": "^7.5.0" } }, + "node_modules/ngx-glide": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/ngx-glide/-/ngx-glide-16.0.0.tgz", + "integrity": "sha512-MVPTfYI+dSA1d/GmC6DVkAD5D3VWWLMzcZNAwrvRbMcj4+h4fWoxXlVNu2yLwFF+Nz0O2YhOFpvi6zlD8xg88Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=16.x", + "@angular/core": ">=16.x", + "@glidejs/glide": "3.x" + } + }, "node_modules/nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", diff --git a/package.json b/package.json index 136ca43..0b5c8bd 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@fortawesome/free-brands-svg-icons": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1", + "@glidejs/glide": "^3.6.0", "bootstrap": "^4.6.2", "cookieconsent": "^3.1.1", "cors": "^2.8.5", @@ -40,6 +41,7 @@ "jquery": "^3.6.0", "ngx-cookie-service": "^16.0.1", "ngx-cookieconsent": "^4.0.2", + "ngx-glide": "^16.0.0", "normalize.css": "^8.0.1", "rxjs": "~7.5.0", "ts-interface-checker": "^1.0.2", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ddced24..1ee9eb6 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -11,12 +11,14 @@ import { AppServiceWorkerModule } from './app-service-worker.module'; import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; import { FooterComponent } from './footer/footer.component'; +import {HomeModule} from "./home/home.module"; @NgModule({ - declarations: [AppComponent, HomeComponent, FooterComponent], + declarations: [AppComponent, FooterComponent], imports: [ BrowserModule, HeaderModule, + HomeModule, AppRouterModule, AppServiceWorkerModule, SharedModule, diff --git a/src/app/footer/footer.component.css b/src/app/footer/footer.component.css index a62fa5a..ba194de 100644 --- a/src/app/footer/footer.component.css +++ b/src/app/footer/footer.component.css @@ -20,18 +20,22 @@ padding: 20px 0; } -.footer-links a { - color: #ffffff; - font-size: 18px; - margin: 0 10px; -} - .footer-btn { color: #ffffff; font-size: 18px; border: 1px solid #ffffff; border-radius: 50%; - margin: 0 5px; + margin: 0 10px; + + width: 42px; + height: 42px; +} + +.footer-btn a { + display: flex; + text-align: center; + justify-content: center; + align-items: center; } .footer-btn:hover { diff --git a/src/app/header/header-slider/header-slider.component.css b/src/app/header/header-slider/header-slider.component.css index 5946178..4d7f6ec 100644 --- a/src/app/header/header-slider/header-slider.component.css +++ b/src/app/header/header-slider/header-slider.component.css @@ -2,7 +2,7 @@ background-color: #2e2e2e; width: 50%; height: 90vh; - position: absolute; + position: fixed; top: 10vh; right: 0; overflow: hidden !important; diff --git a/src/app/header/header.component.css b/src/app/header/header.component.css index 89de955..0b13bc5 100644 --- a/src/app/header/header.component.css +++ b/src/app/header/header.component.css @@ -3,10 +3,17 @@ left: 0; display: flex; position: fixed; - width: 100%; - background-color: #2e2e2e; + width: 100vw; + + + background: rgb(46,46,46); + z-index: 50; + height: 10vh; min-height: 80px; + + justify-content: center; + align-items: center; } .header-spacer { @@ -100,6 +107,14 @@ app-header-slider { /* ====================== COMPUTER MEDIA FORMAT ======================== */ @media only screen and (min-width: 712px) { + .main { + max-width: 1333px; + } + + .slider-container { + display: none; + } + .nav-links { all: unset; width: 50%; diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index 3a00597..f080519 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -54,35 +54,37 @@ > -
- - - - -
- -
- - - - -
+ +
+ + + + +
+ +
+ + + + +
+
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index 734ff54..4f75f3f 100644 --- a/src/app/header/header.component.ts +++ b/src/app/header/header.component.ts @@ -5,7 +5,7 @@ import { OnDestroy, OnInit, ViewChild, - ViewContainerRef, + ViewContainerRef, ViewEncapsulation, } from '@angular/core'; import { faUser } from '@fortawesome/free-solid-svg-icons'; import { LoginComponent } from './header-popup/login/login.component'; @@ -33,8 +33,6 @@ export class HeaderComponent implements OnInit, OnDestroy { profileDropdownState: boolean = false; - signupPopupState: boolean = false; - navSliderStatus: boolean = false; userSliderStatus: boolean = false; diff --git a/src/app/home/home.component.css b/src/app/home/home.component.css index e69de29..0e44c53 100644 --- a/src/app/home/home.component.css +++ b/src/app/home/home.component.css @@ -0,0 +1,140 @@ +.me-section { + background: rgb(46,46,46); + background: linear-gradient(180deg, rgba(46,46,46,1) 35%, rgba(51,51,51,1) 100%); + height: 90vh; +} + +.intro { + height: 60%; + display: flex; + flex-direction: column; + justify-content: center; +} + +.intro h1 { + font-weight: 600; + font-size: 2.5rem; + color: #ffffff; +} + +.intro p { + font-family: "Poppins", sans-serif; + + font-size: 1rem; + font-weight: 100; + color: #f1f1f1; +} + +.intro br { + display: block; + margin: 10px 0; + content: " "; +} + + +/* SCROLL BUTTON*/ +.scroll-btn-container { + display: flex; +} + +.scroll-btn span { + position: relative; + display: block; + content: ""; + + width: 24px; + height: 24px; + + border-left: 1px solid #fff; + border-bottom: 1px solid #fff; + + cursor: pointer; + + transform-style: preserve-3d; + + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-animation: scbt 2s infinite; + animation: scbt 2s infinite; +} +.scroll-btn span:nth-of-type(1) { + -webkit-animation-delay: 0s; + animation-delay: 0s; +} +.scroll-btn span:nth-of-type(2) { + -webkit-animation-delay: .15s; + animation-delay: .15s; +} +.scroll-btn span:nth-of-type(3) { + -webkit-animation-delay: .3s; + animation-delay: .3s; +} +@-webkit-keyframes scbt { + 0% { + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes scbt { + 0% { + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + + +/* STACK SECTION*/ +.stack-section { + background: rgb(241,241,241); + /*background: linear-gradient(0deg, rgba(241,241,241,1) 80%, rgba(51,51,51,1) 100%);*/ + height: 80vh; +} +.stack { + height: 35%; + display: flex; + flex-direction: column; + justify-content: center; +} + +.stack h2 { + font-weight: 600; + font-size: 2.5rem; +} + +.stack p { + font-family: "Poppins", sans-serif; + + font-size: 1rem; + font-weight: 100; +} + +.stack-slider { + height: 65%; +} + + +/*ON MOBILE VIEWPORT*/ +@media only screen and (max-width: 400px) { + .intro { + height: 75%; + } + + .stack-section { + height: 90vh; + } + .stack { + padding-top: 60px; + width: 80%; + height: 30%; + } +} diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index e69de29..5d99240 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -0,0 +1,45 @@ +
+
+

+ I'M VITOR HIDEYOSHI +

+

+ I'm a software engineer with a passion for web development + and a strong interest in data science. I spend most of my time + learning new technologies and improving my skills, searching for + new challenges and opportunities to grow as a professional. + +
+ + In this search for new challenges I gained experience in different + areas of software development, from web development to data science. + I'm always looking for new opportunities to learn and improve my skills. +

+
+ +
+ + + + + +
+
+ + +
+
+

+ My Stack +

+

+ I'm always looking for new technologies to learn and improve my skills. + Here are some of the technologies I've been working with recently: +

+
+ +
+ + +
+
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 68bf907..0698872 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -7,4 +7,16 @@ import { Component, OnInit } from '@angular/core'; }) export class HomeComponent { constructor() {} + + scrollToElement(element: HTMLElement): void { + let block: ScrollLogicalPosition = "start"; + if (window.innerWidth < 400) { + block = "end"; + } + element.scrollIntoView({ + behavior: "smooth", + block: block, + inline: "nearest" + }); + } } diff --git a/src/app/home/home.module.ts b/src/app/home/home.module.ts new file mode 100644 index 0000000..2bfa1be --- /dev/null +++ b/src/app/home/home.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import {CommonModule, NgOptimizedImage} from '@angular/common'; +import {HomeComponent} from "./home.component"; +import {StackSliderComponent} from "./stack-slider/stack-slider.component"; +import {StackCardComponent} from "./stack-slider/stack-card/stack-card.component"; +import {NgxGlideComponent} from "ngx-glide"; + + + +@NgModule({ + declarations: [ + HomeComponent, + StackSliderComponent, + StackCardComponent + ], + imports: [ + CommonModule, + NgxGlideComponent, + NgOptimizedImage + ] +}) +export class HomeModule { } diff --git a/src/app/home/stack-slider/stack-card/stack-card.component.css b/src/app/home/stack-slider/stack-card/stack-card.component.css new file mode 100644 index 0000000..b3c5ebb --- /dev/null +++ b/src/app/home/stack-slider/stack-card/stack-card.component.css @@ -0,0 +1,52 @@ +.stack-card { + width: 325px; + display: flex; + justify-content: center; + align-items: center; + + border-radius: 15px; +} + +.stack-card-image { + width: 250px; + height: 250px; + position: relative; + display: flex; + align-items: center; +} + +.stack-card-body { + padding: 10px; + flex-grow: 1; + + width: 250px; + height: 130px; + inline-size: 250px; +} + +.stack-card-title { + font-size: 1.5rem; + font-weight: 600; + margin-bottom: 10px; +} + +.stack-card-text { + word-break: break-all !important; + white-space: normal !important; + font-size: 1rem; + font-weight: 400 !important; + font-family: 'Hind', sans-serif !important; +} + + +/*CARD STATE*/ +.active { + opacity: 1; + width: 300px; +} + +.inactive { + opacity: 0.7; + width: 280px; + height: 410px; +} diff --git a/src/app/home/stack-slider/stack-card/stack-card.component.html b/src/app/home/stack-slider/stack-card/stack-card.component.html new file mode 100644 index 0000000..f79d7db --- /dev/null +++ b/src/app/home/stack-slider/stack-card/stack-card.component.html @@ -0,0 +1,12 @@ +
+
+ Stack Image +
+
+
{{stack.name}}
+

{{stack.description}}

+
+
diff --git a/src/app/home/stack-slider/stack-card/stack-card.component.spec.ts b/src/app/home/stack-slider/stack-card/stack-card.component.spec.ts new file mode 100644 index 0000000..c36ef9f --- /dev/null +++ b/src/app/home/stack-slider/stack-card/stack-card.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StackCardComponent } from './stack-card.component'; + +describe('StackCardComponent', () => { + let component: StackCardComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [StackCardComponent] + }); + fixture = TestBed.createComponent(StackCardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/home/stack-slider/stack-card/stack-card.component.ts b/src/app/home/stack-slider/stack-card/stack-card.component.ts new file mode 100644 index 0000000..f8b7126 --- /dev/null +++ b/src/app/home/stack-slider/stack-card/stack-card.component.ts @@ -0,0 +1,37 @@ +import {Component, Input} from '@angular/core'; +import {Stack} from "../../../shared/model/stack/stack.model"; +import {animate, state, style, transition, trigger} from "@angular/animations"; + +@Component({ + selector: 'app-stack-card', + templateUrl: './stack-card.component.html', + styleUrls: ['./stack-card.component.css'], + animations: [ + trigger('cardAnimation', [ + state('active', style({ + opacity: 1, + width: '325px', + height: '425px', + })), + state('inactive', style({ + opacity: 0.7, + width: '280px', + height: '410px', + })), + transition('* => *', [ + animate('0.1s') + ]), + ]) + ], +}) +export class StackCardComponent { + @Input() + stack!: Stack; + + @Input() + inFocus: boolean = false; + + get cardState(): 'active'|'inactive' { + return this.inFocus ? 'active' : 'inactive'; + } +} diff --git a/src/app/home/stack-slider/stack-slider.component.css b/src/app/home/stack-slider/stack-slider.component.css new file mode 100644 index 0000000..6c75bf0 --- /dev/null +++ b/src/app/home/stack-slider/stack-slider.component.css @@ -0,0 +1,5 @@ +.slider-card { + justify-content: center; + align-items: center; + display: flex; +} diff --git a/src/app/home/stack-slider/stack-slider.component.html b/src/app/home/stack-slider/stack-slider.component.html new file mode 100644 index 0000000..9967157 --- /dev/null +++ b/src/app/home/stack-slider/stack-slider.component.html @@ -0,0 +1,5 @@ + + + + diff --git a/src/app/home/stack-slider/stack-slider.component.spec.ts b/src/app/home/stack-slider/stack-slider.component.spec.ts new file mode 100644 index 0000000..64e0e2e --- /dev/null +++ b/src/app/home/stack-slider/stack-slider.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StackSliderComponent } from './stack-slider.component'; + +describe('StackSliderComponent', () => { + let component: StackSliderComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [StackSliderComponent] + }); + fixture = TestBed.createComponent(StackSliderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/home/stack-slider/stack-slider.component.ts b/src/app/home/stack-slider/stack-slider.component.ts new file mode 100644 index 0000000..ef32c00 --- /dev/null +++ b/src/app/home/stack-slider/stack-slider.component.ts @@ -0,0 +1,124 @@ +import {AfterViewInit, ChangeDetectorRef, Component, HostListener, ViewChild} from '@angular/core'; +import {NgxGlideComponent} from "ngx-glide"; +import {Stack} from "../../shared/model/stack/stack.model"; + + +@Component({ + selector: 'app-stack-slider', + templateUrl: './stack-slider.component.html', + styleUrls: ['./stack-slider.component.css'] +}) +export class StackSliderComponent implements AfterViewInit { + @ViewChild('ngxGlide') + ngxGlide!: NgxGlideComponent; + + stacks: Stack[] = [ + { + name: 'Angular', + image: './assets/stacks/angular.svg', + description: 'Angular is a platform for building mobile and desktop web applications.', + }, + { + name: 'Next.js', + image: './assets/stacks/nextjs.svg', + description: 'React is a JavaScript library for building user interfaces.', + }, + { + name: 'FastAPI', + image: './assets/stacks/fastapi.svg', + description: 'FastAPI is a modern, fast (high-performance), web framework for building APIs.', + }, + { + name: 'Node.js', + image: './assets/stacks/nodejs.svg', + description: 'Node.js is an open-source, cross-platform, back-end JavaScript runtime environment.', + }, + { + name: 'Spring Boot', + image: './assets/stacks/spring.svg', + description: 'Spring Boot makes it easy to create stand-alone, production-grade APIs', + }, + { + name: 'Docker', + image: './assets/stacks/docker.svg', + description: 'Docker is a set of platform as a service products to deliver software in packages called containers.', + }, + { + name: 'Kubernetes', + image: './assets/stacks/kubernetes.svg', + description: 'Kubernetes is an open-source container-orchestration system for automating deployment, scaling, and management.', + }, + { + name: 'Terraform', + image: './assets/stacks/terraform.svg', + description: 'Terraform is an open-source infrastructure as code software tool.', + }, + { + name: 'PostgreSQL', + image: './assets/stacks/postgresql.svg', + description: 'PostgreSQL is a free and open-source relational database.', + }, + { + name: 'Redis', + image: './assets/stacks/redis.svg', + description: 'Redis is an in-memory data structure store.', + }, + { + name: 'AWS', + image: './assets/stacks/aws.svg', + description: 'Amazon Web Services is a subsidiary of Amazon providing on-demand cloud computing.', + } + ] + + constructor(private cd: ChangeDetectorRef) { } + + @HostListener('window:resize', ['$event']) + onResize(event: any) { + const numberOfCards = this.getNumberOfCards(event.target.innerWidth); + this.buildCarousel(numberOfCards); + } + + ngAfterViewInit(): void { + if (this.ngxGlide) { + const numberOfCards = this.getNumberOfCards(window.innerWidth); + this.buildCarousel(numberOfCards); + } + + this.cd.detectChanges(); + } + + buildCarousel(numberOfCards: number): void { + this.ngxGlide.perView = numberOfCards; + + this.ngxGlide.showArrows = false; + this.ngxGlide.showBullets = false; + this.ngxGlide.type = 'carousel'; + this.ngxGlide.focusAt = 'center'; + this.ngxGlide.gap = 10; + this.ngxGlide.autoplay = 3000; + + this.ngxGlide.recreate(); + } + + get currentIndex(): number { + return this.ngxGlide?.getIndex(); + } + + isInFocus(stack: Stack): boolean { + return this.stacks.indexOf(stack) === this.currentIndex; + } + + private getNumberOfCards(windowWidth: number): number { + if (windowWidth <= 450) { + return 1; + } else if (windowWidth <= 768) { + return 2; + } else if (windowWidth <= 975) { + return 3; + } else if (windowWidth <= 1440) { + return 4; + } else { + return 5; + } + } +} diff --git a/src/app/shared/components/popup/popup.component.css b/src/app/shared/components/popup/popup.component.css index 14fa8fa..8d3867c 100644 --- a/src/app/shared/components/popup/popup.component.css +++ b/src/app/shared/components/popup/popup.component.css @@ -7,14 +7,9 @@ .popup-background { background-color: rgba(0, 0, 0, 0.5); - justify-content: center; - align-content: center; - align-items: center; - overflow-y: hidden; - position: fixed; - display: flex; - height: 100vh; - width: 100vw; + position: absolute; + width: 100%; + height: 100%; left: 0; top: 0; } @@ -25,10 +20,15 @@ border: 1px solid #dddd; border-radius: 18px; height: fit-content; - position: relative; max-width: 400px; overflow: auto; width: 90%; + + position: fixed; + top: 50%; + left: 50%; + + transform: translate(-50%, -50%); } .popup-header { diff --git a/src/app/shared/components/popup/popup.component.ts b/src/app/shared/components/popup/popup.component.ts index b7fee51..93d3539 100644 --- a/src/app/shared/components/popup/popup.component.ts +++ b/src/app/shared/components/popup/popup.component.ts @@ -27,12 +27,14 @@ import { 'hide', style({ opacity: '0', + zIndex: 2 }), ), state( 'show', style({ opacity: '1', + zIndex: 2 }), ), transition( diff --git a/src/app/shared/model/stack/stack.model.ts b/src/app/shared/model/stack/stack.model.ts new file mode 100644 index 0000000..fa6b311 --- /dev/null +++ b/src/app/shared/model/stack/stack.model.ts @@ -0,0 +1,5 @@ +export interface Stack { + name: string; + image: string; + description: string; +} diff --git a/src/assets/stacks/angular.svg b/src/assets/stacks/angular.svg new file mode 100644 index 0000000..468c4ba --- /dev/null +++ b/src/assets/stacks/angular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/aws.svg b/src/assets/stacks/aws.svg new file mode 100644 index 0000000..3840f92 --- /dev/null +++ b/src/assets/stacks/aws.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/docker.svg b/src/assets/stacks/docker.svg new file mode 100644 index 0000000..0a9c6b0 --- /dev/null +++ b/src/assets/stacks/docker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/fastapi.svg b/src/assets/stacks/fastapi.svg new file mode 100644 index 0000000..c307de8 --- /dev/null +++ b/src/assets/stacks/fastapi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/kubernetes.svg b/src/assets/stacks/kubernetes.svg new file mode 100644 index 0000000..9825631 --- /dev/null +++ b/src/assets/stacks/kubernetes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/nextjs.svg b/src/assets/stacks/nextjs.svg new file mode 100644 index 0000000..14b3837 --- /dev/null +++ b/src/assets/stacks/nextjs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/nodejs.svg b/src/assets/stacks/nodejs.svg new file mode 100644 index 0000000..0481f9f --- /dev/null +++ b/src/assets/stacks/nodejs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/postgresql.svg b/src/assets/stacks/postgresql.svg new file mode 100644 index 0000000..9fa5c4d --- /dev/null +++ b/src/assets/stacks/postgresql.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/redis.svg b/src/assets/stacks/redis.svg new file mode 100644 index 0000000..0712975 --- /dev/null +++ b/src/assets/stacks/redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/spring.svg b/src/assets/stacks/spring.svg new file mode 100644 index 0000000..ce9bba0 --- /dev/null +++ b/src/assets/stacks/spring.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/stacks/terraform.svg b/src/assets/stacks/terraform.svg new file mode 100644 index 0000000..4929cd9 --- /dev/null +++ b/src/assets/stacks/terraform.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/styles.css b/src/styles.css index 0b165c2..5d178f5 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,4 +1,5 @@ /* You can add global styles to this file, and also import other style files */ +@import url('https://fonts.googleapis.com/css2?family=Hind:wght@300;400;500;600;700&display=swap'); @import "font-montserrat.css"; * { @@ -6,6 +7,13 @@ margin: 0 auto; } +html, body { + width: 100vw; + overflow-y: scroll; + overflow-x: hidden; + position: absolute; +} + h1, h2, h3, @@ -14,3 +22,7 @@ h5, h6 { font-family: "Montserrat", sans-serif; } + +p { + font-family: "Hind", sans-serif; +}