la base du site fonctionnelle

This commit is contained in:
styve Lioumba
2024-09-25 15:58:42 +02:00
committed by styve Lioumba
parent 27d260829c
commit 1bf76c6c66
92 changed files with 14820 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
<main class="bg-white dark:bg-gray-900">
<app-nav-bar/>
<section class="content bg-white dark:bg-gray-900">
<router-outlet></router-outlet>
</section>
<app-footer/>
</main>

View File

@@ -0,0 +1,18 @@
main {
display: flex;
flex-direction: column;
min-height: 100vh; /* Minimum 100% de la hauteur de la fenêtre */
}
#content {
flex-grow: 1; /* Cette zone grandit pour remplir l'espace restant */
padding: 20px;
}
app-nav-bar {
flex-shrink: 0; /* Le header ne doit pas rétrécir */
}
app-footer {
flex-shrink: 0; /* Le footer ne doit pas rétrécir */
}

View File

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

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

@@ -0,0 +1,16 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import {NavBarComponent} from "@app/shared/components/nav-bar/nav-bar.component";
import {FooterComponent} from "@app/shared/components/footer/footer.component";
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet, NavBarComponent, FooterComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
title = 'TrouveTonProfile';
}

View File

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

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

@@ -0,0 +1,29 @@
import {ApplicationConfig} from '@angular/core';
import {
PreloadAllModules,
provideRouter,
withInMemoryScrolling,
withPreloading,
withViewTransitions
} from '@angular/router';
import {routes} from './app.routes';
import {provideHttpClient, withFetch} from "@angular/common/http";
import {provideAnimations} from "@angular/platform-browser/animations";
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(
routes,
withViewTransitions(),
withPreloading(PreloadAllModules),
withInMemoryScrolling(
{
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
}
)),
provideAnimations(),
provideHttpClient(withFetch())
]
};

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

@@ -0,0 +1,26 @@
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
title: 'Accueil',
loadChildren: () => import('@app/routes/home/home.module').then(m => m.HomeModule)
},
{
path: 'home',
title: 'Accueil',
loadChildren: () => import('@app/routes/home/home.module').then(m => m.HomeModule)
},
{
path: 'profiles',
title: 'Liste des profiles',
loadChildren: () => import('@app/routes/profile/profile.module').then(m => m.ProfileModule)
},
{
path: 'not-found',
title: 'Page non trouvée',
loadChildren: () => import('@app/routes/not-found/not-found.module').then(m => m.NotFoundModule)
},
{path: '', redirectTo: '/', pathMatch: 'full'},
{path: '**', redirectTo: '/not-found'}
];

View File

@@ -0,0 +1,17 @@
import { TestBed } from '@angular/core/testing';
import { ResolveFn } from '@angular/router';
import { detailResolver } from './detail.resolver';
describe('detailResolver', () => {
const executeResolver: ResolveFn<boolean> = (...resolverParameters) =>
TestBed.runInInjectionContext(() => detailResolver(...resolverParameters));
beforeEach(() => {
TestBed.configureTestingModule({});
});
it('should be created', () => {
expect(executeResolver).toBeTruthy();
});
});

View File

@@ -0,0 +1,6 @@
import { ResolveFn } from '@angular/router';
export const detailResolver: ResolveFn<string> = (route, state) => {
const paramValue = route.params['name'];
return "profile-list-resolver works!, paramValue: " + paramValue || "no query value found!";
};

View File

@@ -0,0 +1,17 @@
import { TestBed } from '@angular/core/testing';
import { ResolveFn } from '@angular/router';
import { listResolver } from './list.resolver';
describe('listResolver', () => {
const executeResolver: ResolveFn<boolean> = (...resolverParameters) =>
TestBed.runInInjectionContext(() => listResolver(...resolverParameters));
beforeEach(() => {
TestBed.configureTestingModule({});
});
it('should be created', () => {
expect(executeResolver).toBeTruthy();
});
});

View File

