├── 04 Angular ├── typescript-demo │ ├── src │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── lemoncoder.service.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ └── app.component.spec.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── styles.css │ │ ├── favicon.ico │ │ ├── typings.d.ts │ │ ├── tsconfig.app.json │ │ ├── index.html │ │ ├── main.ts │ │ ├── tsconfig.spec.json │ │ ├── test.ts │ │ └── polyfills.ts │ ├── e2e │ │ ├── tsconfig.e2e.json │ │ ├── app.po.ts │ │ └── app.e2e-spec.ts │ ├── .editorconfig │ ├── tsconfig.json │ ├── .gitignore │ ├── protractor.conf.js │ ├── README.md │ ├── .angular-cli.json │ ├── package.json │ ├── karma.conf.js │ └── tslint.json └── README.md ├── 03 React ├── final │ ├── components │ │ ├── index.ts │ │ ├── multistepform │ │ │ ├── steps │ │ │ │ ├── stepStyles.scss │ │ │ │ ├── index.ts │ │ │ │ ├── common.ts │ │ │ │ ├── thirdStep.tsx │ │ │ │ ├── secondStep.tsx │ │ │ │ └── firstStep.tsx │ │ │ ├── index.ts │ │ │ ├── multistepform.scss │ │ │ └── multistepform.tsx │ │ └── common │ │ │ ├── index.ts │ │ │ ├── common.scss │ │ │ ├── checkbox.scss │ │ │ ├── input.scss │ │ │ ├── button.scss │ │ │ ├── button.tsx │ │ │ ├── checkbox.tsx │ │ │ └── input.tsx │ ├── content │ │ ├── img │ │ │ └── blue-background.jpg │ │ └── styles │ │ │ └── styles.scss │ ├── app.scss │ ├── entities.ts │ ├── index.tsx │ ├── index.html │ └── app.tsx ├── src │ ├── components │ │ ├── index.js │ │ ├── multistepform │ │ │ ├── steps │ │ │ │ ├── stepStyles.scss │ │ │ │ ├── index.js │ │ │ │ ├── common.js │ │ │ │ ├── thirdStep.jsx │ │ │ │ ├── secondStep.jsx │ │ │ │ └── firstStep.jsx │ │ │ ├── index.js │ │ │ ├── multistepform.scss │ │ │ └── multistepform.jsx │ │ └── common │ │ │ ├── index.js │ │ │ ├── common.scss │ │ │ ├── checkbox.scss │ │ │ ├── input.scss │ │ │ ├── button.scss │ │ │ ├── button.jsx │ │ │ ├── checkbox.jsx │ │ │ └── input.jsx │ ├── content │ │ ├── img │ │ │ └── blue-background.jpg │ │ └── styles │ │ │ └── styles.scss │ ├── app.scss │ ├── entities.js │ ├── index.jsx │ ├── index.html │ └── app.jsx ├── Procfile ├── config │ ├── helpers.js │ └── webpack │ │ ├── app │ │ ├── prod.js │ │ ├── dev.js │ │ └── base.js │ │ └── common.js ├── .babelrc ├── tsconfig.json ├── tslint.json ├── package.json └── README.md ├── .gitignore ├── 99 Resources └── 02 Webpack │ ├── 00 run app.png │ └── 01 build prod error.png ├── 02 Webpack ├── .babelrc ├── src │ ├── index.ts │ ├── calculator.ts │ └── index.html ├── 00 start point │ ├── src │ │ └── index.html │ ├── webpack.config.js │ └── package.json ├── tsconfig.json ├── package.json ├── webpack.config.js └── README.md ├── README.md ├── LICENSE ├── 00 Basics └── README.md └── 01 Advanced └── README.md /04 Angular/typescript-demo/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /03 React/final/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './multistepform'; 2 | -------------------------------------------------------------------------------- /03 React/src/components/index.js: -------------------------------------------------------------------------------- 1 | export * from './multistepform'; 2 | -------------------------------------------------------------------------------- /03 React/Procfile: -------------------------------------------------------------------------------- 1 | web: if-env NODE_ENV=production && npm run start:prod || npm run start:dev 2 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

2 | Retrieve user: {{login}} 3 |

