diff --git a/apps/codelab/src/app/codelabs/about/about.component.html b/apps/codelab/src/app/codelabs/about/about.component.html index 92a1d5081..ef5b45b2a 100644 --- a/apps/codelab/src/app/codelabs/about/about.component.html +++ b/apps/codelab/src/app/codelabs/about/about.component.html @@ -1,52 +1,100 @@ -
- codelab.fun + +
+
+

codelab.fun

+
    +
  • 🦊 @thekiba_io
  • +
  • 🍚 @kirjs
  • +
  • 🦠
  • +
+
What is codelab.fun
-
- Online interactive angular tutorial no setup -
+
+

Online interactive angular tutorial no setup

+
-
- Interactive code samples -
+
+

Interactive code samples

+
-
- Hands on exercises -
+
+

Hands on exercises

+
-
- All open source/Angular Ivy/on Github -
+
+

All open source/Angular Ivy/on Github

-
- Regular offline contributors meetings -
+
+

Almost 50 contributors

+
+
+ +
+

Regular offline contributors meetings

+

20+ Live-events in 10+ countries

-
+

~1000 users a month

-
+
+
-

Almost 50 contributors

-
+

Live-Stream "Π—Π²ΡƒΠΊΠΈ программистов"

+

+ @kirjs and @thekiba_io meet on weekends and do long technical streams in + russian, https://www.twitch.tv/kirjs +

+
- +

Live-Stream "Π—Π²ΡƒΠΊΠΈ программистов"

@kirjs and @thekiba_io meet on weekends and do long technical streams in russian, https://www.twitch.tv/kirjs

-
+
+
+ +
+

Overview

+
    +
  • How it all started
  • +
  • Managing exercise source code
  • +
  • Feedback
  • +
  • Creating slides
  • +
  • Storing code samples
  • +
  • Highlighting directives
  • +
  • Types
  • +
  • i18n
  • +
  • What's next
  • +
  • How to contribute
  • +
Nov 11, 2016
Angular 2.1
-
Kirjs did not know Angular
-
Move exercises to the browser
- - -
Running tests (mocha / babel + traversing AST)
-
- - The goal is to quickly assess whether user's code does what we want. -
+
Move exercises to the browser
- - Initially the plan was to run unit tests in an iframe with TestBed, mocha - + chai (code TBD) +

version 1 looked like this:

+
- -
Types
-
There's no types (TODO: Explain)
+ + +
Managing source code in exercises
+
+

Exercises are progressive

+ +
- -
Next level
+
+ +
- -
Creating slides library with Angular
+
+

Need a way to manage source code in a way that:

+
    +
  • Defined in text format
  • +
  • Easy to modify versions
  • +
  • Changes in older versions propagate to the newer versions
  • +
  • Works in a browser
  • +
+
-
-

What's an ideal API for a presentation?

- -
+
+

One folder per exercise

+ + + + -
-

Can we use ng-template?

- -
+
    +
  • βœ… Defined in text format
  • +
  • 🚫Easy to modify versions
  • +
  • + 🚫🚫🚫Changes in older versions propagate to the newer versions🚫🚫🚫 +
  • +
  • βœ… Works in a browser
  • +
+
-
-

Can we use ng-template?

- -
+
+

This sounds like a version control system...?

+
    +
  1. Create a github repo
  2. +
  3. Create the app commit by commit
  4. +
  5. + Use + isomorphic-git +
  6. +
+
    +
  • βœ… Defined in text format
  • +
  • 🀷 Easy to modify versions
  • +
  • βœ… Changes in older versions propagate to the newer versions
  • +
  • βœ… Works in a browser
  • +
+
- -
- Highlights -
+
+

This sounds like a version control system...?

+
    +
  1. Create a github repo
  2. +
  3. Create the app commit by commit
  4. +
  5. + Use + isomorphic-git +
  6. +
+
    +
  • βœ… Defined in text format
  • +
  • 🀷 Easy to modify versions
  • +
  • βœ… Changes in older versions propagate to the newer versions
  • +
  • βœ… Works in a browser
  • +
  • 🚫 Exists in 2016
  • +
  • 🚫 Version history (Yo dawg, who controls the version control?)
  • +
+
-
-

How to implement this?

-
-
+
+

Can we have our own Angular-aware VCS in a browser?

+ +
    +
  • βœ… Defined in text format
  • +
  • βœ… Easy to modify versions
  • +
  • βœ… Changes in older versions propagate to the newer versions
  • +
  • βœ… Works in a browser
  • +
  • 🚫 Doesn't require a ton of code to maintain
  • +
+
-
-

We need a popup which

-
    -
  • plays well with Monaco
  • -
  • Updates when the code is updated
  • -
  • Not obstructive
  • -
-
+
+

New meta-language

+ +
    +
  • βœ… Defined in text format
  • +
  • βœ… Easy to modify versions
  • +
  • βœ… Changes in older versions propagate to the newer versions
  • +
  • βœ… Works in a browser
  • +
  • + 🚫 I shouldn't be the only human in the universe understanding how it + works +
  • +
+
-
-

We don't. We use highlight instead

- -
-
-

We don't. We use highlight instead

- -
+
+

Differ

+ +
+
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+
    +
  • UI displaying multiple versions
  • +
  • Use existing VCS tools for commits/merging
  • +
  • Save full repo snapshot in a VCS
  • +
+
+
-
-

Find position by regex or string

- -
+ + +
+ feedback +
+
+

Users should be able to leave feedback

+
    +
  • Feedback has to be attached to a slide
  • +
  • Minimum work required from presentation creator
  • +
+ +
-
-

Add classes using Monaco's deltaDecorations

- -
+
+

Can we use router URL (slide index)?

+
    +
  • 🚫 Feedback has to be attached to a slide
  • +
  • βœ… Minimum work required from presentation creator
  • +
+

If a slide is added, all indexes get shifted

+
- -
Storing code samples
-
-

This can't be hard!

- -
-
-

Can we use multiline strings?

- -
-
-

Custom interpolation to the rescue?

- -
+
+

Can we hash slide content?

+
    +
  • 🚫 Feedback has to be attached to a slide
  • +
  • βœ… Minimum work required from presentation creator
  • +
+

Is slide content gets changed - all feedback will be lost

+
-
-

Can we use ng-template?

- -
-
-

Can we use ngNonBindable?

- -
-
-

Can we use Script tag?

- -
-
-

Can we use Textarea?

- -
-
-

Textarea + ngNonBindable

- -
+
+

Set each ID manually

+
    +
  • βœ… Feedback has to be attached to a slide
  • +
  • 🚫 Minimum work required from presentation creator
  • +
+
-
-

Code in the component

- -
+
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+

This would not be an issue if all the content was in a DB

+
+
-
-

raw-loader - code in files

- -
+ + +
Creating slides library with Angular
- +
+

What's an ideal API for a presentation written in Angular?

+ +
-
- Can we use figure out the types now? -
+
+

What do we want

+
    +
  • Clean and concise API
  • +
  • + Ability to have + feedback per slide +
  • +
  • On-demand per-slide content loading
  • +
  • Additional per-slides attributes
  • +
+
-
-

Let's fake it!

- - -
+
+

What's an ideal API for a presentation written in Angular?

+ +
    +
  • βœ… Clean and concise API
  • +
  • + 🚫 Ability to have + feedback per slide +
  • +
  • 🚫 On-demand per-slide content loading
  • +
  • 🚫 Additional per-slides attributes
  • +
+
-
-

Then webstorm started shouting at me.

-
-
-
-

Let's fake it!

- - -
-
-

Types work!

-
-
+
+

The same but with ids

+ - -
-

So we kinda ready for prime time, except nothing really works

- -
+
    +
  • βœ… Clean and concise API
  • +
  • + βœ… Ability to have + feedback per slide +
  • +
  • 🚫 On-demand per-slide content loading
  • +
  • 🚫 Additional per-slides attributes
  • +
+
-
-

People will probably get really mad?

- -
+
+

Can we use ng-template?

+ +
    +
  • 🚫 Clean and concise API
  • +
  • + 🚫 Ability to have + feedback per slide +
  • +
  • βœ… On-demand per-slide content loading
  • +
  • 🚫 Additional per-slides attributes
  • +
+
-
-

Let's add feedback feature

- -
-
-

We use firebase

- -
+
+

Structural directive?

+ +
    +
  • βœ… Clean and concise API
  • +
  • + βœ… Ability to have + feedback per slide +
  • +
  • βœ… On-demand per-slide content loading
  • +
  • βœ… Additional per-slides attributes
  • +
+
-
-

- We want the feedback to be as specific as possible, so we need to identify - the slide -

- -
+
+

But how do we get the ID?

+ +
    +
  • 🚫 Clean and concise API
  • +
  • + βœ… Ability to have + feedback per slide +
  • +
  • βœ… On-demand per-slide content loading
  • +
  • βœ… Additional per-slides attributes
  • +
+
-
-

We Already use routing, and each slide has a #

- -
+
+

What if we need more attributes

+ +
    +
  • 🚫🚫🚫🚫 Clean and concise API 🚫🚫🚫🚫
  • +
  • + βœ… Ability to have + feedback per slide +
  • +
  • βœ… .On-demand per-slide content loading
  • +
  • βœ… Additional per-slides attributes
  • +
+
-
-

We can't generate and ID

- -
-
-

We have to give an ID manually

- -
+
+ +
    +
  • βœ… Clean and concise API
  • +
  • + βœ… Ability to have + feedback per slide +
  • +
  • βœ… On-demand per-slide content loading
  • +
  • βœ… Additional per-slides attributes
  • +
+
-
-

TADA

- -
+
+

But how???

+
- +
+
+ πŸ’€πŸ™€Don't try this at home!πŸ™€πŸ’€ +
+ +
- -
i18n
+
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+ +

Angular to support attributes for structural directives.

+
+
-
-

We use standard Angular i18n

- -
-
-

But how can we translate code samples?

- -
-
-
    -
  • Have strings in template with ids
  • -
  • Then query it in the Component
  • -
- {{ "@ViewChild('translations', { static: true }) translation;" }} - -
+ + +
+
+

I'm watching you

+

🦊

+

Always unsubscribe from observables!