@@ -0,0 +1,6 @@
import { ResolveFn } from '@angular/router';
export const listResolver: ResolveFn<string> = (route, state) => {
const queryValue = route.queryParams['search'];
return "profile-list-resolver works!, queryValue: " + queryValue || "no query value found!";
};

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {HomeComponent} from "@app/routes/home/home.component";
const routes: Routes = [
{path: '', component: HomeComponent, title: 'Accueil'}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class HomeRoutingModule { }

View File

@@ -0,0 +1,70 @@
<section class="pb-10 relative">
<div className="absolute inset-0 bg-heroPatternLight dark:bg-heroPatternDark"></div>
<div class="relative overflow-hidden">
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10">
<div class="mt-5 max-w-2xl text-center mx-auto">
<h1
class="block font-bold text-gray-800 dark:text-white text-3xl md:text-5xl lg:text-6xl">
Dans quel secteur se cache votre prochaine
<span class="text-gray-800 dark:text-white">pépites?</span>
<div id=container>
<div id=flip>
<div><div>Les finances</div></div>
<div><div>La Santé</div></div>
<div><div>Les Etudes</div></div>
</div>
</div>
</h1>
</div>
<div class="mt-8 mx-auto max-w-3xl space-y-2">
<app-search (onSearchChange)="showNewQuery($event)" />
</div>
</div>
</div>
<div class="max-w-6xl mx-auto px-4">
<div
class="w-full relative bg-purple-200 rounded-xl px-2 pt-8 space-y-4 md:space-y-0">
<div
class="relative md:absolute inset-0 z-[1] bg-transparent md:px-10 order-0">
<div class="h-full grid place-content-center md:w-1/2 lg:w-2/5">
<div class="px-8 space-y-3 text-center md:text-left">
<h1
class="text-purple-950 text-4xl font-bold mb-4 text-center md:text-left">
Votre prochain profile en quelques clicks
</h1>
<p class="text-center md:text-left">
Le moyen le plus simple de trouver le/la candidat(e) qu'il vous faut.
</p>
<button
class="items-center flex gap-2 px-12 py-3 rounded-full text-white bg-purple-900 mx-auto md:m-0">
<span class="inline-block w-5 h-5">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 -960 960 960">
<path
d="M480-80Q319-217 239.5-334.5T160-552q0-150 96.5-239T480-880q127 0 223.5 89T800-552l84-84 56 56-180 180-180-180 56-56 84 84q0-109-69.5-178.5T480-800q-101 0-170.5 69.5T240-552q0 71 59 162.5T480-186q20-18 37-35l34-34q-5-10-8-21.5t-3-23.5q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29q-8 0-14.5-1t-13.5-3q-29 30-61.5 61T480-80Z" />
</svg>
</span>
<span>Réchercher maintenant</span>
</button>
</div>
</div>
</div>
<img
class="w-full h-auto hidden md:inline-block"
src="https://www.tripadvisor.ca/img2/trips/home-gai-entry-dv.png"
alt="" />
<img
class="w-full h-auto block md:hidden"
src="https://www.tripadvisor.ca/img2/trips/home-gai-entry-mv.png"
alt="" />
</div>
</div>
</section>

View File

@@ -0,0 +1,46 @@
#container {
color:#999;
text-transform: uppercase;
font-size:36px;
font-weight:bold;
display:block;
}
#flip {
margin-top: 10px;
height:50px;
overflow:hidden;
}
#flip > div > div {
color:#fff;
padding:4px 12px;
height:45px;
margin-bottom:45px;
display:inline-block;
}
#flip div:first-child {
animation: show 10s linear infinite;
}
#flip div div {
background:#42c58a;
}
#flip div:first-child div {
background:#4ec7f3;
}
#flip div:last-child div {
background:#DC143C;
}
@keyframes show {
0% {margin-top:-270px;}
5% {margin-top:-180px;}
33% {margin-top:-180px;}
38% {margin-top:-90px;}
66% {margin-top:-90px;}
71% {margin-top:0px;}
99.99% {margin-top:0px;}
100% {margin-top:-270px;}
}

View File

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

View File

