diff --git a/apps/playground/assets/DjbUpOnTheScoreboard.ttf b/apps/playground/assets/DjbUpOnTheScoreboard.ttf new file mode 100644 index 000000000..ded21514c Binary files /dev/null and b/apps/playground/assets/DjbUpOnTheScoreboard.ttf differ diff --git a/apps/playground/assets/alarm-clock.ttf b/apps/playground/assets/alarm-clock.ttf new file mode 100644 index 000000000..9e9b59345 Binary files /dev/null and b/apps/playground/assets/alarm-clock.ttf differ diff --git a/apps/playground/assets/images/DIDiagram.png b/apps/playground/assets/images/DIDiagram.png new file mode 100644 index 000000000..8aab83cbc Binary files /dev/null and b/apps/playground/assets/images/DIDiagram.png differ diff --git a/apps/playground/assets/images/angular.png b/apps/playground/assets/images/angular.png new file mode 100644 index 000000000..6c115fba8 Binary files /dev/null and b/apps/playground/assets/images/angular.png differ diff --git a/apps/playground/assets/images/angular.svg b/apps/playground/assets/images/angular.svg new file mode 100644 index 000000000..bf081acb1 --- /dev/null +++ b/apps/playground/assets/images/angular.svg @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/apps/playground/assets/images/congratulations.jpg b/apps/playground/assets/images/congratulations.jpg new file mode 100644 index 000000000..06bcb7b38 Binary files /dev/null and b/apps/playground/assets/images/congratulations.jpg differ diff --git a/apps/playground/assets/images/email.svg b/apps/playground/assets/images/email.svg new file mode 100644 index 000000000..77c5db3ca --- /dev/null +++ b/apps/playground/assets/images/email.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/apps/playground/assets/images/facebook.gif b/apps/playground/assets/images/facebook.gif new file mode 100644 index 000000000..cb02b6d11 Binary files /dev/null and b/apps/playground/assets/images/facebook.gif differ diff --git a/apps/playground/assets/images/headgears.png b/apps/playground/assets/images/headgears.png new file mode 100644 index 000000000..a0b92b19d Binary files /dev/null and b/apps/playground/assets/images/headgears.png differ diff --git a/apps/playground/assets/images/ngtrophy.png b/apps/playground/assets/images/ngtrophy.png new file mode 100644 index 000000000..282d7c434 Binary files /dev/null and b/apps/playground/assets/images/ngtrophy.png differ diff --git a/apps/playground/assets/images/notbad.jpg b/apps/playground/assets/images/notbad.jpg new file mode 100644 index 000000000..e8a2f9f31 Binary files /dev/null and b/apps/playground/assets/images/notbad.jpg differ diff --git a/apps/playground/assets/images/tryagain.jpeg b/apps/playground/assets/images/tryagain.jpeg new file mode 100644 index 000000000..9b6fdaa1e Binary files /dev/null and b/apps/playground/assets/images/tryagain.jpeg differ diff --git a/apps/playground/assets/images/twitter.svg b/apps/playground/assets/images/twitter.svg new file mode 100644 index 000000000..a4ed81154 --- /dev/null +++ b/apps/playground/assets/images/twitter.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/apps/playground/src/app/app.component.html b/apps/playground/src/app/app.component.html index 0680b43f9..6c46b1de8 100644 --- a/apps/playground/src/app/app.component.html +++ b/apps/playground/src/app/app.component.html @@ -1 +1 @@ - + diff --git a/apps/playground/src/app/app.component.scss b/apps/playground/src/app/app.component.scss index bd8c23046..5401b8eb8 100644 --- a/apps/playground/src/app/app.component.scss +++ b/apps/playground/src/app/app.component.scss @@ -1,133 +1,133 @@ -/* - * Remove template code below - */ -:host { - display: block; - font-family: sans-serif; - min-width: 300px; - max-width: 1600px; - margin: 50px auto; -} - -.gutter-left { - margin-left: 9px; -} - -.col-span-2 { - grid-column: span 2; -} - -.flex { - display: flex; - align-items: center; - justify-content: center; -} - -header { - background-color: #143055; - color: white; - padding: 5px; - border-radius: 3px; -} - -main { - padding: 0 36px; -} - -p { - text-align: center; -} - -h1 { - text-align: center; - margin-left: 18px; - font-size: 24px; -} - -h2 { - text-align: center; - font-size: 20px; - margin: 40px 0 10px 0; -} - -.resources { - text-align: center; - list-style: none; - padding: 0; - display: grid; - grid-gap: 9px; - grid-template-columns: 1fr 1fr; -} - -.resource { - color: #0094ba; - height: 36px; - background-color: rgba(0, 0, 0, 0); - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 4px; - padding: 3px 9px; - text-decoration: none; -} - -.resource:hover { - background-color: rgba(68, 138, 255, 0.04); -} - -pre { - padding: 9px; - border-radius: 4px; - background-color: black; - color: #eee; -} - -details { - border-radius: 4px; - color: #333; - background-color: rgba(0, 0, 0, 0); - border: 1px solid rgba(0, 0, 0, 0.12); - padding: 3px 9px; - margin-bottom: 9px; -} - -summary { - cursor: pointer; - outline: none; - height: 36px; - line-height: 36px; -} - -.github-star-container { - margin-top: 12px; - line-height: 20px; -} - -.github-star-container a { - display: flex; - align-items: center; - text-decoration: none; - color: #333; -} - -.github-star-badge { - color: #24292e; - display: flex; - align-items: center; - font-size: 12px; - padding: 3px 10px; - border: 1px solid rgba(27, 31, 35, 0.2); - border-radius: 3px; - background-image: linear-gradient(-180deg, #fafbfc, #eff3f6 90%); - margin-left: 4px; - font-weight: 600; -} - -.github-star-badge:hover { - background-image: linear-gradient(-180deg, #f0f3f6, #e6ebf1 90%); - border-color: rgba(27, 31, 35, 0.35); - background-position: -0.5em; -} -.github-star-badge .material-icons { - height: 16px; - width: 16px; - margin-right: 4px; -} +/* + * Remove template code below + */ +:host { + display: block; + font-family: sans-serif; + min-width: 300px; + max-width: 1600px; + margin: 50px auto; +} + +.gutter-left { + margin-left: 9px; +} + +.col-span-2 { + grid-column: span 2; +} + +.flex { + display: flex; + align-items: center; + justify-content: center; +} + +header { + background-color: #143055; + color: white; + padding: 5px; + border-radius: 3px; +} + +main { + padding: 0 36px; +} + +p { + text-align: center; +} + +h1 { + text-align: center; + margin-left: 18px; + font-size: 24px; +} + +h2 { + text-align: center; + font-size: 20px; + margin: 40px 0 10px 0; +} + +.resources { + text-align: center; + list-style: none; + padding: 0; + display: grid; + grid-gap: 9px; + grid-template-columns: 1fr 1fr; +} + +.resource { + color: #0094ba; + height: 36px; + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 4px; + padding: 3px 9px; + text-decoration: none; +} + +.resource:hover { + background-color: rgba(68, 138, 255, 0.04); +} + +pre { + padding: 9px; + border-radius: 4px; + background-color: black; + color: #eee; +} + +details { + border-radius: 4px; + color: #333; + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0.12); + padding: 3px 9px; + margin-bottom: 9px; +} + +summary { + cursor: pointer; + outline: none; + height: 36px; + line-height: 36px; +} + +.github-star-container { + margin-top: 12px; + line-height: 20px; +} + +.github-star-container a { + display: flex; + align-items: center; + text-decoration: none; + color: #333; +} + +.github-star-badge { + color: #24292e; + display: flex; + align-items: center; + font-size: 12px; + padding: 3px 10px; + border: 1px solid rgba(27, 31, 35, 0.2); + border-radius: 3px; + background-image: linear-gradient(-180deg, #fafbfc, #eff3f6 90%); + margin-left: 4px; + font-weight: 600; +} + +.github-star-badge:hover { + background-image: linear-gradient(-180deg, #f0f3f6, #e6ebf1 90%); + border-color: rgba(27, 31, 35, 0.35); + background-position: -0.5em; +} +.github-star-badge .material-icons { + height: 16px; + width: 16px; + margin-right: 4px; +} diff --git a/apps/playground/src/app/app.component.spec.ts b/apps/playground/src/app/app.component.spec.ts index 45840ff39..c31a71a50 100644 --- a/apps/playground/src/app/app.component.spec.ts +++ b/apps/playground/src/app/app.component.spec.ts @@ -1,33 +1,33 @@ -import { async, TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppModule } from './app.module'; - -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule, AppModule] - }).compileComponents(); - })); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'playground'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app.title).toEqual('playground'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain( - 'Welcome to playground!' - ); - }); -}); +import { async, TestBed } from '@angular/core/testing'; +import { AppComponent } from './app.component'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppModule } from './app.module'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule, AppModule] + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'playground'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('playground'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain( + 'Welcome to playground!' + ); + }); +}); diff --git a/apps/playground/src/app/app.component.ts b/apps/playground/src/app/app.component.ts index a5db690f0..394aaf7af 100644 --- a/apps/playground/src/app/app.component.ts +++ b/apps/playground/src/app/app.component.ts @@ -1,10 +1,10 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'codelab-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] -}) -export class AppComponent { - title = 'playground'; -} +import { Component } from '@angular/core'; + +@Component({ + selector: 'codelab-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent { + title = 'playground'; +} diff --git a/apps/playground/src/app/app.module.ts b/apps/playground/src/app/app.module.ts index ab8fda53c..ded9fbd03 100644 --- a/apps/playground/src/app/app.module.ts +++ b/apps/playground/src/app/app.module.ts @@ -1,54 +1,59 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { APP_INITIALIZER, NgModule } from '@angular/core'; - -import { AppComponent } from './app.component'; -import { RouterModule } from '@angular/router'; -import { monacoReady } from '@codelab/code-demos'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { environment } from '../environments/environment'; -import { AngularFireModule } from '@angular/fire'; -import { AngularFireDatabaseModule } from '@angular/fire/database'; -import { AngularFireAuthModule } from '@angular/fire/auth'; - -const routes = [ - { - path: '', - redirectTo: 'code-sync', - pathMatch: 'full' - }, - { - path: 'angular', - loadChildren: () => - import('./playground/playground.module').then(m => m.PlaygroundModule) - }, - { - path: 'code-sync', - loadChildren: () => - import('./code-sync/code-sync.module').then(m => m.CodeSyncModule) - } -]; - -export const AngularFireApp = AngularFireModule.initializeApp( - environment.firebaseConfig -); - -@NgModule({ - declarations: [AppComponent], - imports: [ - BrowserModule, - BrowserAnimationsModule, - RouterModule.forRoot(routes, { initialNavigation: 'enabled' }), - AngularFireApp, - AngularFireDatabaseModule, - AngularFireAuthModule - ], - providers: [ - { - provide: APP_INITIALIZER, - useValue: monacoReady, - multi: true - } - ], - bootstrap: [AppComponent] -}) -export class AppModule {} +import { BrowserModule } from '@angular/platform-browser'; +import { APP_INITIALIZER, NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; +import { RouterModule } from '@angular/router'; +import { monacoReady } from '@codelab/code-demos'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { environment } from '../environments/environment'; +import { AngularFireModule } from '@angular/fire'; +import { AngularFireDatabaseModule } from '@angular/fire/database'; +import { AngularFireAuthModule } from '@angular/fire/auth'; + +const routes = [ + { + path: '', + redirectTo: 'code-sync', + pathMatch: 'full' + }, + { + path: 'angular', + loadChildren: () => + import('./playground/playground.module').then(m => m.PlaygroundModule) + }, + { + path: 'code-sync', + loadChildren: () => + import('./code-sync/code-sync.module').then(m => m.CodeSyncModule) + }, + { + path: 'quiz', + loadChildren: () => + import('./quiz/app.module').then(m => m.AppModule) + } +]; + +export const AngularFireApp = AngularFireModule.initializeApp( + environment.firebaseConfig +); + +@NgModule({ + declarations: [AppComponent], + imports: [ + BrowserModule, + BrowserAnimationsModule, + RouterModule.forRoot(routes, { initialNavigation: 'enabled' }), + AngularFireApp, + AngularFireDatabaseModule, + AngularFireAuthModule + ], + providers: [ + { + provide: APP_INITIALIZER, + useValue: monacoReady, + multi: true + } + ], + bootstrap: [AppComponent] +}) +export class AppModule {} diff --git a/apps/playground/src/app/quiz/app-routing.module.ts b/apps/playground/src/app/quiz/app-routing.module.ts new file mode 100644 index 000000000..e9fb4e4f6 --- /dev/null +++ b/apps/playground/src/app/quiz/app-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { Route, RouterModule } from '@angular/router'; +import { IntroductionComponent } from './containers/introduction/introduction.component'; +import { QuestionComponent } from './containers/question/question.component'; +import { ResultsComponent } from './containers/results/results.component'; + +const routes: Route[] = [ + { path: 'intro', component: IntroductionComponent }, + { path: 'question', component: QuestionComponent }, + { path: 'question/:questionId', component: QuestionComponent }, + { path: 'results', component: ResultsComponent }, + { path: '', redirectTo: 'intro' } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/apps/playground/src/app/quiz/app.component.html b/apps/playground/src/app/quiz/app.component.html new file mode 100644 index 000000000..6c46b1de8 --- /dev/null +++ b/apps/playground/src/app/quiz/app.component.html @@ -0,0 +1 @@ + diff --git a/apps/playground/src/app/quiz/app.component.scss b/apps/playground/src/app/quiz/app.component.scss new file mode 100644 index 000000000..5401b8eb8 --- /dev/null +++ b/apps/playground/src/app/quiz/app.component.scss @@ -0,0 +1,133 @@ +/* + * Remove template code below + */ +:host { + display: block; + font-family: sans-serif; + min-width: 300px; + max-width: 1600px; + margin: 50px auto; +} + +.gutter-left { + margin-left: 9px; +} + +.col-span-2 { + grid-column: span 2; +} + +.flex { + display: flex; + align-items: center; + justify-content: center; +} + +header { + background-color: #143055; + color: white; + padding: 5px; + border-radius: 3px; +} + +main { + padding: 0 36px; +} + +p { + text-align: center; +} + +h1 { + text-align: center; + margin-left: 18px; + font-size: 24px; +} + +h2 { + text-align: center; + font-size: 20px; + margin: 40px 0 10px 0; +} + +.resources { + text-align: center; + list-style: none; + padding: 0; + display: grid; + grid-gap: 9px; + grid-template-columns: 1fr 1fr; +} + +.resource { + color: #0094ba; + height: 36px; + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 4px; + padding: 3px 9px; + text-decoration: none; +} + +.resource:hover { + background-color: rgba(68, 138, 255, 0.04); +} + +pre { + padding: 9px; + border-radius: 4px; + background-color: black; + color: #eee; +} + +details { + border-radius: 4px; + color: #333; + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0.12); + padding: 3px 9px; + margin-bottom: 9px; +} + +summary { + cursor: pointer; + outline: none; + height: 36px; + line-height: 36px; +} + +.github-star-container { + margin-top: 12px; + line-height: 20px; +} + +.github-star-container a { + display: flex; + align-items: center; + text-decoration: none; + color: #333; +} + +.github-star-badge { + color: #24292e; + display: flex; + align-items: center; + font-size: 12px; + padding: 3px 10px; + border: 1px solid rgba(27, 31, 35, 0.2); + border-radius: 3px; + background-image: linear-gradient(-180deg, #fafbfc, #eff3f6 90%); + margin-left: 4px; + font-weight: 600; +} + +.github-star-badge:hover { + background-image: linear-gradient(-180deg, #f0f3f6, #e6ebf1 90%); + border-color: rgba(27, 31, 35, 0.35); + background-position: -0.5em; +} +.github-star-badge .material-icons { + height: 16px; + width: 16px; + margin-right: 4px; +} diff --git a/apps/playground/src/app/quiz/app.component.spec.ts b/apps/playground/src/app/quiz/app.component.spec.ts new file mode 100644 index 000000000..d93819206 --- /dev/null +++ b/apps/playground/src/app/quiz/app.component.spec.ts @@ -0,0 +1,35 @@ +import { TestBed, async } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'quiz'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('quiz'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('.content span').textContent).toContain('quiz app is running!'); + }); +}); diff --git a/apps/playground/src/app/quiz/app.component.ts b/apps/playground/src/app/quiz/app.component.ts new file mode 100644 index 000000000..7f4f16ed5 --- /dev/null +++ b/apps/playground/src/app/quiz/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'codelab-quiz', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] +}) +export class AppComponent { + name = 'Angular'; +} diff --git a/apps/playground/src/app/quiz/app.module.ts b/apps/playground/src/app/quiz/app.module.ts new file mode 100644 index 000000000..e0e34cf39 --- /dev/null +++ b/apps/playground/src/app/quiz/app.module.ts @@ -0,0 +1,45 @@ +import { NgModule, NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { CommonModule } from "@angular/common"; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatCardModule } from '@angular/material/card'; +import { MatRadioModule, MAT_RADIO_DEFAULT_OPTIONS } from '@angular/material/radio'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; + +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { IntroductionComponent } from './containers/introduction/introduction.component'; +import { QuestionComponent } from './containers/question/question.component'; +import * as QuestionComponent2 from './components/question/question.component'; +import { ResultsComponent } from './containers/results/results.component'; + +@NgModule({ + declarations: [ + AppComponent, + IntroductionComponent, + QuestionComponent, + QuestionComponent2.QuestionComponent, + ResultsComponent + ], + imports: [ + CommonModule, + AppRoutingModule, + ReactiveFormsModule, + MatCardModule, + MatRadioModule, + MatIconModule, + MatButtonModule, + NgbModule + ], + providers: [{ + provide: MAT_RADIO_DEFAULT_OPTIONS, + useValue: { color: 'accent' }, + }], + bootstrap: [ AppComponent ], + schemas: [ + CUSTOM_ELEMENTS_SCHEMA, + NO_ERRORS_SCHEMA + ] +}) +export class AppModule { } diff --git a/apps/playground/src/app/quiz/browserslist b/apps/playground/src/app/quiz/browserslist new file mode 100644 index 000000000..80848532e --- /dev/null +++ b/apps/playground/src/app/quiz/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/apps/playground/src/app/quiz/components/question/question.component.html b/apps/playground/src/app/quiz/components/question/question.component.html new file mode 100644 index 000000000..02ee38246 --- /dev/null +++ b/apps/playground/src/app/quiz/components/question/question.component.html @@ -0,0 +1,30 @@ + + +
+
    + +
    + +
  1. {{ option.optionText }}
  2. + + +
    + +
    +
    + sentiment_very_satisfied   +
      You're right! The correct answer is Option {{ question.answer }}.
    +
    +
    + sentiment_very_dissatisfied   +
      That's wrong. The correct answer is Option {{ question.answer }}.
    +
    +
    +
    +
    +
+
diff --git a/apps/playground/src/app/quiz/components/question/question.component.scss b/apps/playground/src/app/quiz/components/question/question.component.scss new file mode 100644 index 000000000..32e48c72e --- /dev/null +++ b/apps/playground/src/app/quiz/components/question/question.component.scss @@ -0,0 +1,99 @@ +$font-stack: Space Mono, monospace; +$font-weight-max: 900; + +ol { + margin-top: 15px; + margin-left: -40px; + cursor: pointer; +} +ol li { + margin-left: 30px; +} + +.radio-options { + margin-bottom: 5px; + margin-left: 0.5rem; + padding: 4px; +} + +.option { + border: 2px solid #979797; + font-family: $font-stack; + font-size: 20px; + color: #0f0900; + background-color: #f5f5f5; + width: 39rem !important; + height: auto; + padding: 5px 5px 0 30px; + margin-left: -5px; + vertical-align: middle; +} +.option:hover { + outline: 2px solid #007aff; +} + +.is-correct { + background-color: #00c853 !important; +} +.is-incorrect { + background-color: #ff0000 !important; +} + +.feedback-icon { + position: absolute; + right: 0; + margin-right: 40px; + margin-top: -25px; +} + +section.messages { + display: flex; + justify-content: center; + + .message { + font-family: $font-stack; + font-weight: $font-weight-max; + font-size: 16px; + font-style: italic; + text-align: center !important; + margin: 10px 0 0 0; + padding: 10px !important; + width: 32rem !important; + display: inline-flex; + align-items: center; + vertical-align: middle; + justify-content: center !important; + margin: 0 auto !important; + margin-top: 10px !important; + } + .correct-message { + font-weight: $font-weight-max; + font-style: italic; + border: 2px solid #007aff; + border-radius: 5px; + color: #00c853 !important; + } + .wrong-message { + font-weight: $font-weight-max; + font-style: italic; + border: 2px solid #ff0000; + border-radius: 5px; + color: #ff0000 !important; + padding: 5px; + } + mat-icon.sentiment { + font-size: 30px !important; + color: #9acd32; + margin-right: -50px !important; + vertical-align: top; + margin-top: 18px; + } + pre { + font-size: 17px; + margin-top: 10px; + } +} + +::ng-deep .mat-radio-button .mat-radio-container { + display: none; +} diff --git a/apps/playground/src/app/quiz/components/question/question.component.ts b/apps/playground/src/app/quiz/components/question/question.component.ts new file mode 100644 index 000000000..ddbd1ee5f --- /dev/null +++ b/apps/playground/src/app/quiz/components/question/question.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit, OnChanges, SimpleChanges, Input, Output, EventEmitter } from '@angular/core'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; + +import { QuizQuestion } from '../../model/QuizQuestion'; + +@Component({ + selector: 'codelab-quiz-question', + templateUrl: './question.component.html', + styleUrls: ['./question.component.scss'] +}) +export class QuestionComponent implements OnInit, OnChanges { + @Output() answer = new EventEmitter(); + @Output() formGroup: FormGroup; + @Input() question: QuizQuestion; + option = ''; + grayBorder = '2px solid #979797'; + + constructor() {} + + ngOnInit() { + this.buildForm(); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes.question && changes.question.currentValue && !changes.question.firstChange) { + this.formGroup.patchValue({answer: ''}); + } + } + + buildForm() { + this.formGroup = new FormGroup({ + answer: new FormControl(['', Validators.required]) + }); + } + + radioChange(answer: string) { + this.question.selectedOption = answer; + this.answer.emit(answer); + this.displayExplanation(); + } + + displayExplanation(): void { + const questionElem = document.getElementById('question'); + if (questionElem !== null) { + questionElem.innerHTML = 'Option ' + this.question.answer + ' was correct because ' + this.question.explanation + '.'; + questionElem.style.border = this.grayBorder; + } + } + + // mark the correct answer regardless of which option is selected once answered + isCorrect(option: string): boolean { + return this.question.selectedOption && option === this.question.answer; + } + + // mark incorrect answer if selected + isIncorrect(option: string): boolean { + return option !== this.question.answer && option === this.question.selectedOption; + } + + onSubmit() { + this.formGroup.reset({answer: null}); + } +} diff --git a/apps/playground/src/app/quiz/containers/introduction/introduction.component.html b/apps/playground/src/app/quiz/containers/introduction/introduction.component.html new file mode 100644 index 000000000..4a00535d8 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/introduction/introduction.component.html @@ -0,0 +1,24 @@ + + +
+
+
+ Dependency Injection Quiz + + How well do you know Dependency Injection? + Take the quiz and find out! + +
+
+
+
+ + +

Take this awesome quiz that will help improve your understanding of Dependency Injection. The timed questionnaire + with automatic scoring provides you with a final score at the end. Match wits with your friends! Practice to + increase your knowledge. Good luck and have fun with this quiz. Share and enjoy!

+
+ + + +
diff --git a/apps/playground/src/app/quiz/containers/introduction/introduction.component.scss b/apps/playground/src/app/quiz/containers/introduction/introduction.component.scss new file mode 100644 index 000000000..9a3e778d9 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/introduction/introduction.component.scss @@ -0,0 +1,43 @@ +mat-card-header { + display: block; + + .header-image { + margin-left: 15px; + } + + .mat-card-container { + float: right; + margin-top: 0; + margin-right: 40px; + + .subtitle2 { + display: block; + } + } + + .quiz-topic-img { + display: flex; + justify-content: center; + background: url('../../../../../assets/images/DIDiagram.png') no-repeat center center; + background-size: 100% !important; + margin: 90px -10px 0 5px; + height: 300px !important; + width: 100% !important; + } +} + +mat-card-content p { + text-align: justify; + margin-top: -25px; +} + +mat-card-actions { + text-align: center; + + button { + margin-bottom: 10px !important; + } + button:hover { + border: 1px solid #007aff; + } +} diff --git a/apps/playground/src/app/quiz/containers/introduction/introduction.component.ts b/apps/playground/src/app/quiz/containers/introduction/introduction.component.ts new file mode 100644 index 000000000..4e0066666 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/introduction/introduction.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'codelab-quiz-intro', + templateUrl: './introduction.component.html', + styleUrls: ['./introduction.component.scss'] +}) +export class IntroductionComponent { + + constructor(private router: Router) {} + + startQuiz() { + this.router.navigateByUrl('/quiz/question/1'); + } +} diff --git a/apps/playground/src/app/quiz/containers/question/question.component.html b/apps/playground/src/app/quiz/containers/question/question.component.html new file mode 100644 index 000000000..dcb41c6a1 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/question/question.component.html @@ -0,0 +1,59 @@ + + +
+ Dependency Injection Quiz + + Assess your knowledge of Dependency Injection (DI) + +
+ + +
+
+
+ Score + + {{ correctAnswersCount }}/{{ totalQuestions }} + +
+
+ Question {{ question.questionId }} of {{ totalQuestions }} +
+
+ Time + + 0:0{{ timeLeft }} + +
+
+
+ +
{{ question.questionText }}
+ +
+ + +
+ +
+ +
+
+ +
+
+
+ +
+ + {{ progressValue.toFixed(0) }}% + +
+
+
diff --git a/apps/playground/src/app/quiz/containers/question/question.component.scss b/apps/playground/src/app/quiz/containers/question/question.component.scss new file mode 100644 index 000000000..79b9d25b1 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/question/question.component.scss @@ -0,0 +1,106 @@ +$font-stack: Space Mono, monospace; +$font-weight-max: 900; + +@font-face { + font-family: "Alarm Clock"; + src: url("../../../../../assets/alarm-clock.ttf") format("truetype"); +} + +section.scoreboard { + margin-top: 10px !important; + + .row { + display: inline; + } + .score { + float: left; + margin-left: 1rem; + } + .score .leader { + margin-left: 15px; + } + .badge { + float: left; + margin: 20px 10px 0 100px; + font-family: $font-stack; + font-size: 24px; + font-weight: $font-weight-max; + font-style: italic; + } + .time-left { + float: right; + margin-right: 1rem; + } + .time-left .leader { + margin-left: 20px; + } + .scoreboard { + font-family: "Alarm Clock", $font-stack; + font-weight: $font-weight-max; + font-size: 30px; + color: #006400; + display: inline-block; + margin: -5px 0 0 15px; + width: auto; + } + .leader { + display: block; + font-weight: $font-weight-max; + font-size: 18px; + text-transform: uppercase; + position: relative; + top: -5px; + } +} + +section#question { + font-family: $font-stack; + font-weight: 700; + font-size: 30px !important; + margin: 0 0 10px 0.4rem; + float: left; + border: 2px solid #007aff; + padding: 5px 10px 15px 20px; + background-color: #f5f5f5; + color: #0f0900; + width: 39rem !important; + height: auto; + vertical-align: middle; +} + +section.paging { + width: 40rem; + + mat-card-actions { + margin: -10px 0 10px 0; + + .nextQuestionNav { + float: right; + margin-right: -0.4rem; + } + + .showScoreNav { + width: 150px; + text-align: center; + margin: 0 auto; + } + + .nextQuestionNav:hover, .showScoreNav:hover { + border: 1px solid #007aff; + } + + .showScoreNav:hover { + width: 141.5px !important; + } + } +} + +section.progress-bar { + margin: 40px 0 10px 1.5rem; + width: 39rem; + height: auto; + + ngb-progressbar { + border-radius: 10px; + } +} diff --git a/apps/playground/src/app/quiz/containers/question/question.component.ts b/apps/playground/src/app/quiz/containers/question/question.component.ts new file mode 100644 index 000000000..12e631128 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/question/question.component.ts @@ -0,0 +1,279 @@ +import { Component, OnInit, Input, Output } from '@angular/core'; +import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; +import { FormGroup } from '@angular/forms'; + +import { QuizQuestion } from '../../model/QuizQuestion'; + +@Component({ + selector: 'codelab-question-container', + templateUrl: './question.component.html', + styleUrls: ['./question.component.scss'] +}) +export class QuestionComponent implements OnInit { + @Input() answer: string; + @Input() formGroup: FormGroup; + @Output() question: QuizQuestion; + totalQuestions: number; + percentage: number; + completionTime: number; + correctAnswersCount = 0; + + questionID = 0; + currentQuestion = 0; + questionIndex: number; + correctAnswer: boolean; + hasAnswer: boolean; + disabled: boolean; + quizIsOver: boolean; + progressValue: number; + timeLeft: number; + timePerQuestion = 20; + interval: any; + elapsedTime: number; + elapsedTimes = []; + blueBorder = '2px solid #007aff'; + + allQuestions: QuizQuestion[] = [ + { + questionId: 1, + questionText: 'What is the objective of dependency injection?', + options: [ + { optionValue: '1', optionText: 'Pass the service to the client.' }, + { optionValue: '2', optionText: 'Allow the client to find service.' }, + { optionValue: '3', optionText: 'Allow the client to build service.' }, + { optionValue: '4', optionText: 'Give the client part service.' } + ], + answer: '1', + explanation: 'a service gets passed to the client during DI', + selectedOption: '' + }, + { + questionId: 2, + questionText: 'Which of the following benefit from dependency injection?', + options: [ + { optionValue: '1', optionText: 'Programming' }, + { optionValue: '2', optionText: 'Testability' }, + { optionValue: '3', optionText: 'Software design' }, + { optionValue: '4', optionText: 'All of the above.' }, + ], + answer: '4', + explanation: 'DI simplifies both programming and testing as well as being a popular design pattern', + selectedOption: '' + }, + { + questionId: 3, + questionText: 'Which of the following is the first step in setting up dependency injection?', + options: [ + { optionValue: '1', optionText: 'Require in the component.' }, + { optionValue: '2', optionText: 'Provide in the module.' }, + { optionValue: '3', optionText: 'Mark dependency as @Injectable().' }, + { optionValue: '4', optionText: 'Declare an object.' } + ], + answer: '3', + explanation: 'the first step is marking the class as @Injectable()', + selectedOption: '' + }, + { + questionId: 4, + questionText: 'In which of the following does dependency injection occur?', + options: [ + { optionValue: '1', optionText: '@Injectable()' }, + { optionValue: '2', optionText: 'constructor' }, + { optionValue: '3', optionText: 'function' }, + { optionValue: '4', optionText: 'NgModule' }, + ], + answer: '2', + explanation: 'object instantiations are taken care of by the constructor in Angular', + selectedOption: '' + } + ]; + + constructor(private route: ActivatedRoute, private router: Router) { + this.route.paramMap.subscribe(params => { + this.setQuestionID(+params.get('questionId')); // get the question ID and store it + this.question = this.getQuestion; + }); + } + + ngOnInit() { + this.question = this.getQuestion; + this.totalQuestions = this.allQuestions.length; + this.timeLeft = this.timePerQuestion; + this.progressValue = 100 * (this.currentQuestion + 1) / this.totalQuestions; + this.countDown(); + } + + displayNextQuestion() { + this.resetTimer(); + this.increaseProgressValue(); + + this.questionIndex = this.questionID++; + + if (typeof document.getElementById('question') !== 'undefined') { + document.getElementById('question').innerHTML = this.allQuestions[this.questionIndex]['questionText']; + document.getElementById('question').style.border = this.blueBorder; + } + } + + navigateToNextQuestion(): void { + if (this.question.questionId < this.totalQuestions) { + // this.currentQuestion++; + this.router.navigate(['/quiz/question', this.getQuestionID() + 1]); + this.displayNextQuestion(); + } else { + this.navigateToResults(); + } + } + + navigateToResults(): void { + const navigationExtras: NavigationExtras = { + queryParams: { + totalQuestions: this.totalQuestions, + correctAnswersCount: this.correctAnswersCount, + percentage: this.percentage, + completionTime: this.completionTime, + allQuestions: JSON.stringify(this.allQuestions) + } + }; + this.router.navigate(['/quiz/results'], navigationExtras); + } + + // checks whether the question is a valid question and is answered correctly + checkIfAnsweredCorrectly() { + if (this.isThereAnotherQuestion() && this.question.selectedOption === this.question.answer) { + this.correctAnswer = true; + this.hasAnswer = true; + this.incrementCorrectAnswersCount(); + this.disabled = false; + + this.elapsedTime = Math.floor(this.timePerQuestion - this.timeLeft); + if (this.correctAnswersCount <= this.totalQuestions) { + this.elapsedTimes.push(this.elapsedTime); + } else { + this.elapsedTimes.push(0); + this.elapsedTime = 0; + this.completionTime = this.calculateTotalElapsedTime(this.elapsedTimes); + } + + this.quizDelay(3000); + this.navigateToNextQuestion(); + } + } + + // increase the correct answer count when the correct answer is selected + incrementCorrectAnswersCount() { + if (this.questionID <= this.totalQuestions) { + if (this.question && this.question.selectedOption === this.question.answer) { + if (this.correctAnswersCount === this.totalQuestions) { + return this.correctAnswersCount; + } else { + this.correctAnswer = true; + this.hasAnswer = true; + return this.correctAnswersCount++; + } + } else { + this.correctAnswer = false; + this.hasAnswer = false; + } + } + } + + // increase the progress value when the user presses the next button + increaseProgressValue() { + this.progressValue = 100 * (this.getQuestionID() + 1) / this.totalQuestions; + } + + // determine the percentage from amount of correct answers given and the total number of questions + calculateQuizPercentage() { + if (this.question.questionId < this.totalQuestions && this.correctAnswersCount === this.totalQuestions) { + this.percentage = 100; + } else { + this.percentage = 100 * this.correctAnswersCount / this.totalQuestions; + } + return this.percentage; + } + + calculateTotalElapsedTime(elapsedTimes) { + if (this.question.questionId < this.totalQuestions) { + this.completionTime = elapsedTimes.reduce((acc, cur) => acc + cur, 0); + return this.completionTime; + } + } + + /**************** public API ***************/ + getQuestionID() { + return this.questionID; + } + + setQuestionID(id: number) { + return this.questionID = id; + } + + isThereAnotherQuestion(): boolean { + return this.questionID <= this.allQuestions.length; + } + + get getQuestion(): QuizQuestion { + return this.allQuestions.filter( + question => question.questionId === this.questionID + )[0]; + } + + // countdown timer + private countDown() { + if (this.questionID <= this.totalQuestions) { + this.interval = setInterval(() => { + if (this.timeLeft > 0) { + this.timeLeft--; + + this.checkIfAnsweredCorrectly(); + + if (this.correctAnswersCount <= this.totalQuestions) { + this.calculateQuizPercentage(); + this.calculateTotalElapsedTime(this.elapsedTimes); + } + + // check if timer is expired and if the question is less than the last question + if (this.timeLeft === 0 && this.question && this.currentQuestion < this.totalQuestions) { + this.navigateToNextQuestion(); + } + + // check if timer is expired and if the question is the last question + if (this.timeLeft === 0 && this.question && this.currentQuestion === this.totalQuestions) { + this.elapsedTime = 0; + // this.completionTime = this.calculateTotalElapsedTime(this.elapsedTimes); + this.navigateToResults(); + } + + // check if last question has been answered + if (this.question && this.currentQuestion === this.totalQuestions && this.hasAnswer === true) { + this.elapsedTime = 0; + // this.completionTime = this.calculateTotalElapsedTime(this.elapsedTimes); + this.navigateToResults(); + this.quizIsOver = true; + } + + // disable the next button until an option has been selected + if (typeof this.question !== 'undefined') { + this.question.selectedOption === '' ? this.disabled = true : this.disabled = false; + } + } + }, 1000); + } + } + + private resetTimer() { + this.timeLeft = this.timePerQuestion; + } + + quizDelay(milliseconds) { + const start = new Date().getTime(); + let counter = 0; + let end = 0; + + while (counter < milliseconds) { + end = new Date().getTime(); + counter = end - start; + } + } +} diff --git a/apps/playground/src/app/quiz/containers/results/results.component.html b/apps/playground/src/app/quiz/containers/results/results.component.html new file mode 100644 index 000000000..7e8e727d6 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/results/results.component.html @@ -0,0 +1,90 @@ + + +
+ Dependency Injection Quiz +

Results

+
+ + +
+
+

Statistics

+ You scored {{ correctAnswersCount }} out of {{ totalQuestions }} questions correctly. + You completed the quiz in {{ elapsedMinutes }} minutes and {{ elapsedSeconds }} seconds. + +
+
+
+

Great job!

+
+
+
+

Not bad!

+
+
+
+

Try again!

+
+ + You scored {{ percentage }}% correctly (and quickly)! + You scored {{ percentage }}% correct. +
+
+ +
+
+ View a more detailed summary of your quiz +
+
+
+ + Question #{{ question.questionId }}: {{ question.questionText }} + +
+
+ + Your Answer: + Option {{ question.selectedOption }} — {{ question.options[question.selectedOption - 1].optionText }} + done + clear + (no answer provided) + +
+
+ + Correct Answer: + Option {{ question.answer }} — {{ question.options[question.answer - 1].optionText }} + +
+
+ + Explanation: + Option {{ question.answer }} was correct because {{ question.explanation }}. + +
+
+
+
+
+
+ +
+ + Restart Quiz + Back to Codelab + +
+ +
+ +
+

Challenge your friends!

+ +
+
+
diff --git a/apps/playground/src/app/quiz/containers/results/results.component.scss b/apps/playground/src/app/quiz/containers/results/results.component.scss new file mode 100644 index 000000000..6f758b8e6 --- /dev/null +++ b/apps/playground/src/app/quiz/containers/results/results.component.scss @@ -0,0 +1,196 @@ +$font-stack: Space Mono, monospace; +$font-weight-max: 900; + +section.results { + h3 { + text-align: center; + } + img { + width: 150px; + height: 150px; + margin: 0 auto !important; + display: flex; + justify-content: center; + text-align: center; + } + + section.statistics { + h3, span, .quiz-feedback, div span { + text-align: center; + } + + span { + display: block; + } + + .quiz-feedback { + margin-top: 20px; + + .great-job { + background: url('../../../../../../playground/assets/images/ngtrophy.jpg') no-repeat center center; + } + .not-bad { + background: url('../../../../../../playground/assets/images/notbad.jpg') no-repeat center center; + } + .try-again { + background: url('../../../../../../playground/assets/images/tryagain.jpeg') no-repeat center center; + } + .great-job, .not-bad, .try-again { + display: inline-block !important; + background-size: 100% !important; + border: 0 !important; + margin: -15px 0 0 -5px; + height: 160px !important; + width: 160px !important; + } + .great-job h3, .not-bad h3, .try-again h3 { + margin-top: -40px !important; + } + } + } + + section.quizSummary { + display: flex; + flex-direction: column; + + details { + text-align: center !important; + + summary { + font-size: 16px; + color: #007aff; + font-weight: $font-weight-max; + margin-bottom: 20px; + outline: none; + } + + .allQuestions { + clear: left; + } + + .quiz-summary-question { + font-family: $font-stack; + font-size: 14px; + border: 2px solid #385d8a; + border-radius: 5px; + color: #0f0900; + background-color: #f5f5f5; + margin-bottom: 15px; + padding: 10px; + text-align: left; + + .quiz-summary-field { + display: block !important; + margin-bottom: 10px; + text-align: left; + + span { + display: inline !important; + text-align: left; + font-size: 16px; + color: #00008b; + } + span.leader { + font-weight: $font-weight-max; + } + + mat-icon { + font-size: larger; + top: 10px !important; + } + mat-icon.correct { + color: #006400 !important; + font-weight: $font-weight-max; + } + mat-icon.incorrect { + color: #ff0000 !important; + font-weight: $font-weight-max; + } + } + } + } + } +} + +section.return { + clear: left; + text-align: center; + margin-top: -10px; + + a.btn { + margin-right: 15px; + background-color: #20b2aa; + color: white; + border: 1px solid black; + border-radius: 5px; + } +} + +section.challenge-social { + text-align: center; + + .social-buttons { + display: block; + + a.btn { + text-decoration: none; + margin-right: 20px; + padding: 9px 15px 8px 42px; + background: no-repeat 10px 5px; + background-size: 25px 25px; + color: white; + } + + a.btn.twitter { + background-color: #59adeb; + background-image: url('../../../../../assets/images/twitter.svg'); + top: 5px; + } + + a.btn.email { + background-color: #f0a121; + background-image: url('../../../../../assets/images/email.svg'); + top: 5px; + } + } +} + +/* add ripple effect to buttons */ +a.btn { + position: relative; + overflow: hidden; +} + +a.btn::after { + display: none; + content: ""; + position: absolute; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.3); + + width: 100px; + height: 100px; + margin-top: -50px; + margin-left: -50px; + + /* Center the ripple */ + top: 50%; + left: 50%; + + animation: ripple 1s; + opacity: 0; +} +a.btn:focus:not(:active)::after { + display: block; +} + +@keyframes ripple { + from { + opacity: 1; + transform: scale(0); + } + to { + opacity: 0; + transform: scale(10); + } +} diff --git a/apps/playground/src/app/quiz/containers/results/results.component.ts b/apps/playground/src/app/quiz/containers/results/results.component.ts new file mode 100644 index 000000000..73467460a --- /dev/null +++ b/apps/playground/src/app/quiz/containers/results/results.component.ts @@ -0,0 +1,37 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; + +import { QuizQuestion } from '../../model/QuizQuestion'; + +@Component({ + selector: 'codelab-quiz-results', + templateUrl: './results.component.html', + styleUrls: ['./results.component.scss'] +}) +export class ResultsComponent implements OnInit { + @Input() answer: string; + @Input() question: QuizQuestion; + allQuestions: QuizQuestion[]; + totalQuestions: number; + correctAnswersCount: number; + percentage: number; + completionTime: number; + elapsedMinutes: number; + elapsedSeconds: number; + codelabUrl = 'https://www.codelab.fun'; + + constructor(private route: ActivatedRoute) { + this.route.queryParams.subscribe((params: Params) => { + this.totalQuestions = +params['totalQuestions']; + this.correctAnswersCount = +params['correctAnswersCount']; + this.percentage = +params['percentage']; + this.completionTime = +params['completionTime']; + this.allQuestions = JSON.parse(params['allQuestions']); + }); + } + + ngOnInit() { + this.elapsedMinutes = Math.floor(this.completionTime / 60); + this.elapsedSeconds = this.completionTime % 60; + } +} diff --git a/apps/playground/src/app/quiz/jest.config.js b/apps/playground/src/app/quiz/jest.config.js new file mode 100644 index 000000000..12b435256 --- /dev/null +++ b/apps/playground/src/app/quiz/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + name: 'playground-quiz', + preset: '../../../jest.config.js', + coverageDirectory: '../../../coverage/apps/playground/quiz', + snapshotSerializers: [ + 'jest-preset-angular/AngularSnapshotSerializer.js', + 'jest-preset-angular/HTMLCommentSerializer.js' + ] +}; diff --git a/apps/playground/src/app/quiz/model/Option.ts b/apps/playground/src/app/quiz/model/Option.ts new file mode 100644 index 000000000..46f75a2aa --- /dev/null +++ b/apps/playground/src/app/quiz/model/Option.ts @@ -0,0 +1,4 @@ +export interface Option { + optionValue: string; + optionText: string; +} diff --git a/apps/playground/src/app/quiz/model/QuizQuestion.ts b/apps/playground/src/app/quiz/model/QuizQuestion.ts new file mode 100644 index 000000000..8a345d612 --- /dev/null +++ b/apps/playground/src/app/quiz/model/QuizQuestion.ts @@ -0,0 +1,10 @@ +import { Option } from './Option'; + +export interface QuizQuestion { + questionId: number; + questionText: string; + options: Option[]; + answer: string; + explanation: string; + selectedOption: string; +} diff --git a/apps/playground/src/app/quiz/tsconfig.app.json b/apps/playground/src/app/quiz/tsconfig.app.json new file mode 100644 index 000000000..8925f33e8 --- /dev/null +++ b/apps/playground/src/app/quiz/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["**/*.ts"], + "exclude": ["src/test-setup.ts", "**/*.spec.ts"] +} diff --git a/apps/playground/src/app/quiz/tsconfig.json b/apps/playground/src/app/quiz/tsconfig.json new file mode 100644 index 000000000..08c7db8c9 --- /dev/null +++ b/apps/playground/src/app/quiz/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "types": ["node", "jest"] + }, + "include": ["**/*.ts"] +} diff --git a/apps/playground/src/app/quiz/tsconfig.spec.json b/apps/playground/src/app/quiz/tsconfig.spec.json new file mode 100644 index 000000000..fd405a65e --- /dev/null +++ b/apps/playground/src/app/quiz/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/apps/playground/src/app/quiz/tslint.json b/apps/playground/src/app/quiz/tslint.json new file mode 100644 index 000000000..b6ad5c3a5 --- /dev/null +++ b/apps/playground/src/app/quiz/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tslint.json", + "rules": { + "directive-selector": [true, "attribute", "codelab", "camelCase"], + "component-selector": [true, "element", "codelab", "kebab-case"] + } +} diff --git a/apps/playground/src/styles.scss b/apps/playground/src/styles.scss index 524dd1092..3e051aed5 100644 --- a/apps/playground/src/styles.scss +++ b/apps/playground/src/styles.scss @@ -1 +1,53 @@ -@import '~@angular/material/prebuilt-themes/indigo-pink.css'; +@import "../../../../node_modules/@angular/material/prebuilt-themes/indigo-pink.css"; +$font-stack: Space Mono, monospace; +$font-weight-max: 900; + +mat-card { + margin: 0 auto; + margin: 5% 0 20px 25% !important; + width: 42rem; + height: inherit; + padding: 20px; + display: flex; + justify-content: center; + flex-direction: column; + position: relative; + border: 1px solid black; + border-radius: 10px !important; +} +mat-card:hover { + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2) !important; + transition: 0.3s !important; +} + +mat-card-header { + text-align: center; + display: flex; + justify-content: center; + + .header-image { + float: left; + background: url('../assets/images/angular.png') no-repeat center center; + background-size: cover; + margin: -10px 0 0 -10px; + height: 100px !important; + width: 100px !important; + } + + mat-card-title { + font-family: $font-stack; + font-weight: $font-weight-max; + font-size: 30px !important; + margin: -10px 0 10px 10px; + color: #007aff; + text-align: center; + } + mat-card-subtitle { + font-family: $font-stack; + font-weight: $font-weight-max; + font-size: 17.5px !important; + font-style: italic; + color: #808080; + text-align: center; + } +}