This repository has been archived by the owner on Jun 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from NicolasOmar/5-fifth-exercise
Typescript | Fifth exercise
- Loading branch information
Showing
23 changed files
with
758 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
* { | ||
box-sizing: border-box; | ||
} | ||
|
||
html { | ||
font-family: sans-serif; | ||
} | ||
|
||
body { | ||
margin: 0; | ||
} | ||
|
||
label, | ||
input, | ||
textarea { | ||
display: block; | ||
margin: 0.5rem 0; | ||
} | ||
|
||
label { | ||
font-weight: bold; | ||
} | ||
|
||
input, | ||
textarea { | ||
font: inherit; | ||
padding: 0.2rem 0.4rem; | ||
width: 100%; | ||
max-width: 30rem; | ||
border: 1px solid #ccc; | ||
} | ||
|
||
input:focus, | ||
textarea:focus { | ||
outline: none; | ||
background: #fff5f9; | ||
} | ||
|
||
button { | ||
font: inherit; | ||
background: #ff0062; | ||
border: 1px solid #ff0062; | ||
cursor: pointer; | ||
color: white; | ||
padding: 0.75rem 1rem; | ||
} | ||
|
||
button:focus { | ||
outline: none; | ||
} | ||
|
||
button:hover, | ||
button:active { | ||
background: #a80041; | ||
border-color: #a80041; | ||
} | ||
|
||
.projects { | ||
margin: 1rem; | ||
border: 1px solid #ff0062; | ||
} | ||
|
||
.projects header { | ||
background: #ff0062; | ||
height: 3.5rem; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
#finished-projects { | ||
border-color: #0044ff; | ||
} | ||
|
||
#finished-projects header { | ||
background: #0044ff; | ||
} | ||
|
||
.projects h2 { | ||
margin: 0; | ||
color: white; | ||
} | ||
|
||
.projects ul { | ||
list-style: none; | ||
margin: 0; | ||
padding: 1rem; | ||
} | ||
|
||
.projects li { | ||
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.26); | ||
padding: 1rem; | ||
margin: 1rem; | ||
} | ||
|
||
.projects li h2 { | ||
color: #ff0062; | ||
margin: 0.5rem 0; | ||
} | ||
|
||
#finished-projects li h2 { | ||
color: #0044ff; | ||
} | ||
|
||
.projects li h3 { | ||
color: #575757; | ||
font-size: 1rem; | ||
} | ||
|
||
.project li p { | ||
margin: 0; | ||
} | ||
|
||
.droppable { | ||
background: #ffe3ee; | ||
} | ||
|
||
#finished-projects .droppable { | ||
background: #d6e1ff; | ||
} | ||
|
||
#user-input { | ||
margin: 1rem; | ||
padding: 1rem; | ||
border: 1px solid #ff0062; | ||
background: #f7f7f7; | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> | ||
<title>Typescript Practice | Exercise #5</title> | ||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon"> | ||
<link rel="stylesheet" href="app.css" /> | ||
<script type="module" src="dist/bundle.js"></script> | ||
</head> | ||
<body> | ||
<template id="project-input"> | ||
<form> | ||
<div class="form-control"> | ||
<label for="title">Title</label> | ||
<input type="text" id="title" /> | ||
</div> | ||
<div class="form-control"> | ||
<label for="description">Description</label> | ||
<textarea id="description" rows="3"></textarea> | ||
</div> | ||
<div class="form-control"> | ||
<label for="people">People</label> | ||
<input type="number" id="people" step="1" min="0" max="10" /> | ||
</div> | ||
<button type="submit">ADD PROJECT</button> | ||
</form> | ||
</template> | ||
<template id="single-project"> | ||
<li draggable="true"> | ||
<h2></h2> | ||
<h3></h3> | ||
<p></p> | ||
</li> | ||
</template> | ||
<template id="project-list"> | ||
<section class="projects"> | ||
<header> | ||
<h2></h2> | ||
</header> | ||
<ul></ul> | ||
</section> | ||
</template> | ||
<div id="app"></div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "5-drag-and-drop", | ||
"version": "1.0.0", | ||
"scripts": { | ||
"start": "webpack serve", | ||
"build": "webpack", | ||
"build:watch": "tsc -w", | ||
"build:prod": "webpack --config webpack.config.prod.js" | ||
}, | ||
"devDependencies": { | ||
"clean-webpack-plugin": "^4.0.0", | ||
"ts-loader": "^9.4.2", | ||
"typescript": "^4.9.4", | ||
"webpack": "^5.75.0", | ||
"webpack-cli": "^5.0.1", | ||
"webpack-dev-server": "^4.11.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// COMPONENTS | ||
import { ProjectInput } from "./components/project-input" | ||
import { ProjectList } from "./components/project-list" | ||
|
||
// YOU CAN USE REFERENCE AND NAMESPACES TO LINK DEPENDENCIES IN EACH FILE, BUT IS PRONE TO ERRORS WITHOUT | ||
// A PROPER REFERENCE OF WHICH FILE/FEATURE IS MISSING IN WHICH FILE | ||
// /// <reference path="components/project-list.ts" /> | ||
// /// <reference path="components/project-input.ts" /> | ||
|
||
new ProjectInput() | ||
new ProjectList('active') | ||
new ProjectList('finished') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// COMPONENT BASE CLASS | ||
export abstract class Component<T extends HTMLElement, U extends HTMLElement> { | ||
// THIS PROP IS FOR HTML TEMPLATE | ||
templateElement: HTMLTemplateElement | ||
// THIS PROP IS FOR THE PLACE WHERE WE ARE GOING TO PUT THE HTML WE WANT | ||
hostElement: T | ||
// THIS PROP IS FOR SELECT THE HTML ELEMENT WE WANT TO MOVE FROM THE TEMPLATE TO THE HOST | ||
element: U | ||
|
||
constructor( | ||
templateId: string, | ||
hostElementId: string, | ||
insertAtStart: boolean, | ||
newElementId?: string // YOU CAN USE THE '?' OR ADD A '| undefined' TO ASSIGN POSSIBLE NULL AS A VALUE | ||
) { | ||
this.templateElement = document.getElementById(templateId)! as HTMLTemplateElement | ||
this.hostElement = document.getElementById(hostElementId)! as T | ||
|
||
// HERE YOU ARE GETTING THE TEMPLATE HTML, IMPORTING A DEEP COPY OF THAT NODE/HTMLFRAGMENT | ||
const importedNode = document.importNode(this.templateElement.content, true) | ||
// YOU INSTANTIATE THE FIRST CHILD OF THAT IMPORTED NODE HAS A FORM ELEMENT (YOU KNOW IT WILL BE) | ||
this.element = importedNode.firstElementChild as U | ||
newElementId && (this.element.id = newElementId) | ||
this.attach(insertAtStart) | ||
} | ||
|
||
private attach(insertAtBeginning: boolean) { | ||
this.hostElement.insertAdjacentElement(insertAtBeginning ? 'beforebegin' : 'afterbegin', this.element) | ||
} | ||
|
||
// NO IMPLEMENTATION HERE, BUT IT WILL BE NECESSARY ON CLASSES EXTENDED FROM THIS ONE | ||
// AN ABSTRACT CLASS CAN ONLY BE PUBLIC | ||
abstract configure(): void | ||
abstract renderContent(): void | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// COMPONENTS | ||
import { Component } from "./base-component" | ||
// MODELS & INTERFACES | ||
import { globalProjectState } from "../state/project-state" | ||
// DECORATORS | ||
import { AutoBind } from "../decorators/autobind" | ||
import { Validatable, validate } from "../utils/validation" | ||
|
||
// YOU CAN USE REFERENCE AND NAMESPACES TO LINK DEPENDENCIES IN EACH FILE, BUT IS PRONE TO ERRORS WITHOUT | ||
// A PROPER REFERENCE OF WHICH FILE/FEATURE IS MISSING IN WHICH FILE | ||
// /// <reference path="base-component.ts" /> | ||
// /// <reference path="../decorators/autobind.ts" /> | ||
|
||
export class ProjectInput extends Component<HTMLDivElement, HTMLFormElement> { | ||
titleInputElement: HTMLInputElement | ||
descriptionInputElement: HTMLInputElement | ||
peopleInputElement: HTMLInputElement | ||
|
||
constructor() { | ||
super('project-input', 'app', true, 'user-input') | ||
this.templateElement = document.getElementById('project-input')! as HTMLTemplateElement | ||
this.hostElement = document.getElementById('app')! as HTMLDivElement | ||
|
||
// YOU GET THE FORM INPUTS | ||
this.titleInputElement = this.element.querySelector('#title') as HTMLInputElement | ||
this.descriptionInputElement = this.element.querySelector('#description') as HTMLInputElement | ||
this.peopleInputElement = this.element.querySelector('#people') as HTMLInputElement | ||
// HERE YOU ARE SETTING THE FORM EVENT LISTENER WITH THE SUBMIT HANDLER METHOD | ||
this.configure() | ||
} | ||
|
||
// THE FORM HANDLER METHOD TO BE BINDED WITH FORM'S EVENT LISTENER | ||
@AutoBind | ||
private submitHandler(event: Event) { | ||
event.preventDefault() | ||
const userInputs = this.gatherUserInput() | ||
|
||
if (Array.isArray(userInputs)) { | ||
// USING A SPREAD OPERATOR, YOU ARE SENDING THE INPUTS ARRAY AS A LIST OF PARAMETERS | ||
// INSIDE THE ADDPROJECT METHOD | ||
globalProjectState.addProject(...userInputs) | ||
this.clearInputs() | ||
} | ||
} | ||
|
||
// THOSE FUNCTIONS ARE HERE TO MANTAIN CONCERN SEPARATION | ||
// ANY ABSTRACT METHODS SHOULD BE PUBLIC IN IMPLEMENTED CLASSES AS WELL | ||
configure() { | ||
// YOU ARE BINDING THE SUBMITHANDLER IN ORDER TO FIX THE LEXICAL ENVIROMENT/SCOPE INSIDE THE METHOD | ||
this.element.addEventListener('submit', this.submitHandler) | ||
} | ||
|
||
renderContent(): void { } | ||
|
||
// USE A TUPLE RETURN TYPE AND A UNION TYPE TO RETURN A SPECIFIC ARRAY OF VALUES OR NOTHING | ||
private gatherUserInput(): [string, string, number] | void { | ||
const title = this.titleInputElement.value | ||
const description = this.descriptionInputElement.value | ||
const people = this.peopleInputElement.value | ||
|
||
const titleValidator: Validatable = { | ||
value: title, | ||
required: true | ||
} | ||
const descriptionValidator: Validatable = { | ||
value: description, | ||
required: true | ||
} | ||
const peopleValidator: Validatable = { | ||
value: people, | ||
required: true, | ||
min: 0 | ||
} | ||
|
||
if ( | ||
validate(titleValidator) && | ||
validate(descriptionValidator) && | ||
validate(peopleValidator) | ||
) { | ||
return [title, description, +people] | ||
} else { | ||
alert('Invalid inputs, please try again') | ||
} | ||
} | ||
|
||
private clearInputs() { | ||
this.titleInputElement.value = '' | ||
this.descriptionInputElement.value = '' | ||
this.peopleInputElement.value = '' | ||
} | ||
} |
Oops, something went wrong.