+
+ +
+
-
- How to we translate it in a way that scales? -
+ + +
Storing code samples
+
+

Requirements:

+
    +
  • Compiles
  • +
  • Easy to manage
  • +
  • Syntax highlighting
  • +
+
-
-

Codelab uses PoEditor

-
-
+
+

This can't be hard!

+ +
    +
  • 🚫 Compiles
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Can we use multiline strings?

+ +
    +
  • 🚫 Compiles
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Custom interpolation to the rescue?

+ +
    +
  • 🚫 Compiles
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
-
-

Thanks PoEditor for providing us with an Open Source license!

-
-
+
+

Can we use ng-template?

+ +
    +
  • 🚫 Compiles
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Can we use ngNonBindable?

+ +
    +
  • 🚫 Compiles
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Can we use Script tag?

+ +
    +
  • βœ… Compiles
  • +
  • πŸš«πŸ™€ Can't get access to it πŸ™€πŸš« (security)
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Can we use a comment?

+ +
    +
  • βœ… Compiles
  • +
  • πŸš«πŸ™€ Can't get access to it πŸ™€πŸš« (Angular strips comments)
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Textarea?

+ +
    +
  • βœ… Compiles (although my IDE complains)
  • +
  • βœ… Can get access
  • +
  • πŸš«πŸ™€ Curlies intepolate
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+
+

Textarea + ngNonBindable

+ +
    +
  • βœ… Compiles
  • +
  • βœ… Can get access
  • +
  • βœ… Curlies do not interpolate
  • +
  • βœ… Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+ +
+

✨ We won! ✨

+
+ +
+
+ +
Now, we need a sane way
+ +
+

Code in the component

+ + +
    +
  • βœ… Compiles
  • +
  • βœ… Can get access
  • +
  • βœ… Curlies do not interpolate
  • +
  • 🚫 Easy to manage
  • +
  • 🚫 Syntax highlighting
  • +
+
+ +
+

Storing it in appropriate files

+ +
    +
  • βœ… Compiles
  • +
  • βœ… Can get access
  • +
  • βœ… Curlies do not interpolate
  • +
  • 🀷 ‍Easy to manage
  • +
  • βœ… Syntax highlighting
  • +
+
+ +
+

raw-loader - code in files

+ +
    +
  • βœ… Compiles
  • +
  • βœ… Can get access
  • +
  • βœ… Curlies do not interpolate
  • +
  • 🀷 ‍Easy to manage
  • +
  • βœ… Syntax highlighting
  • +
+
+ +
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+ + + +

UI for editing code (and content)

+
+
-
Anybody can help with translation
-
- Already translated into Russian
+ + +
+ Highlights +
+ +
+

How to implement this?

+
+
+ +
+

We need a popup which

+
    +
  • plays well with Monaco
  • +
  • Updates when the code is updated
  • +
  • Not obstructive
  • +
  • Provides additional context
  • +
+
+ +
+

ng-popover, and 10 other libraries

+
    +
  • 🚫 plays well with Monaco
  • +
  • 🚫 Updates when the code is updated
  • +
  • 🚫 Not obstructive
  • +
  • βœ… Provides additional context
  • +
+
+ +
+

We don't need popovers, we need highlight

+ +
    +
  • βœ… plays well with Monaco
  • +
  • βœ… Updates when the code is updated
  • +
  • βœ… Not obstructive
  • +
  • 🚫 Provides additional context
  • +
+
+ +
+

Find position by regex or string

+ +
+ +
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+
+
    +
  • βœ… plays well with Monaco
  • +
  • βœ… Updates when the code is updated
  • +
  • βœ… Not obstructive
  • +
  • βœ… Provides additional context
  • +
+
+
+ + + +
Types
+
+

Types requirements:

+
    +
  • Autocomplete words
  • +
  • Quick to implement
  • +
  • Quick to update
  • +
  • Lightweight
  • +
+
+
+

No types Β―\_(ツ)_/Β―

+
    +
  • 🚫 Autocomplete works
  • +
  • βœ… Quick to implement
  • +
  • βœ… Quick to update
  • +
  • βœ… Lightweight
  • +
+
+ +
+

Fake types!

+ + + +
    +
  • βœ… Autocomplete works
  • +
  • 🚫 Quick to implement
  • +
  • 🚫 Quick to update
  • +
  • βœ… Lightweight
  • +
+
+ +
+

Then webstorm started shouting at me.

+
+
+
+

Let's rename the file

+ + +
+ +
+

Types work!

+
+
+ +
+

Let's use real types!

+ +
    +
  • βœ… Autocomplete works
  • +
  • βœ… Quick to implement
  • +
  • βœ… Quick to update
  • +
  • βœ… Lightweight
  • +
  • 🚫 Actually works
  • +
+
+ +
+

@angular/core/core.d.ts

+ +
+ +
+

@rxjs/index.d.ts

+ +
+ +
+

It can't be too many files?

+
+ +
+

It can't be too many files?

+ + + + + + + + + + + + + + + + +
# FilesSize
Angular280814M
RxJS6862.7M
+
+ +
+

Let's prebundle

+ +
    +
  • βœ… Autocomplete works
  • +
  • βœ… Quick to implement
  • +
  • 🀷 Quick to update
  • +
  • 🚫 Lightweight
  • +
  • βœ… Actually works
  • +
+
+ +
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+ +
    +
  1. Parse all user .ts files
  2. +
  3. Extract all the imports
  4. +
  5. Fetch types from a CDN (e.g. npmcdn.com)
  6. +
+
    +
  • βœ… Autocomplete works
  • +
  • βœ… Quick to implement
  • +
  • βœ… Quick to update
  • +
  • βœ… Lightweight
  • +
  • 🚫 Actually works
  • +
+
+ Many other tools like stackblitz do that, but proxy it through a server +
+
+
+ + + +
i18n
+ +
+

We use standard Angular i18n

+ +
+
+

But how can we translate code samples?

+ +
+
+
    +
  • Have strings in template with ids
  • +
+ + + +
+ +
+
    +
  • Use ViewChild to extract the messages
  • +
+ + + +
+ +
+

i18n with DOM nodes in a template

+
    +
  • βœ… It works!
  • +
  • 🚫 It's ugly
  • +
  • 🚫 Hard to work with
  • +
  • 🚫 Leads to having lots of stale messages
  • +
+
+ +
+

☁️☁️🌀 My dream solution ☁️☁️☁️️

+

Angular supporting non-template i18n

+
+ +
+

We use PoEditor

+
+ Thanks PoEditor for providing us with an Open Source license! +
+
+
+
+ + + +
What's next?
+
+

What's next?

+
    +
  • More milestones
  • +
  • Other topics
  • +
  • UI for editing
  • +
  • Publishing slide-library
  • +
+
+
+ + + +
How to contribute?
+
+

All kinds of work

+
    +
  • Code
  • +
  • Docs
  • +
  • Translations
  • +
  • Product management
  • +
  • Design
  • +
  • Hosting events
  • +
  • Teaching
  • +
+
+
+ +
+
+

codelab.fun

+
    +
  • 🦊 @thekiba_io
  • +
  • 🍚 @kirjs
  • +
