Enforce ESLint and Prettier
continuous-integration/drone/push Build is passing Details

error-extensions-editor
Clément FRÉVILLE 1 year ago
parent e4fa38e9ce
commit 74a68d9743

@ -0,0 +1,41 @@
{
"root": true,
"ignorePatterns": ["projects/**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
]
}
},
{
"files": ["*.html"],
"extends": [
"plugin:@angular-eslint/template/recommended",
"plugin:@angular-eslint/template/accessibility"
],
"rules": {}
}
]
}

@ -0,0 +1,12 @@
{
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"semi": true,
"bracketSpacing": true,
"arrowParens": "always",
"trailingComma": "es5",
"bracketSameLine": true,
"printWidth": 80,
"endOfLine": "auto"
}

@ -16,17 +16,10 @@
"outputPath": "dist/sandkasten",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
},
"configurations": {
@ -74,25 +67,24 @@
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
}
}
}
}
},
"cli": {
"analytics": false
"analytics": false,
"schematicCollections": ["@angular-eslint/schematics"]
}
}

3111
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -6,23 +6,25 @@
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
"test": "ng test",
"fmt": "prettier --write src",
"lint": "ng lint"
},
"private": true,
"dependencies": {
"@angular/animations": "^17.1.0",
"@angular/cdk": "^17.1.0",
"@angular/common": "^17.1.0",
"@angular/compiler": "^17.1.0",
"@angular/core": "^17.1.0",
"@angular/forms": "^17.1.0",
"@angular/platform-browser": "^17.1.0",
"@angular/platform-browser-dynamic": "^17.1.0",
"@angular/router": "^17.1.0",
"@angular/animations": "^17.1.1",
"@angular/cdk": "^17.1.1",
"@angular/common": "^17.1.1",
"@angular/compiler": "^17.1.1",
"@angular/core": "^17.1.1",
"@angular/forms": "^17.1.1",
"@angular/platform-browser": "^17.1.1",
"@angular/platform-browser-dynamic": "^17.1.1",
"@angular/router": "^17.1.1",
"@codemirror/lang-cpp": "^6.0.2",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0",
"@codemirror/view": "^6.23.1",
"@emailjs/browser": "^3.12.1",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
@ -35,16 +37,25 @@
"zone.js": "~0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.1.0",
"@angular/cli": "~17.1.0",
"@angular/compiler-cli": "^17.1.0",
"@angular-devkit/build-angular": "^17.1.1",
"@angular-eslint/builder": "17.2.1",
"@angular-eslint/eslint-plugin": "17.2.1",
"@angular-eslint/eslint-plugin-template": "17.2.1",
"@angular-eslint/schematics": "17.2.1",
"@angular-eslint/template-parser": "17.2.1",
"@angular/cli": "~17.1.1",
"@angular/compiler-cli": "^17.1.1",
"@types/jasmine": "~5.1.4",
"@typescript-eslint/eslint-plugin": "^6.20.0",
"@typescript-eslint/parser": "^6.20.0",
"eslint": "^8.56.0",
"jasmine-core": "~5.1.1",
"karma": "~6.4.2",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"prettier": "^3.2.4",
"typescript": "~5.3.3"
}
}

@ -2,8 +2,8 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EditorComponent } from './components/editor/editor.component';
import { LandingPageComponent } from './components/landing-page/landing-page.component';
import { DocumentationComponent } from "./components/documentation/documentation.component";
import { FormComponent } from "./components/form/form.component";
import { DocumentationComponent } from './components/documentation/documentation.component';
import { FormComponent } from './components/form/form.component';
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
import { OurStoryComponent } from './components/our-story/our-story.component';
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
@ -16,11 +16,11 @@ const routes: Routes = [
{ path: 'contact', component: FormComponent },
{ path: 'our-story', component: OurStoryComponent },
{ path: 'terms-of-service', component: TermsOfServiceComponent },
{ path: 'privacy-policy', component: PrivacyPolicyComponent }
{ path: 'privacy-policy', component: PrivacyPolicyComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
exports: [RouterModule],
})
export class AppRoutingModule {}

@ -1,7 +1,10 @@
<body [ngClass]="themeClass">
<div [ngClass]="themeClass" class="app">
<header>
<app-header [ngClass]="themeClass" [themeClass]="themeClass" [themeService]="themeService"></app-header>
<app-header
[ngClass]="themeClass"
[themeClass]="themeClass"
[themeService]="themeService"></app-header>
</header>
<main>
@ -11,6 +14,5 @@
<footer>
<app-footer></app-footer>
</footer>
</div>
</body>

@ -2,10 +2,11 @@
body {
overflow: hidden;
transition: background-color .3s ease-in-out, color .3s ease-in-out;
transition:
background-color 0.3s ease-in-out,
color 0.3s ease-in-out;
}
body.light-theme {
background-color: #ffffff;
color: #000000;

@ -3,9 +3,11 @@ import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [RouterTestingModule, AppComponent]
}));
beforeEach(() =>
TestBed.configureTestingModule({
imports: [RouterTestingModule, AppComponent],
})
);
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
@ -17,6 +19,8 @@ describe('AppComponent', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('sandkasten app is running!');
expect(compiled.querySelector('.content span')?.textContent).toContain(
'sandkasten app is running!'
);
});
});

@ -9,9 +9,8 @@ import { NgClass } from '@angular/common';
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
standalone: true,
imports: [NgClass, HeaderComponent, RouterOutlet, FooterComponent]
imports: [NgClass, HeaderComponent, RouterOutlet, FooterComponent],
})
export class AppComponent implements OnInit {
themeClass = 'light-theme';

@ -2,14 +2,35 @@
<h1 class="title">Documentation</h1>
<div class="how_it_works">
<h2 class="question">Comment fonctionne Sandkasten ?</h2>
<span class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in sagittis quam. Suspendisse eget posuere ligula, ut pretium sapien. Nulla vitae aliquam risus. Nulla facilisi. Cras sodales placerat elit, at ultricies dolor fringilla eget. Nullam sodales eros eget nisl dignissim, vel accumsan ligula euismod. Praesent congue placerat ullamcorper. Mauris at ante porttitor, maximus magna at, convallis velit.</span>
<span class="text"
>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in
sagittis quam. Suspendisse eget posuere ligula, ut pretium sapien. Nulla
vitae aliquam risus. Nulla facilisi. Cras sodales placerat elit, at
ultricies dolor fringilla eget. Nullam sodales eros eget nisl dignissim,
vel accumsan ligula euismod. Praesent congue placerat ullamcorper. Mauris
at ante porttitor, maximus magna at, convallis velit.</span
>
</div>
<div class="code_execution">
<h2 class="question">Exécution du code :</h2>
<span class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in sagittis quam. Suspendisse eget posuere ligula, ut pretium sapien. Nulla vitae aliquam risus. Nulla facilisi. Cras sodales placerat elit, at ultricies dolor fringilla eget. Nullam sodales eros eget nisl dignissim, vel accumsan ligula euismod. Praesent congue placerat ullamcorper. Mauris at ante porttitor, maximus magna at, convallis velit.</span>
<span class="text"
>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in
sagittis quam. Suspendisse eget posuere ligula, ut pretium sapien. Nulla
vitae aliquam risus. Nulla facilisi. Cras sodales placerat elit, at
ultricies dolor fringilla eget. Nullam sodales eros eget nisl dignissim,
vel accumsan ligula euismod. Praesent congue placerat ullamcorper. Mauris
at ante porttitor, maximus magna at, convallis velit.</span
>
</div>
<div class="code_transfert">
<h2 class="question">Transmission du code :</h2>
<span class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in sagittis quam. Suspendisse eget posuere ligula, ut pretium sapien. Nulla vitae aliquam risus. Nulla facilisi. Cras sodales placerat elit, at ultricies dolor fringilla eget. Nullam sodales eros eget nisl dignissim, vel accumsan ligula euismod. Praesent congue placerat ullamcorper. Mauris at ante porttitor, maximus magna at, convallis velit.</span>
<span class="text"
>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in
sagittis quam. Suspendisse eget posuere ligula, ut pretium sapien. Nulla
vitae aliquam risus. Nulla facilisi. Cras sodales placerat elit, at
ultricies dolor fringilla eget. Nullam sodales eros eget nisl dignissim,
vel accumsan ligula euismod. Praesent congue placerat ullamcorper. Mauris
at ante porttitor, maximus magna at, convallis velit.</span
>
</div>
</div>

@ -8,7 +8,9 @@
text-align: center;
}
.how_it_works, .code_execution, .code_transfert {
.how_it_works,
.code_execution,
.code_transfert {
display: flex;
flex-direction: column;

@ -8,7 +8,7 @@ describe('DocumentationComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [DocumentationComponent]
imports: [DocumentationComponent],
});
fixture = TestBed.createComponent(DocumentationComponent);
component = fixture.componentInstance;

@ -4,8 +4,6 @@ import { Component } from '@angular/core';
selector: 'app-documentation',
templateUrl: './documentation.component.html',
styleUrls: ['./documentation.component.scss'],
standalone: true
standalone: true,
})
export class DocumentationComponent {
}
export class DocumentationComponent {}