4 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/steps/stepStyles.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 4rem 0; 3 | } 4 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/steps/stepStyles.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 4rem 0; 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist/ 4 | *.orig 5 | .idea/ 6 | bundle.js 7 | package-lock.json 8 | .awcache/ 9 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/index.js: -------------------------------------------------------------------------------- 1 | export { MultiStepForm } from './multistepform'; 2 | export * from './steps'; 3 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/index.ts: -------------------------------------------------------------------------------- 1 | export { MultiStepForm } from './multistepform'; 2 | export * from './steps'; 3 | -------------------------------------------------------------------------------- /99 Resources/02 Webpack/00 run app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/webinar-typescript/HEAD/99 Resources/02 Webpack/00 run app.png -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/webinar-typescript/HEAD/04 Angular/typescript-demo/src/favicon.ico -------------------------------------------------------------------------------- /03 React/src/content/img/blue-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/webinar-typescript/HEAD/03 React/src/content/img/blue-background.jpg -------------------------------------------------------------------------------- /03 React/final/content/img/blue-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/webinar-typescript/HEAD/03 React/final/content/img/blue-background.jpg -------------------------------------------------------------------------------- /03 React/src/components/common/index.js: -------------------------------------------------------------------------------- 1 | export { Input } from './input'; 2 | export { Button } from './button'; 3 | export { Checkbox } from './checkbox'; 4 | -------------------------------------------------------------------------------- /99 Resources/02 Webpack/01 build prod error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/webinar-typescript/HEAD/99 Resources/02 Webpack/01 build prod error.png -------------------------------------------------------------------------------- /02 Webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /03 React/final/components/common/index.ts: -------------------------------------------------------------------------------- 1 | export { Input } from './input'; 2 | export { Button } from './button'; 3 | export { Checkbox } from './checkbox'; 4 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /03 React/src/components/common/common.scss: -------------------------------------------------------------------------------- 1 | @mixin form-control() { 2 | font-size: 1.6rem; 3 | text-shadow: none; 4 | box-shadow: none; 5 | transition: all .3s; 6 | } 7 | -------------------------------------------------------------------------------- /03 React/final/components/common/common.scss: -------------------------------------------------------------------------------- 1 | @mixin form-control() { 2 | font-size: 1.6rem; 3 | text-shadow: none; 4 | box-shadow: none; 5 | transition: all .3s; 6 | } 7 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/steps/index.ts: -------------------------------------------------------------------------------- 1 | export { FirstStep } from './firstStep'; 2 | export { SecondStep } from './secondStep'; 3 | export { ThirdStep } from './thirdStep'; 4 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/steps/index.js: -------------------------------------------------------------------------------- 1 | export { FirstStep } from './firstStep'; 2 | export { SecondStep } from './secondStep'; 3 | export { ThirdStep } from './thirdStep'; 4 | -------------------------------------------------------------------------------- /03 React/config/helpers.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const rootPath = path.resolve(__dirname, '..'); 4 | 5 | exports.resolveFromRootPath = (...args) => path.join(rootPath, ...args); 6 | -------------------------------------------------------------------------------- /02 Webpack/src/index.ts: -------------------------------------------------------------------------------- 1 | import { sum } from './calculator'; 2 | 3 | const result = sum(2, 2); 4 | 5 | const element = document.createElement('h1'); 6 | element.innerHTML = `Sum result: ${result}`; 7 | 8 | document.body.appendChild(element); 9 | -------------------------------------------------------------------------------- /03 React/final/components/common/checkbox.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | .checkbox { 4 | @include form-control(); 5 | 6 | &> input[type="checkbox"] { 7 | width: 1.4rem; 8 | height: 1.4rem; 9 | outline: 0; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /03 React/src/components/common/checkbox.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | .checkbox { 4 | @include form-control(); 5 | 6 | &> input[type="checkbox"] { 7 | width: 1.4rem; 8 | height: 1.4rem; 9 | outline: 0; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/steps/common.ts: -------------------------------------------------------------------------------- 1 | import { Value, SignupData } from '../../../entities'; 2 | 3 | export interface FormStep { 4 | title: string; 5 | formData: SignupData; 6 | onChangeField(field: keyof SignupData, value: Value): void; 7 | } 8 | -------------------------------------------------------------------------------- /03 React/src/app.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | height: 100%; 7 | 8 | @media (min-width: 600px) { 9 | max-width: 500px; 10 | margin: 0 auto; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /03 React/final/app.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | justify-content: center; 6 | height: 100%; 7 | 8 | @media (min-width: 600px) { 9 | max-width: 500px; 10 | margin: 0 auto; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /02 Webpack/src/calculator.ts: -------------------------------------------------------------------------------- 1 | export function sum(a, b) { 2 | return a + b; 3 | } 4 | 5 | export function substract(a,b) { 6 | return a - b; 7 | } 8 | 9 | export function mul(a, b) { 10 | return a * b; 11 | } 12 | 13 | export function div(a, b) { 14 | return a / b; 15 | } 16 | -------------------------------------------------------------------------------- /03 React/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "react", 10 | "stage-2" 11 | ], 12 | "plugins": [ 13 | "react-hot-loader/babel", 14 | "transform-class-properties" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /03 React/final/entities.ts: -------------------------------------------------------------------------------- 1 | export type Value = string | number | boolean; 2 | 3 | export interface SignupData { 4 | agreement: boolean; 5 | username: string; 6 | password: string; 7 | confirmPassword: string; 8 | firstName: string; 9 | lastName: string; 10 | phone: string; 11 | } 12 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class TypescriptDemoPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /03 React/final/content/styles/styles.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100vh; 3 | font-size: 10px; 4 | font-family: sans-serif; 5 | } 6 | 7 | body { 8 | background-image: url('../../content/img/blue-background.jpg'); 9 | background-size: cover; 10 | } 11 | 12 | :global(#root) { 13 | height: 100vh; 14 | } 15 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/steps/common.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { SignupDataType } from '../../../entities'; 3 | 4 | export const FormStepPropTypes = { 5 | title: PropTypes.string.isRequired, 6 | formData: SignupDataType, 7 | onChangeField: PropTypes.func.isRequired, 8 | }; 9 | -------------------------------------------------------------------------------- /03 React/src/content/styles/styles.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100vh; 3 | font-size: 10px; 4 | font-family: sans-serif; 5 | } 6 | 7 | body { 8 | background-image: url('../../content/img/blue-background.jpg'); 9 | background-size: cover; 10 | } 11 | 12 | :global(#root) { 13 | height: 100vh; 14 | } 15 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /02 Webpack/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Webinar TypeScript - 02 Webpack 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /03 React/src/components/common/input.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | .input { 4 | @include form-control(); 5 | line-height: 5rem; 6 | height: auto; 7 | padding: 0 2rem; 8 | background-color: #f8f8f8; 9 | border: .3rem solid #ddd; 10 | 11 | &:focus { 12 | outline: 0; 13 | background: #fff; 14 | border-color: #ccc; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /02 Webpack/00 start point/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Webinar TypeScript - 02 Webpack 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /02 Webpack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "suppressImplicitAnyIndexErrors": true 10 | }, 11 | "compileOnSave": false, 12 | "exclude": [ 13 | "node_modules" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /03 React/final/components/common/input.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | .input { 4 | @include form-control(); 5 | line-height: 5rem; 6 | height: auto; 7 | padding: 0 2rem; 8 | background-color: #f8f8f8; 9 | border: .3rem solid #ddd; 10 | transition: all ease .3s; 11 | 12 | &:focus { 13 | outline: 0; 14 | background: #fff; 15 | border-color: #ccc; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TypescriptDemo 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { TypescriptDemoPage } from './app.po'; 2 | 3 | describe('typescript-demo App', () => { 4 | let page: TypescriptDemoPage; 5 | 6 | beforeEach(() => { 7 | page = new TypescriptDemoPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /03 React/src/entities.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | export const SignupDataType = PropTypes.shape({ 4 | agreement: PropTypes.bool.isRequired, 5 | username: PropTypes.string.isRequired, 6 | password: PropTypes.string.isRequired, 7 | confirmPassword: PropTypes.string.isRequired, 8 | firstName: PropTypes.string.isRequired, 9 | lastName: PropTypes.string.isRequired, 10 | phone: PropTypes.string.isRequired, 11 | }); 12 | -------------------------------------------------------------------------------- /03 React/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "sourceMap": true, 9 | "jsx": "react", 10 | "noLib": false, 11 | "allowJs": true, 12 | "suppressImplicitAnyIndexErrors": true 13 | }, 14 | "compileOnSave": true, 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /03 React/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { AppContainer } from 'react-hot-loader'; 4 | import { App } from './app'; 5 | 6 | const render = (Component) => { 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root'), 12 | ); 13 | }; 14 | 15 | render(App); 16 | 17 | if (module.hot) { 18 | module.hot.accept('./app', () => { 19 | render(App); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /03 React/final/components/common/button.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | $backgroundColor: #19b9e7; 4 | .button { 5 | @include form-control(); 6 | line-height: 5rem; 7 | padding: 0 1.8rem; 8 | background-color: $backgroundColor; 9 | border-radius: .4rem; 10 | min-width: 10.5rem; 11 | 12 | &, &:focus, &:hover { 13 | color: white; 14 | } 15 | 16 | &:hover { 17 | background-color: lighten($backgroundColor, 15%); 18 | } 19 | 20 | & + & { 21 | margin-left: .5rem; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /03 React/src/components/common/button.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | $backgroundColor: #19b9e7; 4 | .button { 5 | @include form-control(); 6 | line-height: 5rem; 7 | padding: 0 1.8rem; 8 | background-color: $backgroundColor; 9 | border-radius: .4rem; 10 | min-width: 10.5rem; 11 | 12 | &, &:focus, &:hover { 13 | color: white; 14 | } 15 | 16 | &:hover { 17 | background-color: lighten($backgroundColor, 15%); 18 | } 19 | 20 | & + & { 21 | margin-left: .5rem; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /03 React/final/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import { AppContainer } from 'react-hot-loader'; 4 | import { App } from './app'; 5 | 6 | const render = (Component) => { 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root'), 12 | ); 13 | }; 14 | 15 | render(App); 16 | 17 | if (module.hot) { 18 | module.hot.accept('./app', () => { 19 | render(App); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/app/lemoncoder.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Observable } from 'rxjs/Observable'; 4 | import { map } from 'rxjs/operators'; 5 | 6 | 7 | @Injectable() 8 | export class LemoncoderService { 9 | constructor(private http: HttpClient) { } 10 | 11 | getCoder(name: string): Observable { 12 | return this.http.get(`https://api.github.com/users/${name}`) 13 | .pipe( 14 | map((result: any) => result.login) 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /03 React/final/components/common/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | const styles: any = require('./button.scss'); 3 | 4 | interface Props { 5 | onClick(event: React.MouseEvent): void; 6 | type?: string; 7 | content: string; 8 | } 9 | 10 | export const Button: React.StatelessComponent = ({ onClick, type, content }) => ( 11 | 18 | ); 19 | 20 | Button.defaultProps = { 21 | type: 'button', 22 | }; 23 | -------------------------------------------------------------------------------- /03 React/src/components/common/button.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styles from './button.scss'; 4 | 5 | export const Button = ({ onClick, type, content }) => ( 6 | 13 | ); 14 | 15 | Button.propTypes = { 16 | onClick: PropTypes.func.isRequired, 17 | type: PropTypes.string, 18 | content: PropTypes.string.isRequired, 19 | } 20 | 21 | Button.defaultProps = { 22 | type: 'button', 23 | }; 24 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { LemoncoderService } from './lemoncoder.service'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'] 8 | }) 9 | export class AppComponent implements OnInit { 10 | login: string; 11 | constructor(private lemoncoderService: LemoncoderService) {} 12 | 13 | ngOnInit(): void { 14 | this.lemoncoderService.getCoder('JaimeSalas') 15 | .subscribe((login) => this.login = login); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /03 React/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | App 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /03 React/final/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | App 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /03 React/config/webpack/app/prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const merge = require('webpack-merge'); 3 | const base = require('./base'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const helpers = require('../../helpers'); 6 | 7 | module.exports = merge(base, { 8 | output: { 9 | path: helpers.resolveFromRootPath('dist'), 10 | filename: '[chunkhash].[name].js', 11 | }, 12 | plugins: [ 13 | new webpack.HashedModuleIdsPlugin(), 14 | new ExtractTextPlugin({ 15 | filename: '[chunkhash].[name].css', 16 | disable: false, 17 | allChunks: true, 18 | }), 19 | ], 20 | }); 21 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/steps/thirdStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Input, Checkbox } from '../../common'; 3 | import { FormStep } from './common'; 4 | const styles: any = require('./stepStyles.scss'); 5 | 6 | export const ThirdStep: React.StatelessComponent = (props) => ( 7 |
8 |
9 | 15 | Accept license agreement 16 | 17 |
18 |
19 | ); 20 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/steps/thirdStep.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, Checkbox } from '../../common'; 3 | import { FormStepPropTypes } from './common'; 4 | import styles from './stepStyles.scss'; 5 | 6 | export const ThirdStep = (props) => ( 7 |
8 |
9 | 15 | Accept license agreement 16 | 17 |
18 |
19 | ); 20 | 21 | ThirdStep.propTypes = FormStepPropTypes; 22 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpClientModule } from '@angular/common/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | 8 | import { LemoncoderService } from './lemoncoder.service'; 9 | 10 | @NgModule({ 11 | declarations: [ 12 | AppComponent 13 | ], 14 | imports: [ 15 | BrowserModule, 16 | FormsModule, 17 | HttpClientModule 18 | ], 19 | providers: [ 20 | LemoncoderService 21 | ], 22 | bootstrap: [AppComponent] 23 | }) 24 | export class AppModule { } 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webinar-typescript 2 | 3 | Demo material for TypeScript webinar: "Es hora de TypeScript..." (spanish). 4 | 5 | Recording: [https://www.youtube.com/watch?v=9fkklSQCCck](https://www.youtube.com/watch?v=9fkklSQCCck) 6 | 7 | # About Basefactor + Lemoncode 8 | 9 | We are an innovating team of Javascript experts, passionate about turning your ideas into robust products. 10 | 11 | [Basefactor, consultancy by Lemoncode](http://www.basefactor.com) provides consultancy and coaching services. 12 | 13 | [Lemoncode](http://lemoncode.net/services/en/#en-home) provides training services. 14 | 15 | For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend 16 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/multistepform.scss: -------------------------------------------------------------------------------- 1 | .form { 2 | width: 100%; 3 | background-color: white; 4 | color: #888; 5 | border-radius: .5rem; 6 | border: .3rem solid transparent; 7 | padding-top: 1.5rem; 8 | } 9 | 10 | .form-top { 11 | display: flex; 12 | flex-direction: row; 13 | padding: 0 2.5rem; 14 | 15 | &-left { 16 | width: 75%; 17 | } 18 | 19 | &-right { 20 | width: 25%; 21 | font-size: 6.6rem; 22 | text-align: right; 23 | } 24 | } 25 | 26 | .heading { 27 | font-size: 3rem; 28 | text-transform: uppercase; 29 | text-align: center; 30 | color: #555; 31 | } 32 | 33 | .step { 34 | font-size: 2.2rem; 35 | } 36 | 37 | .form-bottom { 38 | padding: 2.5rem 2.5rem 3.0rem 2.5rem; 39 | background-color: #eee; 40 | } 41 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/multistepform.scss: -------------------------------------------------------------------------------- 1 | .form { 2 | width: 100%; 3 | background-color: white; 4 | color: #888; 5 | border-radius: .5rem; 6 | border: .3rem solid transparent; 7 | padding-top: 1.5rem; 8 | } 9 | 10 | .form-top { 11 | display: flex; 12 | flex-direction: row; 13 | padding: 0 2.5rem; 14 | 15 | &-left { 16 | width: 75%; 17 | } 18 | 19 | &-right { 20 | width: 25%; 21 | font-size: 6.6rem; 22 | text-align: right; 23 | } 24 | } 25 | 26 | .heading { 27 | font-size: 3rem; 28 | text-transform: uppercase; 29 | text-align: center; 30 | color: #555; 31 | } 32 | 33 | .step { 34 | font-size: 2.2rem; 35 | } 36 | 37 | .form-bottom { 38 | padding: 2.5rem 2.5rem 3.0rem 2.5rem; 39 | background-color: #eee; 40 | } 41 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/steps/secondStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Input } from '../../common'; 3 | import { FormStep } from './common'; 4 | 5 | export const SecondStep: React.StatelessComponent = (props) => ( 6 |
7 | 14 | 21 | 29 |
30 | ); 31 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/steps/secondStep.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input } from '../../common'; 3 | import { FormStepPropTypes } from './common'; 4 | 5 | export const SecondStep = (props) => ( 6 |
7 | 14 | 21 | 29 |
30 | ); 31 | 32 | SecondStep.propTypes = FormStepPropTypes; 33 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /02 Webpack/00 start point/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | 5 | var basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, 'src'), 9 | resolve: { 10 | extensions: ['.js', '.ts'] 11 | }, 12 | entry: { 13 | }, 14 | output: { 15 | path: path.join(basePath, 'dist'), 16 | filename: '[chunkhash].[name].js', 17 | }, 18 | module: { 19 | rules: [ 20 | ], 21 | }, 22 | devtool: 'inline-source-map', 23 | devServer: { 24 | port: 8080, 25 | }, 26 | plugins: [ 27 | new HtmlWebpackPlugin({ 28 | filename: 'index.html', 29 | template: 'index.html', 30 | hash: true, 31 | }), 32 | new webpack.optimize.CommonsChunkPlugin({ 33 | names: ['vendor', 'manifest'], 34 | }), 35 | new webpack.HashedModuleIdsPlugin(), 36 | ], 37 | }; 38 | -------------------------------------------------------------------------------- /03 React/src/components/common/checkbox.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styles from './checkbox.scss'; 4 | 5 | export const Checkbox = (props) => ( 6 |
7 | 18 |
19 | ); 20 | 21 | Checkbox.propTypes = { 22 | id: PropTypes.string.isRequired, 23 | name: PropTypes.string.isRequired, 24 | checked: PropTypes.bool.isRequired, 25 | onChange: PropTypes.func.isRequired, 26 | } 27 | 28 | const onChange = (props) => ({ target: { name, checked } }) => { 29 | props.onChange(name, checked); 30 | }; 31 | -------------------------------------------------------------------------------- /03 React/final/components/multistepform/steps/firstStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Input, Button } from '../../common'; 3 | import { FormStep } from './common'; 4 | 5 | export const FirstStep: React.StatelessComponent = (props) => ( 6 |
7 | 14 | 22 | 30 |
31 | ); 32 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/steps/firstStep.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, Button } from '../../common'; 3 | import { FormStepPropTypes } from './common'; 4 | 5 | export const FirstStep = (props) => ( 6 |
7 | 14 | 22 | 30 |
31 | ); 32 | 33 | FirstStep.propTypes = FormStepPropTypes; 34 | -------------------------------------------------------------------------------- /02 Webpack/00 start point/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webinar-typescript", 3 | "version": "1.0.0", 4 | "description": "02 Webpack sample", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server", 8 | "build": "rimraf dist && webpack", 9 | "build:prod": "rimraf dist && webpack -p" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/Lemoncode/webinar-typescript.git" 14 | }, 15 | "keywords": [ 16 | "webinar", 17 | "typescript", 18 | "lemoncode", 19 | "webpack" 20 | ], 21 | "author": "Lemoncode", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/Lemoncode/webinar-typescript/issues" 25 | }, 26 | "homepage": "https://github.com/Lemoncode/webinar-typescript#readme", 27 | "devDependencies": { 28 | "html-webpack-plugin": "^2.30.1", 29 | "rimraf": "^2.6.2", 30 | "typescript": "^2.6.2", 31 | "webpack": "^3.10.0", 32 | "webpack-dev-server": "^2.9.7" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /03 React/final/components/common/checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Value, SignupData } from '../../entities'; 3 | const styles: any = require('./checkbox.scss'); 4 | 5 | interface Props { 6 | id: string; 7 | name: keyof SignupData; 8 | checked: boolean; 9 | onChange(field: keyof SignupData, value: Value): void; 10 | } 11 | 12 | export const Checkbox: React.StatelessComponent = (props) => ( 13 |
14 | 25 |
26 | ); 27 | 28 | const onChange = (props: Props) => ({ target: { name, checked } }: React.ChangeEvent) => { 29 | props.onChange(name as keyof SignupData, checked); 30 | }; 31 | -------------------------------------------------------------------------------- /03 React/config/webpack/app/dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const merge = require('webpack-merge'); 3 | const base = require('./base'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const helpers = require('../../helpers'); 6 | 7 | const hotReloadingEntries = [ 8 | 'react-hot-loader/patch', 9 | ]; 10 | 11 | module.exports = merge.strategy({ 12 | entry: 'prepend', 13 | })(base, { 14 | devtool: 'inline-source-map', 15 | entry: { 16 | app: hotReloadingEntries, 17 | appStyles: hotReloadingEntries, 18 | }, 19 | output: { 20 | path: helpers.resolveFromRootPath('dist'), 21 | filename: '[name].js', 22 | }, 23 | devServer: { 24 | contentBase: helpers.resolveFromRootPath('dist'), 25 | inline: true, 26 | host: 'localhost', 27 | port: 8080, 28 | stats: 'minimal', 29 | hot: true, 30 | }, 31 | plugins: [ 32 | new webpack.HotModuleReplacementPlugin(), 33 | new webpack.NamedModulesPlugin(), 34 | new ExtractTextPlugin({ 35 | disable: true, 36 | }), 37 | ], 38 | }); 39 | -------------------------------------------------------------------------------- /03 React/src/components/common/input.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styles from './input.scss'; 4 | 5 | export const Input = (props) => ( 6 |
7 | 8 | 17 |
18 | ); 19 | 20 | Input.propTypes = { 21 | value: PropTypes.oneOfType([ 22 | PropTypes.string, 23 | PropTypes.number, 24 | ]).isRequired, 25 | onChange: PropTypes.func.isRequired, 26 | label: PropTypes.string.isRequired, 27 | id: PropTypes.string.isRequired, 28 | name: PropTypes.string.isRequired, 29 | type: PropTypes.string, 30 | } 31 | 32 | Input.defaultProps = { 33 | type: 'text', 34 | }; 35 | 36 | const onChange = (props) => ({ target: { value, name } }) => { 37 | props.onChange(name, value); 38 | }; 39 | -------------------------------------------------------------------------------- /03 React/final/components/common/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Value, SignupData } from '../../entities'; 3 | const styles: any = require('./input.scss'); 4 | 5 | interface Props { 6 | value: string | number; 7 | onChange(field: keyof SignupData, value: Value): void; 8 | label: string; 9 | id: string; 10 | name: keyof SignupData; 11 | type?: string; 12 | } 13 | 14 | export const Input: React.StatelessComponent = (props) => ( 15 |
16 | 17 | 26 |
27 | ); 28 | 29 | Input.defaultProps = { 30 | type: 'text', 31 | }; 32 | 33 | const onChange = (props: Props) => ({ target: { value, name } }: React.ChangeEvent) => { 34 | props.onChange(name as keyof SignupData, value); 35 | }; 36 | -------------------------------------------------------------------------------- /02 Webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webinar-typescript", 3 | "version": "1.0.0", 4 | "description": "02 Webpack sample", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server", 8 | "build": "rimraf dist && webpack", 9 | "build:prod": "rimraf dist && webpack -p" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/Lemoncode/webinar-typescript.git" 14 | }, 15 | "keywords": [ 16 | "webinar", 17 | "typescript", 18 | "lemoncode", 19 | "webpack" 20 | ], 21 | "author": "Lemoncode", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/Lemoncode/webinar-typescript/issues" 25 | }, 26 | "homepage": "https://github.com/Lemoncode/webinar-typescript#readme", 27 | "devDependencies": { 28 | "awesome-typescript-loader": "^3.4.1", 29 | "babel-core": "^6.26.0", 30 | "babel-preset-env": "^1.6.1", 31 | "html-webpack-plugin": "^2.30.1", 32 | "rimraf": "^2.6.2", 33 | "typescript": "^2.6.2", 34 | "webpack": "^3.10.0", 35 | "webpack-dev-server": "^2.9.7" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Lemoncode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /02 Webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | 5 | var basePath = __dirname; 6 | 7 | module.exports = { 8 | context: path.join(basePath, 'src'), 9 | resolve: { 10 | extensions: ['.js', '.ts'] 11 | }, 12 | entry: { 13 | app: './index.ts', 14 | }, 15 | output: { 16 | path: path.join(basePath, 'dist'), 17 | filename: '[chunkhash].[name].js', 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.ts$/, 23 | exclude: /node_modules/, 24 | loader: 'awesome-typescript-loader', 25 | options: { 26 | useBabel: true, 27 | }, 28 | }, 29 | ], 30 | }, 31 | devtool: 'inline-source-map', 32 | devServer: { 33 | port: 8080, 34 | }, 35 | plugins: [ 36 | new HtmlWebpackPlugin({ 37 | filename: 'index.html', 38 | template: 'index.html', 39 | hash: true, 40 | }), 41 | new webpack.optimize.CommonsChunkPlugin({ 42 | names: ['vendor', 'manifest'], 43 | }), 44 | new webpack.HashedModuleIdsPlugin(), 45 | ], 46 | }; 47 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'app works!'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('app works!'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('app works!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/README.md: -------------------------------------------------------------------------------- 1 | # TypescriptDemo 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | Before running the tests make sure you are serving the app via `ng serve`. 25 | 26 | ## Further help 27 | 28 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 29 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare var __karma__: any; 17 | declare var require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /03 React/config/webpack/common.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const { CheckerPlugin } = require('awesome-typescript-loader'); 3 | const helpers = require('../helpers'); 4 | 5 | module.exports = { 6 | resolve: { 7 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 8 | alias: { 9 | 'globalStyles': helpers.resolveFromRootPath("src/content/styles"), 10 | }, 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.tsx?$/, 16 | enforce: 'pre', 17 | loader: 'tslint-loader', 18 | }, 19 | { 20 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 21 | loader: 'url-loader?limit=10000&mimetype=application/font-woff', 22 | }, 23 | { 24 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 25 | loader: 'url-loader?limit=10000&mimetype=application/octet-stream', 26 | }, 27 | { 28 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 29 | loader: 'file-loader', 30 | }, 31 | { 32 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 33 | loader: 'url-loader?limit=10000&mimetype=image/svg+xml', 34 | }, 35 | { 36 | test: /\.(png|jpg|ico)?$/, 37 | loader: 'url-loader?limit=10000&mimetype=image/png', 38 | }, 39 | ] 40 | }, 41 | 42 | plugins: [ 43 | new CheckerPlugin(), 44 | ], 45 | } 46 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "typescript-demo" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "e2e": { 33 | "protractor": { 34 | "config": "./protractor.conf.js" 35 | } 36 | }, 37 | "lint": [ 38 | { 39 | "project": "src/tsconfig.app.json" 40 | }, 41 | { 42 | "project": "src/tsconfig.spec.json" 43 | }, 44 | { 45 | "project": "e2e/tsconfig.e2e.json" 46 | } 47 | ], 48 | "test": { 49 | "karma": { 50 | "config": "./karma.conf.js" 51 | } 52 | }, 53 | "defaults": { 54 | "styleExt": "css", 55 | "component": {} 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-demo", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/common": "^4.0.0", 16 | "@angular/compiler": "^4.0.0", 17 | "@angular/core": "^4.0.0", 18 | "@angular/forms": "^4.0.0", 19 | "@angular/http": "^4.0.0", 20 | "@angular/platform-browser": "^4.0.0", 21 | "@angular/platform-browser-dynamic": "^4.0.0", 22 | "@angular/router": "^4.0.0", 23 | "core-js": "^2.4.1", 24 | "rxjs": "^5.1.0", 25 | "zone.js": "^0.8.4" 26 | }, 27 | "devDependencies": { 28 | "@angular/cli": "1.0.2", 29 | "@angular/compiler-cli": "^4.0.0", 30 | "@types/jasmine": "2.5.38", 31 | "@types/node": "~6.0.60", 32 | "codelyzer": "~2.0.0", 33 | "jasmine-core": "~2.5.2", 34 | "jasmine-spec-reporter": "~3.2.0", 35 | "karma": "~1.4.1", 36 | "karma-chrome-launcher": "~2.0.0", 37 | "karma-cli": "~1.0.1", 38 | "karma-jasmine": "~1.1.0", 39 | "karma-jasmine-html-reporter": "^0.2.2", 40 | "karma-coverage-istanbul-reporter": "^0.2.0", 41 | "protractor": "~5.1.0", 42 | "ts-node": "~2.0.0", 43 | "tslint": "~4.5.0", 44 | "typescript": "~2.2.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /04 Angular/typescript-demo/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | files: [ 19 | { pattern: './src/test.ts', watched: false } 20 | ], 21 | preprocessors: { 22 | './src/test.ts': ['@angular/cli'] 23 | }, 24 | mime: { 25 | 'text/x-typescript': ['ts','tsx'] 26 | }, 27 | coverageIstanbulReporter: { 28 | reports: [ 'html', 'lcovonly' ], 29 | fixWebpackSourcePaths: true 30 | }, 31 | angularCli: { 32 | environment: 'dev' 33 | }, 34 | reporters: config.angularCli && config.angularCli.codeCoverage 35 | ? ['progress', 'coverage-istanbul'] 36 | : ['progress', 'kjhtml'], 37 | port: 9876, 38 | colors: true, 39 | logLevel: config.LOG_INFO, 40 | autoWatch: true, 41 | browsers: ['Chrome'], 42 | singleRun: false 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /03 React/src/app.jsx: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { MultiStepForm, FirstStep, SecondStep, ThirdStep } from './components'; 3 | import styles from './app.scss'; 4 | 5 | export class App extends PureComponent { 6 | state = { 7 | formData: { 8 | agreement: false, 9 | confirmPassword: '', 10 | firstName: '', 11 | lastName: '', 12 | password: '', 13 | phone: '', 14 | username: '', 15 | }, 16 | }; 17 | 18 | render() { 19 | return ( 20 |
21 | 25 | 30 | 35 | 40 | 41 |
42 | ); 43 | } 44 | 45 | onChangeField = (field, value) => { 46 | this.setState({ 47 | formData: { 48 | ...this.state.formData, 49 | [field]: value, 50 | }, 51 | }); 52 | } 53 | 54 | onSubmit = () => { 55 | console.log(JSON.stringify(this.state.formData)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /03 React/final/app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { MultiStepForm, FirstStep, SecondStep, ThirdStep } from './components'; 3 | import { Value, SignupData } from './entities'; 4 | const styles: any = require('./app.scss'); 5 | 6 | interface State { 7 | formData: SignupData; 8 | } 9 | 10 | export class App extends React.PureComponent<{}, State> { 11 | state: State = { 12 | formData: { 13 | agreement: false, 14 | confirmPassword: '', 15 | firstName: '', 16 | lastName: '', 17 | password: '', 18 | phone: '', 19 | username: '', 20 | }, 21 | }; 22 | 23 | render() { 24 | return ( 25 |
26 | 30 | 35 | 40 | 45 | 46 |
47 | ); 48 | } 49 | 50 | onChangeField = (field: keyof SignupData, value: Value) => { 51 | this.setState({ 52 | formData: { 53 | ...this.state.formData, 54 | [field]: value, 55 | }, 56 | }); 57 | } 58 | 59 | onSubmit = () => { 60 | // tslint:disable-next-line:no-console 61 | console.log(JSON.stringify(this.state.formData)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /03 React/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest", 4 | "tslint-react" 5 | ], 6 | "rules": { 7 | "jsx-alignment": true, 8 | "jsx-self-close": true, 9 | "class-name": true, 10 | "interface-name": false, 11 | "object-literal-sort-keys": false, 12 | "ordered-imports": [ 13 | false 14 | ], 15 | "comment-format": [ 16 | true, 17 | "check-space" 18 | ], 19 | "indent": [ 20 | true, 21 | "spaces" 22 | ], 23 | "no-eval": true, 24 | "no-internal-module": true, 25 | "no-trailing-whitespace": true, 26 | "no-unsafe-finally": true, 27 | "no-var-keyword": true, 28 | "only-arrow-functions": [ 29 | false 30 | ], 31 | "one-line": [ 32 | true, 33 | "check-open-brace", 34 | "check-whitespace" 35 | ], 36 | "quotemark": [ 37 | true, 38 | "single", 39 | "jsx-double" 40 | ], 41 | "semicolon": [ 42 | true, 43 | "always" 44 | ], 45 | "triple-equals": [ 46 | true, 47 | "allow-null-check" 48 | ], 49 | "typedef-whitespace": [ 50 | true, 51 | { 52 | "call-signature": "nospace", 53 | "index-signature": "nospace", 54 | "parameter": "nospace", 55 | "property-declaration": "nospace", 56 | "variable-declaration": "nospace" 57 | } 58 | ], 59 | "variable-name": [ 60 | true, 61 | "ban-keywords" 62 | ], 63 | "whitespace": [ 64 | true, 65 | "check-branch", 66 | "check-decl", 67 | "check-operator", 68 | "check-separator", 69 | "check-type" 70 | ], 71 | "jsx-no-multiline-js": false, 72 | "jsx-wrap-multiline": false, 73 | "no-var-requires": false, 74 | "no-empty": false, 75 | "member-ordering": false, 76 | "member-access": false, 77 | "no-submodule-imports": false, 78 | "no-implicit-dependencies": false, 79 | "no-this-assignment": false, 80 | "object-literal-shorthand": false, 81 | "no-object-literal-type-assertion": false 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /03 React/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webinar-typescript", 3 | "version": "1.0.0", 4 | "description": "React sample", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nf start", 8 | "start:dev": "webpack-dev-server --config ./config/webpack/app/dev.js", 9 | "start:prod": "cross-env REST_ENV=real NODE_ENV=production webpack-dev-server --config ./config/webpack/app/prod.js", 10 | "build": "npm run build:dev", 11 | "build:dev": "rimraf dist && webpack --config ./config/webpack/app/dev.js", 12 | "build:prod": "rimraf dist && cross-env REST_ENV=real NODE_ENV=production webpack -p --config ./config/webpack/app/prod.js" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/Lemoncode/webinar-typescript.git" 17 | }, 18 | "keywords": [ 19 | "react", 20 | "typescript" 21 | ], 22 | "author": "Lemoncode", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/Lemoncode/webinar-typescript/issues" 26 | }, 27 | "homepage": "https://github.com/Lemoncode/webinar-typescript#readme", 28 | "dependencies": { 29 | "babel-polyfill": "^6.26.0", 30 | "bootstrap": "^3.3.7", 31 | "font-awesome": "^4.7.0", 32 | "react": "^16.1.1", 33 | "react-dom": "^16.1.1", 34 | "react-hot-loader": "^3.1.3" 35 | }, 36 | "devDependencies": { 37 | "@types/react": "^16.0.24", 38 | "@types/react-dom": "^16.0.3", 39 | "@types/react-hot-loader": "^3.0.5", 40 | "@types/webpack-env": "^1.13.2", 41 | "awesome-typescript-loader": "^3.3.0", 42 | "babel-core": "^6.26.0", 43 | "babel-loader": "^7.1.2", 44 | "babel-plugin-transform-class-properties": "^6.24.1", 45 | "babel-preset-env": "^1.6.1", 46 | "babel-preset-react": "^6.24.1", 47 | "babel-preset-stage-2": "^6.24.1", 48 | "cross-env": "^5.1.1", 49 | "css-loader": "^0.28.7", 50 | "extract-text-webpack-plugin": "^3.0.2", 51 | "file-loader": "^1.1.6", 52 | "foreman": "^2.0.0", 53 | "html-webpack-plugin": "^2.30.1", 54 | "if-env": "^1.0.0", 55 | "node-sass": "^4.6.1", 56 | "prop-types": "^15.6.0", 57 | "rimraf": "^2.6.2", 58 | "sass-loader": "^6.0.6", 59 | "style-loader": "^0.19.0", 60 | "tslint": "^5.8.0", 61 | "tslint-loader": "^3.5.3", 62 | "tslint-react": "^3.2.0", 63 | "typescript": "^2.6.1", 64 | "url-loader": "^0.6.2", 65 | "webpack": "^3.8.1", 66 | "webpack-dev-server": "^2.9.4", 67 | "webpack-merge": "^4.1.1" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /03 React/src/components/multistepform/multistepform.jsx: -------------------------------------------------------------------------------- 1 | import React, { PureComponent, Fragment } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Button } from '../common'; 4 | import styles from './multistepform.scss'; 5 | 6 | export class MultiStepForm extends PureComponent { 7 | 8 | static propTypes = { 9 | heading: PropTypes.string.isRequired, 10 | onSubmit: PropTypes.func.isRequired, 11 | } 12 | 13 | state = { 14 | currentStep: 0, 15 | }; 16 | 17 | render() { 18 | const children = React.Children.toArray(this.props.children); 19 | const child = children[this.state.currentStep]; 20 | 21 | return ( 22 |
23 |

{this.props.heading}

24 |
25 |
26 |

Step {this.state.currentStep + 1} / {children.length}

27 |

{child.props.title}

28 |
29 |
30 | 31 |
32 |
33 |
34 | {child} 35 | {this.renderButtons(children.length)} 36 |
37 | 38 | ); 39 | } 40 | 41 | goPreviousStep = (event) => { 42 | event.preventDefault(); 43 | this.setState({ 44 | currentStep: this.state.currentStep - 1, 45 | }); 46 | } 47 | 48 | goNextStep = (event) => { 49 | event.preventDefault(); 50 | this.setState({ 51 | currentStep: this.state.currentStep + 1, 52 | }); 53 | } 54 | 55 | onSubmit = (event) => { 56 | event.preventDefault(); 57 | this.props.onSubmit(); 58 | } 59 | 60 | renderButtons(childrenLength) { 61 | const { currentStep } = this.state; 62 | let content, type; 63 | const isLastStep = currentStep + 1 === childrenLength; 64 | if (isLastStep) { 65 | content = 'Submit'; 66 | type = 'submit'; 67 | } else { 68 | content = 'Next'; 69 | type = 'button'; 70 | } 71 | 72 | return ( 73 | 74 | {currentStep !== 0 && 75 |