@@ -0,0 +1,23 @@
import {Component, inject} from '@angular/core';
import {FaIconComponent} from "@fortawesome/angular-fontawesome";
import {SearchComponent} from "@app/shared/features/search/search.component";
import {Router} from "@angular/router";
@Component({
selector: 'app-home',
standalone: true,
imports: [
FaIconComponent,
SearchComponent
],
templateUrl: './home.component.html',
styleUrl: './home.component.scss'
})
export class HomeComponent {
private readonly router = inject(Router)
showNewQuery(newQuery: string) {
this.router.navigate(['/profiles'], {queryParams: {search: newQuery}});
}
}

View File

@@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HomeRoutingModule } from './home-routing.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
HomeRoutingModule
]
})
export class HomeModule { }

View File

@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {NotFoundComponent} from "@app/routes/not-found/not-found.component";
const routes: Routes = [
{path: '', component: NotFoundComponent, title: 'Page non trouvée'}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class NotFoundRoutingModule { }

View File

@@ -0,0 +1 @@
<p>not-found works!</p>

View File

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

View File

@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-not-found',
standalone: true,
imports: [],
templateUrl: './not-found.component.html',
styleUrl: './not-found.component.scss'
})
export class NotFoundComponent {
}

View File

@@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NotFoundRoutingModule } from './not-found-routing.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
NotFoundRoutingModule
]
})
export class NotFoundModule { }

View File

@@ -0,0 +1,32 @@
<section class="text-gray-600 body-font">
<div class="container px-5 py-24 mx-auto flex flex-col">
<div class="lg:w-4/6 mx-auto">
<div class="rounded-lg h-64 overflow-hidden">
<img alt="content" class="object-cover object-center h-full w-full" src="https://dummyimage.com/1200x500">
</div>
<div class="flex flex-col sm:flex-row mt-10">
<div class="sm:w-1/3 text-center sm:pr-8 sm:py-8">
<div class="w-20 h-20 rounded-full inline-flex items-center justify-center bg-gray-200 text-gray-400">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-10 h-10" viewBox="0 0 24 24">
<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</div>
<div class="flex flex-col items-center text-center justify-center">
<h2 class="font-medium title-font mt-4 text-gray-900 text-lg">Phoebe Caulfield</h2>
<div class="w-12 h-1 bg-indigo-500 rounded mt-2 mb-4"></div>
<p class="text-base">Raclette knausgaard hella meggs normcore williamsburg enamel pin sartorial venmo tbh hot chicken gentrify portland.</p>
</div>
</div>
<div class="sm:w-2/3 sm:pl-8 sm:py-8 sm:border-l border-gray-200 sm:border-t-0 border-t mt-4 pt-4 sm:mt-0 text-center sm:text-left">
<p class="leading-relaxed text-lg mb-4">Meggings portland fingerstache lyft, post-ironic fixie man bun banh mi umami everyday carry hexagon locavore direct trade art party. Locavore small batch listicle gastropub farm-to-table lumbersexual salvia messenger bag. Coloring book flannel truffaut craft beer drinking vinegar sartorial, disrupt fashion axe normcore meh butcher. Portland 90's scenester vexillologist forage post-ironic asymmetrical, chartreuse disrupt butcher paleo intelligentsia pabst before they sold out four loko. 3 wolf moon brooklyn.</p>
<a class="text-indigo-500 inline-flex items-center">Learn More
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 ml-2" viewBox="0 0 24 24">
<path d="M5 12h14M12 5l7 7-7 7"></path>
</svg>
</a>
</div>
</div>
</div>
</div>
</section>

View File

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

View File

@@ -0,0 +1,19 @@
import {Component, inject} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
@Component({
selector: 'app-profile-detail',
standalone: true,
imports: [],
templateUrl: './profile-detail.component.html',
styleUrl: './profile-detail.component.scss'
})
export class ProfileDetailComponent {
private readonly route = inject(ActivatedRoute);
protected profile = this.route.snapshot.data['profile'];
constructor() {
console.log(this.profile)
}
}

View File

@@ -0,0 +1,30 @@
<section class="pb-10 relative">
<div class="relative overflow-hidden">
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10">
<div class="mt-8 mx-auto max-w-3xl space-y-2">
<app-search/>
</div>
</div>
</div>
<div class="max-w-6xl mx-auto px-4">
<app-display-profile-card (onDisplayChange)="showNewDisplay($event)"/>
@switch (display()){
@case ('list'.toUpperCase()){
<app-horizental-profile-list/>
}
@case ('grid'.toUpperCase()){
<app-vertical-profile-list/>
}
@default{
<app-vertical-profile-list/>
}
}
</div>
</section>