@ -2,8 +2,7 @@
<div>
<codemirror6-editor
[(ngModel)]="editorContent"
[extensions]="extensions"
></codemirror6-editor>
[extensions]="extensions"></codemirror6-editor>
</div>
<pre [innerHTML]="resultContent | safeHTML"></pre>

@ -8,7 +8,7 @@ describe('EditorComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [EditorComponent]
imports: [EditorComponent],
});
fixture = TestBed.createComponent(EditorComponent);
component = fixture.componentInstance;

@ -9,9 +9,9 @@ import { SafeHTMLPipe } from '../../safe-html.pipe';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
@Component({
selector: "app-editor",
templateUrl: "./editor.component.html",
styleUrls: ["./editor.component.scss"],
selector: 'app-editor',
templateUrl: './editor.component.html',
styleUrls: ['./editor.component.scss'],
standalone: true,
imports: [
CodeMirrorComponent,
@ -25,52 +25,56 @@ export class EditorComponent {
readonly languages: LanguageDescription[] = LANGUAGES;
// Mode par défaut
private _selectedLanguage = this.languages.find((lang) => lang.name === "JavaScript")!;
private _selectedLanguage = this.languages.find(
(lang) => lang.name === 'JavaScript'
)!;
get selectedLanguage(): LanguageDescription {
return this._selectedLanguage;
}
set selectedLanguage(value: LanguageDescription) {
this._selectedLanguage = value;
if (value.name in CODE_DEFAULTS) {
this.editorContent = CODE_DEFAULTS[value.name as keyof typeof CODE_DEFAULTS];
this.editorContent =
CODE_DEFAULTS[value.name as keyof typeof CODE_DEFAULTS];
}
this.selectedLanguage.load().then((language) => {
this.codemirror.editor?.dispatch({
effects: this.languageCompartment.reconfigure(language)
effects: this.languageCompartment.reconfigure(language),
});
});
}
// Contenu de l'éditeur que l'on passera au serveur
editorContent: string = CODE_DEFAULTS[this.selectedLanguage.name as keyof typeof CODE_DEFAULTS];
resultContent: string = "";
editorContent: string =
CODE_DEFAULTS[this.selectedLanguage.name as keyof typeof CODE_DEFAULTS];
resultContent: string = '';
// Message d'erreur
errorMessage: string = "";
errorMessage: string = '';
@ViewChild(CodeMirrorComponent) private codemirror!: CodeMirrorComponent;
private readonly languageCompartment = new Compartment();
protected readonly extensions: Extension[] = [
basicSetup,
this.languageCompartment.of(this.selectedLanguage.support!)
this.languageCompartment.of(this.selectedLanguage.support!),
];
constructor(
private codeExecutionService: CodeExecutionService
) {
}
constructor(private codeExecutionService: CodeExecutionService) {}
// Efface le contenu de l'éditeur
clear(): void {
this.editorContent = "";
this.editorContent = '';
}
onRunButtonClicked() {
// Le code à exécuter est le contenu de l'éditeur
const codeToExecute = this.editorContent;
this.codeExecutionService.executeCode(codeToExecute, this.selectedLanguage.name);
this.codeExecutionService.executeCode(
codeToExecute,
this.selectedLanguage.name
);
this.resultContent = '';
}
@ -78,7 +82,7 @@ export class EditorComponent {
loadFromFile(event: Event) {
const file = (event.target as HTMLInputElement).files![0];
for (const language of this.languages) {
if (language.extensions.some(ext => file.name.endsWith(`.${ext}`))) {
if (language.extensions.some((ext) => file.name.endsWith(`.${ext}`))) {
this.selectedLanguage = language;
const reader = new FileReader();
reader.onload = (event) => {
@ -89,9 +93,8 @@ export class EditorComponent {
return;
}
}
const extensions = this.languages.flatMap(lang => lang.extensions);
this.errorMessage =
`Unsupported language. Please select one of the following languages: ${extensions.join(', ')}.`;
const extensions = this.languages.flatMap((lang) => lang.extensions);
this.errorMessage = `Unsupported language. Please select one of the following languages: ${extensions.join(', ')}.`;
console.error(this.errorMessage);
}

@ -1,12 +1,19 @@
<head>
<link href="https://fonts.googleapis.com/css2?family=Podkova:wght@400;700&display=swap" rel="stylesheet">
<link
href="https://fonts.googleapis.com/css2?family=Podkova:wght@400;700&display=swap"
rel="stylesheet" />
</head>
<div class="footer">
<!--Logo and copyrights-->
<div class="rights">
<img class="sandkasten-logo" routerLink="" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }"
[src]="sandkasten_logo" alt="Logo-Sandkasten" />
<img
class="sandkasten-logo"
routerLink=""
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
[src]="sandkasten_logo"
alt="Logo-Sandkasten" />
<div class="title">Sandkasten</div>
<div class="copyright">{{ 'FooterPage.Rights' | translate }}</div>
</div>
@ -17,20 +24,36 @@
<span class="title">{{ 'FooterPage.About' | translate }}</span>
<div class="links">
<!-- TODO - Add the router links -->
<a routerLink="our-story" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">{{
'FooterPage.Story' | translate}}</a>
<a routerLink="" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">{{
'FooterPage.Contact' | translate}}</a>
<a
routerLink="our-story"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'FooterPage.Story' | translate }}</a
>
<a
routerLink=""
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'FooterPage.Contact' | translate }}</a
>
</div>
</div>
<div class="legals">
<span class="title">{{ 'FooterPage.Legal' | translate }}</span>
<div class="links">
<a routerLink="terms-of-service" routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }">{{ 'FooterPage.Terms' | translate}}</a>
<a routerLink="privacy-policy" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">{{
'FooterPage.Privacy' | translate}}</a>
<a
routerLink="terms-of-service"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'FooterPage.Terms' | translate }}</a
>
<a
routerLink="privacy-policy"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'FooterPage.Privacy' | translate }}</a
>
</div>
</div>
</div>
@ -38,19 +61,36 @@
<!--Socials-->
<div class="socials">
<a href="https://twitter.com/Sandkasten3a">
<img class="tiwtter-logo" class="image" routerLink="" routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }" [src]="twitter_logo" alt="Logo-Twitter" />
<img
class="tiwtter-logo"
class="image"
routerLink=""
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
[src]="twitter_logo"
alt="Logo-Twitter" />
</a>
<a href="https://instagram.com">
<img class="instagram-logo" class="image" routerLink="" routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }" [src]="instagram_logo" alt="Logo-Instagram" />
<img
class="instagram-logo"
class="image"
routerLink=""
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
[src]="instagram_logo"
alt="Logo-Instagram" />
</a>
<a href="https://www.facebook.com/profile.php?id=61555217444337">
<img class="facebook-logo" class="image" routerLink="" routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }" [src]="facebook_logo" alt="Logo-Facebook" />
<img
class="facebook-logo"
class="image"
routerLink=""
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
[src]="facebook_logo"
alt="Logo-Facebook" />
</a>
</div>
</div>

@ -1,6 +1,6 @@
.footer {
background-color: #494b92;
padding: .5rem 1rem;
padding: 0.5rem 1rem;
display: flex;
flex-direction: row;
justify-content: space-between;
@ -10,8 +10,8 @@
.rights {
display: grid;
grid: 'logo title' auto 'copyright copyright' / auto 1fr;
gap: .5rem;
color: #FFFFFF;
gap: 0.5rem;
color: #ffffff;
.sandkasten-logo {
grid-area: logo;
@ -48,27 +48,26 @@
.legals {
display: flex;
flex-direction: column;
gap: .5rem;
gap: 0.5rem;
.title {
color: #FFFFFF;
color: #ffffff;
text-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
}
.links {
display: flex;
flex-direction: column;
gap: .25rem;
gap: 0.25rem;
> a {
color: #818181;
text-decoration: none;
transition: color .3s ease;
transition: color 0.3s ease;
}
:hover {
color: #FFFFFF;
color: #ffffff;
}
}
}

@ -8,7 +8,7 @@ describe('FooterComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [FooterComponent]
imports: [FooterComponent],
});
fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { RouterLink, RouterLinkActive } from '@angular/router';
@ -7,12 +7,11 @@ import { RouterLink, RouterLinkActive } from '@angular/router';
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.scss'],
standalone: true,
imports: [RouterLink, RouterLinkActive, TranslateModule]
imports: [RouterLink, RouterLinkActive, TranslateModule],
})
export class FooterComponent {
sandkasten_logo: string = 'assets/img/logo.png';
twitter_logo: string = 'assets/img/twitter.svg';
instagram_logo: string = 'assets/img/instagram.svg';
facebook_logo: string = 'assets/img/facebook.svg';
}

