diff --git a/.all-contributorsrc b/.all-contributorsrc index 38856b436..6f2f57401 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -29,6 +29,10 @@ "translation-ru": { "symbol": "🇷🇺", "description": "Translate in Russian" + }, + "translation-ch": { + "symbol": "🇨🇳", + "description": "Translate in Chinese" } }, "contributors": [ @@ -47,6 +51,18 @@ "translation-fr" ] }, + { + "login": "svenson95", + "name": "Sven Brodny", + "avatar_url": "https://avatars.githubusercontent.com/u/46655156?v=4", + "profile": "https://svenson95.github.io/sb-portfolio/", + "contributions": [ + "doc", + "challenge", + "content", + "design" + ] + }, { "login": "jdegand", "name": "J. Degand", @@ -79,6 +95,43 @@ "translation-ru" ] }, + { + "login": "wandri", + "name": "Wandrille", + "avatar_url": "https://avatars.githubusercontent.com/u/15016833?v=4", + "profile": "https://wandrille-guesdon.com/", + "contributions": [ + "challenge" + ] + }, + { + "login": "alcaidio", + "name": "Timothy Alcaide", + "avatar_url": "https://avatars.githubusercontent.com/u/17033036?v=4", + "profile": "https://twitter.com/alcaidio", + "contributions": [ + "challenge" + ] + }, + { + "login": "LMFinney", + "name": "Lance Finney", + "avatar_url": "https://avatars.githubusercontent.com/u/6683747?v=4", + "profile": "https://github.com/LMFinney", + "contributions": [ + "doc", + "challenge" + ] + }, + { + "login": "tsironis13", + "name": "Tsironis Ioannis", + "avatar_url": "https://avatars.githubusercontent.com/u/7561447?v=4", + "profile": "https://github.com/tsironis13", + "contributions": [ + "challenge" + ] + }, { "login": "alan-bio", "name": "Alan Dragicevich", @@ -201,6 +254,115 @@ "contributions": [ "doc" ] + }, + { + "login": "webbomj", + "name": "Лапин Андрей (Lapin Andrey)", + "avatar_url": "https://avatars.githubusercontent.com/u/86595717?v=4", + "profile": "https://github.com/webbomj", + "contributions": [ + "translation-ru" + ] + }, + { + "login": "Dinozavvvr", + "name": "Dinar Shagaliev", + "avatar_url": "https://avatars.githubusercontent.com/u/45518871?v=4", + "profile": "https://github.com/Dinozavvvr", + "contributions": [ + "translation-ru" + ] + }, + { + "login": "vimulatus", + "name": "Vimulatus", + "avatar_url": "https://avatars.githubusercontent.com/u/63696128?v=4", + "profile": "https://github.com/vimulatus", + "contributions": [ + "doc" + ] + }, + { + "login": "alannelucq", + "name": "Arthur LANNELUCQ", + "avatar_url": "https://avatars.githubusercontent.com/u/44091408?v=4", + "profile": "https://github.com/alannelucq", + "contributions": [ + "translation-fr" + ] + }, + { + "login": "fixedmichal", + "name": "fixed_michal", + "avatar_url": "https://avatars.githubusercontent.com/u/26270192?v=4", + "profile": "https://github.com/fixedmichal", + "contributions": [ + "bug" + ] + }, + { + "login": "Tenessy", + "name": "Tenessy", + "avatar_url": "https://avatars.githubusercontent.com/u/65855673?v=4", + "profile": "https://github.com/Tenessy", + "contributions": [ + "bug" + ] + }, + { + "login": "EnochGao", + "name": "Enoch Gao", + "avatar_url": "https://avatars.githubusercontent.com/u/41459067?v=4", + "profile": "https://enochgao.github.io/", + "contributions": [ + "doc", + "translation-ch" + ] + }, + { + "login": "fpalmab", + "name": "Francisco Palma", + "avatar_url": "https://avatars.githubusercontent.com/u/7729812?v=4", + "profile": "https://github.com/fpalmab", + "contributions": [ + "bug" + ] + }, + { + "login": "michalgrzegorczyk-dev", + "name": "Michał Grzegorczyk", + "avatar_url": "https://avatars.githubusercontent.com/u/47832176?v=4", + "profile": "https://github.com/michalgrzegorczyk-dev", + "contributions": [ + "doc" + ] + }, + { + "login": "tamim36", + "name": "Tamim Arefin Anik", + "avatar_url": "https://avatars.githubusercontent.com/u/42251521?v=4", + "profile": "https://github.com/tamim36", + "contributions": [ + "bug" + ] + }, + { + "login": "WhoisBsa", + "name": "Matheus B.", + "avatar_url": "https://avatars.githubusercontent.com/u/36895235?v=4", + "profile": "https://github.com/WhoisBsa", + "contributions": [ + "bug" + ] + }, + { + "login": "StefH", + "name": "Stef Heyenrath", + "avatar_url": "https://avatars.githubusercontent.com/u/249938?v=4", + "profile": "https://sourcerer.io/stefh", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/.eslintrc.json b/.eslintrc.json index c222fb084..de9b234b6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,6 +6,7 @@ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": { + "@angular-eslint/no-host-metadata-property": "off", "@nx/enforce-module-boundaries": [ "error", { @@ -18,24 +19,24 @@ } ] } - ], - "@angular-eslint/no-host-metadata-property": [ - "error", - { - "allowStatic": true - } ] } }, { "files": ["*.ts", "*.tsx"], "extends": ["plugin:@nx/typescript"], - "rules": {} + "rules": { + "@typescript-eslint/no-extra-semi": "error", + "no-extra-semi": "off" + } }, { "files": ["*.js", "*.jsx"], "extends": ["plugin:@nx/javascript"], - "rules": {} + "rules": { + "@typescript-eslint/no-extra-semi": "error", + "no-extra-semi": "off" + } }, { "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 000000000..f1327048f --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +github: [tomalaforge] diff --git a/.github/github-action/action.yml b/.github/github-action/action.yml new file mode 100644 index 000000000..8019592af --- /dev/null +++ b/.github/github-action/action.yml @@ -0,0 +1,14 @@ +name: 'Hello World' +description: 'Greet someone and record the time' +inputs: + github_token: + description: A GitHub token. + required: false + default: ${{ github.token }} + repo: + description: The owner and repository name. + required: false + default: ${{ github.repository }} +runs: + using: 'node20' + main: 'index.js' diff --git a/.github/github-action/contributors.js b/.github/github-action/contributors.js new file mode 100644 index 000000000..4fa88e697 --- /dev/null +++ b/.github/github-action/contributors.js @@ -0,0 +1,32 @@ +const contributors = [ + 'alcaidio', + 'svenson95', + 'jdegand', + 'DeveshChau', + 'stillst', + 'wandri', + 'webbomj', + 'kabrunko-dev', + 'Sanjar1304', + 'tsironis13', + 'EnochGao', +]; + +const sponsors = [ + 'ddotx', + 'LMFinney', + 'alannelucq', + 'SidV2', + 'fpalmab', + 'CivilEngeneer', + 'apalaio', + 'amosISA', + 'michalgrzegorczyk-dev', + 'zealotrahl', + 'DzoeL123', +]; + +module.exports = { + contributors, + sponsors, +}; diff --git a/.github/github-action/index.js b/.github/github-action/index.js new file mode 100644 index 000000000..a73e6c293 --- /dev/null +++ b/.github/github-action/index.js @@ -0,0 +1,45 @@ +const github = require('@actions/github'); +const core = require('@actions/core'); +const { contributors, sponsors } = require('./contributors'); + +async function run() { + try { + const title = github.context.payload.pull_request.title; + const labels = ['answer']; + + const match = title.match(/Answer(:?)\s*(\d+)/); + if (match) { + labels.push(String(parseInt(match[2], 10))); + } + + const actor = github.context.actor; + if (contributors.includes(actor)) { + labels.push('contributor'); + labels.push('to be reviewed'); + } + + if (sponsors.includes(actor)) { + labels.push('sponsor'); + labels.push('to be reviewed'); + } + + const githubToken = core.getInput('github_token'); + + const number = github.context.payload.pull_request.number; + + const octokit = github.getOctokit(githubToken); + await octokit.rest.issues.addLabels({ + labels, + owner: github.context.repo.owner, + repo: github.context.repo.repo, + issue_number: number, + }); + } catch (e) { + if (e instanceof Error) { + core.error(e); + core.setFailed(e.message); + } + } +} + +run(); diff --git a/.github/workflows/close-inactive-pr.yml b/.github/workflows/close-inactive-pr.yml index d92c25cdb..d5e0e9c95 100644 --- a/.github/workflows/close-inactive-pr.yml +++ b/.github/workflows/close-inactive-pr.yml @@ -1,7 +1,7 @@ name: Close inactive issues on: schedule: - - cron: '20 1 * * *' + - cron: '0 0 * * *' jobs: close-issues: @@ -10,18 +10,19 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v5 + - uses: actions/stale@v9 with: days-before-issue-stale: 20 days-before-issue-close: -1 stale-issue-label: 'stale' - stale-issue-message: 'This issue is stale because it has been open for 20 days with no activity.' + stale-issue-message: 'This issue is stale because it has been open for 15 days with no activity.' exempt-issue-labels: 'long-term' days-before-pr-stale: 20 days-before-pr-close: 7 stale-pr-label: 'stale' - stale-pr-message: 'This pull request is stale because it has been open for 20 days with no activity.' - close-pr-message: 'This pull request was closed because it has been inactive for 7 days since being marked as stale.' + stale-pr-message: 'This pull request is stale because it has been open for 15 days with no activity.' + close-pr-message: 'This pull request was closed because it has been inactive for 5 days since being marked as stale.' only-pr-labels: 'answer' - exempt-pr-labels: 'challenge-creation, long-term' + exempt-pr-labels: 'challenge-creation, long-term, to be reviewed' + remove-pr-stale-when-updated: true repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/label-issue-update.yml b/.github/workflows/label-issue-update.yml new file mode 100644 index 000000000..5f79b0568 --- /dev/null +++ b/.github/workflows/label-issue-update.yml @@ -0,0 +1,21 @@ +name: updates Labels + +on: + push: + branches-ignore: + - main + +jobs: + update_labels: + runs-on: ubuntu-latest + if: | + contains(github.event.pull_request.labels.*.name, 'sponsor') || + contains(github.event.pull_request.labels.*.name, 'contributor') + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Add labels + uses: actions-ecosystem/action-add-labels@v1 + with: + labels: to be reviewed/update diff --git a/.github/workflows/label-issue.yml b/.github/workflows/label-issue.yml new file mode 100644 index 000000000..a5fd40632 --- /dev/null +++ b/.github/workflows/label-issue.yml @@ -0,0 +1,37 @@ +name: Add Labels + +on: + pull_request_target: + types: [ opened, edited, synchronize ] + +jobs: + check-title: + runs-on: ubuntu-latest + steps: + - name: Check PR title + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + echo "Checking PR Title: '$PR_TITLE'" + if [[ ! "$PR_TITLE" =~ ^Answer: ]]; then + echo "❌ PR title should start with 'Answer:[#challenge number]'" + echo "### ❌ PR title should start with 'Answer:[#challenge number]'" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo "✅ PR title format is correct." + echo "### ✅ PR title format is correct." >> $GITHUB_STEP_SUMMARY + fi + add_labels: + runs-on: ubuntu-latest + if: ${{ startsWith(github.event.pull_request.title, 'Answer') }} + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: Install dependencies + run: npm i @actions/core @actions/github + + - name: Add labels + uses: ./.github/github-action/ + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 5472d6bdf..cad0abc01 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,6 @@ Thumbs.db TODO.md .nx/cache +.nx/workspace-data + +.cursorrules \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index ab639d33d..a4684ea74 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,4 +5,5 @@ .angular -/.nx/cache \ No newline at end of file +/.nx/cache +/.nx/workspace-data \ No newline at end of file diff --git a/README.md b/README.md index 1e43bdfef..2965ecc08 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ If you would like to propose a challenge, this project is open source, so feel f ## Challenges -Check [all 44 challenges](https://angular-challenges.vercel.app/) +Check [all 59 challenges](https://angular-challenges.vercel.app/) ## Contributors ✨ @@ -35,26 +35,47 @@ Check [all 44 challenges](https://angular-challenges.vercel.app/) Laforge Thomas
Laforge Thomas

🧩 💻 📖 🖋 🤔 🎨 🇫🇷 + Sven Brodny
Sven Brodny

📖 🧩 🖋 🎨 J. Degand
J. Degand

📖 🖋 💻 Devesh Chaudhari
Devesh Chaudhari

💻 🐛 🧩 stillst
stillst

🧩 🇷🇺 + Wandrille
Wandrille

🧩 + Timothy Alcaide
Timothy Alcaide

🧩 + + + Lance Finney
Lance Finney

📖 🧩 + Tsironis Ioannis
Tsironis Ioannis

🧩 Alan Dragicevich
Alan Dragicevich

📖 Michel EDIGHOFFER
Michel EDIGHOFFER

📖 Gerardo Sebastian Gonzalez
Gerardo Sebastian Gonzalez

📖 - - Evseev Yuriy
Evseev Yuriy

🐛 Tomer953
Tomer953

🐛 📖 💻 + + Dmitriy Mishchenko
Dmitriy Mishchenko

📖 Sagar Devkota
Sagar Devkota

📖 💻 Nelson Gutierrez
Nelson Gutierrez

🇪🇸 Hossain K. M.
Hossain K. M.

📖 Diogo Nishikawa
Diogo Nishikawa

💻 🇵🇹 📖 - - Erick Rodriguez
Erick Rodriguez

🇪🇸 Eduardo Roth
Eduardo Roth

📖 🇪🇸 + + Fernando Bello
Fernando Bello

📖 + Лапин Андрей (Lapin Andrey)
Лапин Андрей (Lapin Andrey)

🇷🇺 + Dinar Shagaliev
Dinar Shagaliev

🇷🇺 + Vimulatus
Vimulatus

📖 + Arthur LANNELUCQ
Arthur LANNELUCQ

🇫🇷 + fixed_michal
fixed_michal

🐛 + Tenessy
Tenessy

🐛 + + + Enoch Gao
Enoch Gao

📖 🇨🇳 + Francisco Palma
Francisco Palma

🐛 + Michał Grzegorczyk
Michał Grzegorczyk

📖 + Tamim Arefin Anik
Tamim Arefin Anik

🐛 + Matheus B.
Matheus B.

🐛 + Stef Heyenrath
Stef Heyenrath

📖 @@ -75,6 +96,8 @@ Check [all 44 challenges](https://angular-challenges.vercel.app/) Contributions of any kind are welcome. -## Licensev +If I have forgotten to add you as a contributor, please reach out to me. 🙏 + +## License MIT diff --git a/apps/angular/projection/.eslintrc.json b/apps/angular/1-projection/.eslintrc.json similarity index 100% rename from apps/angular/projection/.eslintrc.json rename to apps/angular/1-projection/.eslintrc.json diff --git a/apps/angular/projection/README.md b/apps/angular/1-projection/README.md similarity index 100% rename from apps/angular/projection/README.md rename to apps/angular/1-projection/README.md diff --git a/apps/angular/1-projection/jest.config.ts b/apps/angular/1-projection/jest.config.ts new file mode 100644 index 000000000..8eb2510a9 --- /dev/null +++ b/apps/angular/1-projection/jest.config.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +export default { + displayName: 'angular-projection', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + globals: {}, + coverageDirectory: '../../../coverage/apps/angular/1-projection', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/1-projection/project.json b/apps/angular/1-projection/project.json new file mode 100644 index 000000000..d40912c35 --- /dev/null +++ b/apps/angular/1-projection/project.json @@ -0,0 +1,84 @@ +{ + "name": "angular-projection", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/1-projection/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/1-projection", + "index": "apps/angular/1-projection/src/index.html", + "main": "apps/angular/1-projection/src/main.ts", + "polyfills": ["apps/angular/1-projection/src/polyfills.ts"], + "tsConfig": "apps/angular/1-projection/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/1-projection/src/favicon.ico", + "apps/angular/1-projection/src/assets" + ], + "styles": ["apps/angular/1-projection/src/styles.scss"], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-projection:build:production" + }, + "development": { + "buildTarget": "angular-projection:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-projection:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/1-projection/src/app/app.component.ts b/apps/angular/1-projection/src/app/app.component.ts new file mode 100644 index 000000000..df654bbc2 --- /dev/null +++ b/apps/angular/1-projection/src/app/app.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { CityCardComponent } from './component/city-card/city-card.component'; +import { StudentCardComponent } from './component/student-card/student-card.component'; +import { TeacherCardComponent } from './component/teacher-card/teacher-card.component'; + +@Component({ + selector: 'app-root', + template: ` +
+ + + +
+ `, + imports: [TeacherCardComponent, StudentCardComponent, CityCardComponent], +}) +export class AppComponent {} diff --git a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts new file mode 100644 index 000000000..8895c8c84 --- /dev/null +++ b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts @@ -0,0 +1,9 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'app-city-card', + template: 'TODO City', + imports: [], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CityCardComponent {} diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts new file mode 100644 index 000000000..bdfa4abd4 --- /dev/null +++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts @@ -0,0 +1,40 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + OnInit, +} from '@angular/core'; +import { FakeHttpService } from '../../data-access/fake-http.service'; +import { StudentStore } from '../../data-access/student.store'; +import { CardType } from '../../model/card.model'; +import { CardComponent } from '../../ui/card/card.component'; + +@Component({ + selector: 'app-student-card', + template: ` + + `, + styles: [ + ` + ::ng-deep .bg-light-green { + background-color: rgba(0, 250, 0, 0.1); + } + `, + ], + imports: [CardComponent], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class StudentCardComponent implements OnInit { + private http = inject(FakeHttpService); + private store = inject(StudentStore); + + students = this.store.students; + cardType = CardType.STUDENT; + + ngOnInit(): void { + this.http.fetchStudents$.subscribe((s) => this.store.addAll(s)); + } +} diff --git a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts new file mode 100644 index 000000000..adf0ad3c1 --- /dev/null +++ b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts @@ -0,0 +1,34 @@ +import { Component, inject, OnInit } from '@angular/core'; +import { FakeHttpService } from '../../data-access/fake-http.service'; +import { TeacherStore } from '../../data-access/teacher.store'; +import { CardType } from '../../model/card.model'; +import { CardComponent } from '../../ui/card/card.component'; + +@Component({ + selector: 'app-teacher-card', + template: ` + + `, + styles: [ + ` + ::ng-deep .bg-light-red { + background-color: rgba(250, 0, 0, 0.1); + } + `, + ], + imports: [CardComponent], +}) +export class TeacherCardComponent implements OnInit { + private http = inject(FakeHttpService); + private store = inject(TeacherStore); + + teachers = this.store.teachers; + cardType = CardType.TEACHER; + + ngOnInit(): void { + this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t)); + } +} diff --git a/apps/angular/1-projection/src/app/data-access/city.store.ts b/apps/angular/1-projection/src/app/data-access/city.store.ts new file mode 100644 index 000000000..a8b523569 --- /dev/null +++ b/apps/angular/1-projection/src/app/data-access/city.store.ts @@ -0,0 +1,21 @@ +import { Injectable, signal } from '@angular/core'; +import { City } from '../model/city.model'; + +@Injectable({ + providedIn: 'root', +}) +export class CityStore { + private cities = signal([]); + + addAll(cities: City[]) { + this.cities.set(cities); + } + + addOne(city: City) { + this.cities.set([...this.cities(), city]); + } + + deleteOne(id: number) { + this.cities.set(this.cities().filter((s) => s.id !== id)); + } +} diff --git a/apps/angular/projection/src/app/data-access/fake-http.service.ts b/apps/angular/1-projection/src/app/data-access/fake-http.service.ts similarity index 100% rename from apps/angular/projection/src/app/data-access/fake-http.service.ts rename to apps/angular/1-projection/src/app/data-access/fake-http.service.ts diff --git a/apps/angular/1-projection/src/app/data-access/student.store.ts b/apps/angular/1-projection/src/app/data-access/student.store.ts new file mode 100644 index 000000000..6e7f57022 --- /dev/null +++ b/apps/angular/1-projection/src/app/data-access/student.store.ts @@ -0,0 +1,21 @@ +import { Injectable, signal } from '@angular/core'; +import { Student } from '../model/student.model'; + +@Injectable({ + providedIn: 'root', +}) +export class StudentStore { + public students = signal([]); + + addAll(students: Student[]) { + this.students.set(students); + } + + addOne(student: Student) { + this.students.set([...this.students(), student]); + } + + deleteOne(id: number) { + this.students.set(this.students().filter((s) => s.id !== id)); + } +} diff --git a/apps/angular/1-projection/src/app/data-access/teacher.store.ts b/apps/angular/1-projection/src/app/data-access/teacher.store.ts new file mode 100644 index 000000000..5f6dae989 --- /dev/null +++ b/apps/angular/1-projection/src/app/data-access/teacher.store.ts @@ -0,0 +1,21 @@ +import { Injectable, signal } from '@angular/core'; +import { Teacher } from '../model/teacher.model'; + +@Injectable({ + providedIn: 'root', +}) +export class TeacherStore { + public teachers = signal([]); + + addAll(teachers: Teacher[]) { + this.teachers.set(teachers); + } + + addOne(teacher: Teacher) { + this.teachers.set([...this.teachers(), teacher]); + } + + deleteOne(id: number) { + this.teachers.set(this.teachers().filter((t) => t.id !== id)); + } +} diff --git a/apps/angular/projection/src/app/model/card.model.ts b/apps/angular/1-projection/src/app/model/card.model.ts similarity index 100% rename from apps/angular/projection/src/app/model/card.model.ts rename to apps/angular/1-projection/src/app/model/card.model.ts diff --git a/apps/angular/projection/src/app/model/city.model.ts b/apps/angular/1-projection/src/app/model/city.model.ts similarity index 100% rename from apps/angular/projection/src/app/model/city.model.ts rename to apps/angular/1-projection/src/app/model/city.model.ts diff --git a/apps/angular/projection/src/app/model/student.model.ts b/apps/angular/1-projection/src/app/model/student.model.ts similarity index 100% rename from apps/angular/projection/src/app/model/student.model.ts rename to apps/angular/1-projection/src/app/model/student.model.ts diff --git a/apps/angular/projection/src/app/model/teacher.model.ts b/apps/angular/1-projection/src/app/model/teacher.model.ts similarity index 100% rename from apps/angular/projection/src/app/model/teacher.model.ts rename to apps/angular/1-projection/src/app/model/teacher.model.ts diff --git a/apps/angular/1-projection/src/app/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts new file mode 100644 index 000000000..1a6c3648c --- /dev/null +++ b/apps/angular/1-projection/src/app/ui/card/card.component.ts @@ -0,0 +1,58 @@ +import { NgOptimizedImage } from '@angular/common'; +import { Component, inject, input } from '@angular/core'; +import { randStudent, randTeacher } from '../../data-access/fake-http.service'; +import { StudentStore } from '../../data-access/student.store'; +import { TeacherStore } from '../../data-access/teacher.store'; +import { CardType } from '../../model/card.model'; +import { ListItemComponent } from '../list-item/list-item.component'; + +@Component({ + selector: 'app-card', + template: ` +
+ @if (type() === CardType.TEACHER) { + + } + @if (type() === CardType.STUDENT) { + + } + +
+ @for (item of list(); track item) { + + } +
+ + +
+ `, + imports: [ListItemComponent, NgOptimizedImage], +}) +export class CardComponent { + private teacherStore = inject(TeacherStore); + private studentStore = inject(StudentStore); + + readonly list = input(null); + readonly type = input.required(); + readonly customClass = input(''); + + CardType = CardType; + + addNewItem() { + const type = this.type(); + if (type === CardType.TEACHER) { + this.teacherStore.addOne(randTeacher()); + } else if (type === CardType.STUDENT) { + this.studentStore.addOne(randStudent()); + } + } +} diff --git a/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts b/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts new file mode 100644 index 000000000..cffabb451 --- /dev/null +++ b/apps/angular/1-projection/src/app/ui/list-item/list-item.component.ts @@ -0,0 +1,40 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + input, +} from '@angular/core'; +import { StudentStore } from '../../data-access/student.store'; +import { TeacherStore } from '../../data-access/teacher.store'; +import { CardType } from '../../model/card.model'; + +@Component({ + selector: 'app-list-item', + template: ` +
+ {{ name() }} + +
+ `, + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ListItemComponent { + private teacherStore = inject(TeacherStore); + private studentStore = inject(StudentStore); + + readonly id = input.required(); + readonly name = input.required(); + readonly type = input.required(); + + delete(id: number) { + const type = this.type(); + if (type === CardType.TEACHER) { + this.teacherStore.deleteOne(id); + } else if (type === CardType.STUDENT) { + this.studentStore.deleteOne(id); + } + } +} diff --git a/apps/angular/anchor-scrolling/src/assets/.gitkeep b/apps/angular/1-projection/src/assets/.gitkeep similarity index 100% rename from apps/angular/anchor-scrolling/src/assets/.gitkeep rename to apps/angular/1-projection/src/assets/.gitkeep diff --git a/apps/angular/projection/src/assets/img/city.png b/apps/angular/1-projection/src/assets/img/city.png similarity index 100% rename from apps/angular/projection/src/assets/img/city.png rename to apps/angular/1-projection/src/assets/img/city.png diff --git a/apps/angular/projection/src/assets/img/student.webp b/apps/angular/1-projection/src/assets/img/student.webp similarity index 100% rename from apps/angular/projection/src/assets/img/student.webp rename to apps/angular/1-projection/src/assets/img/student.webp diff --git a/apps/angular/projection/src/assets/img/teacher.png b/apps/angular/1-projection/src/assets/img/teacher.png similarity index 100% rename from apps/angular/projection/src/assets/img/teacher.png rename to apps/angular/1-projection/src/assets/img/teacher.png diff --git a/apps/angular/projection/src/assets/svg/trash.svg b/apps/angular/1-projection/src/assets/svg/trash.svg similarity index 100% rename from apps/angular/projection/src/assets/svg/trash.svg rename to apps/angular/1-projection/src/assets/svg/trash.svg diff --git a/apps/angular/anchor-scrolling/src/favicon.ico b/apps/angular/1-projection/src/favicon.ico similarity index 100% rename from apps/angular/anchor-scrolling/src/favicon.ico rename to apps/angular/1-projection/src/favicon.ico diff --git a/apps/angular/1-projection/src/index.html b/apps/angular/1-projection/src/index.html new file mode 100644 index 000000000..bb9c8bc84 --- /dev/null +++ b/apps/angular/1-projection/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-projection + + + + + + + + diff --git a/apps/angular/context-outlet-type/src/main.ts b/apps/angular/1-projection/src/main.ts similarity index 100% rename from apps/angular/context-outlet-type/src/main.ts rename to apps/angular/1-projection/src/main.ts diff --git a/apps/angular/context-outlet-type/src/polyfills.ts b/apps/angular/1-projection/src/polyfills.ts similarity index 100% rename from apps/angular/context-outlet-type/src/polyfills.ts rename to apps/angular/1-projection/src/polyfills.ts diff --git a/apps/angular/projection/src/styles.scss b/apps/angular/1-projection/src/styles.scss similarity index 100% rename from apps/angular/projection/src/styles.scss rename to apps/angular/1-projection/src/styles.scss diff --git a/apps/angular/anchor-scrolling/src/test-setup.ts b/apps/angular/1-projection/src/test-setup.ts similarity index 100% rename from apps/angular/anchor-scrolling/src/test-setup.ts rename to apps/angular/1-projection/src/test-setup.ts diff --git a/apps/angular/anchor-scrolling/tailwind.config.js b/apps/angular/1-projection/tailwind.config.js similarity index 100% rename from apps/angular/anchor-scrolling/tailwind.config.js rename to apps/angular/1-projection/tailwind.config.js diff --git a/apps/angular/context-outlet-type/tsconfig.app.json b/apps/angular/1-projection/tsconfig.app.json similarity index 100% rename from apps/angular/context-outlet-type/tsconfig.app.json rename to apps/angular/1-projection/tsconfig.app.json diff --git a/apps/angular/projection/tsconfig.editor.json b/apps/angular/1-projection/tsconfig.editor.json similarity index 100% rename from apps/angular/projection/tsconfig.editor.json rename to apps/angular/1-projection/tsconfig.editor.json diff --git a/apps/angular/crud/tsconfig.json b/apps/angular/1-projection/tsconfig.json similarity index 100% rename from apps/angular/crud/tsconfig.json rename to apps/angular/1-projection/tsconfig.json diff --git a/apps/angular/projection/tsconfig.spec.json b/apps/angular/1-projection/tsconfig.spec.json similarity index 100% rename from apps/angular/projection/tsconfig.spec.json rename to apps/angular/1-projection/tsconfig.spec.json diff --git a/apps/angular/crud/.eslintrc.json b/apps/angular/10-utility-wrapper-pipe/.eslintrc.json similarity index 100% rename from apps/angular/crud/.eslintrc.json rename to apps/angular/10-utility-wrapper-pipe/.eslintrc.json diff --git a/apps/angular/10-utility-wrapper-pipe/README.md b/apps/angular/10-utility-wrapper-pipe/README.md new file mode 100644 index 000000000..aac426271 --- /dev/null +++ b/apps/angular/10-utility-wrapper-pipe/README.md @@ -0,0 +1,13 @@ +# Utility Wrapper Pipe + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-utility-wrapper-pipe +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/10-pipe-utility/). diff --git a/apps/angular/10-utility-wrapper-pipe/project.json b/apps/angular/10-utility-wrapper-pipe/project.json new file mode 100644 index 000000000..233fc183d --- /dev/null +++ b/apps/angular/10-utility-wrapper-pipe/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-utility-wrapper-pipe", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/10-utility-wrapper-pipe/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/10-utility-wrapper-pipe", + "index": "apps/angular/10-utility-wrapper-pipe/src/index.html", + "main": "apps/angular/10-utility-wrapper-pipe/src/main.ts", + "polyfills": "apps/angular/10-utility-wrapper-pipe/src/polyfills.ts", + "tsConfig": "apps/angular/10-utility-wrapper-pipe/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/10-utility-wrapper-pipe/src/favicon.ico", + "apps/angular/10-utility-wrapper-pipe/src/assets" + ], + "styles": ["apps/angular/10-utility-wrapper-pipe/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-utility-wrapper-pipe:build:production" + }, + "development": { + "buildTarget": "angular-utility-wrapper-pipe:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-utility-wrapper-pipe:build" + } + } + } +} diff --git a/apps/angular/10-utility-wrapper-pipe/src/app/app.component.ts b/apps/angular/10-utility-wrapper-pipe/src/app/app.component.ts new file mode 100644 index 000000000..764d4b9d0 --- /dev/null +++ b/apps/angular/10-utility-wrapper-pipe/src/app/app.component.ts @@ -0,0 +1,35 @@ +import { NgFor } from '@angular/common'; +import { Component } from '@angular/core'; +import { PersonUtils } from './person.utils'; + +@Component({ + imports: [NgFor], + selector: 'app-root', + template: ` +
+ {{ activity.name }} : +
+ {{ showName(person.name, index) }} + {{ isAllowed(person.age, isFirst, activity.minimumAge) }} +
+
+ `, +}) +export class AppComponent { + persons = [ + { name: 'Toto', age: 10 }, + { name: 'Jack', age: 15 }, + { name: 'John', age: 30 }, + ]; + + activities = [ + { name: 'biking', minimumAge: 12 }, + { name: 'hiking', minimumAge: 25 }, + { name: 'dancing', minimumAge: 1 }, + ]; + + showName = PersonUtils.showName; + + isAllowed = PersonUtils.isAllowed; +} diff --git a/apps/angular/pipe-hard/src/app/person.utils.ts b/apps/angular/10-utility-wrapper-pipe/src/app/person.utils.ts similarity index 100% rename from apps/angular/pipe-hard/src/app/person.utils.ts rename to apps/angular/10-utility-wrapper-pipe/src/app/person.utils.ts diff --git a/apps/angular/bug-cd/src/assets/.gitkeep b/apps/angular/10-utility-wrapper-pipe/src/assets/.gitkeep similarity index 100% rename from apps/angular/bug-cd/src/assets/.gitkeep rename to apps/angular/10-utility-wrapper-pipe/src/assets/.gitkeep diff --git a/apps/angular/bug-cd/src/favicon.ico b/apps/angular/10-utility-wrapper-pipe/src/favicon.ico similarity index 100% rename from apps/angular/bug-cd/src/favicon.ico rename to apps/angular/10-utility-wrapper-pipe/src/favicon.ico diff --git a/apps/angular/10-utility-wrapper-pipe/src/index.html b/apps/angular/10-utility-wrapper-pipe/src/index.html new file mode 100644 index 000000000..01d31a163 --- /dev/null +++ b/apps/angular/10-utility-wrapper-pipe/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-utility-wrapper-pipe + + + + + + + + diff --git a/apps/angular/decoupling/src/main.ts b/apps/angular/10-utility-wrapper-pipe/src/main.ts similarity index 100% rename from apps/angular/decoupling/src/main.ts rename to apps/angular/10-utility-wrapper-pipe/src/main.ts diff --git a/apps/angular/crud/src/polyfills.ts b/apps/angular/10-utility-wrapper-pipe/src/polyfills.ts similarity index 100% rename from apps/angular/crud/src/polyfills.ts rename to apps/angular/10-utility-wrapper-pipe/src/polyfills.ts diff --git a/apps/angular/context-outlet-type/src/styles.scss b/apps/angular/10-utility-wrapper-pipe/src/styles.scss similarity index 100% rename from apps/angular/context-outlet-type/src/styles.scss rename to apps/angular/10-utility-wrapper-pipe/src/styles.scss diff --git a/apps/angular/crud/tsconfig.app.json b/apps/angular/10-utility-wrapper-pipe/tsconfig.app.json similarity index 100% rename from apps/angular/crud/tsconfig.app.json rename to apps/angular/10-utility-wrapper-pipe/tsconfig.app.json diff --git a/apps/angular/context-outlet-type/tsconfig.editor.json b/apps/angular/10-utility-wrapper-pipe/tsconfig.editor.json similarity index 100% rename from apps/angular/context-outlet-type/tsconfig.editor.json rename to apps/angular/10-utility-wrapper-pipe/tsconfig.editor.json diff --git a/apps/angular/context-outlet-type/tsconfig.json b/apps/angular/10-utility-wrapper-pipe/tsconfig.json similarity index 100% rename from apps/angular/context-outlet-type/tsconfig.json rename to apps/angular/10-utility-wrapper-pipe/tsconfig.json diff --git a/apps/angular/anchor-scrolling/.eslintrc.json b/apps/angular/13-highly-customizable-css/.eslintrc.json similarity index 100% rename from apps/angular/anchor-scrolling/.eslintrc.json rename to apps/angular/13-highly-customizable-css/.eslintrc.json diff --git a/apps/angular/13-highly-customizable-css/README.md b/apps/angular/13-highly-customizable-css/README.md new file mode 100644 index 000000000..d63171ae6 --- /dev/null +++ b/apps/angular/13-highly-customizable-css/README.md @@ -0,0 +1,13 @@ +# Highly Customizable CSS + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-highly-customizable-css +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/13-styling/). diff --git a/apps/angular/13-highly-customizable-css/project.json b/apps/angular/13-highly-customizable-css/project.json new file mode 100644 index 000000000..8bdda5dba --- /dev/null +++ b/apps/angular/13-highly-customizable-css/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-highly-customizable-css", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/13-highly-customizable-css/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/13-highly-customizable-css", + "index": "apps/angular/13-highly-customizable-css/src/index.html", + "main": "apps/angular/13-highly-customizable-css/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/13-highly-customizable-css/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/13-highly-customizable-css/src/favicon.ico", + "apps/angular/13-highly-customizable-css/src/assets" + ], + "styles": ["apps/angular/13-highly-customizable-css/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-highly-customizable-css:build:production" + }, + "development": { + "buildTarget": "angular-highly-customizable-css:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-highly-customizable-css:build" + } + } + } +} diff --git a/apps/angular/13-highly-customizable-css/src/app/page.component.ts b/apps/angular/13-highly-customizable-css/src/app/page.component.ts new file mode 100644 index 000000000..029ca52d2 --- /dev/null +++ b/apps/angular/13-highly-customizable-css/src/app/page.component.ts @@ -0,0 +1,16 @@ +/* eslint-disable @angular-eslint/component-selector */ +import { Component } from '@angular/core'; +import { TextStaticComponent } from './static-text.component'; +import { TextComponent } from './text.component'; + +@Component({ + selector: 'page', + imports: [TextStaticComponent, TextComponent], + template: ` + + + + This is a blue text + `, +}) +export class PageComponent {} diff --git a/apps/angular/styling/src/app/static-text.component.ts b/apps/angular/13-highly-customizable-css/src/app/static-text.component.ts similarity index 97% rename from apps/angular/styling/src/app/static-text.component.ts rename to apps/angular/13-highly-customizable-css/src/app/static-text.component.ts index cdfd1c19f..70d57d9a3 100644 --- a/apps/angular/styling/src/app/static-text.component.ts +++ b/apps/angular/13-highly-customizable-css/src/app/static-text.component.ts @@ -6,7 +6,6 @@ export type StaticTextType = 'normal' | 'warning' | 'error'; @Component({ selector: 'static-text', - standalone: true, imports: [TextComponent], template: ` This is a static text diff --git a/apps/angular/styling/src/app/text.component.ts b/apps/angular/13-highly-customizable-css/src/app/text.component.ts similarity index 100% rename from apps/angular/styling/src/app/text.component.ts rename to apps/angular/13-highly-customizable-css/src/app/text.component.ts diff --git a/apps/angular/crud/src/assets/.gitkeep b/apps/angular/13-highly-customizable-css/src/assets/.gitkeep similarity index 100% rename from apps/angular/crud/src/assets/.gitkeep rename to apps/angular/13-highly-customizable-css/src/assets/.gitkeep diff --git a/apps/angular/context-outlet-type/src/favicon.ico b/apps/angular/13-highly-customizable-css/src/favicon.ico similarity index 100% rename from apps/angular/context-outlet-type/src/favicon.ico rename to apps/angular/13-highly-customizable-css/src/favicon.ico diff --git a/apps/angular/13-highly-customizable-css/src/index.html b/apps/angular/13-highly-customizable-css/src/index.html new file mode 100644 index 000000000..e4a84b456 --- /dev/null +++ b/apps/angular/13-highly-customizable-css/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-highly-customizable-css + + + + + + + + diff --git a/apps/angular/styling/src/main.ts b/apps/angular/13-highly-customizable-css/src/main.ts similarity index 100% rename from apps/angular/styling/src/main.ts rename to apps/angular/13-highly-customizable-css/src/main.ts diff --git a/apps/angular/ngfor-enhancement/src/styles.scss b/apps/angular/13-highly-customizable-css/src/styles.scss similarity index 100% rename from apps/angular/ngfor-enhancement/src/styles.scss rename to apps/angular/13-highly-customizable-css/src/styles.scss diff --git a/apps/angular/anchor-scrolling/tsconfig.app.json b/apps/angular/13-highly-customizable-css/tsconfig.app.json similarity index 100% rename from apps/angular/anchor-scrolling/tsconfig.app.json rename to apps/angular/13-highly-customizable-css/tsconfig.app.json diff --git a/apps/angular/di/tsconfig.editor.json b/apps/angular/13-highly-customizable-css/tsconfig.editor.json similarity index 100% rename from apps/angular/di/tsconfig.editor.json rename to apps/angular/13-highly-customizable-css/tsconfig.editor.json diff --git a/apps/angular/decoupling/tsconfig.json b/apps/angular/13-highly-customizable-css/tsconfig.json similarity index 100% rename from apps/angular/decoupling/tsconfig.json rename to apps/angular/13-highly-customizable-css/tsconfig.json diff --git a/apps/angular/di/.eslintrc.json b/apps/angular/16-master-dependency-injection/.eslintrc.json similarity index 100% rename from apps/angular/di/.eslintrc.json rename to apps/angular/16-master-dependency-injection/.eslintrc.json diff --git a/apps/angular/16-master-dependency-injection/README.md b/apps/angular/16-master-dependency-injection/README.md new file mode 100644 index 000000000..be19c1ba3 --- /dev/null +++ b/apps/angular/16-master-dependency-injection/README.md @@ -0,0 +1,13 @@ +# Master Dependancy Injection + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-master-dependency-injection +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/16-di/). diff --git a/apps/angular/16-master-dependency-injection/project.json b/apps/angular/16-master-dependency-injection/project.json new file mode 100644 index 000000000..280ed3df4 --- /dev/null +++ b/apps/angular/16-master-dependency-injection/project.json @@ -0,0 +1,74 @@ +{ + "name": "angular-master-dependency-injection", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/16-master-dependency-injection/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/16-master-dependency-injection", + "index": "apps/angular/16-master-dependency-injection/src/index.html", + "main": "apps/angular/16-master-dependency-injection/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/16-master-dependency-injection/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/16-master-dependency-injection/src/favicon.ico", + "apps/angular/16-master-dependency-injection/src/assets" + ], + "styles": [ + "apps/angular/16-master-dependency-injection/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-master-dependency-injection:build:production" + }, + "development": { + "buildTarget": "angular-master-dependency-injection:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-master-dependency-injection:build" + } + } + } +} diff --git a/apps/angular/16-master-dependency-injection/src/app/app.component.ts b/apps/angular/16-master-dependency-injection/src/app/app.component.ts new file mode 100644 index 000000000..5bb91c2b2 --- /dev/null +++ b/apps/angular/16-master-dependency-injection/src/app/app.component.ts @@ -0,0 +1,52 @@ +import { TableComponent } from '@angular-challenges/shared/ui'; +import { AsyncPipe, NgFor } from '@angular/common'; +import { Component, Directive } from '@angular/core'; +import { CurrencyPipe } from './currency.pipe'; +import { CurrencyService } from './currency.service'; +import { Product, products } from './product.model'; + +interface ProductContext { + $implicit: Product; +} + +@Directive({ + selector: 'ng-template[product]', + standalone: true, +}) +export class ProductDirective { + static ngTemplateContextGuard( + dir: ProductDirective, + ctx: unknown, + ): ctx is ProductContext { + return true; + } +} + +@Component({ + imports: [TableComponent, CurrencyPipe, AsyncPipe, NgFor, ProductDirective], + providers: [CurrencyService], + selector: 'app-root', + template: ` + + + + + + + + + + + + + + +
+ {{ col }} +
{{ product.name }}{{ product.priceA | currency | async }}{{ product.priceB | currency | async }}{{ product.priceC | currency | async }}
+ `, +}) +export class AppComponent { + products = products; + displayedColumns = ['name', 'priceA', 'priceB', 'priceC']; +} diff --git a/apps/angular/di/src/app/currency.pipe.ts b/apps/angular/16-master-dependency-injection/src/app/currency.pipe.ts similarity index 100% rename from apps/angular/di/src/app/currency.pipe.ts rename to apps/angular/16-master-dependency-injection/src/app/currency.pipe.ts diff --git a/apps/angular/di/src/app/currency.service.ts b/apps/angular/16-master-dependency-injection/src/app/currency.service.ts similarity index 100% rename from apps/angular/di/src/app/currency.service.ts rename to apps/angular/16-master-dependency-injection/src/app/currency.service.ts diff --git a/apps/angular/di/src/app/product.model.ts b/apps/angular/16-master-dependency-injection/src/app/product.model.ts similarity index 100% rename from apps/angular/di/src/app/product.model.ts rename to apps/angular/16-master-dependency-injection/src/app/product.model.ts diff --git a/apps/angular/decoupling/src/assets/.gitkeep b/apps/angular/16-master-dependency-injection/src/assets/.gitkeep similarity index 100% rename from apps/angular/decoupling/src/assets/.gitkeep rename to apps/angular/16-master-dependency-injection/src/assets/.gitkeep diff --git a/apps/angular/crud/src/favicon.ico b/apps/angular/16-master-dependency-injection/src/favicon.ico similarity index 100% rename from apps/angular/crud/src/favicon.ico rename to apps/angular/16-master-dependency-injection/src/favicon.ico diff --git a/apps/angular/16-master-dependency-injection/src/index.html b/apps/angular/16-master-dependency-injection/src/index.html new file mode 100644 index 000000000..be35bf8c8 --- /dev/null +++ b/apps/angular/16-master-dependency-injection/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-master-dependancy-injection + + + + + + + + diff --git a/apps/angular/di/src/main.ts b/apps/angular/16-master-dependency-injection/src/main.ts similarity index 100% rename from apps/angular/di/src/main.ts rename to apps/angular/16-master-dependency-injection/src/main.ts diff --git a/apps/angular/di/src/styles.scss b/apps/angular/16-master-dependency-injection/src/styles.scss similarity index 100% rename from apps/angular/di/src/styles.scss rename to apps/angular/16-master-dependency-injection/src/styles.scss diff --git a/apps/angular/bug-cd/tsconfig.app.json b/apps/angular/16-master-dependency-injection/tsconfig.app.json similarity index 100% rename from apps/angular/bug-cd/tsconfig.app.json rename to apps/angular/16-master-dependency-injection/tsconfig.app.json diff --git a/apps/angular/router-input/tsconfig.editor.json b/apps/angular/16-master-dependency-injection/tsconfig.editor.json similarity index 100% rename from apps/angular/router-input/tsconfig.editor.json rename to apps/angular/16-master-dependency-injection/tsconfig.editor.json diff --git a/apps/angular/di/tsconfig.json b/apps/angular/16-master-dependency-injection/tsconfig.json similarity index 100% rename from apps/angular/di/tsconfig.json rename to apps/angular/16-master-dependency-injection/tsconfig.json diff --git a/apps/angular/bug-cd/.eslintrc.json b/apps/angular/21-anchor-navigation/.eslintrc.json similarity index 100% rename from apps/angular/bug-cd/.eslintrc.json rename to apps/angular/21-anchor-navigation/.eslintrc.json diff --git a/apps/angular/21-anchor-navigation/README.md b/apps/angular/21-anchor-navigation/README.md new file mode 100644 index 000000000..3683899ba --- /dev/null +++ b/apps/angular/21-anchor-navigation/README.md @@ -0,0 +1,13 @@ +# Anchor Navigation + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-anchor-navigation +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/21-achor-scrolling/). diff --git a/apps/angular/21-anchor-navigation/jest.config.ts b/apps/angular/21-anchor-navigation/jest.config.ts new file mode 100644 index 000000000..7347f70b5 --- /dev/null +++ b/apps/angular/21-anchor-navigation/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'anchor-navigation-anchor-navigation', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/21-anchor-navigation', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/21-anchor-navigation/project.json b/apps/angular/21-anchor-navigation/project.json new file mode 100644 index 000000000..b8ba74b04 --- /dev/null +++ b/apps/angular/21-anchor-navigation/project.json @@ -0,0 +1,83 @@ +{ + "name": "angular-anchor-navigation", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/21-anchor-navigation/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/21-anchor-navigation", + "index": "apps/angular/21-anchor-navigation/src/index.html", + "main": "apps/angular/21-anchor-navigation/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/21-anchor-navigation/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/21-anchor-navigation/src/favicon.ico", + "apps/angular/21-anchor-navigation/src/assets" + ], + "styles": ["apps/angular/21-anchor-navigation/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-anchor-navigation:build:production" + }, + "development": { + "buildTarget": "angular-anchor-navigation:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-anchor-navigation:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/21-anchor-navigation/src/app/app.component.ts b/apps/angular/21-anchor-navigation/src/app/app.component.ts new file mode 100644 index 000000000..5caca0271 --- /dev/null +++ b/apps/angular/21-anchor-navigation/src/app/app.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + template: ` + + `, +}) +export class AppComponent {} diff --git a/apps/angular/anchor-scrolling/src/app/app.config.ts b/apps/angular/21-anchor-navigation/src/app/app.config.ts similarity index 100% rename from apps/angular/anchor-scrolling/src/app/app.config.ts rename to apps/angular/21-anchor-navigation/src/app/app.config.ts diff --git a/apps/angular/anchor-scrolling/src/app/app.routes.ts b/apps/angular/21-anchor-navigation/src/app/app.routes.ts similarity index 100% rename from apps/angular/anchor-scrolling/src/app/app.routes.ts rename to apps/angular/21-anchor-navigation/src/app/app.routes.ts diff --git a/apps/angular/anchor-scrolling/src/app/foo.component.ts b/apps/angular/21-anchor-navigation/src/app/foo.component.ts similarity index 95% rename from apps/angular/anchor-scrolling/src/app/foo.component.ts rename to apps/angular/21-anchor-navigation/src/app/foo.component.ts index 87f9b59d9..6744c3662 100644 --- a/apps/angular/anchor-scrolling/src/app/foo.component.ts +++ b/apps/angular/21-anchor-navigation/src/app/foo.component.ts @@ -2,7 +2,6 @@ import { Component } from '@angular/core'; import { NavButtonComponent } from './nav-button.component'; @Component({ - standalone: true, imports: [NavButtonComponent], selector: 'app-foo', template: ` diff --git a/apps/angular/21-anchor-navigation/src/app/home.component.ts b/apps/angular/21-anchor-navigation/src/app/home.component.ts new file mode 100644 index 000000000..6ef9bc2b6 --- /dev/null +++ b/apps/angular/21-anchor-navigation/src/app/home.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { NavButtonComponent } from './nav-button.component'; + +@Component({ + imports: [NavButtonComponent], + selector: 'app-home', + template: ` + Foo Page +
+ Empty + Scroll Bottom +
+
+ I want to scroll each + Scroll Top +
+ `, +}) +export class HomeComponent {} diff --git a/apps/angular/anchor-scrolling/src/app/nav-button.component.ts b/apps/angular/21-anchor-navigation/src/app/nav-button.component.ts similarity index 100% rename from apps/angular/anchor-scrolling/src/app/nav-button.component.ts rename to apps/angular/21-anchor-navigation/src/app/nav-button.component.ts diff --git a/apps/angular/di/src/assets/.gitkeep b/apps/angular/21-anchor-navigation/src/assets/.gitkeep similarity index 100% rename from apps/angular/di/src/assets/.gitkeep rename to apps/angular/21-anchor-navigation/src/assets/.gitkeep diff --git a/apps/angular/decoupling/src/favicon.ico b/apps/angular/21-anchor-navigation/src/favicon.ico similarity index 100% rename from apps/angular/decoupling/src/favicon.ico rename to apps/angular/21-anchor-navigation/src/favicon.ico diff --git a/apps/angular/21-anchor-navigation/src/index.html b/apps/angular/21-anchor-navigation/src/index.html new file mode 100644 index 000000000..06a706a0a --- /dev/null +++ b/apps/angular/21-anchor-navigation/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-anchor-navigation + + + + + + + + diff --git a/apps/angular/anchor-scrolling/src/main.ts b/apps/angular/21-anchor-navigation/src/main.ts similarity index 100% rename from apps/angular/anchor-scrolling/src/main.ts rename to apps/angular/21-anchor-navigation/src/main.ts diff --git a/apps/angular/anchor-scrolling/src/styles.scss b/apps/angular/21-anchor-navigation/src/styles.scss similarity index 100% rename from apps/angular/anchor-scrolling/src/styles.scss rename to apps/angular/21-anchor-navigation/src/styles.scss diff --git a/apps/angular/projection/src/test-setup.ts b/apps/angular/21-anchor-navigation/src/test-setup.ts similarity index 100% rename from apps/angular/projection/src/test-setup.ts rename to apps/angular/21-anchor-navigation/src/test-setup.ts diff --git a/apps/angular/bug-cd/tailwind.config.js b/apps/angular/21-anchor-navigation/tailwind.config.js similarity index 100% rename from apps/angular/bug-cd/tailwind.config.js rename to apps/angular/21-anchor-navigation/tailwind.config.js diff --git a/apps/angular/decoupling/tsconfig.app.json b/apps/angular/21-anchor-navigation/tsconfig.app.json similarity index 100% rename from apps/angular/decoupling/tsconfig.app.json rename to apps/angular/21-anchor-navigation/tsconfig.app.json diff --git a/apps/angular/anchor-scrolling/tsconfig.editor.json b/apps/angular/21-anchor-navigation/tsconfig.editor.json similarity index 100% rename from apps/angular/anchor-scrolling/tsconfig.editor.json rename to apps/angular/21-anchor-navigation/tsconfig.editor.json diff --git a/apps/angular/anchor-scrolling/tsconfig.json b/apps/angular/21-anchor-navigation/tsconfig.json similarity index 100% rename from apps/angular/anchor-scrolling/tsconfig.json rename to apps/angular/21-anchor-navigation/tsconfig.json diff --git a/apps/angular/anchor-scrolling/tsconfig.spec.json b/apps/angular/21-anchor-navigation/tsconfig.spec.json similarity index 100% rename from apps/angular/anchor-scrolling/tsconfig.spec.json rename to apps/angular/21-anchor-navigation/tsconfig.spec.json diff --git a/apps/angular/decoupling/.eslintrc.json b/apps/angular/22-router-input/.eslintrc.json similarity index 100% rename from apps/angular/decoupling/.eslintrc.json rename to apps/angular/22-router-input/.eslintrc.json diff --git a/apps/angular/router-input/README.md b/apps/angular/22-router-input/README.md similarity index 100% rename from apps/angular/router-input/README.md rename to apps/angular/22-router-input/README.md diff --git a/apps/angular/22-router-input/project.json b/apps/angular/22-router-input/project.json new file mode 100644 index 000000000..58cd889c5 --- /dev/null +++ b/apps/angular/22-router-input/project.json @@ -0,0 +1,71 @@ +{ + "name": "angular-router-input", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/22-router-input/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/22-router-input", + "index": "apps/angular/22-router-input/src/index.html", + "main": "apps/angular/22-router-input/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/22-router-input/tsconfig.app.json", + "assets": [ + "apps/angular/22-router-input/src/favicon.ico", + "apps/angular/22-router-input/src/assets" + ], + "styles": ["apps/angular/22-router-input/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-router-input:build:production" + }, + "development": { + "buildTarget": "angular-router-input:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-router-input:build" + } + } + } +} diff --git a/apps/angular/22-router-input/src/app/app.component.ts b/apps/angular/22-router-input/src/app/app.component.ts new file mode 100644 index 000000000..9dfc11200 --- /dev/null +++ b/apps/angular/22-router-input/src/app/app.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { RouterLink, RouterModule } from '@angular/router'; + +@Component({ + imports: [RouterLink, RouterModule, ReactiveFormsModule], + selector: 'app-root', + template: ` + + + + + + + + `, +}) +export class AppComponent { + userName = new FormControl(); + testId = new FormControl(); +} diff --git a/apps/angular/router-input/src/app/app.config.ts b/apps/angular/22-router-input/src/app/app.config.ts similarity index 100% rename from apps/angular/router-input/src/app/app.config.ts rename to apps/angular/22-router-input/src/app/app.config.ts diff --git a/apps/angular/router-input/src/app/app.routes.ts b/apps/angular/22-router-input/src/app/app.routes.ts similarity index 100% rename from apps/angular/router-input/src/app/app.routes.ts rename to apps/angular/22-router-input/src/app/app.routes.ts diff --git a/apps/angular/22-router-input/src/app/home.component.ts b/apps/angular/22-router-input/src/app/home.component.ts new file mode 100644 index 000000000..0ddc1501d --- /dev/null +++ b/apps/angular/22-router-input/src/app/home.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; +@Component({ + selector: 'app-home', + imports: [], + template: ` +
Home
+ `, +}) +export default class HomeComponent {} diff --git a/apps/angular/router-input/src/app/test.component.ts b/apps/angular/22-router-input/src/app/test.component.ts similarity index 97% rename from apps/angular/router-input/src/app/test.component.ts rename to apps/angular/22-router-input/src/app/test.component.ts index 88c1465f3..747ab4483 100644 --- a/apps/angular/router-input/src/app/test.component.ts +++ b/apps/angular/22-router-input/src/app/test.component.ts @@ -5,7 +5,6 @@ import { map } from 'rxjs'; @Component({ selector: 'app-subscription', - standalone: true, imports: [AsyncPipe], template: `
TestId: {{ testId$ | async }}
diff --git a/apps/angular/injection-token/src/assets/.gitkeep b/apps/angular/22-router-input/src/assets/.gitkeep similarity index 100% rename from apps/angular/injection-token/src/assets/.gitkeep rename to apps/angular/22-router-input/src/assets/.gitkeep diff --git a/apps/angular/di/src/favicon.ico b/apps/angular/22-router-input/src/favicon.ico similarity index 100% rename from apps/angular/di/src/favicon.ico rename to apps/angular/22-router-input/src/favicon.ico diff --git a/apps/angular/22-router-input/src/index.html b/apps/angular/22-router-input/src/index.html new file mode 100644 index 000000000..30e74f7b4 --- /dev/null +++ b/apps/angular/22-router-input/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-router-input + + + + + + + + diff --git a/apps/angular/bug-cd/src/main.ts b/apps/angular/22-router-input/src/main.ts similarity index 100% rename from apps/angular/bug-cd/src/main.ts rename to apps/angular/22-router-input/src/main.ts diff --git a/apps/angular/pipe-easy/src/styles.scss b/apps/angular/22-router-input/src/styles.scss similarity index 100% rename from apps/angular/pipe-easy/src/styles.scss rename to apps/angular/22-router-input/src/styles.scss diff --git a/apps/angular/di/tsconfig.app.json b/apps/angular/22-router-input/tsconfig.app.json similarity index 100% rename from apps/angular/di/tsconfig.app.json rename to apps/angular/22-router-input/tsconfig.app.json diff --git a/apps/angular/signal-input/tsconfig.editor.json b/apps/angular/22-router-input/tsconfig.editor.json similarity index 100% rename from apps/angular/signal-input/tsconfig.editor.json rename to apps/angular/22-router-input/tsconfig.editor.json diff --git a/apps/angular/module-to-standalone/tsconfig.json b/apps/angular/22-router-input/tsconfig.json similarity index 100% rename from apps/angular/module-to-standalone/tsconfig.json rename to apps/angular/22-router-input/tsconfig.json diff --git a/apps/angular/ngfor-enhancement/.eslintrc.json b/apps/angular/3-directive-enhancement/.eslintrc.json similarity index 100% rename from apps/angular/ngfor-enhancement/.eslintrc.json rename to apps/angular/3-directive-enhancement/.eslintrc.json diff --git a/apps/angular/3-directive-enhancement/README.md b/apps/angular/3-directive-enhancement/README.md new file mode 100644 index 000000000..f89eb48bd --- /dev/null +++ b/apps/angular/3-directive-enhancement/README.md @@ -0,0 +1,13 @@ +# Directive Enhancement + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-directive-enhancement +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/3-directive-enhancement/). diff --git a/apps/angular/3-directive-enhancement/project.json b/apps/angular/3-directive-enhancement/project.json new file mode 100644 index 000000000..f16c4d7a1 --- /dev/null +++ b/apps/angular/3-directive-enhancement/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-directive-enhancement", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/3-directive-enhancement/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/3-directive-enhancement", + "index": "apps/angular/3-directive-enhancement/src/index.html", + "main": "apps/angular/3-directive-enhancement/src/main.ts", + "polyfills": "apps/angular/3-directive-enhancement/src/polyfills.ts", + "tsConfig": "apps/angular/3-directive-enhancement/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/3-directive-enhancement/src/favicon.ico", + "apps/angular/3-directive-enhancement/src/assets" + ], + "styles": ["apps/angular/3-directive-enhancement/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-directive-enhancement:build:production" + }, + "development": { + "buildTarget": "angular-directive-enhancement:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-directive-enhancement:build" + } + } + } +} diff --git a/apps/angular/3-directive-enhancement/src/app/app.component.ts b/apps/angular/3-directive-enhancement/src/app/app.component.ts new file mode 100644 index 000000000..8d37369a1 --- /dev/null +++ b/apps/angular/3-directive-enhancement/src/app/app.component.ts @@ -0,0 +1,24 @@ +import { NgFor, NgIf } from '@angular/common'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +interface Person { + name: string; +} + +@Component({ + imports: [NgFor, NgIf], + selector: 'app-root', + template: ` + +
+ {{ person.name }} +
+
+ The list is empty !! + `, + styles: [], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + persons: Person[] = []; +} diff --git a/apps/angular/interop-rxjs-signal/src/assets/.gitkeep b/apps/angular/3-directive-enhancement/src/assets/.gitkeep similarity index 100% rename from apps/angular/interop-rxjs-signal/src/assets/.gitkeep rename to apps/angular/3-directive-enhancement/src/assets/.gitkeep diff --git a/apps/angular/injection-token/src/favicon.ico b/apps/angular/3-directive-enhancement/src/favicon.ico similarity index 100% rename from apps/angular/injection-token/src/favicon.ico rename to apps/angular/3-directive-enhancement/src/favicon.ico diff --git a/apps/angular/3-directive-enhancement/src/index.html b/apps/angular/3-directive-enhancement/src/index.html new file mode 100644 index 000000000..28def4ef2 --- /dev/null +++ b/apps/angular/3-directive-enhancement/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-directive-enhancement + + + + + + + + diff --git a/apps/angular/ngfor-enhancement/src/main.ts b/apps/angular/3-directive-enhancement/src/main.ts similarity index 100% rename from apps/angular/ngfor-enhancement/src/main.ts rename to apps/angular/3-directive-enhancement/src/main.ts diff --git a/apps/angular/ngfor-enhancement/src/polyfills.ts b/apps/angular/3-directive-enhancement/src/polyfills.ts similarity index 100% rename from apps/angular/ngfor-enhancement/src/polyfills.ts rename to apps/angular/3-directive-enhancement/src/polyfills.ts diff --git a/apps/angular/pipe-hard/src/styles.scss b/apps/angular/3-directive-enhancement/src/styles.scss similarity index 100% rename from apps/angular/pipe-hard/src/styles.scss rename to apps/angular/3-directive-enhancement/src/styles.scss diff --git a/apps/angular/ngfor-enhancement/tsconfig.app.json b/apps/angular/3-directive-enhancement/tsconfig.app.json similarity index 100% rename from apps/angular/ngfor-enhancement/tsconfig.app.json rename to apps/angular/3-directive-enhancement/tsconfig.app.json diff --git a/apps/angular/crud/tsconfig.editor.json b/apps/angular/3-directive-enhancement/tsconfig.editor.json similarity index 100% rename from apps/angular/crud/tsconfig.editor.json rename to apps/angular/3-directive-enhancement/tsconfig.editor.json diff --git a/apps/angular/ngfor-enhancement/tsconfig.json b/apps/angular/3-directive-enhancement/tsconfig.json similarity index 100% rename from apps/angular/ngfor-enhancement/tsconfig.json rename to apps/angular/3-directive-enhancement/tsconfig.json diff --git a/apps/angular/interop-rxjs-signal/.eslintrc.json b/apps/angular/31-module-to-standalone/.eslintrc.json similarity index 100% rename from apps/angular/interop-rxjs-signal/.eslintrc.json rename to apps/angular/31-module-to-standalone/.eslintrc.json diff --git a/apps/angular/module-to-standalone/README.md b/apps/angular/31-module-to-standalone/README.md similarity index 100% rename from apps/angular/module-to-standalone/README.md rename to apps/angular/31-module-to-standalone/README.md diff --git a/apps/angular/31-module-to-standalone/project.json b/apps/angular/31-module-to-standalone/project.json new file mode 100644 index 000000000..c1a51b5ed --- /dev/null +++ b/apps/angular/31-module-to-standalone/project.json @@ -0,0 +1,71 @@ +{ + "name": "angular-module-to-standalone", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/31-module-to-standalone/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/31-module-to-standalone", + "index": "apps/angular/31-module-to-standalone/src/index.html", + "main": "apps/angular/31-module-to-standalone/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/31-module-to-standalone/tsconfig.app.json", + "assets": [ + "apps/angular/31-module-to-standalone/src/favicon.ico", + "apps/angular/31-module-to-standalone/src/assets" + ], + "styles": ["apps/angular/31-module-to-standalone/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-module-to-standalone:build:production" + }, + "development": { + "buildTarget": "angular-module-to-standalone:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-module-to-standalone:build" + } + } + } +} diff --git a/apps/angular/31-module-to-standalone/src/app/app.component.ts b/apps/angular/31-module-to-standalone/src/app/app.component.ts new file mode 100644 index 000000000..986df84b5 --- /dev/null +++ b/apps/angular/31-module-to-standalone/src/app/app.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: ` +
+ + + +
+ + `, + host: { + class: 'flex flex-col p-4 gap-3', + }, + standalone: false, +}) +export class AppComponent {} diff --git a/apps/angular/module-to-standalone/src/app/app.module.ts b/apps/angular/31-module-to-standalone/src/app/app.module.ts similarity index 100% rename from apps/angular/module-to-standalone/src/app/app.module.ts rename to apps/angular/31-module-to-standalone/src/app/app.module.ts diff --git a/apps/angular/module-to-standalone/src/assets/.gitkeep b/apps/angular/31-module-to-standalone/src/assets/.gitkeep similarity index 100% rename from apps/angular/module-to-standalone/src/assets/.gitkeep rename to apps/angular/31-module-to-standalone/src/assets/.gitkeep diff --git a/apps/angular/interop-rxjs-signal/src/favicon.ico b/apps/angular/31-module-to-standalone/src/favicon.ico similarity index 100% rename from apps/angular/interop-rxjs-signal/src/favicon.ico rename to apps/angular/31-module-to-standalone/src/favicon.ico diff --git a/apps/angular/31-module-to-standalone/src/index.html b/apps/angular/31-module-to-standalone/src/index.html new file mode 100644 index 000000000..fe0d5b978 --- /dev/null +++ b/apps/angular/31-module-to-standalone/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-module-to-standalone + + + + + + + + diff --git a/apps/angular/module-to-standalone/src/main.ts b/apps/angular/31-module-to-standalone/src/main.ts similarity index 100% rename from apps/angular/module-to-standalone/src/main.ts rename to apps/angular/31-module-to-standalone/src/main.ts diff --git a/apps/angular/bug-cd/src/styles.scss b/apps/angular/31-module-to-standalone/src/styles.scss similarity index 100% rename from apps/angular/bug-cd/src/styles.scss rename to apps/angular/31-module-to-standalone/src/styles.scss diff --git a/apps/angular/module-to-standalone/tailwind.config.js b/apps/angular/31-module-to-standalone/tailwind.config.js similarity index 100% rename from apps/angular/module-to-standalone/tailwind.config.js rename to apps/angular/31-module-to-standalone/tailwind.config.js diff --git a/apps/angular/injection-token/tsconfig.app.json b/apps/angular/31-module-to-standalone/tsconfig.app.json similarity index 100% rename from apps/angular/injection-token/tsconfig.app.json rename to apps/angular/31-module-to-standalone/tsconfig.app.json diff --git a/apps/angular/module-to-standalone/tsconfig.editor.json b/apps/angular/31-module-to-standalone/tsconfig.editor.json similarity index 100% rename from apps/angular/module-to-standalone/tsconfig.editor.json rename to apps/angular/31-module-to-standalone/tsconfig.editor.json diff --git a/apps/angular/router-input/tsconfig.json b/apps/angular/31-module-to-standalone/tsconfig.json similarity index 100% rename from apps/angular/router-input/tsconfig.json rename to apps/angular/31-module-to-standalone/tsconfig.json diff --git a/apps/angular/module-to-standalone/.eslintrc.json b/apps/angular/32-change-detection-bug/.eslintrc.json similarity index 100% rename from apps/angular/module-to-standalone/.eslintrc.json rename to apps/angular/32-change-detection-bug/.eslintrc.json diff --git a/apps/angular/32-change-detection-bug/README.md b/apps/angular/32-change-detection-bug/README.md new file mode 100644 index 000000000..41e533388 --- /dev/null +++ b/apps/angular/32-change-detection-bug/README.md @@ -0,0 +1,13 @@ +# Change Detection Bug + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-change-detection-bug +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/32-bug-cd/). diff --git a/apps/angular/32-change-detection-bug/jest.config.ts b/apps/angular/32-change-detection-bug/jest.config.ts new file mode 100644 index 000000000..d0412f028 --- /dev/null +++ b/apps/angular/32-change-detection-bug/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'angular-change-detection-bug', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/32-change-detection-bug', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/32-change-detection-bug/project.json b/apps/angular/32-change-detection-bug/project.json new file mode 100644 index 000000000..48eb9ef1e --- /dev/null +++ b/apps/angular/32-change-detection-bug/project.json @@ -0,0 +1,82 @@ +{ + "name": "angular-change-detection-bug", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/32-change-detection-bug/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/32-change-detection-bug", + "index": "apps/angular/32-change-detection-bug/src/index.html", + "main": "apps/angular/32-change-detection-bug/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/32-change-detection-bug/tsconfig.app.json", + "assets": [ + "apps/angular/32-change-detection-bug/src/favicon.ico", + "apps/angular/32-change-detection-bug/src/assets" + ], + "styles": ["apps/angular/32-change-detection-bug/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-change-detection-bug:build:production" + }, + "development": { + "buildTarget": "angular-change-detection-bug:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-change-detection-bug:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/32-change-detection-bug/src/app/app.component.ts b/apps/angular/32-change-detection-bug/src/app/app.component.ts new file mode 100644 index 000000000..217999c3a --- /dev/null +++ b/apps/angular/32-change-detection-bug/src/app/app.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + template: ` +

My Application

+
+ +
+ +
+
+ `, + host: { + class: 'flex flex-col gap-2', + }, +}) +export class AppComponent {} diff --git a/apps/angular/bug-cd/src/app/app.config.ts b/apps/angular/32-change-detection-bug/src/app/app.config.ts similarity index 100% rename from apps/angular/bug-cd/src/app/app.config.ts rename to apps/angular/32-change-detection-bug/src/app/app.config.ts diff --git a/apps/angular/bug-cd/src/app/bar.component.ts b/apps/angular/32-change-detection-bug/src/app/bar.component.ts similarity index 100% rename from apps/angular/bug-cd/src/app/bar.component.ts rename to apps/angular/32-change-detection-bug/src/app/bar.component.ts diff --git a/apps/angular/bug-cd/src/app/fake.service.ts b/apps/angular/32-change-detection-bug/src/app/fake.service.ts similarity index 100% rename from apps/angular/bug-cd/src/app/fake.service.ts rename to apps/angular/32-change-detection-bug/src/app/fake.service.ts diff --git a/apps/angular/bug-cd/src/app/foo.component.ts b/apps/angular/32-change-detection-bug/src/app/foo.component.ts similarity index 100% rename from apps/angular/bug-cd/src/app/foo.component.ts rename to apps/angular/32-change-detection-bug/src/app/foo.component.ts diff --git a/apps/angular/bug-cd/src/app/main-navigation.component.ts b/apps/angular/32-change-detection-bug/src/app/main-navigation.component.ts similarity index 97% rename from apps/angular/bug-cd/src/app/main-navigation.component.ts rename to apps/angular/32-change-detection-bug/src/app/main-navigation.component.ts index c8a6f6d22..3d5ce20f8 100644 --- a/apps/angular/bug-cd/src/app/main-navigation.component.ts +++ b/apps/angular/32-change-detection-bug/src/app/main-navigation.component.ts @@ -10,7 +10,6 @@ interface MenuItem { @Component({ selector: 'app-nav', - standalone: true, imports: [RouterLink, RouterLinkActive, NgFor], template: ` @@ -38,7 +37,6 @@ export class NavigationComponent { } @Component({ - standalone: true, imports: [NavigationComponent, NgIf, AsyncPipe], template: ` diff --git a/apps/angular/ngfor-enhancement/src/assets/.gitkeep b/apps/angular/32-change-detection-bug/src/assets/.gitkeep similarity index 100% rename from apps/angular/ngfor-enhancement/src/assets/.gitkeep rename to apps/angular/32-change-detection-bug/src/assets/.gitkeep diff --git a/apps/angular/module-to-standalone/src/favicon.ico b/apps/angular/32-change-detection-bug/src/favicon.ico similarity index 100% rename from apps/angular/module-to-standalone/src/favicon.ico rename to apps/angular/32-change-detection-bug/src/favicon.ico diff --git a/apps/angular/32-change-detection-bug/src/index.html b/apps/angular/32-change-detection-bug/src/index.html new file mode 100644 index 000000000..350759387 --- /dev/null +++ b/apps/angular/32-change-detection-bug/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-change-detection-bug + + + + + + + + diff --git a/apps/angular/injection-token/src/main.ts b/apps/angular/32-change-detection-bug/src/main.ts similarity index 100% rename from apps/angular/injection-token/src/main.ts rename to apps/angular/32-change-detection-bug/src/main.ts diff --git a/apps/angular/decoupling/src/styles.scss b/apps/angular/32-change-detection-bug/src/styles.scss similarity index 100% rename from apps/angular/decoupling/src/styles.scss rename to apps/angular/32-change-detection-bug/src/styles.scss diff --git a/apps/angular/bug-cd/src/test-setup.ts b/apps/angular/32-change-detection-bug/src/test-setup.ts similarity index 100% rename from apps/angular/bug-cd/src/test-setup.ts rename to apps/angular/32-change-detection-bug/src/test-setup.ts diff --git a/apps/angular/decoupling/tailwind.config.js b/apps/angular/32-change-detection-bug/tailwind.config.js similarity index 100% rename from apps/angular/decoupling/tailwind.config.js rename to apps/angular/32-change-detection-bug/tailwind.config.js diff --git a/apps/angular/interop-rxjs-signal/tsconfig.app.json b/apps/angular/32-change-detection-bug/tsconfig.app.json similarity index 100% rename from apps/angular/interop-rxjs-signal/tsconfig.app.json rename to apps/angular/32-change-detection-bug/tsconfig.app.json diff --git a/apps/angular/bug-cd/tsconfig.editor.json b/apps/angular/32-change-detection-bug/tsconfig.editor.json similarity index 100% rename from apps/angular/bug-cd/tsconfig.editor.json rename to apps/angular/32-change-detection-bug/tsconfig.editor.json diff --git a/apps/angular/bug-cd/tsconfig.json b/apps/angular/32-change-detection-bug/tsconfig.json similarity index 100% rename from apps/angular/bug-cd/tsconfig.json rename to apps/angular/32-change-detection-bug/tsconfig.json diff --git a/apps/angular/bug-cd/tsconfig.spec.json b/apps/angular/32-change-detection-bug/tsconfig.spec.json similarity index 100% rename from apps/angular/bug-cd/tsconfig.spec.json rename to apps/angular/32-change-detection-bug/tsconfig.spec.json diff --git a/apps/angular/router-input/.eslintrc.json b/apps/angular/33-decoupling-components/.eslintrc.json similarity index 100% rename from apps/angular/router-input/.eslintrc.json rename to apps/angular/33-decoupling-components/.eslintrc.json diff --git a/apps/angular/33-decoupling-components/README.md b/apps/angular/33-decoupling-components/README.md new file mode 100644 index 000000000..4af70458f --- /dev/null +++ b/apps/angular/33-decoupling-components/README.md @@ -0,0 +1,13 @@ +# Decoupling Components + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-decoupling-components +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/33-decoupling/). diff --git a/apps/angular/33-decoupling-components/project.json b/apps/angular/33-decoupling-components/project.json new file mode 100644 index 000000000..762fc01b5 --- /dev/null +++ b/apps/angular/33-decoupling-components/project.json @@ -0,0 +1,71 @@ +{ + "name": "angular-decoupling-components", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/33-decoupling-components/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/33-decoupling-components", + "index": "apps/angular/33-decoupling-components/src/index.html", + "main": "apps/angular/33-decoupling-components/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/33-decoupling-components/tsconfig.app.json", + "assets": [ + "apps/angular/33-decoupling-components/src/favicon.ico", + "apps/angular/33-decoupling-components/src/assets" + ], + "styles": ["apps/angular/33-decoupling-components/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-decoupling-components:build:production" + }, + "development": { + "buildTarget": "angular-decoupling-components:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-decoupling-components:build" + } + } + } +} diff --git a/apps/angular/33-decoupling-components/src/app/app.component.ts b/apps/angular/33-decoupling-components/src/app/app.component.ts new file mode 100644 index 000000000..0d78f4d34 --- /dev/null +++ b/apps/angular/33-decoupling-components/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { BtnDisabledDirective } from '@angular-challenges/decoupling/brain'; +import { BtnHelmetDirective } from '@angular-challenges/decoupling/helmet'; +import { Component } from '@angular/core'; + +@Component({ + imports: [BtnDisabledDirective, BtnHelmetDirective], + selector: 'app-root', + template: ` + + `, +}) +export class AppComponent {} diff --git a/apps/angular/permissions/src/assets/.gitkeep b/apps/angular/33-decoupling-components/src/assets/.gitkeep similarity index 100% rename from apps/angular/permissions/src/assets/.gitkeep rename to apps/angular/33-decoupling-components/src/assets/.gitkeep diff --git a/apps/angular/ngfor-enhancement/src/favicon.ico b/apps/angular/33-decoupling-components/src/favicon.ico similarity index 100% rename from apps/angular/ngfor-enhancement/src/favicon.ico rename to apps/angular/33-decoupling-components/src/favicon.ico diff --git a/apps/angular/33-decoupling-components/src/index.html b/apps/angular/33-decoupling-components/src/index.html new file mode 100644 index 000000000..b946b0cfd --- /dev/null +++ b/apps/angular/33-decoupling-components/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-decoupling-components + + + + + + + + diff --git a/apps/angular/pipe-easy/src/main.ts b/apps/angular/33-decoupling-components/src/main.ts similarity index 100% rename from apps/angular/pipe-easy/src/main.ts rename to apps/angular/33-decoupling-components/src/main.ts diff --git a/apps/angular/injection-token/src/styles.scss b/apps/angular/33-decoupling-components/src/styles.scss similarity index 100% rename from apps/angular/injection-token/src/styles.scss rename to apps/angular/33-decoupling-components/src/styles.scss diff --git a/apps/angular/injection-token/tailwind.config.js b/apps/angular/33-decoupling-components/tailwind.config.js similarity index 100% rename from apps/angular/injection-token/tailwind.config.js rename to apps/angular/33-decoupling-components/tailwind.config.js diff --git a/apps/angular/module-to-standalone/tsconfig.app.json b/apps/angular/33-decoupling-components/tsconfig.app.json similarity index 100% rename from apps/angular/module-to-standalone/tsconfig.app.json rename to apps/angular/33-decoupling-components/tsconfig.app.json diff --git a/apps/angular/decoupling/tsconfig.editor.json b/apps/angular/33-decoupling-components/tsconfig.editor.json similarity index 100% rename from apps/angular/decoupling/tsconfig.editor.json rename to apps/angular/33-decoupling-components/tsconfig.editor.json diff --git a/apps/angular/styling/tsconfig.json b/apps/angular/33-decoupling-components/tsconfig.json similarity index 100% rename from apps/angular/styling/tsconfig.json rename to apps/angular/33-decoupling-components/tsconfig.json diff --git a/apps/angular/injection-token/.eslintrc.json b/apps/angular/39-injection-token/.eslintrc.json similarity index 100% rename from apps/angular/injection-token/.eslintrc.json rename to apps/angular/39-injection-token/.eslintrc.json diff --git a/apps/angular/injection-token/README.md b/apps/angular/39-injection-token/README.md similarity index 100% rename from apps/angular/injection-token/README.md rename to apps/angular/39-injection-token/README.md diff --git a/apps/angular/39-injection-token/jest.config.ts b/apps/angular/39-injection-token/jest.config.ts new file mode 100644 index 000000000..541d663e7 --- /dev/null +++ b/apps/angular/39-injection-token/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'angular-injection-token', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/39-injection-token', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/39-injection-token/project.json b/apps/angular/39-injection-token/project.json new file mode 100644 index 000000000..8dba72d55 --- /dev/null +++ b/apps/angular/39-injection-token/project.json @@ -0,0 +1,82 @@ +{ + "name": "angular-injection-token", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/39-injection-token/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/39-injection-token", + "index": "apps/angular/39-injection-token/src/index.html", + "main": "apps/angular/39-injection-token/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/39-injection-token/tsconfig.app.json", + "assets": [ + "apps/angular/39-injection-token/src/favicon.ico", + "apps/angular/39-injection-token/src/assets" + ], + "styles": ["apps/angular/39-injection-token/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-injection-token:build:production" + }, + "development": { + "buildTarget": "angular-injection-token:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-injection-token:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/39-injection-token/src/app/app.component.ts b/apps/angular/39-injection-token/src/app/app.component.ts new file mode 100644 index 000000000..280dc090a --- /dev/null +++ b/apps/angular/39-injection-token/src/app/app.component.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet, RouterLink], + selector: 'app-root', + template: ` +
+ + +
+ + `, + host: { + class: 'p-10 flex flex-col', + }, +}) +export class AppComponent {} diff --git a/apps/angular/injection-token/src/app/app.config.ts b/apps/angular/39-injection-token/src/app/app.config.ts similarity index 100% rename from apps/angular/injection-token/src/app/app.config.ts rename to apps/angular/39-injection-token/src/app/app.config.ts diff --git a/apps/angular/injection-token/src/app/data.ts b/apps/angular/39-injection-token/src/app/data.ts similarity index 100% rename from apps/angular/injection-token/src/app/data.ts rename to apps/angular/39-injection-token/src/app/data.ts diff --git a/apps/angular/injection-token/src/app/phone.component.ts b/apps/angular/39-injection-token/src/app/phone.component.ts similarity index 95% rename from apps/angular/injection-token/src/app/phone.component.ts rename to apps/angular/39-injection-token/src/app/phone.component.ts index a58b3cd99..41ee3cfc0 100644 --- a/apps/angular/injection-token/src/app/phone.component.ts +++ b/apps/angular/39-injection-token/src/app/phone.component.ts @@ -3,7 +3,6 @@ import { TimerContainerComponent } from './timer-container.component'; @Component({ selector: 'app-phone', - standalone: true, imports: [TimerContainerComponent], template: `
diff --git a/apps/angular/injection-token/src/app/timer-container.component.ts b/apps/angular/39-injection-token/src/app/timer-container.component.ts similarity index 96% rename from apps/angular/injection-token/src/app/timer-container.component.ts rename to apps/angular/39-injection-token/src/app/timer-container.component.ts index 30af69354..67db6059a 100644 --- a/apps/angular/injection-token/src/app/timer-container.component.ts +++ b/apps/angular/39-injection-token/src/app/timer-container.component.ts @@ -3,7 +3,6 @@ import { DEFAULT_TIMER } from './data'; import { TimerComponent } from './timer.component'; @Component({ selector: 'timer-container', - standalone: true, imports: [TimerComponent], template: `
diff --git a/apps/angular/injection-token/src/app/timer.component.ts b/apps/angular/39-injection-token/src/app/timer.component.ts similarity index 100% rename from apps/angular/injection-token/src/app/timer.component.ts rename to apps/angular/39-injection-token/src/app/timer.component.ts diff --git a/apps/angular/injection-token/src/app/video.component.ts b/apps/angular/39-injection-token/src/app/video.component.ts similarity index 95% rename from apps/angular/injection-token/src/app/video.component.ts rename to apps/angular/39-injection-token/src/app/video.component.ts index 2c218071a..ba0a218b4 100644 --- a/apps/angular/injection-token/src/app/video.component.ts +++ b/apps/angular/39-injection-token/src/app/video.component.ts @@ -3,7 +3,6 @@ import { TimerContainerComponent } from './timer-container.component'; @Component({ selector: 'app-video', - standalone: true, imports: [TimerContainerComponent], template: `
diff --git a/apps/angular/pipe-easy/src/assets/.gitkeep b/apps/angular/39-injection-token/src/assets/.gitkeep similarity index 100% rename from apps/angular/pipe-easy/src/assets/.gitkeep rename to apps/angular/39-injection-token/src/assets/.gitkeep diff --git a/apps/angular/permissions/src/favicon.ico b/apps/angular/39-injection-token/src/favicon.ico similarity index 100% rename from apps/angular/permissions/src/favicon.ico rename to apps/angular/39-injection-token/src/favicon.ico diff --git a/apps/angular/injection-token/src/index.html b/apps/angular/39-injection-token/src/index.html similarity index 100% rename from apps/angular/injection-token/src/index.html rename to apps/angular/39-injection-token/src/index.html diff --git a/apps/angular/interop-rxjs-signal/src/main.ts b/apps/angular/39-injection-token/src/main.ts similarity index 100% rename from apps/angular/interop-rxjs-signal/src/main.ts rename to apps/angular/39-injection-token/src/main.ts diff --git a/apps/angular/interop-rxjs-signal/src/styles.scss b/apps/angular/39-injection-token/src/styles.scss similarity index 100% rename from apps/angular/interop-rxjs-signal/src/styles.scss rename to apps/angular/39-injection-token/src/styles.scss diff --git a/apps/angular/crud/src/test-setup.ts b/apps/angular/39-injection-token/src/test-setup.ts similarity index 100% rename from apps/angular/crud/src/test-setup.ts rename to apps/angular/39-injection-token/src/test-setup.ts diff --git a/apps/angular/interop-rxjs-signal/tailwind.config.js b/apps/angular/39-injection-token/tailwind.config.js similarity index 100% rename from apps/angular/interop-rxjs-signal/tailwind.config.js rename to apps/angular/39-injection-token/tailwind.config.js diff --git a/apps/angular/router-input/tsconfig.app.json b/apps/angular/39-injection-token/tsconfig.app.json similarity index 100% rename from apps/angular/router-input/tsconfig.app.json rename to apps/angular/39-injection-token/tsconfig.app.json diff --git a/apps/angular/injection-token/tsconfig.editor.json b/apps/angular/39-injection-token/tsconfig.editor.json similarity index 100% rename from apps/angular/injection-token/tsconfig.editor.json rename to apps/angular/39-injection-token/tsconfig.editor.json diff --git a/apps/angular/injection-token/tsconfig.json b/apps/angular/39-injection-token/tsconfig.json similarity index 100% rename from apps/angular/injection-token/tsconfig.json rename to apps/angular/39-injection-token/tsconfig.json diff --git a/apps/angular/injection-token/tsconfig.spec.json b/apps/angular/39-injection-token/tsconfig.spec.json similarity index 100% rename from apps/angular/injection-token/tsconfig.spec.json rename to apps/angular/39-injection-token/tsconfig.spec.json diff --git a/apps/angular/context-outlet-type/.eslintrc.json b/apps/angular/4-typed-context-outlet/.eslintrc.json similarity index 100% rename from apps/angular/context-outlet-type/.eslintrc.json rename to apps/angular/4-typed-context-outlet/.eslintrc.json diff --git a/apps/angular/4-typed-context-outlet/README.md b/apps/angular/4-typed-context-outlet/README.md new file mode 100644 index 000000000..e81915167 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/README.md @@ -0,0 +1,13 @@ +# Typed ContextOutlet + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-typed-context-outlet +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/4-context-outlet-typed/). diff --git a/apps/angular/4-typed-context-outlet/project.json b/apps/angular/4-typed-context-outlet/project.json new file mode 100644 index 000000000..ccebf62c7 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-typed-context-outlet", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/4-typed-context-outlet/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/4-typed-context-outlet", + "index": "apps/angular/4-typed-context-outlet/src/index.html", + "main": "apps/angular/4-typed-context-outlet/src/main.ts", + "polyfills": "apps/angular/4-typed-context-outlet/src/polyfills.ts", + "tsConfig": "apps/angular/4-typed-context-outlet/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/4-typed-context-outlet/src/favicon.ico", + "apps/angular/4-typed-context-outlet/src/assets" + ], + "styles": ["apps/angular/4-typed-context-outlet/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-typed-context-outlet:build:production" + }, + "development": { + "buildTarget": "angular-typed-context-outlet:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-typed-context-outlet:build" + } + } + } +} diff --git a/apps/angular/4-typed-context-outlet/src/app/app.component.ts b/apps/angular/4-typed-context-outlet/src/app/app.component.ts new file mode 100644 index 000000000..23be9dac6 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/src/app/app.component.ts @@ -0,0 +1,45 @@ +import { NgTemplateOutlet } from '@angular/common'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ListComponent } from './list.component'; +import { PersonComponent } from './person.component'; + +@Component({ + imports: [NgTemplateOutlet, PersonComponent, ListComponent], + selector: 'app-root', + template: ` + + + {{ name }}: {{ age }} + + + + + + {{ student.name }}: {{ student.age }} - {{ i }} + + + + + + {{ city.name }}: {{ city.country }} - {{ i }} + + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + person = { + name: 'toto', + age: 3, + }; + + students = [ + { name: 'toto', age: 3 }, + { name: 'titi', age: 4 }, + ]; + + cities = [ + { name: 'Paris', country: 'France' }, + { name: 'Berlin', country: 'Germany' }, + ]; +} diff --git a/apps/angular/4-typed-context-outlet/src/app/list.component.ts b/apps/angular/4-typed-context-outlet/src/app/list.component.ts new file mode 100644 index 000000000..b9946e428 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/src/app/list.component.ts @@ -0,0 +1,31 @@ +import { CommonModule } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + ContentChild, + Input, + TemplateRef, +} from '@angular/core'; + +@Component({ + selector: 'list', + imports: [CommonModule], + template: ` +
+ +
+ + No Template + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ListComponent { + @Input() list!: TItem[]; + + @ContentChild('listRef', { read: TemplateRef }) + listTemplateRef!: TemplateRef; +} diff --git a/apps/angular/context-outlet-type/src/app/person.component.ts b/apps/angular/4-typed-context-outlet/src/app/person.component.ts similarity index 97% rename from apps/angular/context-outlet-type/src/app/person.component.ts rename to apps/angular/4-typed-context-outlet/src/app/person.component.ts index 1550cf274..59eb00ab1 100644 --- a/apps/angular/context-outlet-type/src/app/person.component.ts +++ b/apps/angular/4-typed-context-outlet/src/app/person.component.ts @@ -7,7 +7,6 @@ interface Person { } @Component({ - standalone: true, imports: [NgTemplateOutlet], selector: 'person', template: ` diff --git a/apps/angular/pipe-easy/src/favicon.ico b/apps/angular/4-typed-context-outlet/src/favicon.ico similarity index 100% rename from apps/angular/pipe-easy/src/favicon.ico rename to apps/angular/4-typed-context-outlet/src/favicon.ico diff --git a/apps/angular/4-typed-context-outlet/src/index.html b/apps/angular/4-typed-context-outlet/src/index.html new file mode 100644 index 000000000..a9c0b5484 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-typed-context-outlet + + + + + + + + diff --git a/apps/angular/pipe-hard/src/main.ts b/apps/angular/4-typed-context-outlet/src/main.ts similarity index 100% rename from apps/angular/pipe-hard/src/main.ts rename to apps/angular/4-typed-context-outlet/src/main.ts diff --git a/apps/angular/permissions/src/polyfills.ts b/apps/angular/4-typed-context-outlet/src/polyfills.ts similarity index 100% rename from apps/angular/permissions/src/polyfills.ts rename to apps/angular/4-typed-context-outlet/src/polyfills.ts diff --git a/apps/angular/pipe-intermediate/src/styles.scss b/apps/angular/4-typed-context-outlet/src/styles.scss similarity index 100% rename from apps/angular/pipe-intermediate/src/styles.scss rename to apps/angular/4-typed-context-outlet/src/styles.scss diff --git a/apps/angular/permissions/tsconfig.app.json b/apps/angular/4-typed-context-outlet/tsconfig.app.json similarity index 100% rename from apps/angular/permissions/tsconfig.app.json rename to apps/angular/4-typed-context-outlet/tsconfig.app.json diff --git a/apps/angular/ngfor-enhancement/tsconfig.editor.json b/apps/angular/4-typed-context-outlet/tsconfig.editor.json similarity index 100% rename from apps/angular/ngfor-enhancement/tsconfig.editor.json rename to apps/angular/4-typed-context-outlet/tsconfig.editor.json diff --git a/apps/angular/permissions/tsconfig.json b/apps/angular/4-typed-context-outlet/tsconfig.json similarity index 100% rename from apps/angular/permissions/tsconfig.json rename to apps/angular/4-typed-context-outlet/tsconfig.json diff --git a/apps/angular/view-transition/.eslintrc.json b/apps/angular/44-view-transition/.eslintrc.json similarity index 100% rename from apps/angular/view-transition/.eslintrc.json rename to apps/angular/44-view-transition/.eslintrc.json diff --git a/apps/angular/view-transition/README.md b/apps/angular/44-view-transition/README.md similarity index 100% rename from apps/angular/view-transition/README.md rename to apps/angular/44-view-transition/README.md diff --git a/apps/angular/44-view-transition/project.json b/apps/angular/44-view-transition/project.json new file mode 100644 index 000000000..9f4046607 --- /dev/null +++ b/apps/angular/44-view-transition/project.json @@ -0,0 +1,69 @@ +{ + "name": "angular-view-transition", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/44-view-transition/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/44-view-transition", + "index": "apps/angular/44-view-transition/src/index.html", + "browser": "apps/angular/44-view-transition/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/44-view-transition/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/44-view-transition/src/favicon.ico", + "apps/angular/44-view-transition/src/assets" + ], + "styles": ["apps/angular/44-view-transition/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-view-transition:build:production" + }, + "development": { + "buildTarget": "angular-view-transition:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-view-transition:build" + } + } + } +} diff --git a/apps/angular/44-view-transition/src/app/app.component.ts b/apps/angular/44-view-transition/src/app/app.component.ts new file mode 100644 index 000000000..1fcb0c548 --- /dev/null +++ b/apps/angular/44-view-transition/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent {} diff --git a/apps/angular/view-transition/src/app/app.config.ts b/apps/angular/44-view-transition/src/app/app.config.ts similarity index 100% rename from apps/angular/view-transition/src/app/app.config.ts rename to apps/angular/44-view-transition/src/app/app.config.ts diff --git a/apps/angular/view-transition/src/app/blog/blog.component.ts b/apps/angular/44-view-transition/src/app/blog/blog.component.ts similarity index 97% rename from apps/angular/view-transition/src/app/blog/blog.component.ts rename to apps/angular/44-view-transition/src/app/blog/blog.component.ts index 68ffcde50..29291d21e 100644 --- a/apps/angular/view-transition/src/app/blog/blog.component.ts +++ b/apps/angular/44-view-transition/src/app/blog/blog.component.ts @@ -4,7 +4,6 @@ import { ThumbnailComponent } from './thumbnail.component'; @Component({ selector: 'blog', - standalone: true, imports: [ThumbnailComponent], template: `
diff --git a/apps/angular/view-transition/src/app/blog/thumbnail.component.ts b/apps/angular/44-view-transition/src/app/blog/thumbnail.component.ts similarity index 98% rename from apps/angular/view-transition/src/app/blog/thumbnail.component.ts rename to apps/angular/44-view-transition/src/app/blog/thumbnail.component.ts index 6263e97ab..dd2e25e26 100644 --- a/apps/angular/view-transition/src/app/blog/thumbnail.component.ts +++ b/apps/angular/44-view-transition/src/app/blog/thumbnail.component.ts @@ -6,7 +6,6 @@ import { ThumbnailHeaderComponent } from './thumbnail-header.component'; @Component({ selector: 'blog-thumbnail', - standalone: true, imports: [NgOptimizedImage, ThumbnailHeaderComponent, RouterLinkWithHref], template: ` diff --git a/apps/angular/view-transition/src/app/data.ts b/apps/angular/44-view-transition/src/app/data.ts similarity index 100% rename from apps/angular/view-transition/src/app/data.ts rename to apps/angular/44-view-transition/src/app/data.ts diff --git a/apps/angular/view-transition/src/app/post.model.ts b/apps/angular/44-view-transition/src/app/post.model.ts similarity index 100% rename from apps/angular/view-transition/src/app/post.model.ts rename to apps/angular/44-view-transition/src/app/post.model.ts diff --git a/apps/angular/view-transition/src/app/post/post-header.component.ts b/apps/angular/44-view-transition/src/app/post/post-header.component.ts similarity index 89% rename from apps/angular/view-transition/src/app/post/post-header.component.ts rename to apps/angular/44-view-transition/src/app/post/post-header.component.ts index db2f42da0..6d5f30e54 100644 --- a/apps/angular/view-transition/src/app/post/post-header.component.ts +++ b/apps/angular/44-view-transition/src/app/post/post-header.component.ts @@ -3,10 +3,8 @@ import { Component, input } from '@angular/core'; @Component({ selector: 'post-header', - standalone: true, imports: [NgOptimizedImage], template: ` -
Thomas Laforge {{ date() }} - `, host: { class: 'flex flex-col justify-center items-center', diff --git a/apps/angular/44-view-transition/src/app/post/post.component.ts b/apps/angular/44-view-transition/src/app/post/post.component.ts new file mode 100644 index 000000000..edb87f780 --- /dev/null +++ b/apps/angular/44-view-transition/src/app/post/post.component.ts @@ -0,0 +1,46 @@ +import { NgOptimizedImage } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { ThumbnailHeaderComponent } from '../blog/thumbnail-header.component'; +import { fakeTextChapters, posts } from '../data'; +import { PostHeaderComponent } from './post-header.component'; + +@Component({ + selector: 'post', + imports: [ + ThumbnailHeaderComponent, + NgOptimizedImage, + PostHeaderComponent, + RouterLink, + ], + template: ` +
+ + +

{{ post().title }}

+ + @for (chapter of fakeTextChapter; track $index) { +

{{ chapter }}

+ } +
+ `, + host: { + class: 'flex h-full justify-center', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export default class PostComponent { + id = input.required(); + post = computed(() => posts.filter((p) => p.id === this.id())[0]); + + fakeTextChapter = fakeTextChapters; +} diff --git a/apps/angular/pipe-hard/src/assets/.gitkeep b/apps/angular/44-view-transition/src/assets/.gitkeep similarity index 100% rename from apps/angular/pipe-hard/src/assets/.gitkeep rename to apps/angular/44-view-transition/src/assets/.gitkeep diff --git a/apps/angular/view-transition/src/assets/angular.webp b/apps/angular/44-view-transition/src/assets/angular.webp similarity index 100% rename from apps/angular/view-transition/src/assets/angular.webp rename to apps/angular/44-view-transition/src/assets/angular.webp diff --git a/apps/angular/view-transition/src/assets/guard.full.webp b/apps/angular/44-view-transition/src/assets/guard.full.webp similarity index 100% rename from apps/angular/view-transition/src/assets/guard.full.webp rename to apps/angular/44-view-transition/src/assets/guard.full.webp diff --git a/apps/angular/view-transition/src/assets/highly-custom.full.webp b/apps/angular/44-view-transition/src/assets/highly-custom.full.webp similarity index 100% rename from apps/angular/view-transition/src/assets/highly-custom.full.webp rename to apps/angular/44-view-transition/src/assets/highly-custom.full.webp diff --git a/apps/angular/view-transition/src/assets/profil.webp b/apps/angular/44-view-transition/src/assets/profil.webp similarity index 100% rename from apps/angular/view-transition/src/assets/profil.webp rename to apps/angular/44-view-transition/src/assets/profil.webp diff --git a/apps/angular/view-transition/src/assets/signal-cd.full.webp b/apps/angular/44-view-transition/src/assets/signal-cd.full.webp similarity index 100% rename from apps/angular/view-transition/src/assets/signal-cd.full.webp rename to apps/angular/44-view-transition/src/assets/signal-cd.full.webp diff --git a/apps/angular/pipe-hard/src/favicon.ico b/apps/angular/44-view-transition/src/favicon.ico similarity index 100% rename from apps/angular/pipe-hard/src/favicon.ico rename to apps/angular/44-view-transition/src/favicon.ico diff --git a/apps/angular/view-transition/src/index.html b/apps/angular/44-view-transition/src/index.html similarity index 100% rename from apps/angular/view-transition/src/index.html rename to apps/angular/44-view-transition/src/index.html diff --git a/apps/angular/router-input/src/main.ts b/apps/angular/44-view-transition/src/main.ts similarity index 100% rename from apps/angular/router-input/src/main.ts rename to apps/angular/44-view-transition/src/main.ts diff --git a/apps/angular/44-view-transition/src/styles.scss b/apps/angular/44-view-transition/src/styles.scss new file mode 100644 index 000000000..b5c61c956 --- /dev/null +++ b/apps/angular/44-view-transition/src/styles.scss @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/apps/angular/permissions/tailwind.config.js b/apps/angular/44-view-transition/tailwind.config.js similarity index 100% rename from apps/angular/permissions/tailwind.config.js rename to apps/angular/44-view-transition/tailwind.config.js diff --git a/apps/angular/signal-input/tsconfig.app.json b/apps/angular/44-view-transition/tsconfig.app.json similarity index 100% rename from apps/angular/signal-input/tsconfig.app.json rename to apps/angular/44-view-transition/tsconfig.app.json diff --git a/apps/angular/styling/tsconfig.editor.json b/apps/angular/44-view-transition/tsconfig.editor.json similarity index 100% rename from apps/angular/styling/tsconfig.editor.json rename to apps/angular/44-view-transition/tsconfig.editor.json diff --git a/apps/angular/signal-input/tsconfig.json b/apps/angular/44-view-transition/tsconfig.json similarity index 100% rename from apps/angular/signal-input/tsconfig.json rename to apps/angular/44-view-transition/tsconfig.json diff --git a/apps/angular/permissions/.eslintrc.json b/apps/angular/45-react-in-angular/.eslintrc.json similarity index 100% rename from apps/angular/permissions/.eslintrc.json rename to apps/angular/45-react-in-angular/.eslintrc.json diff --git a/apps/angular/45-react-in-angular/README.md b/apps/angular/45-react-in-angular/README.md new file mode 100644 index 000000000..0a8679ac4 --- /dev/null +++ b/apps/angular/45-react-in-angular/README.md @@ -0,0 +1,13 @@ +# React in angular + +> author: wandrille-guesdon + +### Run Application + +```bash +npx nx serve angular-react-in-angular +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/45-react-in-angular/). diff --git a/apps/angular/45-react-in-angular/jest.config.ts b/apps/angular/45-react-in-angular/jest.config.ts new file mode 100644 index 000000000..cda19a635 --- /dev/null +++ b/apps/angular/45-react-in-angular/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'angular-react-in-angular', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/45-react-in-angular', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/45-react-in-angular/project.json b/apps/angular/45-react-in-angular/project.json new file mode 100644 index 000000000..bce6fe70e --- /dev/null +++ b/apps/angular/45-react-in-angular/project.json @@ -0,0 +1,80 @@ +{ + "name": "angular-react-in-angular", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/45-react-in-angular/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/45-react-in-angular", + "index": "apps/angular/45-react-in-angular/src/index.html", + "browser": "apps/angular/45-react-in-angular/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/45-react-in-angular/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/45-react-in-angular/src/favicon.ico", + "apps/angular/45-react-in-angular/src/assets" + ], + "styles": ["apps/angular/45-react-in-angular/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-react-in-angular:build:production" + }, + "development": { + "buildTarget": "angular-react-in-angular:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-react-in-angular:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/45-react-in-angular/src/app/app.component.ts b/apps/angular/45-react-in-angular/src/app/app.component.ts new file mode 100644 index 000000000..87b9675cc --- /dev/null +++ b/apps/angular/45-react-in-angular/src/app/app.component.ts @@ -0,0 +1,61 @@ +import { Component, signal } from '@angular/core'; +import { PostComponent } from './react/post.component'; + +type Post = { title: string; description: string }; + +@Component({ + imports: [PostComponent], + selector: 'app-root', + template: ` +
+
+ @for (post of posts; track post.title) { +
+ +
+ } +
+
+ Selected Post: + + {{ selectedPost()?.title ?? '-' }} + +
+
+ `, + styles: [''], +}) +export class AppComponent { + readonly posts = [ + { + title: 'A Deep Dive into Angular', + description: + "Explore Angular's core features, its evolution, and best practices in development for creating dynamic, efficient web applications in our comprehensive guide.", + pictureLink: + 'https://images.unsplash.com/photo-1471958680802-1345a694ba6d', + }, + { + title: 'The Perfect Combination', + description: + 'Unveil the power of combining Angular & React in web development, maximizing efficiency and flexibility for building scalable, sophisticated applications.', + pictureLink: + 'https://images.unsplash.com/photo-1518717202715-9fa9d099f58a', + }, + { + title: 'Taking Angular to the Next Level', + description: + "Discover how integrating React with Angular elevates web development, blending Angular's structure with React's UI prowess for advanced applications.", + pictureLink: + 'https://images.unsplash.com/photo-1532103050105-860af53bc6aa', + }, + ]; + + readonly selectedPost = signal(null); + + selectPost(post: Post) { + this.selectedPost.set(post); + } +} diff --git a/apps/angular/signal-input/src/app/app.config.ts b/apps/angular/45-react-in-angular/src/app/app.config.ts similarity index 100% rename from apps/angular/signal-input/src/app/app.config.ts rename to apps/angular/45-react-in-angular/src/app/app.config.ts diff --git a/apps/angular/45-react-in-angular/src/app/react/ReactPost.tsx b/apps/angular/45-react-in-angular/src/app/react/ReactPost.tsx new file mode 100644 index 000000000..3f6b9e4cd --- /dev/null +++ b/apps/angular/45-react-in-angular/src/app/react/ReactPost.tsx @@ -0,0 +1,29 @@ +// import React from 'react'; + +export default function ReactPost(props: { + title?: string; + description?: string; + pictureLink?: string; + selected?: boolean; + handleClick: () => void; +}) { + return ( +
+
+ {props.title} +
+
{props.title}
+

{props.description}

+ +
+
+
+ ); +} diff --git a/apps/angular/45-react-in-angular/src/app/react/post.component.ts b/apps/angular/45-react-in-angular/src/app/react/post.component.ts new file mode 100644 index 000000000..2a35eaca6 --- /dev/null +++ b/apps/angular/45-react-in-angular/src/app/react/post.component.ts @@ -0,0 +1,17 @@ +import { Component, EventEmitter, input, Output } from '@angular/core'; + +type Post = { title: string; description: string; pictureLink: string }; + +@Component({ + standalone: true, + selector: 'app-post', + template: ` +
+ `, + styles: [''], +}) +export class PostComponent { + post = input(undefined); + isSelected = input(false); + @Output() selectPost = new EventEmitter(); +} diff --git a/apps/angular/pipe-intermediate/src/assets/.gitkeep b/apps/angular/45-react-in-angular/src/assets/.gitkeep similarity index 100% rename from apps/angular/pipe-intermediate/src/assets/.gitkeep rename to apps/angular/45-react-in-angular/src/assets/.gitkeep diff --git a/apps/angular/pipe-intermediate/src/favicon.ico b/apps/angular/45-react-in-angular/src/favicon.ico similarity index 100% rename from apps/angular/pipe-intermediate/src/favicon.ico rename to apps/angular/45-react-in-angular/src/favicon.ico diff --git a/apps/angular/45-react-in-angular/src/index.html b/apps/angular/45-react-in-angular/src/index.html new file mode 100644 index 000000000..9d9dd3923 --- /dev/null +++ b/apps/angular/45-react-in-angular/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-react-in-angular + + + + + + + + diff --git a/apps/angular/signal-input/src/main.ts b/apps/angular/45-react-in-angular/src/main.ts similarity index 100% rename from apps/angular/signal-input/src/main.ts rename to apps/angular/45-react-in-angular/src/main.ts diff --git a/apps/angular/module-to-standalone/src/styles.scss b/apps/angular/45-react-in-angular/src/styles.scss similarity index 100% rename from apps/angular/module-to-standalone/src/styles.scss rename to apps/angular/45-react-in-angular/src/styles.scss diff --git a/apps/angular/injection-token/src/test-setup.ts b/apps/angular/45-react-in-angular/src/test-setup.ts similarity index 100% rename from apps/angular/injection-token/src/test-setup.ts rename to apps/angular/45-react-in-angular/src/test-setup.ts diff --git a/apps/angular/projection/tailwind.config.js b/apps/angular/45-react-in-angular/tailwind.config.js similarity index 100% rename from apps/angular/projection/tailwind.config.js rename to apps/angular/45-react-in-angular/tailwind.config.js diff --git a/apps/angular/styling/tsconfig.app.json b/apps/angular/45-react-in-angular/tsconfig.app.json similarity index 100% rename from apps/angular/styling/tsconfig.app.json rename to apps/angular/45-react-in-angular/tsconfig.app.json diff --git a/apps/angular/interop-rxjs-signal/tsconfig.editor.json b/apps/angular/45-react-in-angular/tsconfig.editor.json similarity index 100% rename from apps/angular/interop-rxjs-signal/tsconfig.editor.json rename to apps/angular/45-react-in-angular/tsconfig.editor.json diff --git a/apps/forms/control-value-accessor/tsconfig.json b/apps/angular/45-react-in-angular/tsconfig.json similarity index 100% rename from apps/forms/control-value-accessor/tsconfig.json rename to apps/angular/45-react-in-angular/tsconfig.json diff --git a/apps/forms/control-value-accessor/tsconfig.spec.json b/apps/angular/45-react-in-angular/tsconfig.spec.json similarity index 100% rename from apps/forms/control-value-accessor/tsconfig.spec.json rename to apps/angular/45-react-in-angular/tsconfig.spec.json diff --git a/apps/angular/pipe-easy/.eslintrc.json b/apps/angular/46-simple-animations/.eslintrc.json similarity index 100% rename from apps/angular/pipe-easy/.eslintrc.json rename to apps/angular/46-simple-animations/.eslintrc.json diff --git a/apps/angular/46-simple-animations/README.md b/apps/angular/46-simple-animations/README.md new file mode 100644 index 000000000..87e6c7e7c --- /dev/null +++ b/apps/angular/46-simple-animations/README.md @@ -0,0 +1,13 @@ +# Simple Animations + +> author: sven-brodny + +### Run Application + +```bash +npx nx serve angular-simple-animations +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/46-simple-animations/). diff --git a/apps/angular/46-simple-animations/jest.config.ts b/apps/angular/46-simple-animations/jest.config.ts new file mode 100644 index 000000000..2ad20837f --- /dev/null +++ b/apps/angular/46-simple-animations/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'angular-simple-animations', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/46-simple-animations', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/46-simple-animations/project.json b/apps/angular/46-simple-animations/project.json new file mode 100644 index 000000000..1d00fd246 --- /dev/null +++ b/apps/angular/46-simple-animations/project.json @@ -0,0 +1,80 @@ +{ + "name": "angular-simple-animations", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/46-simple-animations/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/46-simple-animations", + "index": "apps/angular/46-simple-animations/src/index.html", + "browser": "apps/angular/46-simple-animations/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/46-simple-animations/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/46-simple-animations/src/favicon.ico", + "apps/angular/46-simple-animations/src/assets" + ], + "styles": ["apps/angular/46-simple-animations/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-simple-animations:build:production" + }, + "development": { + "buildTarget": "angular-simple-animations:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-simple-animations:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/46-simple-animations/src/app/app.component.ts b/apps/angular/46-simple-animations/src/app/app.component.ts new file mode 100644 index 000000000..ae63db419 --- /dev/null +++ b/apps/angular/46-simple-animations/src/app/app.component.ts @@ -0,0 +1,87 @@ +import { Component } from '@angular/core'; + +@Component({ + imports: [], + selector: 'app-root', + styles: ` + section { + @apply flex flex-1 flex-col gap-5; + } + + .list-item { + @apply flex flex-row border-b px-5 pb-2; + + span { + @apply flex-1; + } + } + `, + template: ` +
+
+
+

2008

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae + mollitia sequi accusantium, distinctio similique laudantium eveniet + quidem sit placeat possimus tempore dolorum inventore corporis atque + quae ad, nobis explicabo delectus. +

+
+ +
+

2010

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae + mollitia sequi accusantium, distinctio similique laudantium eveniet + quidem sit placeat possimus tempore dolorum inventore corporis atque + quae ad, nobis explicabo delectus. +

+
+ +
+

2012

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Vitae + mollitia sequi accusantium, distinctio similique laudantium eveniet + quidem sit placeat possimus tempore dolorum inventore corporis atque + quae ad, nobis explicabo delectus. +

+
+
+ +
+
+ Name: + Samuel +
+ +
+ Age: + 28 +
+ +
+ Birthdate: + 02.11.1995 +
+ +
+ City: + Berlin +
+ +
+ Language: + English +
+ +
+ Like Pizza: + Hell yeah +
+
+
+ `, +}) +export class AppComponent {} diff --git a/apps/angular/46-simple-animations/src/app/app.config.ts b/apps/angular/46-simple-animations/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/angular/46-simple-animations/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/angular/projection/src/assets/.gitkeep b/apps/angular/46-simple-animations/src/assets/.gitkeep similarity index 100% rename from apps/angular/projection/src/assets/.gitkeep rename to apps/angular/46-simple-animations/src/assets/.gitkeep diff --git a/apps/angular/projection/src/favicon.ico b/apps/angular/46-simple-animations/src/favicon.ico similarity index 100% rename from apps/angular/projection/src/favicon.ico rename to apps/angular/46-simple-animations/src/favicon.ico diff --git a/apps/angular/46-simple-animations/src/index.html b/apps/angular/46-simple-animations/src/index.html new file mode 100644 index 000000000..8fbebf9fb --- /dev/null +++ b/apps/angular/46-simple-animations/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-simple-animations + + + + + + + + diff --git a/apps/angular/view-transition/src/main.ts b/apps/angular/46-simple-animations/src/main.ts similarity index 100% rename from apps/angular/view-transition/src/main.ts rename to apps/angular/46-simple-animations/src/main.ts diff --git a/apps/angular/permissions/src/styles.scss b/apps/angular/46-simple-animations/src/styles.scss similarity index 100% rename from apps/angular/permissions/src/styles.scss rename to apps/angular/46-simple-animations/src/styles.scss diff --git a/apps/angular/interop-rxjs-signal/src/test-setup.ts b/apps/angular/46-simple-animations/src/test-setup.ts similarity index 100% rename from apps/angular/interop-rxjs-signal/src/test-setup.ts rename to apps/angular/46-simple-animations/src/test-setup.ts diff --git a/apps/angular/signal-input/tailwind.config.js b/apps/angular/46-simple-animations/tailwind.config.js similarity index 100% rename from apps/angular/signal-input/tailwind.config.js rename to apps/angular/46-simple-animations/tailwind.config.js diff --git a/apps/angular/view-transition/tsconfig.app.json b/apps/angular/46-simple-animations/tsconfig.app.json similarity index 100% rename from apps/angular/view-transition/tsconfig.app.json rename to apps/angular/46-simple-animations/tsconfig.app.json diff --git a/apps/forms/control-value-accessor/tsconfig.editor.json b/apps/angular/46-simple-animations/tsconfig.editor.json similarity index 100% rename from apps/forms/control-value-accessor/tsconfig.editor.json rename to apps/angular/46-simple-animations/tsconfig.editor.json diff --git a/apps/angular/46-simple-animations/tsconfig.json b/apps/angular/46-simple-animations/tsconfig.json new file mode 100644 index 000000000..25ca437b4 --- /dev/null +++ b/apps/angular/46-simple-animations/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + }, + { + "path": "./tsconfig.editor.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/performance/ngfor-optimize/tsconfig.spec.json b/apps/angular/46-simple-animations/tsconfig.spec.json similarity index 100% rename from apps/performance/ngfor-optimize/tsconfig.spec.json rename to apps/angular/46-simple-animations/tsconfig.spec.json diff --git a/apps/angular/pipe-hard/.eslintrc.json b/apps/angular/5-crud-application/.eslintrc.json similarity index 100% rename from apps/angular/pipe-hard/.eslintrc.json rename to apps/angular/5-crud-application/.eslintrc.json diff --git a/apps/angular/5-crud-application/README.md b/apps/angular/5-crud-application/README.md new file mode 100644 index 000000000..8992014e3 --- /dev/null +++ b/apps/angular/5-crud-application/README.md @@ -0,0 +1,13 @@ +# Crud application + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-crud-application +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/5-crud/). diff --git a/apps/angular/5-crud-application/jest.config.ts b/apps/angular/5-crud-application/jest.config.ts new file mode 100644 index 000000000..f290dd70a --- /dev/null +++ b/apps/angular/5-crud-application/jest.config.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +export default { + displayName: 'angular-crud-application', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + globals: {}, + coverageDirectory: '../../../coverage/apps/angular/5-crud-application', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/5-crud-application/project.json b/apps/angular/5-crud-application/project.json new file mode 100644 index 000000000..cdad9374a --- /dev/null +++ b/apps/angular/5-crud-application/project.json @@ -0,0 +1,87 @@ +{ + "name": "angular-crud-application", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/5-crud-application/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/5-crud-application", + "index": "apps/angular/5-crud-application/src/index.html", + "main": "apps/angular/5-crud-application/src/main.ts", + "polyfills": "apps/angular/5-crud-application/src/polyfills.ts", + "tsConfig": "apps/angular/5-crud-application/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/5-crud-application/src/favicon.ico", + "apps/angular/5-crud-application/src/assets" + ], + "styles": [ + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", + "apps/angular/5-crud-application/src/styles.scss" + ], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-crud-application:build:production" + }, + "development": { + "buildTarget": "angular-crud-application:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-crud-application:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/5-crud-application/src/app/app.component.ts b/apps/angular/5-crud-application/src/app/app.component.ts new file mode 100644 index 000000000..9152ff5e4 --- /dev/null +++ b/apps/angular/5-crud-application/src/app/app.component.ts @@ -0,0 +1,50 @@ +import { CommonModule } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { randText } from '@ngneat/falso'; + +@Component({ + imports: [CommonModule], + selector: 'app-root', + template: ` +
+ {{ todo.title }} + +
+ `, + styles: [], +}) +export class AppComponent implements OnInit { + todos!: any[]; + + constructor(private http: HttpClient) {} + + ngOnInit(): void { + this.http + .get('https://jsonplaceholder.typicode.com/todos') + .subscribe((todos) => { + this.todos = todos; + }); + } + + update(todo: any) { + this.http + .put( + `https://jsonplaceholder.typicode.com/todos/${todo.id}`, + JSON.stringify({ + todo: todo.id, + title: randText(), + body: todo.body, + userId: todo.userId, + }), + { + headers: { + 'Content-type': 'application/json; charset=UTF-8', + }, + }, + ) + .subscribe((todoUpdated: any) => { + this.todos[todoUpdated.id - 1] = todoUpdated; + }); + } +} diff --git a/apps/angular/5-crud-application/src/app/app.config.ts b/apps/angular/5-crud-application/src/app/app.config.ts new file mode 100644 index 000000000..1c0c9422f --- /dev/null +++ b/apps/angular/5-crud-application/src/app/app.config.ts @@ -0,0 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [provideHttpClient()], +}; diff --git a/apps/angular/router-input/src/assets/.gitkeep b/apps/angular/5-crud-application/src/assets/.gitkeep similarity index 100% rename from apps/angular/router-input/src/assets/.gitkeep rename to apps/angular/5-crud-application/src/assets/.gitkeep diff --git a/apps/angular/router-input/src/favicon.ico b/apps/angular/5-crud-application/src/favicon.ico similarity index 100% rename from apps/angular/router-input/src/favicon.ico rename to apps/angular/5-crud-application/src/favicon.ico diff --git a/apps/angular/5-crud-application/src/index.html b/apps/angular/5-crud-application/src/index.html new file mode 100644 index 000000000..b9ec0b609 --- /dev/null +++ b/apps/angular/5-crud-application/src/index.html @@ -0,0 +1,20 @@ + + + + + angular-crud-application + + + + + + + + + + + diff --git a/apps/angular/crud/src/main.ts b/apps/angular/5-crud-application/src/main.ts similarity index 100% rename from apps/angular/crud/src/main.ts rename to apps/angular/5-crud-application/src/main.ts diff --git a/apps/angular/pipe-easy/src/polyfills.ts b/apps/angular/5-crud-application/src/polyfills.ts similarity index 100% rename from apps/angular/pipe-easy/src/polyfills.ts rename to apps/angular/5-crud-application/src/polyfills.ts diff --git a/apps/angular/crud/src/styles.scss b/apps/angular/5-crud-application/src/styles.scss similarity index 100% rename from apps/angular/crud/src/styles.scss rename to apps/angular/5-crud-application/src/styles.scss diff --git a/apps/forms/control-value-accessor/src/test-setup.ts b/apps/angular/5-crud-application/src/test-setup.ts similarity index 100% rename from apps/forms/control-value-accessor/src/test-setup.ts rename to apps/angular/5-crud-application/src/test-setup.ts diff --git a/apps/angular/pipe-easy/tsconfig.app.json b/apps/angular/5-crud-application/tsconfig.app.json similarity index 100% rename from apps/angular/pipe-easy/tsconfig.app.json rename to apps/angular/5-crud-application/tsconfig.app.json diff --git a/apps/angular/permissions/tsconfig.editor.json b/apps/angular/5-crud-application/tsconfig.editor.json similarity index 100% rename from apps/angular/permissions/tsconfig.editor.json rename to apps/angular/5-crud-application/tsconfig.editor.json diff --git a/apps/angular/projection/tsconfig.json b/apps/angular/5-crud-application/tsconfig.json similarity index 100% rename from apps/angular/projection/tsconfig.json rename to apps/angular/5-crud-application/tsconfig.json diff --git a/apps/angular/crud/tsconfig.spec.json b/apps/angular/5-crud-application/tsconfig.spec.json similarity index 100% rename from apps/angular/crud/tsconfig.spec.json rename to apps/angular/5-crud-application/tsconfig.spec.json diff --git a/apps/angular/pipe-intermediate/.eslintrc.json b/apps/angular/52-lazy-load-component/.eslintrc.json similarity index 100% rename from apps/angular/pipe-intermediate/.eslintrc.json rename to apps/angular/52-lazy-load-component/.eslintrc.json diff --git a/apps/angular/52-lazy-load-component/README.md b/apps/angular/52-lazy-load-component/README.md new file mode 100644 index 000000000..7da25f89b --- /dev/null +++ b/apps/angular/52-lazy-load-component/README.md @@ -0,0 +1,13 @@ +# lazy-load-component + +> author: lance-finney + +### Run Application + +```bash +npx nx serve angular-lazy-load-component +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/52-lazy-load-component/). diff --git a/apps/angular/52-lazy-load-component/jest.config.ts b/apps/angular/52-lazy-load-component/jest.config.ts new file mode 100644 index 000000000..a0fd1100f --- /dev/null +++ b/apps/angular/52-lazy-load-component/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'angular-lazy-load-component', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/52-lazy-load-component', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/52-lazy-load-component/project.json b/apps/angular/52-lazy-load-component/project.json new file mode 100644 index 000000000..d3b28088a --- /dev/null +++ b/apps/angular/52-lazy-load-component/project.json @@ -0,0 +1,80 @@ +{ + "name": "angular-lazy-load-component", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/52-lazy-load-component/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/52-lazy-load-component", + "index": "apps/angular/52-lazy-load-component/src/index.html", + "browser": "apps/angular/52-lazy-load-component/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/52-lazy-load-component/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/52-lazy-load-component/src/favicon.ico", + "apps/angular/52-lazy-load-component/src/assets" + ], + "styles": ["apps/angular/52-lazy-load-component/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-lazy-load-component:build:production" + }, + "development": { + "buildTarget": "angular-lazy-load-component:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-lazy-load-component:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/52-lazy-load-component/src/app/app.component.ts b/apps/angular/52-lazy-load-component/src/app/app.component.ts new file mode 100644 index 000000000..6d8c03d29 --- /dev/null +++ b/apps/angular/52-lazy-load-component/src/app/app.component.ts @@ -0,0 +1,23 @@ +import { Component, signal } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: ` +
+ @if (topLoaded()) { + + } @else { + + + } +
+ `, + standalone: false, +}) +export class AppComponent { + topLoaded = signal(false); +} diff --git a/apps/angular/52-lazy-load-component/src/app/app.module.ts b/apps/angular/52-lazy-load-component/src/app/app.module.ts new file mode 100644 index 000000000..b5d430e67 --- /dev/null +++ b/apps/angular/52-lazy-load-component/src/app/app.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { AppComponent } from './app.component'; +import { PlaceholderComponent } from './placeholder.component'; +import { TopComponent } from './top.component'; + +@NgModule({ + declarations: [AppComponent, PlaceholderComponent, TopComponent], + imports: [BrowserModule], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/apps/angular/52-lazy-load-component/src/app/placeholder.component.ts b/apps/angular/52-lazy-load-component/src/app/placeholder.component.ts new file mode 100644 index 000000000..cbb2b5fa6 --- /dev/null +++ b/apps/angular/52-lazy-load-component/src/app/placeholder.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-placeholder', + template: ` + I'm a placeholder component. + `, + styles: ` + :host { + display: grid; + padding: 20px; + background-color: #f0f0f0; + height: 50%; + } + `, + standalone: false, +}) +export class PlaceholderComponent {} diff --git a/apps/angular/52-lazy-load-component/src/app/top.component.ts b/apps/angular/52-lazy-load-component/src/app/top.component.ts new file mode 100644 index 000000000..e1ca9012c --- /dev/null +++ b/apps/angular/52-lazy-load-component/src/app/top.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-top', + template: ` + I am a very heavy, expensive component that should be lazy loaded. + `, + styles: ` + :host { + display: grid; + padding: 20px; + background-color: #f0f0f0; + height: 50%; + } + `, + standalone: false, +}) +export class TopComponent {} diff --git a/apps/angular/signal-input/src/assets/.gitkeep b/apps/angular/52-lazy-load-component/src/assets/.gitkeep similarity index 100% rename from apps/angular/signal-input/src/assets/.gitkeep rename to apps/angular/52-lazy-load-component/src/assets/.gitkeep diff --git a/apps/angular/signal-input/src/favicon.ico b/apps/angular/52-lazy-load-component/src/favicon.ico similarity index 100% rename from apps/angular/signal-input/src/favicon.ico rename to apps/angular/52-lazy-load-component/src/favicon.ico diff --git a/apps/angular/52-lazy-load-component/src/index.html b/apps/angular/52-lazy-load-component/src/index.html new file mode 100644 index 000000000..242ec3e3f --- /dev/null +++ b/apps/angular/52-lazy-load-component/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-lazy-load-component + + + + + + + + diff --git a/apps/angular/52-lazy-load-component/src/main.ts b/apps/angular/52-lazy-load-component/src/main.ts new file mode 100644 index 000000000..16de2365d --- /dev/null +++ b/apps/angular/52-lazy-load-component/src/main.ts @@ -0,0 +1,6 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)); diff --git a/apps/angular/signal-input/src/styles.scss b/apps/angular/52-lazy-load-component/src/styles.scss similarity index 100% rename from apps/angular/signal-input/src/styles.scss rename to apps/angular/52-lazy-load-component/src/styles.scss diff --git a/apps/performance/ngfor-optimize/src/test-setup.ts b/apps/angular/52-lazy-load-component/src/test-setup.ts similarity index 100% rename from apps/performance/ngfor-optimize/src/test-setup.ts rename to apps/angular/52-lazy-load-component/src/test-setup.ts diff --git a/apps/angular/view-transition/tailwind.config.js b/apps/angular/52-lazy-load-component/tailwind.config.js similarity index 100% rename from apps/angular/view-transition/tailwind.config.js rename to apps/angular/52-lazy-load-component/tailwind.config.js diff --git a/apps/forms/control-value-accessor/tsconfig.app.json b/apps/angular/52-lazy-load-component/tsconfig.app.json similarity index 100% rename from apps/forms/control-value-accessor/tsconfig.app.json rename to apps/angular/52-lazy-load-component/tsconfig.app.json diff --git a/apps/angular/52-lazy-load-component/tsconfig.editor.json b/apps/angular/52-lazy-load-component/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/angular/52-lazy-load-component/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/angular/52-lazy-load-component/tsconfig.json b/apps/angular/52-lazy-load-component/tsconfig.json new file mode 100644 index 000000000..4383e7eb8 --- /dev/null +++ b/apps/angular/52-lazy-load-component/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/angular/52-lazy-load-component/tsconfig.spec.json b/apps/angular/52-lazy-load-component/tsconfig.spec.json new file mode 100644 index 000000000..1a4817a7d --- /dev/null +++ b/apps/angular/52-lazy-load-component/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node", "@testing-library/jest-dom"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/angular/signal-input/.eslintrc.json b/apps/angular/55-back-button-navigation/.eslintrc.json similarity index 100% rename from apps/angular/signal-input/.eslintrc.json rename to apps/angular/55-back-button-navigation/.eslintrc.json diff --git a/apps/angular/55-back-button-navigation/README.md b/apps/angular/55-back-button-navigation/README.md new file mode 100644 index 000000000..2534d270c --- /dev/null +++ b/apps/angular/55-back-button-navigation/README.md @@ -0,0 +1,13 @@ +# Back-Button-Navigation + +> author: ioannis-tsironis + +### Run Application + +```bash +npx nx serve angular-back-button-navigation +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/55-back-button-navigation/). diff --git a/apps/angular/55-back-button-navigation/jest.config.ts b/apps/angular/55-back-button-navigation/jest.config.ts new file mode 100644 index 000000000..845a03a01 --- /dev/null +++ b/apps/angular/55-back-button-navigation/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'angular-back-button-navigation', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/angular/55-back-button-navigation', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/angular/55-back-button-navigation/project.json b/apps/angular/55-back-button-navigation/project.json new file mode 100644 index 000000000..f53d65e27 --- /dev/null +++ b/apps/angular/55-back-button-navigation/project.json @@ -0,0 +1,85 @@ +{ + "name": "angular-back-button-navigation", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/55-back-button-navigation/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/55-back-button-navigation", + "index": "apps/angular/55-back-button-navigation/src/index.html", + "browser": "apps/angular/55-back-button-navigation/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/55-back-button-navigation/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "apps/angular/55-back-button-navigation/public" + } + ], + "styles": [ + "apps/angular/55-back-button-navigation/src/styles.scss", + "node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-back-button-navigation:build:production" + }, + "development": { + "buildTarget": "angular-back-button-navigation:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-back-button-navigation:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/angular/55-back-button-navigation/src/app/app.component.html b/apps/angular/55-back-button-navigation/src/app/app.component.html new file mode 100644 index 000000000..0680b43f9 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/app.component.html @@ -0,0 +1 @@ + diff --git a/apps/angular/55-back-button-navigation/src/app/app.component.ts b/apps/angular/55-back-button-navigation/src/app/app.component.ts new file mode 100644 index 000000000..baffdae25 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/app.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet, RouterLink], + selector: 'app-root', + templateUrl: './app.component.html', +}) +export class AppComponent {} diff --git a/apps/angular/55-back-button-navigation/src/app/app.config.ts b/apps/angular/55-back-button-navigation/src/app/app.config.ts new file mode 100644 index 000000000..440cdf2c3 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/app.config.ts @@ -0,0 +1,10 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { APP_ROUTES } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(APP_ROUTES), + ], +}; diff --git a/apps/angular/55-back-button-navigation/src/app/app.routes.ts b/apps/angular/55-back-button-navigation/src/app/app.routes.ts new file mode 100644 index 000000000..7deecd57a --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/app.routes.ts @@ -0,0 +1,24 @@ +import { Routes } from '@angular/router'; +import { HomeComponent } from './home/home.component'; +import { SensitiveActionComponent } from './sensitive-action/sensitive-action.component'; +import { SimpleActionComponent } from './simple-action/simple-action.component'; + +export const APP_ROUTES: Routes = [ + { + path: '', + pathMatch: 'full', + redirectTo: 'home', + }, + { + path: 'home', + component: HomeComponent, + }, + { + path: 'simple-action', + component: SimpleActionComponent, + }, + { + path: 'sensitive-action', + component: SensitiveActionComponent, + }, +]; diff --git a/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.html b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.html new file mode 100644 index 000000000..ff00ea965 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.html @@ -0,0 +1,6 @@ +

Delete file

+Would you like to delete cat.jpeg? + + + + diff --git a/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.ts b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.ts new file mode 100644 index 000000000..9a9dd0fef --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/dialog/dialog.component.ts @@ -0,0 +1,25 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle, +} from '@angular/material/dialog'; + +@Component({ + selector: 'app-dialog-dialog', + templateUrl: './dialog.component.html', + imports: [ + MatButtonModule, + MatDialogActions, + MatDialogClose, + MatDialogTitle, + MatDialogContent, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DialogComponent { + readonly dialogRef = inject(MatDialogRef); +} diff --git a/apps/angular/55-back-button-navigation/src/app/home/home.component.html b/apps/angular/55-back-button-navigation/src/app/home/home.component.html new file mode 100644 index 000000000..cce9e6d4f --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/home/home.component.html @@ -0,0 +1,7 @@ +
+ Go to simple dialog action page + + + + Go to sensitive dialog action page + diff --git a/apps/angular/55-back-button-navigation/src/app/home/home.component.ts b/apps/angular/55-back-button-navigation/src/app/home/home.component.ts new file mode 100644 index 000000000..18c4147b1 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/home/home.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { RouterLink } from '@angular/router'; + +@Component({ + imports: [MatButtonModule, RouterLink], + selector: 'app-home', + templateUrl: './home.component.html', +}) +export class HomeComponent {} diff --git a/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.html b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.html new file mode 100644 index 000000000..bcb7382e9 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.html @@ -0,0 +1,3 @@ + diff --git a/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts new file mode 100644 index 000000000..a97282c33 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/sensitive-action/sensitive-action.component.ts @@ -0,0 +1,19 @@ +import { Component, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; +import { DialogComponent } from '../dialog/dialog.component'; + +@Component({ + imports: [MatButtonModule], + selector: 'app-sensitive-action', + templateUrl: './sensitive-action.component.html', +}) +export class SensitiveActionComponent { + readonly #dialog = inject(MatDialog); + + openDialog(): void { + this.#dialog.open(DialogComponent, { + width: '250px', + }); + } +} diff --git a/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.html b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.html new file mode 100644 index 000000000..95f63e65e --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.html @@ -0,0 +1 @@ + diff --git a/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.ts b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.ts new file mode 100644 index 000000000..fe97e7368 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/app/simple-action/simple-action.component.ts @@ -0,0 +1,19 @@ +import { Component, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; +import { DialogComponent } from '../dialog/dialog.component'; + +@Component({ + imports: [MatButtonModule], + selector: 'app-simple-action', + templateUrl: './simple-action.component.html', +}) +export class SimpleActionComponent { + readonly #dialog = inject(MatDialog); + + openDialog(): void { + this.#dialog.open(DialogComponent, { + width: '250px', + }); + } +} diff --git a/apps/angular/55-back-button-navigation/src/index.html b/apps/angular/55-back-button-navigation/src/index.html new file mode 100644 index 000000000..4e657d614 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-back-button-navigation + + + + + + + + diff --git a/apps/nx/static-dynamic-import/src/main.ts b/apps/angular/55-back-button-navigation/src/main.ts similarity index 100% rename from apps/nx/static-dynamic-import/src/main.ts rename to apps/angular/55-back-button-navigation/src/main.ts diff --git a/apps/angular/55-back-button-navigation/src/styles.scss b/apps/angular/55-back-button-navigation/src/styles.scss new file mode 100644 index 000000000..acd290007 --- /dev/null +++ b/apps/angular/55-back-button-navigation/src/styles.scss @@ -0,0 +1,29 @@ +@use '@angular/material' as mat; + +/* You can add global styles to this file, and also import other style files */ + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@include mat.elevation-classes(); +@include mat.app-background(); + +$theme-primary: mat.m2-define-palette(mat.$m2-indigo-palette); +$theme-accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400); + +$theme-warn: mat.m2-define-palette(mat.$m2-red-palette); + +$theme: mat.m2-define-light-theme( + ( + color: ( + primary: $theme-primary, + accent: $theme-accent, + warn: $theme-warn, + ), + typography: mat.m2-define-typography-config(), + ) +); + +@include mat.dialog-theme($theme); +@include mat.button-theme($theme); diff --git a/apps/rxjs/catch-error/src/test-setup.ts b/apps/angular/55-back-button-navigation/src/test-setup.ts similarity index 100% rename from apps/rxjs/catch-error/src/test-setup.ts rename to apps/angular/55-back-button-navigation/src/test-setup.ts diff --git a/apps/forms/control-value-accessor/tailwind.config.js b/apps/angular/55-back-button-navigation/tailwind.config.js similarity index 100% rename from apps/forms/control-value-accessor/tailwind.config.js rename to apps/angular/55-back-button-navigation/tailwind.config.js diff --git a/apps/nx/static-dynamic-import/tsconfig.app.json b/apps/angular/55-back-button-navigation/tsconfig.app.json similarity index 100% rename from apps/nx/static-dynamic-import/tsconfig.app.json rename to apps/angular/55-back-button-navigation/tsconfig.app.json diff --git a/apps/angular/55-back-button-navigation/tsconfig.editor.json b/apps/angular/55-back-button-navigation/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/angular/55-back-button-navigation/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/angular/55-back-button-navigation/tsconfig.json b/apps/angular/55-back-button-navigation/tsconfig.json new file mode 100644 index 000000000..4383e7eb8 --- /dev/null +++ b/apps/angular/55-back-button-navigation/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/angular/55-back-button-navigation/tsconfig.spec.json b/apps/angular/55-back-button-navigation/tsconfig.spec.json new file mode 100644 index 000000000..1a4817a7d --- /dev/null +++ b/apps/angular/55-back-button-navigation/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node", "@testing-library/jest-dom"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/forms/control-value-accessor/.eslintrc.json b/apps/angular/57-content-projection-default/.eslintrc.json similarity index 100% rename from apps/forms/control-value-accessor/.eslintrc.json rename to apps/angular/57-content-projection-default/.eslintrc.json diff --git a/apps/angular/57-content-projection-default/README.md b/apps/angular/57-content-projection-default/README.md new file mode 100644 index 000000000..fc4579558 --- /dev/null +++ b/apps/angular/57-content-projection-default/README.md @@ -0,0 +1,13 @@ +# Content Projection Default + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-content-projection-default +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/57-content-projection-default/). diff --git a/apps/angular/57-content-projection-default/project.json b/apps/angular/57-content-projection-default/project.json new file mode 100644 index 000000000..a57738bff --- /dev/null +++ b/apps/angular/57-content-projection-default/project.json @@ -0,0 +1,81 @@ +{ + "name": "angular-content-projection-default", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/57-content-projection-default/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/57-content-projection-default", + "index": "apps/angular/57-content-projection-default/src/index.html", + "browser": "apps/angular/57-content-projection-default/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/57-content-projection-default/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "apps/angular/57-content-projection-default/public" + } + ], + "styles": [ + "apps/angular/57-content-projection-default/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kb", + "maximumError": "8kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-content-projection-default:build:production" + }, + "development": { + "buildTarget": "angular-content-projection-default:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-content-projection-default:build" + } + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "angular-content-projection-default:build", + "staticFilePath": "dist/apps/angular/57-content-projection-default/browser", + "spa": true + } + } + } +} diff --git a/apps/angular/styling/src/favicon.ico b/apps/angular/57-content-projection-default/public/favicon.ico similarity index 100% rename from apps/angular/styling/src/favicon.ico rename to apps/angular/57-content-projection-default/public/favicon.ico diff --git a/apps/angular/57-content-projection-default/src/app/app.component.ts b/apps/angular/57-content-projection-default/src/app/app.component.ts new file mode 100644 index 000000000..b3e370a34 --- /dev/null +++ b/apps/angular/57-content-projection-default/src/app/app.component.ts @@ -0,0 +1,16 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { CardComponent } from './card.component'; + +@Component({ + imports: [CardComponent], + selector: 'app-root', + template: ` + + + `, + host: { + class: 'p-4 block flex flex-col gap-1', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent {} diff --git a/apps/angular/57-content-projection-default/src/app/app.config.ts b/apps/angular/57-content-projection-default/src/app/app.config.ts new file mode 100644 index 000000000..034603cfd --- /dev/null +++ b/apps/angular/57-content-projection-default/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [provideZoneChangeDetection({ eventCoalescing: true })], +}; diff --git a/apps/angular/57-content-projection-default/src/app/card.component.ts b/apps/angular/57-content-projection-default/src/app/card.component.ts new file mode 100644 index 000000000..851a6619d --- /dev/null +++ b/apps/angular/57-content-projection-default/src/app/card.component.ts @@ -0,0 +1,22 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +@Component({ + selector: 'app-card', + imports: [], + template: ` +
{{ title() }}
+ @if (message()) { +
{{ message() }}
+ } @else { +
Aucun message
+ } + `, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'p-4 border border-grey rounded-sm flex flex-col w-[200px]', + }, +}) +export class CardComponent { + title = input.required(); + message = input(undefined); +} diff --git a/apps/angular/57-content-projection-default/src/index.html b/apps/angular/57-content-projection-default/src/index.html new file mode 100644 index 000000000..8b3015d4b --- /dev/null +++ b/apps/angular/57-content-projection-default/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-content-projection-default + + + + + + + + diff --git a/apps/performance/default-onpush/src/main.ts b/apps/angular/57-content-projection-default/src/main.ts similarity index 100% rename from apps/performance/default-onpush/src/main.ts rename to apps/angular/57-content-projection-default/src/main.ts diff --git a/apps/forms/control-value-accessor/src/styles.scss b/apps/angular/57-content-projection-default/src/styles.scss similarity index 100% rename from apps/forms/control-value-accessor/src/styles.scss rename to apps/angular/57-content-projection-default/src/styles.scss diff --git a/apps/nx/static-dynamic-import/tailwind.config.js b/apps/angular/57-content-projection-default/tailwind.config.js similarity index 100% rename from apps/nx/static-dynamic-import/tailwind.config.js rename to apps/angular/57-content-projection-default/tailwind.config.js diff --git a/apps/performance/christmas-web-worker/tsconfig.app.json b/apps/angular/57-content-projection-default/tsconfig.app.json similarity index 100% rename from apps/performance/christmas-web-worker/tsconfig.app.json rename to apps/angular/57-content-projection-default/tsconfig.app.json diff --git a/apps/angular/57-content-projection-default/tsconfig.editor.json b/apps/angular/57-content-projection-default/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/angular/57-content-projection-default/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/angular/57-content-projection-default/tsconfig.json b/apps/angular/57-content-projection-default/tsconfig.json new file mode 100644 index 000000000..1b86db04e --- /dev/null +++ b/apps/angular/57-content-projection-default/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es2022", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/ngrx/effect-selector/.eslintrc.json b/apps/angular/58-content-projection-condition/.eslintrc.json similarity index 100% rename from apps/ngrx/effect-selector/.eslintrc.json rename to apps/angular/58-content-projection-condition/.eslintrc.json diff --git a/apps/angular/58-content-projection-condition/README.md b/apps/angular/58-content-projection-condition/README.md new file mode 100644 index 000000000..755bd8854 --- /dev/null +++ b/apps/angular/58-content-projection-condition/README.md @@ -0,0 +1,13 @@ +# Content Projection Condition + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-content-projection-condition +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/58-content-projection-condition/). diff --git a/apps/angular/58-content-projection-condition/project.json b/apps/angular/58-content-projection-condition/project.json new file mode 100644 index 000000000..42869e68b --- /dev/null +++ b/apps/angular/58-content-projection-condition/project.json @@ -0,0 +1,84 @@ +{ + "name": "angular-content-projection-condition", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/58-content-projection-condition/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/58-content-projection-condition", + "index": "apps/angular/58-content-projection-condition/src/index.html", + "browser": "apps/angular/58-content-projection-condition/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/58-content-projection-condition/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "apps/angular/58-content-projection-condition/public" + } + ], + "styles": [ + "apps/angular/58-content-projection-condition/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kb", + "maximumError": "8kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-content-projection-condition:build:production" + }, + "development": { + "buildTarget": "angular-content-projection-condition:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-content-projection-condition:build" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "angular-content-projection-condition:build", + "staticFilePath": "dist/apps/angular/58-content-projection-condition/browser", + "spa": true + } + } + } +} diff --git a/apps/angular/view-transition/src/favicon.ico b/apps/angular/58-content-projection-condition/public/favicon.ico similarity index 100% rename from apps/angular/view-transition/src/favicon.ico rename to apps/angular/58-content-projection-condition/public/favicon.ico diff --git a/apps/angular/58-content-projection-condition/src/app/app.component.ts b/apps/angular/58-content-projection-condition/src/app/app.component.ts new file mode 100644 index 000000000..afad56f22 --- /dev/null +++ b/apps/angular/58-content-projection-condition/src/app/app.component.ts @@ -0,0 +1,22 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { CardComponent } from './card.component'; + +@Component({ + imports: [CardComponent], + selector: 'app-root', + template: ` + +
Card 1
+
Message 1
+
+ +
Card 2
+
Message 2
+
+ `, + host: { + class: 'p-4 block flex flex-col gap-1', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent {} diff --git a/apps/angular/58-content-projection-condition/src/app/app.config.ts b/apps/angular/58-content-projection-condition/src/app/app.config.ts new file mode 100644 index 000000000..034603cfd --- /dev/null +++ b/apps/angular/58-content-projection-condition/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [provideZoneChangeDetection({ eventCoalescing: true })], +}; diff --git a/apps/angular/58-content-projection-condition/src/app/card.component.ts b/apps/angular/58-content-projection-condition/src/app/card.component.ts new file mode 100644 index 000000000..46925977c --- /dev/null +++ b/apps/angular/58-content-projection-condition/src/app/card.component.ts @@ -0,0 +1,25 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +@Component({ + selector: 'app-card', + template: ` + @if (small()) { + + + } @else { +
+
+ +
+ +
+ } + `, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'p-4 border border-grey rounded-sm flex flex-col w-[200px]', + }, +}) +export class CardComponent { + small = input(false); +} diff --git a/apps/angular/58-content-projection-condition/src/index.html b/apps/angular/58-content-projection-condition/src/index.html new file mode 100644 index 000000000..f1768ec71 --- /dev/null +++ b/apps/angular/58-content-projection-condition/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-content-projection-condition + + + + + + + + diff --git a/apps/performance/memoized/src/main.ts b/apps/angular/58-content-projection-condition/src/main.ts similarity index 100% rename from apps/performance/memoized/src/main.ts rename to apps/angular/58-content-projection-condition/src/main.ts diff --git a/apps/nx/static-dynamic-import/src/styles.scss b/apps/angular/58-content-projection-condition/src/styles.scss similarity index 100% rename from apps/nx/static-dynamic-import/src/styles.scss rename to apps/angular/58-content-projection-condition/src/styles.scss diff --git a/apps/performance/christmas-web-worker/tailwind.config.js b/apps/angular/58-content-projection-condition/tailwind.config.js similarity index 100% rename from apps/performance/christmas-web-worker/tailwind.config.js rename to apps/angular/58-content-projection-condition/tailwind.config.js diff --git a/apps/performance/default-onpush/tsconfig.app.json b/apps/angular/58-content-projection-condition/tsconfig.app.json similarity index 100% rename from apps/performance/default-onpush/tsconfig.app.json rename to apps/angular/58-content-projection-condition/tsconfig.app.json diff --git a/apps/angular/58-content-projection-condition/tsconfig.editor.json b/apps/angular/58-content-projection-condition/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/angular/58-content-projection-condition/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/angular/58-content-projection-condition/tsconfig.json b/apps/angular/58-content-projection-condition/tsconfig.json new file mode 100644 index 000000000..1b86db04e --- /dev/null +++ b/apps/angular/58-content-projection-condition/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es2022", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/angular/59-content-projection-defer/.eslintrc.json b/apps/angular/59-content-projection-defer/.eslintrc.json new file mode 100644 index 000000000..995177b5b --- /dev/null +++ b/apps/angular/59-content-projection-defer/.eslintrc.json @@ -0,0 +1,37 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/component-class-suffix": "off", + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/angular/59-content-projection-defer/README.md b/apps/angular/59-content-projection-defer/README.md new file mode 100644 index 000000000..f726842d1 --- /dev/null +++ b/apps/angular/59-content-projection-defer/README.md @@ -0,0 +1,13 @@ +# content-projection-defer + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-content-projection-defer +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/59-content-projection-defer/). diff --git a/apps/angular/59-content-projection-defer/project.json b/apps/angular/59-content-projection-defer/project.json new file mode 100644 index 000000000..5572ab573 --- /dev/null +++ b/apps/angular/59-content-projection-defer/project.json @@ -0,0 +1,82 @@ +{ + "name": "angular-content-projection-defer", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/angular/59-content-projection-defer/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/59-content-projection-defer", + "index": "apps/angular/59-content-projection-defer/src/index.html", + "browser": "apps/angular/59-content-projection-defer/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular/59-content-projection-defer/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "apps/angular/59-content-projection-defer/public" + } + ], + "styles": ["apps/angular/59-content-projection-defer/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kb", + "maximumError": "8kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-content-projection-defer:build:production" + }, + "development": { + "buildTarget": "angular-content-projection-defer:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-content-projection-defer:build" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "angular-content-projection-defer:build", + "staticFilePath": "dist/apps/angular/59-content-projection-defer/browser", + "spa": true + } + } + } +} diff --git a/apps/forms/control-value-accessor/src/favicon.ico b/apps/angular/59-content-projection-defer/public/favicon.ico similarity index 100% rename from apps/forms/control-value-accessor/src/favicon.ico rename to apps/angular/59-content-projection-defer/public/favicon.ico diff --git a/apps/angular/59-content-projection-defer/src/app/app.component.ts b/apps/angular/59-content-projection-defer/src/app/app.component.ts new file mode 100644 index 000000000..ae40bc880 --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/app/app.component.ts @@ -0,0 +1,23 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink, RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet, RouterLink], + selector: 'app-root', + template: ` +
+ + +
+ + `, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'flex flex-col gap-2 ', + }, +}) +export class AppComponent {} diff --git a/apps/angular/59-content-projection-defer/src/app/app.config.ts b/apps/angular/59-content-projection-defer/src/app/app.config.ts new file mode 100644 index 000000000..faf4d099a --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/app/app.config.ts @@ -0,0 +1,12 @@ +import { provideHttpClient } from '@angular/common/http'; +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { appRoutes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(appRoutes), + provideHttpClient(), + ], +}; diff --git a/apps/angular/59-content-projection-defer/src/app/app.routes.ts b/apps/angular/59-content-projection-defer/src/app/app.routes.ts new file mode 100644 index 000000000..3ca1b67cc --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/app/app.routes.ts @@ -0,0 +1,13 @@ +import { Route } from '@angular/router'; + +export const appRoutes: Route[] = [ + { + path: 'page-1', + loadComponent: () => import('./page-1').then((m) => m.Page1), + }, + { + path: 'page-2', + loadComponent: () => import('./page-2').then((m) => m.Page2), + }, + { path: '**', redirectTo: 'page-1' }, +]; diff --git a/apps/angular/59-content-projection-defer/src/app/expandable-card.ts b/apps/angular/59-content-projection-defer/src/app/expandable-card.ts new file mode 100644 index 000000000..8f446ed80 --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/app/expandable-card.ts @@ -0,0 +1,54 @@ +import { ChangeDetectionStrategy, Component, signal } from '@angular/core'; + +@Component({ + selector: 'app-expandable-card', + template: ` + + +
+ +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + class: 'flex flex-col gap-2 ', + }, +}) +export class ExpandableCard { + public isExpanded = signal(false); +} diff --git a/apps/angular/59-content-projection-defer/src/app/page-1.ts b/apps/angular/59-content-projection-defer/src/app/page-1.ts new file mode 100644 index 000000000..868d76959 --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/app/page-1.ts @@ -0,0 +1,10 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'app-page-1', + template: ` + page1 + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class Page1 {} diff --git a/apps/angular/59-content-projection-defer/src/app/page-2.ts b/apps/angular/59-content-projection-defer/src/app/page-2.ts new file mode 100644 index 000000000..5665466d8 --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/app/page-2.ts @@ -0,0 +1,43 @@ +import { httpResource } from '@angular/common/http'; +import { + ChangeDetectionStrategy, + Component, + ResourceStatus, +} from '@angular/core'; +import { ExpandableCard } from './expandable-card'; + +interface Post { + id: number; + title: string; + body: string; + userId: number; +} + +@Component({ + selector: 'app-page-2', + template: ` + page2 + +
Load Post
+
+ @if (postResource.isLoading()) { + Loading... + } @else if (postResource.status() === ResourceStatus.Error) { + Error... + } @else { + @for (post of postResource.value(); track post.id) { +
{{ post.title }}
+ } + } +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ExpandableCard], +}) +export class Page2 { + public postResource = httpResource( + 'https://jsonplaceholder.typicode.com/posts', + ); + protected readonly ResourceStatus = ResourceStatus; +} diff --git a/apps/angular/59-content-projection-defer/src/index.html b/apps/angular/59-content-projection-defer/src/index.html new file mode 100644 index 000000000..79f435fa6 --- /dev/null +++ b/apps/angular/59-content-projection-defer/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-content-projection-defer + + + + + + + + diff --git a/apps/performance/ngfor-biglist/src/main.ts b/apps/angular/59-content-projection-defer/src/main.ts similarity index 100% rename from apps/performance/ngfor-biglist/src/main.ts rename to apps/angular/59-content-projection-defer/src/main.ts diff --git a/apps/performance/christmas-web-worker/src/styles.scss b/apps/angular/59-content-projection-defer/src/styles.scss similarity index 100% rename from apps/performance/christmas-web-worker/src/styles.scss rename to apps/angular/59-content-projection-defer/src/styles.scss diff --git a/apps/performance/default-onpush/tailwind.config.js b/apps/angular/59-content-projection-defer/tailwind.config.js similarity index 100% rename from apps/performance/default-onpush/tailwind.config.js rename to apps/angular/59-content-projection-defer/tailwind.config.js diff --git a/apps/performance/memoized/tsconfig.app.json b/apps/angular/59-content-projection-defer/tsconfig.app.json similarity index 100% rename from apps/performance/memoized/tsconfig.app.json rename to apps/angular/59-content-projection-defer/tsconfig.app.json diff --git a/apps/angular/59-content-projection-defer/tsconfig.editor.json b/apps/angular/59-content-projection-defer/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/angular/59-content-projection-defer/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/angular/59-content-projection-defer/tsconfig.json b/apps/angular/59-content-projection-defer/tsconfig.json new file mode 100644 index 000000000..1b86db04e --- /dev/null +++ b/apps/angular/59-content-projection-defer/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es2022", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/ngrx/notification/.eslintrc.json b/apps/angular/6-structural-directive/.eslintrc.json similarity index 100% rename from apps/ngrx/notification/.eslintrc.json rename to apps/angular/6-structural-directive/.eslintrc.json diff --git a/apps/angular/6-structural-directive/README.md b/apps/angular/6-structural-directive/README.md new file mode 100644 index 000000000..775b40981 --- /dev/null +++ b/apps/angular/6-structural-directive/README.md @@ -0,0 +1,13 @@ +# Structural Directive + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-structural-directive +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/6-permissions/). diff --git a/apps/angular/6-structural-directive/project.json b/apps/angular/6-structural-directive/project.json new file mode 100644 index 000000000..f803b0cb5 --- /dev/null +++ b/apps/angular/6-structural-directive/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-structural-directive", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/6-structural-directive/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/6-structural-directive", + "index": "apps/angular/6-structural-directive/src/index.html", + "main": "apps/angular/6-structural-directive/src/main.ts", + "polyfills": "apps/angular/6-structural-directive/src/polyfills.ts", + "tsConfig": "apps/angular/6-structural-directive/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/6-structural-directive/src/favicon.ico", + "apps/angular/6-structural-directive/src/assets" + ], + "styles": ["apps/angular/6-structural-directive/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-structural-directive:build:production" + }, + "development": { + "buildTarget": "angular-structural-directive:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-structural-directive:build" + } + } + } +} diff --git a/apps/angular/6-structural-directive/src/app/app.component.ts b/apps/angular/6-structural-directive/src/app/app.component.ts new file mode 100644 index 000000000..a3d63b374 --- /dev/null +++ b/apps/angular/6-structural-directive/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + template: ` + + `, + styles: [], +}) +export class AppComponent {} diff --git a/apps/angular/permissions/src/app/app.config.ts b/apps/angular/6-structural-directive/src/app/app.config.ts similarity index 100% rename from apps/angular/permissions/src/app/app.config.ts rename to apps/angular/6-structural-directive/src/app/app.config.ts diff --git a/apps/angular/permissions/src/app/button.component.ts b/apps/angular/6-structural-directive/src/app/button.component.ts similarity index 100% rename from apps/angular/permissions/src/app/button.component.ts rename to apps/angular/6-structural-directive/src/app/button.component.ts diff --git a/apps/angular/permissions/src/app/dashboard/admin.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/admin.component.ts similarity index 95% rename from apps/angular/permissions/src/app/dashboard/admin.component.ts rename to apps/angular/6-structural-directive/src/app/dashboard/admin.component.ts index 72e4b3bef..26bb23284 100644 --- a/apps/angular/permissions/src/app/dashboard/admin.component.ts +++ b/apps/angular/6-structural-directive/src/app/dashboard/admin.component.ts @@ -4,7 +4,6 @@ import { ButtonComponent } from '../button.component'; @Component({ selector: 'app-dashboard', - standalone: true, imports: [RouterLink, ButtonComponent], template: `

dashboard for Admin works!

diff --git a/apps/angular/permissions/src/app/dashboard/manager.component.ts b/apps/angular/6-structural-directive/src/app/dashboard/manager.component.ts similarity index 100% rename from apps/angular/permissions/src/app/dashboard/manager.component.ts rename to apps/angular/6-structural-directive/src/app/dashboard/manager.component.ts diff --git a/apps/angular/permissions/src/app/information.component.ts b/apps/angular/6-structural-directive/src/app/information.component.ts similarity index 97% rename from apps/angular/permissions/src/app/information.component.ts rename to apps/angular/6-structural-directive/src/app/information.component.ts index e4adeb1b9..81b339520 100644 --- a/apps/angular/permissions/src/app/information.component.ts +++ b/apps/angular/6-structural-directive/src/app/information.component.ts @@ -4,7 +4,6 @@ import { UserStore } from './user.store'; @Component({ selector: 'app-information', - standalone: true, imports: [CommonModule], template: `

Information Panel

diff --git a/apps/angular/permissions/src/app/login.component.ts b/apps/angular/6-structural-directive/src/app/login.component.ts similarity index 98% rename from apps/angular/permissions/src/app/login.component.ts rename to apps/angular/6-structural-directive/src/app/login.component.ts index cd36d9603..b8644ed38 100644 --- a/apps/angular/permissions/src/app/login.component.ts +++ b/apps/angular/6-structural-directive/src/app/login.component.ts @@ -14,7 +14,6 @@ import { import { UserStore } from './user.store'; @Component({ - standalone: true, imports: [InformationComponent, RouterLink, ButtonComponent], selector: 'app-login', template: ` diff --git a/apps/angular/permissions/src/app/routes.ts b/apps/angular/6-structural-directive/src/app/routes.ts similarity index 100% rename from apps/angular/permissions/src/app/routes.ts rename to apps/angular/6-structural-directive/src/app/routes.ts diff --git a/apps/angular/permissions/src/app/user.model.ts b/apps/angular/6-structural-directive/src/app/user.model.ts similarity index 100% rename from apps/angular/permissions/src/app/user.model.ts rename to apps/angular/6-structural-directive/src/app/user.model.ts diff --git a/apps/angular/permissions/src/app/user.store.ts b/apps/angular/6-structural-directive/src/app/user.store.ts similarity index 100% rename from apps/angular/permissions/src/app/user.store.ts rename to apps/angular/6-structural-directive/src/app/user.store.ts diff --git a/apps/angular/styling/src/assets/.gitkeep b/apps/angular/6-structural-directive/src/assets/.gitkeep similarity index 100% rename from apps/angular/styling/src/assets/.gitkeep rename to apps/angular/6-structural-directive/src/assets/.gitkeep diff --git a/apps/ngrx/effect-selector/src/favicon.ico b/apps/angular/6-structural-directive/src/favicon.ico similarity index 100% rename from apps/ngrx/effect-selector/src/favicon.ico rename to apps/angular/6-structural-directive/src/favicon.ico diff --git a/apps/angular/6-structural-directive/src/index.html b/apps/angular/6-structural-directive/src/index.html new file mode 100644 index 000000000..8a35fb109 --- /dev/null +++ b/apps/angular/6-structural-directive/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-structural-directive + + + + + + + + diff --git a/apps/angular/permissions/src/main.ts b/apps/angular/6-structural-directive/src/main.ts similarity index 100% rename from apps/angular/permissions/src/main.ts rename to apps/angular/6-structural-directive/src/main.ts diff --git a/apps/angular/pipe-hard/src/polyfills.ts b/apps/angular/6-structural-directive/src/polyfills.ts similarity index 100% rename from apps/angular/pipe-hard/src/polyfills.ts rename to apps/angular/6-structural-directive/src/polyfills.ts diff --git a/apps/performance/default-onpush/src/styles.scss b/apps/angular/6-structural-directive/src/styles.scss similarity index 100% rename from apps/performance/default-onpush/src/styles.scss rename to apps/angular/6-structural-directive/src/styles.scss diff --git a/apps/performance/memoized/tailwind.config.js b/apps/angular/6-structural-directive/tailwind.config.js similarity index 100% rename from apps/performance/memoized/tailwind.config.js rename to apps/angular/6-structural-directive/tailwind.config.js diff --git a/apps/angular/pipe-hard/tsconfig.app.json b/apps/angular/6-structural-directive/tsconfig.app.json similarity index 100% rename from apps/angular/pipe-hard/tsconfig.app.json rename to apps/angular/6-structural-directive/tsconfig.app.json diff --git a/apps/angular/pipe-easy/tsconfig.editor.json b/apps/angular/6-structural-directive/tsconfig.editor.json similarity index 100% rename from apps/angular/pipe-easy/tsconfig.editor.json rename to apps/angular/6-structural-directive/tsconfig.editor.json diff --git a/apps/angular/pipe-easy/tsconfig.json b/apps/angular/6-structural-directive/tsconfig.json similarity index 100% rename from apps/angular/pipe-easy/tsconfig.json rename to apps/angular/6-structural-directive/tsconfig.json diff --git a/apps/nx/static-dynamic-import/.eslintrc.json b/apps/angular/8-pure-pipe/.eslintrc.json similarity index 100% rename from apps/nx/static-dynamic-import/.eslintrc.json rename to apps/angular/8-pure-pipe/.eslintrc.json diff --git a/apps/angular/8-pure-pipe/README.md b/apps/angular/8-pure-pipe/README.md new file mode 100644 index 000000000..a65a33f85 --- /dev/null +++ b/apps/angular/8-pure-pipe/README.md @@ -0,0 +1,13 @@ +# Pure Pipe + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-pure-pipe +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/8-pipe-pure/). diff --git a/apps/angular/8-pure-pipe/project.json b/apps/angular/8-pure-pipe/project.json new file mode 100644 index 000000000..a684d542f --- /dev/null +++ b/apps/angular/8-pure-pipe/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-pure-pipe", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/8-pure-pipe/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/8-pure-pipe", + "index": "apps/angular/8-pure-pipe/src/index.html", + "main": "apps/angular/8-pure-pipe/src/main.ts", + "polyfills": "apps/angular/8-pure-pipe/src/polyfills.ts", + "tsConfig": "apps/angular/8-pure-pipe/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/8-pure-pipe/src/favicon.ico", + "apps/angular/8-pure-pipe/src/assets" + ], + "styles": ["apps/angular/8-pure-pipe/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-pure-pipe:build:production" + }, + "development": { + "buildTarget": "angular-pure-pipe:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-pure-pipe:build" + } + } + } +} diff --git a/apps/angular/8-pure-pipe/src/app/app.component.ts b/apps/angular/8-pure-pipe/src/app/app.component.ts new file mode 100644 index 000000000..41dd38e25 --- /dev/null +++ b/apps/angular/8-pure-pipe/src/app/app.component.ts @@ -0,0 +1,20 @@ +import { NgFor } from '@angular/common'; +import { Component } from '@angular/core'; + +@Component({ + imports: [NgFor], + selector: 'app-root', + template: ` +
+ {{ heavyComputation(person, index) }} +
+ `, +}) +export class AppComponent { + persons = ['toto', 'jack']; + + heavyComputation(name: string, index: number) { + // very heavy computation + return `${name} - ${index}`; + } +} diff --git a/apps/angular/view-transition/src/assets/.gitkeep b/apps/angular/8-pure-pipe/src/assets/.gitkeep similarity index 100% rename from apps/angular/view-transition/src/assets/.gitkeep rename to apps/angular/8-pure-pipe/src/assets/.gitkeep diff --git a/apps/ngrx/notification/src/favicon.ico b/apps/angular/8-pure-pipe/src/favicon.ico similarity index 100% rename from apps/ngrx/notification/src/favicon.ico rename to apps/angular/8-pure-pipe/src/favicon.ico diff --git a/apps/angular/8-pure-pipe/src/index.html b/apps/angular/8-pure-pipe/src/index.html new file mode 100644 index 000000000..c8ee70b97 --- /dev/null +++ b/apps/angular/8-pure-pipe/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-pure-pipe + + + + + + + + diff --git a/apps/angular/pipe-intermediate/src/main.ts b/apps/angular/8-pure-pipe/src/main.ts similarity index 100% rename from apps/angular/pipe-intermediate/src/main.ts rename to apps/angular/8-pure-pipe/src/main.ts diff --git a/apps/angular/pipe-intermediate/src/polyfills.ts b/apps/angular/8-pure-pipe/src/polyfills.ts similarity index 100% rename from apps/angular/pipe-intermediate/src/polyfills.ts rename to apps/angular/8-pure-pipe/src/polyfills.ts diff --git a/apps/angular/router-input/src/styles.scss b/apps/angular/8-pure-pipe/src/styles.scss similarity index 100% rename from apps/angular/router-input/src/styles.scss rename to apps/angular/8-pure-pipe/src/styles.scss diff --git a/apps/angular/pipe-intermediate/tsconfig.app.json b/apps/angular/8-pure-pipe/tsconfig.app.json similarity index 100% rename from apps/angular/pipe-intermediate/tsconfig.app.json rename to apps/angular/8-pure-pipe/tsconfig.app.json diff --git a/apps/angular/pipe-hard/tsconfig.editor.json b/apps/angular/8-pure-pipe/tsconfig.editor.json similarity index 100% rename from apps/angular/pipe-hard/tsconfig.editor.json rename to apps/angular/8-pure-pipe/tsconfig.editor.json diff --git a/apps/angular/pipe-hard/tsconfig.json b/apps/angular/8-pure-pipe/tsconfig.json similarity index 100% rename from apps/angular/pipe-hard/tsconfig.json rename to apps/angular/8-pure-pipe/tsconfig.json diff --git a/apps/rxjs/pipe-bug/.eslintrc.json b/apps/angular/9-wrap-function-pipe/.eslintrc.json similarity index 100% rename from apps/rxjs/pipe-bug/.eslintrc.json rename to apps/angular/9-wrap-function-pipe/.eslintrc.json diff --git a/apps/angular/9-wrap-function-pipe/README.md b/apps/angular/9-wrap-function-pipe/README.md new file mode 100644 index 000000000..1491e7dda --- /dev/null +++ b/apps/angular/9-wrap-function-pipe/README.md @@ -0,0 +1,13 @@ +# Wrap Function Pipe + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve angular-wrap-function-pipe +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/9-pipe-wrapFn/). diff --git a/apps/angular/9-wrap-function-pipe/project.json b/apps/angular/9-wrap-function-pipe/project.json new file mode 100644 index 000000000..dc5c4ab6e --- /dev/null +++ b/apps/angular/9-wrap-function-pipe/project.json @@ -0,0 +1,72 @@ +{ + "name": "angular-wrap-function-pipe", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/angular/9-wrap-function-pipe/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular/9-wrap-function-pipe", + "index": "apps/angular/9-wrap-function-pipe/src/index.html", + "main": "apps/angular/9-wrap-function-pipe/src/main.ts", + "polyfills": "apps/angular/9-wrap-function-pipe/src/polyfills.ts", + "tsConfig": "apps/angular/9-wrap-function-pipe/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/angular/9-wrap-function-pipe/src/favicon.ico", + "apps/angular/9-wrap-function-pipe/src/assets" + ], + "styles": ["apps/angular/9-wrap-function-pipe/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-wrap-function-pipe:build:production" + }, + "development": { + "buildTarget": "angular-wrap-function-pipe:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-wrap-function-pipe:build" + } + } + } +} diff --git a/apps/angular/9-wrap-function-pipe/src/app/app.component.ts b/apps/angular/9-wrap-function-pipe/src/app/app.component.ts new file mode 100644 index 000000000..dd576ae49 --- /dev/null +++ b/apps/angular/9-wrap-function-pipe/src/app/app.component.ts @@ -0,0 +1,33 @@ +import { NgFor } from '@angular/common'; +import { Component } from '@angular/core'; + +@Component({ + imports: [NgFor], + selector: 'app-root', + template: ` +
+ {{ showName(person.name, index) }} + {{ isAllowed(person.age, isFirst) }} +
+ `, +}) +export class AppComponent { + persons = [ + { name: 'Toto', age: 10 }, + { name: 'Jack', age: 15 }, + { name: 'John', age: 30 }, + ]; + + showName(name: string, index: number) { + // very heavy computation + return `${name} - ${index}`; + } + + isAllowed(age: number, isFirst: boolean) { + if (isFirst) { + return 'always allowed'; + } else { + return age > 25 ? 'allowed' : 'declined'; + } + } +} diff --git a/apps/forms/control-value-accessor/src/assets/.gitkeep b/apps/angular/9-wrap-function-pipe/src/assets/.gitkeep similarity index 100% rename from apps/forms/control-value-accessor/src/assets/.gitkeep rename to apps/angular/9-wrap-function-pipe/src/assets/.gitkeep diff --git a/apps/nx/static-dynamic-import/src/favicon.ico b/apps/angular/9-wrap-function-pipe/src/favicon.ico similarity index 100% rename from apps/nx/static-dynamic-import/src/favicon.ico rename to apps/angular/9-wrap-function-pipe/src/favicon.ico diff --git a/apps/angular/9-wrap-function-pipe/src/index.html b/apps/angular/9-wrap-function-pipe/src/index.html new file mode 100644 index 000000000..bc8a0ddbd --- /dev/null +++ b/apps/angular/9-wrap-function-pipe/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-wrap-function-pipe + + + + + + + + diff --git a/apps/forms/control-value-accessor/src/main.ts b/apps/angular/9-wrap-function-pipe/src/main.ts similarity index 100% rename from apps/forms/control-value-accessor/src/main.ts rename to apps/angular/9-wrap-function-pipe/src/main.ts diff --git a/apps/angular/projection/src/polyfills.ts b/apps/angular/9-wrap-function-pipe/src/polyfills.ts similarity index 100% rename from apps/angular/projection/src/polyfills.ts rename to apps/angular/9-wrap-function-pipe/src/polyfills.ts diff --git a/apps/angular/styling/src/styles.scss b/apps/angular/9-wrap-function-pipe/src/styles.scss similarity index 100% rename from apps/angular/styling/src/styles.scss rename to apps/angular/9-wrap-function-pipe/src/styles.scss diff --git a/apps/angular/projection/tsconfig.app.json b/apps/angular/9-wrap-function-pipe/tsconfig.app.json similarity index 100% rename from apps/angular/projection/tsconfig.app.json rename to apps/angular/9-wrap-function-pipe/tsconfig.app.json diff --git a/apps/angular/pipe-intermediate/tsconfig.editor.json b/apps/angular/9-wrap-function-pipe/tsconfig.editor.json similarity index 100% rename from apps/angular/pipe-intermediate/tsconfig.editor.json rename to apps/angular/9-wrap-function-pipe/tsconfig.editor.json diff --git a/apps/angular/pipe-intermediate/tsconfig.json b/apps/angular/9-wrap-function-pipe/tsconfig.json similarity index 100% rename from apps/angular/pipe-intermediate/tsconfig.json rename to apps/angular/9-wrap-function-pipe/tsconfig.json diff --git a/apps/angular/anchor-scrolling/README.md b/apps/angular/anchor-scrolling/README.md deleted file mode 100644 index a159fd8b7..000000000 --- a/apps/angular/anchor-scrolling/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Anchor Navigation - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-anchor-scrolling -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/21-achor-scrolling/). diff --git a/apps/angular/anchor-scrolling/jest.config.ts b/apps/angular/anchor-scrolling/jest.config.ts deleted file mode 100644 index 166572856..000000000 --- a/apps/angular/anchor-scrolling/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'angular-anchor-scrolling', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/angular/anchor-scrolling', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/angular/anchor-scrolling/project.json b/apps/angular/anchor-scrolling/project.json deleted file mode 100644 index 3fa125347..000000000 --- a/apps/angular/anchor-scrolling/project.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "angular-anchor-scrolling", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/anchor-scrolling/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/anchor-scrolling", - "index": "apps/angular/anchor-scrolling/src/index.html", - "main": "apps/angular/anchor-scrolling/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/anchor-scrolling/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/anchor-scrolling/src/favicon.ico", - "apps/angular/anchor-scrolling/src/assets" - ], - "styles": ["apps/angular/anchor-scrolling/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-anchor-scrolling:build:production" - }, - "development": { - "buildTarget": "angular-anchor-scrolling:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-anchor-scrolling:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/anchor-scrolling/**/*.ts", - "apps/angular/anchor-scrolling/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/angular/anchor-scrolling/jest.config.ts" - } - } - }, - "tags": [] -} diff --git a/apps/angular/anchor-scrolling/src/app/app.component.ts b/apps/angular/anchor-scrolling/src/app/app.component.ts deleted file mode 100644 index 3fb7c5df0..000000000 --- a/apps/angular/anchor-scrolling/src/app/app.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet], - selector: 'app-root', - template: ` - - `, -}) -export class AppComponent {} diff --git a/apps/angular/anchor-scrolling/src/app/home.component.ts b/apps/angular/anchor-scrolling/src/app/home.component.ts deleted file mode 100644 index 0f24ff6e7..000000000 --- a/apps/angular/anchor-scrolling/src/app/home.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Component } from '@angular/core'; -import { NavButtonComponent } from './nav-button.component'; - -@Component({ - standalone: true, - imports: [NavButtonComponent], - selector: 'app-home', - template: ` - Foo Page -
- Empty - Scroll Bottom -
-
- I want to scroll each - Scroll Top -
- `, -}) -export class HomeComponent {} diff --git a/apps/angular/anchor-scrolling/src/index.html b/apps/angular/anchor-scrolling/src/index.html deleted file mode 100644 index 7a2a4b377..000000000 --- a/apps/angular/anchor-scrolling/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - AnchorScrolling - - - - - - - - diff --git a/apps/angular/bug-cd/README.md b/apps/angular/bug-cd/README.md deleted file mode 100644 index cb42e778c..000000000 --- a/apps/angular/bug-cd/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Change Detection Bug - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-bug-cd -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/32-bug-cd/). diff --git a/apps/angular/bug-cd/jest.config.ts b/apps/angular/bug-cd/jest.config.ts deleted file mode 100644 index ded316d4c..000000000 --- a/apps/angular/bug-cd/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'angular-bug-cd', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/angular/bug-cd', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/angular/bug-cd/project.json b/apps/angular/bug-cd/project.json deleted file mode 100644 index f5aaa262e..000000000 --- a/apps/angular/bug-cd/project.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "angular-bug-cd", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/bug-cd/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/bug-cd", - "index": "apps/angular/bug-cd/src/index.html", - "main": "apps/angular/bug-cd/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/bug-cd/tsconfig.app.json", - "assets": [ - "apps/angular/bug-cd/src/favicon.ico", - "apps/angular/bug-cd/src/assets" - ], - "styles": ["apps/angular/bug-cd/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-bug-cd:build:production" - }, - "development": { - "buildTarget": "angular-bug-cd:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-bug-cd:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/bug-cd/**/*.ts", - "apps/angular/bug-cd/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/angular/bug-cd/jest.config.ts" - } - } - } -} diff --git a/apps/angular/bug-cd/src/app/app.component.ts b/apps/angular/bug-cd/src/app/app.component.ts deleted file mode 100644 index 046492f9b..000000000 --- a/apps/angular/bug-cd/src/app/app.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet], - selector: 'app-root', - template: ` -

My Application

-
- -
- -
-
- `, - host: { - class: 'flex flex-col gap-2', - }, -}) -export class AppComponent {} diff --git a/apps/angular/bug-cd/src/index.html b/apps/angular/bug-cd/src/index.html deleted file mode 100644 index ab925a75c..000000000 --- a/apps/angular/bug-cd/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - test - - - - - - - - diff --git a/apps/angular/context-outlet-type/README.md b/apps/angular/context-outlet-type/README.md deleted file mode 100644 index d195baa04..000000000 --- a/apps/angular/context-outlet-type/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Typed ContextOutlet - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-context-outlet-type -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/4-context-outlet-typed/). diff --git a/apps/angular/context-outlet-type/project.json b/apps/angular/context-outlet-type/project.json deleted file mode 100644 index b882d73de..000000000 --- a/apps/angular/context-outlet-type/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-context-outlet-type", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/context-outlet-type/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/context-outlet-type", - "index": "apps/angular/context-outlet-type/src/index.html", - "main": "apps/angular/context-outlet-type/src/main.ts", - "polyfills": "apps/angular/context-outlet-type/src/polyfills.ts", - "tsConfig": "apps/angular/context-outlet-type/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/context-outlet-type/src/favicon.ico", - "apps/angular/context-outlet-type/src/assets" - ], - "styles": ["apps/angular/context-outlet-type/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-context-outlet-type:build:production" - }, - "development": { - "buildTarget": "angular-context-outlet-type:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-context-outlet-type:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/context-outlet-type/**/*.ts", - "apps/angular/context-outlet-type/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/context-outlet-type/src/app/app.component.ts b/apps/angular/context-outlet-type/src/app/app.component.ts deleted file mode 100644 index 2683ba9d4..000000000 --- a/apps/angular/context-outlet-type/src/app/app.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NgTemplateOutlet } from '@angular/common'; -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { ListComponent } from './list.component'; -import { PersonComponent } from './person.component'; - -@Component({ - standalone: true, - imports: [NgTemplateOutlet, PersonComponent, ListComponent], - selector: 'app-root', - template: ` - - - {{ name }}: {{ age }} - - - - - - {{ student.name }}: {{ student.age }} - {{ i }} - - - - - - {{ city.name }}: {{ city.country }} - {{ i }} - - - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AppComponent { - person = { - name: 'toto', - age: 3, - }; - - students = [ - { name: 'toto', age: 3 }, - { name: 'titi', age: 4 }, - ]; - - cities = [ - { name: 'Paris', country: 'France' }, - { name: 'Berlin', country: 'Germany' }, - ]; -} diff --git a/apps/angular/context-outlet-type/src/app/list.component.ts b/apps/angular/context-outlet-type/src/app/list.component.ts deleted file mode 100644 index 5212a425e..000000000 --- a/apps/angular/context-outlet-type/src/app/list.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - ContentChild, - Input, - TemplateRef, -} from '@angular/core'; - -@Component({ - selector: 'list', - standalone: true, - imports: [CommonModule], - template: ` -
- -
- - No Template - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ListComponent { - @Input() list!: TItem[]; - - @ContentChild('listRef', { read: TemplateRef }) - listTemplateRef!: TemplateRef; -} diff --git a/apps/angular/context-outlet-type/src/index.html b/apps/angular/context-outlet-type/src/index.html deleted file mode 100644 index b3ee6c60d..000000000 --- a/apps/angular/context-outlet-type/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - ContextOutletType - - - - - - - - diff --git a/apps/angular/crud/README.md b/apps/angular/crud/README.md deleted file mode 100644 index 0a6518b44..000000000 --- a/apps/angular/crud/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Crud application - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-crud -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/5-crud/). diff --git a/apps/angular/crud/jest.config.ts b/apps/angular/crud/jest.config.ts deleted file mode 100644 index 485099109..000000000 --- a/apps/angular/crud/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'angular-crud', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/apps/angular/crud', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/angular/crud/project.json b/apps/angular/crud/project.json deleted file mode 100644 index 0d656a983..000000000 --- a/apps/angular/crud/project.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "name": "angular-crud", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/crud/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/crud", - "index": "apps/angular/crud/src/index.html", - "main": "apps/angular/crud/src/main.ts", - "polyfills": "apps/angular/crud/src/polyfills.ts", - "tsConfig": "apps/angular/crud/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/crud/src/favicon.ico", - "apps/angular/crud/src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", - "apps/angular/crud/src/styles.scss" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-crud:build:production" - }, - "development": { - "buildTarget": "angular-crud:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-crud:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/crud/**/*.ts", - "apps/angular/crud/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/angular/crud/jest.config.ts" - } - } - }, - "tags": [] -} diff --git a/apps/angular/crud/src/app/app.component.ts b/apps/angular/crud/src/app/app.component.ts deleted file mode 100644 index 8c3d1b8ae..000000000 --- a/apps/angular/crud/src/app/app.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { HttpClient } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { randText } from '@ngneat/falso'; - -@Component({ - standalone: true, - imports: [CommonModule], - selector: 'app-root', - template: ` -
- {{ todo.title }} - -
- `, - styles: [], -}) -export class AppComponent implements OnInit { - todos!: any[]; - - constructor(private http: HttpClient) {} - - ngOnInit(): void { - this.http - .get('https://jsonplaceholder.typicode.com/todos') - .subscribe((todos) => { - this.todos = todos; - }); - } - - update(todo: any) { - this.http - .put( - `https://jsonplaceholder.typicode.com/todos/${todo.id}`, - JSON.stringify({ - todo: todo.id, - title: randText(), - body: todo.body, - userId: todo.userId, - }), - { - headers: { - 'Content-type': 'application/json; charset=UTF-8', - }, - }, - ) - .subscribe((todoUpdated: any) => { - this.todos[todoUpdated.id - 1] = todoUpdated; - }); - } -} diff --git a/apps/angular/crud/src/app/app.config.ts b/apps/angular/crud/src/app/app.config.ts deleted file mode 100644 index de0a3ccec..000000000 --- a/apps/angular/crud/src/app/app.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { HttpClientModule } from '@angular/common/http'; -import { ApplicationConfig, importProvidersFrom } from '@angular/core'; -export const appConfig: ApplicationConfig = { - providers: [importProvidersFrom(HttpClientModule)], -}; diff --git a/apps/angular/crud/src/index.html b/apps/angular/crud/src/index.html deleted file mode 100644 index c556437f0..000000000 --- a/apps/angular/crud/src/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Http - - - - - - - - - - - diff --git a/apps/angular/decoupling/README.md b/apps/angular/decoupling/README.md deleted file mode 100644 index 0ba00e70c..000000000 --- a/apps/angular/decoupling/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Decoupling Components - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-decoupling -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/33-decoupling/). diff --git a/apps/angular/decoupling/project.json b/apps/angular/decoupling/project.json deleted file mode 100644 index c32f85c13..000000000 --- a/apps/angular/decoupling/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-decoupling", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/decoupling/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/decoupling", - "index": "apps/angular/decoupling/src/index.html", - "main": "apps/angular/decoupling/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/decoupling/tsconfig.app.json", - "assets": [ - "apps/angular/decoupling/src/favicon.ico", - "apps/angular/decoupling/src/assets" - ], - "styles": ["apps/angular/decoupling/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-decoupling:build:production" - }, - "development": { - "buildTarget": "angular-decoupling:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-decoupling:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/decoupling/**/*.ts", - "apps/angular/decoupling/**/*.html" - ] - } - } - } -} diff --git a/apps/angular/decoupling/src/app/app.component.ts b/apps/angular/decoupling/src/app/app.component.ts deleted file mode 100644 index 34082c331..000000000 --- a/apps/angular/decoupling/src/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BtnDisabledDirective } from '@angular-challenges/decoupling/brain'; -import { BtnHelmetDirective } from '@angular-challenges/decoupling/helmet'; -import { Component } from '@angular/core'; - -@Component({ - standalone: true, - imports: [BtnDisabledDirective, BtnHelmetDirective], - selector: 'app-root', - template: ` - - `, -}) -export class AppComponent {} diff --git a/apps/angular/decoupling/src/index.html b/apps/angular/decoupling/src/index.html deleted file mode 100644 index 25b5ea13c..000000000 --- a/apps/angular/decoupling/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - decoupling - - - - - - - - diff --git a/apps/angular/di/README.md b/apps/angular/di/README.md deleted file mode 100644 index 032601c1f..000000000 --- a/apps/angular/di/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Master Dependancy Injection - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-di -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/16-di/). diff --git a/apps/angular/di/project.json b/apps/angular/di/project.json deleted file mode 100644 index aa7880866..000000000 --- a/apps/angular/di/project.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "name": "angular-di", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/di/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/di", - "index": "apps/angular/di/src/index.html", - "main": "apps/angular/di/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/di/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/di/src/favicon.ico", - "apps/angular/di/src/assets" - ], - "styles": ["apps/angular/di/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-di:build:production" - }, - "development": { - "buildTarget": "angular-di:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-di:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/di/**/*.ts", - "apps/angular/di/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/di/src/app/app.component.ts b/apps/angular/di/src/app/app.component.ts deleted file mode 100644 index e57a5a5bf..000000000 --- a/apps/angular/di/src/app/app.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { TableComponent } from '@angular-challenges/angular/di'; -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, Directive } from '@angular/core'; -import { CurrencyPipe } from './currency.pipe'; -import { CurrencyService } from './currency.service'; -import { Product, products } from './product.model'; - -interface ProductContext { - $implicit: Product; -} - -@Directive({ - selector: 'ng-template[product]', - standalone: true, -}) -export class ProductDirective { - static ngTemplateContextGuard( - dir: ProductDirective, - ctx: unknown, - ): ctx is ProductContext { - return true; - } -} - -@Component({ - standalone: true, - imports: [TableComponent, CurrencyPipe, AsyncPipe, NgFor, ProductDirective], - providers: [CurrencyService], - selector: 'app-root', - template: ` - - - - - - - - - - - - - - -
- {{ col }} -
{{ product.name }}{{ product.priceA | currency | async }}{{ product.priceB | currency | async }}{{ product.priceC | currency | async }}
- `, -}) -export class AppComponent { - products = products; - displayedColumns = ['name', 'priceA', 'priceB', 'priceC']; -} diff --git a/apps/angular/di/src/index.html b/apps/angular/di/src/index.html deleted file mode 100644 index c120f5b9c..000000000 --- a/apps/angular/di/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Di - - - - - - - - diff --git a/apps/angular/injection-token/jest.config.ts b/apps/angular/injection-token/jest.config.ts deleted file mode 100644 index c48bb4949..000000000 --- a/apps/angular/injection-token/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'angular-injection-token', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/angular/injection-token', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/angular/injection-token/project.json b/apps/angular/injection-token/project.json deleted file mode 100644 index 2a656807f..000000000 --- a/apps/angular/injection-token/project.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "angular-injection-token", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/injection-token/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/injection-token", - "index": "apps/angular/injection-token/src/index.html", - "main": "apps/angular/injection-token/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/injection-token/tsconfig.app.json", - "assets": [ - "apps/angular/injection-token/src/favicon.ico", - "apps/angular/injection-token/src/assets" - ], - "styles": ["apps/angular/injection-token/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-injection-token:build:production" - }, - "development": { - "buildTarget": "angular-injection-token:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-injection-token:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/injection-token/**/*.ts", - "apps/angular/injection-token/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/angular/injection-token/jest.config.ts" - } - } - } -} diff --git a/apps/angular/injection-token/src/app/app.component.ts b/apps/angular/injection-token/src/app/app.component.ts deleted file mode 100644 index 5ac8087cb..000000000 --- a/apps/angular/injection-token/src/app/app.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterLink, RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet, RouterLink], - selector: 'app-root', - template: ` -
- - -
- - `, - host: { - class: 'p-10 flex flex-col', - }, -}) -export class AppComponent {} diff --git a/apps/angular/interop-rxjs-signal/README.md b/apps/angular/interop-rxjs-signal/README.md deleted file mode 100644 index 9cf32efa5..000000000 --- a/apps/angular/interop-rxjs-signal/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Interoperability Rxjs/Signal - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-interop-rxjs-signal -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/30-interop-rxjs-signal/). diff --git a/apps/angular/interop-rxjs-signal/jest.config.ts b/apps/angular/interop-rxjs-signal/jest.config.ts deleted file mode 100644 index 53f7481c3..000000000 --- a/apps/angular/interop-rxjs-signal/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'angular-interop-rxjs-signal', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/angular/interop-rxjs-signal', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/angular/interop-rxjs-signal/project.json b/apps/angular/interop-rxjs-signal/project.json deleted file mode 100644 index 6a94737ca..000000000 --- a/apps/angular/interop-rxjs-signal/project.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "name": "angular-interop-rxjs-signal", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/interop-rxjs-signal/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/interop-rxjs-signal", - "index": "apps/angular/interop-rxjs-signal/src/index.html", - "main": "apps/angular/interop-rxjs-signal/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/interop-rxjs-signal/tsconfig.app.json", - "assets": [ - "apps/angular/interop-rxjs-signal/src/favicon.ico", - "apps/angular/interop-rxjs-signal/src/assets" - ], - "styles": [ - "apps/angular/interop-rxjs-signal/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-interop-rxjs-signal:build:production" - }, - "development": { - "buildTarget": "angular-interop-rxjs-signal:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-interop-rxjs-signal:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/interop-rxjs-signal/**/*.ts", - "apps/angular/interop-rxjs-signal/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/angular/interop-rxjs-signal/jest.config.ts" - } - } - } -} diff --git a/apps/angular/interop-rxjs-signal/src/app/app.component.ts b/apps/angular/interop-rxjs-signal/src/app/app.component.ts deleted file mode 100644 index 7b83d1470..000000000 --- a/apps/angular/interop-rxjs-signal/src/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet], - selector: 'app-root', - template: ` - - `, - styles: [''], -}) -export class AppComponent {} diff --git a/apps/angular/interop-rxjs-signal/src/app/detail/detail.component.ts b/apps/angular/interop-rxjs-signal/src/app/detail/detail.component.ts deleted file mode 100644 index 3576db452..000000000 --- a/apps/angular/interop-rxjs-signal/src/app/detail/detail.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { DatePipe } from '@angular/common'; -import { Component, Input as RouterInput } from '@angular/core'; -import { RouterLink } from '@angular/router'; -import { Photo } from '../photo.model'; - -@Component({ - selector: 'app-photos', - standalone: true, - imports: [DatePipe, RouterLink], - template: ` - {{ photo.title }} -

- Title: - {{ photo.title }} -

-

- Owner: - {{ photo.ownername }} -

-

- Date: - {{ photo.datetaken | date }} -

-

- Tags: - {{ photo.tags }} -

- - - `, - host: { - class: 'p-5 block', - }, -}) -export default class DetailComponent { - @RouterInput({ - required: true, - transform: (value: string) => JSON.parse(decodeURIComponent(value)), - }) - photo!: Photo; -} diff --git a/apps/angular/interop-rxjs-signal/src/index.html b/apps/angular/interop-rxjs-signal/src/index.html deleted file mode 100644 index 1c69fbc7a..000000000 --- a/apps/angular/interop-rxjs-signal/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - rxjs-to-signal - - - - - - - - diff --git a/apps/angular/module-to-standalone/project.json b/apps/angular/module-to-standalone/project.json deleted file mode 100644 index 4ee3a4e5f..000000000 --- a/apps/angular/module-to-standalone/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-module-to-standalone", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/module-to-standalone/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/module-to-standalone", - "index": "apps/angular/module-to-standalone/src/index.html", - "main": "apps/angular/module-to-standalone/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/module-to-standalone/tsconfig.app.json", - "assets": [ - "apps/angular/module-to-standalone/src/favicon.ico", - "apps/angular/module-to-standalone/src/assets" - ], - "styles": ["apps/angular/module-to-standalone/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-module-to-standalone:build:production" - }, - "development": { - "buildTarget": "angular-module-to-standalone:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-module-to-standalone:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/module-to-standalone/**/*.ts", - "apps/angular/module-to-standalone/**/*.html" - ] - } - } - } -} diff --git a/apps/angular/module-to-standalone/src/app/app.component.ts b/apps/angular/module-to-standalone/src/app/app.component.ts deleted file mode 100644 index 95eeab5b9..000000000 --- a/apps/angular/module-to-standalone/src/app/app.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-root', - template: ` -
- - - -
- - `, - host: { - class: 'flex flex-col p-4 gap-3', - }, -}) -export class AppComponent {} diff --git a/apps/angular/module-to-standalone/src/index.html b/apps/angular/module-to-standalone/src/index.html deleted file mode 100644 index 4902faa44..000000000 --- a/apps/angular/module-to-standalone/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - module-to-standalone - - - - - - - - diff --git a/apps/angular/ngfor-enhancement/README.md b/apps/angular/ngfor-enhancement/README.md deleted file mode 100644 index 937dfb54e..000000000 --- a/apps/angular/ngfor-enhancement/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Directive Enhancement - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-ngfor-enhancement -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/3-directive-enhancement/). diff --git a/apps/angular/ngfor-enhancement/project.json b/apps/angular/ngfor-enhancement/project.json deleted file mode 100644 index 8f2b72890..000000000 --- a/apps/angular/ngfor-enhancement/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-ngfor-enhancement", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/ngfor-enhancement/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/ngfor-enhancement", - "index": "apps/angular/ngfor-enhancement/src/index.html", - "main": "apps/angular/ngfor-enhancement/src/main.ts", - "polyfills": "apps/angular/ngfor-enhancement/src/polyfills.ts", - "tsConfig": "apps/angular/ngfor-enhancement/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/ngfor-enhancement/src/favicon.ico", - "apps/angular/ngfor-enhancement/src/assets" - ], - "styles": ["apps/angular/ngfor-enhancement/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-ngfor-enhancement:build:production" - }, - "development": { - "buildTarget": "angular-ngfor-enhancement:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-ngfor-enhancement:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/ngfor-enhancement/**/*.ts", - "apps/angular/ngfor-enhancement/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/ngfor-enhancement/src/app/app.component.ts b/apps/angular/ngfor-enhancement/src/app/app.component.ts deleted file mode 100644 index cd1d5f23c..000000000 --- a/apps/angular/ngfor-enhancement/src/app/app.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NgFor, NgIf } from '@angular/common'; -import { ChangeDetectionStrategy, Component } from '@angular/core'; - -interface Person { - name: string; -} - -@Component({ - standalone: true, - imports: [NgFor, NgIf], - selector: 'app-root', - template: ` - -
- {{ person.name }} -
-
- The list is empty !! - `, - styles: [], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AppComponent { - persons: Person[] = []; -} diff --git a/apps/angular/ngfor-enhancement/src/index.html b/apps/angular/ngfor-enhancement/src/index.html deleted file mode 100644 index c38d89dee..000000000 --- a/apps/angular/ngfor-enhancement/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - NgForEnhance - - - - - - - - diff --git a/apps/angular/permissions/README.md b/apps/angular/permissions/README.md deleted file mode 100644 index 99b2e5582..000000000 --- a/apps/angular/permissions/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Structural Directive - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-permissions -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/6-permissions/). diff --git a/apps/angular/permissions/project.json b/apps/angular/permissions/project.json deleted file mode 100644 index 67b83cb78..000000000 --- a/apps/angular/permissions/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-permissions", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/permissions/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/permissions", - "index": "apps/angular/permissions/src/index.html", - "main": "apps/angular/permissions/src/main.ts", - "polyfills": "apps/angular/permissions/src/polyfills.ts", - "tsConfig": "apps/angular/permissions/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/permissions/src/favicon.ico", - "apps/angular/permissions/src/assets" - ], - "styles": ["apps/angular/permissions/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-permissions:build:production" - }, - "development": { - "buildTarget": "angular-permissions:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-permissions:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/permissions/**/*.ts", - "apps/angular/permissions/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/permissions/src/app/app.component.ts b/apps/angular/permissions/src/app/app.component.ts deleted file mode 100644 index d89a2f579..000000000 --- a/apps/angular/permissions/src/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet], - selector: 'app-root', - template: ` - - `, - styles: [], -}) -export class AppComponent {} diff --git a/apps/angular/permissions/src/index.html b/apps/angular/permissions/src/index.html deleted file mode 100644 index 14ab31c3b..000000000 --- a/apps/angular/permissions/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Permissions - - - - - - - - diff --git a/apps/angular/pipe-easy/README.md b/apps/angular/pipe-easy/README.md deleted file mode 100644 index 8501be8c7..000000000 --- a/apps/angular/pipe-easy/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Pure Pipe - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-pipe-easy -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/8-pipe-pure/). diff --git a/apps/angular/pipe-easy/project.json b/apps/angular/pipe-easy/project.json deleted file mode 100644 index a8f051516..000000000 --- a/apps/angular/pipe-easy/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-pipe-easy", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/pipe-easy/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/pipe-easy", - "index": "apps/angular/pipe-easy/src/index.html", - "main": "apps/angular/pipe-easy/src/main.ts", - "polyfills": "apps/angular/pipe-easy/src/polyfills.ts", - "tsConfig": "apps/angular/pipe-easy/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/pipe-easy/src/favicon.ico", - "apps/angular/pipe-easy/src/assets" - ], - "styles": ["apps/angular/pipe-easy/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-pipe-easy:build:production" - }, - "development": { - "buildTarget": "angular-pipe-easy:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-pipe-easy:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/pipe-easy/**/*.ts", - "apps/angular/pipe-easy/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/pipe-easy/src/app/app.component.ts b/apps/angular/pipe-easy/src/app/app.component.ts deleted file mode 100644 index 3c19fa169..000000000 --- a/apps/angular/pipe-easy/src/app/app.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { NgFor } from '@angular/common'; -import { Component } from '@angular/core'; - -@Component({ - standalone: true, - imports: [NgFor], - selector: 'app-root', - template: ` -
- {{ heavyComputation(person, index) }} -
- `, -}) -export class AppComponent { - persons = ['toto', 'jack']; - - heavyComputation(name: string, index: number) { - // very heavy computation - return `${name} - ${index}`; - } -} diff --git a/apps/angular/pipe-easy/src/index.html b/apps/angular/pipe-easy/src/index.html deleted file mode 100644 index eacdd37b7..000000000 --- a/apps/angular/pipe-easy/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - PipeEasy - - - - - - - - diff --git a/apps/angular/pipe-hard/README.md b/apps/angular/pipe-hard/README.md deleted file mode 100644 index ba801bd0c..000000000 --- a/apps/angular/pipe-hard/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Utility Wrapper Pipe - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-pipe-hard -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/10-pipe-utility/). diff --git a/apps/angular/pipe-hard/project.json b/apps/angular/pipe-hard/project.json deleted file mode 100644 index 544b201f2..000000000 --- a/apps/angular/pipe-hard/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-pipe-hard", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/pipe-hard/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/pipe-hard", - "index": "apps/angular/pipe-hard/src/index.html", - "main": "apps/angular/pipe-hard/src/main.ts", - "polyfills": "apps/angular/pipe-hard/src/polyfills.ts", - "tsConfig": "apps/angular/pipe-hard/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/pipe-hard/src/favicon.ico", - "apps/angular/pipe-hard/src/assets" - ], - "styles": ["apps/angular/pipe-hard/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-pipe-hard:build:production" - }, - "development": { - "buildTarget": "angular-pipe-hard:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-pipe-hard:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/pipe-hard/**/*.ts", - "apps/angular/pipe-hard/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/pipe-hard/src/app/app.component.ts b/apps/angular/pipe-hard/src/app/app.component.ts deleted file mode 100644 index d91fc7436..000000000 --- a/apps/angular/pipe-hard/src/app/app.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { NgFor } from '@angular/common'; -import { Component } from '@angular/core'; -import { PersonUtils } from './person.utils'; - -@Component({ - standalone: true, - imports: [NgFor], - selector: 'app-root', - template: ` -
- {{ activity.name }} : -
- {{ showName(person.name, index) }} - {{ isAllowed(person.age, isFirst, activity.minimumAge) }} -
-
- `, -}) -export class AppComponent { - persons = [ - { name: 'Toto', age: 10 }, - { name: 'Jack', age: 15 }, - { name: 'John', age: 30 }, - ]; - - activities = [ - { name: 'biking', minimumAge: 12 }, - { name: 'hiking', minimumAge: 25 }, - { name: 'dancing', minimumAge: 1 }, - ]; - - showName = PersonUtils.showName; - - isAllowed = PersonUtils.isAllowed; -} diff --git a/apps/angular/pipe-hard/src/index.html b/apps/angular/pipe-hard/src/index.html deleted file mode 100644 index 0b81de34b..000000000 --- a/apps/angular/pipe-hard/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - PipeHard - - - - - - - - diff --git a/apps/angular/pipe-intermediate/README.md b/apps/angular/pipe-intermediate/README.md deleted file mode 100644 index 72809fd19..000000000 --- a/apps/angular/pipe-intermediate/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Wrap Function Pipe - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-pipe-intermediate -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/9-pipe-wrapFn/). diff --git a/apps/angular/pipe-intermediate/project.json b/apps/angular/pipe-intermediate/project.json deleted file mode 100644 index e12928037..000000000 --- a/apps/angular/pipe-intermediate/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-pipe-intermediate", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/pipe-intermediate/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/pipe-intermediate", - "index": "apps/angular/pipe-intermediate/src/index.html", - "main": "apps/angular/pipe-intermediate/src/main.ts", - "polyfills": "apps/angular/pipe-intermediate/src/polyfills.ts", - "tsConfig": "apps/angular/pipe-intermediate/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/pipe-intermediate/src/favicon.ico", - "apps/angular/pipe-intermediate/src/assets" - ], - "styles": ["apps/angular/pipe-intermediate/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-pipe-intermediate:build:production" - }, - "development": { - "buildTarget": "angular-pipe-intermediate:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-pipe-intermediate:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/pipe-intermediate/**/*.ts", - "apps/angular/pipe-intermediate/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/pipe-intermediate/src/app/app.component.ts b/apps/angular/pipe-intermediate/src/app/app.component.ts deleted file mode 100644 index d9c163c93..000000000 --- a/apps/angular/pipe-intermediate/src/app/app.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { NgFor } from '@angular/common'; -import { Component } from '@angular/core'; - -@Component({ - standalone: true, - imports: [NgFor], - selector: 'app-root', - template: ` -
- {{ showName(person.name, index) }} - {{ isAllowed(person.age, isFirst) }} -
- `, -}) -export class AppComponent { - persons = [ - { name: 'Toto', age: 10 }, - { name: 'Jack', age: 15 }, - { name: 'John', age: 30 }, - ]; - - showName(name: string, index: number) { - // very heavy computation - return `${name} - ${index}`; - } - - isAllowed(age: number, isFirst: boolean) { - if (isFirst) { - return 'always allowed'; - } else { - return age > 25 ? 'allowed' : 'declined'; - } - } -} diff --git a/apps/angular/pipe-intermediate/src/index.html b/apps/angular/pipe-intermediate/src/index.html deleted file mode 100644 index 1a8b2ee22..000000000 --- a/apps/angular/pipe-intermediate/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - PipeIntermediate - - - - - - - - diff --git a/apps/angular/projection/jest.config.ts b/apps/angular/projection/jest.config.ts deleted file mode 100644 index 2af97a39a..000000000 --- a/apps/angular/projection/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'angular-projection', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/apps/angular/projection', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/angular/projection/project.json b/apps/angular/projection/project.json deleted file mode 100644 index f1d4943d3..000000000 --- a/apps/angular/projection/project.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "angular-projection", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/projection/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:application", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/projection", - "index": "apps/angular/projection/src/index.html", - "browser": "apps/angular/projection/src/main.ts", - "polyfills": ["apps/angular/projection/src/polyfills.ts"], - "tsConfig": "apps/angular/projection/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/projection/src/favicon.ico", - "apps/angular/projection/src/assets" - ], - "styles": ["apps/angular/projection/src/styles.scss"], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-projection:build:production" - }, - "development": { - "buildTarget": "angular-projection:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-projection:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/angular/projection/**/*.ts", - "apps/angular/projection/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/angular/projection/jest.config.ts" - } - } - }, - "tags": [] -} diff --git a/apps/angular/projection/src/app/app.component.ts b/apps/angular/projection/src/app/app.component.ts deleted file mode 100644 index b1d076a9f..000000000 --- a/apps/angular/projection/src/app/app.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component } from '@angular/core'; -import { CityCardComponent } from './component/city-card/city-card.component'; -import { StudentCardComponent } from './component/student-card/student-card.component'; -import { TeacherCardComponent } from './component/teacher-card/teacher-card.component'; - -@Component({ - selector: 'app-root', - template: ` -
- - - -
- `, - standalone: true, - imports: [TeacherCardComponent, StudentCardComponent, CityCardComponent], -}) -export class AppComponent {} diff --git a/apps/angular/projection/src/app/component/city-card/city-card.component.ts b/apps/angular/projection/src/app/component/city-card/city-card.component.ts deleted file mode 100644 index 30c8f88ec..000000000 --- a/apps/angular/projection/src/app/component/city-card/city-card.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -@Component({ - selector: 'app-city-card', - template: 'TODO City', - standalone: true, - imports: [], -}) -export class CityCardComponent implements OnInit { - constructor() {} - - ngOnInit(): void {} -} diff --git a/apps/angular/projection/src/app/component/student-card/student-card.component.ts b/apps/angular/projection/src/app/component/student-card/student-card.component.ts deleted file mode 100644 index 441cda189..000000000 --- a/apps/angular/projection/src/app/component/student-card/student-card.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; -import { StudentStore } from '../../data-access/student.store'; -import { CardType } from '../../model/card.model'; -import { Student } from '../../model/student.model'; -import { CardComponent } from '../../ui/card/card.component'; - -@Component({ - selector: 'app-student-card', - template: ` - - `, - standalone: true, - styles: [ - ` - ::ng-deep .bg-light-green { - background-color: rgba(0, 250, 0, 0.1); - } - `, - ], - imports: [CardComponent], -}) -export class StudentCardComponent implements OnInit { - students: Student[] = []; - cardType = CardType.STUDENT; - - constructor( - private http: FakeHttpService, - private store: StudentStore, - ) {} - - ngOnInit(): void { - this.http.fetchStudents$.subscribe((s) => this.store.addAll(s)); - - this.store.students$.subscribe((s) => (this.students = s)); - } -} diff --git a/apps/angular/projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/projection/src/app/component/teacher-card/teacher-card.component.ts deleted file mode 100644 index 995cb7c2f..000000000 --- a/apps/angular/projection/src/app/component/teacher-card/teacher-card.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; -import { TeacherStore } from '../../data-access/teacher.store'; -import { CardType } from '../../model/card.model'; -import { Teacher } from '../../model/teacher.model'; -import { CardComponent } from '../../ui/card/card.component'; - -@Component({ - selector: 'app-teacher-card', - template: ` - - `, - styles: [ - ` - ::ng-deep .bg-light-red { - background-color: rgba(250, 0, 0, 0.1); - } - `, - ], - standalone: true, - imports: [CardComponent], -}) -export class TeacherCardComponent implements OnInit { - teachers: Teacher[] = []; - cardType = CardType.TEACHER; - - constructor( - private http: FakeHttpService, - private store: TeacherStore, - ) {} - - ngOnInit(): void { - this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t)); - - this.store.teachers$.subscribe((t) => (this.teachers = t)); - } -} diff --git a/apps/angular/projection/src/app/data-access/city.store.ts b/apps/angular/projection/src/app/data-access/city.store.ts deleted file mode 100644 index 711dad1d7..000000000 --- a/apps/angular/projection/src/app/data-access/city.store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { City } from '../model/city.model'; - -@Injectable({ - providedIn: 'root', -}) -export class CityStore { - private cities = new BehaviorSubject([]); - cities$ = this.cities.asObservable(); - - addAll(cities: City[]) { - this.cities.next(cities); - } - - addOne(student: City) { - this.cities.next([...this.cities.value, student]); - } - - deleteOne(id: number) { - this.cities.next(this.cities.value.filter((s) => s.id !== id)); - } -} diff --git a/apps/angular/projection/src/app/data-access/student.store.ts b/apps/angular/projection/src/app/data-access/student.store.ts deleted file mode 100644 index 7918118c3..000000000 --- a/apps/angular/projection/src/app/data-access/student.store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { Student } from '../model/student.model'; - -@Injectable({ - providedIn: 'root', -}) -export class StudentStore { - private students = new BehaviorSubject([]); - students$ = this.students.asObservable(); - - addAll(students: Student[]) { - this.students.next(students); - } - - addOne(student: Student) { - this.students.next([...this.students.value, student]); - } - - deleteOne(id: number) { - this.students.next(this.students.value.filter((s) => s.id !== id)); - } -} diff --git a/apps/angular/projection/src/app/data-access/teacher.store.ts b/apps/angular/projection/src/app/data-access/teacher.store.ts deleted file mode 100644 index 93f68c4b1..000000000 --- a/apps/angular/projection/src/app/data-access/teacher.store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { Teacher } from '../model/teacher.model'; - -@Injectable({ - providedIn: 'root', -}) -export class TeacherStore { - private teachers = new BehaviorSubject([]); - teachers$ = this.teachers.asObservable(); - - addAll(teachers: Teacher[]) { - this.teachers.next(teachers); - } - - addOne(teacher: Teacher) { - this.teachers.next([...this.teachers.value, teacher]); - } - - deleteOne(id: number) { - this.teachers.next(this.teachers.value.filter((t) => t.id !== id)); - } -} diff --git a/apps/angular/projection/src/app/ui/card/card.component.ts b/apps/angular/projection/src/app/ui/card/card.component.ts deleted file mode 100644 index f06c9ae00..000000000 --- a/apps/angular/projection/src/app/ui/card/card.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { NgFor, NgIf } from '@angular/common'; -import { Component, Input } from '@angular/core'; -import { randStudent, randTeacher } from '../../data-access/fake-http.service'; -import { StudentStore } from '../../data-access/student.store'; -import { TeacherStore } from '../../data-access/teacher.store'; -import { CardType } from '../../model/card.model'; -import { ListItemComponent } from '../list-item/list-item.component'; - -@Component({ - selector: 'app-card', - template: ` -
- - - -
- -
- - -
- `, - standalone: true, - imports: [NgIf, NgFor, ListItemComponent], -}) -export class CardComponent { - @Input() list: any[] | null = null; - @Input() type!: CardType; - @Input() customClass = ''; - - CardType = CardType; - - constructor( - private teacherStore: TeacherStore, - private studentStore: StudentStore, - ) {} - - addNewItem() { - if (this.type === CardType.TEACHER) { - this.teacherStore.addOne(randTeacher()); - } else if (this.type === CardType.STUDENT) { - this.studentStore.addOne(randStudent()); - } - } -} diff --git a/apps/angular/projection/src/app/ui/list-item/list-item.component.ts b/apps/angular/projection/src/app/ui/list-item/list-item.component.ts deleted file mode 100644 index c0f9cff7f..000000000 --- a/apps/angular/projection/src/app/ui/list-item/list-item.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { StudentStore } from '../../data-access/student.store'; -import { TeacherStore } from '../../data-access/teacher.store'; -import { CardType } from '../../model/card.model'; - -@Component({ - selector: 'app-list-item', - template: ` -
- {{ name }} - -
- `, - standalone: true, -}) -export class ListItemComponent { - @Input() id!: number; - @Input() name!: string; - @Input() type!: CardType; - - constructor( - private teacherStore: TeacherStore, - private studentStore: StudentStore, - ) {} - - delete(id: number) { - if (this.type === CardType.TEACHER) { - this.teacherStore.deleteOne(id); - } else if (this.type === CardType.STUDENT) { - this.studentStore.deleteOne(id); - } - } -} diff --git a/apps/angular/projection/src/index.html b/apps/angular/projection/src/index.html deleted file mode 100644 index 7f19c5dfd..000000000 --- a/apps/angular/projection/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Projection - - - - - - - - diff --git a/apps/angular/projection/src/main.ts b/apps/angular/projection/src/main.ts deleted file mode 100644 index 9cd15da95..000000000 --- a/apps/angular/projection/src/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { bootstrapApplication } from '@angular/platform-browser'; -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent); diff --git a/apps/angular/router-input/project.json b/apps/angular/router-input/project.json deleted file mode 100644 index f76728ef1..000000000 --- a/apps/angular/router-input/project.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "name": "angular-router-input", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/router-input/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/router-input", - "index": "apps/angular/router-input/src/index.html", - "main": "apps/angular/router-input/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/router-input/tsconfig.app.json", - "assets": [ - "apps/angular/router-input/src/favicon.ico", - "apps/angular/router-input/src/assets" - ], - "styles": ["apps/angular/router-input/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-router-input:build:production" - }, - "development": { - "buildTarget": "angular-router-input:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-router-input:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/router-input/**/*.ts", - "apps/angular/router-input/**/*.html" - ] - } - } - } -} diff --git a/apps/angular/router-input/src/app/app.component.ts b/apps/angular/router-input/src/app/app.component.ts deleted file mode 100644 index 1ef7e32aa..000000000 --- a/apps/angular/router-input/src/app/app.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { RouterLink, RouterModule } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterLink, RouterModule, ReactiveFormsModule], - selector: 'app-root', - template: ` - - - - - - - - `, -}) -export class AppComponent { - userName = new FormControl(); - testId = new FormControl(); -} diff --git a/apps/angular/router-input/src/app/home.component.ts b/apps/angular/router-input/src/app/home.component.ts deleted file mode 100644 index 2ef8c5eb4..000000000 --- a/apps/angular/router-input/src/app/home.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from '@angular/core'; -@Component({ - selector: 'app-home', - standalone: true, - imports: [], - template: ` -
Home
- `, -}) -export default class HomeComponent {} diff --git a/apps/angular/router-input/src/index.html b/apps/angular/router-input/src/index.html deleted file mode 100644 index daa121537..000000000 --- a/apps/angular/router-input/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - router-input - - - - - - - - diff --git a/apps/angular/signal-input/README.md b/apps/angular/signal-input/README.md deleted file mode 100644 index 78ef74d74..000000000 --- a/apps/angular/signal-input/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Signal Input - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-signal-input -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/43-signal-input/). diff --git a/apps/angular/signal-input/project.json b/apps/angular/signal-input/project.json deleted file mode 100644 index 00f1a6797..000000000 --- a/apps/angular/signal-input/project.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "angular-signal-input", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/signal-input/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:application", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/signal-input", - "index": "apps/angular/signal-input/src/index.html", - "browser": "apps/angular/signal-input/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/signal-input/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/signal-input/src/favicon.ico", - "apps/angular/signal-input/src/assets" - ], - "styles": ["apps/angular/signal-input/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-signal-input:build:production" - }, - "development": { - "buildTarget": "angular-signal-input:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-signal-input:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"] - } - } -} diff --git a/apps/angular/signal-input/src/app/app.component.ts b/apps/angular/signal-input/src/app/app.component.ts deleted file mode 100644 index 22e64386e..000000000 --- a/apps/angular/signal-input/src/app/app.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { JsonPipe } from '@angular/common'; -import { Component } from '@angular/core'; -import { UserComponent } from './user.component'; - -@Component({ - standalone: true, - imports: [UserComponent, JsonPipe], - selector: 'app-root', - template: ` -
-
- Name: - - @if (showUser && !name.value) { -
name required
- } -
-
- LastName: - -
-
- Age: - -
- -
- @if (showUser && !!name.value) { - - } - `, - host: { - class: 'p-10 block flex flex-col gap-10', - }, -}) -export class AppComponent { - showUser = false; -} diff --git a/apps/angular/signal-input/src/index.html b/apps/angular/signal-input/src/index.html deleted file mode 100644 index 4fc2af8ca..000000000 --- a/apps/angular/signal-input/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - angular-signal-input - - - - - - - - diff --git a/apps/angular/styling/README.md b/apps/angular/styling/README.md deleted file mode 100644 index d47efe3e8..000000000 --- a/apps/angular/styling/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Highly Customizable CSS - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve angular-styling -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/13-styling/). diff --git a/apps/angular/styling/project.json b/apps/angular/styling/project.json deleted file mode 100644 index 5fdaa3866..000000000 --- a/apps/angular/styling/project.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "name": "angular-styling", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/angular/styling/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/styling", - "index": "apps/angular/styling/src/index.html", - "main": "apps/angular/styling/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/styling/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/styling/src/favicon.ico", - "apps/angular/styling/src/assets" - ], - "styles": ["apps/angular/styling/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-styling:build:production" - }, - "development": { - "buildTarget": "angular-styling:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-styling:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/angular/styling/**/*.ts", - "apps/angular/styling/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/angular/styling/src/app/page.component.ts b/apps/angular/styling/src/app/page.component.ts deleted file mode 100644 index 067453294..000000000 --- a/apps/angular/styling/src/app/page.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { Component } from '@angular/core'; -import { TextStaticComponent } from './static-text.component'; -import { TextComponent } from './text.component'; - -@Component({ - selector: 'page', - standalone: true, - imports: [TextStaticComponent, TextComponent], - template: ` - - - - This is a blue text - `, -}) -export class PageComponent {} diff --git a/apps/angular/styling/src/index.html b/apps/angular/styling/src/index.html deleted file mode 100644 index 7ea1636bf..000000000 --- a/apps/angular/styling/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Styling - - - - - - - - diff --git a/apps/angular/view-transition/project.json b/apps/angular/view-transition/project.json deleted file mode 100644 index d0a27fd5f..000000000 --- a/apps/angular/view-transition/project.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "angular-view-transition", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/angular/view-transition/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:application", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/angular/view-transition", - "index": "apps/angular/view-transition/src/index.html", - "browser": "apps/angular/view-transition/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/angular/view-transition/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/angular/view-transition/src/favicon.ico", - "apps/angular/view-transition/src/assets" - ], - "styles": ["apps/angular/view-transition/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "angular-view-transition:build:production" - }, - "development": { - "buildTarget": "angular-view-transition:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "angular-view-transition:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"] - } - } -} diff --git a/apps/angular/view-transition/src/app/app.component.ts b/apps/angular/view-transition/src/app/app.component.ts deleted file mode 100644 index da56c04c0..000000000 --- a/apps/angular/view-transition/src/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet], - selector: 'app-root', - template: ` - - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AppComponent {} diff --git a/apps/angular/view-transition/src/app/post/post.component.ts b/apps/angular/view-transition/src/app/post/post.component.ts deleted file mode 100644 index 1e1c6fd89..000000000 --- a/apps/angular/view-transition/src/app/post/post.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { NgOptimizedImage } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - computed, - input, -} from '@angular/core'; -import { RouterLink } from '@angular/router'; -import { ThumbnailHeaderComponent } from '../blog/thumbnail-header.component'; -import { fakeTextChapters, posts } from '../data'; -import { PostHeaderComponent } from './post-header.component'; - -@Component({ - selector: 'post', - standalone: true, - imports: [ - ThumbnailHeaderComponent, - NgOptimizedImage, - PostHeaderComponent, - RouterLink, - ], - template: ` -
- - -

{{ post().title }}

- - @for (chapter of fakeTextChapter; track $index) { -

{{ chapter }}

- } -
- `, - host: { - class: 'flex h-full justify-center', - }, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export default class PostComponent { - id = input.required(); - post = computed(() => posts.filter((p) => p.id === this.id())[0]); - - fakeTextChapter = fakeTextChapters; -} diff --git a/apps/angular/view-transition/src/styles.scss b/apps/angular/view-transition/src/styles.scss deleted file mode 100644 index a90f0749c..000000000 --- a/apps/angular/view-transition/src/styles.scss +++ /dev/null @@ -1,4 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - diff --git a/apps/angular/view-transition/tsconfig.json b/apps/angular/view-transition/tsconfig.json deleted file mode 100644 index db0ec0f25..000000000 --- a/apps/angular/view-transition/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "useDefineForClassFields": false, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json", - }, - { - "path": "./tsconfig.editor.json", - }, - ], - "extends": "../../../tsconfig.base.json", - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true, - }, -} diff --git a/apps/forms/41-control-value-accessor/.eslintrc.json b/apps/forms/41-control-value-accessor/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/forms/41-control-value-accessor/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/forms/control-value-accessor/README.md b/apps/forms/41-control-value-accessor/README.md similarity index 100% rename from apps/forms/control-value-accessor/README.md rename to apps/forms/41-control-value-accessor/README.md diff --git a/apps/forms/41-control-value-accessor/jest.config.ts b/apps/forms/41-control-value-accessor/jest.config.ts new file mode 100644 index 000000000..48769acef --- /dev/null +++ b/apps/forms/41-control-value-accessor/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'forms-control-value-accessor', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/forms/41-control-value-accessor', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/forms/41-control-value-accessor/project.json b/apps/forms/41-control-value-accessor/project.json new file mode 100644 index 000000000..a1ec26bac --- /dev/null +++ b/apps/forms/41-control-value-accessor/project.json @@ -0,0 +1,80 @@ +{ + "name": "forms-control-value-accessor", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/forms/41-control-value-accessor/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/forms/41-control-value-accessor", + "index": "apps/forms/41-control-value-accessor/src/index.html", + "browser": "apps/forms/41-control-value-accessor/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/forms/41-control-value-accessor/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/forms/41-control-value-accessor/src/favicon.ico", + "apps/forms/41-control-value-accessor/src/assets" + ], + "styles": ["apps/forms/41-control-value-accessor/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "forms-control-value-accessor:build:production" + }, + "development": { + "buildTarget": "forms-control-value-accessor:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "forms-control-value-accessor:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/forms/41-control-value-accessor/src/app/app.component.ts b/apps/forms/41-control-value-accessor/src/app/app.component.ts new file mode 100644 index 000000000..69134b864 --- /dev/null +++ b/apps/forms/41-control-value-accessor/src/app/app.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { FeedbackFormComponent } from './feedback-form/feedback-form.component'; + +@Component({ + imports: [FeedbackFormComponent], + selector: 'app-root', + template: ` + + `, +}) +export class AppComponent { + apiCall(event: Record): void { + console.log(event); + } +} diff --git a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.html b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.html similarity index 100% rename from apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.html rename to apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.html diff --git a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.scss b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.scss similarity index 100% rename from apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.scss rename to apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.scss diff --git a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.ts b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts similarity index 98% rename from apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.ts rename to apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts index d99700db1..4110d6cf7 100644 --- a/apps/forms/control-value-accessor/src/app/feedback-form/feedback-form.component.ts +++ b/apps/forms/41-control-value-accessor/src/app/feedback-form/feedback-form.component.ts @@ -8,7 +8,6 @@ import { import { RatingControlComponent } from '../rating-control/rating-control.component'; @Component({ - standalone: true, imports: [RatingControlComponent, ReactiveFormsModule], selector: 'app-feedback-form', templateUrl: 'feedback-form.component.html', diff --git a/apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.html b/apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.html similarity index 100% rename from apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.html rename to apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.html diff --git a/apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.scss b/apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.scss similarity index 100% rename from apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.scss rename to apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.scss diff --git a/apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.ts b/apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.ts similarity index 100% rename from apps/forms/control-value-accessor/src/app/rating-control/rating-control.component.ts rename to apps/forms/41-control-value-accessor/src/app/rating-control/rating-control.component.ts diff --git a/apps/ngrx/effect-selector/src/assets/.gitkeep b/apps/forms/41-control-value-accessor/src/assets/.gitkeep similarity index 100% rename from apps/ngrx/effect-selector/src/assets/.gitkeep rename to apps/forms/41-control-value-accessor/src/assets/.gitkeep diff --git a/apps/performance/christmas-web-worker/src/favicon.ico b/apps/forms/41-control-value-accessor/src/favicon.ico similarity index 100% rename from apps/performance/christmas-web-worker/src/favicon.ico rename to apps/forms/41-control-value-accessor/src/favicon.ico diff --git a/apps/forms/control-value-accessor/src/index.html b/apps/forms/41-control-value-accessor/src/index.html similarity index 100% rename from apps/forms/control-value-accessor/src/index.html rename to apps/forms/41-control-value-accessor/src/index.html diff --git a/apps/performance/christmas-web-worker/src/main.ts b/apps/forms/41-control-value-accessor/src/main.ts similarity index 100% rename from apps/performance/christmas-web-worker/src/main.ts rename to apps/forms/41-control-value-accessor/src/main.ts diff --git a/apps/performance/memoized/src/styles.scss b/apps/forms/41-control-value-accessor/src/styles.scss similarity index 100% rename from apps/performance/memoized/src/styles.scss rename to apps/forms/41-control-value-accessor/src/styles.scss diff --git a/apps/testing/checkbox/src/test-setup.ts b/apps/forms/41-control-value-accessor/src/test-setup.ts similarity index 100% rename from apps/testing/checkbox/src/test-setup.ts rename to apps/forms/41-control-value-accessor/src/test-setup.ts diff --git a/apps/performance/ngfor-biglist/tailwind.config.js b/apps/forms/41-control-value-accessor/tailwind.config.js similarity index 100% rename from apps/performance/ngfor-biglist/tailwind.config.js rename to apps/forms/41-control-value-accessor/tailwind.config.js diff --git a/apps/performance/ngfor-biglist/tsconfig.app.json b/apps/forms/41-control-value-accessor/tsconfig.app.json similarity index 100% rename from apps/performance/ngfor-biglist/tsconfig.app.json rename to apps/forms/41-control-value-accessor/tsconfig.app.json diff --git a/apps/performance/ngfor-optimize/tsconfig.editor.json b/apps/forms/41-control-value-accessor/tsconfig.editor.json similarity index 100% rename from apps/performance/ngfor-optimize/tsconfig.editor.json rename to apps/forms/41-control-value-accessor/tsconfig.editor.json diff --git a/apps/forms/41-control-value-accessor/tsconfig.json b/apps/forms/41-control-value-accessor/tsconfig.json new file mode 100644 index 000000000..25ca437b4 --- /dev/null +++ b/apps/forms/41-control-value-accessor/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + }, + { + "path": "./tsconfig.editor.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/forms/41-control-value-accessor/tsconfig.spec.json b/apps/forms/41-control-value-accessor/tsconfig.spec.json new file mode 100644 index 000000000..1a4817a7d --- /dev/null +++ b/apps/forms/41-control-value-accessor/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node", "@testing-library/jest-dom"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/forms/48-avoid-losing-form-data/.eslintrc.json b/apps/forms/48-avoid-losing-form-data/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/forms/48-avoid-losing-form-data/README.md b/apps/forms/48-avoid-losing-form-data/README.md new file mode 100644 index 000000000..1c0e90b35 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/README.md @@ -0,0 +1,11 @@ +# Avoid losing form data + +> author: [Timothy Alcaide](https://github.com/alcaidio) + +### Run Application + +```bash +npx nx serve forms-avoid-losing-form-data +``` + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/forms/48-forms-avoid-losing-form-data/). diff --git a/apps/forms/48-avoid-losing-form-data/project.json b/apps/forms/48-avoid-losing-form-data/project.json new file mode 100644 index 000000000..9517d3123 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/project.json @@ -0,0 +1,72 @@ +{ + "name": "forms-avoid-losing-form-data", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/forms/48-avoid-losing-form-data/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/forms/48-avoid-losing-form-data", + "index": "apps/forms/48-avoid-losing-form-data/src/index.html", + "browser": "apps/forms/48-avoid-losing-form-data/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/forms/48-avoid-losing-form-data/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/forms/48-avoid-losing-form-data/src/favicon.ico", + "apps/forms/48-avoid-losing-form-data/src/assets" + ], + "styles": [ + "apps/forms/48-avoid-losing-form-data/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "forms-avoid-losing-form-data:build:production" + }, + "development": { + "buildTarget": "forms-avoid-losing-form-data:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "forms-avoid-losing-form-data:build" + } + } + } +} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.component.ts new file mode 100644 index 000000000..2b5adc443 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/app.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { NavComponent } from './ui/nav.component'; + +@Component({ + imports: [RouterOutlet, NavComponent], + selector: 'app-root', + template: ` +
+ + +
+ +
+
+ `, +}) +export class AppComponent {} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.config.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.config.ts new file mode 100644 index 000000000..a7c1007b9 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/app.config.ts @@ -0,0 +1,7 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideRouter, withComponentInputBinding } from '@angular/router'; +import { appRoutes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [provideRouter(appRoutes, withComponentInputBinding())], +}; diff --git a/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts b/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts new file mode 100644 index 000000000..84be34b9a --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/app.routes.ts @@ -0,0 +1,29 @@ +import { Route } from '@angular/router'; +import { JoinComponent } from './pages/join.component'; +import { PageComponent } from './pages/page.component'; + +export const appRoutes: Route[] = [ + { + path: '', + pathMatch: 'full', + redirectTo: 'form', + }, + { + path: 'form', + loadComponent: () => JoinComponent, + }, + { + path: 'page-1', + data: { + title: 'Page 1', + }, + loadComponent: () => PageComponent, + }, + { + path: 'page-2', + data: { + title: 'Page 2', + }, + loadComponent: () => PageComponent, + }, +]; diff --git a/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts new file mode 100644 index 000000000..51449a7fb --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/pages/join.component.ts @@ -0,0 +1,15 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormComponent } from '../ui/form.component'; + +@Component({ + imports: [FormComponent], + template: ` +
+
+ +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class JoinComponent {} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/pages/page.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/pages/page.component.ts new file mode 100644 index 000000000..13f4e09c2 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/pages/page.component.ts @@ -0,0 +1,14 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +@Component({ + standalone: true, + template: ` +
+

{{ title() }}

+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PageComponent { + title = input.required(); +} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts new file mode 100644 index 000000000..661da9bcf --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/dialog.component.ts @@ -0,0 +1,30 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +// NOTE : this is just the dialog content, you need to implement dialog logic + +@Component({ + standalone: true, + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AlertDialogComponent {} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/form.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/form.component.ts new file mode 100644 index 000000000..f3190d517 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/form.component.ts @@ -0,0 +1,77 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-form', + imports: [ReactiveFormsModule], + template: ` +
+
+ + +
+ +
+
+ + +
+ +
+ + +
+
+ +
+ + + +
+ +
+ +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FormComponent { + private fb = inject(FormBuilder); + + form = this.fb.nonNullable.group({ + name: ['', { validators: [Validators.required] }], + email: ['', [Validators.required, Validators.email]], // other syntax + phone: '', + message: '', + }); + + onSubmit() { + if (this.form.valid) this.form.reset(); + } +} diff --git a/apps/forms/48-avoid-losing-form-data/src/app/ui/nav.component.ts b/apps/forms/48-avoid-losing-form-data/src/app/ui/nav.component.ts new file mode 100644 index 000000000..269297280 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/app/ui/nav.component.ts @@ -0,0 +1,32 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-nav', + imports: [RouterLink, RouterLinkActive], + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class NavComponent {} diff --git a/apps/ngrx/notification/src/assets/.gitkeep b/apps/forms/48-avoid-losing-form-data/src/assets/.gitkeep similarity index 100% rename from apps/ngrx/notification/src/assets/.gitkeep rename to apps/forms/48-avoid-losing-form-data/src/assets/.gitkeep diff --git a/apps/performance/default-onpush/src/favicon.ico b/apps/forms/48-avoid-losing-form-data/src/favicon.ico similarity index 100% rename from apps/performance/default-onpush/src/favicon.ico rename to apps/forms/48-avoid-losing-form-data/src/favicon.ico diff --git a/apps/forms/48-avoid-losing-form-data/src/index.html b/apps/forms/48-avoid-losing-form-data/src/index.html new file mode 100644 index 000000000..ed75bb39d --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/src/index.html @@ -0,0 +1,13 @@ + + + + + form-avoid-losing-form-data + + + + + + + + diff --git a/apps/performance/ngfor-optimize/src/main.ts b/apps/forms/48-avoid-losing-form-data/src/main.ts similarity index 100% rename from apps/performance/ngfor-optimize/src/main.ts rename to apps/forms/48-avoid-losing-form-data/src/main.ts diff --git a/apps/performance/ngfor-biglist/src/styles.scss b/apps/forms/48-avoid-losing-form-data/src/styles.scss similarity index 100% rename from apps/performance/ngfor-biglist/src/styles.scss rename to apps/forms/48-avoid-losing-form-data/src/styles.scss diff --git a/apps/forms/48-avoid-losing-form-data/tailwind.config.js b/apps/forms/48-avoid-losing-form-data/tailwind.config.js new file mode 100644 index 000000000..16f83c7f4 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [require('@tailwindcss/forms')], +}; diff --git a/apps/performance/ngfor-optimize/tsconfig.app.json b/apps/forms/48-avoid-losing-form-data/tsconfig.app.json similarity index 100% rename from apps/performance/ngfor-optimize/tsconfig.app.json rename to apps/forms/48-avoid-losing-form-data/tsconfig.app.json diff --git a/apps/forms/48-avoid-losing-form-data/tsconfig.editor.json b/apps/forms/48-avoid-losing-form-data/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/forms/48-avoid-losing-form-data/tsconfig.json b/apps/forms/48-avoid-losing-form-data/tsconfig.json new file mode 100644 index 000000000..3df17b921 --- /dev/null +++ b/apps/forms/48-avoid-losing-form-data/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/forms/control-value-accessor/jest.config.ts b/apps/forms/control-value-accessor/jest.config.ts deleted file mode 100644 index a52c89870..000000000 --- a/apps/forms/control-value-accessor/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'forms-control-value-accessor', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/forms/control-value-accessor', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/forms/control-value-accessor/project.json b/apps/forms/control-value-accessor/project.json deleted file mode 100644 index 3f232a934..000000000 --- a/apps/forms/control-value-accessor/project.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "name": "forms-control-value-accessor", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/forms/control-value-accessor/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:application", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/forms/control-value-accessor", - "index": "apps/forms/control-value-accessor/src/index.html", - "browser": "apps/forms/control-value-accessor/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/forms/control-value-accessor/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/forms/control-value-accessor/src/favicon.ico", - "apps/forms/control-value-accessor/src/assets" - ], - "styles": ["apps/forms/control-value-accessor/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "forms-control-value-accessor:build:production" - }, - "development": { - "buildTarget": "forms-control-value-accessor:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "forms-control-value-accessor:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/forms/control-value-accessor/**/*.ts", - "apps/forms/control-value-accessor/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/forms/control-value-accessor/jest.config.ts" - } - } - } -} diff --git a/apps/forms/control-value-accessor/src/app/app.component.ts b/apps/forms/control-value-accessor/src/app/app.component.ts deleted file mode 100644 index f56b5d7d9..000000000 --- a/apps/forms/control-value-accessor/src/app/app.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from '@angular/core'; -import { FeedbackFormComponent } from './feedback-form/feedback-form.component'; - -@Component({ - standalone: true, - imports: [FeedbackFormComponent], - selector: 'app-root', - template: ` - - `, -}) -export class AppComponent { - apiCall(event: Record): void { - console.log(event); - } -} diff --git a/apps/ngrx/effect-selector/README.md b/apps/ngrx/effect-selector/README.md deleted file mode 100644 index b12a5341e..000000000 --- a/apps/ngrx/effect-selector/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Effect vs Selector - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve ngrx-effect-selector -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/ngrx/2-effect-selector/). diff --git a/apps/ngrx/effect-selector/jest.config.ts b/apps/ngrx/effect-selector/jest.config.ts deleted file mode 100644 index 7e97f0ba2..000000000 --- a/apps/ngrx/effect-selector/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'ngrx-effect-selector', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/apps/ngrx/effect-selector', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/ngrx/effect-selector/project.json b/apps/ngrx/effect-selector/project.json deleted file mode 100644 index f050ffaf0..000000000 --- a/apps/ngrx/effect-selector/project.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "ngrx-effect-selector", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/ngrx/effect-selector/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/ngrx/effect-selector", - "index": "apps/ngrx/effect-selector/src/index.html", - "main": "apps/ngrx/effect-selector/src/main.ts", - "polyfills": "apps/ngrx/effect-selector/src/polyfills.ts", - "tsConfig": "apps/ngrx/effect-selector/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/ngrx/effect-selector/src/favicon.ico", - "apps/ngrx/effect-selector/src/assets" - ], - "styles": ["apps/ngrx/effect-selector/src/styles.scss"], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "ngrx-effect-selector:build:production" - }, - "development": { - "buildTarget": "ngrx-effect-selector:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "ngrx-effect-selector:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/ngrx/effect-selector/**/*.ts", - "apps/ngrx/effect-selector/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/ngrx/effect-selector/jest.config.ts" - } - } - }, - "tags": [] -} diff --git a/apps/ngrx/effect-selector/src/app/app.component.ts b/apps/ngrx/effect-selector/src/app/app.component.ts deleted file mode 100644 index 1e4836644..000000000 --- a/apps/ngrx/effect-selector/src/app/app.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { AsyncPipe, NgFor } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - OnInit, - inject, -} from '@angular/core'; -import { Store } from '@ngrx/store'; -import { loadActivities } from './store/activity/activity.actions'; -import { ActivityType } from './store/activity/activity.model'; -import { selectActivities } from './store/activity/activity.selectors'; -import { loadStatuses } from './store/status/status.actions'; -import { selectAllTeachersByActivityType } from './store/status/status.selectors'; -import { loadUsers } from './store/user/user.actions'; - -@Component({ - selector: 'app-root', - standalone: true, - imports: [NgFor, AsyncPipe], - template: ` -

Activity Board

-
-
-

Activity Name: {{ activity.name }}

-

Main teacher: {{ activity.teacher.name }}

- All teachers available for : {{ activity.type }} are -
    -
  • - {{ teacher.name }} -
  • -
-
-
- `, - styles: [ - ` - section { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 2px; - } - - .card { - display: flex; - flex-direction: column; - border: solid; - border-width: 1px; - border-color: black; - padding: 2px; - } - `, - ], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AppComponent implements OnInit { - private store = inject(Store); - - activities$ = this.store.select(selectActivities); - - ngOnInit(): void { - this.store.dispatch(loadActivities()); - this.store.dispatch(loadUsers()); - this.store.dispatch(loadStatuses()); - } - - getAllTeachersForActivityType$ = (type: ActivityType) => - this.store.select(selectAllTeachersByActivityType(type)); -} diff --git a/apps/ngrx/effect-selector/src/app/app.config.ts b/apps/ngrx/effect-selector/src/app/app.config.ts deleted file mode 100644 index d59c436ed..000000000 --- a/apps/ngrx/effect-selector/src/app/app.config.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ApplicationConfig } from '@angular/core'; -import { provideEffects } from '@ngrx/effects'; -import { provideStore } from '@ngrx/store'; -import { ActivityEffects } from './store/activity/activity.effects'; -import { - activityFeatureKey, - activityReducer, -} from './store/activity/activity.reducer'; -import { StatusEffects } from './store/status/status.effects'; -import { UserEffects } from './store/user/user.effects'; - -import { statusFeatureKey, statusReducer } from './store/status/status.reducer'; - -import { userFeatureKey, userReducer } from './store/user/user.reducer'; - -const reducers = { - [statusFeatureKey]: statusReducer, - [activityFeatureKey]: activityReducer, - [userFeatureKey]: userReducer, -}; - -export const appConfig: ApplicationConfig = { - providers: [ - provideStore(reducers), - provideEffects([ActivityEffects, UserEffects, StatusEffects]), - ], -}; diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.actions.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.actions.ts deleted file mode 100644 index c8affff54..000000000 --- a/apps/ngrx/effect-selector/src/app/store/activity/activity.actions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createAction, props } from '@ngrx/store'; -import { Activity } from './activity.model'; - -export const loadActivities = createAction('[Activity Effect] Load Activities'); - -export const loadActivitiesSuccess = createAction( - '[Activity Effect] Load Activities Success', - props<{ activities: Activity[] }>(), -); - -export const loadActivitiesFailure = createAction( - '[Activity Effect] Load Activities Failure', - props<{ error: unknown }>(), -); diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.effects.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.effects.ts deleted file mode 100644 index 88f8b2317..000000000 --- a/apps/ngrx/effect-selector/src/app/store/activity/activity.effects.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { of } from 'rxjs'; -import { catchError, concatMap, map } from 'rxjs/operators'; -import * as ActivityActions from './activity.actions'; -import { ActivityService } from './activity.service'; - -@Injectable() -export class ActivityEffects { - loadActivities$ = createEffect(() => { - return this.actions$.pipe( - ofType(ActivityActions.loadActivities), - concatMap(() => - this.ActivityService.fetchActivities().pipe( - map((activities) => - ActivityActions.loadActivitiesSuccess({ activities }), - ), - catchError((error) => - of(ActivityActions.loadActivitiesFailure({ error })), - ), - ), - ), - ); - }); - - constructor( - private actions$: Actions, - private ActivityService: ActivityService, - ) {} -} diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.model.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.model.ts deleted file mode 100644 index 75f188132..000000000 --- a/apps/ngrx/effect-selector/src/app/store/activity/activity.model.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - incrementalNumber, - rand, - randFirstName, - randText, -} from '@ngneat/falso'; - -export const activityType = [ - 'Sport', - 'Sciences', - 'History', - 'Maths', - 'Physics', -] as const; -export type ActivityType = (typeof activityType)[number]; - -export interface Person { - id: number; - name: string; -} - -export interface Activity { - id: number; - name: string; - type: ActivityType; - teacher: Person; -} - -const factoryPerson = incrementalNumber(); - -export const randPerson = () => ({ - id: factoryPerson(), - name: randFirstName(), -}); - -const factoryActivity = incrementalNumber(); - -export const randActivity = (): Activity => ({ - id: factoryActivity(), - name: randText(), - type: rand(activityType), - teacher: randPerson(), -}); - -export const activities: Activity[] = [ - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), -]; diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.reducer.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.reducer.ts deleted file mode 100644 index b7285e8f6..000000000 --- a/apps/ngrx/effect-selector/src/app/store/activity/activity.reducer.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createReducer, on } from '@ngrx/store'; -import * as ActivityActions from './activity.actions'; -import { Activity } from './activity.model'; - -export const activityFeatureKey = 'Activity'; - -export interface ActivityState { - activities: Activity[]; -} - -export const initialState: ActivityState = { - activities: [], -}; - -export const activityReducer = createReducer( - initialState, - on(ActivityActions.loadActivitiesSuccess, (state, { activities }) => ({ - ...state, - activities, - })), - on(ActivityActions.loadActivitiesFailure, (state) => ({ - state, - activities: [], - })), -); diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.selectors.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.selectors.ts deleted file mode 100644 index 6c6a25a65..000000000 --- a/apps/ngrx/effect-selector/src/app/store/activity/activity.selectors.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { ActivityState, activityFeatureKey } from './activity.reducer'; - -export const selectActivityState = - createFeatureSelector(activityFeatureKey); - -export const selectActivities = createSelector( - selectActivityState, - (state) => state.activities, -); diff --git a/apps/ngrx/effect-selector/src/app/store/activity/activity.service.ts b/apps/ngrx/effect-selector/src/app/store/activity/activity.service.ts deleted file mode 100644 index 07aa8f8ad..000000000 --- a/apps/ngrx/effect-selector/src/app/store/activity/activity.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@angular/core'; -import { map, timer } from 'rxjs'; -import { activities } from './activity.model'; - -@Injectable({ - providedIn: 'root', -}) -export class ActivityService { - fetchActivities = () => timer(500).pipe(map(() => activities)); -} diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.actions.ts b/apps/ngrx/effect-selector/src/app/store/status/status.actions.ts deleted file mode 100644 index 8fc2ddc49..000000000 --- a/apps/ngrx/effect-selector/src/app/store/status/status.actions.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createAction, props } from '@ngrx/store'; -import { Status } from './status.model'; - -export const loadStatuses = createAction('[Status] Load Statuses'); - -export const loadStatusesSuccess = createAction( - '[Status] Load Statuses Success', - props<{ statuses: Status[] }>(), -); diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.effects.ts b/apps/ngrx/effect-selector/src/app/store/status/status.effects.ts deleted file mode 100644 index 997eb0c1f..000000000 --- a/apps/ngrx/effect-selector/src/app/store/status/status.effects.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; -import { combineLatest, concatMap, map } from 'rxjs'; -import { selectActivities } from '../activity/activity.selectors'; -import { selectUser } from '../user/user.selectors'; -import * as StatusActions from './status.actions'; -import { Status } from './status.model'; - -@Injectable() -export class StatusEffects { - loadStatuses$ = createEffect(() => { - return this.actions$.pipe( - ofType(StatusActions.loadStatuses), - concatMap(() => - combineLatest([ - this.store.select(selectUser), - this.store.select(selectActivities), - ]).pipe( - map(([user, activities]): Status[] => { - if (user?.isAdmin) { - return activities.reduce( - (status: Status[], activity): Status[] => { - const index = status.findIndex( - (s) => s.name === activity.type, - ); - if (index === -1) { - return [ - ...status, - { name: activity.type, teachers: [activity.teacher] }, - ]; - } else { - status[index].teachers.push(activity.teacher); - return status; - } - }, - [], - ); - } - return []; - }), - map((statuses) => StatusActions.loadStatusesSuccess({ statuses })), - ), - ), - ); - }); - - constructor( - private actions$: Actions, - private store: Store, - ) {} -} diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.model.ts b/apps/ngrx/effect-selector/src/app/store/status/status.model.ts deleted file mode 100644 index 07733834a..000000000 --- a/apps/ngrx/effect-selector/src/app/store/status/status.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ActivityType, Person } from '../activity/activity.model'; - -export interface Status { - name: ActivityType; - teachers: Person[]; -} diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.reducer.ts b/apps/ngrx/effect-selector/src/app/store/status/status.reducer.ts deleted file mode 100644 index b91cbe2fb..000000000 --- a/apps/ngrx/effect-selector/src/app/store/status/status.reducer.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createReducer, on } from '@ngrx/store'; -import { ActivityType, Person } from '../activity/activity.model'; -import * as StatusActions from './status.actions'; -import { Status } from './status.model'; - -export const statusFeatureKey = 'status'; - -export interface StatusState { - statuses: Status[]; - teachersMap: Map; -} - -export const initialState: StatusState = { - statuses: [], - teachersMap: new Map(), -}; - -export const statusReducer = createReducer( - initialState, - on(StatusActions.loadStatusesSuccess, (state, { statuses }): StatusState => { - const map = new Map(); - statuses.forEach((s) => map.set(s.name, s.teachers)); - return { - ...state, - statuses, - teachersMap: map, - }; - }), -); diff --git a/apps/ngrx/effect-selector/src/app/store/status/status.selectors.ts b/apps/ngrx/effect-selector/src/app/store/status/status.selectors.ts deleted file mode 100644 index 80ed059a6..000000000 --- a/apps/ngrx/effect-selector/src/app/store/status/status.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { ActivityType } from '../activity/activity.model'; -import { StatusState, statusFeatureKey } from './status.reducer'; - -export const selectStatusState = - createFeatureSelector(statusFeatureKey); - -export const selectStatuses = createSelector( - selectStatusState, - (state) => state.statuses, -); - -export const selectAllTeachersByActivityType = (name: ActivityType) => - createSelector( - selectStatusState, - (state) => state.teachersMap.get(name) ?? [], - ); diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.actions.ts b/apps/ngrx/effect-selector/src/app/store/user/user.actions.ts deleted file mode 100644 index a73147dce..000000000 --- a/apps/ngrx/effect-selector/src/app/store/user/user.actions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createAction, props } from '@ngrx/store'; -import { User } from './user.model'; - -export const loadUsers = createAction('[User] Load Users'); - -export const loadUsersSuccess = createAction( - '[User] Load Users Success', - props<{ user: User }>(), -); - -export const loadUsersFailure = createAction( - '[User] Load Users Failure', - props<{ error: unknown }>(), -); diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.effects.ts b/apps/ngrx/effect-selector/src/app/store/user/user.effects.ts deleted file mode 100644 index fff3f6f6c..000000000 --- a/apps/ngrx/effect-selector/src/app/store/user/user.effects.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { of } from 'rxjs'; -import { catchError, concatMap, map } from 'rxjs/operators'; -import * as UserActions from './user.actions'; -import { UserService } from './user.service'; - -@Injectable() -export class UserEffects { - loadUsers$ = createEffect(() => { - return this.actions$.pipe( - ofType(UserActions.loadUsers), - concatMap(() => - this.userService.fetchUser().pipe( - map((user) => UserActions.loadUsersSuccess({ user })), - catchError((error) => of(UserActions.loadUsersFailure({ error }))), - ), - ), - ); - }); - - constructor( - private actions$: Actions, - private userService: UserService, - ) {} -} diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.model.ts b/apps/ngrx/effect-selector/src/app/store/user/user.model.ts deleted file mode 100644 index d7692041c..000000000 --- a/apps/ngrx/effect-selector/src/app/store/user/user.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { randFirstName, randLastName, randText } from '@ngneat/falso'; - -export interface User { - firstname: string; - lastname: string; - isAdmin: boolean; - apiKey: string; -} - -export const user: User = { - firstname: randFirstName(), - lastname: randLastName(), - isAdmin: true, - apiKey: randText(), -}; diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.reducer.ts b/apps/ngrx/effect-selector/src/app/store/user/user.reducer.ts deleted file mode 100644 index 3f4768c18..000000000 --- a/apps/ngrx/effect-selector/src/app/store/user/user.reducer.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { createReducer, on } from '@ngrx/store'; -import * as UserActions from './user.actions'; -import { User } from './user.model'; - -export const userFeatureKey = 'user'; - -export interface UserState { - user?: User; -} - -export const initialState: UserState = { - user: undefined, -}; - -export const userReducer = createReducer( - initialState, - on(UserActions.loadUsersSuccess, (state, { user }) => ({ ...state, user })), - on(UserActions.loadUsersFailure, (state) => ({ ...state, user: undefined })), -); diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.selectors.ts b/apps/ngrx/effect-selector/src/app/store/user/user.selectors.ts deleted file mode 100644 index 7970b0dfe..000000000 --- a/apps/ngrx/effect-selector/src/app/store/user/user.selectors.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { UserState, userFeatureKey } from './user.reducer'; - -export const selectUserState = createFeatureSelector(userFeatureKey); - -export const selectUser = createSelector( - selectUserState, - (state) => state.user, -); diff --git a/apps/ngrx/effect-selector/src/app/store/user/user.service.ts b/apps/ngrx/effect-selector/src/app/store/user/user.service.ts deleted file mode 100644 index a407b020a..000000000 --- a/apps/ngrx/effect-selector/src/app/store/user/user.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@angular/core'; -import { map, timer } from 'rxjs'; -import { user } from './user.model'; - -@Injectable({ - providedIn: 'root', -}) -export class UserService { - fetchUser = () => timer(500).pipe(map(() => user)); -} diff --git a/apps/ngrx/effect-selector/src/index.html b/apps/ngrx/effect-selector/src/index.html deleted file mode 100644 index 21d573669..000000000 --- a/apps/ngrx/effect-selector/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Ngrx1 - - - - - - - - diff --git a/apps/ngrx/effect-selector/src/main.ts b/apps/ngrx/effect-selector/src/main.ts deleted file mode 100644 index 31c2a3482..000000000 --- a/apps/ngrx/effect-selector/src/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { bootstrapApplication } from '@angular/platform-browser'; -import { appConfig } from './app/app.config'; - -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent, appConfig); diff --git a/apps/ngrx/effect-selector/src/polyfills.ts b/apps/ngrx/effect-selector/src/polyfills.ts deleted file mode 100644 index e4555ed11..000000000 --- a/apps/ngrx/effect-selector/src/polyfills.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes recent versions of Safari, Chrome (including - * Opera), Edge on the desktop, and iOS and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/apps/ngrx/effect-selector/tsconfig.app.json b/apps/ngrx/effect-selector/tsconfig.app.json deleted file mode 100644 index 7a4dbc47e..000000000 --- a/apps/ngrx/effect-selector/tsconfig.app.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "types": [], - "target": "ES2022", - "useDefineForClassFields": false - }, - "files": ["src/main.ts", "src/polyfills.ts"], - "include": ["src/**/*.d.ts"], - "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"] -} diff --git a/apps/ngrx/effect-selector/tsconfig.editor.json b/apps/ngrx/effect-selector/tsconfig.editor.json deleted file mode 100644 index 20c4afdbf..000000000 --- a/apps/ngrx/effect-selector/tsconfig.editor.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["**/*.ts"], - "compilerOptions": { - "types": ["jest", "node"] - } -} diff --git a/apps/ngrx/effect-selector/tsconfig.json b/apps/ngrx/effect-selector/tsconfig.json deleted file mode 100644 index 52eb4f718..000000000 --- a/apps/ngrx/effect-selector/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.editor.json" - } - ], - "compilerOptions": { - "target": "es2020", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/ngrx/effect-selector/tsconfig.spec.json b/apps/ngrx/effect-selector/tsconfig.spec.json deleted file mode 100644 index 7aa46d88c..000000000 --- a/apps/ngrx/effect-selector/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "files": ["src/test-setup.ts"], - "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] -} diff --git a/apps/ngrx/notification/README.md b/apps/ngrx/notification/README.md deleted file mode 100644 index 36acdab46..000000000 --- a/apps/ngrx/notification/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Power of Effect - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve ngrx-notification -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/ngrx/7-power-effect/). diff --git a/apps/ngrx/notification/project.json b/apps/ngrx/notification/project.json deleted file mode 100644 index 5182ec85a..000000000 --- a/apps/ngrx/notification/project.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "ngrx-notification", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/ngrx/notification/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/ngrx/notification", - "index": "apps/ngrx/notification/src/index.html", - "main": "apps/ngrx/notification/src/main.ts", - "polyfills": "apps/ngrx/notification/src/polyfills.ts", - "tsConfig": "apps/ngrx/notification/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/ngrx/notification/src/favicon.ico", - "apps/ngrx/notification/src/assets" - ], - "styles": [ - "apps/ngrx/notification/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "ngrx-notification:build:production" - }, - "development": { - "buildTarget": "ngrx-notification:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "ngrx-notification:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/ngrx/notification/**/*.ts", - "apps/ngrx/notification/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/ngrx/notification/src/app/app.actions.ts b/apps/ngrx/notification/src/app/app.actions.ts deleted file mode 100644 index 3dcba8134..000000000 --- a/apps/ngrx/notification/src/app/app.actions.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createActionGroup, emptyProps } from '@ngrx/store'; - -// This is the global actions. -export const appActions = createActionGroup({ - source: 'App Component', - events: { - 'Init App': emptyProps(), - }, -}); diff --git a/apps/ngrx/notification/src/app/app.component.ts b/apps/ngrx/notification/src/app/app.component.ts deleted file mode 100644 index dc14376ac..000000000 --- a/apps/ngrx/notification/src/app/app.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { RouterLink, RouterOutlet } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { appActions } from './app.actions'; - -@Component({ - standalone: true, - imports: [RouterOutlet, RouterLink], - selector: 'app-root', - template: ` - - - - `, - styles: [ - ` - :host { - display: flex; - flex-direction: column; - gap: 20px; - - nav { - display: flex; - gap: 20px; - } - } - `, - ], -}) -export class AppComponent implements OnInit { - private store = inject(Store); - - ngOnInit(): void { - this.store.dispatch(appActions.initApp()); - } -} diff --git a/apps/ngrx/notification/src/app/app.config.ts b/apps/ngrx/notification/src/app/app.config.ts deleted file mode 100644 index b36822344..000000000 --- a/apps/ngrx/notification/src/app/app.config.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { FakeBackendService } from '@angular-challenges/ngrx-notification/backend'; -import { APP_INITIALIZER, ApplicationConfig, inject } from '@angular/core'; -import { provideAnimations } from '@angular/platform-browser/animations'; -import { provideRouter } from '@angular/router'; -import { provideEffects } from '@ngrx/effects'; -import { provideStore } from '@ngrx/store'; -import { NotificationService } from './data-access/notification.service'; -import { ROUTES } from './routes'; -import { StudentEffects } from './student/store/student.effects'; -import { - studentReducer, - studentsFeatureKey, -} from './student/store/student.reducer'; -import { TeacherEffects } from './teacher/store/teacher.effects'; -import { - teacherReducer, - teachersFeatureKey, -} from './teacher/store/teacher.reducer'; - -const REDUCERS = { - [teachersFeatureKey]: teacherReducer, - [studentsFeatureKey]: studentReducer, -}; - -export const appConfig: ApplicationConfig = { - providers: [ - provideStore(REDUCERS), - provideEffects([TeacherEffects, StudentEffects]), - provideRouter(ROUTES), - { - provide: APP_INITIALIZER, - multi: true, - useFactory: () => { - const service = inject(FakeBackendService); - return () => service.start(); - }, - }, - { - provide: APP_INITIALIZER, - multi: true, - useFactory: () => { - const service = inject(NotificationService); - return () => service.init(); - }, - }, - provideAnimations(), - ], -}; diff --git a/apps/ngrx/notification/src/app/data-access/http.service.ts b/apps/ngrx/notification/src/app/data-access/http.service.ts deleted file mode 100644 index b5a59aab0..000000000 --- a/apps/ngrx/notification/src/app/data-access/http.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FakeBackendService } from '@angular-challenges/ngrx-notification/backend'; -import { inject, Injectable } from '@angular/core'; -import { take } from 'rxjs'; - -@Injectable({ providedIn: 'root' }) -export class HttpService { - private fakeBackend = inject(FakeBackendService); - - getAllTeachers = () => this.fakeBackend.getAllTeachers().pipe(take(1)); - - getAllStudents = () => this.fakeBackend.getAllStudents().pipe(take(1)); - - getAllSchools = () => this.fakeBackend.getAllSchools().pipe(take(1)); -} diff --git a/apps/ngrx/notification/src/app/data-access/notification.service.ts b/apps/ngrx/notification/src/app/data-access/notification.service.ts deleted file mode 100644 index b11614054..000000000 --- a/apps/ngrx/notification/src/app/data-access/notification.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { PushService } from '@angular-challenges/ngrx-notification/backend'; -import { - isSchool, - isStudent, - isTeacher, - Push, -} from '@angular-challenges/ngrx-notification/model'; -import { inject, Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { filter } from 'rxjs'; -import { studentActions } from '../student/store/student.actions'; -import { teacherActions } from '../teacher/store/teacher.actions'; - -@Injectable({ providedIn: 'root' }) -export class NotificationService { - private pushService = inject(PushService); - private store = inject(Store); - - init() { - this.pushService.notification$ - .pipe(filter(Boolean)) - .subscribe((notification: Push) => { - if (isTeacher(notification)) { - this.store.dispatch( - teacherActions.addOneTeacher({ teacher: notification }), - ); - } - if (isStudent(notification)) { - this.store.dispatch( - studentActions.addOneStudent({ student: notification }), - ); - } - if (isSchool(notification)) { - // SchoolStore is a ComponentStore. We can't dispatch a school action here. - // We are stuck. We must have done something wrong and need to refactor... - } - }); - } -} diff --git a/apps/ngrx/notification/src/app/routes.ts b/apps/ngrx/notification/src/app/routes.ts deleted file mode 100644 index 7db44a4dc..000000000 --- a/apps/ngrx/notification/src/app/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Route } from '@angular/router'; -import { TeacherComponent } from './teacher/teacher.component'; - -export const ROUTES: Route[] = [ - { path: '', pathMatch: 'full', redirectTo: 'teacher' }, - { - path: 'teacher', - component: TeacherComponent, - }, - { - path: 'student', - loadComponent: () => - import('./student/student.component').then((m) => m.StudentComponent), - }, - { - path: 'school', - loadComponent: () => - import('./school/school.component').then((m) => m.SchoolComponent), - }, -]; diff --git a/apps/ngrx/notification/src/app/school/school.component.ts b/apps/ngrx/notification/src/app/school/school.component.ts deleted file mode 100644 index af58af9c1..000000000 --- a/apps/ngrx/notification/src/app/school/school.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { provideComponentStore } from '@ngrx/component-store'; -import { SchoolStore } from './school.store'; - -@Component({ - standalone: true, - imports: [NgFor, AsyncPipe], - providers: [provideComponentStore(SchoolStore)], - selector: 'school', - template: ` -

SCHOOL

-
- {{ school.name }} - {{ school.version }} -
- `, - styles: [ - ` - :host { - display: block; - width: fit-content; - height: fit-content; - border: 1px solid red; - padding: 4px; - } - `, - ], -}) -export class SchoolComponent { - private store = inject(SchoolStore); - school$ = this.store.schools$; -} diff --git a/apps/ngrx/notification/src/app/school/school.store.ts b/apps/ngrx/notification/src/app/school/school.store.ts deleted file mode 100644 index 0fd31fa6d..000000000 --- a/apps/ngrx/notification/src/app/school/school.store.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { School } from '@angular-challenges/ngrx-notification/model'; -import { Injectable } from '@angular/core'; -import { - ComponentStore, - OnStoreInit, - tapResponse, -} from '@ngrx/component-store'; -import { pipe, switchMap } from 'rxjs'; -import { HttpService } from '../data-access/http.service'; - -@Injectable() -export class SchoolStore - extends ComponentStore<{ schools: School[] }> - implements OnStoreInit -{ - readonly schools$ = this.select((state) => state.schools); - - constructor(private httpService: HttpService) { - super({ schools: [] }); - } - - addSchool = this.updater((state, school: School) => ({ - ...state, - schools: [...state.schools, school], - })); - - updateSchool = this.updater((state, school: School) => ({ - ...state, - schools: state.schools.map((t) => (t.id === school.id ? school : t)), - })); - - private readonly loadSchools = this.effect( - pipe( - switchMap(() => - this.httpService.getAllSchools().pipe( - tapResponse( - (schools) => this.patchState({ schools }), - (_) => _, // not handling the error - ), - ), - ), - ), - ); - - ngrxOnStoreInit() { - this.loadSchools(); - } -} diff --git a/apps/ngrx/notification/src/app/student/store/student.actions.ts b/apps/ngrx/notification/src/app/student/store/student.actions.ts deleted file mode 100644 index 52eda8ee0..000000000 --- a/apps/ngrx/notification/src/app/student/store/student.actions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Student } from '@angular-challenges/ngrx-notification/model'; -import { createActionGroup, props } from '@ngrx/store'; - -export const studentActions = createActionGroup({ - source: 'Student API', - events: { - 'Add One Student': props<{ student: Student }>(), - 'Add All Students': props<{ students: Student[] }>(), - }, -}); diff --git a/apps/ngrx/notification/src/app/student/store/student.effects.ts b/apps/ngrx/notification/src/app/student/store/student.effects.ts deleted file mode 100644 index b741bd21d..000000000 --- a/apps/ngrx/notification/src/app/student/store/student.effects.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { map, switchMap } from 'rxjs'; -import { appActions } from '../../app.actions'; -import { HttpService } from '../../data-access/http.service'; -import { studentActions } from './student.actions'; - -@Injectable() -export class StudentEffects { - private actions$ = inject(Actions); - private httpService = inject(HttpService); - - loadStudents$ = createEffect(() => - this.actions$.pipe( - ofType(appActions.initApp), - switchMap(() => - this.httpService - .getAllStudents() - .pipe(map((students) => studentActions.addAllStudents({ students }))), - ), - ), - ); -} diff --git a/apps/ngrx/notification/src/app/student/store/student.reducer.ts b/apps/ngrx/notification/src/app/student/store/student.reducer.ts deleted file mode 100644 index 0b02cd322..000000000 --- a/apps/ngrx/notification/src/app/student/store/student.reducer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Student } from '@angular-challenges/ngrx-notification/model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; -import { createReducer, on } from '@ngrx/store'; -import { studentActions } from './student.actions'; - -export const studentsFeatureKey = 'students'; - -export type StudentState = EntityState; - -export const studentAdapter: EntityAdapter = - createEntityAdapter(); - -export const studentReducer = createReducer( - studentAdapter.getInitialState(), - on(studentActions.addOneStudent, (state, { student }) => - studentAdapter.upsertOne(student, state), - ), - on(studentActions.addAllStudents, (state, { students }) => - studentAdapter.setAll(students, state), - ), -); - -export const { selectIds, selectEntities, selectAll, selectTotal } = - studentAdapter.getSelectors(); diff --git a/apps/ngrx/notification/src/app/student/store/student.selectors.ts b/apps/ngrx/notification/src/app/student/store/student.selectors.ts deleted file mode 100644 index b041ff420..000000000 --- a/apps/ngrx/notification/src/app/student/store/student.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { - StudentState, - studentAdapter, - studentsFeatureKey, -} from './student.reducer'; - -const selectStudentState = - createFeatureSelector(studentsFeatureKey); - -export const { selectAll } = studentAdapter.getSelectors(); - -const selectStudents = createSelector(selectStudentState, selectAll); - -export const StudentSelectors = { - selectStudents, -}; diff --git a/apps/ngrx/notification/src/app/student/student.component.ts b/apps/ngrx/notification/src/app/student/student.component.ts deleted file mode 100644 index bbc45bfd7..000000000 --- a/apps/ngrx/notification/src/app/student/student.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { StudentSelectors } from './store/student.selectors'; - -@Component({ - standalone: true, - imports: [NgFor, AsyncPipe], - selector: 'student', - template: ` -

STUDENTS

-
- {{ student.firstname }} {{ student.lastname }} - {{ student.version }} -
- `, - styles: [ - ` - :host { - display: block; - width: fit-content; - height: fit-content; - border: 1px solid red; - padding: 4px; - } - `, - ], -}) -export class StudentComponent { - private store = inject(Store); - students$ = this.store.select(StudentSelectors.selectStudents); -} diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.actions.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.actions.ts deleted file mode 100644 index ff41af34e..000000000 --- a/apps/ngrx/notification/src/app/teacher/store/teacher.actions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Teacher } from '@angular-challenges/ngrx-notification/model'; -import { createActionGroup, props } from '@ngrx/store'; - -export const teacherActions = createActionGroup({ - source: 'Teacher API', - events: { - 'Add One Teacher': props<{ teacher: Teacher }>(), - 'Add All Teachers': props<{ teachers: Teacher[] }>(), - }, -}); diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.effects.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.effects.ts deleted file mode 100644 index 43c3fab0b..000000000 --- a/apps/ngrx/notification/src/app/teacher/store/teacher.effects.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { map, switchMap } from 'rxjs'; -import { appActions } from '../../app.actions'; -import { HttpService } from '../../data-access/http.service'; -import { teacherActions } from './teacher.actions'; - -@Injectable() -export class TeacherEffects { - private actions$ = inject(Actions); - private httpService = inject(HttpService); - - loadTeachers$ = createEffect(() => - this.actions$.pipe( - ofType(appActions.initApp), - switchMap(() => - this.httpService - .getAllTeachers() - .pipe(map((teachers) => teacherActions.addAllTeachers({ teachers }))), - ), - ), - ); -} diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.reducer.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.reducer.ts deleted file mode 100644 index d793b9646..000000000 --- a/apps/ngrx/notification/src/app/teacher/store/teacher.reducer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Teacher } from '@angular-challenges/ngrx-notification/model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; -import { createReducer, on } from '@ngrx/store'; -import { teacherActions } from './teacher.actions'; - -export const teachersFeatureKey = 'teachers'; - -export type TeacherState = EntityState; - -export const teacherAdapter: EntityAdapter = - createEntityAdapter(); - -export const teacherReducer = createReducer( - teacherAdapter.getInitialState(), - on(teacherActions.addOneTeacher, (state, { teacher }) => - teacherAdapter.upsertOne(teacher, state), - ), - on(teacherActions.addAllTeachers, (state, { teachers }) => - teacherAdapter.setAll(teachers, state), - ), -); - -export const { selectIds, selectEntities, selectAll, selectTotal } = - teacherAdapter.getSelectors(); diff --git a/apps/ngrx/notification/src/app/teacher/store/teacher.selectors.ts b/apps/ngrx/notification/src/app/teacher/store/teacher.selectors.ts deleted file mode 100644 index a32e82c2b..000000000 --- a/apps/ngrx/notification/src/app/teacher/store/teacher.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { - TeacherState, - teacherAdapter, - teachersFeatureKey, -} from './teacher.reducer'; - -const selectTeacherState = - createFeatureSelector(teachersFeatureKey); - -export const { selectAll } = teacherAdapter.getSelectors(); - -const selectTeachers = createSelector(selectTeacherState, selectAll); - -export const TeacherSelectors = { - selectTeachers, -}; diff --git a/apps/ngrx/notification/src/app/teacher/teacher.component.ts b/apps/ngrx/notification/src/app/teacher/teacher.component.ts deleted file mode 100644 index 63e812200..000000000 --- a/apps/ngrx/notification/src/app/teacher/teacher.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { TeacherSelectors } from './store/teacher.selectors'; - -@Component({ - standalone: true, - imports: [NgFor, AsyncPipe], - selector: 'teacher', - template: ` -

TEACHERS

-
- {{ teacher.firstname }} {{ teacher.lastname }} - {{ teacher.version }} -
- `, - styles: [ - ` - :host { - display: block; - width: fit-content; - height: fit-content; - border: 1px solid red; - padding: 4px; - } - `, - ], -}) -export class TeacherComponent { - teacher$ = this.store.select(TeacherSelectors.selectTeachers); - - constructor(private store: Store) {} -} diff --git a/apps/ngrx/notification/src/index.html b/apps/ngrx/notification/src/index.html deleted file mode 100644 index cc46b13b2..000000000 --- a/apps/ngrx/notification/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - NgrxNotification - - - - - - - - diff --git a/apps/ngrx/notification/src/main.ts b/apps/ngrx/notification/src/main.ts deleted file mode 100644 index 6f91f21a3..000000000 --- a/apps/ngrx/notification/src/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { appConfig } from './app/app.config'; - -import { bootstrapApplication } from '@angular/platform-browser'; - -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent, appConfig).catch((err) => - console.error(err), -); diff --git a/apps/ngrx/notification/src/polyfills.ts b/apps/ngrx/notification/src/polyfills.ts deleted file mode 100644 index e4555ed11..000000000 --- a/apps/ngrx/notification/src/polyfills.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes recent versions of Safari, Chrome (including - * Opera), Edge on the desktop, and iOS and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/apps/ngrx/notification/tsconfig.app.json b/apps/ngrx/notification/tsconfig.app.json deleted file mode 100644 index 7a4dbc47e..000000000 --- a/apps/ngrx/notification/tsconfig.app.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "types": [], - "target": "ES2022", - "useDefineForClassFields": false - }, - "files": ["src/main.ts", "src/polyfills.ts"], - "include": ["src/**/*.d.ts"], - "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"] -} diff --git a/apps/ngrx/notification/tsconfig.editor.json b/apps/ngrx/notification/tsconfig.editor.json deleted file mode 100644 index 3d4f1db8b..000000000 --- a/apps/ngrx/notification/tsconfig.editor.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "**/*.ts", - "../../../libs/ngrx-notification/backend/src/lib/fake-backend.service.ts" - ], - "compilerOptions": { - "types": [] - } -} diff --git a/apps/ngrx/notification/tsconfig.json b/apps/ngrx/notification/tsconfig.json deleted file mode 100644 index b2dbbf22e..000000000 --- a/apps/ngrx/notification/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.editor.json" - } - ], - "compilerOptions": { - "target": "es2020", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/nx/42-static-vs-dynamic-import/.eslintrc.json b/apps/nx/42-static-vs-dynamic-import/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/nx/42-static-vs-dynamic-import/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/nx/42-static-vs-dynamic-import/README.md b/apps/nx/42-static-vs-dynamic-import/README.md new file mode 100644 index 000000000..a08abaa82 --- /dev/null +++ b/apps/nx/42-static-vs-dynamic-import/README.md @@ -0,0 +1,13 @@ +# Static vs Dynamic Import + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve nx-static-vs-dynamic-import +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/nx/42-static-dynamic-import/). diff --git a/apps/nx/42-static-vs-dynamic-import/project.json b/apps/nx/42-static-vs-dynamic-import/project.json new file mode 100644 index 000000000..7f45fb828 --- /dev/null +++ b/apps/nx/42-static-vs-dynamic-import/project.json @@ -0,0 +1,73 @@ +{ + "name": "nx-static-vs-dynamic-import", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/nx/42-static-vs-dynamic-import/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/nx/42-static-vs-dynamic-import", + "index": "apps/nx/42-static-vs-dynamic-import/src/index.html", + "browser": "apps/nx/42-static-vs-dynamic-import/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/nx/42-static-vs-dynamic-import/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/nx/42-static-vs-dynamic-import/src/favicon.ico", + "apps/nx/42-static-vs-dynamic-import/src/assets" + ], + "styles": [ + "apps/nx/42-static-vs-dynamic-import/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all", + "sourceMap": true + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "nx-static-vs-dynamic-import:build:production" + }, + "development": { + "buildTarget": "nx-static-vs-dynamic-import:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "nx-static-vs-dynamic-import:build" + } + } + } +} diff --git a/apps/nx/42-static-vs-dynamic-import/src/app/app.component.ts b/apps/nx/42-static-vs-dynamic-import/src/app/app.component.ts new file mode 100644 index 000000000..59be617e8 --- /dev/null +++ b/apps/nx/42-static-vs-dynamic-import/src/app/app.component.ts @@ -0,0 +1,26 @@ +import { + UserComponent, + type User, +} from '@angular-challenges/static-dynamic-import/users'; +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [UserComponent, RouterOutlet], + selector: 'app-root', + template: ` + Author: + + + `, + host: { + class: 'flex flex-col', + }, +}) +export class AppComponent { + author: User = { + name: 'Thomas', + lastName: 'Laforge', + country: 'France', + }; +} diff --git a/apps/nx/static-dynamic-import/src/app/app.config.ts b/apps/nx/42-static-vs-dynamic-import/src/app/app.config.ts similarity index 100% rename from apps/nx/static-dynamic-import/src/app/app.config.ts rename to apps/nx/42-static-vs-dynamic-import/src/app/app.config.ts diff --git a/apps/nx/static-dynamic-import/src/assets/.gitkeep b/apps/nx/42-static-vs-dynamic-import/src/assets/.gitkeep similarity index 100% rename from apps/nx/static-dynamic-import/src/assets/.gitkeep rename to apps/nx/42-static-vs-dynamic-import/src/assets/.gitkeep diff --git a/apps/performance/memoized/src/favicon.ico b/apps/nx/42-static-vs-dynamic-import/src/favicon.ico similarity index 100% rename from apps/performance/memoized/src/favicon.ico rename to apps/nx/42-static-vs-dynamic-import/src/favicon.ico diff --git a/apps/nx/42-static-vs-dynamic-import/src/index.html b/apps/nx/42-static-vs-dynamic-import/src/index.html new file mode 100644 index 000000000..1b4f2a84b --- /dev/null +++ b/apps/nx/42-static-vs-dynamic-import/src/index.html @@ -0,0 +1,16 @@ + + + + + nx-static-vs-dynamic-import + + + + + + + + + diff --git a/apps/rxjs/catch-error/src/main.ts b/apps/nx/42-static-vs-dynamic-import/src/main.ts similarity index 100% rename from apps/rxjs/catch-error/src/main.ts rename to apps/nx/42-static-vs-dynamic-import/src/main.ts diff --git a/apps/performance/ngfor-optimize/src/styles.scss b/apps/nx/42-static-vs-dynamic-import/src/styles.scss similarity index 100% rename from apps/performance/ngfor-optimize/src/styles.scss rename to apps/nx/42-static-vs-dynamic-import/src/styles.scss diff --git a/apps/performance/ngfor-optimize/tailwind.config.js b/apps/nx/42-static-vs-dynamic-import/tailwind.config.js similarity index 100% rename from apps/performance/ngfor-optimize/tailwind.config.js rename to apps/nx/42-static-vs-dynamic-import/tailwind.config.js diff --git a/apps/performance/scroll-cd/tsconfig.app.json b/apps/nx/42-static-vs-dynamic-import/tsconfig.app.json similarity index 100% rename from apps/performance/scroll-cd/tsconfig.app.json rename to apps/nx/42-static-vs-dynamic-import/tsconfig.app.json diff --git a/apps/angular/view-transition/tsconfig.editor.json b/apps/nx/42-static-vs-dynamic-import/tsconfig.editor.json similarity index 100% rename from apps/angular/view-transition/tsconfig.editor.json rename to apps/nx/42-static-vs-dynamic-import/tsconfig.editor.json diff --git a/apps/nx/static-dynamic-import/tsconfig.json b/apps/nx/42-static-vs-dynamic-import/tsconfig.json similarity index 100% rename from apps/nx/static-dynamic-import/tsconfig.json rename to apps/nx/42-static-vs-dynamic-import/tsconfig.json diff --git a/apps/nx/static-dynamic-import/README.md b/apps/nx/static-dynamic-import/README.md deleted file mode 100644 index 54691c75b..000000000 --- a/apps/nx/static-dynamic-import/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Static vs Dynamic Import - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve nx-static-dynamic-import -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/nx/42-static-dynamic-import/). diff --git a/apps/nx/static-dynamic-import/project.json b/apps/nx/static-dynamic-import/project.json deleted file mode 100644 index c0208b075..000000000 --- a/apps/nx/static-dynamic-import/project.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "name": "nx-static-dynamic-import", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/nx/static-dynamic-import/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:application", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/nx/static-dynamic-import", - "index": "apps/nx/static-dynamic-import/src/index.html", - "browser": "apps/nx/static-dynamic-import/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/nx/static-dynamic-import/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/nx/static-dynamic-import/src/favicon.ico", - "apps/nx/static-dynamic-import/src/assets" - ], - "styles": [ - "apps/nx/static-dynamic-import/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all", - "sourceMap": true - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "nx-static-dynamic-import:build:production" - }, - "development": { - "buildTarget": "nx-static-dynamic-import:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "nx-static-dynamic-import:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"] - } - } -} diff --git a/apps/nx/static-dynamic-import/src/app/app.component.ts b/apps/nx/static-dynamic-import/src/app/app.component.ts deleted file mode 100644 index 9c5bd67d4..000000000 --- a/apps/nx/static-dynamic-import/src/app/app.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - UserComponent, - type User, -} from '@angular-challenges/static-dynamic-import/users'; -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [UserComponent, RouterOutlet], - selector: 'app-root', - template: ` - Author: - - - `, - host: { - class: 'flex flex-col', - }, -}) -export class AppComponent { - author: User = { - name: 'Thomas', - lastName: 'Laforge', - country: 'France', - }; -} diff --git a/apps/nx/static-dynamic-import/src/index.html b/apps/nx/static-dynamic-import/src/index.html deleted file mode 100644 index 77adec4af..000000000 --- a/apps/nx/static-dynamic-import/src/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - nx-static-dynamic-import - - - - - - - - - diff --git a/apps/angular/styling/.eslintrc.json b/apps/performance/12-optimize-change-detection/.eslintrc.json similarity index 100% rename from apps/angular/styling/.eslintrc.json rename to apps/performance/12-optimize-change-detection/.eslintrc.json diff --git a/apps/performance/12-optimize-change-detection/README.md b/apps/performance/12-optimize-change-detection/README.md new file mode 100644 index 000000000..52fe319d7 --- /dev/null +++ b/apps/performance/12-optimize-change-detection/README.md @@ -0,0 +1,13 @@ +# Optimize Change Detection + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve performance-optimize-change-detection +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/12-performance-optimize-change-detection/). diff --git a/apps/performance/12-optimize-change-detection/jest.config.ts b/apps/performance/12-optimize-change-detection/jest.config.ts new file mode 100644 index 000000000..dc22d99ea --- /dev/null +++ b/apps/performance/12-optimize-change-detection/jest.config.ts @@ -0,0 +1,24 @@ +/* eslint-disable */ +export default { + displayName: 'performance-optimize-change-detection', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + globals: {}, + coverageDirectory: + '../../../coverage/apps/performance/12-optimize-change-detection', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/performance/12-optimize-change-detection/project.json b/apps/performance/12-optimize-change-detection/project.json new file mode 100644 index 000000000..188240700 --- /dev/null +++ b/apps/performance/12-optimize-change-detection/project.json @@ -0,0 +1,85 @@ +{ + "name": "performance-optimize-change-detection", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/performance/12-optimize-change-detection/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/12-optimize-change-detection", + "index": "apps/performance/12-optimize-change-detection/src/index.html", + "main": "apps/performance/12-optimize-change-detection/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/12-optimize-change-detection/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/performance/12-optimize-change-detection/src/favicon.ico", + "apps/performance/12-optimize-change-detection/src/assets" + ], + "styles": [ + "apps/performance/12-optimize-change-detection/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "performance-optimize-change-detection:build:production" + }, + "development": { + "buildTarget": "performance-optimize-change-detection:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "performance-optimize-change-detection:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/performance/12-optimize-change-detection/src/app/app.component.ts b/apps/performance/12-optimize-change-detection/src/app/app.component.ts new file mode 100644 index 000000000..dd818cad5 --- /dev/null +++ b/apps/performance/12-optimize-change-detection/src/app/app.component.ts @@ -0,0 +1,52 @@ +import { AsyncPipe, NgIf } from '@angular/common'; +import { Component, HostListener } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + +@Component({ + imports: [NgIf, AsyncPipe], + selector: 'app-root', + template: ` +
Top
+
Middle
+
Bottom
+ + `, + styles: [ + ` + :host { + height: 1500px; + display: flex; + flex-direction: column; + justify-content: space-between; + + button { + position: fixed; + bottom: 1rem; + left: 1rem; + z-index: 1; + padding: 1rem; + } + } + `, + ], +}) +export class AppComponent { + title = 'scroll-cd'; + + private displayButtonSubject = new BehaviorSubject(false); + displayButton$ = this.displayButtonSubject.asObservable(); + + @HostListener('window:scroll', ['$event']) + onScroll() { + const pos = window.pageYOffset; + this.displayButtonSubject.next(pos > 50); + } + + goToTop() { + window.scroll({ + top: 0, + left: 0, + behavior: 'smooth', + }); + } +} diff --git a/apps/performance/christmas-web-worker/src/assets/.gitkeep b/apps/performance/12-optimize-change-detection/src/assets/.gitkeep similarity index 100% rename from apps/performance/christmas-web-worker/src/assets/.gitkeep rename to apps/performance/12-optimize-change-detection/src/assets/.gitkeep diff --git a/apps/performance/ngfor-biglist/src/favicon.ico b/apps/performance/12-optimize-change-detection/src/favicon.ico similarity index 100% rename from apps/performance/ngfor-biglist/src/favicon.ico rename to apps/performance/12-optimize-change-detection/src/favicon.ico diff --git a/apps/performance/12-optimize-change-detection/src/index.html b/apps/performance/12-optimize-change-detection/src/index.html new file mode 100644 index 000000000..c1cb61764 --- /dev/null +++ b/apps/performance/12-optimize-change-detection/src/index.html @@ -0,0 +1,13 @@ + + + + + performance-optimize-change-detection + + + + + + + + diff --git a/apps/performance/scroll-cd/src/main.ts b/apps/performance/12-optimize-change-detection/src/main.ts similarity index 100% rename from apps/performance/scroll-cd/src/main.ts rename to apps/performance/12-optimize-change-detection/src/main.ts diff --git a/apps/ngrx/notification/src/styles.scss b/apps/performance/12-optimize-change-detection/src/styles.scss similarity index 100% rename from apps/ngrx/notification/src/styles.scss rename to apps/performance/12-optimize-change-detection/src/styles.scss diff --git a/apps/ngrx/effect-selector/src/test-setup.ts b/apps/performance/12-optimize-change-detection/src/test-setup.ts similarity index 100% rename from apps/ngrx/effect-selector/src/test-setup.ts rename to apps/performance/12-optimize-change-detection/src/test-setup.ts diff --git a/apps/rxjs/catch-error/tsconfig.app.json b/apps/performance/12-optimize-change-detection/tsconfig.app.json similarity index 100% rename from apps/rxjs/catch-error/tsconfig.app.json rename to apps/performance/12-optimize-change-detection/tsconfig.app.json diff --git a/apps/performance/scroll-cd/tsconfig.editor.json b/apps/performance/12-optimize-change-detection/tsconfig.editor.json similarity index 100% rename from apps/performance/scroll-cd/tsconfig.editor.json rename to apps/performance/12-optimize-change-detection/tsconfig.editor.json diff --git a/apps/angular/interop-rxjs-signal/tsconfig.json b/apps/performance/12-optimize-change-detection/tsconfig.json similarity index 100% rename from apps/angular/interop-rxjs-signal/tsconfig.json rename to apps/performance/12-optimize-change-detection/tsconfig.json diff --git a/apps/performance/scroll-cd/tsconfig.spec.json b/apps/performance/12-optimize-change-detection/tsconfig.spec.json similarity index 100% rename from apps/performance/scroll-cd/tsconfig.spec.json rename to apps/performance/12-optimize-change-detection/tsconfig.spec.json diff --git a/apps/performance/default-onpush/.eslintrc.json b/apps/performance/34-default-vs-onpush/.eslintrc.json similarity index 100% rename from apps/performance/default-onpush/.eslintrc.json rename to apps/performance/34-default-vs-onpush/.eslintrc.json diff --git a/apps/performance/34-default-vs-onpush/README.md b/apps/performance/34-default-vs-onpush/README.md new file mode 100644 index 000000000..ab82704b5 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/README.md @@ -0,0 +1,13 @@ +# Default vs OnPush + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve performance-default-vs-onpush +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/34-default-onpush/). diff --git a/apps/performance/34-default-vs-onpush/project.json b/apps/performance/34-default-vs-onpush/project.json new file mode 100644 index 000000000..f81cb74a3 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/project.json @@ -0,0 +1,75 @@ +{ + "name": "performance-default-vs-onpush", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/34-default-vs-onpush/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/34-default-vs-onpush", + "index": "apps/performance/34-default-vs-onpush/src/index.html", + "main": "apps/performance/34-default-vs-onpush/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/34-default-vs-onpush/tsconfig.app.json", + "assets": [ + "apps/performance/34-default-vs-onpush/src/favicon.ico", + "apps/performance/34-default-vs-onpush/src/assets" + ], + "styles": [ + "apps/performance/34-default-vs-onpush/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "performance-default-vs-onpush:build:production" + }, + "development": { + "buildTarget": "performance-default-vs-onpush:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "performance-default-vs-onpush:build" + } + } + } +} diff --git a/apps/performance/34-default-vs-onpush/src/app/app.component.ts b/apps/performance/34-default-vs-onpush/src/app/app.component.ts new file mode 100644 index 000000000..88b0a6571 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/src/app/app.component.ts @@ -0,0 +1,21 @@ +import { Component } from '@angular/core'; +import { randFirstName } from '@ngneat/falso'; +import { PersonListComponent } from './person-list.component'; +import { RandomComponent } from './random.component'; + +@Component({ + imports: [PersonListComponent, RandomComponent], + selector: 'app-root', + template: ` + + +
+ + +
+ `, +}) +export class AppComponent { + girlList = randFirstName({ gender: 'female', length: 10 }); + boyList = randFirstName({ gender: 'male', length: 10 }); +} diff --git a/apps/performance/default-onpush/src/app/app.config.ts b/apps/performance/34-default-vs-onpush/src/app/app.config.ts similarity index 100% rename from apps/performance/default-onpush/src/app/app.config.ts rename to apps/performance/34-default-vs-onpush/src/app/app.config.ts diff --git a/apps/performance/34-default-vs-onpush/src/app/person-list.component.ts b/apps/performance/34-default-vs-onpush/src/app/person-list.component.ts new file mode 100644 index 000000000..4cd92396a --- /dev/null +++ b/apps/performance/34-default-vs-onpush/src/app/person-list.component.ts @@ -0,0 +1,67 @@ +import { Component, Input } from '@angular/core'; + +import { CDFlashingDirective } from '@angular-challenges/shared/directives'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; + +@Component({ + selector: 'app-person-list', + imports: [ + CommonModule, + FormsModule, + MatListModule, + MatFormFieldModule, + MatInputModule, + MatChipsModule, + CDFlashingDirective, + ], + template: ` +

+ {{ title | titlecase }} +

+ + + + + + +
Empty list
+ +
+

+ {{ name }} +

+
+
+ +
+ `, + host: { + class: 'w-full flex flex-col items-center', + }, +}) +export class PersonListComponent { + @Input() names: string[] = []; + @Input() title = ''; + + label = ''; + + handleKey(event: KeyboardEvent) { + if (event.key === 'Enter') { + this.names?.unshift(this.label); + this.label = ''; + } + } +} diff --git a/apps/performance/default-onpush/src/app/random.component.ts b/apps/performance/34-default-vs-onpush/src/app/random.component.ts similarity index 93% rename from apps/performance/default-onpush/src/app/random.component.ts rename to apps/performance/34-default-vs-onpush/src/app/random.component.ts index d46cdd053..71479e28d 100644 --- a/apps/performance/default-onpush/src/app/random.component.ts +++ b/apps/performance/34-default-vs-onpush/src/app/random.component.ts @@ -3,7 +3,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-random', - standalone: true, template: `
I do nothing but I'm here
`, diff --git a/apps/performance/default-onpush/src/assets/.gitkeep b/apps/performance/34-default-vs-onpush/src/assets/.gitkeep similarity index 100% rename from apps/performance/default-onpush/src/assets/.gitkeep rename to apps/performance/34-default-vs-onpush/src/assets/.gitkeep diff --git a/apps/performance/ngfor-optimize/src/favicon.ico b/apps/performance/34-default-vs-onpush/src/favicon.ico similarity index 100% rename from apps/performance/ngfor-optimize/src/favicon.ico rename to apps/performance/34-default-vs-onpush/src/favicon.ico diff --git a/apps/performance/34-default-vs-onpush/src/index.html b/apps/performance/34-default-vs-onpush/src/index.html new file mode 100644 index 000000000..251489ea3 --- /dev/null +++ b/apps/performance/34-default-vs-onpush/src/index.html @@ -0,0 +1,13 @@ + + + + + performance-default-vs-onpush + + + + + + + + diff --git a/apps/testing/create-harness/src/main.ts b/apps/performance/34-default-vs-onpush/src/main.ts similarity index 100% rename from apps/testing/create-harness/src/main.ts rename to apps/performance/34-default-vs-onpush/src/main.ts diff --git a/apps/rxjs/catch-error/src/styles.scss b/apps/performance/34-default-vs-onpush/src/styles.scss similarity index 100% rename from apps/rxjs/catch-error/src/styles.scss rename to apps/performance/34-default-vs-onpush/src/styles.scss diff --git a/apps/rxjs/catch-error/tailwind.config.js b/apps/performance/34-default-vs-onpush/tailwind.config.js similarity index 100% rename from apps/rxjs/catch-error/tailwind.config.js rename to apps/performance/34-default-vs-onpush/tailwind.config.js diff --git a/apps/testing/checkbox/tsconfig.app.json b/apps/performance/34-default-vs-onpush/tsconfig.app.json similarity index 100% rename from apps/testing/checkbox/tsconfig.app.json rename to apps/performance/34-default-vs-onpush/tsconfig.app.json diff --git a/apps/performance/default-onpush/tsconfig.editor.json b/apps/performance/34-default-vs-onpush/tsconfig.editor.json similarity index 100% rename from apps/performance/default-onpush/tsconfig.editor.json rename to apps/performance/34-default-vs-onpush/tsconfig.editor.json diff --git a/apps/performance/christmas-web-worker/tsconfig.json b/apps/performance/34-default-vs-onpush/tsconfig.json similarity index 100% rename from apps/performance/christmas-web-worker/tsconfig.json rename to apps/performance/34-default-vs-onpush/tsconfig.json diff --git a/apps/performance/memoized/.eslintrc.json b/apps/performance/35-memoization/.eslintrc.json similarity index 100% rename from apps/performance/memoized/.eslintrc.json rename to apps/performance/35-memoization/.eslintrc.json diff --git a/apps/performance/35-memoization/README.md b/apps/performance/35-memoization/README.md new file mode 100644 index 000000000..a06a0e91d --- /dev/null +++ b/apps/performance/35-memoization/README.md @@ -0,0 +1,13 @@ +# Memoization + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve performance-memoization +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/35-memoize/). diff --git a/apps/performance/35-memoization/project.json b/apps/performance/35-memoization/project.json new file mode 100644 index 000000000..041308626 --- /dev/null +++ b/apps/performance/35-memoization/project.json @@ -0,0 +1,75 @@ +{ + "name": "performance-memoization", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/35-memoization/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/35-memoization", + "index": "apps/performance/35-memoization/src/index.html", + "main": "apps/performance/35-memoization/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/35-memoization/tsconfig.app.json", + "assets": [ + "apps/performance/35-memoization/src/favicon.ico", + "apps/performance/35-memoization/src/assets" + ], + "styles": [ + "apps/performance/35-memoization/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "performance-memoization:build:production" + }, + "development": { + "buildTarget": "performance-memoization:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "performance-memoization:build" + } + } + } +} diff --git a/apps/performance/35-memoization/src/app/app.component.ts b/apps/performance/35-memoization/src/app/app.component.ts new file mode 100644 index 000000000..04c7758fc --- /dev/null +++ b/apps/performance/35-memoization/src/app/app.component.ts @@ -0,0 +1,27 @@ +import { NgIf } from '@angular/common'; +import { Component } from '@angular/core'; +import { generateList } from './generateList'; +import { PersonListComponent } from './person-list.component'; + +@Component({ + imports: [PersonListComponent, NgIf], + selector: 'app-root', + template: ` +

Performance is key!!

+ + + + `, +}) +export class AppComponent { + persons = generateList(); + loadList = false; +} diff --git a/apps/performance/memoized/src/app/app.config.ts b/apps/performance/35-memoization/src/app/app.config.ts similarity index 100% rename from apps/performance/memoized/src/app/app.config.ts rename to apps/performance/35-memoization/src/app/app.config.ts diff --git a/apps/performance/memoized/src/app/generateList.ts b/apps/performance/35-memoization/src/app/generateList.ts similarity index 100% rename from apps/performance/memoized/src/app/generateList.ts rename to apps/performance/35-memoization/src/app/generateList.ts diff --git a/apps/performance/35-memoization/src/app/person-list.component.ts b/apps/performance/35-memoization/src/app/person-list.component.ts new file mode 100644 index 000000000..28cbac267 --- /dev/null +++ b/apps/performance/35-memoization/src/app/person-list.component.ts @@ -0,0 +1,63 @@ +import { Component, Input } from '@angular/core'; + +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; +import { Person } from './person.model'; + +const fibonacci = (num: number): number => { + if (num === 1 || num === 2) { + return 1; + } + return fibonacci(num - 1) + fibonacci(num - 2); +}; + +@Component({ + selector: 'app-person-list', + imports: [ + CommonModule, + FormsModule, + MatListModule, + MatFormFieldModule, + MatInputModule, + MatChipsModule, + ], + template: ` +

+ {{ title | titlecase }} +

+ + + + + + + +
+

{{ person.name }}

+ {{ calculate(person.fib) }} +
+
+
+ `, + host: { + class: 'w-full flex flex-col items-center', + }, +}) +export class PersonListComponent { + @Input() persons: Person[] = []; + @Input() title = ''; + + label = ''; + + calculate(num: number) { + return fibonacci(num); + } +} diff --git a/apps/performance/memoized/src/app/person.model.ts b/apps/performance/35-memoization/src/app/person.model.ts similarity index 100% rename from apps/performance/memoized/src/app/person.model.ts rename to apps/performance/35-memoization/src/app/person.model.ts diff --git a/apps/performance/memoized/src/assets/.gitkeep b/apps/performance/35-memoization/src/assets/.gitkeep similarity index 100% rename from apps/performance/memoized/src/assets/.gitkeep rename to apps/performance/35-memoization/src/assets/.gitkeep diff --git a/apps/performance/scroll-cd/src/favicon.ico b/apps/performance/35-memoization/src/favicon.ico similarity index 100% rename from apps/performance/scroll-cd/src/favicon.ico rename to apps/performance/35-memoization/src/favicon.ico diff --git a/apps/performance/35-memoization/src/index.html b/apps/performance/35-memoization/src/index.html new file mode 100644 index 000000000..39ddb9045 --- /dev/null +++ b/apps/performance/35-memoization/src/index.html @@ -0,0 +1,13 @@ + + + + + performance-memoization + + + + + + + + diff --git a/apps/testing/harness/src/main.ts b/apps/performance/35-memoization/src/main.ts similarity index 100% rename from apps/testing/harness/src/main.ts rename to apps/performance/35-memoization/src/main.ts diff --git a/apps/testing/checkbox/src/styles.scss b/apps/performance/35-memoization/src/styles.scss similarity index 100% rename from apps/testing/checkbox/src/styles.scss rename to apps/performance/35-memoization/src/styles.scss diff --git a/apps/testing/checkbox/tailwind.config.js b/apps/performance/35-memoization/tailwind.config.js similarity index 100% rename from apps/testing/checkbox/tailwind.config.js rename to apps/performance/35-memoization/tailwind.config.js diff --git a/apps/testing/create-harness/tsconfig.app.json b/apps/performance/35-memoization/tsconfig.app.json similarity index 100% rename from apps/testing/create-harness/tsconfig.app.json rename to apps/performance/35-memoization/tsconfig.app.json diff --git a/apps/nx/static-dynamic-import/tsconfig.editor.json b/apps/performance/35-memoization/tsconfig.editor.json similarity index 100% rename from apps/nx/static-dynamic-import/tsconfig.editor.json rename to apps/performance/35-memoization/tsconfig.editor.json diff --git a/apps/performance/default-onpush/tsconfig.json b/apps/performance/35-memoization/tsconfig.json similarity index 100% rename from apps/performance/default-onpush/tsconfig.json rename to apps/performance/35-memoization/tsconfig.json diff --git a/apps/performance/ngfor-biglist/.eslintrc.json b/apps/performance/36-ngfor-optimization/.eslintrc.json similarity index 100% rename from apps/performance/ngfor-biglist/.eslintrc.json rename to apps/performance/36-ngfor-optimization/.eslintrc.json diff --git a/apps/performance/36-ngfor-optimization/README.md b/apps/performance/36-ngfor-optimization/README.md new file mode 100644 index 000000000..2ee0bb20e --- /dev/null +++ b/apps/performance/36-ngfor-optimization/README.md @@ -0,0 +1,13 @@ +# NgFor Optimization + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve performance-ngfor-optimization +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/36-ngfor-optimize/). diff --git a/apps/performance/36-ngfor-optimization/jest.config.ts b/apps/performance/36-ngfor-optimization/jest.config.ts new file mode 100644 index 000000000..2e138df90 --- /dev/null +++ b/apps/performance/36-ngfor-optimization/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'performance-ngfor-optimization', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/performance/36-ngfor-optimization', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/performance/36-ngfor-optimization/project.json b/apps/performance/36-ngfor-optimization/project.json new file mode 100644 index 000000000..05dfcd1e2 --- /dev/null +++ b/apps/performance/36-ngfor-optimization/project.json @@ -0,0 +1,86 @@ +{ + "name": "performance-ngfor-optimization", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/36-ngfor-optimization/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/36-ngfor-optimization", + "index": "apps/performance/36-ngfor-optimization/src/index.html", + "main": "apps/performance/36-ngfor-optimization/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/36-ngfor-optimization/tsconfig.app.json", + "assets": [ + "apps/performance/36-ngfor-optimization/src/favicon.ico", + "apps/performance/36-ngfor-optimization/src/assets" + ], + "styles": [ + "apps/performance/36-ngfor-optimization/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "performance-ngfor-optimization:build:production" + }, + "development": { + "buildTarget": "performance-ngfor-optimization:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "performance-ngfor-optimization:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/performance/36-ngfor-optimization/src/app/app.component.ts b/apps/performance/36-ngfor-optimization/src/app/app.component.ts new file mode 100644 index 000000000..f1aa9f133 --- /dev/null +++ b/apps/performance/36-ngfor-optimization/src/app/app.component.ts @@ -0,0 +1,57 @@ +import { Component, OnInit, inject } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { PersonService } from './list.service'; +import { PersonListComponent } from './person-list.component'; + +@Component({ + imports: [ + PersonListComponent, + FormsModule, + MatFormFieldModule, + MatInputModule, + ], + providers: [PersonService], + selector: 'app-root', + template: ` +

+ List of Persons +

+ + + + + + + `, + host: { + class: 'flex items-center flex-col gap-5', + }, +}) +export class AppComponent implements OnInit { + readonly personService = inject(PersonService); + readonly persons = this.personService.persons; + + label = ''; + + ngOnInit(): void { + this.personService.loadPersons(); + } + + handleKey(event: any) { + if (event.keyCode === 13) { + this.personService.addPerson(this.label); + this.label = ''; + } + } +} diff --git a/apps/performance/ngfor-biglist/src/app/app.config.ts b/apps/performance/36-ngfor-optimization/src/app/app.config.ts similarity index 100% rename from apps/performance/ngfor-biglist/src/app/app.config.ts rename to apps/performance/36-ngfor-optimization/src/app/app.config.ts diff --git a/apps/performance/ngfor-optimize/src/app/generateList.ts b/apps/performance/36-ngfor-optimization/src/app/generateList.ts similarity index 100% rename from apps/performance/ngfor-optimize/src/app/generateList.ts rename to apps/performance/36-ngfor-optimization/src/app/generateList.ts diff --git a/apps/performance/ngfor-biglist/src/app/list.service.ts b/apps/performance/36-ngfor-optimization/src/app/list.service.ts similarity index 100% rename from apps/performance/ngfor-biglist/src/app/list.service.ts rename to apps/performance/36-ngfor-optimization/src/app/list.service.ts diff --git a/apps/performance/36-ngfor-optimization/src/app/person-list.component.ts b/apps/performance/36-ngfor-optimization/src/app/person-list.component.ts new file mode 100644 index 000000000..6d9b2b4af --- /dev/null +++ b/apps/performance/36-ngfor-optimization/src/app/person-list.component.ts @@ -0,0 +1,36 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +import { CommonModule } from '@angular/common'; +import { Person } from './person.model'; + +@Component({ + selector: 'app-person-list', + imports: [CommonModule], + template: ` +
+

{{ person.name }}

+
+ + +
+
+ `, + host: { + class: 'w-full flex flex-col', + }, +}) +export class PersonListComponent { + @Input() persons: Person[] = []; + @Output() delete = new EventEmitter(); + @Output() update = new EventEmitter(); +} diff --git a/apps/performance/ngfor-biglist/src/app/person.model.ts b/apps/performance/36-ngfor-optimization/src/app/person.model.ts similarity index 100% rename from apps/performance/ngfor-biglist/src/app/person.model.ts rename to apps/performance/36-ngfor-optimization/src/app/person.model.ts diff --git a/apps/performance/ngfor-biglist/src/assets/.gitkeep b/apps/performance/36-ngfor-optimization/src/assets/.gitkeep similarity index 100% rename from apps/performance/ngfor-biglist/src/assets/.gitkeep rename to apps/performance/36-ngfor-optimization/src/assets/.gitkeep diff --git a/apps/rxjs/catch-error/src/favicon.ico b/apps/performance/36-ngfor-optimization/src/favicon.ico similarity index 100% rename from apps/rxjs/catch-error/src/favicon.ico rename to apps/performance/36-ngfor-optimization/src/favicon.ico diff --git a/apps/performance/36-ngfor-optimization/src/index.html b/apps/performance/36-ngfor-optimization/src/index.html new file mode 100644 index 000000000..07ec600a8 --- /dev/null +++ b/apps/performance/36-ngfor-optimization/src/index.html @@ -0,0 +1,13 @@ + + + + + performance-ngfor-optimization + + + + + + + + diff --git a/apps/performance/36-ngfor-optimization/src/main.ts b/apps/performance/36-ngfor-optimization/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/performance/36-ngfor-optimization/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/testing/modal/src/styles.scss b/apps/performance/36-ngfor-optimization/src/styles.scss similarity index 100% rename from apps/testing/modal/src/styles.scss rename to apps/performance/36-ngfor-optimization/src/styles.scss diff --git a/apps/testing/create-harness/src/test-setup.ts b/apps/performance/36-ngfor-optimization/src/test-setup.ts similarity index 100% rename from apps/testing/create-harness/src/test-setup.ts rename to apps/performance/36-ngfor-optimization/src/test-setup.ts diff --git a/apps/testing/create-harness/tailwind.config.js b/apps/performance/36-ngfor-optimization/tailwind.config.js similarity index 100% rename from apps/testing/create-harness/tailwind.config.js rename to apps/performance/36-ngfor-optimization/tailwind.config.js diff --git a/apps/testing/harness/tsconfig.app.json b/apps/performance/36-ngfor-optimization/tsconfig.app.json similarity index 100% rename from apps/testing/harness/tsconfig.app.json rename to apps/performance/36-ngfor-optimization/tsconfig.app.json diff --git a/apps/rxjs/catch-error/tsconfig.editor.json b/apps/performance/36-ngfor-optimization/tsconfig.editor.json similarity index 100% rename from apps/rxjs/catch-error/tsconfig.editor.json rename to apps/performance/36-ngfor-optimization/tsconfig.editor.json diff --git a/apps/performance/ngfor-optimize/tsconfig.json b/apps/performance/36-ngfor-optimization/tsconfig.json similarity index 100% rename from apps/performance/ngfor-optimize/tsconfig.json rename to apps/performance/36-ngfor-optimization/tsconfig.json diff --git a/apps/performance/36-ngfor-optimization/tsconfig.spec.json b/apps/performance/36-ngfor-optimization/tsconfig.spec.json new file mode 100644 index 000000000..1a4817a7d --- /dev/null +++ b/apps/performance/36-ngfor-optimization/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node", "@testing-library/jest-dom"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/performance/ngfor-optimize/.eslintrc.json b/apps/performance/37-optimize-big-list/.eslintrc.json similarity index 100% rename from apps/performance/ngfor-optimize/.eslintrc.json rename to apps/performance/37-optimize-big-list/.eslintrc.json diff --git a/apps/performance/37-optimize-big-list/README.md b/apps/performance/37-optimize-big-list/README.md new file mode 100644 index 000000000..1d8e134c2 --- /dev/null +++ b/apps/performance/37-optimize-big-list/README.md @@ -0,0 +1,13 @@ +# NgFor optimize big list + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve performance-optimize-big-list +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/37-ngfor-biglist/). diff --git a/apps/performance/37-optimize-big-list/project.json b/apps/performance/37-optimize-big-list/project.json new file mode 100644 index 000000000..fbd03771e --- /dev/null +++ b/apps/performance/37-optimize-big-list/project.json @@ -0,0 +1,75 @@ +{ + "name": "performance-optimize-big-list", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/37-optimize-big-list/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/37-optimize-big-list", + "index": "apps/performance/37-optimize-big-list/src/index.html", + "main": "apps/performance/37-optimize-big-list/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/37-optimize-big-list/tsconfig.app.json", + "assets": [ + "apps/performance/37-optimize-big-list/src/favicon.ico", + "apps/performance/37-optimize-big-list/src/assets" + ], + "styles": [ + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", + "apps/performance/37-optimize-big-list/src/styles.scss" + ], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "performance-optimize-big-list:build:production" + }, + "development": { + "buildTarget": "performance-optimize-big-list:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "performance-optimize-big-list:build" + } + } + } +} diff --git a/apps/performance/37-optimize-big-list/src/app/app.component.ts b/apps/performance/37-optimize-big-list/src/app/app.component.ts new file mode 100644 index 000000000..c441134df --- /dev/null +++ b/apps/performance/37-optimize-big-list/src/app/app.component.ts @@ -0,0 +1,41 @@ +import { NgIf } from '@angular/common'; +import { Component, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { generateList } from './generateList'; +import { PersonService } from './list.service'; +import { PersonListComponent } from './person-list.component'; + +@Component({ + imports: [ + NgIf, + PersonListComponent, + FormsModule, + MatFormFieldModule, + MatInputModule, + ], + providers: [PersonService], + selector: 'app-root', + template: ` + + + + `, + host: { + class: 'flex items-center flex-col gap-5', + }, +}) +export class AppComponent { + readonly persons = signal(generateList()); + readonly loadList = signal(false); + + label = ''; +} diff --git a/apps/performance/ngfor-optimize/src/app/app.config.ts b/apps/performance/37-optimize-big-list/src/app/app.config.ts similarity index 100% rename from apps/performance/ngfor-optimize/src/app/app.config.ts rename to apps/performance/37-optimize-big-list/src/app/app.config.ts diff --git a/apps/performance/ngfor-biglist/src/app/generateList.ts b/apps/performance/37-optimize-big-list/src/app/generateList.ts similarity index 100% rename from apps/performance/ngfor-biglist/src/app/generateList.ts rename to apps/performance/37-optimize-big-list/src/app/generateList.ts diff --git a/apps/performance/ngfor-optimize/src/app/list.service.ts b/apps/performance/37-optimize-big-list/src/app/list.service.ts similarity index 100% rename from apps/performance/ngfor-optimize/src/app/list.service.ts rename to apps/performance/37-optimize-big-list/src/app/list.service.ts diff --git a/apps/performance/37-optimize-big-list/src/app/person-list.component.ts b/apps/performance/37-optimize-big-list/src/app/person-list.component.ts new file mode 100644 index 000000000..6159baaaa --- /dev/null +++ b/apps/performance/37-optimize-big-list/src/app/person-list.component.ts @@ -0,0 +1,29 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +import { NgForTrackByModule } from '@angular-challenges/shared/directives'; +import { CommonModule } from '@angular/common'; +import { Person } from './person.model'; + +@Component({ + selector: 'app-person-list', + imports: [CommonModule, NgForTrackByModule], + template: ` +
+
+
+

{{ person.name }}

+

{{ person.email }}

+
+
+
+ `, + host: { + class: 'w-full flex flex-col', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PersonListComponent { + @Input() persons: Person[] = []; +} diff --git a/apps/performance/ngfor-optimize/src/app/person.model.ts b/apps/performance/37-optimize-big-list/src/app/person.model.ts similarity index 100% rename from apps/performance/ngfor-optimize/src/app/person.model.ts rename to apps/performance/37-optimize-big-list/src/app/person.model.ts diff --git a/apps/performance/ngfor-optimize/src/assets/.gitkeep b/apps/performance/37-optimize-big-list/src/assets/.gitkeep similarity index 100% rename from apps/performance/ngfor-optimize/src/assets/.gitkeep rename to apps/performance/37-optimize-big-list/src/assets/.gitkeep diff --git a/apps/rxjs/pipe-bug/src/favicon.ico b/apps/performance/37-optimize-big-list/src/favicon.ico similarity index 100% rename from apps/rxjs/pipe-bug/src/favicon.ico rename to apps/performance/37-optimize-big-list/src/favicon.ico diff --git a/apps/performance/37-optimize-big-list/src/index.html b/apps/performance/37-optimize-big-list/src/index.html new file mode 100644 index 000000000..f93d2d26f --- /dev/null +++ b/apps/performance/37-optimize-big-list/src/index.html @@ -0,0 +1,13 @@ + + + + + performance-optimize-big-list + + + + + + + + diff --git a/apps/performance/37-optimize-big-list/src/main.ts b/apps/performance/37-optimize-big-list/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/performance/37-optimize-big-list/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/performance/37-optimize-big-list/src/styles.scss b/apps/performance/37-optimize-big-list/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/performance/37-optimize-big-list/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/testing/harness/tailwind.config.js b/apps/performance/37-optimize-big-list/tailwind.config.js similarity index 100% rename from apps/testing/harness/tailwind.config.js rename to apps/performance/37-optimize-big-list/tailwind.config.js diff --git a/apps/typescript/overload/tsconfig.app.json b/apps/performance/37-optimize-big-list/tsconfig.app.json similarity index 100% rename from apps/typescript/overload/tsconfig.app.json rename to apps/performance/37-optimize-big-list/tsconfig.app.json diff --git a/apps/performance/christmas-web-worker/tsconfig.editor.json b/apps/performance/37-optimize-big-list/tsconfig.editor.json similarity index 100% rename from apps/performance/christmas-web-worker/tsconfig.editor.json rename to apps/performance/37-optimize-big-list/tsconfig.editor.json diff --git a/apps/performance/memoized/tsconfig.json b/apps/performance/37-optimize-big-list/tsconfig.json similarity index 100% rename from apps/performance/memoized/tsconfig.json rename to apps/performance/37-optimize-big-list/tsconfig.json diff --git a/apps/performance/christmas-web-worker/.eslintrc.json b/apps/performance/40-web-workers/.eslintrc.json similarity index 100% rename from apps/performance/christmas-web-worker/.eslintrc.json rename to apps/performance/40-web-workers/.eslintrc.json diff --git a/apps/performance/40-web-workers/README.md b/apps/performance/40-web-workers/README.md new file mode 100644 index 000000000..067777a8f --- /dev/null +++ b/apps/performance/40-web-workers/README.md @@ -0,0 +1,13 @@ +# Web workers + +> Author: Thomas Laforge + +### Run Application + +```bash +npx nx serve performance-web-workers +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/40-christmas-web-worker/). diff --git a/apps/performance/40-web-workers/project.json b/apps/performance/40-web-workers/project.json new file mode 100644 index 000000000..843a35c60 --- /dev/null +++ b/apps/performance/40-web-workers/project.json @@ -0,0 +1,69 @@ +{ + "name": "performance-web-workers", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/performance/40-web-workers/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/performance/40-web-workers", + "index": "apps/performance/40-web-workers/src/index.html", + "browser": "apps/performance/40-web-workers/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/performance/40-web-workers/tsconfig.app.json", + "assets": [ + "apps/performance/40-web-workers/src/favicon.ico", + "apps/performance/40-web-workers/src/assets" + ], + "styles": ["apps/performance/40-web-workers/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "performance-web-workers:build:production" + }, + "development": { + "buildTarget": "performance-web-workers:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "performance-web-workers:build" + } + } + } +} diff --git a/apps/performance/40-web-workers/src/app/app.component.ts b/apps/performance/40-web-workers/src/app/app.component.ts new file mode 100644 index 000000000..583572ed2 --- /dev/null +++ b/apps/performance/40-web-workers/src/app/app.component.ts @@ -0,0 +1,31 @@ +import { CommonModule } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { HeavyCalculationService } from './heavy-calculation.service'; +import { UnknownPersonComponent } from './unknown-person/unknown-person.component'; + +@Component({ + imports: [CommonModule, UnknownPersonComponent], + providers: [HeavyCalculationService], + selector: 'app-root', + template: ` + + +
Progress: {{ loadingPercentage() }}%
+ `, + host: { + class: `flex flex-col h-screen w-screen bg-[#1f75c0]`, + }, +}) +export class AppComponent { + private heavyCalculationService = inject(HeavyCalculationService); + + readonly loadingPercentage = this.heavyCalculationService.loadingPercentage; + + discover() { + this.heavyCalculationService.startLoading(); + } +} diff --git a/apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts b/apps/performance/40-web-workers/src/app/heavy-calculation.service.ts similarity index 100% rename from apps/performance/christmas-web-worker/src/app/heavy-calculation.service.ts rename to apps/performance/40-web-workers/src/app/heavy-calculation.service.ts diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css b/apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.css similarity index 100% rename from apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.css rename to apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.css diff --git a/apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts b/apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.ts similarity index 100% rename from apps/performance/christmas-web-worker/src/app/unknown-person/unknown-person.component.ts rename to apps/performance/40-web-workers/src/app/unknown-person/unknown-person.component.ts diff --git a/apps/performance/scroll-cd/src/assets/.gitkeep b/apps/performance/40-web-workers/src/assets/.gitkeep similarity index 100% rename from apps/performance/scroll-cd/src/assets/.gitkeep rename to apps/performance/40-web-workers/src/assets/.gitkeep diff --git a/apps/rxjs/race-condition/src/favicon.ico b/apps/performance/40-web-workers/src/favicon.ico similarity index 100% rename from apps/rxjs/race-condition/src/favicon.ico rename to apps/performance/40-web-workers/src/favicon.ico diff --git a/apps/performance/40-web-workers/src/index.html b/apps/performance/40-web-workers/src/index.html new file mode 100644 index 000000000..fa0cf99ae --- /dev/null +++ b/apps/performance/40-web-workers/src/index.html @@ -0,0 +1,13 @@ + + + + + performance-web-worker + + + + + + + + diff --git a/apps/rxjs/pipe-bug/src/main.ts b/apps/performance/40-web-workers/src/main.ts similarity index 100% rename from apps/rxjs/pipe-bug/src/main.ts rename to apps/performance/40-web-workers/src/main.ts diff --git a/apps/performance/40-web-workers/src/styles.scss b/apps/performance/40-web-workers/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/performance/40-web-workers/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/testing/modal/tailwind.config.js b/apps/performance/40-web-workers/tailwind.config.js similarity index 100% rename from apps/testing/modal/tailwind.config.js rename to apps/performance/40-web-workers/tailwind.config.js diff --git a/apps/performance/40-web-workers/tsconfig.app.json b/apps/performance/40-web-workers/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/performance/40-web-workers/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/performance/memoized/tsconfig.editor.json b/apps/performance/40-web-workers/tsconfig.editor.json similarity index 100% rename from apps/performance/memoized/tsconfig.editor.json rename to apps/performance/40-web-workers/tsconfig.editor.json diff --git a/apps/performance/ngfor-biglist/tsconfig.json b/apps/performance/40-web-workers/tsconfig.json similarity index 100% rename from apps/performance/ngfor-biglist/tsconfig.json rename to apps/performance/40-web-workers/tsconfig.json diff --git a/apps/performance/christmas-web-worker/README.md b/apps/performance/christmas-web-worker/README.md deleted file mode 100644 index 6da93949a..000000000 --- a/apps/performance/christmas-web-worker/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Web workers - -> Author: Thomas Laforge - -### Run Application - -```bash -npx nx serve performance-christmas-web-worker -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/40-christmas-web-worker/). diff --git a/apps/performance/christmas-web-worker/project.json b/apps/performance/christmas-web-worker/project.json deleted file mode 100644 index a1eae3c67..000000000 --- a/apps/performance/christmas-web-worker/project.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "name": "performance-christmas-web-worker", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/performance/christmas-web-worker/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:application", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/performance/christmas-web-worker", - "index": "apps/performance/christmas-web-worker/src/index.html", - "browser": "apps/performance/christmas-web-worker/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/performance/christmas-web-worker/tsconfig.app.json", - "assets": [ - "apps/performance/christmas-web-worker/src/favicon.ico", - "apps/performance/christmas-web-worker/src/assets" - ], - "styles": ["apps/performance/christmas-web-worker/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "performance-christmas-web-worker:build:production" - }, - "development": { - "buildTarget": "performance-christmas-web-worker:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "performance-christmas-web-worker:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/performance/christmas-web-worker/**/*.ts", - "apps/performance/christmas-web-worker/**/*.html" - ] - } - } - } -} diff --git a/apps/performance/christmas-web-worker/src/app/app.component.ts b/apps/performance/christmas-web-worker/src/app/app.component.ts deleted file mode 100644 index 6b9846b13..000000000 --- a/apps/performance/christmas-web-worker/src/app/app.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { HeavyCalculationService } from './heavy-calculation.service'; -import { UnknownPersonComponent } from './unknown-person/unknown-person.component'; - -@Component({ - standalone: true, - imports: [CommonModule, UnknownPersonComponent], - providers: [HeavyCalculationService], - selector: 'app-root', - template: ` - - -
Progress: {{ loadingPercentage() }}%
- `, - host: { - class: `flex flex-col h-screen w-screen bg-[#1f75c0]`, - }, -}) -export class AppComponent { - private heavyCalculationService = inject(HeavyCalculationService); - - readonly loadingPercentage = this.heavyCalculationService.loadingPercentage; - - discover() { - this.heavyCalculationService.startLoading(); - } -} diff --git a/apps/performance/christmas-web-worker/src/index.html b/apps/performance/christmas-web-worker/src/index.html deleted file mode 100644 index 4ca378971..000000000 --- a/apps/performance/christmas-web-worker/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - performance-christmas-web-worker - - - - - - - - diff --git a/apps/performance/default-onpush/README.md b/apps/performance/default-onpush/README.md deleted file mode 100644 index 29d7696ff..000000000 --- a/apps/performance/default-onpush/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Default vs OnPush - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve performance-default-onpush -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/34-default-onpush/). diff --git a/apps/performance/default-onpush/project.json b/apps/performance/default-onpush/project.json deleted file mode 100644 index 2f819ee75..000000000 --- a/apps/performance/default-onpush/project.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "performance-default-onpush", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/performance/default-onpush/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/performance/default-onpush", - "index": "apps/performance/default-onpush/src/index.html", - "main": "apps/performance/default-onpush/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/performance/default-onpush/tsconfig.app.json", - "assets": [ - "apps/performance/default-onpush/src/favicon.ico", - "apps/performance/default-onpush/src/assets" - ], - "styles": [ - "apps/performance/default-onpush/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "performance-default-onpush:build:production" - }, - "development": { - "buildTarget": "performance-default-onpush:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "performance-default-onpush:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/performance/default-onpush/**/*.ts", - "apps/performance/default-onpush/**/*.html" - ] - } - } - } -} diff --git a/apps/performance/default-onpush/src/app/app.component.ts b/apps/performance/default-onpush/src/app/app.component.ts deleted file mode 100644 index 1eab3c839..000000000 --- a/apps/performance/default-onpush/src/app/app.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component } from '@angular/core'; -import { randFirstName } from '@ngneat/falso'; -import { PersonListComponent } from './person-list.component'; -import { RandomComponent } from './random.component'; - -@Component({ - standalone: true, - imports: [PersonListComponent, RandomComponent], - selector: 'app-root', - template: ` - - -
- - -
- `, -}) -export class AppComponent { - girlList = randFirstName({ gender: 'female', length: 10 }); - boyList = randFirstName({ gender: 'male', length: 10 }); -} diff --git a/apps/performance/default-onpush/src/app/person-list.component.ts b/apps/performance/default-onpush/src/app/person-list.component.ts deleted file mode 100644 index c4f556945..000000000 --- a/apps/performance/default-onpush/src/app/person-list.component.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { CDFlashingDirective } from '@angular-challenges/shared/directives'; -import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { MatListModule } from '@angular/material/list'; - -@Component({ - selector: 'app-person-list', - standalone: true, - imports: [ - CommonModule, - FormsModule, - MatListModule, - MatFormFieldModule, - MatInputModule, - MatChipsModule, - CDFlashingDirective, - ], - template: ` -

- {{ title | titlecase }} -

- - - - - - -
Empty list
- -
-

- {{ name }} -

-
-
- -
- `, - host: { - class: 'w-full flex flex-col items-center', - }, -}) -export class PersonListComponent { - @Input() names: string[] = []; - @Input() title = ''; - - label = ''; - - handleKey(event: any) { - if (event.keyCode === 13) { - this.names?.unshift(this.label); - this.label = ''; - } - } -} diff --git a/apps/performance/default-onpush/src/index.html b/apps/performance/default-onpush/src/index.html deleted file mode 100644 index eecd767f7..000000000 --- a/apps/performance/default-onpush/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Default OnPush - - - - - - - - diff --git a/apps/performance/memoized/README.md b/apps/performance/memoized/README.md deleted file mode 100644 index 520efb1f1..000000000 --- a/apps/performance/memoized/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Memoization - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve performance-memoized -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/35-memoize/). diff --git a/apps/performance/memoized/project.json b/apps/performance/memoized/project.json deleted file mode 100644 index e613c1303..000000000 --- a/apps/performance/memoized/project.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "performance-memoized", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/performance/memoized/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/performance/memoized", - "index": "apps/performance/memoized/src/index.html", - "main": "apps/performance/memoized/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/performance/memoized/tsconfig.app.json", - "assets": [ - "apps/performance/memoized/src/favicon.ico", - "apps/performance/memoized/src/assets" - ], - "styles": [ - "apps/performance/memoized/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "performance-memoized:build:production" - }, - "development": { - "buildTarget": "performance-memoized:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "performance-memoized:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/performance/memoized/**/*.ts", - "apps/performance/memoized/**/*.html" - ] - } - } - } -} diff --git a/apps/performance/memoized/src/app/app.component.ts b/apps/performance/memoized/src/app/app.component.ts deleted file mode 100644 index 4b24fced0..000000000 --- a/apps/performance/memoized/src/app/app.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { NgIf } from '@angular/common'; -import { Component } from '@angular/core'; -import { generateList } from './generateList'; -import { PersonListComponent } from './person-list.component'; - -@Component({ - standalone: true, - imports: [PersonListComponent, NgIf], - selector: 'app-root', - template: ` -

Performance is key!!

- - - - `, -}) -export class AppComponent { - persons = generateList(); - loadList = false; -} diff --git a/apps/performance/memoized/src/app/person-list.component.ts b/apps/performance/memoized/src/app/person-list.component.ts deleted file mode 100644 index 4a425d4f2..000000000 --- a/apps/performance/memoized/src/app/person-list.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Component, Input } from '@angular/core'; - -import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; -import { MatChipsModule } from '@angular/material/chips'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { MatListModule } from '@angular/material/list'; -import { Person } from './person.model'; - -const fibonacci = (num: number): number => { - if (num === 1 || num === 2) { - return 1; - } - return fibonacci(num - 1) + fibonacci(num - 2); -}; - -@Component({ - selector: 'app-person-list', - standalone: true, - imports: [ - CommonModule, - FormsModule, - MatListModule, - MatFormFieldModule, - MatInputModule, - MatChipsModule, - ], - template: ` -

- {{ title | titlecase }} -

- - - - - - - -
-

{{ person.name }}

- {{ calculate(person.fib) }} -
-
-
- `, - host: { - class: 'w-full flex flex-col items-center', - }, -}) -export class PersonListComponent { - @Input() persons: Person[] = []; - @Input() title = ''; - - label = ''; - - calculate(num: number) { - return fibonacci(num); - } -} diff --git a/apps/performance/memoized/src/index.html b/apps/performance/memoized/src/index.html deleted file mode 100644 index 1c07d985d..000000000 --- a/apps/performance/memoized/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - performance-memoized - - - - - - - - diff --git a/apps/performance/ngfor-biglist/README.md b/apps/performance/ngfor-biglist/README.md deleted file mode 100644 index 4d164f0c9..000000000 --- a/apps/performance/ngfor-biglist/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# NgFor optimize big list - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve performance-ngfor-biglist -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/37-ngfor-biglist/). diff --git a/apps/performance/ngfor-biglist/project.json b/apps/performance/ngfor-biglist/project.json deleted file mode 100644 index 22d61fe16..000000000 --- a/apps/performance/ngfor-biglist/project.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "performance-ngfor-biglist", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/performance/ngfor-biglist/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/performance/ngfor-biglist", - "index": "apps/performance/ngfor-biglist/src/index.html", - "main": "apps/performance/ngfor-biglist/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/performance/ngfor-biglist/tsconfig.app.json", - "assets": [ - "apps/performance/ngfor-biglist/src/favicon.ico", - "apps/performance/ngfor-biglist/src/assets" - ], - "styles": [ - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", - "apps/performance/ngfor-biglist/src/styles.scss" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "performance-ngfor-biglist:build:production" - }, - "development": { - "buildTarget": "performance-ngfor-biglist:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "performance-ngfor-biglist:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/performance/ngfor-biglist/**/*.ts", - "apps/performance/ngfor-biglist/**/*.html" - ] - } - } - } -} diff --git a/apps/performance/ngfor-biglist/src/app/app.component.ts b/apps/performance/ngfor-biglist/src/app/app.component.ts deleted file mode 100644 index 9c26149b2..000000000 --- a/apps/performance/ngfor-biglist/src/app/app.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { NgIf } from '@angular/common'; -import { Component, signal } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { generateList } from './generateList'; -import { PersonService } from './list.service'; -import { PersonListComponent } from './person-list.component'; - -@Component({ - standalone: true, - imports: [ - NgIf, - PersonListComponent, - FormsModule, - MatFormFieldModule, - MatInputModule, - ], - providers: [PersonService], - selector: 'app-root', - template: ` - - - - `, - host: { - class: 'flex items-center flex-col gap-5', - }, -}) -export class AppComponent { - readonly persons = signal(generateList()); - readonly loadList = signal(false); - - label = ''; -} diff --git a/apps/performance/ngfor-biglist/src/app/person-list.component.ts b/apps/performance/ngfor-biglist/src/app/person-list.component.ts deleted file mode 100644 index 4d438e664..000000000 --- a/apps/performance/ngfor-biglist/src/app/person-list.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; - -import { NgForTrackByModule } from '@angular-challenges/shared/directives'; -import { CommonModule } from '@angular/common'; -import { Person } from './person.model'; - -@Component({ - selector: 'app-person-list', - standalone: true, - imports: [CommonModule, NgForTrackByModule], - template: ` -
-
-
-

{{ person.name }}

-

{{ person.email }}

-
-
-
- `, - host: { - class: 'w-full flex flex-col', - }, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class PersonListComponent { - @Input() persons: Person[] = []; -} diff --git a/apps/performance/ngfor-biglist/src/index.html b/apps/performance/ngfor-biglist/src/index.html deleted file mode 100644 index 1b058276a..000000000 --- a/apps/performance/ngfor-biglist/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - performance-ngfor-biglist - - - - - - - - diff --git a/apps/performance/ngfor-optimize/README.md b/apps/performance/ngfor-optimize/README.md deleted file mode 100644 index 1e9b2f833..000000000 --- a/apps/performance/ngfor-optimize/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# NgFor Optimization - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve performance-ngfor-optimize -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/36-ngfor-optimize/). diff --git a/apps/performance/ngfor-optimize/jest.config.ts b/apps/performance/ngfor-optimize/jest.config.ts deleted file mode 100644 index 49ac9d7ac..000000000 --- a/apps/performance/ngfor-optimize/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'performance-ngfor-optimize', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/performance/ngfor-optimize', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/performance/ngfor-optimize/project.json b/apps/performance/ngfor-optimize/project.json deleted file mode 100644 index 57538baa0..000000000 --- a/apps/performance/ngfor-optimize/project.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "name": "performance-ngfor-optimize", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/performance/ngfor-optimize/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/performance/ngfor-optimize", - "index": "apps/performance/ngfor-optimize/src/index.html", - "main": "apps/performance/ngfor-optimize/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/performance/ngfor-optimize/tsconfig.app.json", - "assets": [ - "apps/performance/ngfor-optimize/src/favicon.ico", - "apps/performance/ngfor-optimize/src/assets" - ], - "styles": [ - "apps/performance/ngfor-optimize/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "performance-ngfor-optimize:build:production" - }, - "development": { - "buildTarget": "performance-ngfor-optimize:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "performance-ngfor-optimize:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/performance/ngfor-optimize/**/*.ts", - "apps/performance/ngfor-optimize/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/performance/ngfor-optimize/jest.config.ts" - } - } - } -} diff --git a/apps/performance/ngfor-optimize/src/app/app.component.ts b/apps/performance/ngfor-optimize/src/app/app.component.ts deleted file mode 100644 index fb9e98516..000000000 --- a/apps/performance/ngfor-optimize/src/app/app.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Component, OnInit, inject } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { PersonService } from './list.service'; -import { PersonListComponent } from './person-list.component'; - -@Component({ - standalone: true, - imports: [ - PersonListComponent, - FormsModule, - MatFormFieldModule, - MatInputModule, - ], - providers: [PersonService], - selector: 'app-root', - template: ` -

- List of Persons -

- - - - - - - `, - host: { - class: 'flex items-center flex-col gap-5', - }, -}) -export class AppComponent implements OnInit { - readonly personService = inject(PersonService); - readonly persons = this.personService.persons; - - label = ''; - - ngOnInit(): void { - this.personService.loadPersons(); - } - - handleKey(event: any) { - if (event.keyCode === 13) { - this.personService.addPerson(this.label); - this.label = ''; - } - } -} diff --git a/apps/performance/ngfor-optimize/src/app/person-list.component.ts b/apps/performance/ngfor-optimize/src/app/person-list.component.ts deleted file mode 100644 index ca04956d0..000000000 --- a/apps/performance/ngfor-optimize/src/app/person-list.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; - -import { CommonModule } from '@angular/common'; -import { Person } from './person.model'; - -@Component({ - selector: 'app-person-list', - standalone: true, - imports: [CommonModule], - template: ` -
-

{{ person.name }}

-
- - -
-
- `, - host: { - class: 'w-full flex flex-col', - }, -}) -export class PersonListComponent { - @Input() persons: Person[] = []; - @Output() delete = new EventEmitter(); - @Output() update = new EventEmitter(); -} diff --git a/apps/performance/ngfor-optimize/src/index.html b/apps/performance/ngfor-optimize/src/index.html deleted file mode 100644 index e5b79903e..000000000 --- a/apps/performance/ngfor-optimize/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - performance-ngfor-optimize - - - - - - - - diff --git a/apps/performance/scroll-cd/README.md b/apps/performance/scroll-cd/README.md deleted file mode 100644 index dc0c31301..000000000 --- a/apps/performance/scroll-cd/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Optimize Change Detection - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve performance-scroll-cd -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/performance/12-performance-scroll-cd/). diff --git a/apps/performance/scroll-cd/jest.config.ts b/apps/performance/scroll-cd/jest.config.ts deleted file mode 100644 index 7e8ea5b99..000000000 --- a/apps/performance/scroll-cd/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'performance-scroll-cd', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/apps/performance/scroll-cd', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/performance/scroll-cd/project.json b/apps/performance/scroll-cd/project.json deleted file mode 100644 index 9affd7c3e..000000000 --- a/apps/performance/scroll-cd/project.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "performance-scroll-cd", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/performance/scroll-cd/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/performance/scroll-cd", - "index": "apps/performance/scroll-cd/src/index.html", - "main": "apps/performance/scroll-cd/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/performance/scroll-cd/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/performance/scroll-cd/src/favicon.ico", - "apps/performance/scroll-cd/src/assets" - ], - "styles": ["apps/performance/scroll-cd/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "performance-scroll-cd:build:production" - }, - "development": { - "buildTarget": "performance-scroll-cd:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "performance-scroll-cd:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/performance/scroll-cd/**/*.ts", - "apps/performance/scroll-cd/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/performance/scroll-cd/jest.config.ts" - } - } - }, - "tags": [] -} diff --git a/apps/performance/scroll-cd/src/app/app.component.ts b/apps/performance/scroll-cd/src/app/app.component.ts deleted file mode 100644 index e75ef991e..000000000 --- a/apps/performance/scroll-cd/src/app/app.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AsyncPipe, NgIf } from '@angular/common'; -import { Component, HostListener } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; - -@Component({ - standalone: true, - imports: [NgIf, AsyncPipe], - selector: 'app-root', - template: ` -
Top
-
Middle
-
Bottom
- - `, - styles: [ - ` - :host { - height: 1500px; - display: flex; - flex-direction: column; - justify-content: space-between; - - button { - position: fixed; - bottom: 1rem; - left: 1rem; - z-index: 1; - padding: 1rem; - } - } - `, - ], -}) -export class AppComponent { - title = 'scroll-cd'; - - private displayButtonSubject = new BehaviorSubject(false); - displayButton$ = this.displayButtonSubject.asObservable(); - - @HostListener('window:scroll', ['$event']) - onScroll() { - const pos = window.pageYOffset; - this.displayButtonSubject.next(pos > 50); - } - - goToTop() { - window.scroll({ - top: 0, - left: 0, - behavior: 'smooth', - }); - } -} diff --git a/apps/performance/scroll-cd/src/index.html b/apps/performance/scroll-cd/src/index.html deleted file mode 100644 index 1d22cac27..000000000 --- a/apps/performance/scroll-cd/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - ScrollCd - - - - - - - - diff --git a/apps/rxjs/11-high-order-operator-bug/.eslintrc.json b/apps/rxjs/11-high-order-operator-bug/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/rxjs/11-high-order-operator-bug/README.md b/apps/rxjs/11-high-order-operator-bug/README.md new file mode 100644 index 000000000..5a4fa5512 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/README.md @@ -0,0 +1,13 @@ +# High Order Operator Bug + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve rxjs-high-order-operator-bug +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/rxjs/11-bug-chaining-operator/). diff --git a/apps/rxjs/11-high-order-operator-bug/project.json b/apps/rxjs/11-high-order-operator-bug/project.json new file mode 100644 index 000000000..e8e3f2045 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/project.json @@ -0,0 +1,73 @@ +{ + "name": "rxjs-high-order-operator-bug", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/rxjs/11-high-order-operator-bug/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/rxjs/11-high-order-operator-bug", + "index": "apps/rxjs/11-high-order-operator-bug/src/index.html", + "main": "apps/rxjs/11-high-order-operator-bug/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/rxjs/11-high-order-operator-bug/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/rxjs/11-high-order-operator-bug/src/favicon.ico", + "apps/rxjs/11-high-order-operator-bug/src/assets" + ], + "styles": ["apps/rxjs/11-high-order-operator-bug/src/styles.scss"], + "scripts": [], + "allowedCommonJsDependencies": ["seedrandom"] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "rxjs-high-order-operator-bug:build:production" + }, + "development": { + "buildTarget": "rxjs-high-order-operator-bug:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "rxjs-high-order-operator-bug:build" + } + } + } +} diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts b/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts new file mode 100644 index 000000000..fb80fb2b6 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts @@ -0,0 +1,52 @@ +/* eslint-disable @angular-eslint/component-selector */ +import { Component, inject, input, signal } from '@angular/core'; +import { take } from 'rxjs'; +import { AppService } from './app.service'; +import { TopicType } from './localDB.service'; + +@Component({ + selector: 'button-delete-topic', + template: ` + +
{{ message() }}
+ `, +}) +export class ButtonDeleteComponent { + readonly topic = input.required(); + + message = signal(''); + + private service = inject(AppService); + + deleteTopic() { + this.service + .deleteOldTopics(this.topic()) + .pipe(take(1)) + .subscribe((result) => + this.message.set( + result + ? `All ${this.topic()} have been deleted` + : `Error: deletion of some ${this.topic()} failed`, + ), + ); + } +} + +@Component({ + imports: [ButtonDeleteComponent], + selector: 'app-root', + template: ` + @for (info of allInfo(); track info.id) { +
{{ info.id }} - {{ info.topic }}
+ } + + Delete Food + Delete Sport + Delete Book + `, +}) +export class AppComponent { + private service = inject(AppService); + + allInfo = this.service.getAllInfo; +} diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts b/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts new file mode 100644 index 000000000..df2269a89 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts @@ -0,0 +1,19 @@ +import { inject, Injectable } from '@angular/core'; +import { merge, Observable, of } from 'rxjs'; +import { LocalDBService, TopicType } from './localDB.service'; + +@Injectable({ providedIn: 'root' }) +export class AppService { + private dbService = inject(LocalDBService); + + getAllInfo = this.dbService.infos; + + deleteOldTopics(type: TopicType): Observable { + const infoByType = this.dbService.searchByType(type); + return infoByType.length > 0 + ? infoByType + .map((t) => this.dbService.deleteOneTopic(t.id)) + .reduce((acc, curr) => merge(acc, curr), of(true)) + : of(true); + } +} diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts b/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts new file mode 100644 index 000000000..5a035e087 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts @@ -0,0 +1,53 @@ +/* eslint-disable @typescript-eslint/member-ordering */ +import { randomError } from '@angular-challenges/shared/utils'; +import { computed, Injectable, signal } from '@angular/core'; +import { of } from 'rxjs'; + +export type TopicType = 'food' | 'book' | 'sport'; + +interface Info { + id: number; + topic: TopicType; +} + +interface DBState { + infos: Info[]; +} + +const initialState: DBState = { + infos: [ + { id: 1, topic: 'book' }, + { id: 2, topic: 'book' }, + { id: 3, topic: 'book' }, + { id: 4, topic: 'book' }, + { id: 5, topic: 'food' }, + { id: 6, topic: 'food' }, + { id: 7, topic: 'book' }, + { id: 8, topic: 'book' }, + { id: 9, topic: 'book' }, + { id: 10, topic: 'sport' }, + ], +}; + +@Injectable({ providedIn: 'root' }) +export class LocalDBService { + private state = signal(initialState); + + infos = computed(() => this.state().infos); + + searchByType = (type: TopicType) => + this.infos().filter((i) => i.topic === type); + + deleteOne = (id: number) => { + this.state.set({ infos: this.state().infos.filter((i) => i.id !== id) }); + }; + + deleteOneTopic = (id: number) => + randomError({ + success: () => { + this.deleteOne(id); + return of(true); + }, + error: () => of(false), + }); +} diff --git a/apps/rxjs/catch-error/src/assets/.gitkeep b/apps/rxjs/11-high-order-operator-bug/src/assets/.gitkeep similarity index 100% rename from apps/rxjs/catch-error/src/assets/.gitkeep rename to apps/rxjs/11-high-order-operator-bug/src/assets/.gitkeep diff --git a/apps/testing/checkbox/src/favicon.ico b/apps/rxjs/11-high-order-operator-bug/src/favicon.ico similarity index 100% rename from apps/testing/checkbox/src/favicon.ico rename to apps/rxjs/11-high-order-operator-bug/src/favicon.ico diff --git a/apps/rxjs/11-high-order-operator-bug/src/index.html b/apps/rxjs/11-high-order-operator-bug/src/index.html new file mode 100644 index 000000000..148a16280 --- /dev/null +++ b/apps/rxjs/11-high-order-operator-bug/src/index.html @@ -0,0 +1,13 @@ + + + + + rxjs-high-order-operator-bug + + + + + + + + diff --git a/apps/testing/checkbox/src/main.ts b/apps/rxjs/11-high-order-operator-bug/src/main.ts similarity index 100% rename from apps/testing/checkbox/src/main.ts rename to apps/rxjs/11-high-order-operator-bug/src/main.ts diff --git a/apps/performance/scroll-cd/src/styles.scss b/apps/rxjs/11-high-order-operator-bug/src/styles.scss similarity index 100% rename from apps/performance/scroll-cd/src/styles.scss rename to apps/rxjs/11-high-order-operator-bug/src/styles.scss diff --git a/apps/rxjs/pipe-bug/tsconfig.app.json b/apps/rxjs/11-high-order-operator-bug/tsconfig.app.json similarity index 100% rename from apps/rxjs/pipe-bug/tsconfig.app.json rename to apps/rxjs/11-high-order-operator-bug/tsconfig.app.json diff --git a/apps/rxjs/pipe-bug/tsconfig.editor.json b/apps/rxjs/11-high-order-operator-bug/tsconfig.editor.json similarity index 100% rename from apps/rxjs/pipe-bug/tsconfig.editor.json rename to apps/rxjs/11-high-order-operator-bug/tsconfig.editor.json diff --git a/apps/rxjs/pipe-bug/tsconfig.json b/apps/rxjs/11-high-order-operator-bug/tsconfig.json similarity index 100% rename from apps/rxjs/pipe-bug/tsconfig.json rename to apps/rxjs/11-high-order-operator-bug/tsconfig.json diff --git a/apps/performance/scroll-cd/.eslintrc.json b/apps/rxjs/14-race-condition/.eslintrc.json similarity index 100% rename from apps/performance/scroll-cd/.eslintrc.json rename to apps/rxjs/14-race-condition/.eslintrc.json diff --git a/apps/rxjs/race-condition/README.md b/apps/rxjs/14-race-condition/README.md similarity index 100% rename from apps/rxjs/race-condition/README.md rename to apps/rxjs/14-race-condition/README.md diff --git a/apps/rxjs/race-condition/cypress.config.ts b/apps/rxjs/14-race-condition/cypress.config.ts similarity index 100% rename from apps/rxjs/race-condition/cypress.config.ts rename to apps/rxjs/14-race-condition/cypress.config.ts diff --git a/apps/rxjs/race-condition/cypress/fixtures/example.json b/apps/rxjs/14-race-condition/cypress/fixtures/example.json similarity index 100% rename from apps/rxjs/race-condition/cypress/fixtures/example.json rename to apps/rxjs/14-race-condition/cypress/fixtures/example.json diff --git a/apps/rxjs/race-condition/cypress/support/commands.ts b/apps/rxjs/14-race-condition/cypress/support/commands.ts similarity index 100% rename from apps/rxjs/race-condition/cypress/support/commands.ts rename to apps/rxjs/14-race-condition/cypress/support/commands.ts diff --git a/apps/rxjs/race-condition/cypress/support/component-index.html b/apps/rxjs/14-race-condition/cypress/support/component-index.html similarity index 100% rename from apps/rxjs/race-condition/cypress/support/component-index.html rename to apps/rxjs/14-race-condition/cypress/support/component-index.html diff --git a/apps/rxjs/race-condition/cypress/support/component.ts b/apps/rxjs/14-race-condition/cypress/support/component.ts similarity index 100% rename from apps/rxjs/race-condition/cypress/support/component.ts rename to apps/rxjs/14-race-condition/cypress/support/component.ts diff --git a/apps/rxjs/race-condition/cypress/tsconfig.json b/apps/rxjs/14-race-condition/cypress/tsconfig.json similarity index 100% rename from apps/rxjs/race-condition/cypress/tsconfig.json rename to apps/rxjs/14-race-condition/cypress/tsconfig.json diff --git a/apps/rxjs/14-race-condition/jest.config.ts b/apps/rxjs/14-race-condition/jest.config.ts new file mode 100644 index 000000000..493fb2452 --- /dev/null +++ b/apps/rxjs/14-race-condition/jest.config.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +export default { + displayName: 'rxjs-race-condition', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + globals: {}, + coverageDirectory: '../../../coverage/apps/rxjs/14-race-condition', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/rxjs/14-race-condition/project.json b/apps/rxjs/14-race-condition/project.json new file mode 100644 index 000000000..f84ccf155 --- /dev/null +++ b/apps/rxjs/14-race-condition/project.json @@ -0,0 +1,83 @@ +{ + "name": "rxjs-race-condition", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/rxjs/14-race-condition/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/rxjs/14-race-condition", + "index": "apps/rxjs/14-race-condition/src/index.html", + "main": "apps/rxjs/14-race-condition/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/rxjs/14-race-condition/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/rxjs/14-race-condition/src/favicon.ico", + "apps/rxjs/14-race-condition/src/assets" + ], + "styles": ["apps/rxjs/14-race-condition/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "rxjs-race-condition:build:production" + }, + "development": { + "buildTarget": "rxjs-race-condition:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "rxjs-race-condition:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/rxjs/race-condition/src/app/app.component.cy.ts b/apps/rxjs/14-race-condition/src/app/app.component.cy.ts similarity index 100% rename from apps/rxjs/race-condition/src/app/app.component.cy.ts rename to apps/rxjs/14-race-condition/src/app/app.component.cy.ts diff --git a/apps/rxjs/race-condition/src/app/app.component.ts b/apps/rxjs/14-race-condition/src/app/app.component.ts similarity index 100% rename from apps/rxjs/race-condition/src/app/app.component.ts rename to apps/rxjs/14-race-condition/src/app/app.component.ts diff --git a/apps/rxjs/race-condition/src/app/app.config.ts b/apps/rxjs/14-race-condition/src/app/app.config.ts similarity index 100% rename from apps/rxjs/race-condition/src/app/app.config.ts rename to apps/rxjs/14-race-condition/src/app/app.config.ts diff --git a/apps/rxjs/race-condition/src/app/topic-dialog.component.ts b/apps/rxjs/14-race-condition/src/app/topic-dialog.component.ts similarity index 97% rename from apps/rxjs/race-condition/src/app/topic-dialog.component.ts rename to apps/rxjs/14-race-condition/src/app/topic-dialog.component.ts index d63ed4ada..e01a69a01 100644 --- a/apps/rxjs/race-condition/src/app/topic-dialog.component.ts +++ b/apps/rxjs/14-race-condition/src/app/topic-dialog.component.ts @@ -18,7 +18,6 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
`, imports: [MatDialogModule, MatButtonModule, NgFor], - standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, }) export class TopicModalComponent { diff --git a/apps/rxjs/race-condition/src/app/topic.service.ts b/apps/rxjs/14-race-condition/src/app/topic.service.ts similarity index 100% rename from apps/rxjs/race-condition/src/app/topic.service.ts rename to apps/rxjs/14-race-condition/src/app/topic.service.ts diff --git a/apps/rxjs/pipe-bug/src/assets/.gitkeep b/apps/rxjs/14-race-condition/src/assets/.gitkeep similarity index 100% rename from apps/rxjs/pipe-bug/src/assets/.gitkeep rename to apps/rxjs/14-race-condition/src/assets/.gitkeep diff --git a/apps/testing/create-harness/src/favicon.ico b/apps/rxjs/14-race-condition/src/favicon.ico similarity index 100% rename from apps/testing/create-harness/src/favicon.ico rename to apps/rxjs/14-race-condition/src/favicon.ico diff --git a/apps/rxjs/14-race-condition/src/index.html b/apps/rxjs/14-race-condition/src/index.html new file mode 100644 index 000000000..629547b5b --- /dev/null +++ b/apps/rxjs/14-race-condition/src/index.html @@ -0,0 +1,13 @@ + + + + + rxjs-race-condition + + + + + + + + diff --git a/apps/rxjs/race-condition/src/main.ts b/apps/rxjs/14-race-condition/src/main.ts similarity index 100% rename from apps/rxjs/race-condition/src/main.ts rename to apps/rxjs/14-race-condition/src/main.ts diff --git a/apps/rxjs/14-race-condition/src/styles.scss b/apps/rxjs/14-race-condition/src/styles.scss new file mode 100644 index 000000000..215c83eb9 --- /dev/null +++ b/apps/rxjs/14-race-condition/src/styles.scss @@ -0,0 +1,25 @@ +/* You can add global styles to this file, and also import other style files */ + +@use '@angular/material' as mat; + +@include mat.elevation-classes(); +@include mat.app-background(); + +$theme-primary: mat.m2-define-palette(mat.$m2-indigo-palette); +$theme-accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400); + +$theme-warn: mat.m2-define-palette(mat.$m2-red-palette); + +$theme: mat.m2-define-light-theme( + ( + color: ( + primary: $theme-primary, + accent: $theme-accent, + warn: $theme-warn, + ), + typography: mat.m2-define-typography-config(), + ) +); + +@include mat.dialog-theme($theme); +@include mat.button-theme($theme); diff --git a/apps/performance/scroll-cd/src/test-setup.ts b/apps/rxjs/14-race-condition/src/test-setup.ts similarity index 100% rename from apps/performance/scroll-cd/src/test-setup.ts rename to apps/rxjs/14-race-condition/src/test-setup.ts diff --git a/apps/rxjs/race-condition/tsconfig.app.json b/apps/rxjs/14-race-condition/tsconfig.app.json similarity index 100% rename from apps/rxjs/race-condition/tsconfig.app.json rename to apps/rxjs/14-race-condition/tsconfig.app.json diff --git a/apps/rxjs/race-condition/tsconfig.editor.json b/apps/rxjs/14-race-condition/tsconfig.editor.json similarity index 100% rename from apps/rxjs/race-condition/tsconfig.editor.json rename to apps/rxjs/14-race-condition/tsconfig.editor.json diff --git a/apps/rxjs/14-race-condition/tsconfig.json b/apps/rxjs/14-race-condition/tsconfig.json new file mode 100644 index 000000000..8a0cb05fc --- /dev/null +++ b/apps/rxjs/14-race-condition/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + }, + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./cypress/tsconfig.base.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/rxjs/race-condition/tsconfig.spec.json b/apps/rxjs/14-race-condition/tsconfig.spec.json similarity index 100% rename from apps/rxjs/race-condition/tsconfig.spec.json rename to apps/rxjs/14-race-condition/tsconfig.spec.json diff --git a/apps/rxjs/catch-error/.eslintrc.json b/apps/rxjs/38-catch-error/.eslintrc.json similarity index 100% rename from apps/rxjs/catch-error/.eslintrc.json rename to apps/rxjs/38-catch-error/.eslintrc.json diff --git a/apps/rxjs/catch-error/README.md b/apps/rxjs/38-catch-error/README.md similarity index 100% rename from apps/rxjs/catch-error/README.md rename to apps/rxjs/38-catch-error/README.md diff --git a/apps/rxjs/38-catch-error/jest.config.ts b/apps/rxjs/38-catch-error/jest.config.ts new file mode 100644 index 000000000..52f04480f --- /dev/null +++ b/apps/rxjs/38-catch-error/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'rxjs-catch-error', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/rxjs/38-catch-error', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/rxjs/38-catch-error/project.json b/apps/rxjs/38-catch-error/project.json new file mode 100644 index 000000000..a655389f3 --- /dev/null +++ b/apps/rxjs/38-catch-error/project.json @@ -0,0 +1,82 @@ +{ + "name": "rxjs-catch-error", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/rxjs/38-catch-error/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/rxjs/38-catch-error", + "index": "apps/rxjs/38-catch-error/src/index.html", + "main": "apps/rxjs/38-catch-error/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/rxjs/38-catch-error/tsconfig.app.json", + "assets": [ + "apps/rxjs/38-catch-error/src/favicon.ico", + "apps/rxjs/38-catch-error/src/assets" + ], + "styles": ["apps/rxjs/38-catch-error/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "rxjs-catch-error:build:production" + }, + "development": { + "buildTarget": "rxjs-catch-error:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "rxjs-catch-error:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/rxjs/catch-error/src/app/app.component.css b/apps/rxjs/38-catch-error/src/app/app.component.css similarity index 100% rename from apps/rxjs/catch-error/src/app/app.component.css rename to apps/rxjs/38-catch-error/src/app/app.component.css diff --git a/apps/rxjs/catch-error/src/app/app.component.spec.ts b/apps/rxjs/38-catch-error/src/app/app.component.spec.ts similarity index 100% rename from apps/rxjs/catch-error/src/app/app.component.spec.ts rename to apps/rxjs/38-catch-error/src/app/app.component.spec.ts diff --git a/apps/rxjs/38-catch-error/src/app/app.component.ts b/apps/rxjs/38-catch-error/src/app/app.component.ts new file mode 100644 index 000000000..65e177567 --- /dev/null +++ b/apps/rxjs/38-catch-error/src/app/app.component.ts @@ -0,0 +1,60 @@ +import { CommonModule } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; +import { Component, DestroyRef, OnInit, inject } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { FormsModule } from '@angular/forms'; +import { Subject, concatMap, map } from 'rxjs'; + +@Component({ + imports: [CommonModule, FormsModule], + selector: 'app-root', + template: ` +
+ + possible values: posts, comments, albums, photos, todos, users + +
+
+ + +
+
+ {{ response | json }} +
+ `, + styleUrls: ['./app.component.css'], +}) +export class AppComponent implements OnInit { + submit$ = new Subject(); + input = ''; + response: unknown; + + private destroyRef = inject(DestroyRef); + private http = inject(HttpClient); + + ngOnInit() { + this.submit$ + .pipe( + map(() => this.input), + concatMap((value) => + this.http.get(`https://jsonplaceholder.typicode.com/${value}/1`), + ), + takeUntilDestroyed(this.destroyRef), + ) + .subscribe({ + next: (value) => { + console.log(value); + this.response = value; + }, + error: (error) => { + console.log(error); + this.response = error; + }, + complete: () => console.log('done'), + }); + } +} diff --git a/apps/rxjs/38-catch-error/src/app/app.config.ts b/apps/rxjs/38-catch-error/src/app/app.config.ts new file mode 100644 index 000000000..1c0c9422f --- /dev/null +++ b/apps/rxjs/38-catch-error/src/app/app.config.ts @@ -0,0 +1,6 @@ +import { provideHttpClient } from '@angular/common/http'; +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [provideHttpClient()], +}; diff --git a/apps/rxjs/race-condition/src/assets/.gitkeep b/apps/rxjs/38-catch-error/src/assets/.gitkeep similarity index 100% rename from apps/rxjs/race-condition/src/assets/.gitkeep rename to apps/rxjs/38-catch-error/src/assets/.gitkeep diff --git a/apps/testing/harness/src/favicon.ico b/apps/rxjs/38-catch-error/src/favicon.ico similarity index 100% rename from apps/testing/harness/src/favicon.ico rename to apps/rxjs/38-catch-error/src/favicon.ico diff --git a/apps/rxjs/catch-error/src/index.html b/apps/rxjs/38-catch-error/src/index.html similarity index 100% rename from apps/rxjs/catch-error/src/index.html rename to apps/rxjs/38-catch-error/src/index.html diff --git a/apps/rxjs/38-catch-error/src/main.ts b/apps/rxjs/38-catch-error/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/rxjs/38-catch-error/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/rxjs/38-catch-error/src/styles.scss b/apps/rxjs/38-catch-error/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/rxjs/38-catch-error/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/testing/harness/src/test-setup.ts b/apps/rxjs/38-catch-error/src/test-setup.ts similarity index 100% rename from apps/testing/harness/src/test-setup.ts rename to apps/rxjs/38-catch-error/src/test-setup.ts diff --git a/apps/testing/table/tailwind.config.js b/apps/rxjs/38-catch-error/tailwind.config.js similarity index 100% rename from apps/testing/table/tailwind.config.js rename to apps/rxjs/38-catch-error/tailwind.config.js diff --git a/apps/rxjs/38-catch-error/tsconfig.app.json b/apps/rxjs/38-catch-error/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/rxjs/38-catch-error/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/testing/checkbox/tsconfig.editor.json b/apps/rxjs/38-catch-error/tsconfig.editor.json similarity index 100% rename from apps/testing/checkbox/tsconfig.editor.json rename to apps/rxjs/38-catch-error/tsconfig.editor.json diff --git a/apps/performance/scroll-cd/tsconfig.json b/apps/rxjs/38-catch-error/tsconfig.json similarity index 100% rename from apps/performance/scroll-cd/tsconfig.json rename to apps/rxjs/38-catch-error/tsconfig.json diff --git a/apps/angular/interop-rxjs-signal/tsconfig.spec.json b/apps/rxjs/38-catch-error/tsconfig.spec.json similarity index 100% rename from apps/angular/interop-rxjs-signal/tsconfig.spec.json rename to apps/rxjs/38-catch-error/tsconfig.spec.json diff --git a/apps/rxjs/49-hold-to-save-button/.eslintrc.json b/apps/rxjs/49-hold-to-save-button/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/rxjs/49-hold-to-save-button/README.md b/apps/rxjs/49-hold-to-save-button/README.md new file mode 100644 index 000000000..e0d4c012b --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/README.md @@ -0,0 +1,13 @@ +# Hold to send button + +> author: alcaidio + +### Run Application + +```bash +npx nx serve rxjs-hold-to-save-button +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/rxjs/49-hold-to-save-btn/). diff --git a/apps/rxjs/49-hold-to-save-button/jest.config.ts b/apps/rxjs/49-hold-to-save-button/jest.config.ts new file mode 100644 index 000000000..1071a5815 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'rxjs-hold-to-save-button', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/rxjs/49-hold-to-save-button', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/rxjs/49-hold-to-save-button/project.json b/apps/rxjs/49-hold-to-save-button/project.json new file mode 100644 index 000000000..7b34db2c9 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/project.json @@ -0,0 +1,80 @@ +{ + "name": "rxjs-hold-to-save-button", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/rxjs/49-hold-to-save-button/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/rxjs/49-hold-to-save-button", + "index": "apps/rxjs/49-hold-to-save-button/src/index.html", + "browser": "apps/rxjs/49-hold-to-save-button/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/rxjs/49-hold-to-save-button/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/rxjs/49-hold-to-save-button/src/favicon.ico", + "apps/rxjs/49-hold-to-save-button/src/assets" + ], + "styles": ["apps/rxjs/49-hold-to-save-button/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "rxjs-hold-to-save-button:build:production" + }, + "development": { + "buildTarget": "rxjs-hold-to-save-button:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "rxjs-hold-to-save-button:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/rxjs/49-hold-to-save-button/src/app/app.component.ts b/apps/rxjs/49-hold-to-save-button/src/app/app.component.ts new file mode 100644 index 000000000..8f0dbbc70 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/src/app/app.component.ts @@ -0,0 +1,25 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + imports: [], + selector: 'app-root', + template: ` +
+
+ + + +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + onSend() { + console.log('Save it!'); + } +} diff --git a/apps/rxjs/49-hold-to-save-button/src/app/app.config.ts b/apps/rxjs/49-hold-to-save-button/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/testing/checkbox/src/assets/.gitkeep b/apps/rxjs/49-hold-to-save-button/src/assets/.gitkeep similarity index 100% rename from apps/testing/checkbox/src/assets/.gitkeep rename to apps/rxjs/49-hold-to-save-button/src/assets/.gitkeep diff --git a/apps/testing/input-output/src/favicon.ico b/apps/rxjs/49-hold-to-save-button/src/favicon.ico similarity index 100% rename from apps/testing/input-output/src/favicon.ico rename to apps/rxjs/49-hold-to-save-button/src/favicon.ico diff --git a/apps/rxjs/49-hold-to-save-button/src/index.html b/apps/rxjs/49-hold-to-save-button/src/index.html new file mode 100644 index 000000000..3f8e222b1 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/src/index.html @@ -0,0 +1,13 @@ + + + + + rxjs-hold-to-save-button + + + + + + + + diff --git a/apps/rxjs/49-hold-to-save-button/src/main.ts b/apps/rxjs/49-hold-to-save-button/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/rxjs/49-hold-to-save-button/src/styles.scss b/apps/rxjs/49-hold-to-save-button/src/styles.scss new file mode 100644 index 000000000..c98dac907 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/src/styles.scss @@ -0,0 +1,14 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +progress { + @apply h-4 w-full rounded-full bg-gray-200; +} +progress::-webkit-progress-bar { + @apply rounded-full bg-gray-200; +} + +progress::-webkit-progress-value { + @apply rounded-full bg-indigo-600; +} diff --git a/apps/testing/input-output/src/test-setup.ts b/apps/rxjs/49-hold-to-save-button/src/test-setup.ts similarity index 100% rename from apps/testing/input-output/src/test-setup.ts rename to apps/rxjs/49-hold-to-save-button/src/test-setup.ts diff --git a/apps/testing/todos-list/tailwind.config.js b/apps/rxjs/49-hold-to-save-button/tailwind.config.js similarity index 100% rename from apps/testing/todos-list/tailwind.config.js rename to apps/rxjs/49-hold-to-save-button/tailwind.config.js diff --git a/apps/rxjs/49-hold-to-save-button/tsconfig.app.json b/apps/rxjs/49-hold-to-save-button/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/rxjs/49-hold-to-save-button/tsconfig.editor.json b/apps/rxjs/49-hold-to-save-button/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/rxjs/49-hold-to-save-button/tsconfig.json b/apps/rxjs/49-hold-to-save-button/tsconfig.json new file mode 100644 index 000000000..4383e7eb8 --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/rxjs/49-hold-to-save-button/tsconfig.spec.json b/apps/rxjs/49-hold-to-save-button/tsconfig.spec.json new file mode 100644 index 000000000..1a4817a7d --- /dev/null +++ b/apps/rxjs/49-hold-to-save-button/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node", "@testing-library/jest-dom"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/rxjs/catch-error/jest.config.ts b/apps/rxjs/catch-error/jest.config.ts deleted file mode 100644 index be57e8c7b..000000000 --- a/apps/rxjs/catch-error/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'rxjs-catch-error', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/rxjs/catch-error', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/rxjs/catch-error/project.json b/apps/rxjs/catch-error/project.json deleted file mode 100644 index c03e663c3..000000000 --- a/apps/rxjs/catch-error/project.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "rxjs-catch-error", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/rxjs/catch-error/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/rxjs/catch-error", - "index": "apps/rxjs/catch-error/src/index.html", - "main": "apps/rxjs/catch-error/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/rxjs/catch-error/tsconfig.app.json", - "assets": [ - "apps/rxjs/catch-error/src/favicon.ico", - "apps/rxjs/catch-error/src/assets" - ], - "styles": ["apps/rxjs/catch-error/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "rxjs-catch-error:build:production" - }, - "development": { - "buildTarget": "rxjs-catch-error:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "rxjs-catch-error:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/rxjs/catch-error/**/*.ts", - "apps/rxjs/catch-error/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/rxjs/catch-error/jest.config.ts" - } - } - } -} diff --git a/apps/rxjs/catch-error/src/app/app.component.ts b/apps/rxjs/catch-error/src/app/app.component.ts deleted file mode 100644 index b6ac06679..000000000 --- a/apps/rxjs/catch-error/src/app/app.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { HttpClient } from '@angular/common/http'; -import { Component, DestroyRef, OnInit, inject } from '@angular/core'; -import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { FormsModule } from '@angular/forms'; -import { Subject, concatMap, map } from 'rxjs'; - -@Component({ - standalone: true, - imports: [CommonModule, FormsModule], - selector: 'app-root', - template: ` -
- - possible values: posts, comments, albums, photos, todos, users - -
-
- - -
-
- {{ response | json }} -
- `, - styleUrls: ['./app.component.css'], -}) -export class AppComponent implements OnInit { - submit$ = new Subject(); - input = ''; - response: unknown; - - private destroyRef = inject(DestroyRef); - private http = inject(HttpClient); - - ngOnInit() { - this.submit$ - .pipe( - map(() => this.input), - concatMap((value) => - this.http.get(`https://jsonplaceholder.typicode.com/${value}/1`), - ), - takeUntilDestroyed(this.destroyRef), - ) - .subscribe({ - next: (value) => { - console.log(value); - this.response = value; - }, - error: (error) => { - console.log(error); - this.response = error; - }, - complete: () => console.log('done'), - }); - } -} diff --git a/apps/rxjs/catch-error/src/app/app.config.ts b/apps/rxjs/catch-error/src/app/app.config.ts deleted file mode 100644 index c5abc2a63..000000000 --- a/apps/rxjs/catch-error/src/app/app.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { HttpClientModule } from '@angular/common/http'; -import { ApplicationConfig, importProvidersFrom } from '@angular/core'; - -export const appConfig: ApplicationConfig = { - providers: [importProvidersFrom(HttpClientModule)], -}; diff --git a/apps/rxjs/pipe-bug/README.md b/apps/rxjs/pipe-bug/README.md deleted file mode 100644 index cad896a79..000000000 --- a/apps/rxjs/pipe-bug/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# High Order Operator Bug - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve rxjs-pipe-bug -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/rxjs/11-bug-chaining-operator/). diff --git a/apps/rxjs/pipe-bug/project.json b/apps/rxjs/pipe-bug/project.json deleted file mode 100644 index 54e1e8306..000000000 --- a/apps/rxjs/pipe-bug/project.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "name": "rxjs-pipe-bug", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/rxjs/pipe-bug/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/rxjs/pipe-bug", - "index": "apps/rxjs/pipe-bug/src/index.html", - "main": "apps/rxjs/pipe-bug/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/rxjs/pipe-bug/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/rxjs/pipe-bug/src/favicon.ico", - "apps/rxjs/pipe-bug/src/assets" - ], - "styles": ["apps/rxjs/pipe-bug/src/styles.scss"], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "rxjs-pipe-bug:build:production" - }, - "development": { - "buildTarget": "rxjs-pipe-bug:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "rxjs-pipe-bug:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/rxjs/pipe-bug/**/*.ts", - "apps/rxjs/pipe-bug/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/rxjs/pipe-bug/src/app/app.component.ts b/apps/rxjs/pipe-bug/src/app/app.component.ts deleted file mode 100644 index f22b16749..000000000 --- a/apps/rxjs/pipe-bug/src/app/app.component.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, Input, inject } from '@angular/core'; -import { BehaviorSubject, take } from 'rxjs'; -import { AppService } from './app.service'; -import { TopicType } from './localDB.service'; - -@Component({ - standalone: true, - selector: 'button-delete-topic', - imports: [AsyncPipe], - template: ` - -
{{ message$$ | async }}
- `, -}) -export class ButtonDeleteComponent { - @Input() topic!: TopicType; - - message$$ = new BehaviorSubject(''); - - private service = inject(AppService); - - deleteTopic() { - this.service - .deleteOldTopics(this.topic) - .pipe(take(1)) - .subscribe((result) => - this.message$$.next( - result - ? `All ${this.topic} have been deleted` - : `Error: deletion of some ${this.topic} failed`, - ), - ); - } -} - -@Component({ - standalone: true, - imports: [AsyncPipe, NgFor, ButtonDeleteComponent], - selector: 'app-root', - template: ` -
- {{ item.id }} - {{ item.topic }} -
- - Delete Food - Delete Sport - Delete Book - `, -}) -export class AppComponent { - private service = inject(AppService); - - all$ = this.service.getAll$; -} diff --git a/apps/rxjs/pipe-bug/src/app/app.service.ts b/apps/rxjs/pipe-bug/src/app/app.service.ts deleted file mode 100644 index 7c8173514..000000000 --- a/apps/rxjs/pipe-bug/src/app/app.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { merge, mergeMap, Observable, of, take } from 'rxjs'; -import { LocalDBService, TopicType } from './localDB.service'; - -@Injectable({ providedIn: 'root' }) -export class AppService { - private dbService = inject(LocalDBService); - - getAll$ = this.dbService.infos$; - - deleteOldTopics(type: TopicType): Observable { - return this.dbService.searchByType(type).pipe( - take(1), - mergeMap((topicToDelete) => - topicToDelete.length > 0 - ? topicToDelete - .map((t) => this.dbService.deleteOneTopic(t.id)) - .reduce((acc, curr) => merge(acc, curr), of(true)) - : of(true), - ), - ); - } -} diff --git a/apps/rxjs/pipe-bug/src/app/localDB.service.ts b/apps/rxjs/pipe-bug/src/app/localDB.service.ts deleted file mode 100644 index d13d0ed9c..000000000 --- a/apps/rxjs/pipe-bug/src/app/localDB.service.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable @typescript-eslint/member-ordering */ -import { randomError } from '@angular-challenges/shared/utils'; -import { Injectable } from '@angular/core'; -import { ComponentStore } from '@ngrx/component-store'; -import { of } from 'rxjs'; - -export type TopicType = 'food' | 'book' | 'sport'; - -interface Info { - id: number; - topic: TopicType; -} - -interface DBState { - infos: Info[]; -} - -const initialState: DBState = { - infos: [ - { id: 1, topic: 'book' }, - { id: 2, topic: 'book' }, - { id: 3, topic: 'book' }, - { id: 4, topic: 'book' }, - { id: 5, topic: 'food' }, - { id: 6, topic: 'food' }, - { id: 7, topic: 'book' }, - { id: 8, topic: 'book' }, - { id: 9, topic: 'book' }, - { id: 10, topic: 'sport' }, - ], -}; - -@Injectable({ providedIn: 'root' }) -export class LocalDBService extends ComponentStore { - constructor() { - super(initialState); - } - - infos$ = this.select((state) => state.infos); - - searchByType = (type: TopicType) => - this.select((state) => state.infos.filter((i) => i.topic === type)); - - deleteOne = this.updater( - (state, id: number): DBState => ({ - infos: state.infos.filter((i) => i.id !== id), - }), - ); - - deleteOneTopic = (id: number) => - randomError({ - success: () => { - this.deleteOne(id); - return of(true); - }, - error: () => of(false), - }); -} diff --git a/apps/rxjs/pipe-bug/src/index.html b/apps/rxjs/pipe-bug/src/index.html deleted file mode 100644 index 401ddc0d8..000000000 --- a/apps/rxjs/pipe-bug/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - RxjsPipeBug - - - - - - - - diff --git a/apps/rxjs/race-condition/jest.config.ts b/apps/rxjs/race-condition/jest.config.ts deleted file mode 100644 index b77456835..000000000 --- a/apps/rxjs/race-condition/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'rxjs-race-condition', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/apps/rxjs/race-condition', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/rxjs/race-condition/project.json b/apps/rxjs/race-condition/project.json deleted file mode 100644 index eeb2833e2..000000000 --- a/apps/rxjs/race-condition/project.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "rxjs-race-condition", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/rxjs/race-condition/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/rxjs/race-condition", - "index": "apps/rxjs/race-condition/src/index.html", - "main": "apps/rxjs/race-condition/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/rxjs/race-condition/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/rxjs/race-condition/src/favicon.ico", - "apps/rxjs/race-condition/src/assets" - ], - "styles": ["apps/rxjs/race-condition/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "rxjs-race-condition:build:production" - }, - "development": { - "buildTarget": "rxjs-race-condition:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "rxjs-race-condition:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/rxjs/race-condition/**/*.ts", - "apps/rxjs/race-condition/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/rxjs/race-condition/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/rxjs/race-condition/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "rxjs-race-condition:build" - } - } - }, - "tags": [] -} diff --git a/apps/rxjs/race-condition/src/index.html b/apps/rxjs/race-condition/src/index.html deleted file mode 100644 index af7595012..000000000 --- a/apps/rxjs/race-condition/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - RxjsRaceCondition - - - - - - - - diff --git a/apps/rxjs/race-condition/src/styles.scss b/apps/rxjs/race-condition/src/styles.scss deleted file mode 100644 index 5f2e97eb4..000000000 --- a/apps/rxjs/race-condition/src/styles.scss +++ /dev/null @@ -1,24 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ - -@use '@angular/material' as mat; - -@include mat.core(); - -$theme-primary: mat.define-palette(mat.$indigo-palette); -$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); - -$theme-warn: mat.define-palette(mat.$red-palette); - -$theme: mat.define-light-theme( - ( - color: ( - primary: $theme-primary, - accent: $theme-accent, - warn: $theme-warn, - ), - typography: mat.define-typography-config(), - ) -); - -@include mat.dialog-theme($theme); -@include mat.button-theme($theme); diff --git a/apps/rxjs/race-condition/src/test-setup.ts b/apps/rxjs/race-condition/src/test-setup.ts deleted file mode 100644 index 1100b3e8a..000000000 --- a/apps/rxjs/race-condition/src/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import 'jest-preset-angular/setup-jest'; diff --git a/apps/rxjs/race-condition/.eslintrc.json b/apps/signal/30-interop-rxjs-signal/.eslintrc.json similarity index 100% rename from apps/rxjs/race-condition/.eslintrc.json rename to apps/signal/30-interop-rxjs-signal/.eslintrc.json diff --git a/apps/signal/30-interop-rxjs-signal/README.md b/apps/signal/30-interop-rxjs-signal/README.md new file mode 100644 index 000000000..f726d1b0f --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/README.md @@ -0,0 +1,13 @@ +# Interoperability Rxjs/Signal + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-interop-rxjs-signal +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/30-interop-rxjs-signal/). diff --git a/apps/signal/30-interop-rxjs-signal/jest.config.ts b/apps/signal/30-interop-rxjs-signal/jest.config.ts new file mode 100644 index 000000000..9f2001768 --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'signal-interop-rxjs-signal', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/signal/30-interop-rxjs-signal', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/signal/30-interop-rxjs-signal/project.json b/apps/signal/30-interop-rxjs-signal/project.json new file mode 100644 index 000000000..0407655ee --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/project.json @@ -0,0 +1,85 @@ +{ + "name": "signal-interop-rxjs-signal", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/30-interop-rxjs-signal/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/30-interop-rxjs-signal", + "index": "apps/signal/30-interop-rxjs-signal/src/index.html", + "main": "apps/signal/30-interop-rxjs-signal/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/30-interop-rxjs-signal/tsconfig.app.json", + "assets": [ + "apps/signal/30-interop-rxjs-signal/src/favicon.ico", + "apps/signal/30-interop-rxjs-signal/src/assets" + ], + "styles": [ + "apps/signal/30-interop-rxjs-signal/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-interop-rxjs-signal:build:production" + }, + "development": { + "buildTarget": "signal-interop-rxjs-signal:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-interop-rxjs-signal:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/signal/30-interop-rxjs-signal/src/app/app.component.ts b/apps/signal/30-interop-rxjs-signal/src/app/app.component.ts new file mode 100644 index 000000000..54fa2b85d --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + template: ` + + `, + styles: [''], +}) +export class AppComponent {} diff --git a/apps/angular/interop-rxjs-signal/src/app/app.config.ts b/apps/signal/30-interop-rxjs-signal/src/app/app.config.ts similarity index 100% rename from apps/angular/interop-rxjs-signal/src/app/app.config.ts rename to apps/signal/30-interop-rxjs-signal/src/app/app.config.ts diff --git a/apps/signal/30-interop-rxjs-signal/src/app/detail/detail.component.ts b/apps/signal/30-interop-rxjs-signal/src/app/detail/detail.component.ts new file mode 100644 index 000000000..070bf7d7c --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/src/app/detail/detail.component.ts @@ -0,0 +1,44 @@ +import { DatePipe } from '@angular/common'; +import { Component, Input as RouterInput } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { Photo } from '../photo.model'; + +@Component({ + selector: 'app-photos', + imports: [DatePipe, RouterLink], + template: ` + {{ photo.title }} +

+ Title: + {{ photo.title }} +

+

+ Owner: + {{ photo.ownername }} +

+

+ Date: + {{ photo.datetaken | date }} +

+

+ Tags: + {{ photo.tags }} +

+ + + `, + host: { + class: 'p-5 block', + }, +}) +export default class DetailComponent { + @RouterInput({ + required: true, + transform: (value: string) => JSON.parse(decodeURIComponent(value)), + }) + photo!: Photo; +} diff --git a/apps/angular/interop-rxjs-signal/src/app/list/photos.component.ts b/apps/signal/30-interop-rxjs-signal/src/app/list/photos.component.ts similarity index 99% rename from apps/angular/interop-rxjs-signal/src/app/list/photos.component.ts rename to apps/signal/30-interop-rxjs-signal/src/app/list/photos.component.ts index 29dc0c3f5..f81361957 100644 --- a/apps/angular/interop-rxjs-signal/src/app/list/photos.component.ts +++ b/apps/signal/30-interop-rxjs-signal/src/app/list/photos.component.ts @@ -13,7 +13,6 @@ import { PhotoStore } from './photos.store'; @Component({ selector: 'app-photos', - standalone: true, imports: [ ReactiveFormsModule, MatFormFieldModule, diff --git a/apps/angular/interop-rxjs-signal/src/app/list/photos.store.ts b/apps/signal/30-interop-rxjs-signal/src/app/list/photos.store.ts similarity index 96% rename from apps/angular/interop-rxjs-signal/src/app/list/photos.store.ts rename to apps/signal/30-interop-rxjs-signal/src/app/list/photos.store.ts index 01de2d4ec..f1315e87e 100644 --- a/apps/angular/interop-rxjs-signal/src/app/list/photos.store.ts +++ b/apps/signal/30-interop-rxjs-signal/src/app/list/photos.store.ts @@ -1,10 +1,10 @@ -import { Injectable, inject } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { ComponentStore, OnStateInit, OnStoreInit, - tapResponse, } from '@ngrx/component-store'; +import { tapResponse } from '@ngrx/operators'; import { pipe } from 'rxjs'; import { filter, mergeMap, tap } from 'rxjs/operators'; import { Photo } from '../photo.model'; diff --git a/apps/angular/interop-rxjs-signal/src/app/photo.model.ts b/apps/signal/30-interop-rxjs-signal/src/app/photo.model.ts similarity index 100% rename from apps/angular/interop-rxjs-signal/src/app/photo.model.ts rename to apps/signal/30-interop-rxjs-signal/src/app/photo.model.ts diff --git a/apps/angular/interop-rxjs-signal/src/app/photos.service.ts b/apps/signal/30-interop-rxjs-signal/src/app/photos.service.ts similarity index 100% rename from apps/angular/interop-rxjs-signal/src/app/photos.service.ts rename to apps/signal/30-interop-rxjs-signal/src/app/photos.service.ts diff --git a/apps/testing/create-harness/src/assets/.gitkeep b/apps/signal/30-interop-rxjs-signal/src/assets/.gitkeep similarity index 100% rename from apps/testing/create-harness/src/assets/.gitkeep rename to apps/signal/30-interop-rxjs-signal/src/assets/.gitkeep diff --git a/apps/testing/modal/src/favicon.ico b/apps/signal/30-interop-rxjs-signal/src/favicon.ico similarity index 100% rename from apps/testing/modal/src/favicon.ico rename to apps/signal/30-interop-rxjs-signal/src/favicon.ico diff --git a/apps/signal/30-interop-rxjs-signal/src/index.html b/apps/signal/30-interop-rxjs-signal/src/index.html new file mode 100644 index 000000000..c8a8e0de5 --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/src/index.html @@ -0,0 +1,13 @@ + + + + + signal-interop-rxjs-signal + + + + + + + + diff --git a/apps/signal/30-interop-rxjs-signal/src/main.ts b/apps/signal/30-interop-rxjs-signal/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/signal/30-interop-rxjs-signal/src/styles.scss b/apps/signal/30-interop-rxjs-signal/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/testing/modal/src/test-setup.ts b/apps/signal/30-interop-rxjs-signal/src/test-setup.ts similarity index 100% rename from apps/testing/modal/src/test-setup.ts rename to apps/signal/30-interop-rxjs-signal/src/test-setup.ts diff --git a/apps/signal/30-interop-rxjs-signal/tailwind.config.js b/apps/signal/30-interop-rxjs-signal/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/30-interop-rxjs-signal/tsconfig.app.json b/apps/signal/30-interop-rxjs-signal/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/30-interop-rxjs-signal/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/testing/input-output/tsconfig.editor.json b/apps/signal/30-interop-rxjs-signal/tsconfig.editor.json similarity index 100% rename from apps/testing/input-output/tsconfig.editor.json rename to apps/signal/30-interop-rxjs-signal/tsconfig.editor.json diff --git a/apps/rxjs/catch-error/tsconfig.json b/apps/signal/30-interop-rxjs-signal/tsconfig.json similarity index 100% rename from apps/rxjs/catch-error/tsconfig.json rename to apps/signal/30-interop-rxjs-signal/tsconfig.json diff --git a/apps/rxjs/catch-error/tsconfig.spec.json b/apps/signal/30-interop-rxjs-signal/tsconfig.spec.json similarity index 100% rename from apps/rxjs/catch-error/tsconfig.spec.json rename to apps/signal/30-interop-rxjs-signal/tsconfig.spec.json diff --git a/apps/signal/43-signal-input/.eslintrc.json b/apps/signal/43-signal-input/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/signal/43-signal-input/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/signal/43-signal-input/README.md b/apps/signal/43-signal-input/README.md new file mode 100644 index 000000000..d82216bfd --- /dev/null +++ b/apps/signal/43-signal-input/README.md @@ -0,0 +1,13 @@ +# Signal Input + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-signal-input +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/43-signal-input). diff --git a/apps/signal/43-signal-input/project.json b/apps/signal/43-signal-input/project.json new file mode 100644 index 000000000..674aed1a3 --- /dev/null +++ b/apps/signal/43-signal-input/project.json @@ -0,0 +1,69 @@ +{ + "name": "signal-signal-input", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/43-signal-input/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/43-signal-input", + "index": "apps/signal/43-signal-input/src/index.html", + "browser": "apps/signal/43-signal-input/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/43-signal-input/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/signal/43-signal-input/src/favicon.ico", + "apps/signal/43-signal-input/src/assets" + ], + "styles": ["apps/signal/43-signal-input/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-signal-input:build:production" + }, + "development": { + "buildTarget": "signal-signal-input:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-signal-input:build" + } + } + } +} diff --git a/apps/signal/43-signal-input/src/app/app.component.ts b/apps/signal/43-signal-input/src/app/app.component.ts new file mode 100644 index 000000000..5c2deb684 --- /dev/null +++ b/apps/signal/43-signal-input/src/app/app.component.ts @@ -0,0 +1,43 @@ +import { Component } from '@angular/core'; +import { UserComponent } from './user.component'; + +@Component({ + imports: [UserComponent], + selector: 'app-root', + template: ` +
+
+ Name: + + @if (showUser && !name.value) { +
name required
+ } +
+
+ LastName: + +
+
+ Age: + +
+ +
+ @if (showUser && !!name.value) { + + } + `, + host: { + class: 'p-10 block flex flex-col gap-10', + }, +}) +export class AppComponent { + showUser = false; +} diff --git a/apps/signal/43-signal-input/src/app/app.config.ts b/apps/signal/43-signal-input/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/signal/43-signal-input/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/angular/signal-input/src/app/user.component.ts b/apps/signal/43-signal-input/src/app/user.component.ts similarity index 98% rename from apps/angular/signal-input/src/app/user.component.ts rename to apps/signal/43-signal-input/src/app/user.component.ts index 082638bf6..908f952c3 100644 --- a/apps/angular/signal-input/src/app/user.component.ts +++ b/apps/signal/43-signal-input/src/app/user.component.ts @@ -16,7 +16,6 @@ const ageToCategory = (age: number): Category => { @Component({ selector: 'app-user', - standalone: true, imports: [TitleCasePipe], template: ` {{ fullName | titlecase }} plays tennis in the {{ category }} category!! diff --git a/apps/testing/harness/src/assets/.gitkeep b/apps/signal/43-signal-input/src/assets/.gitkeep similarity index 100% rename from apps/testing/harness/src/assets/.gitkeep rename to apps/signal/43-signal-input/src/assets/.gitkeep diff --git a/apps/testing/nested/src/favicon.ico b/apps/signal/43-signal-input/src/favicon.ico similarity index 100% rename from apps/testing/nested/src/favicon.ico rename to apps/signal/43-signal-input/src/favicon.ico diff --git a/apps/signal/43-signal-input/src/index.html b/apps/signal/43-signal-input/src/index.html new file mode 100644 index 000000000..642a346a4 --- /dev/null +++ b/apps/signal/43-signal-input/src/index.html @@ -0,0 +1,13 @@ + + + + + signal-signal-input + + + + + + + + diff --git a/apps/signal/43-signal-input/src/main.ts b/apps/signal/43-signal-input/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/signal/43-signal-input/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/signal/43-signal-input/src/styles.scss b/apps/signal/43-signal-input/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/signal/43-signal-input/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/signal/43-signal-input/tailwind.config.js b/apps/signal/43-signal-input/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/43-signal-input/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/43-signal-input/tsconfig.app.json b/apps/signal/43-signal-input/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/43-signal-input/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/performance/ngfor-biglist/tsconfig.editor.json b/apps/signal/43-signal-input/tsconfig.editor.json similarity index 100% rename from apps/performance/ngfor-biglist/tsconfig.editor.json rename to apps/signal/43-signal-input/tsconfig.editor.json diff --git a/apps/signal/43-signal-input/tsconfig.json b/apps/signal/43-signal-input/tsconfig.json new file mode 100644 index 000000000..b94f8837d --- /dev/null +++ b/apps/signal/43-signal-input/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.editor.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/signal/50-bug-in-effect/.eslintrc.json b/apps/signal/50-bug-in-effect/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/signal/50-bug-in-effect/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/signal/50-bug-in-effect/README.md b/apps/signal/50-bug-in-effect/README.md new file mode 100644 index 000000000..9e55d151a --- /dev/null +++ b/apps/signal/50-bug-in-effect/README.md @@ -0,0 +1,13 @@ +# Bug in Effect ? + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-bug-in-effect +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/50-bug-effect-signal/). diff --git a/apps/signal/50-bug-in-effect/project.json b/apps/signal/50-bug-in-effect/project.json new file mode 100644 index 000000000..12a9bb47a --- /dev/null +++ b/apps/signal/50-bug-in-effect/project.json @@ -0,0 +1,69 @@ +{ + "name": "signal-bug-in-effect", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/50-bug-in-effect/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/50-bug-in-effect", + "index": "apps/signal/50-bug-in-effect/src/index.html", + "browser": "apps/signal/50-bug-in-effect/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/50-bug-in-effect/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/signal/50-bug-in-effect/src/favicon.ico", + "apps/signal/50-bug-in-effect/src/assets" + ], + "styles": ["apps/signal/50-bug-in-effect/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-bug-in-effect:build:production" + }, + "development": { + "buildTarget": "signal-bug-in-effect:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-bug-in-effect:build" + } + } + } +} diff --git a/apps/signal/50-bug-in-effect/src/app/app.component.ts b/apps/signal/50-bug-in-effect/src/app/app.component.ts new file mode 100644 index 000000000..ec6ba09b0 --- /dev/null +++ b/apps/signal/50-bug-in-effect/src/app/app.component.ts @@ -0,0 +1,52 @@ +import { + ChangeDetectionStrategy, + Component, + effect, + model, +} from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +@Component({ + imports: [FormsModule], + selector: 'app-root', + template: ` +
+

MacBook

+

1999,99 €

+
+ +
+

Extras:

+ +
+ + +500 GB drive-space +
+
+ + +4 GB RAM +
+
+ + Better GPU +
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + drive = model(false); + ram = model(false); + gpu = model(false); + + constructor() { + /* + Explain for your junior team mate why this bug occurs ... + */ + effect(() => { + if (this.drive() || this.ram() || this.gpu()) { + alert('Price increased!'); + } + }); + } +} diff --git a/apps/signal/50-bug-in-effect/src/app/app.config.ts b/apps/signal/50-bug-in-effect/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/signal/50-bug-in-effect/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/testing/input-output/src/assets/.gitkeep b/apps/signal/50-bug-in-effect/src/assets/.gitkeep similarity index 100% rename from apps/testing/input-output/src/assets/.gitkeep rename to apps/signal/50-bug-in-effect/src/assets/.gitkeep diff --git a/apps/testing/router-outlet/src/favicon.ico b/apps/signal/50-bug-in-effect/src/favicon.ico similarity index 100% rename from apps/testing/router-outlet/src/favicon.ico rename to apps/signal/50-bug-in-effect/src/favicon.ico diff --git a/apps/signal/50-bug-in-effect/src/index.html b/apps/signal/50-bug-in-effect/src/index.html new file mode 100644 index 000000000..e8f5b7364 --- /dev/null +++ b/apps/signal/50-bug-in-effect/src/index.html @@ -0,0 +1,13 @@ + + + + + signal-bug-in-effect + + + + + + + + diff --git a/apps/signal/50-bug-in-effect/src/main.ts b/apps/signal/50-bug-in-effect/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/signal/50-bug-in-effect/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/signal/50-bug-in-effect/src/styles.scss b/apps/signal/50-bug-in-effect/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/signal/50-bug-in-effect/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/signal/50-bug-in-effect/tailwind.config.js b/apps/signal/50-bug-in-effect/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/50-bug-in-effect/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/50-bug-in-effect/tsconfig.app.json b/apps/signal/50-bug-in-effect/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/50-bug-in-effect/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/50-bug-in-effect/tsconfig.editor.json b/apps/signal/50-bug-in-effect/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/signal/50-bug-in-effect/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/50-bug-in-effect/tsconfig.json b/apps/signal/50-bug-in-effect/tsconfig.json new file mode 100644 index 000000000..3df17b921 --- /dev/null +++ b/apps/signal/50-bug-in-effect/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/signal/51-function-call-effect/.eslintrc.json b/apps/signal/51-function-call-effect/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/signal/51-function-call-effect/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/signal/51-function-call-effect/README.md b/apps/signal/51-function-call-effect/README.md new file mode 100644 index 000000000..6d4543361 --- /dev/null +++ b/apps/signal/51-function-call-effect/README.md @@ -0,0 +1,13 @@ +# Function call in effect + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-function-call-effect +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/angular/51-function-call-effect/). diff --git a/apps/signal/51-function-call-effect/project.json b/apps/signal/51-function-call-effect/project.json new file mode 100644 index 000000000..3b3a4f8ae --- /dev/null +++ b/apps/signal/51-function-call-effect/project.json @@ -0,0 +1,69 @@ +{ + "name": "signal-function-call-effect", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/51-function-call-effect/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/51-function-call-effect", + "index": "apps/signal/51-function-call-effect/src/index.html", + "browser": "apps/signal/51-function-call-effect/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/51-function-call-effect/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/signal/51-function-call-effect/src/favicon.ico", + "apps/signal/51-function-call-effect/src/assets" + ], + "styles": ["apps/signal/51-function-call-effect/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-function-call-effect:build:production" + }, + "development": { + "buildTarget": "signal-function-call-effect:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-function-call-effect:build" + } + } + } +} diff --git a/apps/signal/51-function-call-effect/src/app/action.component.ts b/apps/signal/51-function-call-effect/src/app/action.component.ts new file mode 100644 index 000000000..22e0e7a4f --- /dev/null +++ b/apps/signal/51-function-call-effect/src/app/action.component.ts @@ -0,0 +1,44 @@ +import { + ChangeDetectionStrategy, + Component, + effect, + inject, + signal, +} from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { UserService } from './user.service'; + +@Component({ + imports: [FormsModule], + selector: 'app-actions', + template: ` +
+ + +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ActionsComponent { + private userService = inject(UserService); + protected action = signal(undefined); + + protected actions = ['Create', 'Read', 'Update', 'Delete']; + + constructor() { + effect(() => { + this.userService.log(this.action() ?? 'No action selected'); + }); + } +} diff --git a/apps/signal/51-function-call-effect/src/app/app.component.ts b/apps/signal/51-function-call-effect/src/app/app.component.ts new file mode 100644 index 000000000..5f9342eda --- /dev/null +++ b/apps/signal/51-function-call-effect/src/app/app.component.ts @@ -0,0 +1,33 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ActionsComponent } from './action.component'; +import { UserService } from './user.service'; + +@Component({ + imports: [FormsModule, ActionsComponent], + selector: 'app-root', + template: ` + + + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + protected userService = inject(UserService); + + protected users = ['Thomas', 'John', 'Alice', 'Bob', 'Charlie', 'David']; +} diff --git a/apps/signal/51-function-call-effect/src/app/app.config.ts b/apps/signal/51-function-call-effect/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/signal/51-function-call-effect/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/signal/51-function-call-effect/src/app/user.service.ts b/apps/signal/51-function-call-effect/src/app/user.service.ts new file mode 100644 index 000000000..b43756b9e --- /dev/null +++ b/apps/signal/51-function-call-effect/src/app/user.service.ts @@ -0,0 +1,10 @@ +import { Injectable, signal } from '@angular/core'; + +@Injectable({ providedIn: 'root' }) +export class UserService { + name = signal('Thomas'); + + log(message: string) { + console.log(`${this.name()}: ${message}`); + } +} diff --git a/apps/testing/modal/src/assets/.gitkeep b/apps/signal/51-function-call-effect/src/assets/.gitkeep similarity index 100% rename from apps/testing/modal/src/assets/.gitkeep rename to apps/signal/51-function-call-effect/src/assets/.gitkeep diff --git a/apps/testing/table/src/favicon.ico b/apps/signal/51-function-call-effect/src/favicon.ico similarity index 100% rename from apps/testing/table/src/favicon.ico rename to apps/signal/51-function-call-effect/src/favicon.ico diff --git a/apps/signal/51-function-call-effect/src/index.html b/apps/signal/51-function-call-effect/src/index.html new file mode 100644 index 000000000..523bcaef2 --- /dev/null +++ b/apps/signal/51-function-call-effect/src/index.html @@ -0,0 +1,13 @@ + + + + + angular-function-call-effect + + + + + + + + diff --git a/apps/signal/51-function-call-effect/src/main.ts b/apps/signal/51-function-call-effect/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/signal/51-function-call-effect/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/signal/51-function-call-effect/src/styles.scss b/apps/signal/51-function-call-effect/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/signal/51-function-call-effect/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/signal/51-function-call-effect/tailwind.config.js b/apps/signal/51-function-call-effect/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/51-function-call-effect/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/51-function-call-effect/tsconfig.app.json b/apps/signal/51-function-call-effect/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/51-function-call-effect/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/51-function-call-effect/tsconfig.editor.json b/apps/signal/51-function-call-effect/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/signal/51-function-call-effect/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/51-function-call-effect/tsconfig.json b/apps/signal/51-function-call-effect/tsconfig.json new file mode 100644 index 000000000..3df17b921 --- /dev/null +++ b/apps/signal/51-function-call-effect/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/signal/53-big-signal-performance/.eslintrc.json b/apps/signal/53-big-signal-performance/.eslintrc.json new file mode 100644 index 000000000..d3cd7997a --- /dev/null +++ b/apps/signal/53-big-signal-performance/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": {} + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/signal/53-big-signal-performance/README.md b/apps/signal/53-big-signal-performance/README.md new file mode 100644 index 000000000..2b1b56672 --- /dev/null +++ b/apps/signal/53-big-signal-performance/README.md @@ -0,0 +1,13 @@ +# Big Signal Performance + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-big-signal-performance +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/52-big-signal-performance/). diff --git a/apps/signal/53-big-signal-performance/project.json b/apps/signal/53-big-signal-performance/project.json new file mode 100644 index 000000000..88363564f --- /dev/null +++ b/apps/signal/53-big-signal-performance/project.json @@ -0,0 +1,69 @@ +{ + "name": "signal-big-signal-performance", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/53-big-signal-performance/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/53-big-signal-performance", + "index": "apps/signal/53-big-signal-performance/src/index.html", + "browser": "apps/signal/53-big-signal-performance/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/53-big-signal-performance/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/signal/53-big-signal-performance/src/favicon.ico", + "apps/signal/53-big-signal-performance/src/assets" + ], + "styles": ["apps/signal/53-big-signal-performance/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-big-signal-performance:build:production" + }, + "development": { + "buildTarget": "signal-big-signal-performance:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-big-signal-performance:build" + } + } + } +} diff --git a/apps/signal/53-big-signal-performance/src/app/address.component.ts b/apps/signal/53-big-signal-performance/src/app/address.component.ts new file mode 100644 index 000000000..f894d697e --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/address.component.ts @@ -0,0 +1,20 @@ +import { CDFlashingDirective } from '@angular-challenges/shared/directives'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { UserStore } from './user.service'; + +@Component({ + selector: 'address-user', + template: ` +
+ Address: +
Street: {{ userService.user().address.street }}
+
ZipCode: {{ userService.user().address.zipCode }}
+
City: {{ userService.user().address.city }}
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [CDFlashingDirective], +}) +export class AddressComponent { + userService = inject(UserStore); +} diff --git a/apps/signal/53-big-signal-performance/src/app/app.component.ts b/apps/signal/53-big-signal-performance/src/app/app.component.ts new file mode 100644 index 000000000..bf15a5dc2 --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/app.component.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; +import { AddressComponent } from './address.component'; +import { JobComponent } from './job.component'; +import { NameComponent } from './name.component'; +import { NoteComponent } from './note.component'; +import { UserFormComponent } from './user-form.component'; + +@Component({ + selector: 'app-root', + template: ` + + + + + + `, + styles: [''], + imports: [ + JobComponent, + NameComponent, + AddressComponent, + NoteComponent, + UserFormComponent, + ], +}) +export class AppComponent {} diff --git a/apps/signal/53-big-signal-performance/src/app/app.config.ts b/apps/signal/53-big-signal-performance/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/signal/53-big-signal-performance/src/app/job.component.ts b/apps/signal/53-big-signal-performance/src/app/job.component.ts new file mode 100644 index 000000000..d3186fc9f --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/job.component.ts @@ -0,0 +1,19 @@ +import { CDFlashingDirective } from '@angular-challenges/shared/directives'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { UserStore } from './user.service'; + +@Component({ + selector: 'job', + template: ` +
+ Job: +
title: {{ userService.user().title }}
+
salary: {{ userService.user().salary }}
+
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [CDFlashingDirective], +}) +export class JobComponent { + userService = inject(UserStore); +} diff --git a/apps/signal/53-big-signal-performance/src/app/name.component.ts b/apps/signal/53-big-signal-performance/src/app/name.component.ts new file mode 100644 index 000000000..f93b5675a --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/name.component.ts @@ -0,0 +1,17 @@ +import { CDFlashingDirective } from '@angular-challenges/shared/directives'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { UserStore } from './user.service'; + +@Component({ + selector: 'name', + template: ` +
+ Name: {{ userService.user().name }} +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [CDFlashingDirective], +}) +export class NameComponent { + userService = inject(UserStore); +} diff --git a/apps/signal/53-big-signal-performance/src/app/note.component.ts b/apps/signal/53-big-signal-performance/src/app/note.component.ts new file mode 100644 index 000000000..dd0033962 --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/note.component.ts @@ -0,0 +1,17 @@ +import { CDFlashingDirective } from '@angular-challenges/shared/directives'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { UserStore } from './user.service'; + +@Component({ + selector: 'note', + template: ` +
+ Note: {{ userService.user().note }} +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [CDFlashingDirective], +}) +export class NoteComponent { + userService = inject(UserStore); +} diff --git a/apps/signal/53-big-signal-performance/src/app/user-form.component.ts b/apps/signal/53-big-signal-performance/src/app/user-form.component.ts new file mode 100644 index 000000000..d0f2164ce --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/user-form.component.ts @@ -0,0 +1,99 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { UserStore } from './user.service'; + +@Component({ + selector: 'user-form', + imports: [ReactiveFormsModule], + template: ` +
+
+ Name: + +
+
+ Address: +
+ street: + +
+
+ zipCode: + +
+
+ city: + +
+
+
+ note: + +
+
+ title: + +
+
+ salary: + +
+ +
+ `, + host: { + class: 'block border border-gray-500 p-4 pt-10 m-4', + }, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class UserFormComponent { + userStore = inject(UserStore); + + form = new FormGroup({ + name: new FormControl(this.userStore.user().name, { nonNullable: true }), + street: new FormControl(this.userStore.user().address.street, { + nonNullable: true, + }), + zipCode: new FormControl(this.userStore.user().address.zipCode, { + nonNullable: true, + }), + city: new FormControl(this.userStore.user().address.city, { + nonNullable: true, + }), + note: new FormControl(this.userStore.user().note, { nonNullable: true }), + title: new FormControl(this.userStore.user().title, { nonNullable: true }), + salary: new FormControl(this.userStore.user().salary, { + nonNullable: true, + }), + }); + + submit() { + this.userStore.user.update((u) => ({ + ...u, + name: this.form.getRawValue().name, + address: { + ...u.address, + street: this.form.getRawValue().street, + zipCode: this.form.getRawValue().zipCode, + city: this.form.getRawValue().city, + }, + note: this.form.getRawValue().note, + title: this.form.getRawValue().title, + salary: this.form.getRawValue().salary, + })); + } +} diff --git a/apps/signal/53-big-signal-performance/src/app/user.service.ts b/apps/signal/53-big-signal-performance/src/app/user.service.ts new file mode 100644 index 000000000..4b3b7c512 --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/app/user.service.ts @@ -0,0 +1,16 @@ +import { Injectable, signal } from '@angular/core'; + +@Injectable({ providedIn: 'root' }) +export class UserStore { + user = signal({ + name: 'Bob', + address: { + street: '', + zipCode: '', + city: '', + }, + note: '', + title: '', + salary: 0, + }); +} diff --git a/apps/testing/nested/src/assets/.gitkeep b/apps/signal/53-big-signal-performance/src/assets/.gitkeep similarity index 100% rename from apps/testing/nested/src/assets/.gitkeep rename to apps/signal/53-big-signal-performance/src/assets/.gitkeep diff --git a/apps/testing/todos-list/src/favicon.ico b/apps/signal/53-big-signal-performance/src/favicon.ico similarity index 100% rename from apps/testing/todos-list/src/favicon.ico rename to apps/signal/53-big-signal-performance/src/favicon.ico diff --git a/apps/signal/53-big-signal-performance/src/index.html b/apps/signal/53-big-signal-performance/src/index.html new file mode 100644 index 000000000..3f038cc7a --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/index.html @@ -0,0 +1,13 @@ + + + + + signal-big-signal-performance + + + + + + + + diff --git a/apps/signal/53-big-signal-performance/src/main.ts b/apps/signal/53-big-signal-performance/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/signal/53-big-signal-performance/src/styles.scss b/apps/signal/53-big-signal-performance/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/signal/53-big-signal-performance/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/signal/53-big-signal-performance/tailwind.config.js b/apps/signal/53-big-signal-performance/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/53-big-signal-performance/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/53-big-signal-performance/tsconfig.app.json b/apps/signal/53-big-signal-performance/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/53-big-signal-performance/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/53-big-signal-performance/tsconfig.editor.json b/apps/signal/53-big-signal-performance/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/signal/53-big-signal-performance/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/53-big-signal-performance/tsconfig.json b/apps/signal/53-big-signal-performance/tsconfig.json new file mode 100644 index 000000000..3df17b921 --- /dev/null +++ b/apps/signal/53-big-signal-performance/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/signal/54-pipe-observable-to-signal/.eslintrc.json b/apps/signal/54-pipe-observable-to-signal/.eslintrc.json new file mode 100644 index 000000000..d3cd7997a --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": {} + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/signal/54-pipe-observable-to-signal/README.md b/apps/signal/54-pipe-observable-to-signal/README.md new file mode 100644 index 000000000..495cd3aa9 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/README.md @@ -0,0 +1,13 @@ +# Pipe Observable to Signal + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-pipe-observable-to-signal +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/54-pipe-observable-to-signal/). diff --git a/apps/signal/54-pipe-observable-to-signal/project.json b/apps/signal/54-pipe-observable-to-signal/project.json new file mode 100644 index 000000000..47ab2b9ae --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/project.json @@ -0,0 +1,69 @@ +{ + "name": "signal-pipe-observable-to-signal", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/54-pipe-observable-to-signal/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/54-pipe-observable-to-signal", + "index": "apps/signal/54-pipe-observable-to-signal/src/index.html", + "browser": "apps/signal/54-pipe-observable-to-signal/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/54-pipe-observable-to-signal/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/signal/54-pipe-observable-to-signal/src/favicon.ico", + "apps/signal/54-pipe-observable-to-signal/src/assets" + ], + "styles": ["apps/signal/54-pipe-observable-to-signal/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-pipe-observable-to-signal:build:production" + }, + "development": { + "buildTarget": "signal-pipe-observable-to-signal:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-pipe-observable-to-signal:build" + } + } + } +} diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts b/apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts new file mode 100644 index 000000000..72fe7106e --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/app/app.component.ts @@ -0,0 +1,28 @@ +import { TableComponent } from '@angular-challenges/shared/ui'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ProductRowComponent } from './product-row.component'; +import { products } from './product.model'; + +@Component({ + imports: [TableComponent, ProductRowComponent], + selector: 'app-root', + template: ` + + + + @for (col of displayedColumns; track col) { + + } + + + + + +
{{ col }}
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppComponent { + products = products; + displayedColumns = ['name', 'priceA', 'priceB', 'priceC']; +} diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts b/apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts new file mode 100644 index 000000000..e3cc993f4 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/app/currency.pipe.ts @@ -0,0 +1,15 @@ +import { inject, Pipe, PipeTransform } from '@angular/core'; +import { map, Observable } from 'rxjs'; +import { CurrencyService } from './currency.service'; + +@Pipe({ + name: 'currency', + standalone: true, +}) +export class CurrencyPipe implements PipeTransform { + currencyService = inject(CurrencyService); + + transform(price: number): Observable { + return this.currencyService.symbol$.pipe(map((s) => `${price}${s}`)); + } +} diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts b/apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts new file mode 100644 index 000000000..8ddf570bf --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/app/currency.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, map } from 'rxjs'; + +export interface Currency { + name: string; + code: string; + symbol: string; +} + +export const currency: Currency[] = [ + { name: 'Euro', code: 'EUR', symbol: '€' }, + { name: 'Dollar US', code: 'USD', symbol: 'US$' }, + { name: 'Dollar Australian', code: 'AUD', symbol: 'AU$' }, + { name: 'Pound Sterling', code: 'GBP', symbol: '£' }, + { name: 'Dollar Canadian', code: 'CAD', symbol: 'CAD' }, +]; + +@Injectable() +export class CurrencyService { + private code = new BehaviorSubject('EUR'); + + readonly code$ = this.code.asObservable(); + readonly symbol$ = this.code$.pipe( + map((code) => currency.find((c) => c.code === code)?.symbol ?? code), + ); + + public updateCode(code: string) { + this.code.next(code); + } +} diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts b/apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts new file mode 100644 index 000000000..7cb3d4e03 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/app/product-row.component.ts @@ -0,0 +1,33 @@ +import { AsyncPipe } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + inject, + Input, +} from '@angular/core'; +import { CurrencyPipe } from './currency.pipe'; +import { CurrencyService } from './currency.service'; +import { Product } from './product.model'; + +@Component({ + selector: 'tr[product-row]', + template: ` + {{ productInfo.name }} + {{ productInfo.priceA | currency | async }} + {{ productInfo.priceB | currency | async }} + {{ productInfo.priceC | currency | async }} + `, + imports: [AsyncPipe, CurrencyPipe], + providers: [CurrencyService], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ProductRowComponent { + protected productInfo!: Product; + + @Input({ required: true }) set product(product: Product) { + this.currencyService.updateCode(product.currencyCode); + this.productInfo = product; + } + + currencyService = inject(CurrencyService); +} diff --git a/apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts b/apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts new file mode 100644 index 000000000..174e7dc77 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/app/product.model.ts @@ -0,0 +1,55 @@ +export interface Product { + name: string; + priceA: number; + priceB: number; + priceC: number; + currencyCode: string; +} + +export const products: Product[] = [ + { + name: 'bike', + priceA: 1000, + priceB: 2000, + priceC: 2200, + currencyCode: 'USD', + }, + { name: 'tent', priceA: 112, priceB: 120, priceC: 41, currencyCode: 'EUR' }, + { + name: 'sofa', + priceA: 500, + priceB: 422, + priceC: 5000, + currencyCode: 'EUR', + }, + { + name: 'watch', + priceA: 50, + priceB: 130, + priceC: 150, + currencyCode: 'AUD', + }, + { + name: 'computer', + priceA: 1000, + priceB: 2200, + priceC: 3500, + currencyCode: 'GBP', + }, + { name: 'mug', priceA: 10, priceB: 15, priceC: 20, currencyCode: 'EUR' }, + { + name: 'headset', + priceA: 100, + priceB: 150, + priceC: 220, + currencyCode: 'CAD', + }, + { name: 'cable', priceA: 5, priceB: 10, priceC: 15, currencyCode: 'EUR' }, + { + name: 'table', + priceA: 100, + priceB: 20, + priceC: 500, + currencyCode: 'EUR', + }, +]; diff --git a/apps/testing/router-outlet/src/assets/.gitkeep b/apps/signal/54-pipe-observable-to-signal/src/assets/.gitkeep similarity index 100% rename from apps/testing/router-outlet/src/assets/.gitkeep rename to apps/signal/54-pipe-observable-to-signal/src/assets/.gitkeep diff --git a/apps/typescript/overload/src/favicon.ico b/apps/signal/54-pipe-observable-to-signal/src/favicon.ico similarity index 100% rename from apps/typescript/overload/src/favicon.ico rename to apps/signal/54-pipe-observable-to-signal/src/favicon.ico diff --git a/apps/signal/54-pipe-observable-to-signal/src/index.html b/apps/signal/54-pipe-observable-to-signal/src/index.html new file mode 100644 index 000000000..997f94663 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/index.html @@ -0,0 +1,13 @@ + + + + + signal-pipe-observable-to-signal + + + + + + + + diff --git a/apps/testing/input-output/src/main.ts b/apps/signal/54-pipe-observable-to-signal/src/main.ts similarity index 100% rename from apps/testing/input-output/src/main.ts rename to apps/signal/54-pipe-observable-to-signal/src/main.ts diff --git a/apps/signal/54-pipe-observable-to-signal/src/styles.scss b/apps/signal/54-pipe-observable-to-signal/src/styles.scss new file mode 100644 index 000000000..552f97df9 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/src/styles.scss @@ -0,0 +1,26 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ +table { + width: 100%; +} + +table thead > tr > th { + text-align: left; + padding: 1rem 1rem; + border: 1px solid #dee2e6; + border-width: 0 0 1px 0; + font-weight: 700; + color: #343a40; + background: #f8f9fa; + transition: box-shadow 0.2s; +} + +table tbody > tr > td { + text-align: left; + border: 1px solid #dee2e6; + border-width: 0 0 1px 0; + padding: 1rem 1rem; +} diff --git a/apps/signal/54-pipe-observable-to-signal/tailwind.config.js b/apps/signal/54-pipe-observable-to-signal/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/54-pipe-observable-to-signal/tsconfig.app.json b/apps/signal/54-pipe-observable-to-signal/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json b/apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/54-pipe-observable-to-signal/tsconfig.json b/apps/signal/54-pipe-observable-to-signal/tsconfig.json new file mode 100644 index 000000000..3df17b921 --- /dev/null +++ b/apps/signal/54-pipe-observable-to-signal/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/signal/56-forms-and-signal/.eslintrc.json b/apps/signal/56-forms-and-signal/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/signal/56-forms-and-signal/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/signal/56-forms-and-signal/README.md b/apps/signal/56-forms-and-signal/README.md new file mode 100644 index 000000000..ba5def1f0 --- /dev/null +++ b/apps/signal/56-forms-and-signal/README.md @@ -0,0 +1,13 @@ +# forms and signal + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve signal-forms-and-signal +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/signal/56-forms-and-signal/). diff --git a/apps/signal/56-forms-and-signal/project.json b/apps/signal/56-forms-and-signal/project.json new file mode 100644 index 000000000..d825b063c --- /dev/null +++ b/apps/signal/56-forms-and-signal/project.json @@ -0,0 +1,71 @@ +{ + "name": "signal-forms-and-signal", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/signal/56-forms-and-signal/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/signal/56-forms-and-signal", + "index": "apps/signal/56-forms-and-signal/src/index.html", + "browser": "apps/signal/56-forms-and-signal/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/signal/56-forms-and-signal/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "apps/signal/56-forms-and-signal/public" + } + ], + "styles": ["apps/signal/56-forms-and-signal/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "signal-forms-and-signal:build:production" + }, + "development": { + "buildTarget": "signal-forms-and-signal:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "signal-forms-and-signal:build" + } + } + } +} diff --git a/apps/signal/56-forms-and-signal/public/favicon.ico b/apps/signal/56-forms-and-signal/public/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/signal/56-forms-and-signal/public/favicon.ico differ diff --git a/apps/signal/56-forms-and-signal/src/app/app.component.ts b/apps/signal/56-forms-and-signal/src/app/app.component.ts new file mode 100644 index 000000000..d6690ea9a --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/app.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet], + selector: 'app-root', + template: ` +

Shop

+
+ +
+ `, + host: { + class: 'w-full flex justify-center flex-col items-center p-4 gap-10', + }, +}) +export class AppComponent {} diff --git a/apps/signal/56-forms-and-signal/src/app/app.config.ts b/apps/signal/56-forms-and-signal/src/app/app.config.ts new file mode 100644 index 000000000..9cebc385d --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/app.config.ts @@ -0,0 +1,10 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter, withComponentInputBinding } from '@angular/router'; +import { routes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes, withComponentInputBinding()), + ], +}; diff --git a/apps/signal/56-forms-and-signal/src/app/app.routes.ts b/apps/signal/56-forms-and-signal/src/app/app.routes.ts new file mode 100644 index 000000000..091c56d90 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/app.routes.ts @@ -0,0 +1,29 @@ +import { Routes } from '@angular/router'; + +export const routes: Routes = [ + { + path: '', + redirectTo: 'dashboard', + pathMatch: 'full', + }, + { + path: 'dashboard', + loadComponent: () => import('./dashboard.component'), + }, + { + path: 'order', + loadComponent: () => import('./order.component'), + }, + { + path: 'checkout', + loadComponent: () => import('./checkout.component'), + }, + { + path: 'payment', + loadComponent: () => import('./payment.component'), + }, + { + path: '**', + redirectTo: 'dashboard', + }, +]; diff --git a/apps/signal/56-forms-and-signal/src/app/checkout.component.ts b/apps/signal/56-forms-and-signal/src/app/checkout.component.ts new file mode 100644 index 000000000..f9d831088 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/checkout.component.ts @@ -0,0 +1,55 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { products } from './products'; + +@Component({ + selector: 'app-dashboard', + imports: [RouterLink], + template: ` +

Checkout

+ +
+
Your order:
+
+ {{ quantity() }} x {{ product()?.name }}: {{ product()?.price }}€ +
+
+ +
Billing Information
+
...
+
...
+
...
+
...
+
...
+ + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export default class DashboardComponent { + quantity = input(1); + productId = input('1'); + + product = computed(() => + products.find((product) => product.id === this.productId()), + ); + totalWithVAT = computed( + () => this.quantity() * (this.product()?.price ?? 0) * 1.21, + ); +} diff --git a/apps/signal/56-forms-and-signal/src/app/dashboard.component.ts b/apps/signal/56-forms-and-signal/src/app/dashboard.component.ts new file mode 100644 index 000000000..d96fedfd7 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/dashboard.component.ts @@ -0,0 +1,30 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { products } from './products'; + +@Component({ + selector: 'app-dashboard', + imports: [RouterLink], + template: ` +

List of Products

+
    + @for (product of products; track product.id) { +
  • +
    + {{ product.name }} ({{ product.price }}€) + +
    +
  • + } +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export default class DashboardComponent { + products = products; +} diff --git a/apps/signal/56-forms-and-signal/src/app/order.component.ts b/apps/signal/56-forms-and-signal/src/app/order.component.ts new file mode 100644 index 000000000..2b03ba814 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/order.component.ts @@ -0,0 +1,71 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { RouterLink } from '@angular/router'; +import { products } from './products'; + +@Component({ + selector: 'app-order', + imports: [RouterLink, ReactiveFormsModule], + template: ` +

Order

+
+
+ + +
+
+
SubTotal
+
{{ totalWithoutVat() }} €
+
+
+
VAT (21%)
+
{{ vat() }} €
+
+
+
Total
+
{{ total() }} €
+
+ +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export default class OrderComponent { + form = new FormGroup({ + quantity: new FormControl(1, { nonNullable: true }), + }); + + productId = input('1'); + price = computed( + () => products.find((p) => p.id === this.productId())?.price ?? 0, + ); + quantity = toSignal(this.form.controls.quantity.valueChanges, { + initialValue: this.form.getRawValue().quantity, + }); + totalWithoutVat = computed(() => Number(this.price()) * this.quantity()); + vat = computed(() => this.totalWithoutVat() * 0.21); + total = computed(() => this.totalWithoutVat() + this.vat()); +} diff --git a/apps/signal/56-forms-and-signal/src/app/payment.component.ts b/apps/signal/56-forms-and-signal/src/app/payment.component.ts new file mode 100644 index 000000000..800bd6f36 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/payment.component.ts @@ -0,0 +1,18 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; + +@Component({ + selector: 'app-dashboard', + imports: [RouterLink], + template: ` +

Payment Success

+ + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export default class DashboardComponent {} diff --git a/apps/signal/56-forms-and-signal/src/app/products.ts b/apps/signal/56-forms-and-signal/src/app/products.ts new file mode 100644 index 000000000..a893a5b54 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/app/products.ts @@ -0,0 +1,17 @@ +export const products = [ + { + id: '1', + name: 'Computer', + price: 2000, + }, + { + id: '2', + name: 'Mouse', + price: 40, + }, + { + id: '3', + name: 'Keyboard', + price: 80, + }, +]; diff --git a/apps/signal/56-forms-and-signal/src/index.html b/apps/signal/56-forms-and-signal/src/index.html new file mode 100644 index 000000000..eca231086 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/index.html @@ -0,0 +1,13 @@ + + + + + signal-forms-and-signal + + + + + + + + diff --git a/apps/signal/56-forms-and-signal/src/main.ts b/apps/signal/56-forms-and-signal/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/signal/56-forms-and-signal/src/styles.scss b/apps/signal/56-forms-and-signal/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/signal/56-forms-and-signal/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/signal/56-forms-and-signal/tailwind.config.js b/apps/signal/56-forms-and-signal/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/signal/56-forms-and-signal/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/signal/56-forms-and-signal/tsconfig.app.json b/apps/signal/56-forms-and-signal/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/signal/56-forms-and-signal/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/56-forms-and-signal/tsconfig.editor.json b/apps/signal/56-forms-and-signal/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/signal/56-forms-and-signal/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/signal/56-forms-and-signal/tsconfig.json b/apps/signal/56-forms-and-signal/tsconfig.json new file mode 100644 index 000000000..3df17b921 --- /dev/null +++ b/apps/signal/56-forms-and-signal/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/testing/checkbox/.eslintrc.json b/apps/testing/17-router/.eslintrc.json similarity index 100% rename from apps/testing/checkbox/.eslintrc.json rename to apps/testing/17-router/.eslintrc.json diff --git a/apps/testing/17-router/README.md b/apps/testing/17-router/README.md new file mode 100644 index 000000000..fe9a75448 --- /dev/null +++ b/apps/testing/17-router/README.md @@ -0,0 +1,13 @@ +# Router + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve testing-router +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/17-router/). diff --git a/apps/testing/input-output/cypress.config.ts b/apps/testing/17-router/cypress.config.ts similarity index 100% rename from apps/testing/input-output/cypress.config.ts rename to apps/testing/17-router/cypress.config.ts diff --git a/apps/testing/input-output/cypress/fixtures/example.json b/apps/testing/17-router/cypress/fixtures/example.json similarity index 100% rename from apps/testing/input-output/cypress/fixtures/example.json rename to apps/testing/17-router/cypress/fixtures/example.json diff --git a/apps/testing/17-router/cypress/support/commands.ts b/apps/testing/17-router/cypress/support/commands.ts new file mode 100644 index 000000000..b5d8a9582 --- /dev/null +++ b/apps/testing/17-router/cypress/support/commands.ts @@ -0,0 +1,25 @@ +/// +import { mount } from 'cypress/angular'; + +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(email: string, password: string): void; + mount: typeof mount; + } + } +} + +Cypress.Commands.add('mount', mount); diff --git a/apps/testing/router-outlet/cypress/support/component-index.html b/apps/testing/17-router/cypress/support/component-index.html similarity index 100% rename from apps/testing/router-outlet/cypress/support/component-index.html rename to apps/testing/17-router/cypress/support/component-index.html diff --git a/apps/testing/input-output/cypress/support/component.ts b/apps/testing/17-router/cypress/support/component.ts similarity index 100% rename from apps/testing/input-output/cypress/support/component.ts rename to apps/testing/17-router/cypress/support/component.ts diff --git a/apps/testing/input-output/cypress/tsconfig.json b/apps/testing/17-router/cypress/tsconfig.json similarity index 100% rename from apps/testing/input-output/cypress/tsconfig.json rename to apps/testing/17-router/cypress/tsconfig.json diff --git a/apps/testing/17-router/jest.config.ts b/apps/testing/17-router/jest.config.ts new file mode 100644 index 000000000..997c99f0e --- /dev/null +++ b/apps/testing/17-router/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'testing-router', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + globals: {}, + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/17-router/project.json b/apps/testing/17-router/project.json new file mode 100644 index 000000000..44c7a2b18 --- /dev/null +++ b/apps/testing/17-router/project.json @@ -0,0 +1,96 @@ +{ + "name": "testing-router", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/testing/17-router/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/17-router", + "index": "apps/testing/17-router/src/index.html", + "main": "apps/testing/17-router/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/17-router/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/testing/17-router/src/favicon.ico", + "apps/testing/17-router/src/assets" + ], + "styles": ["apps/testing/17-router/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-router:build:production" + }, + "development": { + "buildTarget": "testing-router:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-router:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + }, + "component-test": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/testing/17-router/cypress.config.ts", + "testingType": "component", + "skipServe": true, + "devServerTarget": "testing-router:build" + } + } + } +} diff --git a/apps/testing/router-outlet/src/app/app.component.cy.ts b/apps/testing/17-router/src/app/app.component.cy.ts similarity index 100% rename from apps/testing/router-outlet/src/app/app.component.cy.ts rename to apps/testing/17-router/src/app/app.component.cy.ts diff --git a/apps/testing/router-outlet/src/app/app.component.spec.ts b/apps/testing/17-router/src/app/app.component.spec.ts similarity index 100% rename from apps/testing/router-outlet/src/app/app.component.spec.ts rename to apps/testing/17-router/src/app/app.component.spec.ts diff --git a/apps/testing/17-router/src/app/app.component.ts b/apps/testing/17-router/src/app/app.component.ts new file mode 100644 index 000000000..cc6298f17 --- /dev/null +++ b/apps/testing/17-router/src/app/app.component.ts @@ -0,0 +1,41 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterOutlet } from '@angular/router'; + +@Component({ + imports: [RouterOutlet, RouterLink], + selector: 'app-root', + styles: [ + ` + h1 { + margin-bottom: 0; + } + nav a { + padding: 1rem; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #e8e8e8; + color: #3d3d3d; + border-radius: 4px; + margin-bottom: 10px; + } + nav a:hover { + color: white; + background-color: #42545c; + } + nav a.active { + background-color: black; + } + `, + ], + template: ` +

Library

+ + + + + `, +}) +export class AppComponent {} diff --git a/apps/testing/router-outlet/src/app/app.config.ts b/apps/testing/17-router/src/app/app.config.ts similarity index 100% rename from apps/testing/router-outlet/src/app/app.config.ts rename to apps/testing/17-router/src/app/app.config.ts diff --git a/apps/testing/router-outlet/src/app/app.routes.ts b/apps/testing/17-router/src/app/app.routes.ts similarity index 100% rename from apps/testing/router-outlet/src/app/app.routes.ts rename to apps/testing/17-router/src/app/app.routes.ts diff --git a/apps/testing/router-outlet/src/app/book.guard.ts b/apps/testing/17-router/src/app/book.guard.ts similarity index 100% rename from apps/testing/router-outlet/src/app/book.guard.ts rename to apps/testing/17-router/src/app/book.guard.ts diff --git a/apps/testing/router-outlet/src/app/book.model.ts b/apps/testing/17-router/src/app/book.model.ts similarity index 100% rename from apps/testing/router-outlet/src/app/book.model.ts rename to apps/testing/17-router/src/app/book.model.ts diff --git a/apps/testing/router-outlet/src/app/no-book-search.component.ts b/apps/testing/17-router/src/app/no-book-search.component.ts similarity index 100% rename from apps/testing/router-outlet/src/app/no-book-search.component.ts rename to apps/testing/17-router/src/app/no-book-search.component.ts diff --git a/apps/testing/router-outlet/src/app/search.component.ts b/apps/testing/17-router/src/app/search.component.ts similarity index 98% rename from apps/testing/router-outlet/src/app/search.component.ts rename to apps/testing/17-router/src/app/search.component.ts index b6f8666c3..9027c0cfe 100644 --- a/apps/testing/router-outlet/src/app/search.component.ts +++ b/apps/testing/17-router/src/app/search.component.ts @@ -5,7 +5,6 @@ import { RouterLink } from '@angular/router'; import { availableBooks } from './book.model'; @Component({ - standalone: true, imports: [ReactiveFormsModule, RouterLink, NgFor, NgIf], styles: [ ` diff --git a/apps/testing/router-outlet/src/app/shelf.component.ts b/apps/testing/17-router/src/app/shelf.component.ts similarity index 97% rename from apps/testing/router-outlet/src/app/shelf.component.ts rename to apps/testing/17-router/src/app/shelf.component.ts index a7da5af1a..63cddfab6 100644 --- a/apps/testing/router-outlet/src/app/shelf.component.ts +++ b/apps/testing/17-router/src/app/shelf.component.ts @@ -6,7 +6,6 @@ import { availableBooks } from './book.model'; @Component({ selector: 'app-shelf', - standalone: true, imports: [AsyncPipe, JsonPipe, NgFor], template: `
    diff --git a/apps/testing/table/src/assets/.gitkeep b/apps/testing/17-router/src/assets/.gitkeep similarity index 100% rename from apps/testing/table/src/assets/.gitkeep rename to apps/testing/17-router/src/assets/.gitkeep diff --git a/apps/testing/17-router/src/favicon.ico b/apps/testing/17-router/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/17-router/src/favicon.ico differ diff --git a/apps/testing/17-router/src/index.html b/apps/testing/17-router/src/index.html new file mode 100644 index 000000000..80ec9bf77 --- /dev/null +++ b/apps/testing/17-router/src/index.html @@ -0,0 +1,13 @@ + + + + + testing-router + + + + + + + + diff --git a/apps/testing/modal/src/main.ts b/apps/testing/17-router/src/main.ts similarity index 100% rename from apps/testing/modal/src/main.ts rename to apps/testing/17-router/src/main.ts diff --git a/apps/rxjs/pipe-bug/src/styles.scss b/apps/testing/17-router/src/styles.scss similarity index 100% rename from apps/rxjs/pipe-bug/src/styles.scss rename to apps/testing/17-router/src/styles.scss diff --git a/apps/testing/nested/src/test-setup.ts b/apps/testing/17-router/src/test-setup.ts similarity index 100% rename from apps/testing/nested/src/test-setup.ts rename to apps/testing/17-router/src/test-setup.ts diff --git a/apps/testing/input-output/tsconfig.app.json b/apps/testing/17-router/tsconfig.app.json similarity index 100% rename from apps/testing/input-output/tsconfig.app.json rename to apps/testing/17-router/tsconfig.app.json diff --git a/apps/testing/modal/tsconfig.editor.json b/apps/testing/17-router/tsconfig.editor.json similarity index 100% rename from apps/testing/modal/tsconfig.editor.json rename to apps/testing/17-router/tsconfig.editor.json diff --git a/apps/rxjs/race-condition/tsconfig.json b/apps/testing/17-router/tsconfig.json similarity index 100% rename from apps/rxjs/race-condition/tsconfig.json rename to apps/testing/17-router/tsconfig.json diff --git a/apps/testing/checkbox/tsconfig.spec.json b/apps/testing/17-router/tsconfig.spec.json similarity index 100% rename from apps/testing/checkbox/tsconfig.spec.json rename to apps/testing/17-router/tsconfig.spec.json diff --git a/apps/testing/nested/.eslintrc.json b/apps/testing/18-nested-components/.eslintrc.json similarity index 100% rename from apps/testing/nested/.eslintrc.json rename to apps/testing/18-nested-components/.eslintrc.json diff --git a/apps/testing/18-nested-components/README.md b/apps/testing/18-nested-components/README.md new file mode 100644 index 000000000..659b9e365 --- /dev/null +++ b/apps/testing/18-nested-components/README.md @@ -0,0 +1,13 @@ +# Nested Components + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve testing-nested-components +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/18-nested-comp/). diff --git a/apps/testing/modal/cypress.config.ts b/apps/testing/18-nested-components/cypress.config.ts similarity index 100% rename from apps/testing/modal/cypress.config.ts rename to apps/testing/18-nested-components/cypress.config.ts diff --git a/apps/testing/modal/cypress/fixtures/example.json b/apps/testing/18-nested-components/cypress/fixtures/example.json similarity index 100% rename from apps/testing/modal/cypress/fixtures/example.json rename to apps/testing/18-nested-components/cypress/fixtures/example.json diff --git a/apps/testing/18-nested-components/cypress/support/commands.ts b/apps/testing/18-nested-components/cypress/support/commands.ts new file mode 100644 index 000000000..b5d8a9582 --- /dev/null +++ b/apps/testing/18-nested-components/cypress/support/commands.ts @@ -0,0 +1,25 @@ +/// +import { mount } from 'cypress/angular'; + +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(email: string, password: string): void; + mount: typeof mount; + } + } +} + +Cypress.Commands.add('mount', mount); diff --git a/apps/testing/nested/cypress/support/component-index.html b/apps/testing/18-nested-components/cypress/support/component-index.html similarity index 100% rename from apps/testing/nested/cypress/support/component-index.html rename to apps/testing/18-nested-components/cypress/support/component-index.html diff --git a/apps/testing/modal/cypress/support/component.ts b/apps/testing/18-nested-components/cypress/support/component.ts similarity index 100% rename from apps/testing/modal/cypress/support/component.ts rename to apps/testing/18-nested-components/cypress/support/component.ts diff --git a/apps/testing/modal/cypress/tsconfig.json b/apps/testing/18-nested-components/cypress/tsconfig.json similarity index 100% rename from apps/testing/modal/cypress/tsconfig.json rename to apps/testing/18-nested-components/cypress/tsconfig.json diff --git a/apps/testing/18-nested-components/jest.config.ts b/apps/testing/18-nested-components/jest.config.ts new file mode 100644 index 000000000..c77df55f9 --- /dev/null +++ b/apps/testing/18-nested-components/jest.config.ts @@ -0,0 +1,21 @@ +/* eslint-disable */ +export default { + displayName: 'testing-nested-components', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/18-nested-components/project.json b/apps/testing/18-nested-components/project.json new file mode 100644 index 000000000..3ea6467a4 --- /dev/null +++ b/apps/testing/18-nested-components/project.json @@ -0,0 +1,96 @@ +{ + "name": "testing-nested-components", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/testing/18-nested-components/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/18-nested-components", + "index": "apps/testing/18-nested-components/src/index.html", + "main": "apps/testing/18-nested-components/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/18-nested-components/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/testing/18-nested-components/src/favicon.ico", + "apps/testing/18-nested-components/src/assets" + ], + "styles": ["apps/testing/18-nested-components/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-nested-components:build:production" + }, + "development": { + "buildTarget": "testing-nested-components:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-nested-components:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + }, + "component-test": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/testing/18-nested-components/cypress.config.ts", + "testingType": "component", + "skipServe": true, + "devServerTarget": "testing-nested-components:build" + } + } + } +} diff --git a/apps/testing/18-nested-components/src/app/app.component.ts b/apps/testing/18-nested-components/src/app/app.component.ts new file mode 100644 index 000000000..84b0df68a --- /dev/null +++ b/apps/testing/18-nested-components/src/app/app.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { ChildComponent } from './child.component'; + +@Component({ + imports: [ChildComponent], + selector: 'app-root', + template: ` + + `, +}) +export class AppComponent {} diff --git a/apps/testing/nested/src/app/child.component.cy.ts b/apps/testing/18-nested-components/src/app/child.component.cy.ts similarity index 100% rename from apps/testing/nested/src/app/child.component.cy.ts rename to apps/testing/18-nested-components/src/app/child.component.cy.ts diff --git a/apps/testing/nested/src/app/child.component.spec.ts b/apps/testing/18-nested-components/src/app/child.component.spec.ts similarity index 100% rename from apps/testing/nested/src/app/child.component.spec.ts rename to apps/testing/18-nested-components/src/app/child.component.spec.ts diff --git a/apps/testing/18-nested-components/src/app/child.component.ts b/apps/testing/18-nested-components/src/app/child.component.ts new file mode 100644 index 000000000..1aaca5117 --- /dev/null +++ b/apps/testing/18-nested-components/src/app/child.component.ts @@ -0,0 +1,92 @@ +import { NgIf } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, + inject, +} from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { HttpService } from './http.service'; + +@Component({ + selector: 'app-input', + imports: [ReactiveFormsModule], + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class InputComponent { + title = new FormControl('', { nonNullable: true }); +} + +@Component({ + selector: 'result', + standalone: true, + template: ` +

    Title is {{ title }}

    + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ResultComponent { + @Input() title = ''; +} + +@Component({ + selector: 'app-button', + standalone: true, + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ButtonComponent { + @Output() validate = new EventEmitter(); +} + +@Component({ + selector: 'app-error', + standalone: true, + template: ` +

    Title is required !!!

    + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ErrorComponent { + @Output() validate = new EventEmitter(); +} + +@Component({ + selector: 'app-child', + imports: [ + ResultComponent, + ButtonComponent, + InputComponent, + ErrorComponent, + NgIf, + ], + template: ` + + + + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ChildComponent { + http = inject(HttpService); + + showError = false; + + submit(title: string) { + this.showError = false; + if (title === '') { + this.showError = true; + return; + } + + this.http.sendTitle(title); + } +} diff --git a/apps/testing/nested/src/app/http.service.ts b/apps/testing/18-nested-components/src/app/http.service.ts similarity index 100% rename from apps/testing/nested/src/app/http.service.ts rename to apps/testing/18-nested-components/src/app/http.service.ts diff --git a/apps/testing/todos-list/src/assets/.gitkeep b/apps/testing/18-nested-components/src/assets/.gitkeep similarity index 100% rename from apps/testing/todos-list/src/assets/.gitkeep rename to apps/testing/18-nested-components/src/assets/.gitkeep diff --git a/apps/testing/18-nested-components/src/favicon.ico b/apps/testing/18-nested-components/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/18-nested-components/src/favicon.ico differ diff --git a/apps/testing/18-nested-components/src/index.html b/apps/testing/18-nested-components/src/index.html new file mode 100644 index 000000000..5f7055208 --- /dev/null +++ b/apps/testing/18-nested-components/src/index.html @@ -0,0 +1,13 @@ + + + + + testing-nested-components + + + + + + + + diff --git a/apps/testing/nested/src/main.ts b/apps/testing/18-nested-components/src/main.ts similarity index 100% rename from apps/testing/nested/src/main.ts rename to apps/testing/18-nested-components/src/main.ts diff --git a/apps/testing/input-output/src/styles.scss b/apps/testing/18-nested-components/src/styles.scss similarity index 100% rename from apps/testing/input-output/src/styles.scss rename to apps/testing/18-nested-components/src/styles.scss diff --git a/apps/testing/router-outlet/src/test-setup.ts b/apps/testing/18-nested-components/src/test-setup.ts similarity index 100% rename from apps/testing/router-outlet/src/test-setup.ts rename to apps/testing/18-nested-components/src/test-setup.ts diff --git a/apps/testing/modal/tsconfig.app.json b/apps/testing/18-nested-components/tsconfig.app.json similarity index 100% rename from apps/testing/modal/tsconfig.app.json rename to apps/testing/18-nested-components/tsconfig.app.json diff --git a/apps/testing/nested/tsconfig.editor.json b/apps/testing/18-nested-components/tsconfig.editor.json similarity index 100% rename from apps/testing/nested/tsconfig.editor.json rename to apps/testing/18-nested-components/tsconfig.editor.json diff --git a/apps/testing/input-output/tsconfig.json b/apps/testing/18-nested-components/tsconfig.json similarity index 100% rename from apps/testing/input-output/tsconfig.json rename to apps/testing/18-nested-components/tsconfig.json diff --git a/apps/testing/input-output/tsconfig.spec.json b/apps/testing/18-nested-components/tsconfig.spec.json similarity index 100% rename from apps/testing/input-output/tsconfig.spec.json rename to apps/testing/18-nested-components/tsconfig.spec.json diff --git a/apps/testing/create-harness/.eslintrc.json b/apps/testing/19-input-output/.eslintrc.json similarity index 100% rename from apps/testing/create-harness/.eslintrc.json rename to apps/testing/19-input-output/.eslintrc.json diff --git a/apps/testing/input-output/README.md b/apps/testing/19-input-output/README.md similarity index 100% rename from apps/testing/input-output/README.md rename to apps/testing/19-input-output/README.md diff --git a/apps/testing/nested/cypress.config.ts b/apps/testing/19-input-output/cypress.config.ts similarity index 100% rename from apps/testing/nested/cypress.config.ts rename to apps/testing/19-input-output/cypress.config.ts diff --git a/apps/testing/nested/cypress/fixtures/example.json b/apps/testing/19-input-output/cypress/fixtures/example.json similarity index 100% rename from apps/testing/nested/cypress/fixtures/example.json rename to apps/testing/19-input-output/cypress/fixtures/example.json diff --git a/apps/testing/19-input-output/cypress/support/commands.ts b/apps/testing/19-input-output/cypress/support/commands.ts new file mode 100644 index 000000000..b5d8a9582 --- /dev/null +++ b/apps/testing/19-input-output/cypress/support/commands.ts @@ -0,0 +1,25 @@ +/// +import { mount } from 'cypress/angular'; + +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(email: string, password: string): void; + mount: typeof mount; + } + } +} + +Cypress.Commands.add('mount', mount); diff --git a/apps/testing/input-output/cypress/support/component-index.html b/apps/testing/19-input-output/cypress/support/component-index.html similarity index 100% rename from apps/testing/input-output/cypress/support/component-index.html rename to apps/testing/19-input-output/cypress/support/component-index.html diff --git a/apps/testing/nested/cypress/support/component.ts b/apps/testing/19-input-output/cypress/support/component.ts similarity index 100% rename from apps/testing/nested/cypress/support/component.ts rename to apps/testing/19-input-output/cypress/support/component.ts diff --git a/apps/testing/nested/cypress/tsconfig.json b/apps/testing/19-input-output/cypress/tsconfig.json similarity index 100% rename from apps/testing/nested/cypress/tsconfig.json rename to apps/testing/19-input-output/cypress/tsconfig.json diff --git a/apps/testing/19-input-output/jest.config.ts b/apps/testing/19-input-output/jest.config.ts new file mode 100644 index 000000000..63370e2a3 --- /dev/null +++ b/apps/testing/19-input-output/jest.config.ts @@ -0,0 +1,21 @@ +/* eslint-disable */ +export default { + displayName: 'testing-input-output', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/19-input-output/project.json b/apps/testing/19-input-output/project.json new file mode 100644 index 000000000..e143e2e02 --- /dev/null +++ b/apps/testing/19-input-output/project.json @@ -0,0 +1,96 @@ +{ + "name": "testing-input-output", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/testing/19-input-output/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/19-input-output", + "index": "apps/testing/19-input-output/src/index.html", + "main": "apps/testing/19-input-output/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/19-input-output/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/testing/19-input-output/src/favicon.ico", + "apps/testing/19-input-output/src/assets" + ], + "styles": ["apps/testing/19-input-output/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-input-output:build:production" + }, + "development": { + "buildTarget": "testing-input-output:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-input-output:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + }, + "component-test": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/testing/19-input-output/cypress.config.ts", + "testingType": "component", + "skipServe": true, + "devServerTarget": "testing-input-output:build" + } + } + } +} diff --git a/apps/testing/19-input-output/src/app/app.component.ts b/apps/testing/19-input-output/src/app/app.component.ts new file mode 100644 index 000000000..7e9e0f78a --- /dev/null +++ b/apps/testing/19-input-output/src/app/app.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; +import { CounterComponent } from './counter.component'; + +@Component({ + imports: [CounterComponent], + selector: 'app-root', + template: ` + + `, +}) +export class AppComponent { + log(counter: number) { + console.log('output log', counter); + } +} diff --git a/apps/testing/input-output/src/app/counter.component.cy.ts b/apps/testing/19-input-output/src/app/counter.component.cy.ts similarity index 100% rename from apps/testing/input-output/src/app/counter.component.cy.ts rename to apps/testing/19-input-output/src/app/counter.component.cy.ts diff --git a/apps/testing/input-output/src/app/counter.component.spec.ts b/apps/testing/19-input-output/src/app/counter.component.spec.ts similarity index 100% rename from apps/testing/input-output/src/app/counter.component.spec.ts rename to apps/testing/19-input-output/src/app/counter.component.spec.ts diff --git a/apps/testing/19-input-output/src/app/counter.component.ts b/apps/testing/19-input-output/src/app/counter.component.ts new file mode 100644 index 000000000..df1eed103 --- /dev/null +++ b/apps/testing/19-input-output/src/app/counter.component.ts @@ -0,0 +1,32 @@ +import { + ChangeDetectionStrategy, + Component, + input, + linkedSignal, + output, +} from '@angular/core'; + +@Component({ + selector: 'app-counter', + template: ` +

    Counter: {{ counter() }}

    + + + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class CounterComponent { + initialValue = input.required(); + public counter = linkedSignal(() => this.initialValue()); + + send = output(); + + public increment = () => { + this.counter.set(this.counter() + 1); + }; + + public decrement = () => { + this.counter.set(this.counter() - 1); + }; +} diff --git a/apps/typescript/overload/src/assets/.gitkeep b/apps/testing/19-input-output/src/assets/.gitkeep similarity index 100% rename from apps/typescript/overload/src/assets/.gitkeep rename to apps/testing/19-input-output/src/assets/.gitkeep diff --git a/apps/testing/19-input-output/src/favicon.ico b/apps/testing/19-input-output/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/19-input-output/src/favicon.ico differ diff --git a/apps/testing/19-input-output/src/index.html b/apps/testing/19-input-output/src/index.html new file mode 100644 index 000000000..a5cd1c5da --- /dev/null +++ b/apps/testing/19-input-output/src/index.html @@ -0,0 +1,13 @@ + + + + + testing-input-ouput + + + + + + + + diff --git a/apps/typescript/overload/src/main.ts b/apps/testing/19-input-output/src/main.ts similarity index 100% rename from apps/typescript/overload/src/main.ts rename to apps/testing/19-input-output/src/main.ts diff --git a/apps/testing/nested/src/styles.scss b/apps/testing/19-input-output/src/styles.scss similarity index 100% rename from apps/testing/nested/src/styles.scss rename to apps/testing/19-input-output/src/styles.scss diff --git a/apps/testing/table/src/test-setup.ts b/apps/testing/19-input-output/src/test-setup.ts similarity index 100% rename from apps/testing/table/src/test-setup.ts rename to apps/testing/19-input-output/src/test-setup.ts diff --git a/apps/testing/nested/tsconfig.app.json b/apps/testing/19-input-output/tsconfig.app.json similarity index 100% rename from apps/testing/nested/tsconfig.app.json rename to apps/testing/19-input-output/tsconfig.app.json diff --git a/apps/testing/router-outlet/tsconfig.editor.json b/apps/testing/19-input-output/tsconfig.editor.json similarity index 100% rename from apps/testing/router-outlet/tsconfig.editor.json rename to apps/testing/19-input-output/tsconfig.editor.json diff --git a/apps/testing/modal/tsconfig.json b/apps/testing/19-input-output/tsconfig.json similarity index 100% rename from apps/testing/modal/tsconfig.json rename to apps/testing/19-input-output/tsconfig.json diff --git a/apps/testing/modal/tsconfig.spec.json b/apps/testing/19-input-output/tsconfig.spec.json similarity index 100% rename from apps/testing/modal/tsconfig.spec.json rename to apps/testing/19-input-output/tsconfig.spec.json diff --git a/apps/testing/harness/.eslintrc.json b/apps/testing/20-modal/.eslintrc.json similarity index 100% rename from apps/testing/harness/.eslintrc.json rename to apps/testing/20-modal/.eslintrc.json diff --git a/apps/testing/modal/README.md b/apps/testing/20-modal/README.md similarity index 100% rename from apps/testing/modal/README.md rename to apps/testing/20-modal/README.md diff --git a/apps/testing/router-outlet/cypress.config.ts b/apps/testing/20-modal/cypress.config.ts similarity index 100% rename from apps/testing/router-outlet/cypress.config.ts rename to apps/testing/20-modal/cypress.config.ts diff --git a/apps/testing/router-outlet/cypress/fixtures/example.json b/apps/testing/20-modal/cypress/fixtures/example.json similarity index 100% rename from apps/testing/router-outlet/cypress/fixtures/example.json rename to apps/testing/20-modal/cypress/fixtures/example.json diff --git a/apps/testing/20-modal/cypress/support/commands.ts b/apps/testing/20-modal/cypress/support/commands.ts new file mode 100644 index 000000000..b5d8a9582 --- /dev/null +++ b/apps/testing/20-modal/cypress/support/commands.ts @@ -0,0 +1,25 @@ +/// +import { mount } from 'cypress/angular'; + +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(email: string, password: string): void; + mount: typeof mount; + } + } +} + +Cypress.Commands.add('mount', mount); diff --git a/apps/testing/modal/cypress/support/component-index.html b/apps/testing/20-modal/cypress/support/component-index.html similarity index 100% rename from apps/testing/modal/cypress/support/component-index.html rename to apps/testing/20-modal/cypress/support/component-index.html diff --git a/apps/testing/router-outlet/cypress/support/component.ts b/apps/testing/20-modal/cypress/support/component.ts similarity index 100% rename from apps/testing/router-outlet/cypress/support/component.ts rename to apps/testing/20-modal/cypress/support/component.ts diff --git a/apps/testing/router-outlet/cypress/tsconfig.json b/apps/testing/20-modal/cypress/tsconfig.json similarity index 100% rename from apps/testing/router-outlet/cypress/tsconfig.json rename to apps/testing/20-modal/cypress/tsconfig.json diff --git a/apps/testing/20-modal/jest.config.ts b/apps/testing/20-modal/jest.config.ts new file mode 100644 index 000000000..809080bcc --- /dev/null +++ b/apps/testing/20-modal/jest.config.ts @@ -0,0 +1,21 @@ +/* eslint-disable */ +export default { + displayName: 'testing-modal', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/20-modal/project.json b/apps/testing/20-modal/project.json new file mode 100644 index 000000000..28134614f --- /dev/null +++ b/apps/testing/20-modal/project.json @@ -0,0 +1,99 @@ +{ + "name": "testing-modal", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/testing/20-modal/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/20-modal", + "index": "apps/testing/20-modal/src/index.html", + "main": "apps/testing/20-modal/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/20-modal/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/testing/20-modal/src/favicon.ico", + "apps/testing/20-modal/src/assets" + ], + "styles": [ + "apps/testing/20-modal/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-modal:build:production" + }, + "development": { + "buildTarget": "testing-modal:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-modal:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + }, + "component-test": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/testing/20-modal/cypress.config.ts", + "testingType": "component", + "skipServe": true, + "devServerTarget": "testing-modal:build" + } + } + } +} diff --git a/apps/testing/modal/src/app/app.component.cy.ts b/apps/testing/20-modal/src/app/app.component.cy.ts similarity index 100% rename from apps/testing/modal/src/app/app.component.cy.ts rename to apps/testing/20-modal/src/app/app.component.cy.ts diff --git a/apps/testing/modal/src/app/app.component.spec.ts b/apps/testing/20-modal/src/app/app.component.spec.ts similarity index 100% rename from apps/testing/modal/src/app/app.component.spec.ts rename to apps/testing/20-modal/src/app/app.component.spec.ts diff --git a/apps/testing/20-modal/src/app/app.component.ts b/apps/testing/20-modal/src/app/app.component.ts new file mode 100644 index 000000000..d5f35b4bf --- /dev/null +++ b/apps/testing/20-modal/src/app/app.component.ts @@ -0,0 +1,64 @@ +import { AsyncPipe } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { BehaviorSubject } from 'rxjs'; +import { ErrorDialog } from './error.dialog'; +import { ProfilConfirmationDialog } from './profil-confirmation.dialog'; +@Component({ + imports: [ + ReactiveFormsModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule, + MatButtonModule, + AsyncPipe, + ], + selector: 'app-root', + host: { + class: 'p-4 block flex gap-4 items-center', + }, + template: ` + + Name + + + + +
    {{ result$ | async }}
    + `, +}) +export class AppComponent { + private modal = inject(MatDialog); + private result = new BehaviorSubject(''); + result$ = this.result.asObservable(); + + name = new FormControl('', { nonNullable: true }); + + confirm() { + if (!this.name.value) { + this.modal.open(ErrorDialog); + return; + } + + this.modal + .open(ProfilConfirmationDialog, { + data: { + name: this.name.value, + }, + }) + .afterClosed() + .subscribe((result) => + this.result.next( + result ? 'Name has been submitted' : 'Name is invalid !!', + ), + ); + } +} diff --git a/apps/testing/modal/src/app/app.config.ts b/apps/testing/20-modal/src/app/app.config.ts similarity index 100% rename from apps/testing/modal/src/app/app.config.ts rename to apps/testing/20-modal/src/app/app.config.ts diff --git a/apps/testing/modal/src/app/error.dialog.ts b/apps/testing/20-modal/src/app/error.dialog.ts similarity index 96% rename from apps/testing/modal/src/app/error.dialog.ts rename to apps/testing/20-modal/src/app/error.dialog.ts index 38412ba5e..251d5d513 100644 --- a/apps/testing/modal/src/app/error.dialog.ts +++ b/apps/testing/20-modal/src/app/error.dialog.ts @@ -4,7 +4,6 @@ import { MatButtonModule } from '@angular/material/button'; import { MatDialogModule } from '@angular/material/dialog'; @Component({ - standalone: true, imports: [MatButtonModule, MatDialogModule], template: `

    Error

    diff --git a/apps/testing/modal/src/app/profil-confirmation.dialog.ts b/apps/testing/20-modal/src/app/profil-confirmation.dialog.ts similarity index 97% rename from apps/testing/modal/src/app/profil-confirmation.dialog.ts rename to apps/testing/20-modal/src/app/profil-confirmation.dialog.ts index 6af2d41dd..e77211e24 100644 --- a/apps/testing/modal/src/app/profil-confirmation.dialog.ts +++ b/apps/testing/20-modal/src/app/profil-confirmation.dialog.ts @@ -4,7 +4,6 @@ import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; @Component({ - standalone: true, imports: [MatButtonModule, MatDialogModule], template: `

    Profil

    diff --git a/NX b/apps/testing/20-modal/src/assets/.gitkeep similarity index 100% rename from NX rename to apps/testing/20-modal/src/assets/.gitkeep diff --git a/apps/testing/20-modal/src/favicon.ico b/apps/testing/20-modal/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/20-modal/src/favicon.ico differ diff --git a/apps/testing/20-modal/src/index.html b/apps/testing/20-modal/src/index.html new file mode 100644 index 000000000..362733ce1 --- /dev/null +++ b/apps/testing/20-modal/src/index.html @@ -0,0 +1,13 @@ + + + + + testing-modal + + + + + + + + diff --git a/apps/testing/router-outlet/src/main.ts b/apps/testing/20-modal/src/main.ts similarity index 100% rename from apps/testing/router-outlet/src/main.ts rename to apps/testing/20-modal/src/main.ts diff --git a/apps/testing/20-modal/src/styles.scss b/apps/testing/20-modal/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/testing/20-modal/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/testing/todos-list/src/test-setup.ts b/apps/testing/20-modal/src/test-setup.ts similarity index 100% rename from apps/testing/todos-list/src/test-setup.ts rename to apps/testing/20-modal/src/test-setup.ts diff --git a/apps/testing/20-modal/tailwind.config.js b/apps/testing/20-modal/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/testing/20-modal/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/testing/router-outlet/tsconfig.app.json b/apps/testing/20-modal/tsconfig.app.json similarity index 100% rename from apps/testing/router-outlet/tsconfig.app.json rename to apps/testing/20-modal/tsconfig.app.json diff --git a/apps/testing/table/tsconfig.editor.json b/apps/testing/20-modal/tsconfig.editor.json similarity index 100% rename from apps/testing/table/tsconfig.editor.json rename to apps/testing/20-modal/tsconfig.editor.json diff --git a/apps/testing/nested/tsconfig.json b/apps/testing/20-modal/tsconfig.json similarity index 100% rename from apps/testing/nested/tsconfig.json rename to apps/testing/20-modal/tsconfig.json diff --git a/apps/testing/nested/tsconfig.spec.json b/apps/testing/20-modal/tsconfig.spec.json similarity index 100% rename from apps/testing/nested/tsconfig.spec.json rename to apps/testing/20-modal/tsconfig.spec.json diff --git a/apps/testing/input-output/.eslintrc.json b/apps/testing/23-harness/.eslintrc.json similarity index 100% rename from apps/testing/input-output/.eslintrc.json rename to apps/testing/23-harness/.eslintrc.json diff --git a/apps/testing/harness/README.md b/apps/testing/23-harness/README.md similarity index 100% rename from apps/testing/harness/README.md rename to apps/testing/23-harness/README.md diff --git a/apps/testing/23-harness/jest.config.ts b/apps/testing/23-harness/jest.config.ts new file mode 100644 index 000000000..2b9e6d44c --- /dev/null +++ b/apps/testing/23-harness/jest.config.ts @@ -0,0 +1,21 @@ +/* eslint-disable */ +export default { + displayName: 'testing-harness', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/23-harness/project.json b/apps/testing/23-harness/project.json new file mode 100644 index 000000000..23e5b04f4 --- /dev/null +++ b/apps/testing/23-harness/project.json @@ -0,0 +1,86 @@ +{ + "name": "testing-harness", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/testing/23-harness/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/23-harness", + "index": "apps/testing/23-harness/src/index.html", + "main": "apps/testing/23-harness/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/23-harness/tsconfig.app.json", + "assets": [ + "apps/testing/23-harness/src/favicon.ico", + "apps/testing/23-harness/src/assets" + ], + "styles": ["apps/testing/23-harness/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-harness:build:production" + }, + "development": { + "buildTarget": "testing-harness:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-harness:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/testing/23-harness/src/app/app.component.ts b/apps/testing/23-harness/src/app/app.component.ts new file mode 100644 index 000000000..7ecf1998d --- /dev/null +++ b/apps/testing/23-harness/src/app/app.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { ChildComponent } from './child.component'; + +@Component({ + imports: [ChildComponent], + selector: 'app-root', + template: ` + + `, + styles: [''], +}) +export class AppComponent {} diff --git a/apps/testing/create-harness/src/app/app.config.ts b/apps/testing/23-harness/src/app/app.config.ts similarity index 100% rename from apps/testing/create-harness/src/app/app.config.ts rename to apps/testing/23-harness/src/app/app.config.ts diff --git a/apps/testing/harness/src/app/child.component.spec.ts b/apps/testing/23-harness/src/app/child.component.spec.ts similarity index 100% rename from apps/testing/harness/src/app/child.component.spec.ts rename to apps/testing/23-harness/src/app/child.component.spec.ts diff --git a/apps/testing/23-harness/src/app/child.component.ts b/apps/testing/23-harness/src/app/child.component.ts new file mode 100644 index 000000000..935f08f89 --- /dev/null +++ b/apps/testing/23-harness/src/app/child.component.ts @@ -0,0 +1,119 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatCardModule } from '@angular/material/card'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSliderModule } from '@angular/material/slider'; + +@Component({ + selector: 'app-child', + template: ` + + +

    Slider configuration

    + +
    + + Value + + + + Min value + + + + Max value + + + + Step size + + +
    + +
    + Show ticks +
    + +
    + Show thumb label +
    + +
    + Disabled +
    +
    +
    + + + +
    + + + + + +
    +
    +
    + `, + styles: [ + ` + .mat-mdc-slider { + max-width: 300px; + width: 100%; + } + + .mat-mdc-card + .mat-mdc-card { + margin-top: 8px; + } + `, + ], + imports: [ + MatCardModule, + MatFormFieldModule, + MatInputModule, + FormsModule, + MatCheckboxModule, + MatSliderModule, + MatIconModule, + ], +}) +export class ChildComponent { + disabled = false; + max = 100; + min = 0; + showTicks = false; + step = 1; + thumbLabel = false; + value = 0; + + back() { + if (this.value - this.step >= this.min) { + this.value -= this.step; + } + } + + forward() { + if (this.value + this.step <= this.max) { + this.value += this.step; + } + } +} diff --git a/apps/ngrx/effect-selector/src/styles.scss b/apps/testing/23-harness/src/assets/.gitkeep similarity index 100% rename from apps/ngrx/effect-selector/src/styles.scss rename to apps/testing/23-harness/src/assets/.gitkeep diff --git a/apps/testing/23-harness/src/favicon.ico b/apps/testing/23-harness/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/23-harness/src/favicon.ico differ diff --git a/apps/testing/23-harness/src/index.html b/apps/testing/23-harness/src/index.html new file mode 100644 index 000000000..9b55da74f --- /dev/null +++ b/apps/testing/23-harness/src/index.html @@ -0,0 +1,16 @@ + + + + + testing-harness + + + + + + + + + diff --git a/apps/testing/23-harness/src/main.ts b/apps/testing/23-harness/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/testing/23-harness/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/testing/23-harness/src/styles.scss b/apps/testing/23-harness/src/styles.scss new file mode 100644 index 000000000..9a29b71e6 --- /dev/null +++ b/apps/testing/23-harness/src/styles.scss @@ -0,0 +1,29 @@ +@use '@angular/material' as mat; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ + +@include mat.elevation-classes(); +@include mat.app-background(); + +$theme-primary: mat.m2-define-palette(mat.$m2-indigo-palette); +$theme-accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400); + +$theme-warn: mat.m2-define-palette(mat.$m2-red-palette); + +$theme: mat.m2-define-light-theme( + ( + color: ( + primary: $theme-primary, + accent: $theme-accent, + warn: $theme-warn, + ), + typography: mat.m2-define-typography-config(), + ) +); + +@include mat.dialog-theme($theme); +@include mat.all-component-themes($theme); diff --git a/apps/testing/23-harness/src/test-setup.ts b/apps/testing/23-harness/src/test-setup.ts new file mode 100644 index 000000000..15de72a3c --- /dev/null +++ b/apps/testing/23-harness/src/test-setup.ts @@ -0,0 +1,2 @@ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; diff --git a/apps/testing/23-harness/tailwind.config.js b/apps/testing/23-harness/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/testing/23-harness/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/testing/23-harness/tsconfig.app.json b/apps/testing/23-harness/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/testing/23-harness/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/testing/harness/tsconfig.editor.json b/apps/testing/23-harness/tsconfig.editor.json similarity index 100% rename from apps/testing/harness/tsconfig.editor.json rename to apps/testing/23-harness/tsconfig.editor.json diff --git a/apps/testing/create-harness/tsconfig.json b/apps/testing/23-harness/tsconfig.json similarity index 100% rename from apps/testing/create-harness/tsconfig.json rename to apps/testing/23-harness/tsconfig.json diff --git a/apps/testing/create-harness/tsconfig.spec.json b/apps/testing/23-harness/tsconfig.spec.json similarity index 100% rename from apps/testing/create-harness/tsconfig.spec.json rename to apps/testing/23-harness/tsconfig.spec.json diff --git a/apps/testing/modal/.eslintrc.json b/apps/testing/24-harness-creation/.eslintrc.json similarity index 100% rename from apps/testing/modal/.eslintrc.json rename to apps/testing/24-harness-creation/.eslintrc.json diff --git a/apps/testing/24-harness-creation/README.md b/apps/testing/24-harness-creation/README.md new file mode 100644 index 000000000..928bb1aab --- /dev/null +++ b/apps/testing/24-harness-creation/README.md @@ -0,0 +1,13 @@ +# Harness Creation + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve testing-harness-creation +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/24-harness-creation/). diff --git a/apps/testing/24-harness-creation/jest.config.ts b/apps/testing/24-harness-creation/jest.config.ts new file mode 100644 index 000000000..c4b9f08db --- /dev/null +++ b/apps/testing/24-harness-creation/jest.config.ts @@ -0,0 +1,21 @@ +/* eslint-disable */ +export default { + displayName: 'testing-harness-creation', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/24-harness-creation/project.json b/apps/testing/24-harness-creation/project.json new file mode 100644 index 000000000..f65194122 --- /dev/null +++ b/apps/testing/24-harness-creation/project.json @@ -0,0 +1,86 @@ +{ + "name": "testing-harness-creation", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/testing/24-harness-creation/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/24-harness-creation", + "index": "apps/testing/24-harness-creation/src/index.html", + "main": "apps/testing/24-harness-creation/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/24-harness-creation/tsconfig.app.json", + "assets": [ + "apps/testing/24-harness-creation/src/favicon.ico", + "apps/testing/24-harness-creation/src/assets" + ], + "styles": ["apps/testing/24-harness-creation/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-harness-creation:build:production" + }, + "development": { + "buildTarget": "testing-harness-creation:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-harness-creation:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/testing/create-harness/src/app/app.component.spec.ts b/apps/testing/24-harness-creation/src/app/app.component.spec.ts similarity index 100% rename from apps/testing/create-harness/src/app/app.component.spec.ts rename to apps/testing/24-harness-creation/src/app/app.component.spec.ts diff --git a/apps/testing/24-harness-creation/src/app/app.component.ts b/apps/testing/24-harness-creation/src/app/app.component.ts new file mode 100644 index 000000000..b1c16240e --- /dev/null +++ b/apps/testing/24-harness-creation/src/app/app.component.ts @@ -0,0 +1,27 @@ +import { Component, signal } from '@angular/core'; +import { SliderComponent } from './slider.component'; + +@Component({ + imports: [SliderComponent], + selector: 'app-root', + template: ` +

    Slider 1: {{ slider1Value() }}

    + +

    Slider 2: {{ slider2Value() }}

    +

    Enabled only if Slider 1 > 20

    + + `, + styles: [''], +}) +export class AppComponent { + slider1Value = signal(10); + slider2Value = signal(0); +} diff --git a/apps/testing/harness/src/app/app.config.ts b/apps/testing/24-harness-creation/src/app/app.config.ts similarity index 100% rename from apps/testing/harness/src/app/app.config.ts rename to apps/testing/24-harness-creation/src/app/app.config.ts diff --git a/apps/testing/create-harness/src/app/slider.component.ts b/apps/testing/24-harness-creation/src/app/slider.component.ts similarity index 99% rename from apps/testing/create-harness/src/app/slider.component.ts rename to apps/testing/24-harness-creation/src/app/slider.component.ts index bc77ff1f3..4a3e429bb 100644 --- a/apps/testing/create-harness/src/app/slider.component.ts +++ b/apps/testing/24-harness-creation/src/app/slider.component.ts @@ -48,7 +48,6 @@ import { skip } from 'rxjs'; } `, ], - standalone: true, imports: [MatCardModule, MatSliderModule, MatIconModule, FormsModule], }) export class SliderComponent implements OnInit { diff --git a/apps/testing/create-harness/src/app/slider.harness.ts b/apps/testing/24-harness-creation/src/app/slider.harness.ts similarity index 100% rename from apps/testing/create-harness/src/app/slider.harness.ts rename to apps/testing/24-harness-creation/src/app/slider.harness.ts diff --git a/apps/testing/24-harness-creation/src/assets/.gitkeep b/apps/testing/24-harness-creation/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/testing/24-harness-creation/src/favicon.ico b/apps/testing/24-harness-creation/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/24-harness-creation/src/favicon.ico differ diff --git a/apps/testing/24-harness-creation/src/index.html b/apps/testing/24-harness-creation/src/index.html new file mode 100644 index 000000000..c66440e5c --- /dev/null +++ b/apps/testing/24-harness-creation/src/index.html @@ -0,0 +1,16 @@ + + + + + testing-harness-creation + + + + + + + + + diff --git a/apps/testing/24-harness-creation/src/main.ts b/apps/testing/24-harness-creation/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/testing/24-harness-creation/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/testing/24-harness-creation/src/styles.scss b/apps/testing/24-harness-creation/src/styles.scss new file mode 100644 index 000000000..1430d2f9b --- /dev/null +++ b/apps/testing/24-harness-creation/src/styles.scss @@ -0,0 +1,30 @@ +/* You can add global styles to this file, and also import other style files */ +@use '@angular/material' as mat; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ + +@include mat.elevation-classes(); +@include mat.app-background(); + +$theme-primary: mat.m2-define-palette(mat.$m2-indigo-palette); +$theme-accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400); + +$theme-warn: mat.m2-define-palette(mat.$m2-red-palette); + +$theme: mat.m2-define-light-theme( + ( + color: ( + primary: $theme-primary, + accent: $theme-accent, + warn: $theme-warn, + ), + typography: mat.m2-define-typography-config(), + ) +); + +@include mat.dialog-theme($theme); +@include mat.all-component-themes($theme); diff --git a/apps/testing/24-harness-creation/src/test-setup.ts b/apps/testing/24-harness-creation/src/test-setup.ts new file mode 100644 index 000000000..15de72a3c --- /dev/null +++ b/apps/testing/24-harness-creation/src/test-setup.ts @@ -0,0 +1,2 @@ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; diff --git a/apps/testing/24-harness-creation/tailwind.config.js b/apps/testing/24-harness-creation/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/testing/24-harness-creation/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/testing/24-harness-creation/tsconfig.app.json b/apps/testing/24-harness-creation/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/testing/24-harness-creation/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/testing/create-harness/tsconfig.editor.json b/apps/testing/24-harness-creation/tsconfig.editor.json similarity index 100% rename from apps/testing/create-harness/tsconfig.editor.json rename to apps/testing/24-harness-creation/tsconfig.editor.json diff --git a/apps/testing/harness/tsconfig.json b/apps/testing/24-harness-creation/tsconfig.json similarity index 100% rename from apps/testing/harness/tsconfig.json rename to apps/testing/24-harness-creation/tsconfig.json diff --git a/apps/testing/harness/tsconfig.spec.json b/apps/testing/24-harness-creation/tsconfig.spec.json similarity index 100% rename from apps/testing/harness/tsconfig.spec.json rename to apps/testing/24-harness-creation/tsconfig.spec.json diff --git a/apps/testing/router-outlet/.eslintrc.json b/apps/testing/28-checkbox/.eslintrc.json similarity index 100% rename from apps/testing/router-outlet/.eslintrc.json rename to apps/testing/28-checkbox/.eslintrc.json diff --git a/apps/testing/checkbox/README.md b/apps/testing/28-checkbox/README.md similarity index 100% rename from apps/testing/checkbox/README.md rename to apps/testing/28-checkbox/README.md diff --git a/apps/testing/28-checkbox/jest.config.ts b/apps/testing/28-checkbox/jest.config.ts new file mode 100644 index 000000000..c27a02c1e --- /dev/null +++ b/apps/testing/28-checkbox/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'testing-checkbox', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/testing/28-checkbox', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/28-checkbox/project.json b/apps/testing/28-checkbox/project.json new file mode 100644 index 000000000..982e85c2e --- /dev/null +++ b/apps/testing/28-checkbox/project.json @@ -0,0 +1,82 @@ +{ + "name": "testing-checkbox", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/testing/28-checkbox/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/28-checkbox", + "index": "apps/testing/28-checkbox/src/index.html", + "main": "apps/testing/28-checkbox/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/28-checkbox/tsconfig.app.json", + "assets": [ + "apps/testing/28-checkbox/src/favicon.ico", + "apps/testing/28-checkbox/src/assets" + ], + "styles": ["apps/testing/28-checkbox/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-checkbox:build:production" + }, + "development": { + "buildTarget": "testing-checkbox:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-checkbox:build" + } + }, + "test": { + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + } + } +} diff --git a/apps/testing/checkbox/src/app/app.component.spec.ts b/apps/testing/28-checkbox/src/app/app.component.spec.ts similarity index 100% rename from apps/testing/checkbox/src/app/app.component.spec.ts rename to apps/testing/28-checkbox/src/app/app.component.spec.ts diff --git a/apps/testing/checkbox/src/app/app.component.ts b/apps/testing/28-checkbox/src/app/app.component.ts similarity index 100% rename from apps/testing/checkbox/src/app/app.component.ts rename to apps/testing/28-checkbox/src/app/app.component.ts diff --git a/apps/testing/28-checkbox/src/assets/.gitkeep b/apps/testing/28-checkbox/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/testing/28-checkbox/src/favicon.ico b/apps/testing/28-checkbox/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/28-checkbox/src/favicon.ico differ diff --git a/apps/testing/checkbox/src/index.html b/apps/testing/28-checkbox/src/index.html similarity index 100% rename from apps/testing/checkbox/src/index.html rename to apps/testing/28-checkbox/src/index.html diff --git a/apps/testing/28-checkbox/src/main.ts b/apps/testing/28-checkbox/src/main.ts new file mode 100644 index 000000000..31c5da482 --- /dev/null +++ b/apps/testing/28-checkbox/src/main.ts @@ -0,0 +1,4 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent).catch((err) => console.error(err)); diff --git a/apps/testing/28-checkbox/src/styles.scss b/apps/testing/28-checkbox/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/testing/28-checkbox/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/testing/28-checkbox/src/test-setup.ts b/apps/testing/28-checkbox/src/test-setup.ts new file mode 100644 index 000000000..15de72a3c --- /dev/null +++ b/apps/testing/28-checkbox/src/test-setup.ts @@ -0,0 +1,2 @@ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; diff --git a/apps/testing/28-checkbox/tailwind.config.js b/apps/testing/28-checkbox/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/testing/28-checkbox/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/testing/28-checkbox/tsconfig.app.json b/apps/testing/28-checkbox/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/testing/28-checkbox/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/testing/todos-list/tsconfig.editor.json b/apps/testing/28-checkbox/tsconfig.editor.json similarity index 100% rename from apps/testing/todos-list/tsconfig.editor.json rename to apps/testing/28-checkbox/tsconfig.editor.json diff --git a/apps/testing/checkbox/tsconfig.json b/apps/testing/28-checkbox/tsconfig.json similarity index 100% rename from apps/testing/checkbox/tsconfig.json rename to apps/testing/28-checkbox/tsconfig.json diff --git a/apps/testing/router-outlet/tsconfig.spec.json b/apps/testing/28-checkbox/tsconfig.spec.json similarity index 100% rename from apps/testing/router-outlet/tsconfig.spec.json rename to apps/testing/28-checkbox/tsconfig.spec.json diff --git a/apps/testing/table/.eslintrc.json b/apps/testing/29-real-life-application/.eslintrc.json similarity index 100% rename from apps/testing/table/.eslintrc.json rename to apps/testing/29-real-life-application/.eslintrc.json diff --git a/apps/testing/29-real-life-application/README.md b/apps/testing/29-real-life-application/README.md new file mode 100644 index 000000000..8dcfe21e6 --- /dev/null +++ b/apps/testing/29-real-life-application/README.md @@ -0,0 +1,13 @@ +# Real-life Application + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve testing-real-life-application +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/29-real-application/). diff --git a/apps/testing/table/cypress.config.ts b/apps/testing/29-real-life-application/cypress.config.ts similarity index 100% rename from apps/testing/table/cypress.config.ts rename to apps/testing/29-real-life-application/cypress.config.ts diff --git a/apps/testing/table/cypress/fixtures/example.json b/apps/testing/29-real-life-application/cypress/fixtures/example.json similarity index 100% rename from apps/testing/table/cypress/fixtures/example.json rename to apps/testing/29-real-life-application/cypress/fixtures/example.json diff --git a/apps/testing/29-real-life-application/cypress/support/commands.ts b/apps/testing/29-real-life-application/cypress/support/commands.ts new file mode 100644 index 000000000..b5d8a9582 --- /dev/null +++ b/apps/testing/29-real-life-application/cypress/support/commands.ts @@ -0,0 +1,25 @@ +/// +import { mount } from 'cypress/angular'; + +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(email: string, password: string): void; + mount: typeof mount; + } + } +} + +Cypress.Commands.add('mount', mount); diff --git a/apps/testing/todos-list/cypress/support/component-index.html b/apps/testing/29-real-life-application/cypress/support/component-index.html similarity index 100% rename from apps/testing/todos-list/cypress/support/component-index.html rename to apps/testing/29-real-life-application/cypress/support/component-index.html diff --git a/apps/testing/table/cypress/support/component.ts b/apps/testing/29-real-life-application/cypress/support/component.ts similarity index 100% rename from apps/testing/table/cypress/support/component.ts rename to apps/testing/29-real-life-application/cypress/support/component.ts diff --git a/apps/testing/table/cypress/tsconfig.json b/apps/testing/29-real-life-application/cypress/tsconfig.json similarity index 100% rename from apps/testing/table/cypress/tsconfig.json rename to apps/testing/29-real-life-application/cypress/tsconfig.json diff --git a/apps/testing/29-real-life-application/jest.config.ts b/apps/testing/29-real-life-application/jest.config.ts new file mode 100644 index 000000000..b78a06561 --- /dev/null +++ b/apps/testing/29-real-life-application/jest.config.ts @@ -0,0 +1,21 @@ +/* eslint-disable */ +export default { + displayName: 'testing-real-life-application', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/testing/29-real-life-application/project.json b/apps/testing/29-real-life-application/project.json new file mode 100644 index 000000000..c6f1c12d9 --- /dev/null +++ b/apps/testing/29-real-life-application/project.json @@ -0,0 +1,99 @@ +{ + "name": "testing-real-life-application", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/testing/29-real-life-application/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/testing/29-real-life-application", + "index": "apps/testing/29-real-life-application/src/index.html", + "main": "apps/testing/29-real-life-application/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/testing/29-real-life-application/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/testing/29-real-life-application/src/favicon.ico", + "apps/testing/29-real-life-application/src/assets" + ], + "styles": [ + "apps/testing/29-real-life-application/src/styles.scss", + "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "testing-real-life-application:build:production" + }, + "development": { + "buildTarget": "testing-real-life-application:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "testing-real-life-application:build" + } + }, + "test": { + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}", + "{projectRoot}/coverage" + ], + "options": { + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "coverage": true + } + } + }, + "component-test": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/testing/29-real-life-application/cypress.config.ts", + "testingType": "component", + "skipServe": true, + "devServerTarget": "testing-real-life-application:build" + } + } + } +} diff --git a/apps/testing/29-real-life-application/src/app/app.component.ts b/apps/testing/29-real-life-application/src/app/app.component.ts new file mode 100644 index 000000000..a4b00aaec --- /dev/null +++ b/apps/testing/29-real-life-application/src/app/app.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +@Component({ + selector: 'app-root', + imports: [RouterOutlet], + template: ` + + `, +}) +export class AppComponent {} diff --git a/apps/testing/todos-list/src/app/app.config.ts b/apps/testing/29-real-life-application/src/app/app.config.ts similarity index 100% rename from apps/testing/todos-list/src/app/app.config.ts rename to apps/testing/29-real-life-application/src/app/app.config.ts diff --git a/apps/testing/todos-list/src/app/app.route.ts b/apps/testing/29-real-life-application/src/app/app.route.ts similarity index 100% rename from apps/testing/todos-list/src/app/app.route.ts rename to apps/testing/29-real-life-application/src/app/app.route.ts diff --git a/apps/testing/todos-list/src/app/backend.service.ts b/apps/testing/29-real-life-application/src/app/backend.service.ts similarity index 100% rename from apps/testing/todos-list/src/app/backend.service.ts rename to apps/testing/29-real-life-application/src/app/backend.service.ts diff --git a/apps/testing/29-real-life-application/src/app/detail/detail.component.ts b/apps/testing/29-real-life-application/src/app/detail/detail.component.ts new file mode 100644 index 000000000..1afdfb31f --- /dev/null +++ b/apps/testing/29-real-life-application/src/app/detail/detail.component.ts @@ -0,0 +1,63 @@ +import { AsyncPipe, NgIf } from '@angular/common'; +import { Component, inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { RouterLink } from '@angular/router'; +import { LetDirective } from '@ngrx/component'; +import { provideComponentStore } from '@ngrx/component-store'; +import { DetailStore } from './detail.store'; + +@Component({ + selector: 'app-detail', + imports: [ + MatButtonModule, + RouterLink, + NgIf, + AsyncPipe, + MatProgressBarModule, + LetDirective, + ], + template: ` +

    Ticket Detail:

    + + +
    +
    + Ticket: + {{ ticket.id }} +
    +
    + Description: + {{ ticket.description }} +
    +
    + AssigneeId: + {{ ticket.assigneeId }} +
    +
    + Is done: + {{ ticket.completed }} +
    +
    +
    + + + `, + providers: [provideComponentStore(DetailStore)], + host: { + class: 'p-5 block', + }, +}) +export class DetailComponent { + vm$ = inject(DetailStore).vm$; +} diff --git a/apps/testing/todos-list/src/app/detail/detail.store.ts b/apps/testing/29-real-life-application/src/app/detail/detail.store.ts similarity index 100% rename from apps/testing/todos-list/src/app/detail/detail.store.ts rename to apps/testing/29-real-life-application/src/app/detail/detail.store.ts diff --git a/apps/testing/todos-list/src/app/list/list.component.spec.ts b/apps/testing/29-real-life-application/src/app/list/list.component.spec.ts similarity index 100% rename from apps/testing/todos-list/src/app/list/list.component.spec.ts rename to apps/testing/29-real-life-application/src/app/list/list.component.spec.ts diff --git a/apps/testing/29-real-life-application/src/app/list/list.component.ts b/apps/testing/29-real-life-application/src/app/list/list.component.ts new file mode 100644 index 000000000..64b8f6e63 --- /dev/null +++ b/apps/testing/29-real-life-application/src/app/list/list.component.ts @@ -0,0 +1,74 @@ +import { NgFor, NgIf } from '@angular/common'; +import { Component, OnInit, inject } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { LetDirective } from '@ngrx/component'; +import { provideComponentStore } from '@ngrx/component-store'; +import { TicketStore } from './ticket.store'; +import { AddComponent } from './ui/add.component'; +import { RowComponent } from './ui/row.component'; + +@Component({ + selector: 'app-list', + imports: [ + ReactiveFormsModule, + AddComponent, + RowComponent, + MatFormFieldModule, + MatProgressBarModule, + NgIf, + NgFor, + MatInputModule, + LetDirective, + ], + template: ` +

    Tickets

    + + + Search + + + + + + + +
      + +
    +
    + {{ vm.error }} +
    +
    + `, + providers: [provideComponentStore(TicketStore)], + host: { + class: 'p-5 block', + }, +}) +export class ListComponent implements OnInit { + ticketStore = inject(TicketStore); + readonly vm$ = this.ticketStore.vm$; + + search = new FormControl(); + + ngOnInit(): void { + this.ticketStore.search(this.search.valueChanges); + } +} diff --git a/apps/testing/todos-list/src/app/list/ticket.store.spec.ts b/apps/testing/29-real-life-application/src/app/list/ticket.store.spec.ts similarity index 100% rename from apps/testing/todos-list/src/app/list/ticket.store.spec.ts rename to apps/testing/29-real-life-application/src/app/list/ticket.store.spec.ts diff --git a/apps/testing/todos-list/src/app/list/ticket.store.ts b/apps/testing/29-real-life-application/src/app/list/ticket.store.ts similarity index 100% rename from apps/testing/todos-list/src/app/list/ticket.store.ts rename to apps/testing/29-real-life-application/src/app/list/ticket.store.ts diff --git a/apps/testing/todos-list/src/app/list/ui/add.component.ts b/apps/testing/29-real-life-application/src/app/list/ui/add.component.ts similarity index 98% rename from apps/testing/todos-list/src/app/list/ui/add.component.ts rename to apps/testing/29-real-life-application/src/app/list/ui/add.component.ts index b3e517125..c48e85a9a 100644 --- a/apps/testing/todos-list/src/app/list/ui/add.component.ts +++ b/apps/testing/29-real-life-application/src/app/list/ui/add.component.ts @@ -12,7 +12,6 @@ import { MatInputModule } from '@angular/material/input'; @Component({ selector: 'app-add', - standalone: true, imports: [ ReactiveFormsModule, MatFormFieldModule, diff --git a/apps/testing/todos-list/src/app/list/ui/row.component.spec.ts b/apps/testing/29-real-life-application/src/app/list/ui/row.component.spec.ts similarity index 100% rename from apps/testing/todos-list/src/app/list/ui/row.component.spec.ts rename to apps/testing/29-real-life-application/src/app/list/ui/row.component.spec.ts diff --git a/apps/testing/todos-list/src/app/list/ui/row.component.ts b/apps/testing/29-real-life-application/src/app/list/ui/row.component.ts similarity index 99% rename from apps/testing/todos-list/src/app/list/ui/row.component.ts rename to apps/testing/29-real-life-application/src/app/list/ui/row.component.ts index ca97d0d65..12c7d5367 100644 --- a/apps/testing/todos-list/src/app/list/ui/row.component.ts +++ b/apps/testing/29-real-life-application/src/app/list/ui/row.component.ts @@ -10,7 +10,6 @@ import { Ticket, TicketUser, User } from '../../backend.service'; @Component({ selector: 'app-row', - standalone: true, imports: [ RouterLink, ReactiveFormsModule, diff --git a/apps/testing/29-real-life-application/src/assets/.gitkeep b/apps/testing/29-real-life-application/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/testing/29-real-life-application/src/favicon.ico b/apps/testing/29-real-life-application/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/testing/29-real-life-application/src/favicon.ico differ diff --git a/apps/testing/29-real-life-application/src/index.html b/apps/testing/29-real-life-application/src/index.html new file mode 100644 index 000000000..91b0bf44a --- /dev/null +++ b/apps/testing/29-real-life-application/src/index.html @@ -0,0 +1,13 @@ + + + + + testing-real-life-application + + + + + + + + diff --git a/apps/testing/todos-list/src/main.ts b/apps/testing/29-real-life-application/src/main.ts similarity index 100% rename from apps/testing/todos-list/src/main.ts rename to apps/testing/29-real-life-application/src/main.ts diff --git a/apps/testing/todos-list/src/styles.scss b/apps/testing/29-real-life-application/src/styles.scss similarity index 100% rename from apps/testing/todos-list/src/styles.scss rename to apps/testing/29-real-life-application/src/styles.scss diff --git a/apps/testing/29-real-life-application/src/test-setup.ts b/apps/testing/29-real-life-application/src/test-setup.ts new file mode 100644 index 000000000..15de72a3c --- /dev/null +++ b/apps/testing/29-real-life-application/src/test-setup.ts @@ -0,0 +1,2 @@ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; diff --git a/apps/testing/29-real-life-application/tailwind.config.js b/apps/testing/29-real-life-application/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/testing/29-real-life-application/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/testing/table/tsconfig.app.json b/apps/testing/29-real-life-application/tsconfig.app.json similarity index 100% rename from apps/testing/table/tsconfig.app.json rename to apps/testing/29-real-life-application/tsconfig.app.json diff --git a/apps/testing/29-real-life-application/tsconfig.editor.json b/apps/testing/29-real-life-application/tsconfig.editor.json new file mode 100644 index 000000000..8ae117d96 --- /dev/null +++ b/apps/testing/29-real-life-application/tsconfig.editor.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "types": ["jest", "node"] + } +} diff --git a/apps/testing/29-real-life-application/tsconfig.json b/apps/testing/29-real-life-application/tsconfig.json new file mode 100644 index 000000000..c0f4e6dd3 --- /dev/null +++ b/apps/testing/29-real-life-application/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + }, + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./cypress/tsconfig .json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/testing/todos-list/tsconfig.spec.json b/apps/testing/29-real-life-application/tsconfig.spec.json similarity index 100% rename from apps/testing/todos-list/tsconfig.spec.json rename to apps/testing/29-real-life-application/tsconfig.spec.json diff --git a/apps/testing/checkbox/jest.config.ts b/apps/testing/checkbox/jest.config.ts deleted file mode 100644 index ea6f808cf..000000000 --- a/apps/testing/checkbox/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-checkbox', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - coverageDirectory: '../../../coverage/apps/testing/checkbox', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/checkbox/project.json b/apps/testing/checkbox/project.json deleted file mode 100644 index e030b7595..000000000 --- a/apps/testing/checkbox/project.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "testing-checkbox", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/testing/checkbox/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/checkbox", - "index": "apps/testing/checkbox/src/index.html", - "main": "apps/testing/checkbox/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/checkbox/tsconfig.app.json", - "assets": [ - "apps/testing/checkbox/src/favicon.ico", - "apps/testing/checkbox/src/assets" - ], - "styles": ["apps/testing/checkbox/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-checkbox:build:production" - }, - "development": { - "buildTarget": "testing-checkbox:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-checkbox:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/checkbox/**/*.ts", - "apps/testing/checkbox/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/checkbox/jest.config.ts" - } - } - } -} diff --git a/apps/testing/create-harness/README.md b/apps/testing/create-harness/README.md deleted file mode 100644 index 600f34055..000000000 --- a/apps/testing/create-harness/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Harness Creation - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve testing-create-harness -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/24-harness-creation/). diff --git a/apps/testing/create-harness/jest.config.ts b/apps/testing/create-harness/jest.config.ts deleted file mode 100644 index 195dab15a..000000000 --- a/apps/testing/create-harness/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-create-harness', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/create-harness/project.json b/apps/testing/create-harness/project.json deleted file mode 100644 index be2c2c91d..000000000 --- a/apps/testing/create-harness/project.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "testing-create-harness", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/testing/create-harness/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/create-harness", - "index": "apps/testing/create-harness/src/index.html", - "main": "apps/testing/create-harness/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/create-harness/tsconfig.app.json", - "assets": [ - "apps/testing/create-harness/src/favicon.ico", - "apps/testing/create-harness/src/assets" - ], - "styles": ["apps/testing/create-harness/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-create-harness:build:production" - }, - "development": { - "buildTarget": "testing-create-harness:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-create-harness:build" - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/create-harness/jest.config.ts" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/create-harness/**/*.ts", - "apps/testing/create-harness/**/*.html" - ] - } - } - } -} diff --git a/apps/testing/create-harness/src/app/app.component.ts b/apps/testing/create-harness/src/app/app.component.ts deleted file mode 100644 index 06c7eb9af..000000000 --- a/apps/testing/create-harness/src/app/app.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component, signal } from '@angular/core'; -import { SliderComponent } from './slider.component'; - -@Component({ - standalone: true, - imports: [SliderComponent], - selector: 'app-root', - template: ` -

    Slider 1: {{ slider1Value() }}

    - -

    Slider 2: {{ slider2Value() }}

    -

    Enabled only if Slider 1 > 20

    - - `, - styles: [''], -}) -export class AppComponent { - slider1Value = signal(10); - slider2Value = signal(0); -} diff --git a/apps/testing/create-harness/src/index.html b/apps/testing/create-harness/src/index.html deleted file mode 100644 index 03bd39e4f..000000000 --- a/apps/testing/create-harness/src/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - create-harness - - - - - - - - - diff --git a/apps/testing/create-harness/src/styles.scss b/apps/testing/create-harness/src/styles.scss deleted file mode 100644 index 94dbf8ff3..000000000 --- a/apps/testing/create-harness/src/styles.scss +++ /dev/null @@ -1,29 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ -@use '@angular/material' as mat; - -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* You can add global styles to this file, and also import other style files */ - -@include mat.core(); - -$theme-primary: mat.define-palette(mat.$indigo-palette); -$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); - -$theme-warn: mat.define-palette(mat.$red-palette); - -$theme: mat.define-light-theme( - ( - color: ( - primary: $theme-primary, - accent: $theme-accent, - warn: $theme-warn, - ), - typography: mat.define-typography-config(), - ) -); - -@include mat.dialog-theme($theme); -@include mat.all-component-themes($theme); diff --git a/apps/testing/harness/jest.config.ts b/apps/testing/harness/jest.config.ts deleted file mode 100644 index e342863b1..000000000 --- a/apps/testing/harness/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-harness', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/harness/project.json b/apps/testing/harness/project.json deleted file mode 100644 index b5e0ce057..000000000 --- a/apps/testing/harness/project.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "name": "testing-harness", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "prefix": "app", - "sourceRoot": "apps/testing/harness/src", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/harness", - "index": "apps/testing/harness/src/index.html", - "main": "apps/testing/harness/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/harness/tsconfig.app.json", - "assets": [ - "apps/testing/harness/src/favicon.ico", - "apps/testing/harness/src/assets" - ], - "styles": ["apps/testing/harness/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-harness:build:production" - }, - "development": { - "buildTarget": "testing-harness:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-harness:build" - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/harness/jest.config.ts" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/harness/**/*.ts", - "apps/testing/harness/**/*.html" - ] - } - } - } -} diff --git a/apps/testing/harness/src/app/app.component.ts b/apps/testing/harness/src/app/app.component.ts deleted file mode 100644 index 1f89505d8..000000000 --- a/apps/testing/harness/src/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; -import { ChildComponent } from './child.component'; - -@Component({ - standalone: true, - imports: [ChildComponent], - selector: 'app-root', - template: ` - - `, - styles: [''], -}) -export class AppComponent {} diff --git a/apps/testing/harness/src/app/child.component.ts b/apps/testing/harness/src/app/child.component.ts deleted file mode 100644 index cc9a03e74..000000000 --- a/apps/testing/harness/src/app/child.component.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatCardModule } from '@angular/material/card'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatSliderModule } from '@angular/material/slider'; - -@Component({ - selector: 'app-child', - template: ` - - -

    Slider configuration

    - -
    - - Value - - - - Min value - - - - Max value - - - - Step size - - -
    - -
    - Show ticks -
    - -
    - Show thumb label -
    - -
    - Disabled -
    -
    -
    - - - -
    - - - - - -
    -
    -
    - `, - styles: [ - ` - .mat-mdc-slider { - max-width: 300px; - width: 100%; - } - - .mat-mdc-card + .mat-mdc-card { - margin-top: 8px; - } - `, - ], - standalone: true, - imports: [ - MatCardModule, - MatFormFieldModule, - MatInputModule, - FormsModule, - MatCheckboxModule, - MatSliderModule, - MatIconModule, - ], -}) -export class ChildComponent { - disabled = false; - max = 100; - min = 0; - showTicks = false; - step = 1; - thumbLabel = false; - value = 0; - - back() { - if (this.value - this.step >= this.min) { - this.value -= this.step; - } - } - - forward() { - if (this.value + this.step <= this.max) { - this.value += this.step; - } - } -} diff --git a/apps/testing/harness/src/index.html b/apps/testing/harness/src/index.html deleted file mode 100644 index a4122017e..000000000 --- a/apps/testing/harness/src/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - harness - - - - - - - - - diff --git a/apps/testing/harness/src/styles.scss b/apps/testing/harness/src/styles.scss deleted file mode 100644 index c9c067e5f..000000000 --- a/apps/testing/harness/src/styles.scss +++ /dev/null @@ -1,28 +0,0 @@ -@use '@angular/material' as mat; - -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* You can add global styles to this file, and also import other style files */ - -@include mat.core(); - -$theme-primary: mat.define-palette(mat.$indigo-palette); -$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); - -$theme-warn: mat.define-palette(mat.$red-palette); - -$theme: mat.define-light-theme( - ( - color: ( - primary: $theme-primary, - accent: $theme-accent, - warn: $theme-warn, - ), - typography: mat.define-typography-config(), - ) -); - -@include mat.dialog-theme($theme); -@include mat.all-component-themes($theme); diff --git a/apps/testing/input-output/cypress/support/commands.ts b/apps/testing/input-output/cypress/support/commands.ts deleted file mode 100644 index e6c897603..000000000 --- a/apps/testing/input-output/cypress/support/commands.ts +++ /dev/null @@ -1,42 +0,0 @@ -/// -import { mount } from 'cypress/angular'; - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - mount: typeof mount; - } - } -} - -Cypress.Commands.add('mount', mount); - -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/testing/input-output/jest.config.ts b/apps/testing/input-output/jest.config.ts deleted file mode 100644 index 7d2312104..000000000 --- a/apps/testing/input-output/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-input-output', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/input-output/project.json b/apps/testing/input-output/project.json deleted file mode 100644 index ddfff165f..000000000 --- a/apps/testing/input-output/project.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "testing-input-output", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/testing/input-output/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/input-output", - "index": "apps/testing/input-output/src/index.html", - "main": "apps/testing/input-output/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/input-output/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/testing/input-output/src/favicon.ico", - "apps/testing/input-output/src/assets" - ], - "styles": ["apps/testing/input-output/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-input-output:build:production" - }, - "development": { - "buildTarget": "testing-input-output:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-input-output:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/input-output/**/*.ts", - "apps/testing/input-output/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/input-output/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/testing/input-output/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "testing-input-output:build" - } - } - }, - "tags": [] -} diff --git a/apps/testing/input-output/src/app/app.component.ts b/apps/testing/input-output/src/app/app.component.ts deleted file mode 100644 index 6a6392a4b..000000000 --- a/apps/testing/input-output/src/app/app.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from '@angular/core'; -import { CounterComponent } from './counter.component'; - -@Component({ - standalone: true, - imports: [CounterComponent], - selector: 'app-root', - template: ` - - `, -}) -export class AppComponent { - log(counter: number) { - console.log('output log', counter); - } -} diff --git a/apps/testing/input-output/src/app/counter.component.ts b/apps/testing/input-output/src/app/counter.component.ts deleted file mode 100644 index 1ca95430d..000000000 --- a/apps/testing/input-output/src/app/counter.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { AsyncPipe } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - Output, -} from '@angular/core'; -import { LetDirective } from '@ngrx/component'; -import { ComponentStore } from '@ngrx/component-store'; - -@Component({ - selector: 'app-counter', - standalone: true, - imports: [AsyncPipe, LetDirective], - template: ` - -

    Counter: {{ counter }}

    - - - -
    - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CounterComponent extends ComponentStore<{ counter: number }> { - @Input() set initialValue(initialValue: number) { - this.patchState({ counter: initialValue }); - } - - @Output() send = new EventEmitter(); - - readonly counter$ = this.select((state) => state.counter); - - readonly increment = this.updater((state) => ({ - counter: state.counter + 1, - })); - readonly decrement = this.updater((state) => ({ - counter: state.counter - 1, - })); - - constructor() { - super({ counter: 0 }); - } -} diff --git a/apps/testing/input-output/src/index.html b/apps/testing/input-output/src/index.html deleted file mode 100644 index bb1c5edf3..000000000 --- a/apps/testing/input-output/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - TestingInputOutput - - - - - - - - diff --git a/apps/testing/modal/cypress/support/commands.ts b/apps/testing/modal/cypress/support/commands.ts deleted file mode 100644 index e6c897603..000000000 --- a/apps/testing/modal/cypress/support/commands.ts +++ /dev/null @@ -1,42 +0,0 @@ -/// -import { mount } from 'cypress/angular'; - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - mount: typeof mount; - } - } -} - -Cypress.Commands.add('mount', mount); - -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/testing/modal/jest.config.ts b/apps/testing/modal/jest.config.ts deleted file mode 100644 index 137c0c8c7..000000000 --- a/apps/testing/modal/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-modal', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/modal/project.json b/apps/testing/modal/project.json deleted file mode 100644 index 6cacc2e08..000000000 --- a/apps/testing/modal/project.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "testing-modal", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/testing/modal/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/modal", - "index": "apps/testing/modal/src/index.html", - "main": "apps/testing/modal/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/modal/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/testing/modal/src/favicon.ico", - "apps/testing/modal/src/assets" - ], - "styles": [ - "apps/testing/modal/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-modal:build:production" - }, - "development": { - "buildTarget": "testing-modal:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-modal:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/modal/**/*.ts", - "apps/testing/modal/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/modal/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/testing/modal/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "testing-modal:build" - } - } - }, - "tags": [] -} diff --git a/apps/testing/modal/src/app/app.component.ts b/apps/testing/modal/src/app/app.component.ts deleted file mode 100644 index afb4b291f..000000000 --- a/apps/testing/modal/src/app/app.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { AsyncPipe } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDialog, MatDialogModule } from '@angular/material/dialog'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { BehaviorSubject } from 'rxjs'; -import { ErrorDialog } from './error.dialog'; -import { ProfilConfirmationDialog } from './profil-confirmation.dialog'; -@Component({ - standalone: true, - imports: [ - ReactiveFormsModule, - MatDialogModule, - MatFormFieldModule, - MatInputModule, - MatButtonModule, - AsyncPipe, - ], - selector: 'app-root', - host: { - class: 'p-4 block flex gap-4 items-center', - }, - template: ` - - Name - - - - -
    {{ result$ | async }}
    - `, -}) -export class AppComponent { - private modal = inject(MatDialog); - private result = new BehaviorSubject(''); - result$ = this.result.asObservable(); - - name = new FormControl('', { nonNullable: true }); - - confirm() { - if (!this.name.value) { - this.modal.open(ErrorDialog); - return; - } - - this.modal - .open(ProfilConfirmationDialog, { - data: { - name: this.name.value, - }, - }) - .afterClosed() - .subscribe((result) => - this.result.next( - result ? 'Name has been submitted' : 'Name is invalid !!', - ), - ); - } -} diff --git a/apps/testing/modal/src/index.html b/apps/testing/modal/src/index.html deleted file mode 100644 index f63ff6890..000000000 --- a/apps/testing/modal/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - TestingModal - - - - - - - - diff --git a/apps/testing/nested/README.md b/apps/testing/nested/README.md deleted file mode 100644 index 8e1876a73..000000000 --- a/apps/testing/nested/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Nested Components - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve testing-nested -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/18-nested-comp/). diff --git a/apps/testing/nested/cypress/support/commands.ts b/apps/testing/nested/cypress/support/commands.ts deleted file mode 100644 index e6c897603..000000000 --- a/apps/testing/nested/cypress/support/commands.ts +++ /dev/null @@ -1,42 +0,0 @@ -/// -import { mount } from 'cypress/angular'; - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - mount: typeof mount; - } - } -} - -Cypress.Commands.add('mount', mount); - -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/testing/nested/jest.config.ts b/apps/testing/nested/jest.config.ts deleted file mode 100644 index b6643db38..000000000 --- a/apps/testing/nested/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-nested', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/nested/project.json b/apps/testing/nested/project.json deleted file mode 100644 index 379bbca01..000000000 --- a/apps/testing/nested/project.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "testing-nested", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/testing/nested/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/nested", - "index": "apps/testing/nested/src/index.html", - "main": "apps/testing/nested/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/nested/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/testing/nested/src/favicon.ico", - "apps/testing/nested/src/assets" - ], - "styles": ["apps/testing/nested/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-nested:build:production" - }, - "development": { - "buildTarget": "testing-nested:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-nested:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/nested/**/*.ts", - "apps/testing/nested/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/nested/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/testing/nested/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "testing-nested:build" - } - } - }, - "tags": [] -} diff --git a/apps/testing/nested/src/app/app.component.ts b/apps/testing/nested/src/app/app.component.ts deleted file mode 100644 index 098836b6f..000000000 --- a/apps/testing/nested/src/app/app.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; -import { ChildComponent } from './child.component'; - -@Component({ - standalone: true, - imports: [ChildComponent], - selector: 'app-root', - template: ` - - `, -}) -export class AppComponent {} diff --git a/apps/testing/nested/src/app/child.component.ts b/apps/testing/nested/src/app/child.component.ts deleted file mode 100644 index bcee84ecd..000000000 --- a/apps/testing/nested/src/app/child.component.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { NgIf } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - Output, - inject, -} from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { HttpService } from './http.service'; - -@Component({ - selector: 'app-input', - standalone: true, - imports: [ReactiveFormsModule], - template: ` - - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class InputComponent { - title = new FormControl('', { nonNullable: true }); -} - -@Component({ - selector: 'result', - standalone: true, - template: ` -

    Title is {{ title }}

    - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ResultComponent { - @Input() title = ''; -} - -@Component({ - selector: 'app-button', - standalone: true, - template: ` - - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ButtonComponent { - @Output() validate = new EventEmitter(); -} - -@Component({ - selector: 'app-error', - standalone: true, - template: ` -

    Title is required !!!

    - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ErrorComponent { - @Output() validate = new EventEmitter(); -} - -@Component({ - selector: 'app-child', - standalone: true, - imports: [ - ResultComponent, - ButtonComponent, - InputComponent, - ErrorComponent, - NgIf, - ], - template: ` - - - - - `, - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ChildComponent { - http = inject(HttpService); - - showError = false; - - submit(title: string) { - this.showError = false; - if (title === '') { - this.showError = true; - return; - } - - this.http.sendTitle(title); - } -} diff --git a/apps/testing/nested/src/index.html b/apps/testing/nested/src/index.html deleted file mode 100644 index 620e0cd2d..000000000 --- a/apps/testing/nested/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - TestingNested - - - - - - - - diff --git a/apps/testing/router-outlet/README.md b/apps/testing/router-outlet/README.md deleted file mode 100644 index 774915930..000000000 --- a/apps/testing/router-outlet/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Router - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve testing-router-outlet -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/17-router/). diff --git a/apps/testing/router-outlet/cypress/support/commands.ts b/apps/testing/router-outlet/cypress/support/commands.ts deleted file mode 100644 index e6c897603..000000000 --- a/apps/testing/router-outlet/cypress/support/commands.ts +++ /dev/null @@ -1,42 +0,0 @@ -/// -import { mount } from 'cypress/angular'; - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - mount: typeof mount; - } - } -} - -Cypress.Commands.add('mount', mount); - -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/testing/router-outlet/jest.config.ts b/apps/testing/router-outlet/jest.config.ts deleted file mode 100644 index f8f0ad165..000000000 --- a/apps/testing/router-outlet/jest.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-router-outlet', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - globals: {}, - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/router-outlet/project.json b/apps/testing/router-outlet/project.json deleted file mode 100644 index 921ec3571..000000000 --- a/apps/testing/router-outlet/project.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "testing-router-outlet", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/testing/router-outlet/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/router-outlet", - "index": "apps/testing/router-outlet/src/index.html", - "main": "apps/testing/router-outlet/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/router-outlet/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/testing/router-outlet/src/favicon.ico", - "apps/testing/router-outlet/src/assets" - ], - "styles": ["apps/testing/router-outlet/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-router-outlet:build:production" - }, - "development": { - "buildTarget": "testing-router-outlet:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-router-outlet:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/router-outlet/**/*.ts", - "apps/testing/router-outlet/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/router-outlet/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/testing/router-outlet/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "testing-router-outlet:build" - } - } - }, - "tags": [] -} diff --git a/apps/testing/router-outlet/src/app/app.component.ts b/apps/testing/router-outlet/src/app/app.component.ts deleted file mode 100644 index 3b420a867..000000000 --- a/apps/testing/router-outlet/src/app/app.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterLink, RouterOutlet } from '@angular/router'; - -@Component({ - standalone: true, - imports: [RouterOutlet, RouterLink], - selector: 'app-root', - styles: [ - ` - h1 { - margin-bottom: 0; - } - nav a { - padding: 1rem; - text-decoration: none; - margin-top: 10px; - display: inline-block; - background-color: #e8e8e8; - color: #3d3d3d; - border-radius: 4px; - margin-bottom: 10px; - } - nav a:hover { - color: white; - background-color: #42545c; - } - nav a.active { - background-color: black; - } - `, - ], - template: ` -

    Library

    - - - - - `, -}) -export class AppComponent {} diff --git a/apps/testing/router-outlet/src/index.html b/apps/testing/router-outlet/src/index.html deleted file mode 100644 index b7065804e..000000000 --- a/apps/testing/router-outlet/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - RouterTesting - - - - - - - - diff --git a/apps/testing/router-outlet/tsconfig.json b/apps/testing/router-outlet/tsconfig.json deleted file mode 100644 index 3879b94cd..000000000 --- a/apps/testing/router-outlet/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "useDefineForClassFields": false, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.editor.json" - }, - { - "path": "./cypress/tsconfig.json" - } - ], - "extends": "../../../tsconfig.base.json", - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/testing/table/README.md b/apps/testing/table/README.md deleted file mode 100644 index ff3b4b560..000000000 --- a/apps/testing/table/README.md +++ /dev/null @@ -1,38 +0,0 @@ -

    Table testing

    - -> author: thomas-laforge - -## Statement: - -NOT IMPLEMENTED YET - - - -### Submitting your work - -1. Fork the project -2. clone it -3. npm ci -4. `npx nx serve testing-table` to play with the application -5. `npx nx test testing-table` to test your application with Testing Library -6. `npx nx component-test testing-table --watch` to test your application with Cypress -7. _...work on it_ -8. Commit your work -9. Submit a PR with a title beginning with **Answer:22** that I will review and other dev can review. - -nested testing -nested testing solution author - - - -_You can ask any question on_ twitter diff --git a/apps/testing/table/cypress/support/commands.ts b/apps/testing/table/cypress/support/commands.ts deleted file mode 100644 index e6c897603..000000000 --- a/apps/testing/table/cypress/support/commands.ts +++ /dev/null @@ -1,42 +0,0 @@ -/// -import { mount } from 'cypress/angular'; - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - mount: typeof mount; - } - } -} - -Cypress.Commands.add('mount', mount); - -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/testing/table/cypress/support/component-index.html b/apps/testing/table/cypress/support/component-index.html deleted file mode 100644 index c0a4681dc..000000000 --- a/apps/testing/table/cypress/support/component-index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - testing-table Components App - - -
    - - diff --git a/apps/testing/table/jest.config.ts b/apps/testing/table/jest.config.ts deleted file mode 100644 index 98474ecca..000000000 --- a/apps/testing/table/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-table', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/table/project.json b/apps/testing/table/project.json deleted file mode 100644 index f2a0ea9cb..000000000 --- a/apps/testing/table/project.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "name": "testing-table", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/testing/table/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/table", - "index": "apps/testing/table/src/index.html", - "main": "apps/testing/table/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/table/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/testing/table/src/favicon.ico", - "apps/testing/table/src/assets" - ], - "styles": ["apps/testing/table/src/styles.scss"], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-table:build:production" - }, - "development": { - "buildTarget": "testing-table:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-table:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/table/**/*.ts", - "apps/testing/table/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/table/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/testing/table/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "testing-table:build" - } - } - }, - "tags": [] -} diff --git a/apps/testing/table/src/app/app.component.ts b/apps/testing/table/src/app/app.component.ts deleted file mode 100644 index 236bc50a6..000000000 --- a/apps/testing/table/src/app/app.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; -import { TableComponent } from './table.component'; - -@Component({ - standalone: true, - imports: [TableComponent], - selector: 'app-root', - template: ` - - `, -}) -export class AppComponent {} diff --git a/apps/testing/table/src/app/table.component.spec.ts b/apps/testing/table/src/app/table.component.spec.ts deleted file mode 100644 index db4015d9f..000000000 --- a/apps/testing/table/src/app/table.component.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; -import { MatTableHarness } from '@angular/material/table/testing'; -import { render } from '@testing-library/angular'; -import userEvent from '@testing-library/user-event'; -import { TableComponent } from './table.component'; - -describe('AppComponent', () => { - // let loader: HarnessLoader; - // let fixture: ComponentFixture; - // let loader: HarnessLoader; - - // beforeEach(async () => { - // const view = await render(TableComponent); - // fixture = view.fixture; - // loader = TestbedHarnessEnvironment.loader(fixture); - // }); - it('error modal is displayed if you click on "Confirm" without inputing a name', async () => { - userEvent.setup(); - const { fixture } = await render(TableComponent); - const loader = TestbedHarnessEnvironment.loader(fixture); - - const tables = await loader.getAllHarnesses(MatTableHarness); - expect(tables.length).toBe(1); - - // const confirmButton = await screen.findByRole('button', { - // name: /confirm/i, - // }); - // await userEvent.click(confirmButton); - - // const dialogControl = await screen.findByRole('dialog'); - // expect(dialogControl).toBeInTheDocument(); - // const errorTitle = await screen.findByRole('heading', { - // name: /error/i, - // }); - // expect(errorTitle).toBeInTheDocument(); - - // const okButton = await screen.findByRole('button', { - // name: /ok/i, - // }); - // await userEvent.click(okButton); - }); - - // subscription('error message is shown if you click "Cancel" in the confirmation modal after submitting a name', async () => { - // userEvent.setup(); - // await render(AppComponent); - - // const inputControl = await screen.getByRole('textbox'); - // await userEvent.type(inputControl, 'toto'); - - // const confirmButton = await screen.findByRole('button', { - // name: /confirm/i, - // }); - // await userEvent.click(confirmButton); - - // const dialogControl = await screen.findByRole('dialog'); - // expect(dialogControl).toBeInTheDocument(); - // const profilTitle = await screen.findByRole('heading', { - // name: /profil/i, - // }); - // expect(profilTitle).toBeInTheDocument(); - - // const cancelButton = await screen.findByRole('button', { - // name: /cancel/i, - // }); - // await userEvent.click(cancelButton); - - // const errorText = await screen.getByText('Name is invalid !!'); - // expect(errorText).toBeInTheDocument(); - // }); - - // subscription('confirm message is shown if you click "Confirm" in the confirmation modal after submitting a name', async () => { - // userEvent.setup(); - // await render(AppComponent); - - // const inputControl = await screen.getByRole('textbox'); - // await userEvent.type(inputControl, 'toto'); - - // const confirmButton = await screen.findByRole('button', { - // name: /confirm/i, - // }); - // await userEvent.click(confirmButton); - - // const dialogControl = await screen.findByRole('dialog'); - // expect(dialogControl).toBeInTheDocument(); - // const profilTitle = await screen.findByRole('heading', { - // name: /profil/i, - // }); - // expect(profilTitle).toBeInTheDocument(); - - // const confirmDialogButton = await screen.findByRole('button', { - // name: /confirm/i, - // }); - // await userEvent.click(confirmDialogButton); - - // const confirmText = await screen.getByText('Name has been submitted'); - // expect(confirmText).toBeInTheDocument(); - // }); -}); diff --git a/apps/testing/table/src/app/table.component.ts b/apps/testing/table/src/app/table.component.ts deleted file mode 100644 index 74df216e6..000000000 --- a/apps/testing/table/src/app/table.component.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { FakeBackendService } from '@angular-challenges/testing-table/backend'; -import { AsyncPipe, DatePipe, NgIf } from '@angular/common'; -import { AfterViewInit, Component, ViewChild, inject } from '@angular/core'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatSort, MatSortModule, SortDirection } from '@angular/material/sort'; -import { MatTableModule } from '@angular/material/table'; -import { User } from '@ngneat/falso'; -import { LetDirective } from '@ngrx/component'; -import { ComponentStore, tapResponse } from '@ngrx/component-store'; -import { map, pipe, startWith, switchMap, tap } from 'rxjs'; - -interface TableState { - loading: boolean; - error?: string; - users: User[]; -} - -@Component({ - selector: 'app-table', - standalone: true, - imports: [ - MatFormFieldModule, - MatInputModule, - MatTableModule, - MatSortModule, - MatPaginatorModule, - MatProgressSpinnerModule, - LetDirective, - NgIf, - AsyncPipe, - DatePipe, - ], - template: ` -
    -
    - - -
    - -
    - - - - - - - - - - - - - - - - - - - - - - - - -
    FirstName{{ row.firstName }}LastName{{ row.lastName }}Email{{ row.email }}
    -
    - - -
    - `, -}) -export class TableComponent - extends ComponentStore - implements AfterViewInit -{ - readonly displayedColumns = ['firstName', 'lastName', 'email']; - - private api = inject(FakeBackendService); - - readonly issues$ = this.select((s) => s.users).pipe( - tap((t) => console.log('UserNEw ', t)), - ); - readonly loading$ = this.select((s) => s.loading); - readonly error$ = this.select((s) => s.error); - readonly resultsLength$ = this.select((s) => 100); - - // resultsLength = 0; - // isLoadingResults = true; - // isRateLimitReached = false; - - @ViewChild(MatPaginator) paginator!: MatPaginator; - @ViewChild(MatSort) sort!: MatSort; - - constructor() { - super({ loading: false, users: [] }); - } - - readonly loadData = this.effect<{ - sortActive: keyof User; - sortDir: SortDirection; - pageIndex: number; - }>( - pipe( - tap((t) => console.log('cocou', t)), - tap(() => this.patchState({ loading: true, users: [] })), - switchMap(({ sortActive, sortDir, pageIndex }) => - this.api.getUsers(sortActive, sortDir, pageIndex).pipe( - tap((t) => console.log('user', t)), - tapResponse( - (data) => this.patchState({ users: data, loading: false }), - (err) => this.patchState({ error: err as string, loading: false }), - ), - ), - ), - ), - ); - - ngAfterViewInit(): void { - // due to ExpressionChangedAfterItHasBeenCheckedError - console.log('cocuo', this.sort, this.paginator); - this.loadData( - this.select({ - sortActive: this.sort.sortChange.pipe( - map((s) => s.active as keyof User), - ), - sortDir: this.sort.sortChange.pipe(map((s) => s.direction)), - pageIndex: this.paginator.page.pipe(map((p) => p.pageIndex)), - }).pipe( - startWith({ - sortActive: this.sort.active as keyof User, - sortDir: this.sort.direction, - pageIndex: 1, - }), - ), - ); - } - - // applyFilter(event: Event) { - // const filterValue = (event.target as HTMLInputElement).value; - // this.dataSource.filter = filterValue.trim().toLowerCase(); - - // if (this.dataSource.paginator) { - // this.dataSource.paginator.firstPage(); - // } - // } -} diff --git a/apps/testing/table/src/index.html b/apps/testing/table/src/index.html deleted file mode 100644 index 11da4b083..000000000 --- a/apps/testing/table/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - TestingTable - - - - - - - - diff --git a/apps/testing/table/src/main.ts b/apps/testing/table/src/main.ts deleted file mode 100644 index b0ca80b94..000000000 --- a/apps/testing/table/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { provideHttpClient } from '@angular/common/http'; -import { bootstrapApplication } from '@angular/platform-browser'; -import { provideAnimations } from '@angular/platform-browser/animations'; -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent, { - providers: [provideAnimations(), provideHttpClient()], -}).catch((err) => console.error(err)); diff --git a/apps/testing/table/src/styles.scss b/apps/testing/table/src/styles.scss deleted file mode 100644 index ce5105b51..000000000 --- a/apps/testing/table/src/styles.scss +++ /dev/null @@ -1,31 +0,0 @@ -@use '@angular/material' as mat; - -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* You can add global styles to this file, and also import other style files */ - -@include mat.core(); - -$theme-primary: mat.define-palette(mat.$indigo-palette); -$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400); - -$theme-warn: mat.define-palette(mat.$red-palette); - -$theme: mat.define-light-theme( - ( - color: ( - primary: $theme-primary, - accent: $theme-accent, - warn: $theme-warn, - ), - typography: mat.define-typography-config(), - ) -); - -@include mat.core-theme($theme); -@include mat.all-component-themes($theme); -// @include mat.form-field-theme($theme); -// @include mat.input-theme($theme); -// @include mat.paginator-theme($theme); diff --git a/apps/testing/table/tsconfig.json b/apps/testing/table/tsconfig.json deleted file mode 100644 index 3879b94cd..000000000 --- a/apps/testing/table/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "useDefineForClassFields": false, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.editor.json" - }, - { - "path": "./cypress/tsconfig.json" - } - ], - "extends": "../../../tsconfig.base.json", - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/testing/table/tsconfig.spec.json b/apps/testing/table/tsconfig.spec.json deleted file mode 100644 index a578b4624..000000000 --- a/apps/testing/table/tsconfig.spec.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node", "@testing-library/jest-dom"], - "target": "ES2016" - }, - "files": ["src/test-setup.ts"], - "include": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/apps/testing/todos-list/README.md b/apps/testing/todos-list/README.md deleted file mode 100644 index 37a8e93be..000000000 --- a/apps/testing/todos-list/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Real-life Application - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve testing-todos-list -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/testing/29-real-application/). diff --git a/apps/testing/todos-list/cypress.config.ts b/apps/testing/todos-list/cypress.config.ts deleted file mode 100644 index 1abef9c0c..000000000 --- a/apps/testing/todos-list/cypress.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing'; -import { defineConfig } from 'cypress'; - -export default defineConfig({ - component: nxComponentTestingPreset(__filename), -}); diff --git a/apps/testing/todos-list/cypress/fixtures/example.json b/apps/testing/todos-list/cypress/fixtures/example.json deleted file mode 100644 index 02e425437..000000000 --- a/apps/testing/todos-list/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/apps/testing/todos-list/cypress/support/commands.ts b/apps/testing/todos-list/cypress/support/commands.ts deleted file mode 100644 index e6c897603..000000000 --- a/apps/testing/todos-list/cypress/support/commands.ts +++ /dev/null @@ -1,42 +0,0 @@ -/// -import { mount } from 'cypress/angular'; - -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - mount: typeof mount; - } - } -} - -Cypress.Commands.add('mount', mount); - -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/testing/todos-list/cypress/support/component.ts b/apps/testing/todos-list/cypress/support/component.ts deleted file mode 100644 index e7c3e3cbc..000000000 --- a/apps/testing/todos-list/cypress/support/component.ts +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example support/component.ts is processed and -// loaded automatically before your subscription files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.ts using ES2015 syntax: -import './commands'; diff --git a/apps/testing/todos-list/cypress/tsconfig.json b/apps/testing/todos-list/cypress/tsconfig.json deleted file mode 100644 index 918d96378..000000000 --- a/apps/testing/todos-list/cypress/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["cypress", "node"], - "sourceMap": false - }, - "include": [ - "support/**/*.ts", - "../cypress.config.ts", - "../**/*.cy.ts", - "../**/*.cy.tsx", - "../**/*.cy.js", - "../**/*.cy.jsx", - "../**/*.d.ts" - ] -} diff --git a/apps/testing/todos-list/jest.config.ts b/apps/testing/todos-list/jest.config.ts deleted file mode 100644 index 3b92b5677..000000000 --- a/apps/testing/todos-list/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'testing-todos-list', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/subscription-setup.ts'], - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/testing/todos-list/project.json b/apps/testing/todos-list/project.json deleted file mode 100644 index 9d5c670b5..000000000 --- a/apps/testing/todos-list/project.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "testing-todos-list", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/testing/todos-list/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/testing/todos-list", - "index": "apps/testing/todos-list/src/index.html", - "main": "apps/testing/todos-list/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/testing/todos-list/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/testing/todos-list/src/favicon.ico", - "apps/testing/todos-list/src/assets" - ], - "styles": [ - "apps/testing/todos-list/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "testing-todos-list:build:production" - }, - "development": { - "buildTarget": "testing-todos-list:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "testing-todos-list:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/testing/todos-list/**/*.ts", - "apps/testing/todos-list/**/*.html" - ] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/testing/todos-list/jest.config.ts" - } - }, - "component-test": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/testing/todos-list/cypress.config.ts", - "testingType": "component", - "skipServe": true, - "devServerTarget": "testing-todos-list:build" - } - } - }, - "tags": [] -} diff --git a/apps/testing/todos-list/src/app/app.component.ts b/apps/testing/todos-list/src/app/app.component.ts deleted file mode 100644 index 6b61097d4..000000000 --- a/apps/testing/todos-list/src/app/app.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from '@angular/core'; -import { RouterOutlet } from '@angular/router'; - -@Component({ - selector: 'app-root', - standalone: true, - imports: [RouterOutlet], - template: ` - - `, -}) -export class AppComponent {} diff --git a/apps/testing/todos-list/src/app/detail/detail.component.ts b/apps/testing/todos-list/src/app/detail/detail.component.ts deleted file mode 100644 index 7e5eed829..000000000 --- a/apps/testing/todos-list/src/app/detail/detail.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { AsyncPipe, NgIf } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { RouterLink } from '@angular/router'; -import { LetDirective } from '@ngrx/component'; -import { provideComponentStore } from '@ngrx/component-store'; -import { DetailStore } from './detail.store'; - -@Component({ - selector: 'app-detail', - standalone: true, - imports: [ - MatButtonModule, - RouterLink, - NgIf, - AsyncPipe, - MatProgressBarModule, - LetDirective, - ], - template: ` -

    Ticket Detail:

    - - -
    -
    - Ticket: - {{ ticket.id }} -
    -
    - Description: - {{ ticket.description }} -
    -
    - AssigneeId: - {{ ticket.assigneeId }} -
    -
    - Is done: - {{ ticket.completed }} -
    -
    -
    - - - `, - providers: [provideComponentStore(DetailStore)], - host: { - class: 'p-5 block', - }, -}) -export class DetailComponent { - vm$ = inject(DetailStore).vm$; -} diff --git a/apps/testing/todos-list/src/app/list/list.component.ts b/apps/testing/todos-list/src/app/list/list.component.ts deleted file mode 100644 index 8942f7cc6..000000000 --- a/apps/testing/todos-list/src/app/list/list.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { NgFor, NgIf } from '@angular/common'; -import { Component, OnInit, inject } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatInputModule } from '@angular/material/input'; -import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { LetDirective } from '@ngrx/component'; -import { provideComponentStore } from '@ngrx/component-store'; -import { TicketStore } from './ticket.store'; -import { AddComponent } from './ui/add.component'; -import { RowComponent } from './ui/row.component'; - -@Component({ - selector: 'app-list', - standalone: true, - imports: [ - ReactiveFormsModule, - AddComponent, - RowComponent, - MatFormFieldModule, - MatProgressBarModule, - NgIf, - NgFor, - MatInputModule, - LetDirective, - ], - template: ` -

    Tickets

    - - - Search - - - - - - - -
      - -
    -
    - {{ vm.error }} -
    -
    - `, - providers: [provideComponentStore(TicketStore)], - host: { - class: 'p-5 block', - }, -}) -export class ListComponent implements OnInit { - ticketStore = inject(TicketStore); - readonly vm$ = this.ticketStore.vm$; - - search = new FormControl(); - - ngOnInit(): void { - this.ticketStore.search(this.search.valueChanges); - } -} diff --git a/apps/testing/todos-list/src/index.html b/apps/testing/todos-list/src/index.html deleted file mode 100644 index 8321d8a0e..000000000 --- a/apps/testing/todos-list/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - TestingTodosList - - - - - - - - diff --git a/apps/testing/todos-list/tsconfig.app.json b/apps/testing/todos-list/tsconfig.app.json deleted file mode 100644 index 01a02ed77..000000000 --- a/apps/testing/todos-list/tsconfig.app.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "types": [] - }, - "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"], - "exclude": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.spec.ts", - "cypress/**/*", - "cypress.config.ts", - "**/*.cy.ts", - "**/*.cy.js", - "**/*.cy.tsx", - "**/*.cy.jsx" - ] -} diff --git a/apps/testing/todos-list/tsconfig.json b/apps/testing/todos-list/tsconfig.json deleted file mode 100644 index 3879b94cd..000000000 --- a/apps/testing/todos-list/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "useDefineForClassFields": false, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.editor.json" - }, - { - "path": "./cypress/tsconfig.json" - } - ], - "extends": "../../../tsconfig.base.json", - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/testing/todos-list/.eslintrc.json b/apps/typescript/15-function-overload/.eslintrc.json similarity index 100% rename from apps/testing/todos-list/.eslintrc.json rename to apps/typescript/15-function-overload/.eslintrc.json diff --git a/apps/typescript/15-function-overload/README.md b/apps/typescript/15-function-overload/README.md new file mode 100644 index 000000000..96ce65e9d --- /dev/null +++ b/apps/typescript/15-function-overload/README.md @@ -0,0 +1,13 @@ +# Function Overload + +> author: thomas-laforge + +### Run Application + +```bash +npx nx serve typescript-function-overload` +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/typescript/15-typescript-function-overload-fn/). diff --git a/apps/typescript/15-function-overload/project.json b/apps/typescript/15-function-overload/project.json new file mode 100644 index 000000000..95e554c3d --- /dev/null +++ b/apps/typescript/15-function-overload/project.json @@ -0,0 +1,72 @@ +{ + "name": "typescript-function-overload", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/typescript/15-function-overload/src", + "prefix": "app", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/typescript/15-function-overload", + "index": "apps/typescript/15-function-overload/src/index.html", + "main": "apps/typescript/15-function-overload/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/typescript/15-function-overload/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/typescript/15-function-overload/src/favicon.ico", + "apps/typescript/15-function-overload/src/assets" + ], + "styles": ["apps/typescript/15-function-overload/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "typescript-function-overload:build:production" + }, + "development": { + "buildTarget": "typescript-function-overload:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "typescript-function-overload:build" + } + } + } +} diff --git a/apps/typescript/overload/src/app/app.component.ts b/apps/typescript/15-function-overload/src/app/app.component.ts similarity index 100% rename from apps/typescript/overload/src/app/app.component.ts rename to apps/typescript/15-function-overload/src/app/app.component.ts diff --git a/apps/typescript/overload/src/app/vehicle.utils.ts b/apps/typescript/15-function-overload/src/app/vehicle.utils.ts similarity index 100% rename from apps/typescript/overload/src/app/vehicle.utils.ts rename to apps/typescript/15-function-overload/src/app/vehicle.utils.ts diff --git a/apps/typescript/15-function-overload/src/assets/.gitkeep b/apps/typescript/15-function-overload/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/typescript/15-function-overload/src/favicon.ico b/apps/typescript/15-function-overload/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/typescript/15-function-overload/src/favicon.ico differ diff --git a/apps/typescript/15-function-overload/src/index.html b/apps/typescript/15-function-overload/src/index.html new file mode 100644 index 000000000..37dd3a978 --- /dev/null +++ b/apps/typescript/15-function-overload/src/index.html @@ -0,0 +1,13 @@ + + + + + typescript-function-overload + + + + + + + + diff --git a/apps/typescript/15-function-overload/src/main.ts b/apps/typescript/15-function-overload/src/main.ts new file mode 100644 index 000000000..31c5da482 --- /dev/null +++ b/apps/typescript/15-function-overload/src/main.ts @@ -0,0 +1,4 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent).catch((err) => console.error(err)); diff --git a/apps/testing/router-outlet/src/styles.scss b/apps/typescript/15-function-overload/src/styles.scss similarity index 100% rename from apps/testing/router-outlet/src/styles.scss rename to apps/typescript/15-function-overload/src/styles.scss diff --git a/apps/typescript/15-function-overload/tsconfig.app.json b/apps/typescript/15-function-overload/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/typescript/15-function-overload/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/typescript/overload/tsconfig.editor.json b/apps/typescript/15-function-overload/tsconfig.editor.json similarity index 100% rename from apps/typescript/overload/tsconfig.editor.json rename to apps/typescript/15-function-overload/tsconfig.editor.json diff --git a/apps/typescript/overload/tsconfig.json b/apps/typescript/15-function-overload/tsconfig.json similarity index 100% rename from apps/typescript/overload/tsconfig.json rename to apps/typescript/15-function-overload/tsconfig.json diff --git a/apps/typescript/47-enums-vs-union-types/.eslintrc.json b/apps/typescript/47-enums-vs-union-types/.eslintrc.json new file mode 100644 index 000000000..8ebcbfd59 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/.eslintrc.json @@ -0,0 +1,36 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "app", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "app", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/typescript/47-enums-vs-union-types/README.md b/apps/typescript/47-enums-vs-union-types/README.md new file mode 100644 index 000000000..99aa0acf2 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/README.md @@ -0,0 +1,13 @@ +# Enums vs Union Types + +> author: sven-brodny + +### Run Application + +```bash +npx nx serve typescript-enums-vs-union-types +``` + +### Documentation and Instruction + +Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/typescript/47-enums-vs-union-types/). diff --git a/apps/typescript/47-enums-vs-union-types/project.json b/apps/typescript/47-enums-vs-union-types/project.json new file mode 100644 index 000000000..964750ac6 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/project.json @@ -0,0 +1,69 @@ +{ + "name": "typescript-enums-vs-union-types", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/typescript/47-enums-vs-union-types/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/typescript/47-enums-vs-union-types", + "index": "apps/typescript/47-enums-vs-union-types/src/index.html", + "browser": "apps/typescript/47-enums-vs-union-types/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/typescript/47-enums-vs-union-types/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/typescript/47-enums-vs-union-types/src/favicon.ico", + "apps/typescript/47-enums-vs-union-types/src/assets" + ], + "styles": ["apps/typescript/47-enums-vs-union-types/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "typescript-enums-vs-union-types:build:production" + }, + "development": { + "buildTarget": "typescript-enums-vs-union-types:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "typescript-enums-vs-union-types:build" + } + } + } +} diff --git a/apps/typescript/47-enums-vs-union-types/src/app/app.component.ts b/apps/typescript/47-enums-vs-union-types/src/app/app.component.ts new file mode 100644 index 000000000..05886724f --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/src/app/app.component.ts @@ -0,0 +1,82 @@ +import { Component, computed, signal } from '@angular/core'; + +enum Difficulty { + EASY = 'easy', + NORMAL = 'normal', +} + +enum Direction { + LEFT = 'left', + RIGHT = 'right', +} + +@Component({ + imports: [], + selector: 'app-root', + template: ` +
    +
    + + +
    +

    Selected Difficulty: {{ difficultyLabel() }}

    +
    + +
    +
    + + +
    +

    {{ directionLabel() }}

    +
    + `, + styles: ` + section { + @apply mx-auto my-5 flex w-fit flex-col items-center gap-2; + + > div { + @apply flex w-fit gap-5; + } + } + + button { + @apply rounded-md border px-4 py-2; + } + `, +}) +export class AppComponent { + readonly Difficulty = Difficulty; + readonly difficulty = signal(Difficulty.EASY); + + readonly Direction = Direction; + readonly direction = signal(undefined); + + readonly difficultyLabel = computed(() => { + switch (this.difficulty()) { + case Difficulty.EASY: + return Difficulty.EASY; + case Difficulty.NORMAL: + return Difficulty.NORMAL; + } + }); + + readonly directionLabel = computed(() => { + const prefix = 'You chose to go'; + switch (this.direction()) { + case Direction.LEFT: + return `${prefix} ${Direction.LEFT}`; + case Direction.RIGHT: + return `${prefix} ${Direction.RIGHT}`; + default: + return 'Choose a direction!'; + } + }); +} diff --git a/apps/typescript/47-enums-vs-union-types/src/app/app.config.ts b/apps/typescript/47-enums-vs-union-types/src/app/app.config.ts new file mode 100644 index 000000000..81a6edde4 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [], +}; diff --git a/apps/typescript/47-enums-vs-union-types/src/assets/.gitkeep b/apps/typescript/47-enums-vs-union-types/src/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/typescript/47-enums-vs-union-types/src/favicon.ico b/apps/typescript/47-enums-vs-union-types/src/favicon.ico new file mode 100644 index 000000000..317ebcb23 Binary files /dev/null and b/apps/typescript/47-enums-vs-union-types/src/favicon.ico differ diff --git a/apps/typescript/47-enums-vs-union-types/src/index.html b/apps/typescript/47-enums-vs-union-types/src/index.html new file mode 100644 index 000000000..1b677a046 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/src/index.html @@ -0,0 +1,13 @@ + + + + + typescript-enums-vs-union-types + + + + + + + + diff --git a/apps/typescript/47-enums-vs-union-types/src/main.ts b/apps/typescript/47-enums-vs-union-types/src/main.ts new file mode 100644 index 000000000..f3a7223da --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err), +); diff --git a/apps/typescript/47-enums-vs-union-types/src/styles.scss b/apps/typescript/47-enums-vs-union-types/src/styles.scss new file mode 100644 index 000000000..77e408aa8 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/src/styles.scss @@ -0,0 +1,5 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/typescript/47-enums-vs-union-types/tailwind.config.js b/apps/typescript/47-enums-vs-union-types/tailwind.config.js new file mode 100644 index 000000000..38183db2c --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/tailwind.config.js @@ -0,0 +1,14 @@ +const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind'); +const { join } = require('path'); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/typescript/47-enums-vs-union-types/tsconfig.app.json b/apps/typescript/47-enums-vs-union-types/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/typescript/47-enums-vs-union-types/tsconfig.editor.json b/apps/typescript/47-enums-vs-union-types/tsconfig.editor.json new file mode 100644 index 000000000..4ee639340 --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/tsconfig.editor.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "types": [] + } +} diff --git a/apps/typescript/47-enums-vs-union-types/tsconfig.json b/apps/typescript/47-enums-vs-union-types/tsconfig.json new file mode 100644 index 000000000..b94f8837d --- /dev/null +++ b/apps/typescript/47-enums-vs-union-types/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.editor.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/typescript/overload/.eslintrc.json b/apps/typescript/overload/.eslintrc.json deleted file mode 100644 index bf8df1428..000000000 --- a/apps/typescript/overload/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "app", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "app", - "style": "kebab-case" - } - ] - }, - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ] - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/apps/typescript/overload/README.md b/apps/typescript/overload/README.md deleted file mode 100644 index b4336af99..000000000 --- a/apps/typescript/overload/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Function Overload - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve typescript-overload` -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/typescript/15-typescript-overload-fn/). diff --git a/apps/typescript/overload/project.json b/apps/typescript/overload/project.json deleted file mode 100644 index 1cb7b3680..000000000 --- a/apps/typescript/overload/project.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "name": "typescript-overload", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/typescript/overload/src", - "prefix": "app", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/typescript/overload", - "index": "apps/typescript/overload/src/index.html", - "main": "apps/typescript/overload/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/typescript/overload/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/typescript/overload/src/favicon.ico", - "apps/typescript/overload/src/assets" - ], - "styles": ["apps/typescript/overload/src/styles.scss"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "typescript-overload:build:production" - }, - "development": { - "buildTarget": "typescript-overload:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "typescript-overload:build" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": [ - "apps/typescript/overload/**/*.ts", - "apps/typescript/overload/**/*.html" - ] - } - } - }, - "tags": [] -} diff --git a/apps/typescript/overload/src/index.html b/apps/typescript/overload/src/index.html deleted file mode 100644 index 86561b663..000000000 --- a/apps/typescript/overload/src/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Overload - - - - - - - - diff --git a/apps/typescript/overload/src/styles.scss b/apps/typescript/overload/src/styles.scss deleted file mode 100644 index 90d4ee007..000000000 --- a/apps/typescript/overload/src/styles.scss +++ /dev/null @@ -1 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ diff --git a/challenge-number.json b/challenge-number.json index a48a4f1cb..9504fd39d 100644 --- a/challenge-number.json +++ b/challenge-number.json @@ -1,6 +1,6 @@ { - "total": 44, - "🟢": 16, - "🟠": 120, - "🔴": 208 + "total": 59, + "🟢": 22, + "🟠": 124, + "🔴": 212 } diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index da50dd102..953462156 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -1,101 +1,124 @@ import starlight from '@astrojs/starlight'; import { defineConfig } from 'astro/config'; +import svelte from '@astrojs/svelte'; +import vercel from '@astrojs/vercel/serverless'; export const locales = { root: { label: 'English', - lang: 'en', + lang: 'en' }, es: { label: 'Español', - lang: 'es', + lang: 'es' }, fr: { label: 'Français', - lang: 'fr', + lang: 'fr' }, pt: { label: 'Português', - lang: 'pt', + lang: 'pt' }, ru: { label: 'Русский', - lang: 'ru', + lang: 'ru' }, + 'zh-cn': { + label: '简体中文', + lang: 'zh-CN' + } }; + // https://astro.build/config export default defineConfig({ - integrations: [ - starlight({ - title: 'Angular Challenges', - logo: { - src: './public/angular-challenge.webp', - alt: 'angular challenges logo', + integrations: [starlight({ + title: 'Angular Challenges', + logo: { + src: './public/angular-challenge.webp', + alt: 'angular challenges logo' + }, + favicon: './angular-challenge.ico', + social: { + github: 'https://github.com/tomalaforge/angular-challenges', + linkedin: 'https://www.linkedin.com/in/thomas-laforge-2b05a945/', + twitter: 'https://twitter.com/laforge_toma' + }, + customCss: ['./src/styles/custom-css.css'], + sidebar: [{ + label: 'Guides', + autogenerate: { + directory: 'guides' + }, + translations: { + es: 'Guías', + fr: 'Guides', + pt: 'Guias', + ru: 'Руководство', + 'zh-CN': '指南' + } + }, + { + label: 'Leaderboard', + autogenerate: { + directory: 'leaderboard', + collapsed: true }, - favicon: './angular-challenge.ico', - social: { - github: 'https://github.com/tomalaforge/angular-challenges', - linkedin: 'https://www.linkedin.com/in/thomas-laforge-2b05a945/', - twitter: 'https://twitter.com/laforge_toma', + translations: { + es: 'Leaderboard', + fr: 'Leaderboard', + pt: 'Tabela de Classificação', + ru: 'Leaderboard', + 'zh-CN': '排行榜' + } + }, + { + label: 'Challenges', + autogenerate: { + directory: 'challenges' }, - customCss: ['./src/styles/custom-css.css'], - sidebar: [ - { - label: 'Guides', - autogenerate: { directory: 'guides' }, - translations: { - es: 'Guías', - fr: 'Guides', - pt: 'Guias', - ru: 'Руководство', - }, - }, - { - label: 'Challenges', - autogenerate: { directory: 'challenges' }, - translations: { - es: 'Desafíos', - fr: 'Challenges', - pt: 'Desafios', - ru: 'Задачи', - }, - }, - ], - head: [ - { - tag: 'script', - attrs: { - src: 'https://www.googletagmanager.com/gtag/js?id=G-6BXJ62W6G5', - async: true, - }, - }, - { - tag: 'script', - content: ` + translations: { + es: 'Desafíos', + fr: 'Challenges', + pt: 'Desafios', + ru: 'Задачи', + 'zh-CN': '挑战' + } + }], + head: [{ + tag: 'script', + attrs: { + src: 'https://www.googletagmanager.com/gtag/js?id=G-6BXJ62W6G5', + async: true + } + }, { + tag: 'script', + content: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-6BXJ62W6G5'); - `, - }, - { - tag: 'script', - attrs: { - src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2438923752868254', - async: true, - } - } - ], - components: { - MarkdownContent: './src/components/Content.astro', - TableOfContents: './src/components/TableOfContents.astro', - PageTitle: './src/components/PageTitle.astro', - MobileMenuFooter: './src/components/MobileMenuFooter.astro', - }, - defaultLocale: 'root', - locales, - }), - ], + ` + }, { + tag: 'script', + attrs: { + src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2438923752868254', + async: true + } + }], + components: { + MarkdownContent: './src/components/Content.astro', + TableOfContents: './src/components/TableOfContents.astro', + PageTitle: './src/components/PageTitle.astro', + MobileMenuFooter: './src/components/MobileMenuFooter.astro', + SiteTitle: './src/components/SiteTitle.astro', + Hero: './src/components/Hero.astro' + }, + defaultLocale: 'root', + locales + }), svelte()], + output: "hybrid", + adapter: vercel() }); diff --git a/docs/package-lock.json b/docs/package-lock.json index 4624d4d17..626127ffe 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -9,9 +9,13 @@ "version": "0.0.1", "dependencies": { "@astrojs/starlight": "^0.15.1", + "@astrojs/svelte": "^5.2.0", + "@astrojs/vercel": "^7.5.0", "@fontsource/ibm-plex-serif": "^5.0.8", "astro": "^4.0.0", - "sharp": "^0.32.5" + "sharp": "^0.32.5", + "svelte": "^4.2.12", + "typescript": "^5.4.3" } }, "node_modules/@ampproject/remapping": { @@ -27,14 +31,14 @@ } }, "node_modules/@astrojs/compiler": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.3.4.tgz", - "integrity": "sha512-33/YtWoBCE0cBUNy1kh78FCDXBoBANX87ShgATlAHECYbG2+buNTAgq4Xgz4t5NgnEHPN21GIBC2Mvvwisoutw==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.7.0.tgz", + "integrity": "sha512-XpC8MAaWjD1ff6/IfkRq/5k1EFj6zhCNqXRd5J43SVJEBj/Bsmizkm8N0xOYscGcDFQkRgEw6/eKnI5x/1l6aA==" }, "node_modules/@astrojs/internal-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.2.1.tgz", - "integrity": "sha512-06DD2ZnItMwUnH81LBLco3tWjcZ1lGU9rLCCBaeUCGYe9cI0wKyY2W3kDyoW1I6GmcWgt1fu+D1CTvz+FIKf8A==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.4.0.tgz", + "integrity": "sha512-6B13lz5n6BrbTqCTwhXjJXuR1sqiX/H6rTxzlXx+lN1NnV4jgnq/KJldCQaUWJzPL5SiWahQyinxAbxQtwgPHA==" }, "node_modules/@astrojs/markdown-remark": { "version": "4.0.1", @@ -418,683 +422,525 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@astrojs/telemetry": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.4.tgz", - "integrity": "sha512-A+0c7k/Xy293xx6odsYZuXiaHO0PL+bnDoXOc47sGDF5ffIKdKQGRPFl2NMlCF4L0NqN4Ynbgnaip+pPF0s7pQ==", + "node_modules/@astrojs/svelte": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@astrojs/svelte/-/svelte-5.2.0.tgz", + "integrity": "sha512-GmwbXks2WMkmAfl0rlPM/2gA1RtmZzjGV2mOceV3g7QNyjIsSYBPKrlEnSFnuR+YMvlAtWdbMFBsb3gtGxnTTg==", "dependencies": { - "ci-info": "^3.8.0", - "debug": "^4.3.4", - "dlv": "^1.1.3", - "dset": "^3.1.2", - "is-docker": "^3.0.0", - "is-wsl": "^3.0.0", - "which-pm-runs": "^1.1.0" + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte2tsx": "^0.6.27" }, "engines": { "node": ">=18.14.1" + }, + "peerDependencies": { + "astro": "^4.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.56", + "typescript": "^5.3.3" } }, - "node_modules/@astrojs/telemetry/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } + "node_modules/@astrojs/svelte/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" ], + "peer": true, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/core": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", - "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.6", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", - "@babel/types": "^7.23.6", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" + "node": ">=12" } }, - "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", - "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dependencies": { - "@babel/types": "^7.22.5" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", - "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" + "node_modules/@astrojs/svelte/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dependencies": { - "@babel/types": "^7.22.15" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" + "node": ">=12" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=12" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", - "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", - "@babel/types": "^7.23.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", - "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz", - "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.22.5", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", - "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz", - "integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", "cpu": [ "ppc64" ], "optional": true, "os": [ - "aix" + "linux" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz", - "integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", "cpu": [ - "arm" + "riscv64" ], "optional": true, "os": [ - "android" + "linux" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz", - "integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", "cpu": [ - "arm64" + "s390x" ], "optional": true, "os": [ - "android" + "linux" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz", - "integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", "cpu": [ "x64" ], "optional": true, "os": [ - "android" + "linux" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz", - "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", "cpu": [ - "arm64" + "x64" ], "optional": true, "os": [ - "darwin" + "netbsd" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz", - "integrity": "sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", "cpu": [ "x64" ], "optional": true, "os": [ - "darwin" + "openbsd" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz", - "integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", "cpu": [ - "arm64" + "x64" ], "optional": true, "os": [ - "freebsd" + "sunos" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz", - "integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", "cpu": [ - "x64" + "arm64" ], "optional": true, "os": [ - "freebsd" + "win32" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz", - "integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", "cpu": [ - "arm" + "ia32" ], "optional": true, "os": [ - "linux" + "win32" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz", - "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==", + "node_modules/@astrojs/svelte/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", "cpu": [ - "arm64" + "x64" ], "optional": true, "os": [ - "linux" + "win32" ], + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz", - "integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.1.tgz", + "integrity": "sha512-4C4UERETjXpC4WpBXDbkgNVgHyWfG3B/NKY46e7w5H134UDOFqUJKpsLm0UYmuupW+aJmRgeScrDNfvZ5WV80A==", "cpu": [ - "ia32" + "arm" ], "optional": true, "os": [ - "linux" + "android" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz", - "integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.1.tgz", + "integrity": "sha512-TrTaFJ9pXgfXEiJKQ3yQRelpQFqgRzVR9it8DbeRzG0RX7mKUy0bqhCFsgevwXLJepQKTnLl95TnPGf9T9AMOA==", "cpu": [ - "loong64" + "arm64" ], "optional": true, "os": [ - "linux" + "android" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz", - "integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.1.tgz", + "integrity": "sha512-fz7jN6ahTI3cKzDO2otQuybts5cyu0feymg0bjvYCBrZQ8tSgE8pc0sSNEuGvifrQJWiwx9F05BowihmLxeQKw==", "cpu": [ - "mips64el" + "arm64" ], "optional": true, "os": [ - "linux" + "darwin" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz", - "integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.1.tgz", + "integrity": "sha512-WTvdz7SLMlJpektdrnWRUN9C0N2qNHwNbWpNo0a3Tod3gb9leX+yrYdCeB7VV36OtoyiPAivl7/xZ3G1z5h20g==", "cpu": [ - "ppc64" + "x64" ], "optional": true, "os": [ - "linux" + "darwin" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz", - "integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.1.tgz", + "integrity": "sha512-dBHQl+7wZzBYcIF6o4k2XkAfwP2ks1mYW2q/Gzv9n39uDcDiAGDqEyml08OdY0BIct0yLSPkDTqn4i6czpBLLw==", "cpu": [ - "riscv64" + "arm" ], "optional": true, "os": [ "linux" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz", - "integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.1.tgz", + "integrity": "sha512-bur4JOxvYxfrAmocRJIW0SADs3QdEYK6TQ7dTNz6Z4/lySeu3Z1H/+tl0a4qDYv0bCdBpUYM0sYa/X+9ZqgfSQ==", "cpu": [ - "s390x" + "arm64" ], "optional": true, "os": [ "linux" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz", - "integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.1.tgz", + "integrity": "sha512-ssp77SjcDIUSoUyj7DU7/5iwM4ZEluY+N8umtCT9nBRs3u045t0KkW02LTyHouHDomnMXaXSZcCSr2bdMK63kA==", "cpu": [ - "x64" + "arm64" ], "optional": true, "os": [ "linux" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz", - "integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.1.tgz", + "integrity": "sha512-Jv1DkIvwEPAb+v25/Unrnnq9BO3F5cbFPT821n3S5litkz+O5NuXuNhqtPx5KtcwOTtaqkTsO+IVzJOsxd11aQ==", "cpu": [ - "x64" + "riscv64" ], "optional": true, "os": [ - "netbsd" + "linux" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz", - "integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.1.tgz", + "integrity": "sha512-zGRDulLTeDemR8DFYyFIQ8kMP02xpUsX4IBikc7lwL9PrwR3gWmX2NopqiGlI2ZVWMl15qZeUjumTwpv18N7sQ==", "cpu": [ "x64" ], "optional": true, "os": [ - "openbsd" + "linux" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz", - "integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.1.tgz", + "integrity": "sha512-VTk/MveyPdMFkYJJPCkYBw07KcTkGU2hLEyqYMsU4NjiOfzoaDTW9PWGRsNwiOA3qI0k/JQPjkl/4FCK1smskQ==", "cpu": [ "x64" ], "optional": true, "os": [ - "sunos" + "linux" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz", - "integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.1.tgz", + "integrity": "sha512-L+hX8Dtibb02r/OYCsp4sQQIi3ldZkFI0EUkMTDwRfFykXBPptoz/tuuGqEd3bThBSLRWPR6wsixDSgOx/U3Zw==", "cpu": [ "arm64" ], @@ -1102,14 +948,12 @@ "os": [ "win32" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz", - "integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.1.tgz", + "integrity": "sha512-+dI2jVPfM5A8zme8riEoNC7UKk0Lzc7jCj/U89cQIrOjrZTCWZl/+IXUeRT2rEZ5j25lnSA9G9H1Ob9azaF/KQ==", "cpu": [ "ia32" ], @@ -1117,14 +961,12 @@ "os": [ "win32" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz", - "integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==", + "node_modules/@astrojs/svelte/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.1.tgz", + "integrity": "sha512-YY1Exxo2viZ/O2dMHuwQvimJ0SqvL+OAWQLLY6rvXavgQKjhQUzn7nc1Dd29gjB5Fqi00nrBWctJBOyfVMIVxw==", "cpu": [ "x64" ], @@ -1132,1075 +974,2536 @@ "os": [ "win32" ], - "engines": { - "node": ">=12" - } + "peer": true }, - "node_modules/@expressive-code/core": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.30.1.tgz", - "integrity": "sha512-z11G1lfzzuTJ63C4dGPUIEKxJse5eKrVxqxQJRiuCDH8hPqfIQs/+by04UceSWB0dt5SIFsL5J+7HvCycbc1iA==", + "node_modules/@astrojs/svelte/node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz", + "integrity": "sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==", "dependencies": { - "@ctrl/tinycolor": "^3.6.0", - "hast-util-to-html": "^8.0.4", - "hastscript": "^7.2.0", - "postcss": "^8.4.21", - "postcss-nested": "^6.0.1" + "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "svelte-hmr": "^0.15.3", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" } }, - "node_modules/@expressive-code/core/node_modules/@types/hast": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", - "integrity": "sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==", + "node_modules/@astrojs/svelte/node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz", + "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==", "dependencies": { - "@types/unist": "^2" + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" } }, - "node_modules/@expressive-code/core/node_modules/hast-util-from-parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz", - "integrity": "sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==", + "node_modules/@astrojs/svelte/node_modules/@types/node": { + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "optional": true, + "peer": true, "dependencies": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "hastscript": "^7.0.0", - "property-information": "^6.0.0", - "vfile": "^5.0.0", - "vfile-location": "^4.0.0", - "web-namespaces": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "undici-types": "~5.26.4" } }, - "node_modules/@expressive-code/core/node_modules/hast-util-parse-selector": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", - "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "node_modules/@astrojs/svelte/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "hasInstallScript": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/@astrojs/svelte/node_modules/rollup": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.1.tgz", + "integrity": "sha512-hFi+fU132IvJ2ZuihN56dwgpltpmLZHZWsx27rMCTZ2sYwrqlgL5sECGy1eeV2lAihD8EzChBVVhsXci0wD4Tg==", + "peer": true, "dependencies": { - "@types/hast": "^2.0.0" + "@types/estree": "1.0.5" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.1", + "@rollup/rollup-android-arm64": "4.13.1", + "@rollup/rollup-darwin-arm64": "4.13.1", + "@rollup/rollup-darwin-x64": "4.13.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.1", + "@rollup/rollup-linux-arm64-gnu": "4.13.1", + "@rollup/rollup-linux-arm64-musl": "4.13.1", + "@rollup/rollup-linux-riscv64-gnu": "4.13.1", + "@rollup/rollup-linux-s390x-gnu": "4.13.1", + "@rollup/rollup-linux-x64-gnu": "4.13.1", + "@rollup/rollup-linux-x64-musl": "4.13.1", + "@rollup/rollup-win32-arm64-msvc": "4.13.1", + "@rollup/rollup-win32-ia32-msvc": "4.13.1", + "@rollup/rollup-win32-x64-msvc": "4.13.1", + "fsevents": "~2.3.2" } }, - "node_modules/@expressive-code/core/node_modules/hast-util-raw": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz", - "integrity": "sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==", + "node_modules/@astrojs/svelte/node_modules/vite": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", + "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "peer": true, "dependencies": { - "@types/hast": "^2.0.0", - "@types/parse5": "^6.0.0", - "hast-util-from-parse5": "^7.0.0", - "hast-util-to-parse5": "^7.0.0", - "html-void-elements": "^2.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^4.0.0", - "unist-util-visit": "^4.0.0", - "vfile": "^5.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" + "esbuild": "^0.20.1", + "postcss": "^8.4.36", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, - "node_modules/@expressive-code/core/node_modules/hast-util-to-html": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.4.tgz", - "integrity": "sha512-4tpQTUOr9BMjtYyNlt0P50mH7xj0Ks2xpo8M943Vykljf99HW6EzulIoJP1N3eKOSScEHzyzi9dm7/cn0RfGwA==", + "node_modules/@astrojs/telemetry": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.4.tgz", + "integrity": "sha512-A+0c7k/Xy293xx6odsYZuXiaHO0PL+bnDoXOc47sGDF5ffIKdKQGRPFl2NMlCF4L0NqN4Ynbgnaip+pPF0s7pQ==", "dependencies": { - "@types/hast": "^2.0.0", - "@types/unist": "^2.0.0", - "ccount": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-raw": "^7.0.0", - "hast-util-whitespace": "^2.0.0", - "html-void-elements": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "stringify-entities": "^4.0.0", - "zwitch": "^2.0.4" + "ci-info": "^3.8.0", + "debug": "^4.3.4", + "dlv": "^1.1.3", + "dset": "^3.1.2", + "is-docker": "^3.0.0", + "is-wsl": "^3.0.0", + "which-pm-runs": "^1.1.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=18.14.1" } }, - "node_modules/@expressive-code/core/node_modules/hast-util-to-parse5": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz", - "integrity": "sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==", - "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0", - "web-namespaces": "^2.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/@astrojs/telemetry/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" } }, - "node_modules/@expressive-code/core/node_modules/hast-util-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", - "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/@astrojs/vercel": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@astrojs/vercel/-/vercel-7.5.0.tgz", + "integrity": "sha512-RYFZNHkfNgFNb41nblG26ubw5924hAjLYs+Bpp4kttcsYJAX/wavIfDbfZQ/XesDTKwIH+Gi/+3c5bldZePFDA==", + "dependencies": { + "@astrojs/internal-helpers": "0.4.0", + "@vercel/analytics": "^1.0.2", + "@vercel/edge": "^1.1.1", + "@vercel/nft": "^0.26.4", + "esbuild": "^0.19.6", + "fast-glob": "^3.3.2", + "set-cookie-parser": "^2.6.0", + "web-vitals": "^3.4.0" + }, + "peerDependencies": { + "astro": "^4.2.0" } }, - "node_modules/@expressive-code/core/node_modules/hastscript": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", - "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/core/node_modules/html-void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", - "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/core/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/@expressive-code/core/node_modules/unist-util-position": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", - "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", + "node_modules/@babel/core": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.3.tgz", + "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", "dependencies": { - "@types/unist": "^2.0.0" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@expressive-code/core/node_modules/vfile-location": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz", - "integrity": "sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==", - "dependencies": { - "@types/unist": "^2.0.0", - "vfile": "^5.0.0" + "engines": { + "node": ">=6.9.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://opencollective.com/babel" } }, - "node_modules/@expressive-code/plugin-frames": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.30.1.tgz", - "integrity": "sha512-fBqd+NWcmlP63q8kNi73b6EuwWZwb+8OIhqWEsEQ/lsoOmT8FVYqsnH+M+TRC9or+U0PNd7Po/ojcFNnS0TAIQ==", - "dependencies": { - "@expressive-code/core": "^0.30.1", - "hastscript": "^7.2.0" + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@expressive-code/plugin-frames/node_modules/@types/hast": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", - "integrity": "sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==", + "node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", "dependencies": { - "@types/unist": "^2" + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-frames/node_modules/hast-util-parse-selector": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", - "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dependencies": { - "@types/hast": "^2.0.0" + "@babel/types": "^7.22.5" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-frames/node_modules/hastscript": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", - "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-shiki": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.30.1.tgz", - "integrity": "sha512-VoJZWZ1wjW/I+CsHg4/RwurrHdtnF5C5fbXESQCQlnXWOhWBfJnOX1ilx5B11gsH5kEWNoD5WRAt8t0L0V/VJA==", - "dependencies": { - "@expressive-code/core": "^0.30.1", - "shikiji": "^0.8.0" + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@expressive-code/plugin-shiki/node_modules/shikiji": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/shikiji/-/shikiji-0.8.7.tgz", - "integrity": "sha512-j5usxwI0yHkDTHOuhuSJl9+wT5CNYeYO82dJMSJBlJ/NYT5SIebGcPoL6y9QOyH15wGrJC4LOP2nz5k8mUDGRQ==", - "dependencies": { - "hast-util-to-html": "^9.0.0" + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-text-markers": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.30.1.tgz", - "integrity": "sha512-Dtw2lIsAfcfWy/qUhrEW1NwZdgMsI+qeHQ/7Do+W9fMBIoIIHh2GLwmhwkBitoOvLgOJQWsNoBvT42LUp2+16g==", + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@expressive-code/core": "^0.30.1", - "hastscript": "^7.2.0", - "unist-util-visit-parents": "^5.1.3" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-text-markers/node_modules/@types/hast": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", - "integrity": "sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@types/unist": "^2" + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-text-markers/node_modules/hast-util-parse-selector": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", - "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { - "@types/hast": "^2.0.0" + "@babel/types": "^7.22.15" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@expressive-code/plugin-text-markers/node_modules/hastscript": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", - "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@fontsource/ibm-plex-serif": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-serif/-/ibm-plex-serif-5.0.8.tgz", - "integrity": "sha512-KUp1E9Wzf2Umhr2SbpcF9HwgFJmuxvKAARmpl7GDDkIG30R1PMFJWxfSfQ7oX/oVBtomGq5RUTaMMUeE0ngEgw==" + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@babel/types": "^7.22.5" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@mdx-js/mdx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", - "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdx": "^2.0.0", - "collapse-white-space": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-build-jsx": "^3.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "estree-util-to-js": "^2.0.0", - "estree-walker": "^3.0.0", - "hast-util-to-estree": "^3.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "markdown-extensions": "^2.0.0", - "periscopic": "^3.0.0", - "remark-mdx": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "source-map": "^0.7.0", - "unified": "^11.0.0", - "unist-util-position-from-estree": "^2.0.0", - "unist-util-stringify-position": "^4.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@mdx-js/mdx/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" - }, - "node_modules/@mdx-js/mdx/node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "node_modules/@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dependencies": { - "@types/unist": "^3.0.0" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "bin": { + "parser": "bin/babel-parser.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" + "@babel/helper-plugin-utils": "^7.22.5" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@mdx-js/mdx/node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz", + "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.15" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@mdx-js/mdx/node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@mdx-js/mdx/node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", "engines": { - "node": ">= 8" + "node": ">=10" } }, - "node_modules/@pagefind/darwin-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.0.3.tgz", - "integrity": "sha512-vsHDtvao3W4iFCxVc4S0BVhpj3E2MAoIVM7RmuQfGp1Ng22nGLRaMP6FguLO8TMabRJdvp4SVr227hL4WGKOHA==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz", + "integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==", "cpu": [ - "arm64" + "ppc64" ], "optional": true, "os": [ - "darwin" - ] + "aix" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@pagefind/darwin-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.0.3.tgz", - "integrity": "sha512-NhEXHHYmB/hT6lx5rCcmnVTxH+uIkMAd43bzEqMwHQosqTZEIQfwihmV39H+m8yo7jFvz3zRbJNzhAh7G4PiwA==", + "node_modules/@esbuild/android-arm": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz", + "integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==", "cpu": [ - "x64" + "arm" ], "optional": true, "os": [ - "darwin" - ] - }, - "node_modules/@pagefind/default-ui": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.0.3.tgz", - "integrity": "sha512-WieFJXvezyvjZh49I8j7a7Kz3LsXYY2Uep3IWvG5NG05mmiurURXjXc+KyrpIp/iAycSnjrC1TDJ8CdES/ee3A==" + "android" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@pagefind/linux-arm64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.0.3.tgz", - "integrity": "sha512-RGsMt4AmGT8WxCSeP09arU7Za6Vf/We4TWHVSbY7vDMuwWql9Ngoib/q1cP9dIAIMdkXh9ePG/S3mGnJYsdzuQ==", + "node_modules/@esbuild/android-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz", + "integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==", "cpu": [ "arm64" ], "optional": true, "os": [ - "linux" - ] - }, - "node_modules/@pagefind/linux-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.0.3.tgz", - "integrity": "sha512-o+VCKaqImL42scSH1n5gUfppYSNyu3BuGTvtKKgWHmycbL+A3fkFH+ZOFbaLeN7LVTvJqJIOYbk4j2yaq9784Q==", - "cpu": [ - "x64" + "android" ], - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">=12" + } }, - "node_modules/@pagefind/windows-x64": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.0.3.tgz", - "integrity": "sha512-S+Yq4FyvXJm4F+iN/wRiLvEEF8Xs9lTKGtQGaRHXJslQyl65dytDDPIULXJXIadrDbnMrnTt4C2YHmEUIyUIHg==", + "node_modules/@esbuild/android-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz", + "integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==", "cpu": [ "x64" ], "optional": true, "os": [ - "win32" - ] + "android" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz", - "integrity": "sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz", + "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==", "cpu": [ - "arm" + "arm64" ], "optional": true, "os": [ - "android" - ] + "darwin" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.1.tgz", - "integrity": "sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz", + "integrity": "sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==", "cpu": [ - "arm64" + "x64" ], "optional": true, "os": [ - "android" - ] + "darwin" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz", - "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz", + "integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==", "cpu": [ "arm64" ], "optional": true, "os": [ - "darwin" - ] + "freebsd" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.1.tgz", - "integrity": "sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz", + "integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==", "cpu": [ "x64" ], "optional": true, "os": [ - "darwin" - ] + "freebsd" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.1.tgz", - "integrity": "sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==", + "node_modules/@esbuild/linux-arm": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz", + "integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==", "cpu": [ "arm" ], "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.1.tgz", - "integrity": "sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz", + "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==", "cpu": [ "arm64" ], "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.1.tgz", - "integrity": "sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz", + "integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==", "cpu": [ - "arm64" + "ia32" ], "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.1.tgz", - "integrity": "sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz", + "integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==", "cpu": [ - "riscv64" + "loong64" ], "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.1.tgz", - "integrity": "sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz", + "integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==", "cpu": [ - "x64" + "mips64el" ], "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.1.tgz", - "integrity": "sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz", + "integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==", "cpu": [ - "x64" + "ppc64" ], "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.1.tgz", - "integrity": "sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz", + "integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==", "cpu": [ - "arm64" + "riscv64" ], "optional": true, "os": [ - "win32" - ] + "linux" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.1.tgz", - "integrity": "sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz", + "integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==", "cpu": [ - "ia32" + "s390x" ], "optional": true, "os": [ - "win32" - ] + "linux" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.1.tgz", - "integrity": "sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==", + "node_modules/@esbuild/linux-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz", + "integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==", "cpu": [ "x64" ], "optional": true, "os": [ - "win32" - ] - }, - "node_modules/@types/acorn": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", - "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", - "dependencies": { - "@types/estree": "*" + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz", + "integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dependencies": { - "@babel/types": "^7.0.0" + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz", + "integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz", + "integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", - "dependencies": { - "@babel/types": "^7.20.7" + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz", + "integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dependencies": { - "@types/ms": "*" + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz", + "integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@types/estree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", - "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==" + "node_modules/@esbuild/win32-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz", + "integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/@types/estree-jsx": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", - "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", + "node_modules/@expressive-code/core": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.30.1.tgz", + "integrity": "sha512-z11G1lfzzuTJ63C4dGPUIEKxJse5eKrVxqxQJRiuCDH8hPqfIQs/+by04UceSWB0dt5SIFsL5J+7HvCycbc1iA==", "dependencies": { - "@types/estree": "*" + "@ctrl/tinycolor": "^3.6.0", + "hast-util-to-html": "^8.0.4", + "hastscript": "^7.2.0", + "postcss": "^8.4.21", + "postcss-nested": "^6.0.1" } }, - "node_modules/@types/hast": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", - "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "node_modules/@expressive-code/core/node_modules/@types/hast": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", + "integrity": "sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==", "dependencies": { - "@types/unist": "*" + "@types/unist": "^2" } }, - "node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "node_modules/@expressive-code/core/node_modules/hast-util-from-parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz", + "integrity": "sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==", "dependencies": { - "@types/unist": "*" + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0", + "hastscript": "^7.0.0", + "property-information": "^6.0.0", + "vfile": "^5.0.0", + "vfile-location": "^4.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@types/mdx": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.10.tgz", - "integrity": "sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==" - }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" - }, - "node_modules/@types/nlcst": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.2.tgz", - "integrity": "sha512-ykxL/GDDUhqikjU0LIywZvEwb1NTYXTEWf+XgMSS2o6IXIakafPccxZmxgZcvJPZ3yFl2kdL1gJZz3U3iZF3QA==", + "node_modules/@expressive-code/core/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", "dependencies": { - "@types/unist": "^2" + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" - }, - "node_modules/@types/parse5": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", - "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" - }, - "node_modules/@types/sax": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", - "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "node_modules/@expressive-code/core/node_modules/hast-util-raw": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz", + "integrity": "sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==", "dependencies": { - "@types/node": "*" + "@types/hast": "^2.0.0", + "@types/parse5": "^6.0.0", + "hast-util-from-parse5": "^7.0.0", + "hast-util-to-parse5": "^7.0.0", + "html-void-elements": "^2.0.0", + "parse5": "^6.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/@types/unist": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz", - "integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "node_modules/@expressive-code/core/node_modules/hast-util-to-html": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.4.tgz", + "integrity": "sha512-4tpQTUOr9BMjtYyNlt0P50mH7xj0Ks2xpo8M943Vykljf99HW6EzulIoJP1N3eKOSScEHzyzi9dm7/cn0RfGwA==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/unist": "^2.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-raw": "^7.0.0", + "hast-util-whitespace": "^2.0.0", + "html-void-elements": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/core/node_modules/hast-util-to-parse5": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz", + "integrity": "sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/core/node_modules/hast-util-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", + "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/core/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/core/node_modules/html-void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz", + "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/@expressive-code/core/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/@expressive-code/core/node_modules/unist-util-position": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", + "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/core/node_modules/vfile-location": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz", + "integrity": "sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==", + "dependencies": { + "@types/unist": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/plugin-frames": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-frames/-/plugin-frames-0.30.1.tgz", + "integrity": "sha512-fBqd+NWcmlP63q8kNi73b6EuwWZwb+8OIhqWEsEQ/lsoOmT8FVYqsnH+M+TRC9or+U0PNd7Po/ojcFNnS0TAIQ==", + "dependencies": { + "@expressive-code/core": "^0.30.1", + "hastscript": "^7.2.0" + } + }, + "node_modules/@expressive-code/plugin-frames/node_modules/@types/hast": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", + "integrity": "sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@expressive-code/plugin-frames/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/plugin-frames/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/plugin-shiki": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.30.1.tgz", + "integrity": "sha512-VoJZWZ1wjW/I+CsHg4/RwurrHdtnF5C5fbXESQCQlnXWOhWBfJnOX1ilx5B11gsH5kEWNoD5WRAt8t0L0V/VJA==", + "dependencies": { + "@expressive-code/core": "^0.30.1", + "shikiji": "^0.8.0" + } + }, + "node_modules/@expressive-code/plugin-shiki/node_modules/shikiji": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/shikiji/-/shikiji-0.8.7.tgz", + "integrity": "sha512-j5usxwI0yHkDTHOuhuSJl9+wT5CNYeYO82dJMSJBlJ/NYT5SIebGcPoL6y9QOyH15wGrJC4LOP2nz5k8mUDGRQ==", + "dependencies": { + "hast-util-to-html": "^9.0.0" + } + }, + "node_modules/@expressive-code/plugin-text-markers": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-text-markers/-/plugin-text-markers-0.30.1.tgz", + "integrity": "sha512-Dtw2lIsAfcfWy/qUhrEW1NwZdgMsI+qeHQ/7Do+W9fMBIoIIHh2GLwmhwkBitoOvLgOJQWsNoBvT42LUp2+16g==", + "dependencies": { + "@expressive-code/core": "^0.30.1", + "hastscript": "^7.2.0", + "unist-util-visit-parents": "^5.1.3" + } + }, + "node_modules/@expressive-code/plugin-text-markers/node_modules/@types/hast": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.8.tgz", + "integrity": "sha512-aMIqAlFd2wTIDZuvLbhUT+TGvMxrNC8ECUIVtH6xxy0sQLs3iu6NO8Kp/VT5je7i5ufnebXzdV1dNDMnvaH6IQ==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@expressive-code/plugin-text-markers/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", + "dependencies": { + "@types/hast": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@expressive-code/plugin-text-markers/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@fontsource/ibm-plex-serif": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-serif/-/ibm-plex-serif-5.0.8.tgz", + "integrity": "sha512-KUp1E9Wzf2Umhr2SbpcF9HwgFJmuxvKAARmpl7GDDkIG30R1PMFJWxfSfQ7oX/oVBtomGq5RUTaMMUeE0ngEgw==" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mdx-js/mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.0.tgz", + "integrity": "sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-to-js": "^2.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-estree": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "periscopic": "^3.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/@mdx-js/mdx/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/mdx/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pagefind/darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.0.3.tgz", + "integrity": "sha512-vsHDtvao3W4iFCxVc4S0BVhpj3E2MAoIVM7RmuQfGp1Ng22nGLRaMP6FguLO8TMabRJdvp4SVr227hL4WGKOHA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.0.3.tgz", + "integrity": "sha512-NhEXHHYmB/hT6lx5rCcmnVTxH+uIkMAd43bzEqMwHQosqTZEIQfwihmV39H+m8yo7jFvz3zRbJNzhAh7G4PiwA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/default-ui": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pagefind/default-ui/-/default-ui-1.0.3.tgz", + "integrity": "sha512-WieFJXvezyvjZh49I8j7a7Kz3LsXYY2Uep3IWvG5NG05mmiurURXjXc+KyrpIp/iAycSnjrC1TDJ8CdES/ee3A==" + }, + "node_modules/@pagefind/linux-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.0.3.tgz", + "integrity": "sha512-RGsMt4AmGT8WxCSeP09arU7Za6Vf/We4TWHVSbY7vDMuwWql9Ngoib/q1cP9dIAIMdkXh9ePG/S3mGnJYsdzuQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/linux-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.0.3.tgz", + "integrity": "sha512-o+VCKaqImL42scSH1n5gUfppYSNyu3BuGTvtKKgWHmycbL+A3fkFH+ZOFbaLeN7LVTvJqJIOYbk4j2yaq9784Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/windows-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.0.3.tgz", + "integrity": "sha512-S+Yq4FyvXJm4F+iN/wRiLvEEF8Xs9lTKGtQGaRHXJslQyl65dytDDPIULXJXIadrDbnMrnTt4C2YHmEUIyUIHg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.2.tgz", + "integrity": "sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.2.tgz", + "integrity": "sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.2.tgz", + "integrity": "sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.2.tgz", + "integrity": "sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.2.tgz", + "integrity": "sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.2.tgz", + "integrity": "sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.2.tgz", + "integrity": "sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.13.2.tgz", + "integrity": "sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ==", + "cpu": [ + "ppc64le" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.2.tgz", + "integrity": "sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.1.tgz", + "integrity": "sha512-U564BrhEfaNChdATQaEODtquCC7Ez+8Hxz1h5MAdMYj0AqD0GA9rHCpElajb/sQcaFL6NXmHc5O+7FXpWMa73Q==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.2.tgz", + "integrity": "sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.2.tgz", + "integrity": "sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.2.tgz", + "integrity": "sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.2.tgz", + "integrity": "sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.2.tgz", + "integrity": "sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.2.1.tgz", + "integrity": "sha512-KaIS0H4EQ3KI2d++TjYqRNgwp8E3M/68e9veR4QtInzA7kKFgcjeiJqb80fuXW+blDy5fmd11PN9g9soz/3ANQ==" + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.3.tgz", + "integrity": "sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.3.tgz", + "integrity": "sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.10.tgz", + "integrity": "sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/nlcst": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.2.tgz", + "integrity": "sha512-ykxL/GDDUhqikjU0LIywZvEwb1NTYXTEWf+XgMSS2o6IXIakafPccxZmxgZcvJPZ3yFl2kdL1gJZz3U3iZF3QA==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==" + }, + "node_modules/@types/parse5": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz", + "integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz", + "integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/@vercel/analytics": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.2.2.tgz", + "integrity": "sha512-X0rctVWkQV1e5Y300ehVNqpOfSOufo7ieA5PIdna8yX/U7Vjz0GFsGf4qvAhxV02uQ2CVt7GYcrFfddXXK2Y4A==", + "dependencies": { + "server-only": "^0.0.1" + }, + "peerDependencies": { + "next": ">= 13", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@vercel/edge": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@vercel/edge/-/edge-1.1.1.tgz", + "integrity": "sha512-NtKiIbn9Cq6HWGy+qRudz28mz5nxfOJWls5Pnckjw1yCfSX8rhXdvY/il3Sy3Zd5n/sKCM2h7VSCCpJF/oaDrQ==" + }, + "node_modules/@vercel/nft": { + "version": "0.26.4", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.26.4.tgz", + "integrity": "sha512-j4jCOOXke2t8cHZCIxu1dzKLHLcFmYzC3yqAK6MfZznOL1QIJKd0xcFsXK3zcqzU7ScsE2zWkiMMNHGMHgp+FA==", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.5", + "@rollup/pluginutils": "^4.0.0", + "acorn": "^8.6.0", + "acorn-import-attributes": "^1.9.2", + "async-sema": "^3.1.1", + "bindings": "^1.4.0", + "estree-walker": "2.0.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.2", + "node-gyp-build": "^4.2.2", + "resolve-from": "^5.0.0" + }, + "bin": { + "nft": "out/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@vercel/nft/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/acorn": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "bin": { - "acorn": "bin/acorn" + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.4.tgz", + "integrity": "sha512-dNIX/5UEnZvVL94dV2scl4VIooK36D8AteP4xiz7cPKhDbhLhSuWkzG580g+Q7TXJklp+Z21SiaK7/HpLO84Qg==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/astro": { + "version": "4.5.12", + "resolved": "https://registry.npmjs.org/astro/-/astro-4.5.12.tgz", + "integrity": "sha512-xIJcFI2hbyV8+h5pWjL7SKD1jIP0K01fYVAH+gdAt0mJaXy+u8Mj+goD0cPlK6sEaykR+7zxQLYGKJ44U4qarg==", + "dependencies": { + "@astrojs/compiler": "^2.7.0", + "@astrojs/internal-helpers": "0.4.0", + "@astrojs/markdown-remark": "4.3.2", + "@astrojs/telemetry": "3.0.4", + "@babel/core": "^7.24.3", + "@babel/generator": "^7.23.3", + "@babel/parser": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.5", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "@types/babel__core": "^7.20.4", + "acorn": "^8.11.2", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "boxen": "^7.1.1", + "chokidar": "^3.5.3", + "ci-info": "^4.0.0", + "clsx": "^2.0.0", + "common-ancestor-path": "^1.0.1", + "cookie": "^0.6.0", + "cssesc": "^3.0.0", + "debug": "^4.3.4", + "deterministic-object-hash": "^2.0.1", + "devalue": "^4.3.2", + "diff": "^5.1.0", + "dlv": "^1.1.3", + "dset": "^3.1.3", + "es-module-lexer": "^1.4.1", + "esbuild": "^0.19.6", + "estree-walker": "^3.0.3", + "execa": "^8.0.1", + "fast-glob": "^3.3.2", + "flattie": "^1.1.0", + "github-slugger": "^2.0.0", + "gray-matter": "^4.0.3", + "html-escaper": "^3.0.3", + "http-cache-semantics": "^4.1.1", + "js-yaml": "^4.1.0", + "kleur": "^4.1.4", + "magic-string": "^0.30.3", + "mime": "^3.0.0", + "ora": "^7.0.1", + "p-limit": "^5.0.0", + "p-queue": "^8.0.1", + "path-to-regexp": "^6.2.1", + "preferred-pm": "^3.1.2", + "prompts": "^2.4.2", + "rehype": "^13.0.1", + "resolve": "^1.22.4", + "semver": "^7.5.4", + "shiki": "^1.1.2", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0", + "tsconfck": "^3.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.1", + "vite": "^5.1.4", + "vitefu": "^0.2.5", + "which-pm": "^2.1.1", + "yargs-parser": "^21.1.1", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.22.4" + }, + "bin": { + "astro": "astro.js" + }, + "engines": { + "node": ">=18.14.1", + "npm": ">=6.14.0" }, + "optionalDependencies": { + "sharp": "^0.32.6" + } + }, + "node_modules/astro-expressive-code": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.30.1.tgz", + "integrity": "sha512-Dr3VbK4HvIXTT8rsvd8PuRW4uZOpfRz9J8noVSSxmx7/M7o73SBtqauBYvxXpGHnagTJPGzYOa9BQS7jDHNUVw==", + "dependencies": { + "remark-expressive-code": "^0.30.1" + }, + "peerDependencies": { + "astro": "^3.3.0 || ^4.0.0-beta" + } + }, + "node_modules/astro/node_modules/@astrojs/markdown-remark": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-4.3.2.tgz", + "integrity": "sha512-4Oa4VaYiBd0MatB+rWIU/0A8pZH/sK3c2QkRYb+OO2lPl+qzevJtWaZY8hAQc4qurIOlRdn6B6ofDAGhWw+DSg==", + "dependencies": { + "@astrojs/prism": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-from-html": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "import-meta-resolve": "^4.0.0", + "mdast-util-definitions": "^6.0.0", + "rehype-raw": "^7.0.0", + "rehype-stringify": "^10.0.0", + "remark-gfm": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "remark-smartypants": "^2.0.0", + "shiki": "^1.1.2", + "unified": "^11.0.4", + "unist-util-remove-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.1" + } + }, + "node_modules/astro/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=0.4.0" + "node": ">=12" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node_modules/astro/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dependencies": { - "string-width": "^4.1.0" + "node_modules/astro/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/ansi-align/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/astro/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/ansi-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/ansi-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "node_modules/astro/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/ansi-align/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "node_modules/astro/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/astro/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, + "node_modules/astro/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "node_modules/astro/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/astro/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } }, - "node_modules/array-iterate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", - "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/astro/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/astring": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", - "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", - "bin": { - "astring": "bin/astring" + "node_modules/astro/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/astro": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/astro/-/astro-4.0.6.tgz", - "integrity": "sha512-P7CfFqWKzkJozzF6IoOC6qoI2ONndV8P3ULhGDgMiXPL7xVkWI5haTBSpyrcjBx643tVXspIRsSV/v+Cx+CjGw==", - "dependencies": { - "@astrojs/compiler": "^2.3.4", - "@astrojs/internal-helpers": "0.2.1", - "@astrojs/markdown-remark": "4.0.1", - "@astrojs/telemetry": "3.0.4", - "@babel/core": "^7.23.3", - "@babel/generator": "^7.23.3", - "@babel/parser": "^7.23.3", - "@babel/plugin-transform-react-jsx": "^7.22.5", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "@types/babel__core": "^7.20.4", - "acorn": "^8.11.2", - "boxen": "^7.1.1", - "chokidar": "^3.5.3", - "ci-info": "^4.0.0", - "clsx": "^2.0.0", - "common-ancestor-path": "^1.0.1", - "cookie": "^0.6.0", - "debug": "^4.3.4", - "deterministic-object-hash": "^2.0.1", - "devalue": "^4.3.2", - "diff": "^5.1.0", - "dlv": "^1.1.3", - "dset": "^3.1.3", - "es-module-lexer": "^1.4.1", - "esbuild": "^0.19.6", - "estree-walker": "^3.0.3", - "execa": "^8.0.1", - "fast-glob": "^3.3.2", - "flattie": "^1.1.0", - "github-slugger": "^2.0.0", - "gray-matter": "^4.0.3", - "html-escaper": "^3.0.3", - "http-cache-semantics": "^4.1.1", - "js-yaml": "^4.1.0", - "kleur": "^4.1.4", - "magic-string": "^0.30.3", - "mdast-util-to-hast": "13.0.2", - "mime": "^3.0.0", - "ora": "^7.0.1", - "p-limit": "^5.0.0", - "p-queue": "^7.4.1", - "path-to-regexp": "^6.2.1", - "preferred-pm": "^3.1.2", - "probe-image-size": "^7.2.3", - "prompts": "^2.4.2", - "rehype": "^13.0.1", - "resolve": "^1.22.4", - "semver": "^7.5.4", - "server-destroy": "^1.0.1", - "shikiji": "^0.6.13", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0", - "tsconfck": "^3.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.1", - "vite": "^5.0.0", - "vitefu": "^0.2.5", - "which-pm": "^2.1.1", - "yargs-parser": "^21.1.1", - "zod": "^3.22.4" - }, - "bin": { - "astro": "astro.js" - }, + "node_modules/astro/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18.14.1", - "npm": ">=6.14.0" - }, - "optionalDependencies": { - "sharp": "^0.32.5" + "node": ">=12" } }, - "node_modules/astro-expressive-code": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/astro-expressive-code/-/astro-expressive-code-0.30.1.tgz", - "integrity": "sha512-Dr3VbK4HvIXTT8rsvd8PuRW4uZOpfRz9J8noVSSxmx7/M7o73SBtqauBYvxXpGHnagTJPGzYOa9BQS7jDHNUVw==", - "dependencies": { - "remark-expressive-code": "^0.30.1" - }, - "peerDependencies": { - "astro": "^3.3.0 || ^4.0.0-beta" + "node_modules/astro/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/astro/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, + "node_modules/astro/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.2.tgz", + "integrity": "sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/astro/node_modules/@types/node": { - "version": "20.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", - "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", "optional": true, "peer": true, "dependencies": { @@ -2213,9 +3516,12 @@ "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, "node_modules/astro/node_modules/rollup": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", - "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz", + "integrity": "sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==", + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -2224,19 +3530,21 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.1", - "@rollup/rollup-android-arm64": "4.9.1", - "@rollup/rollup-darwin-arm64": "4.9.1", - "@rollup/rollup-darwin-x64": "4.9.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.1", - "@rollup/rollup-linux-arm64-gnu": "4.9.1", - "@rollup/rollup-linux-arm64-musl": "4.9.1", - "@rollup/rollup-linux-riscv64-gnu": "4.9.1", - "@rollup/rollup-linux-x64-gnu": "4.9.1", - "@rollup/rollup-linux-x64-musl": "4.9.1", - "@rollup/rollup-win32-arm64-msvc": "4.9.1", - "@rollup/rollup-win32-ia32-msvc": "4.9.1", - "@rollup/rollup-win32-x64-msvc": "4.9.1", + "@rollup/rollup-android-arm-eabi": "4.13.2", + "@rollup/rollup-android-arm64": "4.13.2", + "@rollup/rollup-darwin-arm64": "4.13.2", + "@rollup/rollup-darwin-x64": "4.13.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.2", + "@rollup/rollup-linux-arm64-gnu": "4.13.2", + "@rollup/rollup-linux-arm64-musl": "4.13.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.13.2", + "@rollup/rollup-linux-riscv64-gnu": "4.13.2", + "@rollup/rollup-linux-s390x-gnu": "4.13.2", + "@rollup/rollup-linux-x64-gnu": "4.13.2", + "@rollup/rollup-linux-x64-musl": "4.13.2", + "@rollup/rollup-win32-arm64-msvc": "4.13.2", + "@rollup/rollup-win32-ia32-msvc": "4.13.2", + "@rollup/rollup-win32-x64-msvc": "4.13.2", "fsevents": "~2.3.2" } }, @@ -2256,6 +3564,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/astro/node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/astro/node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -2335,13 +3661,13 @@ } }, "node_modules/astro/node_modules/vite": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.10.tgz", - "integrity": "sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==", + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", + "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.32", - "rollup": "^4.2.0" + "esbuild": "^0.20.1", + "postcss": "^8.4.36", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" @@ -2388,6 +3714,56 @@ } } }, + "node_modules/astro/node_modules/vite/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==" + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/b4a": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", @@ -2402,6 +3778,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "node_modules/base-64": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", @@ -2457,6 +3838,14 @@ "node": ">=8" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/bl": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -2525,6 +3914,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -2767,6 +4165,18 @@ "node": ">=6" } }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, "node_modules/collapse-white-space": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", @@ -2810,6 +4220,14 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/color/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2840,6 +4258,16 @@ "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2881,6 +4309,18 @@ } ] }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2934,6 +4374,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/dedent-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz", + "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==" + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -2942,6 +4387,19 @@ "node": ">=4.0.0" } }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3289,6 +4747,11 @@ "reusify": "^1.0.4" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3337,6 +4800,38 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3350,6 +4845,67 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -3390,6 +4946,25 @@ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -3464,6 +5039,11 @@ "node": ">=4" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hast-util-from-html": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz", @@ -3600,6 +5180,18 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-parse-selector": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", @@ -3944,6 +5536,26 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-text": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.0.tgz", + "integrity": "sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -3991,6 +5603,18 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -3999,17 +5623,6 @@ "node": ">=16.17.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4038,6 +5651,15 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -4375,6 +5997,11 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4389,11 +6016,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, "node_modules/log-symbols": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", @@ -4429,6 +6051,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4448,6 +6078,28 @@ "node": ">=12" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/markdown-extensions": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", @@ -5038,6 +6690,11 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5916,6 +7573,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -5924,6 +7592,53 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -5956,30 +7671,6 @@ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, - "node_modules/needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/nlcst-to-string": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.1.tgz", @@ -5992,6 +7683,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-abi": { "version": "3.51.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", @@ -6008,11 +7708,54 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -6051,6 +7794,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -6062,6 +7816,14 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6171,26 +7933,26 @@ } }, "node_modules/p-queue": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-7.4.1.tgz", - "integrity": "sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.0.1.tgz", + "integrity": "sha512-NXzu9aQJTAzbBqOt2hwsR63ea7yvxJc0PwN/zobNAudYfb1B7R08SzB4TsLeSbUCuG467NhnoT0oO6w1qRO+BA==", "dependencies": { "eventemitter3": "^5.0.1", - "p-timeout": "^5.0.2" + "p-timeout": "^6.1.2" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-timeout": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", - "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", + "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", "engines": { - "node": ">=12" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6263,6 +8025,15 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6271,6 +8042,14 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -6383,9 +8162,9 @@ } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -6403,7 +8182,7 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -6557,16 +8336,6 @@ "node": ">=6" } }, - "node_modules/probe-image-size": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz", - "integrity": "sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==", - "dependencies": { - "lodash.merge": "^4.6.2", - "needle": "^2.5.2", - "stream-parser": "~0.3.1" - } - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -7556,6 +9325,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, "node_modules/restore-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", @@ -7666,6 +9443,20 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "3.29.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", @@ -7724,11 +9515,6 @@ } ] }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, "node_modules/sax": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", @@ -7776,10 +9562,20 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "node_modules/server-destroy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", - "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==" + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" }, "node_modules/sharp": { "version": "0.32.6", @@ -7822,6 +9618,14 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.2.1.tgz", + "integrity": "sha512-u+XW6o0vCkUNlneZb914dLO+AayEIwK5tI62WeS//R5HIXBFiYaj/Hc5xcq27Yh83Grr4JbNtUBV8W6zyK4hWg==", + "dependencies": { + "@shikijs/core": "1.2.1" + } + }, "node_modules/shikiji": { "version": "0.6.13", "resolved": "https://registry.npmjs.org/shikiji/-/shikiji-0.6.13.tgz", @@ -7924,9 +9728,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -7959,27 +9763,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stream-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", - "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", - "dependencies": { - "debug": "2" - } - }, - "node_modules/stream-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/stream-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/streamx": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", @@ -8105,6 +9888,70 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svelte": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.12.tgz", + "integrity": "sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug==", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-hmr": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", + "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte2tsx": { + "version": "0.6.27", + "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.6.27.tgz", + "integrity": "sha512-E1uPW1o6VsbRz+nUk3fznZ2lSmCITAJoNu8AYefWSvIwE2pSB01i5sId4RMbWNzfcwCQl1DcgGShCPcldl4rvg==", + "dependencies": { + "dedent-js": "^1.0.1", + "pascal-case": "^3.1.1" + }, + "peerDependencies": { + "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0", + "typescript": "^4.9.4 || ^5.0.0" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", @@ -8125,6 +9972,19 @@ "streamx": "^2.15.0" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -8144,6 +10004,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -8181,6 +10046,11 @@ } } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -8203,6 +10073,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -8237,6 +10119,36 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unist-util-find-after/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-is": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", @@ -9035,6 +10947,25 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-vitals": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.2.tgz", + "integrity": "sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9069,6 +11000,51 @@ "node": ">=4" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -9189,6 +11165,14 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", + "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "peerDependencies": { + "zod": "^3.22.4" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/docs/package.json b/docs/package.json index 4a5780129..520d3f94b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,8 +11,12 @@ }, "dependencies": { "@astrojs/starlight": "^0.15.1", + "@astrojs/svelte": "^5.2.0", + "@astrojs/vercel": "^7.5.0", "@fontsource/ibm-plex-serif": "^5.0.8", "astro": "^4.0.0", - "sharp": "^0.32.5" + "sharp": "^0.32.5", + "svelte": "^4.2.12", + "typescript": "^5.4.3" } } diff --git a/docs/src/assets/codespaces.png b/docs/src/assets/codespaces.png new file mode 100644 index 000000000..2b8e8a43c Binary files /dev/null and b/docs/src/assets/codespaces.png differ diff --git a/docs/src/assets/rxjs/49/prototype.gif b/docs/src/assets/rxjs/49/prototype.gif new file mode 100644 index 000000000..32c33528c Binary files /dev/null and b/docs/src/assets/rxjs/49/prototype.gif differ diff --git a/docs/src/components/ActionButtonFooter.astro b/docs/src/components/ActionButtonFooter.astro index 512532ffe..ccc03c221 100644 --- a/docs/src/components/ActionButtonFooter.astro +++ b/docs/src/components/ActionButtonFooter.astro @@ -6,22 +6,23 @@ import { getEntry } from 'astro:content'; const { lang } = Astro.props; const { data } = await getEntry('i18n', lang); + --- -