View File

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

View File

@@ -0,0 +1,47 @@
import {Component, inject, signal} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {SearchComponent} from "@app/shared/features/search/search.component";
import {
HorizentalProfileItemComponent
} from "@app/shared/components/horizental-profile-item/horizental-profile-item.component";
import {
VerticalProfileItemComponent
} from "@app/shared/components/vertical-profile-item/vertical-profile-item.component";
import {DisplayProfileCardComponent} from "@app/shared/features/display-profile-card/display-profile-card.component";
import {JsonPipe} from "@angular/common";
import {
HorizentalProfileListComponent
} from "@app/shared/components/horizental-profile-list/horizental-profile-list.component";
import {
VerticalProfileListComponent
} from "@app/shared/components/vertical-profile-list/vertical-profile-list.component";
@Component({
selector: 'app-profile-list',
standalone: true,
imports: [
SearchComponent,
HorizentalProfileItemComponent,
VerticalProfileItemComponent,
DisplayProfileCardComponent,
JsonPipe,
HorizentalProfileListComponent,
VerticalProfileListComponent
],
templateUrl: './profile-list.component.html',
styleUrl: './profile-list.component.scss'
})
export class ProfileListComponent {
private readonly route = inject(ActivatedRoute);
protected profiles = this.route.snapshot.data['profiles'];
protected display = signal<string>('grid'.toUpperCase());
constructor() {
console.log(this.profiles)
}
showNewDisplay($event: string) {
this.display.set($event.toUpperCase())
}
}

View File

@@ -0,0 +1,18 @@
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {ProfileListComponent} from "@app/routes/profile/profile-list/profile-list.component";
import {ProfileDetailComponent} from "@app/routes/profile/profile-detail/profile-detail.component";
import {listResolver} from "@app/core/resolvers/profile/list/list.resolver";
import {detailResolver} from "@app/core/resolvers/profile/detail/detail.resolver";
const routes: Routes = [
{path: '', component: ProfileListComponent, title: 'Liste des profiles', resolve: {profiles: listResolver}},
{path: ':name', component: ProfileDetailComponent, title: 'Detail du profile', resolve: {profile: detailResolver}},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProfileRoutingModule {
}

View File

@@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProfileRoutingModule } from './profile-routing.module';
@NgModule({
declarations: [],
imports: [
CommonModule,
ProfileRoutingModule
]
})
export class ProfileModule { }

View File

@@ -0,0 +1,78 @@
<footer class=" py-4 w-full min-h-full bg-white dark:bg-gray-900 ">
<div class="max-w-[80rem] mx-auto space-y-6 px-2 md:px-4 lg:px-6 pt-4">
<div class="h-px w-full bg-gray-900/10 bg-gray-800 dark:bg-white"></div>
<div
class="flex flex-row justify-between items-center text-sm text-gray-600">
<a
[routerLink]="['/']"
class="inline-flex items-center gap-1">
<span class="inline-block text-xl text-gray-800 dark:text-white">TrouveTonProfile</span>
</a>
<ul class="flex items-center gap-4">
<li>
<a [routerLink]="['/conditions']" class="inline-block text-gray-800 dark:text-white">Conditions</a>
</li>
<li>
<a [routerLink]="['/terms']" class="inline-block text-gray-800 dark:text-white">Terms</a>
</li>
<li>
<a [routerLink]="['/politiques']" class="inline-block text-gray-800 dark:text-white">Politiques</a>
</li>
</ul>
<ul class="flex items-center gap-4">
<li>
<a
target="_blank"
href="#"
class="inline-block rounded-full h-8 w-8 p-2 border text-gray-800 dark:text-white">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 0 448 512">
<path
d="M100.28 448H7.4V148.9h92.88zM53.79 108.1C24.09 108.1 0 83.5 0 53.8a53.79 53.79 0 0 1 107.58 0c0 29.7-24.1 54.3-53.79 54.3zM447.9 448h-92.68V302.4c0-34.7-.7-79.2-48.29-79.2-48.29 0-55.69 37.7-55.69 76.7V448h-92.78V148.9h89.08v40.8h1.3c12.4-23.5 42.69-48.3 87.88-48.3 94 0 111.28 61.9 111.28 142.3V448z"/>
</svg>
</a>
</li>
<li>
<a
target="_blank"
href="#"
class="inline-block rounded-full h-8 w-8 p-2 border text-gray-800 dark:text-white">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 0 24 24">
<g
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="M0 0h24v24H0z"/>
<path
fill="currentColor"
d="M18 2a1 1 0 0 1 .993.883L19 3v4a1 1 0 0 1-.883.993L18 8h-3v1h3a1 1 0 0 1 .991 1.131l-.02.112l-1 4a1 1 0 0 1-.858.75L17 15h-2v6a1 1 0 0 1-.883.993L14 22h-4a1 1 0 0 1-.993-.883L9 21v-6H7a1 1 0 0 1-.993-.883L6 14v-4a1 1 0 0 1 .883-.993L7 9h2V8a6 6 0 0 1 5.775-5.996L15 2z"/>
</g>
</svg>
</a>
</li>
<li>
<a
target="_blank"
href="#"
class="inline-block rounded-full h-8 w-8 p-2 border text-gray-800 dark:text-white">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 0 512 512">
<path
d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"/>
</svg>
</a>
</li>
</ul>
</div>
</div>
</footer>