+
+
Let's make it faster
+ +
Running tests (mocha / babel + traversing AST)
+ +
+ - The goal is to quickly assess whether user's code does what we want. +
+
+ - Initially the plan was to run unit tests in an iframe with TestBed, mocha + + chai (code TBD) +
+ + + +
Next level
- ΠΈΠ·Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹:
ΠΎΡ‡Π΅Π½ΡŒ Π΄ΠΎΠ»Π³ΠΎ ΠΏΠ΅Ρ€Π΅ΡΠΎΠ±ΠΈΡ€Π°Π»ΠΎΡΡŒ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ пСрСсоздавался iframe
diff --git a/apps/codelab/src/app/codelabs/about/about.component.scss b/apps/codelab/src/app/codelabs/about/about.component.scss index 5b77e2453..8123f5c9a 100644 --- a/apps/codelab/src/app/codelabs/about/about.component.scss +++ b/apps/codelab/src/app/codelabs/about/about.component.scss @@ -32,7 +32,7 @@ text-align: center; color: black; font-size: 100px; - font-weight: 280; + font-weight: 300; } .types-error { @@ -55,6 +55,18 @@ background-image: url('./images/highlight-slides.png'); } +.zvuki { + background-image: url('./images/zvuki.png'); +} + +.zvuki2 { + background-image: url('./images/zvuki2.png'); +} + +.visitors { + background-image: url('./images/visitors.png'); +} + .img-todo { content: 'lol'; border: 50px white dotted; @@ -72,6 +84,7 @@ color: white; } } + h2 { padding: 20px; } @@ -99,3 +112,44 @@ h2 { .community { background-image: url('./images/codelab.jpeg'); } + +.contributors { + background-image: url('./images/contributors.png'); +} + +.v1 { + background-image: url('./images/v1.jpg'); +} + +.live { + background-image: url('./images/live.jpg'); +} + +.dream-highlight { + background-image: url('./images/dream-highlight.jpg'); +} + +table { + width: 800px; +} +td { + font-size: 2vw; + font-weight: 300; + padding: 1vw; +} + +[main][main][main] { + flex-direction: row; + justify-content: center; + text-align: center; + display: flex; + align-items: center; + height: 100%; + ul { + list-style: none; + } + + h2 { + font-size: 15vw; + } +} diff --git a/apps/codelab/src/app/codelabs/about/about.component.ts b/apps/codelab/src/app/codelabs/about/about.component.ts index f4731b7d4..e00fef9ee 100644 --- a/apps/codelab/src/app/codelabs/about/about.component.ts +++ b/apps/codelab/src/app/codelabs/about/about.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; +import { ng2tsConfig } from '../../../../../../ng2ts/ng2ts'; declare const require; @@ -7,28 +8,97 @@ declare const require; templateUrl: './about.component.html', styleUrls: ['./about.component.scss'] }) -export class AboutComponent implements OnInit { +export class AboutComponent { code = { - fakeTypes: require('!!raw-loader!./samples/fake-types.d.ts.not-really'), slides: { + initial: require('!!raw-loader!./samples/slides/initial.html'), template: require('!!raw-loader!./samples/slides/ng-template.html'), component: require('!!raw-loader!./samples/slides/slide-component.html'), - directive: require('!!raw-loader!./samples/slides/structural-directive.html') + directive: require('!!raw-loader!./samples/slides/structural-directive.html'), + directiveId: require('!!raw-loader!./samples/slides/structural-directive-ids.html'), + directiveIdMilestone: require('!!raw-loader!./samples/slides/structural-directive-ids-milestone.html'), + final: require('!!raw-loader!./samples/slides/structural-directive-final.html') }, storingCode: { plain: require('!!raw-loader!./samples/storing-code/plain.html'), backticks: require('!!raw-loader!./samples/storing-code/backticks.html'), backticksMatch: [/{{`/, /`}}/], + ngTemplate: require('!!raw-loader!./samples/storing-code/ng-template.html'), + ngNonBindable: require('!!raw-loader!./samples/storing-code/ng-non-bindable.html'), + script: require('!!raw-loader!./samples/storing-code/script.html'), + comment: require('!!raw-loader!./samples/storing-code/comment.html'), + textarea: require('!!raw-loader!./samples/storing-code/textarea.html'), + textareaNonBindable: require('!!raw-loader!./samples/storing-code/textarea-non-bindable.html'), + rawLoader: require('!!raw-loader!./about.component.ts'), + inComponent: require('!!raw-loader!./samples/storing-code/in-component.ts'), interpolation: { 'bootstrap.ts': require('!!raw-loader!./samples/storing-code/interpolations.ts') } }, + gettingId: { + code: require('!!raw-loader!@codelab/slides/src/lib/slide/slide.directive.ts') + }, + + stages: { + differ: require('!!raw-loader!@codelab/utils/src/lib/differ/differ'), + builders: require('!!raw-loader!./samples/versions/builders'), + component: require('!!raw-loader!../../../../../../ng2ts/app.component'), + firstStage: "import { Component } from '@angular/core';" + }, + exercise: { + translations: { + createClassAppComponent: "Create a class called 'AppComponent'", + exportClass: 'Export the class', + addComponentDecorator: 'Add a Component decorator for the class', + addSelectorMyApp: + "Add a selector to the component decorator and set it to 'my-app'", + addTemplateHelloMewTube: + 'Add a template that contains: h1 with a text "Hello MewTube!"' + }, + config: ng2tsConfig.milestones[1].exercises[1] + }, + preview: [ + ng2tsConfig.milestones[1].exercises[1], + ng2tsConfig.milestones[2].exercises[1], + ng2tsConfig.milestones[3].exercises[1], + ng2tsConfig.milestones[4].exercises[1], + ng2tsConfig.milestones[5].exercises[0], + ng2tsConfig.milestones[6].exercises[0], + ng2tsConfig.milestones[7].exercises[0] + ], + simpleAngular: { + code: { + 'bootstrap.ts': require('!!raw-loader!./../../shared/angular-code/bootstrap.ts'), + 'app.module.ts': require('!!raw-loader!./../../shared/angular-code/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./../../shared/angular-code/app.component.ts'), + 'index.html': require('!!raw-loader!./../../shared/angular-code/index.html'), + 'styles.css': ` + h1:first-child { + font-size: 100px !important; + } + ` + }, + files: ['app.component.ts'] + }, + highlights: { - find: require('!!raw-loader!@codelab/code-demos/src/lib/code-demo-editor/utils/utils') + appComponent: { 'app.component.ts': 'AppComponent' }, + find: require('!!raw-loader!@codelab/code-demos/src/lib/code-demo-editor/utils/utils'), + directive: require('!!raw-loader!@codelab/code-demos/src/lib/code-demo-editor/directives/code-demo-editor.highlight.directive') + }, + types: { + realtypes: require('!!raw-loader!./samples/types/realtypes.ts'), + fakeTypes: require('!!raw-loader!./samples/fake-types.d.ts.not-really'), + coreTypes: require('!!raw-loader!@angular/core/core.d.ts'), + rxjsTypes: require('!!raw-loader!rxjs/index.d.ts'), + bundler: require('!!raw-loader!@codelab/code-demos/assets/runner/ng-dts/bundler.ts') + }, + fox: { + unsubscribe: require('!!raw-loader!./samples/fox/unsubscribe') + }, + i18n: { + template: require('!!raw-loader!../angular/typescript/typescript/typescript.component.html'), + ts: require('!!raw-loader!../angular/typescript/typescript/typescript.component.ts') } }; - - constructor() {} - - ngOnInit() {} } diff --git a/apps/codelab/src/app/codelabs/about/about.module.ts b/apps/codelab/src/app/codelabs/about/about.module.ts index 8988f0fc1..c8bc34f55 100644 --- a/apps/codelab/src/app/codelabs/about/about.module.ts +++ b/apps/codelab/src/app/codelabs/about/about.module.ts @@ -6,11 +6,24 @@ import { RouterModule } from '@angular/router'; import { AboutComponent } from './about.component'; import { CodeDemoModule } from '@codelab/code-demos'; import { FormsModule } from '@angular/forms'; +import { CodelabComponentsModule } from '../../components/codelab-components.module'; +import { StagesComponent } from './stages/stages.component'; +import { ButtonsNavBarModule } from '../../components/buttons-nav-bar/buttons-nav-bar.module'; +import { NewProgressBarModule } from '../../../../../kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.module'; const routes = RouterModule.forChild(SlidesRoutes.get(AboutComponent)); @NgModule({ - declarations: [AboutComponent], - imports: [CommonModule, SlidesModule, routes, CodeDemoModule, FormsModule] + declarations: [AboutComponent, StagesComponent], + imports: [ + CommonModule, + SlidesModule, + routes, + CodeDemoModule, + FormsModule, + CodelabComponentsModule, + ButtonsNavBarModule, + NewProgressBarModule + ] }) export class AboutModule {} diff --git a/apps/codelab/src/app/codelabs/about/images/contributors.png b/apps/codelab/src/app/codelabs/about/images/contributors.png new file mode 100644 index 000000000..dfd2446c2 Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/contributors.png differ diff --git a/apps/codelab/src/app/codelabs/about/images/debug.png b/apps/codelab/src/app/codelabs/about/images/debug.png new file mode 100644 index 000000000..cc5a772b1 Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/debug.png differ diff --git a/apps/codelab/src/app/codelabs/about/images/dream-highlight.jpg b/apps/codelab/src/app/codelabs/about/images/dream-highlight.jpg new file mode 100644 index 000000000..cd2fc7f2e Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/dream-highlight.jpg differ diff --git a/apps/codelab/src/app/codelabs/about/images/live.jpg b/apps/codelab/src/app/codelabs/about/images/live.jpg new file mode 100644 index 000000000..38071c3c7 Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/live.jpg differ diff --git a/apps/codelab/src/app/codelabs/about/images/v1.jpg b/apps/codelab/src/app/codelabs/about/images/v1.jpg new file mode 100644 index 000000000..61a74593a Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/v1.jpg differ diff --git a/apps/codelab/src/app/codelabs/about/images/visitors.png b/apps/codelab/src/app/codelabs/about/images/visitors.png new file mode 100644 index 000000000..7b7c3c619 Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/visitors.png differ diff --git a/apps/codelab/src/app/codelabs/about/images/zvuki.png b/apps/codelab/src/app/codelabs/about/images/zvuki.png new file mode 100644 index 000000000..cb87da400 Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/zvuki.png differ diff --git a/apps/codelab/src/app/codelabs/about/images/zvuki2.png b/apps/codelab/src/app/codelabs/about/images/zvuki2.png new file mode 100644 index 000000000..c97792788 Binary files /dev/null and b/apps/codelab/src/app/codelabs/about/images/zvuki2.png differ diff --git a/apps/codelab/src/app/codelabs/about/samples/feedback/feedback.ts b/apps/codelab/src/app/codelabs/about/samples/feedback/feedback.ts new file mode 100644 index 000000000..8c629ad0f --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/feedback/feedback.ts @@ -0,0 +1,4 @@ +submitFeeback({ + id: '', + text: 'Hello ngRuAir!' +}); diff --git a/apps/codelab/src/app/codelabs/about/samples/fox/unsubscribe.ts b/apps/codelab/src/app/codelabs/about/samples/fox/unsubscribe.ts new file mode 100644 index 000000000..28feccdfa --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/fox/unsubscribe.ts @@ -0,0 +1,20 @@ +import { takeUntil } from 'rxjs/operators'; +import { Observable, ReplaySubject } from 'rxjs'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; + +@Component({ + selector: '🦊', + templateUrl: '🦊.html' +}) +export class AppComponent implements OnInit, OnDestroy { + @Input() readonly request: Observable; + destroy: ReplaySubject = new ReplaySubject(1); + + ngOnInit() { + this.request.pipe(takeUntil(this.destroy)).subscribe(); + } + + ngOnDestroy() { + this.destroy.next(null); + } +} diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/initial.html b/apps/codelab/src/app/codelabs/about/samples/slides/initial.html new file mode 100644 index 000000000..ba93beff0 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/slides/initial.html @@ -0,0 +1,11 @@ + + +

Awesome slide

+
+ + Code sample + + + + +
diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html b/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html index ac97206a2..9e289d5a6 100644 --- a/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html +++ b/apps/codelab/src/app/codelabs/about/samples/slides/ng-template.html @@ -1,11 +1,11 @@ - +

Awesome slide

- -

Code sample

+ + Code sample - - + +
diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html b/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html index a3ef823ca..ac56d2f82 100644 --- a/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html +++ b/apps/codelab/src/app/codelabs/about/samples/slides/slide-component.html @@ -1,11 +1,11 @@ - +

Awesome slide

- -

Code sample

+ + Code sample - - + +
diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-final.html b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-final.html new file mode 100644 index 000000000..76c19e5eb --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-final.html @@ -0,0 +1,11 @@ + +
+

Awesome slide

+
+
+ Code sample +
+
+ +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-ids-milestone.html b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-ids-milestone.html new file mode 100644 index 000000000..0cfdf57b7 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-ids-milestone.html @@ -0,0 +1,11 @@ + +
+

Awesome slide

+
+
+ Code sample +
+
+ +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-ids.html b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-ids.html new file mode 100644 index 000000000..ac9aa1066 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive-ids.html @@ -0,0 +1,11 @@ + +
+

Awesome slide

+
+
+ Code sample +
+
+ +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html index 1cfbd9f6f..675366591 100644 --- a/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html +++ b/apps/codelab/src/app/codelabs/about/samples/slides/structural-directive.html @@ -1,11 +1,11 @@ -
+

Awesome slide

-
-

Code sample

+
+ Code sample
-
- +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html index cc57e7b58..90a4b1d36 100644 --- a/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/backticks.html @@ -1,9 +1,12 @@
- - {{` import { Component } from '@angular/core'; @Component({ selector: - 'hello-world', template: ` -

Hello I'm an Angular app!

-

Very soon you will learn how to create and bootstrap me!

- ` }) export class AppComponent {} `}} -
+
+    {{` import { Component } from '@angular/core';
+
+    @Component({
+      selector: 'hello-world',
+      template: `
+          

Hello I'm an Angular app!

+

Very soon you will learn how to create and bootstrap me!

+ ` }) export class AppComponent {} `}} +
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/comment.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/comment.html new file mode 100644 index 000000000..706874048 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/comment.html @@ -0,0 +1,11 @@ +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/in-component.ts b/apps/codelab/src/app/codelabs/about/samples/storing-code/in-component.ts new file mode 100644 index 000000000..ee9e4463a --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/in-component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hello-world', + template: ` + {{ code }} + ` +}) +export class AppComponent { + code = `import { Component } from '@angular/core'; + + @Component({ + selector: 'hello-world', + template: \` +

Hello I'm an Angular app!

+

Very soon you will learn how to create and bootstrap me!

+ \` }) export class AppComponent {}`; +} diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/ng-non-bindable.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/ng-non-bindable.html new file mode 100644 index 000000000..0158ed2b2 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/ng-non-bindable.html @@ -0,0 +1,9 @@ +
+
+ import { Component } from '@angular/core'; @Component({ selector: + 'hello-world', template: ` +

Hello I'm an Angular app!

+

Very soon you will learn how to create and bootstrap me!

+ ` }) export class AppComponent {} +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/ng-template.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/ng-template.html new file mode 100644 index 000000000..25d03c54a --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/ng-template.html @@ -0,0 +1,9 @@ +
+ + import { Component } from '@angular/core'; @Component({ selector: + 'hello-world', template: ` +

Hello I'm an Angular app!

+

Very soon you will learn how to create and bootstrap me!

+ ` }) export class AppComponent {} +
+
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html index 56f62aa14..b181d6c33 100644 --- a/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/plain.html @@ -1,9 +1,13 @@
- - import { Component } from '@angular/core'; @Component({ selector: - 'hello-world', template: ` -

Hello I'm an Angular app!

-

Very soon you will learn how to create and bootstrap me!

- ` }) export class AppComponent {} -
+
+    import { Component } from '@angular/core';
+
+    @Component({
+      selector: 'hello-world',
+      template: `
+        

Hello I'm an Angular app!

+

Very soon you will learn how to create and bootstrap me!

+ ` }) + export class AppComponent {} +
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/script.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/script.html new file mode 100644 index 000000000..68eb52c42 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/script.html @@ -0,0 +1,12 @@ +
+ +
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/textarea-non-bindable.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/textarea-non-bindable.html new file mode 100644 index 000000000..3fd997b8d --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/textarea-non-bindable.html @@ -0,0 +1,13 @@ +
+ +
diff --git a/apps/codelab/src/app/codelabs/about/samples/storing-code/textarea.html b/apps/codelab/src/app/codelabs/about/samples/storing-code/textarea.html new file mode 100644 index 000000000..6a0c300cc --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/storing-code/textarea.html @@ -0,0 +1,12 @@ +
+ +
diff --git a/apps/codelab/src/app/codelabs/about/samples/types/realtypes.ts b/apps/codelab/src/app/codelabs/about/samples/types/realtypes.ts new file mode 100644 index 000000000..7d64c94b1 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/types/realtypes.ts @@ -0,0 +1,9 @@ +monaco.languages.typescript.typescriptDefaults.addExtraLib( + require('!!!raw-loader!@angular/core/core.d.ts'), + '@angular/core/index.d.ts' +); + +monaco.languages.typescript.typescriptDefaults.addExtraLib( + require('!!!raw-loader!@angular/common/common.d.ts'), + '@angular/common/index.d.ts' +); diff --git a/apps/codelab/src/app/codelabs/about/samples/versions/builders.ts b/apps/codelab/src/app/codelabs/about/samples/versions/builders.ts new file mode 100644 index 000000000..597644fab --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/samples/versions/builders.ts @@ -0,0 +1,17 @@ +Repository() + .version('create-component', v => { + v.file('app.component.ts') + .getImport('@angular.core') + .add('Component'); + }) + .version('create-component-solution', v => { + v.file('app.component.ts') + .getClass('AppComponent') + .getDecorator('Component') + .addProperty('template', '

lol

'); + }) + .version('inputs', v => { + v.file('app.component.ts') + .getImport('@angular.core') + .add('Input'); + }); diff --git a/apps/codelab/src/app/codelabs/about/stages/stages.component.css b/apps/codelab/src/app/codelabs/about/stages/stages.component.css new file mode 100644 index 000000000..bc2f2e3d1 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/stages/stages.component.css @@ -0,0 +1,22 @@ +.selected { + background: #6cae00; + color: white; +} + +ul { + margin: 0 20px 0 0; + padding: 0; +} + +:host li:not(.lol) { + margin: 0; + font-size: 14px !important; + list-style: none; + padding: 8px 4px; + display: block; + cursor: pointer; +} + +.wrapper { + display: flex; +} diff --git a/apps/codelab/src/app/codelabs/about/stages/stages.component.html b/apps/codelab/src/app/codelabs/about/stages/stages.component.html new file mode 100644 index 000000000..6ad585162 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/stages/stages.component.html @@ -0,0 +1,33 @@ +
+
    +
  • + {{ file }} +
  • +
+
    +
  • + {{ stage }} +
  • +
+
+ +

Initial code

+ +

Solution

+ + +
+
+
diff --git a/apps/codelab/src/app/codelabs/about/stages/stages.component.spec.ts b/apps/codelab/src/app/codelabs/about/stages/stages.component.spec.ts new file mode 100644 index 000000000..ec4cc7b56 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/stages/stages.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StagesComponent } from './stages.component'; + +describe('StagesComponent', () => { + let component: StagesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [StagesComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(StagesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/codelab/src/app/codelabs/about/stages/stages.component.ts b/apps/codelab/src/app/codelabs/about/stages/stages.component.ts new file mode 100644 index 000000000..27ac6f4c0 --- /dev/null +++ b/apps/codelab/src/app/codelabs/about/stages/stages.component.ts @@ -0,0 +1,69 @@ +import { Component, OnInit } from '@angular/core'; +import { ng2tsConfig } from '../../../../../../../ng2ts/ng2ts'; + +@Component({ + selector: 'slides-stages', + templateUrl: './stages.component.html', + styleUrls: ['./stages.component.css'] +}) +export class StagesComponent implements OnInit { + files: string[]; + selectedFile: string; + stages: string[]; + selectedStage: string; + + displayedContent?: { + solution: string; + template: string; + }; + + constructor() { + this.files = this.extractFiles() as string[]; + this.selectFile(this.files[0]); + } + + selectFile(file: string) { + this.selectedFile = file; + this.stages = this.extractStages(file) as string[]; + this.selectStage(this.stages[0]); + } + + extractStages(file) { + return ng2tsConfig.milestones + .map(m => m.exercises) + .flat() + .filter(e => e.files && e.files.some(f => f.path === file)) + .map(e => e.name); + } + + extractFiles() { + const allFiles = ng2tsConfig.milestones + .map(m => m.exercises) + .flat() + .filter(e => e.files) + .map(e => e.files.map(f => f.path)) + .flat(); + + return [...new Set(allFiles)]; + } + + extractSingleFile(stage: string, file: string) { + const result = ng2tsConfig.milestones + .map(m => m.exercises) + .flat() + .find(e => e.name === stage) + .files.find(f => f.path === file); + + this.displayedContent = { + solution: result.solution, + template: result.template + }; + } + + ngOnInit(): void {} + + selectStage(stage: string) { + this.selectedStage = stage; + this.extractSingleFile(stage, this.selectedFile); + } +} diff --git a/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html b/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html index 899cba331..0315f5274 100644 --- a/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html +++ b/apps/codelab/src/app/codelabs/angular/component-tree/component-tree.component.html @@ -128,6 +128,12 @@

Change the size to 100 and color to red to recreate the Japanese flag.

+ diff --git a/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html b/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html index f436bb307..182f6fa51 100644 --- a/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html +++ b/apps/codelab/src/app/codelabs/angular/create-first-app/create-first-app.component.html @@ -212,7 +212,7 @@

Create first Angular component!

diff --git a/apps/codelab/src/app/codelabs/angular/forms/forms.component.html b/apps/codelab/src/app/codelabs/angular/forms/forms.component.html index b9183b7d7..a4966db7e 100644 --- a/apps/codelab/src/app/codelabs/angular/forms/forms.component.html +++ b/apps/codelab/src/app/codelabs/angular/forms/forms.component.html @@ -32,19 +32,20 @@

We have this simple form, let's find out how to map input values with the ones from our Angular component!

- +

Simple Form

First we have to add FormsModule to our NgModule.

- - +
@@ -54,9 +55,11 @@

component.

Try changing the inputs and see the values updated.

- +
[(NgModel)] - Banana in the box is a simple mnemonic for the braces order. @@ -66,13 +69,14 @@

Try changing the inputs and see the values updated.

Validation

- It's really easy to add validation for your inputs using predefined - Angular directives. + Add validation to your inputs using predefined Angular directives.

Let's make username required

- +
If you clear the input it'll be marked with an error, however no error will be displayed. We'll learn how to display it in the next slide @@ -88,9 +92,11 @@

Now we let's display validation error. It takes 2 steps:

  • Use usernameModel's errors property.
  • - +
    Try clearing the username input and see the error displayed.
    @@ -105,14 +111,12 @@

    that Angular provides out of the box

      -
    • min
    • -
    • max
    • +
    • min and max (for numbers)
    • required
    • -
    • requiredTrue
    • +
    • requiredTrue (for checkboxes)
    • email
    • -
    • minLength
    • -
    • maxLength
    • -
    • pattern
    • +
    • minLength and maxLength (for text)
    • +
    • pattern (regular expression)
    It's also possible to create custom validators, but it's out of scope for @@ -129,33 +133,31 @@

    There's one small issue though, if we don't have initial values, the error is displayed right away.

    - - +
    - Touched & Dirty + Dirty

    Luckily we can check if the user interacted with an input using - touched property. + dirty property.

    • dirty is true if the user changed the value of the input.
    • -
    • - touched is true if the user focused on the input, and then blured - without changing the value. -
    - +
    - Try focusing/bluring the username field, or adding some value and - then removing to see the error. + Try adding and then removing value in the username field to see the + error.
    @@ -171,9 +173,11 @@

  • mat-error - Smarter error wrapper
  • - +
    Note that we don't need to #name the input anymore.
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts b/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts index db58b0fc0..670fc954e 100644 --- a/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts +++ b/apps/codelab/src/app/codelabs/angular/forms/forms.component.ts @@ -5,52 +5,10 @@ import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts'; import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools'; +import { CodeDemos } from '../../../shared/models'; declare const require; -interface FileHighlights { - appModule?: RegExp | RegExp[]; - appHtml?: RegExp | RegExp[]; - appComponent?: RegExp | RegExp[]; -} - -function formsConfig(code, highlights: FileHighlights = {}) { - const files = { - appHtml: require('!!raw-loader!./samples/basic/app.1.html'), - appModule: require('!!raw-loader!./samples/basic/app.module.ts'), - appComponent: require('!!raw-loader!./samples/basic/app.component.ts'), - ...code - }; - - return { - files: [ - CodelabFile.Html('app') - .setCode(files.appHtml) - .withHighlight(highlights.appHtml), - - CodelabFile.TypeScriptFile('app.module') - .setCode(files.appModule) - .withHighlight(highlights.appModule), - - CodelabFile.TypeScriptFile('app.component') - .setCode(files.appComponent) - .withHighlight(highlights.appComponent), - - CodelabFile.TypeScriptFile('bootstrap') - .setCode(require('!!raw-loader!./samples/basic/main.ts')) - .makeBootstrappable(), - - CodelabFile.Css('styles').setCode( - require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css') - ), - - CodelabFile.Css('extra').setCode( - require('!!raw-loader!./samples/basic/styles.css') - ) - ] - }; -} - @Component({ selector: 'codelab-slides-forms', templateUrl: './forms.component.html', @@ -58,73 +16,127 @@ function formsConfig(code, highlights: FileHighlights = {}) { }) export class FormsComponent implements AfterViewInit { @ViewChild('translations', { static: false }) translations; - exercise: ExerciseConfigTemplate; - samples = { - basicForm: formsConfig( - { appHtml: require('!!raw-loader!./samples/basic/app.1.html') }, - { - appModule: /FormsModule]/ - } - ), - ngModel: formsConfig( - { appHtml: require('!!raw-loader!./samples/basic/app.2.html') }, - { - appHtml: [/ngModel/g] - } - ), - ngValidation1: formsConfig( - { appHtml: require('!!raw-loader!./samples/basic/app.3.html') }, - { - appHtml: [/required/] + exercise: ExerciseConfigTemplate = this.exercises.getExercises(7, 0); + code: CodeDemos = { + simpleForm: { + code: { + 'app.component.html': require('!!raw-loader!./samples/simple-form/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') + }, + files: ['app.component.html'] + }, + formsModule: { + code: { + 'app.component.html': require('!!raw-loader!./samples/simple-form/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') + }, + files: ['app.module.ts'], + highlights: { 'app.module.ts': /, FormsModule/ } + }, + ngModel: { + code: { + 'app.component.html': require('!!raw-loader!./samples/ng-model/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') + }, + files: ['app.component.html', 'app.component.ts'], + highlights: { + 'app.component.html': ['"username"', '"email"'], + 'app.component.ts': ['username', 'email'] } - ), - ngValidation2: formsConfig( - { appHtml: require('!!raw-loader!./samples/basic/app.4.html') }, - { - appHtml: [/#usernameModel="ngModel"/, /
    /] + }, + addValidation: { + code: { + 'app.component.html': require('!!raw-loader!./samples/add-validation/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') + }, + files: ['app.component.html'], + highlights: { + 'app.component.html': ['required'] } - ), - touched: formsConfig( - { - appHtml: require('!!raw-loader!./samples/basic/app.4.html'), - appComponent: require('!!raw-loader!./samples/basic/app.component.5.ts') + }, + addError: { + code: { + 'app.component.html': require('!!raw-loader!./samples/add-error/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') }, - { - appComponent: /username = ''/ + files: ['app.component.html'], + highlights: { + 'app.component.html': [ + '#usernameModel="ngModel"', + '*ngIf="usernameModel.invalid"', + 'Username is required' + ] } - ), - touched2: formsConfig( - { - appHtml: require('!!raw-loader!./samples/basic/app.5.html'), - appComponent: require('!!raw-loader!./samples/basic/app.component.5.ts') + }, + alwaysRequired: { + code: { + 'app.component.html': require('!!raw-loader!./samples/add-error/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/always-required/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') + }, + files: ['app.component.html'] + }, + dirty: { + code: { + 'app.component.html': require('!!raw-loader!./samples/dirty/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/always-required/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': require('!!raw-loader!./samples/basic/styles.css') }, - { - appHtml: /(usernameModel.touched \|\| usernameModel.dirty)/ + files: ['app.component.html'], + highlights: { + 'app.component.html': ['usernameModel.dirty'] } - ), - ngMaterial: formsConfig( - { - appHtml: require('!!raw-loader!./samples/basic/app.6.html'), - appModule: require('!!raw-loader!./samples/basic/app.module.6.ts').replace( - 'component.5', - 'component' /*Stupid hack*/ - ) + }, + material: { + code: { + 'app.component.html': require('!!raw-loader!./samples/material/app.component.html'), + 'app.module.ts': require('!!raw-loader!./samples/material/app.module.ts'), + 'app.component.ts': require('!!raw-loader!./samples/always-required/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./samples/bootstrap.ts'), + 'material-theme.css': require('!!raw-loader!@angular/material/prebuilt-themes/indigo-pink.css'), + 'styles.css': 'mat-form-field { display: block }' }, - { - appHtml: [ - //, - /<\/mat-form-field>/, - /matInput/, - /.*<\/mat-error>/ + files: ['app.component.html'], + highlights: { + 'app.component.html': [ + 'matInput', + 'mat-form-field', + 'mat-error', + 'mat-label' ] } - ) + } }; + private t: Record; - constructor(private exercises: Ng2TsExercises) { - this.exercise = exercises.getExercises(7, 0); - } + constructor(private readonly exercises: Ng2TsExercises) {} ngAfterViewInit() { this.t = extractMessages(this.translations); diff --git a/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts b/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts index ca299ca6a..47486a5a2 100644 --- a/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts +++ b/apps/codelab/src/app/codelabs/angular/forms/forms.module.ts @@ -9,6 +9,7 @@ import { Ng2TsExercises } from '../../../../../../../ng2ts/ng2ts'; import { CodelabComponentsModule } from '../../../components/codelab-components.module'; import { SlidesModule } from '@codelab/slides'; import { FormsModule } from '@angular/forms'; +import { CodeDemoModule } from '@codelab/code-demos'; const routes = RouterModule.forChild([...SlidesRoutes.get(FormsComponent)]); @@ -20,7 +21,8 @@ const routes = RouterModule.forChild([...SlidesRoutes.get(FormsComponent)]); BrowserWindowModule, CodelabComponentsModule, SlidesModule, - FormsModule + FormsModule, + CodeDemoModule ], declarations: [FormsComponent], exports: [FormsComponent], diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/add-error/app.component.html b/apps/codelab/src/app/codelabs/angular/forms/samples/add-error/app.component.html new file mode 100644 index 000000000..44c6a9b38 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/add-error/app.component.html @@ -0,0 +1,13 @@ + + + +
    name: {{ username }}, email: {{ email }}
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/add-validation/app.component.html b/apps/codelab/src/app/codelabs/angular/forms/samples/add-validation/app.component.html new file mode 100644 index 000000000..84ae03797 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/add-validation/app.component.html @@ -0,0 +1,10 @@ + + + +
    name: {{ username }}, email: {{ email }}
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/always-required/app.component.ts b/apps/codelab/src/app/codelabs/angular/forms/samples/always-required/app.component.ts new file mode 100644 index 000000000..9a647c6ce --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/always-required/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: 'app.component.html' +}) +export class AppComponent { + username = ''; + email = 'pirojok@angular.io'; +} diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/app.component.ts b/apps/codelab/src/app/codelabs/angular/forms/samples/app.component.ts new file mode 100644 index 000000000..f87d6c78b --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: 'app.component.html' +}) +export class AppComponent { + username = 'Pirojok'; + email = 'pirojok@angular.io'; +} diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/app.module.ts b/apps/codelab/src/app/codelabs/angular/forms/samples/app.module.ts new file mode 100644 index 000000000..d1b8795f3 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/app.module.ts @@ -0,0 +1,11 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppComponent } from './app.component'; +import { FormsModule } from '@angular/forms'; + +@NgModule({ + imports: [BrowserModule, FormsModule], + declarations: [AppComponent], + bootstrap: [AppComponent] +}) +export class AppModule {} diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css b/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css index f2a00b407..6de799882 100644 --- a/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/basic/styles.css @@ -20,5 +20,10 @@ body { } .values { - margin-top: 20px; + padding: 16px; +} + +label { + display: block; + padding: 16px; } diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/bootstrap.ts b/apps/codelab/src/app/codelabs/angular/forms/samples/bootstrap.ts new file mode 100644 index 000000000..fb38f68fb --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/bootstrap.ts @@ -0,0 +1,23 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app.module'; +import { ResourceLoader } from '@angular/compiler'; +import * as code from './code'; + +class MyResourceLoader extends ResourceLoader { + get(url: string): Promise { + const templateId = Object.keys(code).find(key => + key.includes(url.replace(/[\/\.-]/gi, '_')) + ); + const template = code[templateId]; + if (!template) { + console.log(template); + // tslint:disable-next-line:no-debugger + debugger; + } + return Promise.resolve(template); + } +} + +platformBrowserDynamic().bootstrapModule(AppModule, { + providers: [{ provide: ResourceLoader, useClass: MyResourceLoader, deps: [] }] +} as any); diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/dirty/app.component.html b/apps/codelab/src/app/codelabs/angular/forms/samples/dirty/app.component.html new file mode 100644 index 000000000..aa6f4eab7 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/dirty/app.component.html @@ -0,0 +1,13 @@ + + + +
    name: {{ username }}, email: {{ email }}
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/material/app.component.html b/apps/codelab/src/app/codelabs/angular/forms/samples/material/app.component.html new file mode 100644 index 000000000..cbf5c8de2 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/material/app.component.html @@ -0,0 +1,12 @@ + + Name + + Username is required + + + + Email + + + +
    name: {{ username }}, email: {{ email }}
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/material/app.module.ts b/apps/codelab/src/app/codelabs/angular/forms/samples/material/app.module.ts new file mode 100644 index 000000000..9310b4508 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/material/app.module.ts @@ -0,0 +1,20 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppComponent } from './app.component'; +import { FormsModule } from '@angular/forms'; +import { MatInputModule } from '@angular/material/input'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + MatFormFieldModule, + MatInputModule, + NoopAnimationsModule + ], + declarations: [AppComponent], + bootstrap: [AppComponent] +}) +export class AppModule {} diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/ng-model/app.component.html b/apps/codelab/src/app/codelabs/angular/forms/samples/ng-model/app.component.html new file mode 100644 index 000000000..f3bf1d20e --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/ng-model/app.component.html @@ -0,0 +1,10 @@ + + + +
    name: {{ username }}, email: {{ email }}
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/simple-form/app.component.html b/apps/codelab/src/app/codelabs/angular/forms/samples/simple-form/app.component.html new file mode 100644 index 000000000..d94fa6148 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/simple-form/app.component.html @@ -0,0 +1,8 @@ +
    + *name: + +
    +
    + email: + +
    diff --git a/apps/codelab/src/app/codelabs/angular/forms/samples/styles.css b/apps/codelab/src/app/codelabs/angular/forms/samples/styles.css new file mode 100644 index 000000000..ad691a2fb --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/forms/samples/styles.css @@ -0,0 +1,2 @@ +label { +} diff --git a/apps/codelab/src/app/codelabs/angular/material/material.component.html b/apps/codelab/src/app/codelabs/angular/material/material.component.html index d700acd8d..45d01bb30 100644 --- a/apps/codelab/src/app/codelabs/angular/material/material.component.html +++ b/apps/codelab/src/app/codelabs/angular/material/material.component.html @@ -81,9 +81,9 @@

    Adding a toolbar takes 2 steps:

    Note that Angular animations come in a separate module. We're including @@ -97,9 +97,9 @@

    Adding a toolbar takes 2 steps:

    Now let's add material card.

    @@ -108,9 +108,9 @@

    Now let's add material card.

    Header and an image.

    @@ -119,9 +119,9 @@

    Header and an image.

    Adding some actions....

    Note that for the button we're using mat-button attribute instead @@ -175,8 +175,8 @@

    Read more on theming Angular Material diff --git a/apps/codelab/src/app/codelabs/angular/material/material.component.ts b/apps/codelab/src/app/codelabs/angular/material/material.component.ts index 9141260ba..b372c3c5d 100644 --- a/apps/codelab/src/app/codelabs/angular/material/material.component.ts +++ b/apps/codelab/src/app/codelabs/angular/material/material.component.ts @@ -11,6 +11,7 @@ import { } from '../../../../../../../ng2ts/ng2ts'; import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools'; import { CodelabFile } from '../../../shared/helpers/codelabFile'; +import { CodeDemos } from '../../../shared/models'; declare const require; @@ -70,77 +71,71 @@ export class MaterialComponent implements AfterViewInit { purple: require('!!raw-loader!@angular/material/prebuilt-themes/purple-green.css') }; - code = { - material: { - step1: { - code: { - 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), - 'app.module.ts': require('!!raw-loader!./samples/step1/app.module.ts'), - 'app.html': require('!!raw-loader!./samples/step1/app.html'), - 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), - 'styles.css': this.themes.indigo - }, - files: ['app.module.ts', 'app.html'], - highlights: { - 'app.module.ts': 'MatToolbarModule,', - 'app.html': // - } + code: CodeDemos = { + step1: { + code: { + 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), + 'app.module.ts': require('!!raw-loader!./samples/step1/app.module.ts'), + 'app.html': require('!!raw-loader!./samples/step1/app.html'), + 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), + 'styles.css': this.themes.indigo }, - step2: { - code: { - 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), - 'app.module.ts': require('!!raw-loader!./samples/step2/app.module.ts'), - 'app.html': require('!!raw-loader!./samples/step2/app.html'), - 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), - 'styles.css': this.themes.indigo - }, - files: ['app.module.ts', 'app.html'], - highlights: { - 'app.module.ts': /MatCardModule,/, - 'app.html': // - } + files: ['app.module.ts', 'app.html'], + highlights: { + 'app.module.ts': 'MatToolbarModule,', + 'app.html': // + } + }, + step2: { + code: { + 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), + 'app.module.ts': require('!!raw-loader!./samples/step2/app.module.ts'), + 'app.html': require('!!raw-loader!./samples/step2/app.html'), + 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), + 'styles.css': this.themes.indigo }, - step3: { - code: { - 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), - 'app.module.ts': require('!!raw-loader!./samples/step2/app.module.ts'), - 'app.html': require('!!raw-loader!./samples/step3/app.html'), - 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), - 'styles.css': this.themes.indigo - }, - files: ['app.html'], - highlights: { - 'app.html': // - } + files: ['app.module.ts', 'app.html'], + highlights: { + 'app.module.ts': /MatCardModule,/, + 'app.html': // + } + }, + step3: { + code: { + 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), + 'app.module.ts': require('!!raw-loader!./samples/step2/app.module.ts'), + 'app.html': require('!!raw-loader!./samples/step3/app.html'), + 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), + 'styles.css': this.themes.indigo }, - step4: { - code: { - 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), - 'app.module.ts': require('!!raw-loader!./samples/step4/app.module.ts'), - 'app.html': require('!!raw-loader!./samples/step4/app.html'), - 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), - 'styles.css': this.themes.indigo - }, - files: ['app.module.ts', 'app.html'], - highlights: { - 'app.module.ts': /MatButtonModule\n/, - 'app.html': // - } + files: ['app.html'], + highlights: { + 'app.html': // + } + }, + step4: { + code: { + 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), + 'app.module.ts': require('!!raw-loader!./samples/step4/app.module.ts'), + 'app.html': require('!!raw-loader!./samples/step4/app.html'), + 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), + 'styles.css': this.themes.indigo }, - themes: { - code: { - 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), - 'app.module.ts': require('!!raw-loader!./samples/step4/app.module.ts'), - 'app.html': require('!!raw-loader!./samples/step4/app.html'), - 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), - 'styles.css': this.themes.indigo - }, - files: ['app.html', 'styles.css'] + files: ['app.module.ts', 'app.html'], + highlights: { + 'app.module.ts': /MatButtonModule\n/, + 'app.html': // + } + }, + themes: { + code: { + 'app.component.ts': require('!!raw-loader!./samples/basic/app.component.ts'), + 'app.module.ts': require('!!raw-loader!./samples/step4/app.module.ts'), + 'app.html': require('!!raw-loader!./samples/step4/app.html'), + 'bootstrap.ts': require('!!raw-loader!./samples/basic/main.ts'), + 'styles.css': this.themes.indigo }, - theme: matExercise( - `MatToolbarModule,\n MatCardModule,\n MatButtonModule`, - require('!!raw-loader!./samples/basic/app.4.html') - ) + files: ['app.html', 'styles.css'] } }; private theme = 'indigo'; @@ -156,7 +151,7 @@ export class MaterialComponent implements AfterViewInit { setTheme(theme) { this.theme = theme; - this.code.material.themes.code['styles.css'] = this.themes[theme]; - this.code.material.themes.code = { ...this.code.material.themes.code }; + this.code.themes.code['styles.css'] = this.themes[theme]; + this.code.themes.code = { ...this.code.themes.code }; } } diff --git a/apps/codelab/src/app/codelabs/angular/router/router.component.ts b/apps/codelab/src/app/codelabs/angular/router/router.component.ts index 9029146b6..6e965ea9b 100644 --- a/apps/codelab/src/app/codelabs/angular/router/router.component.ts +++ b/apps/codelab/src/app/codelabs/angular/router/router.component.ts @@ -1,4 +1,3 @@ -import { CodelabFile } from '../../../shared/helpers/codelabFile'; import { AfterViewInit, Component, ViewChild } from '@angular/core'; import { ExerciseConfigTemplate, @@ -31,8 +30,7 @@ export class RouterComponent implements AfterViewInit { 'components/kitten.ts': require('!!raw-loader!./samples/simple-router/components/kitten.ts'), 'components/puppy.ts': require('!!raw-loader!./samples/simple-router/components/puppy.ts'), 'bootstrap.ts': require('!!raw-loader!./samples/simple-router/main.ts'), - 'index.html': require('!!raw-loader!./samples/simple-router/index.html'), - 'components/.html': require('!!raw-loader!./samples/simple-router/index.html') + 'index.html': require('!!raw-loader!./samples/simple-router/index.html') }, config: { files: ['app.module.ts'], diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-pre/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-pre/app.component.ts new file mode 100644 index 000000000..d9adabf63 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding-pre/app.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Hello {{ fullName() }}!

    + + ` +}) +export class AppComponent { + firstName = 'Pierre-Auguste'; + lastName = 'Renoir'; + avatar = 'assets/images/renoir.jpg'; + + fullName() { + return this.firstName + ' ' + this.lastName; + } +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding/app.component.ts new file mode 100644 index 000000000..563484dba --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/data-binding/app.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Hello {{ fullName() }}!

    + + ` +}) +export class AppComponent { + firstName = 'Pierre-Auguste'; + lastName = 'Renoir'; + avatar = 'assets/images/renoir.jpg'; + + fullName() { + return this.firstName + ' ' + this.lastName; + } +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/expressions/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/expressions/app.component.ts new file mode 100644 index 000000000..767afbdad --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/expressions/app.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Hello {{ fullName() }}!

    + ` +}) +export class AppComponent { + firstName = 'Pierre-Auguste'; + lastName = 'Renoir'; + fullName() { + return this.firstName + ' ' + this.lastName; + } +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/interpolation/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/interpolation/app.component.ts new file mode 100644 index 000000000..bbfaa095f --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/interpolation/app.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Hello {{ firstName }}!

    + ` +}) +export class AppComponent { + firstName = 'Pierre-Auguste'; +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/intro/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/intro/app.component.ts new file mode 100644 index 000000000..18e8ad62b --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/intro/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: '

    πŸ”₯πŸ’– Angular Magic πŸ’–πŸ”₯

    ' +}) +export class AppComponent {} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/intro/bootstrap.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/intro/bootstrap.ts new file mode 100644 index 000000000..9a5ae6ce4 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/intro/bootstrap.ts @@ -0,0 +1,14 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [BrowserModule, NoopAnimationsModule], + declarations: [AppComponent], + bootstrap: [AppComponent] +}) +export class AppModule {} + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/ng-if/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/ng-if/app.component.ts new file mode 100644 index 000000000..c93e240c0 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/ng-if/app.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Hello {{ firstName }}!

    + + ` +}) +export class AppComponent { + firstName = 'Pierre-Auguste'; + avatar = 'assets/images/renoir.jpg'; + + onDisplay() { + return false; // Try changing to true! + } +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/repeating/app.component.ts b/apps/codelab/src/app/codelabs/angular/templates/samples/repeating/app.component.ts new file mode 100644 index 000000000..06f04df7a --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/repeating/app.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Puppies names:

    + ??? + + ` +}) +export class AppComponent { + puppies = ['Schumann', 'Mendelssohn', 'Bach']; +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/samples/styles.css b/apps/codelab/src/app/codelabs/angular/templates/samples/styles.css new file mode 100644 index 000000000..c5a5e6cc0 --- /dev/null +++ b/apps/codelab/src/app/codelabs/angular/templates/samples/styles.css @@ -0,0 +1,19 @@ +body, +html { + margin: 0; + padding: 2vw; + font-family: sans-serif; +} + +h1, +h2 { + margin: 0; + padding: 0; +} + +h1 { + font-size: 6vw; +} +h2 { + font-size: 4vw; +} diff --git a/apps/codelab/src/app/codelabs/angular/templates/templates.component.html b/apps/codelab/src/app/codelabs/angular/templates/templates.component.html index d23046841..50b54ca5a 100644 --- a/apps/codelab/src/app/codelabs/angular/templates/templates.component.html +++ b/apps/codelab/src/app/codelabs/angular/templates/templates.component.html @@ -131,10 +131,12 @@

    Angular has a very expressive template system, which takes HTML as a base, and extends it with custom elements

    - + +
    @@ -143,10 +145,11 @@

    Double curlies include the appropriate component property value

    - +
    Backticks ` `, are magic quotes that allow multi-line strings and text interpolation. @@ -160,10 +163,11 @@

    Simple expressions are also allowed, you can run a component method (like fullName() below), or calculate 323213+34234

    - +
    @@ -195,10 +199,12 @@

    String interpolation {{ curlies }} can also be used to pass a value to a child element's attribute

    - + +
    @@ -207,10 +213,11 @@

    Better option is to use property binding [attribute] = property

    - +
    You can use arbitrary expressions in the binding.
    @@ -223,9 +230,9 @@

    Angular supports more advanced property bindings than just attribute name

    @@ -287,10 +294,12 @@

    This conditional expression will add or remove an element from the DOM if it evaluates as a truthy

    - +
    @@ -323,10 +332,13 @@

    the page. Angular has a special syntax for that called *ngFor, let's see how it works on the next slide

    - + +
    @@ -337,8 +349,8 @@

    HTML attributes in Angular are case sensitive: diff --git a/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts b/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts index dcaf69710..86d8eb6d2 100644 --- a/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts +++ b/apps/codelab/src/app/codelabs/angular/templates/templates.component.ts @@ -1,159 +1,154 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { ng2tsConfig } from '../../../../../../../ng2ts/ng2ts'; -import { - displayAngularComponent, - displayAngularComponentWithHtml -} from '../../../shared/helpers/helpers'; +import { displayAngularComponent } from '../../../shared/helpers/helpers'; import { extractMessages } from '@codelab/utils/src/lib/i18n/i18n-tools'; +import { CodeDemos, MilestoneWithDemos } from '../../../shared/models'; declare const require; -const baseCode = 'TODO'; - @Component({ selector: 'codelab-slides-templates', templateUrl: './templates.component.html', styleUrls: ['./templates.component.css'] }) -export class TemplatesComponent implements OnInit { +export class TemplatesComponent implements OnInit, MilestoneWithDemos { t: { [key: string]: string }; exercises = [ ng2tsConfig.milestones[2].exercises[1], ng2tsConfig.milestones[2].exercises[2], ng2tsConfig.milestones[2].exercises[3] ]; - curlies = '{{ property }}'; // TODO(kirjs): we can't access tanslation in OnInit hook iwht static set to false // need to consider changing how we set code @ViewChild('translations', { static: true }) translation; - code: any = {}; - - constructor() {} - - ngOnInit() { - this.t = extractMessages(this.translation); - - this.code = { - template: { - intro: displayAngularComponent(`import {Component} from '@angular/core'; - -@Component({ - selector: 'my-app', - template: '

    Hello World!

    ' -}) -export class AppComponent { -}`), - - matches: { - curlies: { 'app.component.ts': [/{{.*}}/, /firstName = .*/] }, - curliesFullName: { 'app.component.ts': [/{{.*}}/, /fullName\(\){/] }, - curliesAttribute: { 'app.component.ts': [/"{{.*}}"/, /avatar = .*/] }, - template: { 'app.component.ts': /

    .*<\/h1>/ }, - squares: { 'app.component.ts': /\[.*]/ } - }, - interpolation: displayAngularComponent( - `import {Component} from '@angular/core'; - -@Component({ - selector: 'my-app', - template: \`

    - Hello {{firstName}}! -

    \` -}) -export class AppComponent { - firstName = 'Pierre-Auguste'; - lastName = 'Renoir'; -}`, - '' - ), - interpolationMethod: displayAngularComponent(`import {Component} from '@angular/core'; - -@Component({ - selector: 'my-app', - template: \`

    Hello {{fullName()}}!

    \` -}) -export class AppComponent { - firstName = 'Pierre-Auguste'; - lastName = 'Renoir'; - fullName(){ - return this.firstName + " " + this.lastName - } -}`), - dataBindingPre: displayAngularComponent(`import {Component} from '@angular/core'; - -@Component({ - selector: 'my-app', - template: \`

    Hello {{fullName()}}!

    - - \` -}) -export class AppComponent { - firstName = 'Pierre-Auguste'; - lastName = 'Renoir'; - avatar = 'assets/images/renoir.jpg'; - fullName(){ return this.firstName + " " + this.lastName } -}`), - dataBinding: displayAngularComponent(`import {Component} from '@angular/core'; - -@Component({ - selector: 'my-app', - template: \`

    Hello {{fullName()}}!

    - - \` -}) -export class AppComponent { - firstName = 'Pierre-Auguste'; - lastName = 'Renoir'; - avatar = 'assets/images/renoir.jpg'; - fullName(){ return this.firstName + " " + this.lastName } -}`), - dataBindingExtra: { - code: { - 'app.component.html': require('!!raw-loader!./samples/data-binding-extra/app.component.html'), - 'app.component.ts': require('!!raw-loader!./samples/data-binding-extra/app.component.ts'), - 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), - 'app.module.ts': require('!!raw-loader!./samples/data-binding-extra/app.module.ts'), - 'number-praiser.ts': require('!!raw-loader!./samples/data-binding-extra/number-praiser.ts'), - 'index.html': require('!!raw-loader!./samples/data-binding-extra/index.html') - }, - files: ['app.component.html', 'app.component.ts'] - } + code: CodeDemos = { + intro: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/intro/app.component.ts') }, - ngIfDirective: { - template: displayAngularComponent(`import {Component} from '@angular/core'; -@Component({ - selector: 'my-app', - template: \`

    Hello {{firstName}}!

    - - \` -}) -export class AppComponent { - firstName = 'Pierre-Auguste'; - avatar = 'assets/images/renoir.jpg'; - onDisplay(){ return false } // ${this.t.tryChangingToTrue} -}`), - matches: { - ngIf: { 'app.component.ts': /\*ngIf/ } - } + files: ['app.component.ts'], + highlights: { + 'app.component.ts': [/

    .*<\/h1>/] + } + }, + + interpolation: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/interpolation/app.component.ts') + }, + files: ['app.component.ts'], + highlights: { + 'app.component.ts': [/{{.*}}/, /firstName = .*/] + } + }, + + expressions: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/expressions/app.component.ts') + }, + files: ['app.component.ts'], + highlights: { + 'app.component.ts': [/{{.*}}/, /fullName\(\){/] + } + }, + + dataBindingPre: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/data-binding-pre/app.component.ts') + }, + files: ['app.component.ts'], + highlights: { + 'app.component.ts': [/"{{.*}}"/, /avatar = .*/] + } + }, + + dataBinding: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/data-binding/app.component.ts') }, - ngForDirectivePre: { - template: displayAngularComponent(`import {Component} from '@angular/core'; + files: ['app.component.ts'], + highlights: { + 'app.component.ts': /\[.*]/ + } + }, + + dataBindingExtra: { + code: { + 'app.component.html': require('!!raw-loader!./samples/data-binding-extra/app.component.html'), + 'app.component.ts': require('!!raw-loader!./samples/data-binding-extra/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), + 'app.module.ts': require('!!raw-loader!./samples/data-binding-extra/app.module.ts'), + 'number-praiser.ts': require('!!raw-loader!./samples/data-binding-extra/number-praiser.ts'), + 'index.html': require('!!raw-loader!./samples/data-binding-extra/index.html') + }, + files: ['app.component.html', 'app.component.ts'] + }, -@Component({ - selector: 'my-app', - template: \`

    Puppies names:

    - ??? - \` -}) -export class AppComponent { - puppies = ['Schumann', 'Mendelssohn', 'Bach']; -}`), - matches: { 'app.component.ts': ['???', /puppies.*;/] } + ngIf: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/ng-if/app.component.ts') }, - ngForDirective: { - template: displayAngularComponent( - `import {Component} from '@angular/core'; + files: ['app.component.ts'], + highlights: { + 'app.component.ts': /\*ngIf/ + } + }, + repeating: { + code: { + 'bootstrap.ts': require('!!raw-loader!./samples/intro/bootstrap.ts'), + 'app.component.ts': require('!!raw-loader!./samples/repeating/app.component.ts') + }, + files: ['app.component.ts'], + highlights: { + 'app.component.ts': ['???', /puppies.*;/] + } + }, + eventBinding: { + code: { + 'app.component.html': require('!!raw-loader!./samples/event-binding/app.component.html'), + 'app.component.ts': require('!!raw-loader!./samples/event-binding/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), + 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'), + 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html') + }, + files: ['app.component.html'], + highlights: { 'app.component.html': '(click)' } + }, + referenceBinding: { + code: { + 'app.component.html': require('!!raw-loader!./samples/reference-binding/app.component.html'), + 'app.component.ts': require('!!raw-loader!./samples/reference-binding/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), + 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'), + 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html') + }, + files: ['app.component.html'], + highlights: { 'app.component.html': ['#input', 'input.value'] } + }, + eventBindingShortcuts: { + code: { + 'app.component.html': require('!!raw-loader!./samples/event-binding-shortcuts/app.component.html'), + 'app.component.ts': require('!!raw-loader!./samples/reference-binding/app.component.ts'), + 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), + 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'), + 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html') + }, + files: ['app.component.html'], + highlights: { 'app.component.html': '(keydown.control.enter)' } + } + }; + + legacyCode = { + ngForDirective: { + template: displayAngularComponent( + `import {Component} from '@angular/core'; @Component({ selector: 'my-app', @@ -168,7 +163,7 @@ export class AppComponent { export class AppComponent { puppies = ['Schumann', 'Mendelssohn', 'Bach']; }`, - ` + ` import {AppComponent} from './app.component'; describe('AppComponent', ()=>{ @@ -179,92 +174,14 @@ describe('AppComponent', ()=>{ }) ` - ), - matches: { - ngFor: { 'app.component.ts': '*ngFor' } - } - }, - - templateInterpolation: ` - -

    Profile for {{person.name}}

    - - -

    Profile for {{person.getBiography()}}

    - - - Photo of {{person.name}} - `, - templateInterpolationMatch: /{{person.name}}/, - templateInterpolationExercise: displayAngularComponentWithHtml( - baseCode, - `

    Hello, {{user.firstName}}

    ` ), - templateInterpolationExerciseMatch: /user.firstName/, - bindingPropMatch: /person.photoUrl/, - bindingPropExercise: displayAngularComponentWithHtml( - baseCode, - `

    ` - ), - bindingPropExerciseMatch: /user.pic/, - eventBinding: { - code: { - 'app.component.html': require('!!raw-loader!./samples/event-binding/app.component.html'), - 'app.component.ts': require('!!raw-loader!./samples/event-binding/app.component.ts'), - 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), - 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'), - 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html') - }, - files: ['app.component.html'], - highlights: { 'app.component.html': '(click)' } - }, - referenceBinding: { - code: { - 'app.component.html': require('!!raw-loader!./samples/reference-binding/app.component.html'), - 'app.component.ts': require('!!raw-loader!./samples/reference-binding/app.component.ts'), - 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), - 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'), - 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html') - }, - files: ['app.component.html'], - highlights: { 'app.component.html': ['#input', 'input.value'] } - }, - eventBindingShortcuts: { - code: { - 'app.component.html': require('!!raw-loader!./samples/event-binding-shortcuts/app.component.html'), - 'app.component.ts': require('!!raw-loader!./samples/reference-binding/app.component.ts'), - 'bootstrap.ts': require('!!raw-loader!./../../../shared/angular-code/bootstrap.ts'), - 'app.module.ts': require('!!raw-loader!./../../../shared/angular-code/app.module.ts'), - 'index.html': require('!!raw-loader!./../../../shared/angular-code/index.html') - }, - files: ['app.component.html'], - highlights: { 'app.component.html': '(keydown.control.enter)' } - }, + matches: { + ngFor: { 'app.component.ts': '*ngFor' } + } + } + }; - eventBindingExercise: displayAngularComponentWithHtml( - baseCode, - `` - ), - conditionalDisplay: ` -
    Howdy!
    - - -`, - conditionalDisplayMatch: /ngIf/, - conditionalDisplayExercise: displayAngularComponentWithHtml( - baseCode, - `` - ), - conditionalDisplayFor: `
      -
    • - {{puppy.name}} -
    • -
    `, - conditionalDisplayForMatch: /ngFor/, - conditionalDisplayForExercise: displayAngularComponentWithHtml( - baseCode, - `` - ) - }; + ngOnInit() { + this.t = extractMessages(this.translation); } } diff --git a/apps/codelab/src/app/components/exercise/exercise.component.html b/apps/codelab/src/app/components/exercise/exercise.component.html index 6a53f3106..cca855868 100644 --- a/apps/codelab/src/app/components/exercise/exercise.component.html +++ b/apps/codelab/src/app/components/exercise/exercise.component.html @@ -40,7 +40,12 @@
    - +
    + +
    Hello World! + ` }) export class AppComponent {} diff --git a/apps/codelab/src/app/shared/models.ts b/apps/codelab/src/app/shared/models.ts new file mode 100644 index 000000000..3f2097eb6 --- /dev/null +++ b/apps/codelab/src/app/shared/models.ts @@ -0,0 +1,13 @@ +export type Highlight = RegExp | string | Array; + +export interface CodeDemo { + code: Record; + files?: string[]; + highlights?: Record; +} + +export type CodeDemos = Record; + +export interface MilestoneWithDemos { + code: CodeDemos; +} diff --git a/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css b/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css index 26fffe6bf..7486a67f5 100644 --- a/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css +++ b/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.css @@ -1,3 +1,16 @@ +:host { + font-family: 'Helvetica Neue', sans-serif; + font-weight: 300; +} + +.points-container { + display: flex; + height: 25px; + flex-wrap: wrap; + margin-right: 30vw; + margin-top: 0.7vw; +} + .progress-bar { position: fixed; bottom: 0; @@ -49,8 +62,10 @@ margin-right: 0.3vw; } +.title { + font-size: 3vw; +} .handle { - font-family: 'Helvetica Neue', sans-serif; position: fixed; right: 0; bottom: 0; @@ -59,8 +74,8 @@ z-index: 101; padding: 0.5vw; padding-right: 2vw; - text-shadow: 0px 3px 20px #fff, 0px -3px 20px #fff, -3px 0px 20px #fff, - 3px 0px 20px #fff; + text-shadow: 0 3px 20px #fff, 0 -3px 20px #fff, -3px 0 20px #fff, + 3px 0 20px #fff; text-decoration: none; } diff --git a/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html b/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html index a67d63567..aba714528 100644 --- a/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html +++ b/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.html @@ -1,16 +1,12 @@ -
    - {{ title }} - +
    + {{ title }} + -
    +
    -sli.do/armadajs | @kirjs +{{ handle }} diff --git a/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts b/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts index e1f6d8e7f..d33e8034e 100644 --- a/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts +++ b/apps/kirjs/src/app/modules/ast/new-progress-bar/new-progress-bar.component.ts @@ -15,6 +15,8 @@ import { SlidesDeckComponent } from '@codelab/slides/src/lib/deck/deck.component export class NewProgressBarComponent implements AfterViewInit { @Input() fontSize = 28; @Input() title = 'JavaScript AST'; + @Input() handle = '@kirjs'; + @Input() displayFontSize = true; @Output() fontSizeChange = new EventEmitter(); slides = []; activeSlideIndex = 0; diff --git a/libs/slides/src/lib/deck/deck.component.ts b/libs/slides/src/lib/deck/deck.component.ts index 7c4c469a6..c4d45586f 100644 --- a/libs/slides/src/lib/deck/deck.component.ts +++ b/libs/slides/src/lib/deck/deck.component.ts @@ -1,14 +1,11 @@ import { ChangeDetectorRef, Component, - ContentChildren, EventEmitter, HostBinding, Input, Optional, - Output, - QueryList, - TemplateRef + Output } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @@ -21,7 +18,7 @@ import { ActivatedRoute } from '@angular/router'; export class SlidesDeckComponent { slides: any[] = []; @Input() theme = 'basic'; - @ContentChildren(TemplateRef) templates: QueryList>; + activeSlideIndex = 0; @Output() slideChange = new EventEmitter(); @Output() slideAdded = new EventEmitter<{ index: number; id: string }>(); diff --git a/libs/slides/src/lib/slide/slide.directive.ts b/libs/slides/src/lib/slide/slide.directive.ts index 8e2baa8e9..244ca7206 100644 --- a/libs/slides/src/lib/slide/slide.directive.ts +++ b/libs/slides/src/lib/slide/slide.directive.ts @@ -1,4 +1,4 @@ -import { Directive, Input, TemplateRef } from '@angular/core'; +import { Directive, TemplateRef } from '@angular/core'; import { SlidesDeckComponent } from '../deck/deck.component'; const ID_ATTR_NAME = 'id'; @@ -8,11 +8,9 @@ const MILESTONE_ATTR_NAME = 'milestone'; selector: '[slide]' }) export class SlideDirective { - @Input() class; - constructor( - private presentation: SlidesDeckComponent, - private template: TemplateRef + private readonly presentation: SlidesDeckComponent, + private readonly template: TemplateRef ) { let slide;