diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index a8f8a53..30e95f9 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -1,15 +1,33 @@
+@import '../styles';
+
+body {
+ overflow: hidden;
+ transition: background-color .3s ease-in-out, color .3s ease-in-out;
+}
+
+
body.light-theme {
background-color: #ffffff;
color: #000000;
- /* Autres styles pour le thème clair */
}
body.dark-theme {
background-color: #333333;
color: #ffffff;
- /* Autres styles pour le thème sombre */
}
-main {
- flex: 1;
+.app {
+ min-height: 100dvh;
+ display: flex;
+ flex-direction: column;
+
+ footer {
+ display: flex;
+ flex: 1;
+ align-items: flex-end;
+
+ app-footer {
+ width: 100%;
+ }
+ }
}
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 3f94dc8..b3bc364 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -9,7 +9,7 @@ import { ThemeService } from './services/theme.service';
export class AppComponent implements OnInit {
themeClass = 'light-theme';
- constructor(private themeService: ThemeService) {}
+ constructor(public themeService: ThemeService) {}
ngOnInit() {
this.themeService.isDarkTheme.subscribe((isDark) => {
diff --git a/src/app/components/header/header.component.html b/src/app/components/header/header.component.html
index 7f03bbb..bb52965 100644
--- a/src/app/components/header/header.component.html
+++ b/src/app/components/header/header.component.html
@@ -1,61 +1,138 @@
-
-
-
-
-
![Logo-Sandkasten]()
-
{{ title }}
-
-
-
-
-
-
-
-
-
-
{{ 'HeaderPage.Language' | translate }}
-
-
-
-
-
-
-
-
Version : {{ version }}
-
+
diff --git a/src/app/components/header/header.component.scss b/src/app/components/header/header.component.scss
index 8a9be90..e406312 100644
--- a/src/app/components/header/header.component.scss
+++ b/src/app/components/header/header.component.scss
@@ -1,121 +1,396 @@
-.toolbar {
- &.dark-theme {
- background-color: black !important;
- }
+@import '../../../styles';
- &.light-theme {
- background-color: white !important;
- }
- padding: 0 1rem;
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- gap: 4rem;
-}
+//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;
+// endregion
-.left_part {
- display: flex;
- flex-direction: row;
- gap: 4rem;
+//region Mixins
+@mixin crater($top, $left, $size) {
+ content: '';
+ position: absolute;
+ top: $top;
+ left: $left;
+ width: $size;
+ height: $size;
+ background-color: #EFEEDA;
+ border-radius: 100%;
+ border: 4px solid $color-moon-outer;
}
-.left_part .logo_container {
- display: flex;
- flex-direction: row;
- gap: 2rem;
+@mixin cloudBubble($top, $right, $width, $height, $deg) {
+ content: '';
+ display: block;
+ position: relative;
+ top: $top;
+ right: $right;
+ width: $width;
+ height: $height;
+ border: 8px solid $color-cloud-outer;
+ border-radius: 100%;
+ border-right-color: transparent;
+ border-bottom-color: transparent;
+ transform: rotateZ($deg);
+ background-color: $color-cloud-inner;
}
+//endregion
+
+$theme-transition: all .3s ease-in-out;
-.left_part .menu {
+.header {
+ position: relative;
+
+ padding: 1rem;
display: flex;
flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
gap: 2rem;
- align-items: flex-end;
-}
+ .left_part {
+ display: flex;
+ flex-direction: row;
-.left_part .menu a {
- &.dark-theme {
- color: black !important;
- }
+ &__logo {
+ &--container{
+ display: flex;
+ flex-direction: row;
+ gap: 2rem;
+ }
- &.light-theme {
- color: white !important;
+ &--sandkasten{
+ width: 4rem;
+ height: auto;
+ aspect-ratio: 1;
+ }
+ }
}
- text-decoration: none;
- padding: .5rem .5rem 0;
-}
-.left_part .menu a:hover {
- &.dark-theme {
- background-color: black !important;
- }
+ .right_part, .mobile_menu {
+ // Dark mode button
+ .wrapper {
+ text-align: center;
- &.light-theme {
- background-color: white !important;
- }
- transition: background-color .3s ease;
-}
+ .toggle {
+ position: relative;
+ display: inline-block;
+ width: 100px;
+ padding: 4px;
+ border-radius: 40px;
+ }
-.left_part .menu a.active {
- &.dark-theme {
- background-color: black !important;
- }
+ &:before, &:after {
+ content: '';
+ display: table;
+ }
+
+ &:after {
+ clear: both;
+ }
+
+ .toggle-bg {
+ position: absolute;
+ top: -4px;
+ left: -4px;
+ width: 100%;
+ height: 100%;
+ 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);
+ }
+
+ .toggle-input {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: 1px solid red;
+ border-radius: 40px;
+ z-index: 2;
+ opacity: 0;
+
+ &:checked ~ .toggle-switch {
+ margin-left: 0;
+ border-color: $color-moon-outer;
+ background-color: $color-moon-inner;
+ }
+
+ &:checked ~ .toggle-bg {
+ background-color: #484848;
+ border-color: #202020;
+ }
- &.light-theme {
- background-color: white !important;
+ &:checked ~ .toggle-switch .toggle-switch-figure {
+ margin-left: 40px;
+ opacity: 0;
+ transform: scale(0.1);
+ }
+
+ &:checked ~ .toggle-switch .toggle-switch-figureAlt {
+ transform: scale(1);
+ }
+ }
+
+ .toggle-switch {
+ position: relative;
+ width: 30px;
+ height: 30px;
+ margin-left: 60px;
+ background-color: #F5EB42;
+ border: 4px solid $color-sun;
+ border-radius: 50%;
+ transition: all .1s cubic-bezier(0.250, 0.460, 0.450, 0.940);
+
+ .toggle-switch-figure {
+ position: absolute;
+ bottom: -14px;
+ left: -50px;
+ display: block;
+ width: 80px;
+ height: 30px;
+ border: 8px solid $color-cloud-outer;
+ border-radius: 20px;
+ background-color: #fff;
+ transform: scale(0.4);
+ transition: all .12s cubic-bezier(0.250, 0.460, 0.450, 0.940);
+ &:after {
+ @include cloudBubble(-65px, -42px, 15px, 15px, 70deg);
+ }
+ &:before {
+ @include cloudBubble(-25px, -10px, 30px, 30px, 30deg);
+ }
+ }
+
+ .toggle-switch-figureAlt {
+ @include crater(5px, 2px, 2px);
+
+ box-shadow:
+ 42px -7px 0 -3px $color-stars,
+ 75px -10px 0 -3px $color-stars,
+ 54px 4px 0 -4px $color-stars,
+ 83px 7px 0 -2px $color-stars,
+ 63px 18px 0 -4px $color-stars,
+ 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);
+ transform: scale(0);
+
+ &:before {
+ @include crater(-6px, 12px, 7px);
+ }
+
+ &:after {
+ @include crater(10px, 6px, 2px);
+ }
+ }
+ }
+ }
}
-}
-.sandkasten-logo {
- width: 4rem;
- height: auto;
- aspect-ratio: 1;
-}
+ .right_part {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 2rem;
+
+ &--menu {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 1rem;
+
+ a {
+ color: $color-black;
+ text-decoration: none;
+ white-space: nowrap;
+
+ transition: $theme-transition;
+ }
+ }
+
+ &--menu_mobile {
+ cursor: pointer;
+ display: none;
+ z-index: 100;
+ }
+
+ &--bottom {
+ display: flex;
+ flex-direction: row;
+ gap: 2rem;
+ align-items: center;
+ }
+
+ &--toggles {
+ display: flex;
+ flex-direction: row;
+ gap: 2rem;
+ align-items: center;
+ }
+
+ &__lang {
+ height: fit-content;
+ }
-.logo_title {
- font-size: 1.5rem;
- font-weight: 500;
- &.dark-theme {
- color: black !important;
+ &__connexion {
+ display: flex;
+ flex-direction: row;
+ gap: 1rem;
+
+ &--login {
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: .5rem;
+
+ color: $color-purple;
+ white-space: nowrap;
+ }
+
+ &--register {
+ cursor: pointer;
+ border: 1px solid $color-black;
+ border-radius: 10px;
+ padding: .75rem 2rem;
+ white-space: nowrap;
+
+ transition: border .3s ease-in-out;
+ }
+ }
}
- &.light-theme {
- color: white !important;
+ .mobile_menu {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 50%;
+ height: 100vh;
+ background: $color-white;
+ transform: translateX(100%);
+ z-index: 99;
+
+ transition: transform .3s ease-in-out, box-shadow .3s ease-in-out, background .3s ease-in-out;
+
+ &.opened {
+ transform: translateX(0);
+ box-shadow: $color-black 0 0 5px 0;
+ }
+
+ &--wrapper {
+ //padding-top: 6rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 3rem;
+
+ height: 100%;
+ }
+
+ &--toggles {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2rem;
+ }
+
+ &--menu {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+
+ a {
+ color: $color-black;
+ text-decoration: none;
+ white-space: nowrap;
+
+ transition: $theme-transition;
+ }
+ }
+
+ &__connexion {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ }
}
}
-.right_part {
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 2rem;
- &.dark-theme {
- color: black !important;
+.dark-theme {
+ .right_part {
+ &--menu {
+ a {
+ color: $color-white;
+ }
+ }
+ &__connexion {
+ &--register {
+ border-color: $color-white;
+ }
+ }
}
- &.light-theme {
- color: white !important;
+ .mobile_menu {
+ background: $color-light-black;
+
+ &.opened {
+ box-shadow: $color-white 0 0 5px 0;
+ }
+
+ &--menu {
+ a {
+ color: $color-white;
+ }
+ }
+ &__connexion {
+ &--register {
+ border-color: $color-white;
+ }
+ }
}
}
-.gitea_logo_container .gitea-logo {
- width: 4rem;
- height: auto;
- aspect-ratio: 1;
-}
@media (max-width: 1024px) {
- .toolbar {
- gap: 2rem;
- }
+ .header {
+ .right_part {
+ flex-direction: column-reverse;
- .toolbar .left_part {
- gap: 2rem;
+ &--menu_mobile {
+ display: flex;
+ }
+
+ &--menu {
+ display: none;
+ }
+
+ &__connexion {
+ display: none;
+ }
+
+ &--toggles {
+ display: none;
+ }
+ }
}
+}
- .toolbar .left_part .logo_container .logo_title {
- display: none;
+@media(max-width: 767px) {
+ .header {
+ .mobile_menu {
+ width: 75%;
+ }
}
}
diff --git a/src/app/components/header/header.component.ts b/src/app/components/header/header.component.ts
index b62270a..06ebad8 100644
--- a/src/app/components/header/header.component.ts
+++ b/src/app/components/header/header.component.ts
@@ -1,29 +1,47 @@
-import { Component, OnInit } from '@angular/core';
-import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
-import { Router } from "@angular/router";
-import { TranslationService } from '../../services/translation.service';
+import {Component, ElementRef, HostListener, Input, OnInit, ViewChild} from '@angular/core';
+import {TranslationService} from '../../services/translation.service';
+import {ThemeService} from "../../services/theme.service";
@Component({
- selector: 'app-header',
- templateUrl: './header.component.html',
- styleUrls: ['./header.component.scss']
+ selector: 'app-header',
+ templateUrl: './header.component.html',
+ styleUrls: ['./header.component.scss']
})
export class HeaderComponent {
- title: string = 'Sandkasten';
- version: string = '1.0';
- sandkasten_logo: string = 'assets/img/logo.png';
- gitea_logo: string = 'assets/img/gitea.png';
+ title: string = 'Sandkasten';
+ version: string = '1.0';
+ sandkasten_logo: string = 'assets/img/logo.png';
+ isMenuOpen: boolean = false;
+ isCheck: boolean = false;
+ @ViewChild('menuRef') menuRef!: ElementRef;
+ @Input() themeClass!: string;
+ @Input() themeService!: ThemeService;
- // Instanciation du service pour les actions de traduction
- constructor(private translationService: TranslationService) { }
+ // Instanciation du service pour les actions de traduction
+ constructor(private translationService: TranslationService) {
+ }
- // Méthode pour changer la langue
- onLanguageChange(event: any) {
- this.translationService.onLanguageChange(event);
- }
+ // Méthode pour changer la langue
+ onLanguageChange(event: any) {
+ this.translationService.onLanguageChange(event);
+ }
- // Méthode pour récupérer le drapeau de la langue courante
- getFlagImageUrl(): string {
- return this.translationService.getFlagImageUrl();
- }
+ toggleTheme() {
+ this.themeService.toggleDarkTheme();
+ this.themeService.isDarkTheme.subscribe(value => {
+ this.isCheck = value;
+ })
+ }
+
+ openCloseMenu() {
+ this.isMenuOpen = !this.isMenuOpen;
+ }
+
+ @HostListener('document:click', ['$event'])
+ clickout(event: any) {
+ // 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;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/app/components/landing-page/landing-page.component.html b/src/app/components/landing-page/landing-page.component.html
index a5eb4ce..b10e201 100644
--- a/src/app/components/landing-page/landing-page.component.html
+++ b/src/app/components/landing-page/landing-page.component.html
@@ -1,11 +1,9 @@
-
-
-
{{ 'LandingPage.Welcome' | translate}}
- {{ 'LandingPage.Description' | translate}}
-
-
+
+
+
{{ 'LandingPage.Welcome' | translate}}
+
{{ 'LandingPage.Description' | translate}}
+
+
diff --git a/src/app/components/landing-page/landing-page.component.scss b/src/app/components/landing-page/landing-page.component.scss
index cd12a31..31713f9 100644
--- a/src/app/components/landing-page/landing-page.component.scss
+++ b/src/app/components/landing-page/landing-page.component.scss
@@ -1,59 +1,63 @@
-.landing-block {
+@import '../../../styles';
+
+.landing-page {
padding: 6rem;
display: flex;
flex-direction: row;
gap: 2rem;
-}
-/* Upper block*/
-.hero-container {
- display: flex;
- flex-direction: column;
- gap: 2.5rem;
- padding: 2rem 1rem;
- background: #686AB7;
-}
+ color: $color-black;
+ transition: color .3s ease-in-out;
-.landing-links {
- width: 100%;
- text-align: center;
-}
-button{
- font-size: 20px;
-}
+ &--container {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ }
-/* Animated Button*/
-.landing-links {
- width: fit-content;
- padding: 1rem;
- height: fit-content;
+ &--title {
+ font-size: 5rem;
+ font-weight: 700;
+ margin: 0;
+ }
-}
+ &--subtitle {
+ font-size: 1rem;
+ font-weight: 400;
+ margin: 0;
+ }
-.button-container {
- position: relative;
- margin: auto;
-
- &:before {
- content: "";
- position: absolute;
- top: 0;
- left: -1rem;
- border-radius: 100px;
- width: 2rem;
- height: 2rem;
- transform: translate(0%, -25%);
- background: rgba(0, 0, 255, 0.5);
- transition: width 0.3s ease;
+ &__button {
+ padding: .75rem 2rem;
+ background: $color-purple;
+ border-radius: 10px;
+ width: fit-content;
+ white-space: nowrap;
+
+ color: $color-white;
}
-}
-.landing-links:hover .button-container:before {
- width: calc(100% + 2rem);
-}
+ @media(max-width: 1024px) {
+ padding: 4rem;
+ flex-direction: column;
+ gap: 1rem;
+
+ &--title {
+ font-size: 4rem;
+ }
+ }
-.button-container .animated-button {
- position: relative;
- white-space: nowrap;
+ @media(max-width: 767px) {
+ padding: 2rem;
+
+ &--title {
+ font-size: 2.5rem;
+ }
+ }
+
+
+ &.dark-theme {
+ color: $color-white;
+ }
}
diff --git a/src/app/components/landing-page/landing-page.component.ts b/src/app/components/landing-page/landing-page.component.ts
index 5c2ce47..2f22f03 100644
--- a/src/app/components/landing-page/landing-page.component.ts
+++ b/src/app/components/landing-page/landing-page.component.ts
@@ -1,5 +1,6 @@
-import { Component, OnInit } from '@angular/core';
+import {Component, OnInit} from '@angular/core';
import { Router } from '@angular/router';
+import {ThemeService} from "../../services/theme.service";
@Component({
selector: 'app-landing-page',
@@ -7,12 +8,17 @@ import { Router } from '@angular/router';
styleUrls: ['./landing-page.component.scss']
})
export class LandingPageComponent implements OnInit {
- constructor(private router: Router) { }
- ngOnInit(): void {
+ themeClass!: string;
+ constructor(private router: Router, private themeService: ThemeService){}
+
+ ngOnInit() {
+ 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 {
- this.router.navigateByUrl('/editor');
+ onContinue():void{
+ this.router.navigateByUrl('/editor');
}
}
diff --git a/src/app/services/translation.service.ts b/src/app/services/translation.service.ts
index b4e5fc0..70e2acf 100644
--- a/src/app/services/translation.service.ts
+++ b/src/app/services/translation.service.ts
@@ -14,8 +14,4 @@ export class TranslationService {
this.translate.use(this.language);
console.log(this.language);
}
-
- getFlagImageUrl(): string {
- return `../../assets/img/${this.language}_flag.jpg`;
- }
}
\ No newline at end of file
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index a8330de..ac48afa 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -5,8 +5,6 @@
"Try": "Try it now !"
},
"HeaderPage": {
- "Language": "You can choose your language here :",
- "Home": "Home",
"Editor": "Editor",
"Documentation": "Documentation",
"Contact": "Contact us"
diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json
index 98c912a..2f64176 100644
--- a/src/assets/i18n/fr.json
+++ b/src/assets/i18n/fr.json
@@ -1,12 +1,10 @@
{
"LandingPage": {
- "Welcome": "Bienvenue sur Sandkasten",
+ "Welcome" : "Bienvenue sur Sandkasten",
"Description": "Vous voici arrivé sur le meilleur site bac à sable de test de code ! Nous vous permettons de tester tous vos programmes sur vos langages préférés. Grâce à l’éditeur Code Mirror et à notre gestion personalisée de l’exécution sur des conteneurs, votre code devient complétement inoffensif et vous pouvez donc vous amusez autant que vous le souhaitez !",
"Try": "Essayez maintenant !"
},
"HeaderPage": {
- "Language": "Vous pouvez choisir votre langage ici :",
- "Home": "Accueil",
"Editor": "Éditeur",
"Documentation": "Documentation",
"Contact": "Nous contacter"
diff --git a/src/styles.scss b/src/styles.scss
index f405c2f..e78eea3 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -1,10 +1,18 @@
@import 'codemirror/lib/codemirror.css';
@import 'codemirror/theme/material.css';
+//region Colors
+$color-purple: #605FFC;
+$color-white: #FFFFFF;
+$color-black: #000000;
+$color-light-black: #333333;
+//endregion
+
* {
font-family: Roboto, Helvetica, sans-serif;
}
body {
margin: 0;
-}
\ No newline at end of file
+}
+