View File

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

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import {RouterLink} from "@angular/router";
@Component({
selector: 'app-footer',
standalone: true,
imports: [
RouterLink
],
templateUrl: './footer.component.html',
styleUrl: './footer.component.scss'
})
export class FooterComponent {
}

View File

@@ -0,0 +1,34 @@
<div class="items-center bg-gray-50 rounded-lg shadow sm:flex dark:bg-gray-800 dark:border-gray-700 cursor-pointer" (click)="onShowDetail(user)">
<a href="#">
<img class="w-full rounded-lg sm:rounded-none sm:rounded-l-lg" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/bonnie-green.png" alt="Bonnie Avatar">
</a>
<div class="p-5">
<h3 class="text-xl font-bold tracking-tight text-gray-900 dark:text-white">
<a href="#">Bonnie Green</a>
</h3>
<span class="text-gray-500 dark:text-gray-400">CEO & Web Developer</span>
<p class="mt-3 mb-4 font-light text-gray-500 dark:text-gray-400">Bonnie drives the technical strategy of the flowbite platform and brand.</p>
<ul class="flex space-x-4 sm:mt-0">
<li>
<a href="#" class="text-gray-500 hover:text-gray-900 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fill-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clip-rule="evenodd" /></svg>
</a>
</li>
<li>
<a href="#" class="text-gray-500 hover:text-gray-900 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" /></svg>
</a>
</li>
<li>
<a href="#" class="text-gray-500 hover:text-gray-900 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" /></svg>
</a>
</li>
<li>
<a href="#" class="text-gray-500 hover:text-gray-900 dark:hover:text-white">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10c5.51 0 10-4.48 10-10S17.51 2 12 2zm6.605 4.61a8.502 8.502 0 011.93 5.314c-.281-.054-3.101-.629-5.943-.271-.065-.141-.12-.293-.184-.445a25.416 25.416 0 00-.564-1.236c3.145-1.28 4.577-3.124 4.761-3.362zM12 3.475c2.17 0 4.154.813 5.662 2.148-.152.216-1.443 1.941-4.48 3.08-1.399-2.57-2.95-4.675-3.189-5A8.687 8.687 0 0112 3.475zm-3.633.803a53.896 53.896 0 013.167 4.935c-3.992 1.063-7.517 1.04-7.896 1.04a8.581 8.581 0 014.729-5.975zM3.453 12.01v-.26c.37.01 4.512.065 8.775-1.215.25.477.477.965.694 1.453-.109.033-.228.065-.336.098-4.404 1.42-6.747 5.303-6.942 5.629a8.522 8.522 0 01-2.19-5.705zM12 20.547a8.482 8.482 0 01-5.239-1.8c.152-.315 1.888-3.656 6.703-5.337.022-.01.033-.01.054-.022a35.318 35.318 0 011.823 6.475 8.4 8.4 0 01-3.341.684zm4.761-1.465c-.086-.52-.542-3.015-1.659-6.084 2.679-.423 5.022.271 5.314.369a8.468 8.468 0 01-3.655 5.715z" clip-rule="evenodd" /></svg>
</a>
</li>
</ul>
</div>
</div>