@ -4,28 +4,55 @@
<div [formGroup]="form" class="form">
<div>
<!-- <label for="name">Nom</label>-->
<input type="text" id="name" name="name" placeholder="Votre nom" required formControlName="from_name">
<input
type="text"
id="name"
name="name"
placeholder="Votre nom"
required
formControlName="from_name" />
</div>
<div>
<!-- <label for="email">Email</label>-->
<input type="email" id="email" name="email" placeholder="Votre email" required formControlName="from_email">
<input
type="email"
id="email"
name="email"
placeholder="Votre email"
required
formControlName="from_email" />
</div>
<div>
<!-- <label for="subject">Sujet</label>-->
<input type="text" id="subject" name="subject" placeholder="Sujet" required formControlName="subject">
<input
type="text"
id="subject"
name="subject"
placeholder="Sujet"
required
formControlName="subject" />
</div>
<div>
<!-- <label for="message">Message</label>-->
<textarea id="message" name="message" placeholder="Votre message" required formControlName="message"></textarea>
<textarea
id="message"
name="message"
placeholder="Votre message"
required
formControlName="message"></textarea>
</div>
<div class="submit_button">
<button class="submit_btn" type="submit" (click)="send()" [disabled]="!form.valid">Envoyer</button>
<button
class="submit_btn"
type="submit"
(click)="send()"
[disabled]="!form.valid">
Envoyer
</button>
</div>
</div>
</div>

@ -16,7 +16,8 @@
width: 100%;
max-width: 600px;
& input, & textarea {
& input,
& textarea {
width: 100%;
min-height: 2rem;
}
@ -32,7 +33,7 @@
& button {
border: none;
background-color: #1976D2;
background-color: #1976d2;
color: white;
border-radius: 10px;
width: 80%;
@ -41,13 +42,12 @@
text-transform: uppercase;
cursor: pointer;
transition: scale .3s ease-in-out;
transition: scale 0.3s ease-in-out;
&:hover {
scale: 1.05;
}
}
}
}
}

@ -8,7 +8,7 @@ describe('FormComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [FormComponent]
imports: [FormComponent],
});
fixture = TestBed.createComponent(FormComponent);
component = fixture.componentInstance;
@ -19,4 +19,3 @@ describe('FormComponent', () => {
expect(component).toBeTruthy();
});
});

