diff --git a/nx.json b/nx.json index f946d4d..6a50ccc 100644 --- a/nx.json +++ b/nx.json @@ -4,17 +4,31 @@ "default": { "runner": "nx/tasks-runners/default", "options": { - "cacheableOperations": ["build", "lint", "test", "e2e"] + "cacheableOperations": [ + "build", + "lint", + "test", + "e2e" + ] } } }, "targetDefaults": { "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"] + "dependsOn": [ + "^build" + ], + "inputs": [ + "production", + "^production" + ] }, "test": { - "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"] + "inputs": [ + "default", + "^production", + "{workspaceRoot}/jest.preset.js" + ] }, "lint": { "inputs": [ @@ -26,7 +40,10 @@ } }, "namedInputs": { - "default": ["{projectRoot}/**/*", "sharedGlobals"], + "default": [ + "{projectRoot}/**/*", + "sharedGlobals" + ], "production": [ "default", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", diff --git a/package.json b/package.json index 69f0a32..c3468d4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "0.0.0", "license": "MIT", "scripts": { - "part1": "nx run part-1-html-css:serve" + "part1": "nx run part-1-html-css:serve", + "part2": "nx run part-2-javascript:serve" }, "private": true, "devDependencies": { diff --git a/part-2-javascript/.eslintrc.json b/part-2-javascript/.eslintrc.json new file mode 100644 index 0000000..bca8fff --- /dev/null +++ b/part-2-javascript/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": [ + "../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": {} + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} diff --git a/part-2-javascript/.swcrc b/part-2-javascript/.swcrc new file mode 100644 index 0000000..a2d5b04 --- /dev/null +++ b/part-2-javascript/.swcrc @@ -0,0 +1,8 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript" + }, + "target": "es2016" + } +} diff --git a/part-2-javascript/jest.config.ts b/part-2-javascript/jest.config.ts new file mode 100644 index 0000000..197ef37 --- /dev/null +++ b/part-2-javascript/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + displayName: 'part-2-javascript', + preset: '../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.[tj]s$': '@swc/jest' + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../coverage/part-2-javascript' +}; diff --git a/part-2-javascript/project.json b/part-2-javascript/project.json new file mode 100644 index 0000000..8a5ff53 --- /dev/null +++ b/part-2-javascript/project.json @@ -0,0 +1,86 @@ +{ + "name": "part-2-javascript", + "$schema": "../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "part-2-javascript/src", + "tags": [], + "targets": { + "build": { + "executor": "@nx/webpack:webpack", + "outputs": [ + "{options.outputPath}" + ], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/part-2-javascript", + "compiler": "swc", + "main": "part-2-javascript/src/main.ts", + "tsConfig": "part-2-javascript/tsconfig.app.json", + "webpackConfig": "part-2-javascript/webpack.config.js", + "assets": [ + "part-2-javascript/src/assets" + ], + "index": "part-2-javascript/src/index.html", + "baseHref": "/", + "styles": [ + "part-2-javascript/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "fileReplacements": [ + { + "replace": "part-2-javascript/src/environments/environment.ts", + "with": "part-2-javascript/src/environments/environment.prod.ts" + } + ] + } + } + }, + "serve": { + "executor": "@nx/webpack:dev-server", + "options": { + "buildTarget": "part-2-javascript:build" + }, + "configurations": { + "production": { + "buildTarget": "part-2-javascript:build:production" + } + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": [ + "{options.outputFile}" + ], + "options": { + "lintFilePatterns": [ + "part-2-javascript/**/*.ts" + ] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}" + ], + "options": { + "jestConfig": "part-2-javascript/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + } + } +} diff --git a/part-2-javascript/src/app/app.element.scss b/part-2-javascript/src/app/app.element.scss new file mode 100644 index 0000000..d55aa11 --- /dev/null +++ b/part-2-javascript/src/app/app.element.scss @@ -0,0 +1,47 @@ +/* + * Remove template code below + */ +html { + -webkit-text-size-adjust: 100%; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, + 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + line-height: 1.5; + tab-size: 4; + scroll-behavior: smooth; +} + +body { + font-family: inherit; + line-height: inherit; + margin: 0; +} + +h1, +h2, +p, +pre { + margin: 0; +} + +*, +::before, +::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; +} + +h1, +h2 { + font-size: inherit; + font-weight: inherit; +} + +a { + color: inherit; + text-decoration: inherit; +} + diff --git a/part-2-javascript/src/app/app.element.spec.ts b/part-2-javascript/src/app/app.element.spec.ts new file mode 100644 index 0000000..08e8a01 --- /dev/null +++ b/part-2-javascript/src/app/app.element.spec.ts @@ -0,0 +1,21 @@ +import { AppElement } from './app.element'; + +describe('AppElement', () => { + let app: AppElement; + + beforeEach(() => { + app = new AppElement(); + }); + + it('should create successfully', () => { + expect(app).toBeTruthy(); + }); + + it('should have a greeting', () => { + app.connectedCallback(); + + expect(app.querySelector('h1').innerHTML).toContain( + 'Welcome part-2-javascript' + ); + }); +}); diff --git a/part-2-javascript/src/app/app.element.ts b/part-2-javascript/src/app/app.element.ts new file mode 100644 index 0000000..8bb3d90 --- /dev/null +++ b/part-2-javascript/src/app/app.element.ts @@ -0,0 +1,88 @@ +import "./app.element.scss"; +import { Book } from "./book.interface"; + +export class AppElement extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+ + +
+ +
+ +
+

Books

+
    + + +
    + +
    + `; + const searchInput = this.querySelector("[data-search]"); + const bookCardTemplate: any = this.querySelector("[data-book-card-template]"); + const bookCardContainer: HTMLDivElement = this.querySelector("[data-book-cards-container]"); + + let books = []; + + fetch("assets/books.json") + .then(res => res.json()) + .then(data => { + books = data.map((book: Book) => { + const card = bookCardTemplate.content.cloneNode(true).children[0]; + const initials = card.querySelector("[data-initials]"); + const title = card.querySelector("[data-title]"); + const author = card.querySelector("[data-author]"); + const year = card.querySelector("[data-year]"); + + initials.textContent = book.initials; + title.textContent = book.title; + author.textContent = book.author; + year.textContent = book.year; + + bookCardContainer.append(card); + + return { initials: book.initials, title: book.title, author: book.author, year: book.year, element: card }; + }); + }); + + // Create a function to filter the books array based on the search input value. + const filterBooks = (value: string) => { + return books.filter((book) => { + return book.author.toLowerCase().includes(value) || + book.title.toLowerCase().includes(value); + }); + }; + + // Add a change event listener to the search input field. + searchInput.addEventListener("input", (e: any) => { + // Get the search input value. + const value = e.target.value.toLowerCase(); + + // Filter the books array based on the search input value. + const filteredBooks = filterBooks(value); + + // Update the visibility of the book elements. + books.forEach((book) => { + book.element.classList.toggle("hidden", !filteredBooks.includes(book)); + }); + + // Update UI when no books are found + + }); + } +} + +customElements.define("app-root", AppElement); diff --git a/part-2-javascript/src/app/book.interface.ts b/part-2-javascript/src/app/book.interface.ts new file mode 100644 index 0000000..baa6e75 --- /dev/null +++ b/part-2-javascript/src/app/book.interface.ts @@ -0,0 +1,6 @@ +export interface Book { + author: string; + initials: string; + title: string; + year: number; +} diff --git a/part-2-javascript/src/assets/.gitkeep b/part-2-javascript/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/part-2-javascript/src/assets/books.json b/part-2-javascript/src/assets/books.json new file mode 100644 index 0000000..3e19bcc --- /dev/null +++ b/part-2-javascript/src/assets/books.json @@ -0,0 +1,26 @@ +[ + { + "author": "F. Scott Fitzgerald", + "initials": "FS", + "title": "The Great Gatsby", + "year": 1925 + }, + { + "author": "Harper Lee", + "initials": "HL", + "title": "To Kill a Mockingbird", + "year": 1960 + }, + { + "author": "Stephenie Meyer", + "initials": "SM", + "title": "Twilight", + "year": 2005 + }, + { + "author": "Stephen King", + "initials": "S", + "title": "If It Bleeds", + "year": 2020 + } +] diff --git a/part-2-javascript/src/environments/environment.prod.ts b/part-2-javascript/src/environments/environment.prod.ts new file mode 100644 index 0000000..3612073 --- /dev/null +++ b/part-2-javascript/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/part-2-javascript/src/environments/environment.ts b/part-2-javascript/src/environments/environment.ts new file mode 100644 index 0000000..d9370e9 --- /dev/null +++ b/part-2-javascript/src/environments/environment.ts @@ -0,0 +1,6 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// When building for production, this file is replaced with `environment.prod.ts`. + +export const environment = { + production: false +}; diff --git a/part-2-javascript/src/index.html b/part-2-javascript/src/index.html new file mode 100644 index 0000000..4eaf7f0 --- /dev/null +++ b/part-2-javascript/src/index.html @@ -0,0 +1,19 @@ + + + + + Part2Javascript + + + + + + + + + + + + + diff --git a/part-2-javascript/src/main.ts b/part-2-javascript/src/main.ts new file mode 100644 index 0000000..fdb879d --- /dev/null +++ b/part-2-javascript/src/main.ts @@ -0,0 +1 @@ +import './app/app.element'; diff --git a/part-2-javascript/src/styles.scss b/part-2-javascript/src/styles.scss new file mode 100644 index 0000000..90d4ee0 --- /dev/null +++ b/part-2-javascript/src/styles.scss @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/part-2-javascript/src/test-setup.ts b/part-2-javascript/src/test-setup.ts new file mode 100644 index 0000000..e69de29 diff --git a/part-2-javascript/tsconfig.app.json b/part-2-javascript/tsconfig.app.json new file mode 100644 index 0000000..207432d --- /dev/null +++ b/part-2-javascript/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../dist/out-tsc", + "types": ["node"] + }, + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/part-2-javascript/tsconfig.json b/part-2-javascript/tsconfig.json new file mode 100644 index 0000000..1ef755b --- /dev/null +++ b/part-2-javascript/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/part-2-javascript/tsconfig.spec.json b/part-2-javascript/tsconfig.spec.json new file mode 100644 index 0000000..ae8ad1b --- /dev/null +++ b/part-2-javascript/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/part-2-javascript/webpack.config.js b/part-2-javascript/webpack.config.js new file mode 100644 index 0000000..b8de6b4 --- /dev/null +++ b/part-2-javascript/webpack.config.js @@ -0,0 +1,9 @@ + +const { composePlugins, withNx } = require('@nx/webpack'); + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + return config; +});