View File

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

View File

@@ -0,0 +1,19 @@
import {Component, inject, Input} from '@angular/core';
import {Router} from "@angular/router";
@Component({
selector: 'app-horizental-profile-item',
standalone: true,
imports: [],
templateUrl: './horizental-profile-item.component.html',
styleUrl: './horizental-profile-item.component.scss'
})
export class HorizentalProfileItemComponent {
@Input() user: any = {};
protected router = inject(Router)
onShowDetail(user: any) {
this.router.navigate(['/profiles', "user1"])
}
}

View File

@@ -0,0 +1,11 @@
<section class="bg-white dark:bg-gray-900">
<div class="py-8 px-4 mx-auto max-w-screen-xl text-center lg:py-16 lg:px-6 ">
<div class="grid gap-8 mb-6 lg:mb-16 md:grid-cols-2">
@for (n of [1, 2, 3, 4]; track n) {
<app-horizental-profile-item/>
}
</div>
</div>
</section>

View File

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

View File

@@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import {
HorizentalProfileItemComponent
} from "@app/shared/components/horizental-profile-item/horizental-profile-item.component";
@Component({
selector: 'app-horizental-profile-list',
standalone: true,
imports: [
HorizentalProfileItemComponent
],
templateUrl: './horizental-profile-list.component.html',
styleUrl: './horizental-profile-list.component.scss'
})
export class HorizentalProfileListComponent {
}

View File

@@ -0,0 +1,67 @@
<header class="bg-white dark:bg-gray-900">
<div class="w-full">
<nav
class="fixed w-full z-20 top-0 start-1/2 max-w-6xl -translate-x-1/2 bg-white dark:bg-gray-900">
<div
class="max-w-screen-xl flex flex-nowrap items-center justify-between mx-auto p-4">
<a [routerLink]="['/']"
class="flex items-center space-x-3 rtl:space-x-reverse">
<div class="flex flex-row items-center gap-1 mr-3">
<span class="text-xl select-none text-black dark:text-white">TrouveTonProfile</span>
</div>
</a>
<div class="flex md:order-2 space-x-1 items-center">
<button
type="button"
class="text-black dark:text-white font-medium rounded-lg text-sm px-4 py-2 text-center flex items-center justify-center gap-1">
<span class="inline-block h-4 w-4">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 -960 960 960">
<path
d="M480-120q-150 0-255-105T120-480q0-150 105-255t255-105q14 0 27.5 1t26.5 3q-41 29-65.5 75.5T444-660q0 90 63 153t153 63q55 0 101-24.5t75-65.5q2 13 3 26.5t1 27.5q0 150-105 255T480-120Zm0-80q88 0 158-48.5T740-375q-20 5-40 8t-40 3q-123 0-209.5-86.5T364-660q0-20 3-40t8-40q-78 32-126.5 102T200-480q0 116 82 198t198 82Zm-10-270Z" />
</svg>
</span>
</button>
<span class="text-black dark:text-white"> | </span>
<button
type="button"
class="text-black dark:text-white font-medium rounded-lg text-sm px-4 py-2 text-center flex items-center justify-center gap-1">
<span class="inline-block h-4 w-4">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 -960 960 960">
<path
d="M234-276q51-39 114-61.5T480-360q69 0 132 22.5T726-276q35-41 54.5-93T800-480q0-133-93.5-226.5T480-800q-133 0-226.5 93.5T160-480q0 59 19.5 111t54.5 93Zm246-164q-59 0-99.5-40.5T340-580q0-59 40.5-99.5T480-720q59 0 99.5 40.5T620-580q0 59-40.5 99.5T480-440Zm0 360q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q53 0 100-15.5t86-44.5q-39-29-86-44.5T480-280q-53 0-100 15.5T294-220q39 29 86 44.5T480-160Zm0-360q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm0-60Zm0 360Z" />
</svg>
</span>
<span class="hidden sm:block text-black dark:text-white">Se connecter</span>
</button>
<button
data-collapse-toggle="navbar-sticky"
type="button"
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
aria-controls="navbar-sticky"
aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg
class="w-5 h-5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 17 14">
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M1 1h15M1 7h15M1 13h15" />
</svg>
</button>
</div>
</div>
</nav>
</div>
</header>