@ -8,7 +8,7 @@ import emailjs from '@emailjs/browser';
templateUrl: './form.component.html',
styleUrls: ['./form.component.scss'],
standalone: true,
imports: [ReactiveFormsModule]
imports: [ReactiveFormsModule],
})
export class FormComponent {
form: FormGroup;
@ -19,24 +19,28 @@ export class FormComponent {
to_name: ['Sandkasten'],
from_email: [''],
subject: [''],
message: ['']
message: [''],
});
}
async send() {
emailjs.init('cLIr6GuwhkrH1JFio');
try {
let response = await emailjs.send("service_rvmwu94", "template_q0spe61", {
const response = await emailjs.send(
'service_rvmwu94',
'template_q0spe61',
{
from_name: this.form.value.from_name,
to_name: this.form.value.to_name,
message: this.form.value.message,
from_email: this.form.value.from_email,
subject: this.form.value.subject,
});
}
);
console.log("Envoi du message:", response);
console.log('Envoi du message:', response);
alert("Message envoyé avec succès !");
alert('Message envoyé avec succès !');
this.form.reset();
} catch (error) {
console.error("Erreur lors de l'envoi du message:", error);

@ -1,16 +1,23 @@
<div class="header" role="banner" [ngClass]="themeClass">
<div class="left_part">
<div class="left_part__logo--container">
<img class="left_part__logo--sandkasten"
routerLink=""
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
[src]="sandkasten_logo" alt="Logo-Sandkasten" />
<a routerLink="/" routerLinkActive="active">
<img
class="left_part__logo--sandkasten"
ngSrc="assets/img/logo.png"
width="64"
height="64"
alt="Logo Sandkasten" />
</a>
</div>
</div>
<div class="right_part">
<div class="right_part--menu_mobile" (click)="openCloseMenu(); $event.stopPropagation();">
<div
class="right_part--menu_mobile"
(click)="openCloseMenu()"
(keydown)="openCloseMenu()"
tabindex="0">
Menu
</div>
@ -19,26 +26,33 @@
routerLink="editor"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'HeaderPage.Editor' | translate }}</a>
>{{ 'HeaderPage.Editor' | translate }}</a
>
<a
routerLink="documentation"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'HeaderPage.Documentation' | translate }}</a>
>{{ 'HeaderPage.Documentation' | translate }}</a
>
<a
routerLink="contact"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'HeaderPage.Contact' | translate }}</a>
>{{ 'HeaderPage.Contact' | translate }}</a
>
</nav>
<div class="right_part--bottom">
<div class="right_part--toggles">
<div class="wrapper">
<div class="toggle">
<input class="toggle-input" type="checkbox" (click)="toggleTheme()" [checked]="isCheck"/>
<input
class="toggle-input"
type="checkbox"
(click)="toggleTheme()"
[checked]="isCheck" />
<div class="toggle-bg"></div>
<div class="toggle-switch">
<div class="toggle-switch-figure"></div>
@ -57,9 +71,16 @@
<!--Login-->
<div class="right_part__connexion--login">
<span>Log In</span>
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_67_222)">
<path d="M15 28.8462C11.4456 28.8462 8.214 27.495 5.7624 25.2936C7.1148 22.0764 10.2576 20.3334 14.9862 20.3334C19.7196 20.3334 22.8696 22.1598 24.231 25.3842C21.7806 27.5796 18.5484 28.8462 15 28.8462ZM15.1668 7.6662C18.123 7.6662 20.3334 9.9534 20.3334 12.993C20.3334 16.119 18.0084 18.6666 15.1668 18.6666C12.3252 18.6666 10.0002 16.119 10.0002 12.993C10.0002 9.9534 12.2106 7.6662 15.1668 7.6662ZM15 0C6.7158 0 0 6.7158 0 15C0 15.549 0.0336 16.0896 0.0912 16.623C0.1104 16.8 0.1458 16.9716 0.171 17.1468C0.222 17.5002 0.2748 17.8524 0.3498 18.1974C0.3936 18.4002 0.4512 18.5964 0.5034 18.7956C0.5844 19.1046 0.6672 19.4118 0.7668 19.713C0.8352 19.9182 0.9126 20.118 0.9888 20.319C1.0968 20.6046 1.2102 20.886 1.335 21.1626C1.4244 21.3612 1.5198 21.5568 1.6182 21.7506C1.7532 22.0182 1.896 22.2804 2.0466 22.5384C2.1558 22.7256 2.2656 22.9098 2.3826 23.0916C2.5458 23.3454 2.7186 23.5908 2.8962 23.8338C3.0204 24.0042 3.1422 24.1746 3.2736 24.3384C3.4686 24.5832 3.6762 24.816 3.8856 25.0476C4.0176 25.194 4.1448 25.344 4.2828 25.4844C4.5258 25.7334 4.7826 25.965 5.0418 26.196C5.1456 26.2884 5.2392 26.391 5.346 26.481L5.3484 26.4744C8.04719 28.7544 11.467 30.0036 15 30C18.5284 30.004 21.9442 28.7581 24.6414 26.4834C24.6421 26.4854 24.6427 26.4874 24.6432 26.4894C24.7464 26.403 24.8376 26.304 24.9372 26.2146C25.2024 25.9794 25.4652 25.7424 25.713 25.4892C25.8498 25.35 25.9752 25.2018 26.106 25.0572C26.3172 24.8238 26.5266 24.5892 26.7228 24.3426C26.8536 24.1794 26.9754 24.009 27.099 23.8398C27.2772 23.5968 27.4512 23.3502 27.6144 23.0958C28.0087 22.4779 28.3592 21.8331 28.6632 21.1662C28.788 20.8896 28.902 20.6082 29.0106 20.3226C29.0868 20.121 29.1642 19.9212 29.232 19.7154C29.3322 19.4142 29.415 19.107 29.496 18.7974C29.5482 18.5982 29.6058 18.402 29.6496 18.1998C29.7252 17.8542 29.778 17.5014 29.829 17.1474C29.8542 16.9722 29.8896 16.8012 29.9088 16.6242C29.9658 16.0902 30 15.5496 30 15C30 6.7158 23.2842 0 15 0Z" fill="#605FFC"/>
<path
d="M15 28.8462C11.4456 28.8462 8.214 27.495 5.7624 25.2936C7.1148 22.0764 10.2576 20.3334 14.9862 20.3334C19.7196 20.3334 22.8696 22.1598 24.231 25.3842C21.7806 27.5796 18.5484 28.8462 15 28.8462ZM15.1668 7.6662C18.123 7.6662 20.3334 9.9534 20.3334 12.993C20.3334 16.119 18.0084 18.6666 15.1668 18.6666C12.3252 18.6666 10.0002 16.119 10.0002 12.993C10.0002 9.9534 12.2106 7.6662 15.1668 7.6662ZM15 0C6.7158 0 0 6.7158 0 15C0 15.549 0.0336 16.0896 0.0912 16.623C0.1104 16.8 0.1458 16.9716 0.171 17.1468C0.222 17.5002 0.2748 17.8524 0.3498 18.1974C0.3936 18.4002 0.4512 18.5964 0.5034 18.7956C0.5844 19.1046 0.6672 19.4118 0.7668 19.713C0.8352 19.9182 0.9126 20.118 0.9888 20.319C1.0968 20.6046 1.2102 20.886 1.335 21.1626C1.4244 21.3612 1.5198 21.5568 1.6182 21.7506C1.7532 22.0182 1.896 22.2804 2.0466 22.5384C2.1558 22.7256 2.2656 22.9098 2.3826 23.0916C2.5458 23.3454 2.7186 23.5908 2.8962 23.8338C3.0204 24.0042 3.1422 24.1746 3.2736 24.3384C3.4686 24.5832 3.6762 24.816 3.8856 25.0476C4.0176 25.194 4.1448 25.344 4.2828 25.4844C4.5258 25.7334 4.7826 25.965 5.0418 26.196C5.1456 26.2884 5.2392 26.391 5.346 26.481L5.3484 26.4744C8.04719 28.7544 11.467 30.0036 15 30C18.5284 30.004 21.9442 28.7581 24.6414 26.4834C24.6421 26.4854 24.6427 26.4874 24.6432 26.4894C24.7464 26.403 24.8376 26.304 24.9372 26.2146C25.2024 25.9794 25.4652 25.7424 25.713 25.4892C25.8498 25.35 25.9752 25.2018 26.106 25.0572C26.3172 24.8238 26.5266 24.5892 26.7228 24.3426C26.8536 24.1794 26.9754 24.009 27.099 23.8398C27.2772 23.5968 27.4512 23.3502 27.6144 23.0958C28.0087 22.4779 28.3592 21.8331 28.6632 21.1662C28.788 20.8896 28.902 20.6082 29.0106 20.3226C29.0868 20.121 29.1642 19.9212 29.232 19.7154C29.3322 19.4142 29.415 19.107 29.496 18.7974C29.5482 18.5982 29.6058 18.402 29.6496 18.1998C29.7252 17.8542 29.778 17.5014 29.829 17.1474C29.8542 16.9722 29.8896 16.8012 29.9088 16.6242C29.9658 16.0902 30 15.5496 30 15C30 6.7158 23.2842 0 15 0Z"
fill="#605FFC" />
</g>
<defs>
<clipPath id="clip0_67_222">
@ -75,12 +96,16 @@
</div>
</div>
</div>
<div class="mobile_menu" [ngClass]="{'opened': isMenuOpen}" #menuRef>
<div class="mobile_menu" [ngClass]="{ opened: isMenuOpen }" #menuRef>
<div class="mobile_menu--wrapper">
<div class="mobile_menu--toggles">
<div class="wrapper">
<div class="toggle">
<input class="toggle-input" type="checkbox" (click)="toggleTheme()" [checked]="isCheck"/>
<input
class="toggle-input"
type="checkbox"
(click)="toggleTheme()"
[checked]="isCheck" />
<div class="toggle-bg"></div>
<div class="toggle-switch">
<div class="toggle-switch-figure"></div>
@ -98,27 +123,37 @@
routerLink="editor"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'HeaderPage.Editor' | translate }}</a>
>{{ 'HeaderPage.Editor' | translate }}</a
>
<a
routerLink="documentation"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'HeaderPage.Documentation' | translate }}</a>
>{{ 'HeaderPage.Documentation' | translate }}</a
>
<a
routerLink="contact"
routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }"
>{{ 'HeaderPage.Contact' | translate }}</a>
>{{ 'HeaderPage.Contact' | translate }}</a
>
</nav>
<div class="mobile_menu__connexion">
<!--Login-->
<div class="right_part__connexion--login">
<span>Log In</span>
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="30"
height="30"
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_67_222)">
<path d="M15 28.8462C11.4456 28.8462 8.214 27.495 5.7624 25.2936C7.1148 22.0764 10.2576 20.3334 14.9862 20.3334C19.7196 20.3334 22.8696 22.1598 24.231 25.3842C21.7806 27.5796 18.5484 28.8462 15 28.8462ZM15.1668 7.6662C18.123 7.6662 20.3334 9.9534 20.3334 12.993C20.3334 16.119 18.0084 18.6666 15.1668 18.6666C12.3252 18.6666 10.0002 16.119 10.0002 12.993C10.0002 9.9534 12.2106 7.6662 15.1668 7.6662ZM15 0C6.7158 0 0 6.7158 0 15C0 15.549 0.0336 16.0896 0.0912 16.623C0.1104 16.8 0.1458 16.9716 0.171 17.1468C0.222 17.5002 0.2748 17.8524 0.3498 18.1974C0.3936 18.4002 0.4512 18.5964 0.5034 18.7956C0.5844 19.1046 0.6672 19.4118 0.7668 19.713C0.8352 19.9182 0.9126 20.118 0.9888 20.319C1.0968 20.6046 1.2102 20.886 1.335 21.1626C1.4244 21.3612 1.5198 21.5568 1.6182 21.7506C1.7532 22.0182 1.896 22.2804 2.0466 22.5384C2.1558 22.7256 2.2656 22.9098 2.3826 23.0916C2.5458 23.3454 2.7186 23.5908 2.8962 23.8338C3.0204 24.0042 3.1422 24.1746 3.2736 24.3384C3.4686 24.5832 3.6762 24.816 3.8856 25.0476C4.0176 25.194 4.1448 25.344 4.2828 25.4844C4.5258 25.7334 4.7826 25.965 5.0418 26.196C5.1456 26.2884 5.2392 26.391 5.346 26.481L5.3484 26.4744C8.04719 28.7544 11.467 30.0036 15 30C18.5284 30.004 21.9442 28.7581 24.6414 26.4834C24.6421 26.4854 24.6427 26.4874 24.6432 26.4894C24.7464 26.403 24.8376 26.304 24.9372 26.2146C25.2024 25.9794 25.4652 25.7424 25.713 25.4892C25.8498 25.35 25.9752 25.2018 26.106 25.0572C26.3172 24.8238 26.5266 24.5892 26.7228 24.3426C26.8536 24.1794 26.9754 24.009 27.099 23.8398C27.2772 23.5968 27.4512 23.3502 27.6144 23.0958C28.0087 22.4779 28.3592 21.8331 28.6632 21.1662C28.788 20.8896 28.902 20.6082 29.0106 20.3226C29.0868 20.121 29.1642 19.9212 29.232 19.7154C29.3322 19.4142 29.415 19.107 29.496 18.7974C29.5482 18.5982 29.6058 18.402 29.6496 18.1998C29.7252 17.8542 29.778 17.5014 29.829 17.1474C29.8542 16.9722 29.8896 16.8012 29.9088 16.6242C29.9658 16.0902 30 15.5496 30 15C30 6.7158 23.2842 0 15 0Z" fill="#605FFC"/>
<path
d="M15 28.8462C11.4456 28.8462 8.214 27.495 5.7624 25.2936C7.1148 22.0764 10.2576 20.3334 14.9862 20.3334C19.7196 20.3334 22.8696 22.1598 24.231 25.3842C21.7806 27.5796 18.5484 28.8462 15 28.8462ZM15.1668 7.6662C18.123 7.6662 20.3334 9.9534 20.3334 12.993C20.3334 16.119 18.0084 18.6666 15.1668 18.6666C12.3252 18.6666 10.0002 16.119 10.0002 12.993C10.0002 9.9534 12.2106 7.6662 15.1668 7.6662ZM15 0C6.7158 0 0 6.7158 0 15C0 15.549 0.0336 16.0896 0.0912 16.623C0.1104 16.8 0.1458 16.9716 0.171 17.1468C0.222 17.5002 0.2748 17.8524 0.3498 18.1974C0.3936 18.4002 0.4512 18.5964 0.5034 18.7956C0.5844 19.1046 0.6672 19.4118 0.7668 19.713C0.8352 19.9182 0.9126 20.118 0.9888 20.319C1.0968 20.6046 1.2102 20.886 1.335 21.1626C1.4244 21.3612 1.5198 21.5568 1.6182 21.7506C1.7532 22.0182 1.896 22.2804 2.0466 22.5384C2.1558 22.7256 2.2656 22.9098 2.3826 23.0916C2.5458 23.3454 2.7186 23.5908 2.8962 23.8338C3.0204 24.0042 3.1422 24.1746 3.2736 24.3384C3.4686 24.5832 3.6762 24.816 3.8856 25.0476C4.0176 25.194 4.1448 25.344 4.2828 25.4844C4.5258 25.7334 4.7826 25.965 5.0418 26.196C5.1456 26.2884 5.2392 26.391 5.346 26.481L5.3484 26.4744C8.04719 28.7544 11.467 30.0036 15 30C18.5284 30.004 21.9442 28.7581 24.6414 26.4834C24.6421 26.4854 24.6427 26.4874 24.6432 26.4894C24.7464 26.403 24.8376 26.304 24.9372 26.2146C25.2024 25.9794 25.4652 25.7424 25.713 25.4892C25.8498 25.35 25.9752 25.2018 26.106 25.0572C26.3172 24.8238 26.5266 24.5892 26.7228 24.3426C26.8536 24.1794 26.9754 24.009 27.099 23.8398C27.2772 23.5968 27.4512 23.3502 27.6144 23.0958C28.0087 22.4779 28.3592 21.8331 28.6632 21.1662C28.788 20.8896 28.902 20.6082 29.0106 20.3226C29.0868 20.121 29.1642 19.9212 29.232 19.7154C29.3322 19.4142 29.415 19.107 29.496 18.7974C29.5482 18.5982 29.6058 18.402 29.6496 18.1998C29.7252 17.8542 29.778 17.5014 29.829 17.1474C29.8542 16.9722 29.8896 16.8012 29.9088 16.6242C29.9658 16.0902 30 15.5496 30 15C30 6.7158 23.2842 0 15 0Z"
fill="#605FFC" />
</g>
<defs>
<clipPath id="clip0_67_222">
@ -135,4 +170,3 @@
</div>
</div>
</div>