View File

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

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import {RouterLink} from "@angular/router";
@Component({
selector: 'app-nav-bar',
standalone: true,
imports: [
RouterLink
],
templateUrl: './nav-bar.component.html',
styleUrl: './nav-bar.component.scss'
})
export class NavBarComponent {
}

View File

@@ -0,0 +1,29 @@
<div class="text-center text-gray-500 dark:text-gray-400 cursor-pointer" (click)="onShowDetail(user)">
<img class="mx-auto mb-4 w-36 h-36 rounded-full" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/bonnie-green.png" alt="Bonnie Avatar">
<h3 class="mb-1 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
<a href="#">Bonnie Green</a>
</h3>
<p>CEO/Co-founder</p>
<ul class="flex justify-center mt-4 space-x-4">
<li>
<a href="#" class="text-[#39569c] hover:text-gray-900 dark:hover:text-white">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fill-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clip-rule="evenodd" /></svg>
</a>
</li>
<li>
<a href="#" class="text-[#00acee] hover:text-gray-900 dark:hover:text-white">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" /></svg>
</a>
</li>
<li>
<a href="#" class="text-gray-900 hover:text-gray-900 dark:hover:text-white dark:text-gray-300">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" /></svg>
</a>
</li>
<li>
<a href="#" class="text-[#ea4c89] hover:text-gray-900 dark:hover:text-white">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10c5.51 0 10-4.48 10-10S17.51 2 12 2zm6.605 4.61a8.502 8.502 0 011.93 5.314c-.281-.054-3.101-.629-5.943-.271-.065-.141-.12-.293-.184-.445a25.416 25.416 0 00-.564-1.236c3.145-1.28 4.577-3.124 4.761-3.362zM12 3.475c2.17 0 4.154.813 5.662 2.148-.152.216-1.443 1.941-4.48 3.08-1.399-2.57-2.95-4.675-3.189-5A8.687 8.687 0 0112 3.475zm-3.633.803a53.896 53.896 0 013.167 4.935c-3.992 1.063-7.517 1.04-7.896 1.04a8.581 8.581 0 014.729-5.975zM3.453 12.01v-.26c.37.01 4.512.065 8.775-1.215.25.477.477.965.694 1.453-.109.033-.228.065-.336.098-4.404 1.42-6.747 5.303-6.942 5.629a8.522 8.522 0 01-2.19-5.705zM12 20.547a8.482 8.482 0 01-5.239-1.8c.152-.315 1.888-3.656 6.703-5.337.022-.01.033-.01.054-.022a35.318 35.318 0 011.823 6.475 8.4 8.4 0 01-3.341.684zm4.761-1.465c-.086-.52-.542-3.015-1.659-6.084 2.679-.423 5.022.271 5.314.369a8.468 8.468 0 01-3.655 5.715z" clip-rule="evenodd" /></svg>
</a>
</li>
</ul>
</div>

View File

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

View File

@@ -0,0 +1,20 @@
import {Component, inject, Input} from '@angular/core';
import {Router} from "@angular/router";
@Component({
selector: 'app-vertical-profile-item',
standalone: true,
imports: [],
templateUrl: './vertical-profile-item.component.html',
styleUrl: './vertical-profile-item.component.scss'
})
export class VerticalProfileItemComponent {
@Input() user: any = {};
protected router = inject(Router)
onShowDetail(user: any) {
this.router.navigate(['/profiles', "user1"])
}
}

View File

@@ -0,0 +1,11 @@
<section class="bg-white dark:bg-gray-900">
<div class="py-8 px-4 mx-auto max-w-screen-xl text-center lg:py-16 lg:px-6">
<div class="grid gap-8 lg:gap-16 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
@for (n of [1, 2, 3, 4]; track n) {
<app-vertical-profile-item/>
}
</div>
</div>
</section>

View File

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

View File

@@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import {
VerticalProfileItemComponent
} from "@app/shared/components/vertical-profile-item/vertical-profile-item.component";
@Component({
selector: 'app-vertical-profile-list',
standalone: true,
imports: [
VerticalProfileItemComponent
],
templateUrl: './vertical-profile-list.component.html',
styleUrl: './vertical-profile-list.component.scss'
})
export class VerticalProfileListComponent {
}

View File

@@ -0,0 +1,8 @@
<section class="w-full">
<div class="text-end">
<i class="pi pi-th-large text-gray-800 dark:text-white py-4 px-3 border rounded-l-lg cursor-pointer"
(click)="onDisplayChange.emit('grid'.toUpperCase())"></i>
<i class="pi pi-bars text-gray-800 dark:text-white py-4 px-3 border rounded-r-lg cursor-pointer"
(click)="onDisplayChange.emit('list'.toUpperCase())"></i>
</div>
</section>

View File

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

View File

@@ -0,0 +1,12 @@
import {Component, output} from '@angular/core';
@Component({
selector: 'app-display-profile-card',
standalone: true,
imports: [],
templateUrl: './display-profile-card.component.html',
styleUrl: './display-profile-card.component.scss'
})
export class DisplayProfileCardComponent {
onDisplayChange = output<string>();
}

View File

@@ -0,0 +1,35 @@
<form class="w-full relative" [formGroup]="searchForm" (ngSubmit)="onSubmit()">
<div class="flex w-full border rounded-full p-2 items-center">
<div class="flex-1 flex flex-row items-center">
<button class="inline-block w-8 h-8 p-1 text-gray-400">
<svg
xmlns="http://www.w3.org/2000/svg"
class="w-full h-full fill-current"
viewBox="0 0 512 512">
<path
d="M337.509 305.372h-17.501l-6.571-5.486c20.791-25.232 33.922-57.054 33.922-93.257C347.358 127.632 283.896 64 205.135 64 127.452 64 64 127.632 64 206.629s63.452 142.628 142.225 142.628c35.011 0 67.831-13.167 92.991-34.008l6.561 5.487v17.551L415.18 448 448 415.086 337.509 305.372zm-131.284 0c-54.702 0-98.463-43.887-98.463-98.743 0-54.858 43.761-98.742 98.463-98.742 54.7 0 98.462 43.884 98.462 98.742 0 54.856-43.762 98.743-98.462 98.743z"
fill="currentColor" />
</svg>
</button>
<input
formControlName="search"
type="search"
autocomplete="off"
autocorrect="off"
autocapitalize="none"
spellcheck="false"
required=""
class="flex-1 focus:ring-0 focus:outline-none placeholder:text-gray-400 bg-transparent text-gray-800 dark:text-white"
placeholder="Domaines, activités..."
title="Search"
role="searchbox"
aria-label="Search"
aria-controls="typeahead_results"
aria-autocomplete="list" />
</div>
<button
class="w-32 h-12 rounded-full bg-purple-800 hover:bg-purple-900 text-gray-50">
Trouver
</button>
</div>
</form>

View File

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

View File

@@ -0,0 +1,34 @@
import {Component, inject, output} from '@angular/core';
import {FormBuilder, FormControl, ReactiveFormsModule, Validators} from "@angular/forms";
@Component({
selector: 'app-search',
standalone: true,
imports: [
ReactiveFormsModule
],
templateUrl: './search.component.html',
styleUrl: './search.component.scss'
})
export class SearchComponent {
onSearchChange = output<string>()
private formBuilder: FormBuilder = inject(FormBuilder);
searchForm = this.formBuilder.group({
search: new FormControl('', Validators.required)
});
onSubmit(){
if (this.searchForm.invalid) {
return;
}
const search = this.searchForm.value.search?.toLowerCase()!;
this.setNewName(search);
}
setNewName(newName: string) {
this.onSearchChange.emit(newName);
}
}