@ -1,14 +1,14 @@
@import '../../../styles';
//region Colors
$color-sun: #E4C74D;
$color-cloud-inner: #FFFFFF;
$color-cloud-outer: #D4D4D2;
$color-parent-outer: #81C0D5;
$color-parent-inner: #C0E6F6;
$color-moon-inner: #FFFDF2;
$color-moon-outer: #DEE1C5;
$color-stars: #FCFCFC;
$color-sun: #e4c74d;
$color-cloud-inner: #ffffff;
$color-cloud-outer: #d4d4d2;
$color-parent-outer: #81c0d5;
$color-parent-inner: #c0e6f6;
$color-moon-inner: #fffdf2;
$color-moon-outer: #dee1c5;
$color-stars: #fcfcfc;
// endregion
//region Mixins
@ -19,7 +19,7 @@ $color-stars: #FCFCFC;
left: $left;
width: $size;
height: $size;
background-color: #EFEEDA;
background-color: #efeeda;
border-radius: 100%;
border: 4px solid $color-moon-outer;
}
@ -41,7 +41,7 @@ $color-stars: #FCFCFC;
}
//endregion
$theme-transition: all .3s ease-in-out;
$theme-transition: all 0.3s ease-in-out;
.header {
position: relative;
@ -72,7 +72,8 @@ $theme-transition: all .3s ease-in-out;
}
}
.right_part, .mobile_menu {
.right_part,
.mobile_menu {
// Dark mode button
.wrapper {
text-align: center;
@ -85,7 +86,8 @@ $theme-transition: all .3s ease-in-out;
border-radius: 40px;
}
&:before, &:after {
&:before,
&:after {
content: '';
display: table;
}
@ -103,7 +105,7 @@ $theme-transition: all .3s ease-in-out;
background-color: $color-parent-inner;
border-radius: 40px;
border: 4px solid $color-parent-outer;
transition: all .1s cubic-bezier(0.250, 0.460, 0.450, 0.940);
transition: all 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.toggle-input {
@ -144,10 +146,10 @@ $theme-transition: all .3s ease-in-out;
width: 30px;
height: 30px;
margin-left: 60px;
background-color: #F5EB42;
background-color: #f5eb42;
border: 4px solid $color-sun;
border-radius: 50%;
transition: all .1s cubic-bezier(0.250, 0.460, 0.450, 0.940);
transition: all 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
.toggle-switch-figure {
position: absolute;
@ -160,7 +162,7 @@ $theme-transition: all .3s ease-in-out;
border-radius: 20px;
background-color: #fff;
transform: scale(0.4);
transition: all .12s cubic-bezier(0.250, 0.460, 0.450, 0.940);
transition: all 0.12s cubic-bezier(0.25, 0.46, 0.45, 0.94);
&:after {
@include cloudBubble(-65px, -42px, 15px, 15px, 70deg);
}
@ -181,7 +183,7 @@ $theme-transition: all .3s ease-in-out;
44px 23px 0 -2px $color-stars,
78px 21px 0 -3px $color-stars;
transition: all .12s cubic-bezier(0.250, 0.460, 0.450, 0.940);
transition: all 0.12s cubic-bezier(0.25, 0.46, 0.45, 0.94);
transform: scale(0);
&:before {
@ -250,7 +252,7 @@ $theme-transition: all .3s ease-in-out;
cursor: pointer;
display: flex;
align-items: center;
gap: .5rem;
gap: 0.5rem;
color: $color-purple;
white-space: nowrap;
@ -260,10 +262,10 @@ $theme-transition: all .3s ease-in-out;
cursor: pointer;
border: 1px solid $color-black;
border-radius: 10px;
padding: .75rem 2rem;
padding: 0.75rem 2rem;
white-space: nowrap;
transition: border .3s ease-in-out;
transition: border 0.3s ease-in-out;
}
}
}
@ -278,7 +280,10 @@ $theme-transition: all .3s ease-in-out;
transform: translateX(100%);
z-index: 99;
transition: transform .3s ease-in-out, box-shadow .3s ease-in-out, background .3s ease-in-out;
transition:
transform 0.3s ease-in-out,
box-shadow 0.3s ease-in-out,
background 0.3s ease-in-out;
&.opened {
transform: translateX(0);
@ -361,7 +366,6 @@ $theme-transition: all .3s ease-in-out;
}
}
@media (max-width: 1024px) {
.header {
.right_part {
@ -393,5 +397,3 @@ $theme-transition: all .3s ease-in-out;
}
}
}

@ -8,7 +8,7 @@ describe('HeaderComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HeaderComponent]
imports: [HeaderComponent],
});
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;

@ -1,22 +1,34 @@
import {Component, ElementRef, HostListener, Input, OnInit, ViewChild} from '@angular/core';
import {
Component,
ElementRef,
HostListener,
Input,
ViewChild,
} from '@angular/core';
import { TranslationService } from '../../services/translation.service';
import {ThemeService} from "../../services/theme.service";
import { ThemeService } from '../../services/theme.service';
import { TranslateModule } from '@ngx-translate/core';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterLink, RouterLinkActive } from '@angular/router';
import { NgClass } from '@angular/common';
import { NgClass, NgOptimizedImage } from '@angular/common';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
standalone: true,
imports: [NgClass, RouterLink, RouterLinkActive, ReactiveFormsModule, TranslateModule]
imports: [
NgClass,
RouterLink,
RouterLinkActive,
ReactiveFormsModule,
TranslateModule,
NgOptimizedImage,
],
})
export class HeaderComponent {
title: string = 'Sandkasten';
version: string = '1.0';
sandkasten_logo: string = 'assets/img/logo.png';
isMenuOpen: boolean = false;
isCheck: boolean = false;
@ViewChild('menuRef') menuRef!: ElementRef;
@ -24,19 +36,20 @@ export class HeaderComponent {
@Input() themeService!: ThemeService;
// Instanciation du service pour les actions de traduction
constructor(private translationService: TranslationService) {
}
constructor(private translationService: TranslationService) {}
// Méthode pour changer la langue
onLanguageChange(event: any) {
this.translationService.onLanguageChange(event);
onLanguageChange(event: Event) {
this.translationService.onLanguageChange(
(event.target as HTMLSelectElement).value as 'fr' | 'en'
);
}
toggleTheme() {
this.themeService.toggleDarkTheme();
this.themeService.isDarkTheme.subscribe(value => {
this.themeService.isDarkTheme.subscribe((value) => {
this.isCheck = value;
})
});
}
openCloseMenu() {
@ -44,7 +57,7 @@ export class HeaderComponent {
}
@HostListener('document:click', ['$event'])
clickout(event: any) {
clickout(event: MouseEvent) {
// If the menu is open and click is outside the menu, we close it
if (this.isMenuOpen && !this.menuRef.nativeElement.contains(event.target)) {
this.isMenuOpen = false;

@ -1,9 +1,13 @@
<div class="landing-page" [ngClass]="themeClass">
<div class="landing-page--container">
<h2 class="landing-page--title">{{ 'LandingPage.Welcome' | translate }}</h2>
<span class="landing-page--subtitle">{{ 'LandingPage.Description' | translate}}</span>
<span class="landing-page--subtitle">{{
'LandingPage.Description' | translate
}}</span>
<div class="landing-page__button">
<a class="landing-page__button--link" (click)="onContinue()">{{ 'LandingPage.Try' | translate}}</a>
<a class="landing-page__button--link" routerLink="/editor">{{
'LandingPage.Try' | translate
}}</a>
</div>
</div>
</div>

@ -7,8 +7,7 @@
gap: 2rem;
color: $color-black;
transition: color .3s ease-in-out;
transition: color 0.3s ease-in-out;
&--container {
display: flex;
@ -29,7 +28,7 @@
}
&__button {
padding: .75rem 2rem;
padding: 0.75rem 2rem;
background: $color-purple;
border-radius: 10px;
width: fit-content;
@ -56,7 +55,6 @@
}
}
&.dark-theme {
color: $color-white;
}

@ -8,7 +8,7 @@ describe('LandingPageComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [LandingPageComponent]
imports: [LandingPageComponent],
});
fixture = TestBed.createComponent(LandingPageComponent);
component = fixture.componentInstance;

@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import {ThemeService} from "../../services/theme.service";
import { Router, RouterLink } from '@angular/router';
import { ThemeService } from '../../services/theme.service';
import { TranslateModule } from '@ngx-translate/core';
import { NgClass } from '@angular/common';
@ -9,17 +9,22 @@ import { NgClass } from '@angular/common';
templateUrl: './landing-page.component.html',
styleUrls: ['./landing-page.component.scss'],
standalone: true,
imports: [NgClass, TranslateModule]
imports: [NgClass, TranslateModule, RouterLink],
})
export class LandingPageComponent implements OnInit {
themeClass!: string;
constructor(private router: Router, private themeService: ThemeService){}
constructor(
private router: Router,
private themeService: ThemeService
) {}
ngOnInit() {
this.themeService.isDarkTheme.subscribe(value => {
value ? this.themeClass = 'dark-theme' : this.themeClass = 'light-theme';
})
this.themeService.isDarkTheme.subscribe((value) => {
value
? (this.themeClass = 'dark-theme')
: (this.themeClass = 'light-theme');
});
}
// Si click sur "Run", on redirige vers la page d'édition
onContinue(): void {

@ -1,8 +1,8 @@
import {LanguageDescription} from "@codemirror/language";
import {javascript} from "@codemirror/lang-javascript";
import { LanguageDescription } from '@codemirror/language';
import { javascript } from '@codemirror/lang-javascript';
export const CODE_DEFAULTS = {
'C': /** @lang C */ `#include <stdio.h>
C: /** @lang C */ `#include <stdio.h>
int main() {
printf("Hello, World!\\n");
return 0;
@ -12,8 +12,8 @@ int main() {
std::cout << "Hello, World!\\n";
return 0;
}`,
'JavaScript': /** @lang JS */ `console.log("Hello, World!");`,
'TypeScript': /** @lang TS */ `console.log("Hello, World!");`
JavaScript: /** @lang JS */ `console.log("Hello, World!");`,
TypeScript: /** @lang TS */ `console.log("Hello, World!");`,
};
export const LANGUAGES = [
@ -21,16 +21,16 @@ export const LANGUAGES = [
name: 'C',
extensions: ['c', 'h', 'ino'],
load() {
return import("@codemirror/lang-cpp").then(m => m.cpp())
}
return import('@codemirror/lang-cpp').then((m) => m.cpp());
},
}),
LanguageDescription.of({
name: "C++",
name: 'C++',
alias: ['cpp'],
extensions: ['cpp', "c++", 'cc', 'cxx', 'hpp', "h++", 'hh', 'hxx'],
extensions: ['cpp', 'c++', 'cc', 'cxx', 'hpp', 'h++', 'hh', 'hxx'],
load() {
return import("@codemirror/lang-cpp").then(m => m.cpp())
}
return import('@codemirror/lang-cpp').then((m) => m.cpp());
},
}),
LanguageDescription.of({
name: 'JavaScript',
@ -43,7 +43,9 @@ export const LANGUAGES = [
alias: ['ts'],
extensions: ['ts'],
load() {
return import("@codemirror/lang-javascript").then(m => m.javascript({typescript: true}))
}
return import('@codemirror/lang-javascript').then((m) =>
m.javascript({ typescript: true })
);
},
}),
];

@ -1,31 +1,36 @@
<body>
<main>
<div>
<img class="colin"
[src]="colin" alt="Photo-Colin" />
<img class="colin" [src]="colin" alt="Photo-Colin" />
<h1>COLIN FRIZOT</h1>
<p>Bonjour, je suis Colin, un poisson développeur. (fraude)</p>
<img class="hugo"
[src]="hugo" alt="Photo-Hugo" />
<img class="hugo" [src]="hugo" alt="Photo-Hugo" />
<h1>HUGO PRADIER</h1>
<p>Bonjour, je suis Hugo, un développeur bientôt chauve. (suit tous les tutos en ligne, mais ça marche jamais)</p>
<p>
Bonjour, je suis Hugo, un développeur bientôt chauve. (suit tous les
tutos en ligne, mais ça marche jamais)
</p>
<img class="bastien"
[src]="bastien" alt="Photo-Bastien" />
<img class="bastien" [src]="bastien" alt="Photo-Bastien" />
<h1>BASTIEN OLLIER</h1>
<p>Bonjour, je suis Bastien, un développeur visuellement parlant, très puant. (connaît l'adresse de la grand-mère de Colin)</p>
<p>
Bonjour, je suis Bastien, un développeur visuellement parlant, très
puant. (connaît l'adresse de la grand-mère de Colin)
</p>
<img class="clement"
[src]="clement" alt="Photo-Clement" />
<img class="clement" [src]="clement" alt="Photo-Clement" />
<h1>CLÉMENT FRÉVILLE</h1>
<p>Bonjour, je suis Clément, un développeur meilleur que tes profs. (dieu)</p>
<p>
Bonjour, je suis Clément, un développeur meilleur que tes profs. (dieu)
</p>
<img class="matis"
[src]="matis" alt="Photo-Matis" />
<img class="matis" [src]="matis" alt="Photo-Matis" />
<h1>MATIS MAZINGUE</h1>
<p>Bonjour, je suis Matis, un "développeur". (est là que pour l'argent, mais il est nul)</p>
<p>
Bonjour, je suis Matis, un "développeur". (est là que pour l'argent,
mais il est nul)
</p>
</div>
</main>
</body>

@ -8,9 +8,8 @@ describe('OurStoryComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [OurStoryComponent]
})
.compileComponents();
imports: [OurStoryComponent],
}).compileComponents();
fixture = TestBed.createComponent(OurStoryComponent);
component = fixture.componentInstance;

@ -1,11 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-our-story',
templateUrl: './our-story.component.html',
styleUrl: './our-story.component.scss',
standalone: true
standalone: true,
})
export class OurStoryComponent {
constructor(private router: Router) {}

@ -1,57 +1,84 @@
<body>
<h1>{{ 'PrivacyPolicyPage.PrivacyPolicy' | translate }}</h1>
<p>{{ 'PrivacyPolicyPage.Promise' | translate}}<a href="https://www.sandkasten.fr">sandkasten.fr</a>
{{ 'PrivacyPolicyPage.PromisePart2' | translate}}</p>
<p>
{{ 'PrivacyPolicyPage.Promise' | translate
}}<a href="https://www.sandkasten.fr">sandkasten.fr</a>
{{ 'PrivacyPolicyPage.PromisePart2' | translate }}
</p>
<p>{{ 'PrivacyPolicyPage.Policy' | translate }}</p>
<div class="wpembed-toc">
<h3>{{ 'PrivacyPolicyPage.TableContents' | translate }}</h3>
<ol class="wpembed-toc">
<li>
<a href="#collection-of-personal-information">{{ 'PrivacyPolicyPage.PersonalInformation.Title' |
translate}}</a>
<a href="#collection-of-personal-information">{{
'PrivacyPolicyPage.PersonalInformation.Title' | translate
}}</a>
</li>
<li>
<a href="#privacy-of-children">{{ 'PrivacyPolicyPage.PrivacyChildren.Title' | translate}}</a>
<a href="#privacy-of-children">{{
'PrivacyPolicyPage.PrivacyChildren.Title' | translate
}}</a>
</li>
<li>
<a href="#use-and-processing-of-collected-information">{{ 'PrivacyPolicyPage.UseProcInformation.Title' |
translate}}</a>
<a href="#use-and-processing-of-collected-information">{{
'PrivacyPolicyPage.UseProcInformation.Title' | translate
}}</a>
</li>
<li>
<a href="#managing-information">{{ 'PrivacyPolicyPage.ManagingInformation.Title' | translate }}</a>
<a href="#managing-information">{{
'PrivacyPolicyPage.ManagingInformation.Title' | translate
}}</a>
</li>
<li>
<a href="#disclosure-of-information">{{ 'PrivacyPolicyPage.DisclosureInformation.Title' | translate
<a href="#disclosure-of-information">{{
'PrivacyPolicyPage.DisclosureInformation.Title' | translate
}}</a>
</li>
<li>
<a href="#retention-of-information">{{ 'PrivacyPolicyPage.RetentionInformation.Title' | translate }}</a>
<a href="#retention-of-information">{{
'PrivacyPolicyPage.RetentionInformation.Title' | translate
}}</a>
</li>
<li>
<a href="#do-not-track-signals">{{ 'PrivacyPolicyPage.DoNotTrack.Title' | translate}}</a>
<a href="#do-not-track-signals">{{
'PrivacyPolicyPage.DoNotTrack.Title' | translate
}}</a>
</li>
<li>
<a href="#links-to-other-resources">{{ 'PrivacyPolicyPage.LinksResources.Title' | translate}}</a>
<a href="#links-to-other-resources">{{
'PrivacyPolicyPage.LinksResources.Title' | translate
}}</a>
</li>
<li>
<a href="#information-security">{{ 'PrivacyPolicyPage.InformationSecurity.Title' | translate}}</a>
<a href="#information-security">{{
'PrivacyPolicyPage.InformationSecurity.Title' | translate
}}</a>
</li>
<li>
<a href="#data-breach">{{ 'PrivacyPolicyPage.DataBreach.Title' | translate}}</a>
<a href="#data-breach">{{
'PrivacyPolicyPage.DataBreach.Title' | translate
}}</a>
</li>
<li>
<a href="#changes-and-amendments">{{ 'PrivacyPolicyPage.Amendments.Title' | translate}}</a>
<a href="#changes-and-amendments">{{
'PrivacyPolicyPage.Amendments.Title' | translate
}}</a>
</li>
<li>
<a href="#acceptance-of-this-policy">{{ 'PrivacyPolicyPage.Acceptance.Title' | translate}}</a>
<a href="#acceptance-of-this-policy">{{
'PrivacyPolicyPage.Acceptance.Title' | translate
}}</a>
</li>
<li>
<a href="#contacting-us">{{ 'PrivacyPolicyPage.ContactingUs.Title' | translate}}</a>
<a href="#contacting-us">{{
'PrivacyPolicyPage.ContactingUs.Title' | translate
}}</a>
</li>
</ol>
</div>
<h2 id="collection-of-personal-information">{{ 'PrivacyPolicyPage.PersonalInformation.Title' | translate}}</h2>
<h2 id="collection-of-personal-information">
{{ 'PrivacyPolicyPage.PersonalInformation.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.PersonalInformation.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.PersonalInformation.Text2' | translate }}</p>
<ul>
@ -60,10 +87,13 @@
</ul>
<p>{{ 'PrivacyPolicyPage.PersonalInformation.Text5' | translate }}</p>
<h2 id="privacy-of-children">{{ 'PrivacyPolicyPage.PrivacyChildren.Title' | translate}}</h2>
<h2 id="privacy-of-children">
{{ 'PrivacyPolicyPage.PrivacyChildren.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.PrivacyChildren.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.PrivacyChildren.Text2' | translate }}</p>
<h2 id="use-and-processing-of-collected-information">{{ 'PrivacyPolicyPage.UseProcInformation.Title' | translate}}
<h2 id="use-and-processing-of-collected-information">
{{ 'PrivacyPolicyPage.UseProcInformation.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.UseProcInformation.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.UseProcInformation.Text2' | translate }}</p>
@ -78,43 +108,73 @@
<p>{{ 'PrivacyPolicyPage.UseProcInformation.Text5' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.UseProcInformation.Text6' | translate }}</p>
<h2 id="managing-information">{{ 'PrivacyPolicyPage.ManagingInformation.Title' | translate}}</h2>
<h2 id="managing-information">
{{ 'PrivacyPolicyPage.ManagingInformation.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.ManagingInformation.Text1' | translate }}</p>
<h2 id="disclosure-of-information">{{ 'PrivacyPolicyPage.DisclosureInformation.Title' | translate}}</h2>
<h2 id="disclosure-of-information">
{{ 'PrivacyPolicyPage.DisclosureInformation.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.DisclosureInformation.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.DisclosureInformation.Text2' | translate }}</p>
<h2 id="retention-of-information">{{ 'PrivacyPolicyPage.RetentionInformation.Title' | translate }}</h2>
<h2 id="retention-of-information">
{{ 'PrivacyPolicyPage.RetentionInformation.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.RetentionInformation.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.RetentionInformation.Text2' | translate }}</p>
<h2 id="do-not-track-signals">{{ 'PrivacyPolicyPage.DoNotTrack.Title' | translate}}</h2>
<p>{{ 'PrivacyPolicyPage.DoNotTrack.Text1' | translate}}<a href="https://www.internetcookies.com" target="_blank"
ref="nofollow noreferrer noopener external">internetcookies.com</a></p>
<h2 id="do-not-track-signals">
{{ 'PrivacyPolicyPage.DoNotTrack.Title' | translate }}
</h2>
<p>
{{ 'PrivacyPolicyPage.DoNotTrack.Text1' | translate
}}<a
href="https://www.internetcookies.com"
target="_blank"
ref="nofollow noreferrer noopener external"
>internetcookies.com</a
>
</p>
<h2 id="links-to-other-resources">{{ 'PrivacyPolicyPage.LinksResources.Title' | translate}}</h2>
<h2 id="links-to-other-resources">
{{ 'PrivacyPolicyPage.LinksResources.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.LinksResources.Text1' | translate }}</p>
<h2 id="information-security">{{ 'PrivacyPolicyPage.InformationSecurity.Title' | translate}}</h2>
<h2 id="information-security">
{{ 'PrivacyPolicyPage.InformationSecurity.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.InformationSecurity.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.InformationSecurity.Text2' | translate}}/p>
<p>{{ 'PrivacyPolicyPage.InformationSecurity.Text2' | translate }}/p></p>
<p>{{ 'PrivacyPolicyPage.InformationSecurity.Text3' | translate }}</p>
<h2 id="data-breach">{{ 'PrivacyPolicyPage.DataBreach.Title' | translate}}</h2>
<h2 id="data-breach">
{{ 'PrivacyPolicyPage.DataBreach.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.DataBreach.Text1' | translate }}</p>
<h2 id="changes-and-amendments">{{ 'PrivacyPolicyPage.Amendments.Title' | translate}}</h2>
<h2 id="changes-and-amendments">
{{ 'PrivacyPolicyPage.Amendments.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.Amendments.Text1' | translate }}</p>
<p>{{ 'PrivacyPolicyPage.Amendments.Text2' | translate }}</p>
<h2 id="acceptance-of-this-policy">{{ 'PrivacyPolicyPage.Acceptance.Title' | translate}}</h2>
<p>{{ 'PrivacyPolicyPage.Acceptance.Text1' | translate}}
<h2 id="acceptance-of-this-policy">
{{ 'PrivacyPolicyPage.Acceptance.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.Acceptance.Text1' | translate }}</p>
<h2 id="contacting-us">{{ 'PrivacyPolicyPage.ContactingUs.Title' | translate}}</h2>
<h2 id="contacting-us">
{{ 'PrivacyPolicyPage.ContactingUs.Title' | translate }}
</h2>
<p>{{ 'PrivacyPolicyPage.ContactingUs.Text1' | translate }}</p>
<p><a
href="&#109;&#097;&#105;&#108;&#116;&#111;&#058;s&#97;n&#100;ka&#115;&#116;e&#110;3a&#64;&#103;&#109;a&#105;&#108;.&#99;&#111;m">sa&#110;&#100;&#107;&#97;&#115;te&#110;&#51;&#97;&#64;&#103;m&#97;il.&#99;&#111;m</a>
<p>
<a
href="&#109;&#097;&#105;&#108;&#116;&#111;&#058;s&#97;n&#100;ka&#115;&#116;e&#110;3a&#64;&#103;&#109;a&#105;&#108;.&#99;&#111;m"
>sa&#110;&#100;&#107;&#97;&#115;te&#110;&#51;&#97;&#64;&#103;m&#97;il.&#99;&#111;m</a
>
</p>
<p>{{ 'PrivacyPolicyPage.ContactingUs.Text2' | translate }}</p>

@ -8,9 +8,8 @@ describe('PrivacyPolicyComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PrivacyPolicyComponent]
})
.compileComponents();
imports: [PrivacyPolicyComponent],
}).compileComponents();
fixture = TestBed.createComponent(PrivacyPolicyComponent);
component = fixture.componentInstance;

@ -2,13 +2,12 @@ import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'app-privacy-policy',
templateUrl: './privacy-policy.component.html',
styleUrl: './privacy-policy.component.scss',
standalone: true,
imports: [TranslateModule]
imports: [TranslateModule],
})
export class PrivacyPolicyComponent {
constructor(private router: Router) {}

@ -3,12 +3,19 @@
<p>{{ 'TermsOfServicePage.Law' | translate }}</p>
<h2>{{ 'TermsOfServicePage.Edition' | translate }}</h2>
<p>{{ 'TermsOfServicePage.URL' | translate }} <a href="www.sandkasten.fr">www.sandkasten.fr</a> {{
'TermsOfServicePage.Site' | translate}}</p>
<p>
{{ 'TermsOfServicePage.URL' | translate }}
<a href="www.sandkasten.fr">www.sandkasten.fr</a>
{{ 'TermsOfServicePage.Site' | translate }}
</p>
<p>{{ 'TermsOfServicePage.Address' | translate }}</p>
<h2>{{ 'TermsOfServicePage.Hosting' | translate }}</h2>
<p>{{ 'TermsOfServicePage.Host' | translate }}<a
href="https://www.hostinger.fr/contact">https://www.hostinger.fr/contact</a>).</p>
<p>
{{ 'TermsOfServicePage.Host' | translate
}}<a href="https://www.hostinger.fr/contact"
>https://www.hostinger.fr/contact</a
>).
</p>
<h2>{{ 'TermsOfServicePage.Publishing' | translate }}</h2>
<p>{{ 'TermsOfServicePage.DirectorPublish' | translate }}</p>

@ -8,9 +8,8 @@ describe('TermsOfServiceComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TermsOfServiceComponent]
})
.compileComponents();
imports: [TermsOfServiceComponent],
}).compileComponents();
fixture = TestBed.createComponent(TermsOfServiceComponent);
component = fixture.componentInstance;

@ -2,13 +2,12 @@ import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'app-terms-of-service',
templateUrl: './terms-of-service.component.html',
styleUrl: './terms-of-service.component.scss',
standalone: true,
imports: [TranslateModule]
imports: [TranslateModule],
})
export class TermsOfServiceComponent {
constructor(private router: Router) {}

@ -3,8 +3,11 @@ import { inject } from '@angular/core/testing';
import { DomSanitizer } from '@angular/platform-browser';
describe('SafeHTMLPipe', () => {
it('create an instance', inject([DomSanitizer], (domSanitizer: DomSanitizer) => {
it('create an instance', inject(
[DomSanitizer],
(domSanitizer: DomSanitizer) => {
const pipe = new SafeHTMLPipe(domSanitizer);
expect(pipe).toBeTruthy();
}));
}
));
});

@ -6,11 +6,9 @@ import { DomSanitizer } from '@angular/platform-browser';
standalone: true,
})
export class SafeHTMLPipe implements PipeTransform {
constructor(protected sanitizer: DomSanitizer) {}
transform(value: unknown, ...args: unknown[]): unknown {
transform(value: unknown): unknown {
return this.sanitizer.bypassSecurityTrustHtml(value as string);
}
}

@ -3,8 +3,8 @@ import { SSE } from 'sse.js';
import { Observable, Subject } from 'rxjs';
export type ExecutionMessage = {
type: 'stdout' | 'stderr' | 'exit',
text: string
type: 'stdout' | 'stderr' | 'exit';
text: string;
};
@Injectable({
@ -29,7 +29,7 @@ export class CodeExecutionService {
sse.addEventListener('message', (event: MessageEvent<string>) => {
const result = event.data;
// @ts-ignore
// @ts-expect-error The type is not declared although present
const type = event.id;
const text = decodeURIComponent(result.replace(/%00/g, ''));
if (type === 'end') {

@ -5,13 +5,13 @@ import { TranslateService } from '@ngx-translate/core';
providedIn: 'root',
})
export class TranslationService {
language: string = 'fr'; // Par défaut, français
get language() {
return this.translate.currentLang;
}
constructor(private translate: TranslateService) {}
onLanguageChange(event: any) {
this.language = event.target.value;
this.translate.use(this.language);
console.log(this.language);
onLanguageChange(language: 'fr' | 'en') {
this.translate.use(language);
}
}

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
@ -10,8 +10,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap"
rel="stylesheet"
/>
rel="stylesheet" />
</head>
<body>
<app-root></app-root>

@ -2,7 +2,11 @@ import { createTranslateLoader } from './app/app.module';
import { importProvidersFrom } from '@angular/core';
import { AppComponent } from './app/app.component';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { withInterceptorsFromDi, provideHttpClient, HttpClient } from '@angular/common/http';
import {
withInterceptorsFromDi,
provideHttpClient,
HttpClient,
} from '@angular/common/http';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app/app-routing.module';
import { BrowserModule, bootstrapApplication } from '@angular/platform-browser';
@ -10,16 +14,21 @@ import { TranslationService } from './app/services/translation.service';
bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(BrowserModule, AppRoutingModule, ReactiveFormsModule, FormsModule,
importProvidersFrom(
BrowserModule,
AppRoutingModule,
ReactiveFormsModule,
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
useFactory: createTranslateLoader,
deps: [HttpClient],
},
defaultLanguage: 'fr'
})),
defaultLanguage: 'fr',
})
),
TranslationService,
provideHttpClient(withInterceptorsFromDi())
]
provideHttpClient(withInterceptorsFromDi()),
],
}).catch(console.error);

@ -1,6 +1,6 @@
//region Colors
$color-purple: #605FFC;
$color-white: #FFFFFF;
$color-purple: #605ffc;
$color-white: #ffffff;
$color-black: #000000;
$color-light-black: #333333;
//endregion
@ -12,4 +12,3 @@ $color-light-black: #333333;
body {
margin: 0;
}

@ -5,10 +5,6 @@
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts"
],
"include": [
"src/**/*.d.ts"
]
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}

@ -20,15 +20,12 @@
"module": "ES2022",
"useDefineForClassFields": false,
"allowSyntheticDefaultImports": true,
"lib": [
"ES2022",
"dom"
]
"lib": ["ES2022", "dom"],
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
"strictTemplates": true,
},
}

@ -3,12 +3,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
]
"types": ["jasmine"]
},
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}

Loading…
Cancel
Save