Explorar el Código

Modified the character selection and creation. Next is the personality.

Warafear hace 1 año
padre
commit
565b001e38
Se han modificado 26 ficheros con 1091 adiciones y 247 borrados
  1. 108 0
      .nx/cache/d/daemon.log
  2. 1 1
      .nx/cache/d/server-process.json
  3. 52 6
      src/app/character/character-creator/character-creator.component.html
  4. 56 0
      src/app/character/character-creator/character-creator.component.scss
  5. 80 5
      src/app/character/character-creator/character-creator.component.ts
  6. 25 2
      src/app/character/character-picker/character-card/character-card.component.html
  7. 74 4
      src/app/character/character-picker/character-card/character-card.component.scss
  8. 27 3
      src/app/character/character-picker/character-card/character-card.component.ts
  9. 41 11
      src/app/character/character-picker/character-picker.component.html
  10. 71 5
      src/app/character/character-picker/character-picker.component.scss
  11. 33 14
      src/app/character/character-picker/character-picker.component.ts
  12. 7 0
      src/app/character/character-picker/deletion-confirm/deletion-confirm.component.html
  13. 7 0
      src/app/character/character-picker/deletion-confirm/deletion-confirm.component.scss
  14. 23 0
      src/app/character/character-picker/deletion-confirm/deletion-confirm.component.spec.ts
  15. 27 0
      src/app/character/character-picker/deletion-confirm/deletion-confirm.component.ts
  16. 14 1
      src/app/character/character.module.ts
  17. 13 193
      src/app/journal/journal-character/class/class.component.ts
  18. 1 0
      src/assets/icons/UIIcons/delete.svg
  19. BIN
      src/assets/images/character_coming_soon.jpeg
  20. BIN
      src/assets/images/diverse.jpg
  21. BIN
      src/assets/images/female.jpg
  22. BIN
      src/assets/images/male.jpg
  23. 420 2
      src/services/class/class.service.ts
  24. 6 0
      src/services/data/data.service.ts
  25. 1 0
      src/services/modal/modal.service.ts
  26. 4 0
      src/styles.scss

+ 108 - 0
.nx/cache/d/daemon.log

@@ -462014,3 +462014,111 @@ To fix this, set a unique name for each project in a project.json inside the pro
     at async processFilesAndCreateAndSerializeProjectGraph (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:138:17)
 [NX Daemon Server] - 2023-12-27T11:41:18.263Z - Time taken for 'hash changed files from watcher' 19.6149001121521ms
 [NX Daemon Server] - 2023-12-27T11:41:18.263Z - Done responding to the client null
+[NX Daemon Server] - 2024-01-04T06:51:00.725Z - Started listening on: \\.\pipe\nx\C:\Users\chris\AppData\Local\Temp\83d14e7134fc08a15480\d.sock
+[NX Daemon Server] - 2024-01-04T06:51:00.732Z - [WATCHER]: Subscribed to changes within: c:\Softwareprojekte\DnD (native)
+[NX Daemon Server] - 2024-01-04T06:51:00.744Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-01-04T06:51:00.746Z - Closed a connection. Number of open connections: 0
+[NX Daemon Server] - 2024-01-04T06:51:00.746Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-01-04T06:51:00.748Z - [REQUEST]: Client Request for Project Graph Received
+[NX Daemon Server] - 2024-01-04T06:51:01.346Z - Error detected when recomputing project file map: The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+[NX Daemon Server] - 2024-01-04T06:51:01.346Z - [REQUEST]: Responding to the client with an error. Error when preparing serialized project graph. The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+Error: The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+    at readProjectConfigurationsFromRootMap (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:97:15)
+    at buildProjectsConfigurationsFromProjectPathsAndPlugins (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:70:19)
+    at createProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:131:129)
+    at WorkspaceContext.<anonymous> (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:82:39)
+    at getProjectConfigurationsFromContext (c:\Softwareprojekte\DnD\node_modules\nx\src\utils\workspace-context.js:26:29)
+    at _retrieveProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:81:72)
+    at retrieveProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:58:12)
+    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
+    at async processCollectedUpdatedAndDeletedFiles (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:102:34)
+    at async processFilesAndCreateAndSerializeProjectGraph (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:138:17)
+[NX Daemon Server] - 2024-01-04T06:51:01.347Z - Time taken for 'hash changed files from watcher' 51.083799839019775ms
+[NX Daemon Server] - 2024-01-04T06:51:01.348Z - Done responding to the client null
+[NX Daemon Server] - 2024-01-05T06:57:17.805Z - Started listening on: \\.\pipe\nx\C:\Users\chris\AppData\Local\Temp\83d14e7134fc08a15480\d.sock
+[NX Daemon Server] - 2024-01-05T06:57:17.809Z - [WATCHER]: Subscribed to changes within: c:\Softwareprojekte\DnD (native)
+[NX Daemon Server] - 2024-01-05T06:57:17.810Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-01-05T06:57:17.811Z - Established a connection. Number of open connections: 2
+[NX Daemon Server] - 2024-01-05T06:57:17.812Z - Closed a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-01-05T06:57:17.813Z - [REQUEST]: Client Request for Project Graph Received
+[NX Daemon Server] - 2024-01-05T06:57:18.318Z - Error detected when recomputing project file map: The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+[NX Daemon Server] - 2024-01-05T06:57:18.318Z - [REQUEST]: Responding to the client with an error. Error when preparing serialized project graph. The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+Error: The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+    at readProjectConfigurationsFromRootMap (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:97:15)
+    at buildProjectsConfigurationsFromProjectPathsAndPlugins (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:70:19)
+    at createProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:131:129)
+    at WorkspaceContext.<anonymous> (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:82:39)
+    at getProjectConfigurationsFromContext (c:\Softwareprojekte\DnD\node_modules\nx\src\utils\workspace-context.js:26:29)
+    at _retrieveProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:81:72)
+    at retrieveProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:58:12)
+    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
+    at async processCollectedUpdatedAndDeletedFiles (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:102:34)
+    at async processFilesAndCreateAndSerializeProjectGraph (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:138:17)
+[NX Daemon Server] - 2024-01-05T06:57:18.319Z - Time taken for 'hash changed files from watcher' 41.231199979782104ms
+[NX Daemon Server] - 2024-01-05T06:57:18.320Z - Done responding to the client null
+[NX Daemon Server] - 2024-01-08T06:52:32.014Z - Started listening on: \\.\pipe\nx\C:\Users\chris\AppData\Local\Temp\83d14e7134fc08a15480\d.sock
+[NX Daemon Server] - 2024-01-08T06:52:32.017Z - [WATCHER]: Subscribed to changes within: c:\Softwareprojekte\DnD (native)
+[NX Daemon Server] - 2024-01-08T07:10:37.293Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-01-08T07:10:37.295Z - Closed a connection. Number of open connections: 0
+[NX Daemon Server] - 2024-01-08T07:10:37.295Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-01-08T07:10:37.304Z - [REQUEST]: Client Request for Project Graph Received
+[NX Daemon Server] - 2024-01-08T07:10:38.186Z - Error detected when recomputing project file map: The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+[NX Daemon Server] - 2024-01-08T07:10:38.187Z - [REQUEST]: Responding to the client with an error. Error when preparing serialized project graph. The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+Error: The following projects are defined in multiple locations:
+- DnDTools: 
+  - 
+  - .
+
+To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.
+    at readProjectConfigurationsFromRootMap (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:97:15)
+    at buildProjectsConfigurationsFromProjectPathsAndPlugins (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:70:19)
+    at createProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:131:129)
+    at WorkspaceContext.<anonymous> (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:82:39)
+    at getProjectConfigurationsFromContext (c:\Softwareprojekte\DnD\node_modules\nx\src\utils\workspace-context.js:26:29)
+    at _retrieveProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:81:72)
+    at retrieveProjectConfigurations (c:\Softwareprojekte\DnD\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:58:12)
+    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
+    at async processCollectedUpdatedAndDeletedFiles (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:102:34)
+    at async processFilesAndCreateAndSerializeProjectGraph (c:\Softwareprojekte\DnD\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:138:17)
+[NX Daemon Server] - 2024-01-08T07:10:38.189Z - Time taken for 'hash changed files from watcher' 1.509899616241455ms
+[NX Daemon Server] - 2024-01-08T07:10:38.190Z - Done responding to the client null

+ 1 - 1
.nx/cache/d/server-process.json

@@ -1 +1 @@
-{"processId":16032}
+{"processId":9652}

+ 52 - 6
src/app/character/character-creator/character-creator.component.html

@@ -1,7 +1,53 @@
-<div>
-  <div>
-    <label>Name</label>
-    <input [(ngModel)]="characterName" />
-  </div>
-  <button (click)="createCharacter()">Neuen Charakter erstellen</button>
+<div class="creation-container">
+  <form class="form-box">
+    <h3 style="text-align: center">Neuen Charakter erstellen</h3>
+    <mat-form-field appearance="outline">
+      <mat-label>Name</mat-label>
+      <input matInput [(ngModel)]="characterName" name="name" />
+    </mat-form-field>
+    <mat-form-field appearance="outline">
+      <mat-label>Volk</mat-label>
+      <mat-select [(ngModel)]="characterSpecies" name="species">
+        @for (species of species; track species) {
+        <mat-option [value]="species.value">{{ species.view }}</mat-option>
+        }
+      </mat-select>
+    </mat-form-field>
+    <mat-form-field appearance="outline">
+      <mat-label>Klasse</mat-label>
+      <mat-select [(ngModel)]="characterClass" name="class">
+        @for (characterClass of classes; track characterClass) {
+        <mat-option [value]="characterClass.value">{{
+          characterClass.view
+        }}</mat-option>
+        }
+      </mat-select>
+    </mat-form-field>
+    <mat-form-field appearance="outline">
+      <mat-label>Hintergrund</mat-label>
+      <mat-select [(ngModel)]="characterBackground" name="background">
+        @for (background of backgrounds; track background) {
+        <mat-option [value]="background.value">{{
+          background.view
+        }}</mat-option>
+        }
+      </mat-select>
+    </mat-form-field>
+    <mat-form-field appearance="outline">
+      <mat-label>Geschlecht</mat-label>
+      <mat-select [(ngModel)]="characterGender" name="gender">
+        @for (gender of genders; track gender) {
+        <mat-option [value]="gender.value">{{ gender.view }}</mat-option>
+        }
+      </mat-select>
+    </mat-form-field>
+    <div class="button-row">
+      <button class="create-button" (click)="createCharacter()">
+        Erstellen
+      </button>
+      <button class="cancel-button" [routerLink]="'character/picker'">
+        Abbrechen
+      </button>
+    </div>
+  </form>
 </div>

+ 56 - 0
src/app/character/character-creator/character-creator.component.scss

@@ -0,0 +1,56 @@
+.creation-container {
+    background-color: var(--background-color);
+    background-size: cover;
+    height: 100%;
+    width: 100%;
+    padding-top: 3rem;
+    // display: flex;
+}
+
+.form-box {
+    padding: 1rem;
+    margin: auto;
+    width: 800px;
+    border: 1px solid var(--border-color);
+    background-color: var(--secondary-color-light);
+    box-shadow: var(--shadow);
+    border-radius: 10px;
+    display: flex;
+    flex-direction: column;
+    gap: 1rem;
+}
+
+@mixin button {
+    color: black;
+    border: none;
+    border-radius: 10px;
+    box-shadow: var(--shadow);
+    height: 4rem;
+    width: 12rem;
+    font-size: 1.125rem;
+    font-weight: 600;
+    transition: all 0.2s ease-in-out;
+}
+
+.button-row {
+    display: flex;
+    justify-content: space-around;
+    margin-top: 1rem;
+}
+.cancel-button {
+    background: var(--delete);
+    @include button;
+    &:hover {
+        background: var(--delete-hover);
+        scale: 1.03;
+    }
+}
+
+.create-button {
+    background: var(--accept);
+    @include button;
+    &:hover {
+        background: var(--accept-hover);
+        scale: 1.03;
+    }
+}

+ 80 - 5
src/app/character/character-creator/character-creator.component.ts

@@ -2,20 +2,87 @@ import { Component } from '@angular/core';
 import { DataService } from 'src/services/data/data.service';
 import { Router } from '@angular/router';
 
+interface characterData {
+  view: string;
+  value: string;
+}
+
 @Component({
   selector: 'app-character-creator',
   templateUrl: './character-creator.component.html',
   styleUrls: ['./character-creator.component.scss'],
 })
 export class CharacterCreatorComponent {
+  selectedValue: string = '';
+
+  // TODO: Implement the species
+  public species: characterData[] = [
+    { view: 'Mensch', value: 'human' },
+    { view: 'Zwerg', value: 'dwarf' },
+    { view: 'Elf', value: 'elf' },
+    { view: 'Halbelf', value: 'halfelf' },
+    { view: 'Halbling', value: 'halfling' },
+    { view: 'Gnom', value: 'gnome' },
+    { view: 'Halbork', value: 'halforc' },
+    { view: 'Tiefling', value: 'tiefling' },
+  ];
+
+  // TODO: Implement the classes
+  public classes: characterData[] = [
+    { view: 'Barbar', value: 'barbarian' },
+    { view: 'Barde', value: 'bard' },
+    { view: 'Druide', value: 'druid' },
+    { view: 'Hexenmeister', value: 'warlock' },
+    { view: 'Kämpfer', value: 'fighter' },
+    { view: 'Kleriker', value: 'cleric' },
+    { view: 'Magier', value: 'wizard' },
+    { view: 'Mönch', value: 'monk' },
+    { view: 'Paladin', value: 'paladin' },
+    { view: 'Schurke', value: 'rogue' },
+    { view: 'Waldläufer', value: 'ranger' },
+    { view: 'Zauberer', value: 'sorcerer' },
+  ];
+
+  public backgrounds: characterData[] = [
+    { view: 'Akolyth', value: 'acolyte' },
+    { view: 'Scharlatan', value: 'charlatan' },
+    { view: 'Edelmann', value: 'noble' },
+    { view: 'Entertainer', value: 'entertainer' },
+    { view: 'Folk Held', value: 'folkHero' },
+    { view: 'Gelehrter', value: 'sage' },
+    { view: 'Gladiator', value: 'gladiator' },
+    { view: 'Gildenhändler', value: 'guildArtisan' },
+    { view: 'Gildehandwerker', value: 'guildMerchant' },
+    { view: 'Herumtreiber', value: 'outlander' },
+    { view: 'Krimineller', value: 'criminal' },
+    { view: 'Künstler', value: 'artist' },
+    { view: 'Marine', value: 'sailor' },
+    { view: 'Scharlatan', value: 'charlatan' },
+    { view: 'Soldat', value: 'soldier' },
+    { view: 'Stadtwache', value: 'cityWatch' },
+    { view: 'Urchin', value: 'urchin' },
+  ];
+
+  public genders: characterData[] = [
+    { view: 'Weiblich', value: 'female' },
+    { view: 'Männlich', value: 'male' },
+    { view: 'Divers', value: 'diverse' },
+  ];
+
+  public characterName: string = '';
+  public characterClass: string = '';
+  public characterSpecies: string = '';
+  public characterBackground: string = '';
+  public characterGender: string = '';
+
   public constructor(
     public dataAccessor: DataService,
     private Router: Router
   ) {}
 
-  public characterName: string = '';
-
   public async createCharacter(): Promise<void> {
+    console.log(this.characterName);
+
     // Creates a new entry in the character collection
     this.dataAccessor.addData('characters', { name: this.characterName });
     // Creates a new collection with the character name
@@ -34,12 +101,20 @@ export class CharacterCreatorComponent {
       this.dataAccessor.addData(
         this.characterName,
         {
-          class: '',
+          class: this.characterClass,
           subclass: '',
-          race: '',
-          background: '',
+          race: this.characterSpecies,
+          background: this.characterBackground,
           level: 1,
           experience: 0,
+          image: '',
+          gender: this.characterGender,
+          age: '',
+          height: '',
+          weight: '',
+          eyes: '',
+          skin: '',
+          hair: '',
         },
         'characterData'
       ),

+ 25 - 2
src/app/character/character-picker/character-card/character-card.component.html

@@ -1,3 +1,26 @@
-<div class="character-card">
-  <div class="character-card__name">{{ character }}</div>
+<div class="character-card" (click)="selectCharacter()">
+  <div
+    class="delete-area"
+    (click)="deleteCharacter(); $event.stopPropagation()"
+  >
+    <img
+      style="width: 50%"
+      src="assets/icons/UIIcons/delete.svg"
+      alt="Delete Button"
+    />
+  </div>
+  <!-- The characterData is not loaded initially, so this is a workaround. Maybe add a resolver first -->
+  @if(characterData.gender){
+  <img
+    [src]="'assets/images/' + characterData.gender + '.jpg'"
+    alt="character"
+  />
+  }
+  <div class="content">
+    <div class="name">{{ character }}</div>
+    <div class="level">Stufe {{ characterData.level }}</div>
+    <div class="species">{{ characterData.race }}</div>
+    <div class="class">{{ characterData.class }}</div>
+    <div class="subclass">{{ characterData.class }}</div>
+  </div>
 </div>

+ 74 - 4
src/app/character/character-picker/character-card/character-card.component.scss

@@ -1,6 +1,76 @@
-.character-card{
-    width: 30vw;
-    height: 30vh;
+.character-card {
+    width: 35rem;
+    height: 20rem;
     border-radius: 10px;
     box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
-}
+    display: flex;
+    overflow: hidden;
+    position: relative;
+    background-color: var(--field-background-color);
+    box-shadow: var(--shadow);
+    position: relative;
+    &:hover {
+        filter: brightness(0.9);
+        .delete-area {
+            width: 5rem;
+        }
+        .content {
+            margin: 1rem 0.25rem 0 0.25rem;
+            transition: all 0.2s ease-in-out;
+        }
+    }
+    transition: all 0.2s ease-in-out;
+}
+
+.delete-area {
+    height: 20rem;
+    width: 0rem;
+    background-color: var(--delete);
+    transition: all 0.2s ease-in-out;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    &:hover {
+        background-color: var(--delete-hover);
+    }
+}
+
+img {
+    width: 20rem;
+    height: 20rem;
+}
+
+.content {
+    width: 15rem;
+    margin: 1rem;
+}
+
+.name {
+    font-size: 1.75rem;
+    font-weight: 600;
+    text-align: center;
+}
+
+.level {
+    position: absolute;
+    right: 0.5rem;
+    bottom: 8rem;
+}
+
+.species {
+    position: absolute;
+    right: 0.5rem;
+    bottom: 6rem;
+}
+
+.class {
+    position: absolute;
+    right: 0.5rem;
+    bottom: 4rem;
+}
+
+.subclass {
+    position: absolute;
+    right: 0.5rem;
+    bottom: 2rem;
+}

+ 27 - 3
src/app/character/character-picker/character-card/character-card.component.ts

@@ -1,11 +1,35 @@
-import { Component, Input } from '@angular/core';
-import { Character } from 'src/interfaces/character';
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { DataService } from 'src/services/data/data.service';
 
 @Component({
-  selector: 'app-character-card',
+  selector: 'character-card',
   templateUrl: './character-card.component.html',
   styleUrls: ['./character-card.component.scss'],
 })
 export class CharacterCardComponent {
   @Input() character: string = '';
+  @Output() delete: EventEmitter<string> = new EventEmitter<string>();
+  @Output() select: EventEmitter<string> = new EventEmitter<string>();
+  public characterData: any = {};
+
+  constructor(private dataAccessor: DataService) {}
+
+  ngOnInit() {
+    this.dataAccessor
+      .getData(this.character, 'characterData')
+      .then((characterData: any) => {
+        this.characterData = characterData;
+        console.log(this.characterData);
+      });
+  }
+
+  public deleteCharacter(): void {
+    this.delete.emit();
+    // console.warn('Delete character: ' + this.character);
+  }
+
+  public selectCharacter(): void {
+    this.select.emit();
+    // console.warn('Select character: ' + this.character);
+  }
 }

+ 41 - 11
src/app/character/character-picker/character-picker.component.html

@@ -1,13 +1,43 @@
-<div class="charater-picker-page">
-  <div class="character-card-container">
-    <ng-container *ngFor="let character of characters">
-      <app-character-card
-        [character]="character"
-        (click)="selectCharacter(character)"
-      ></app-character-card>
-    </ng-container>
+<div class="header">
+  <h1>DND-TOOLS</h1>
+</div>
+<div class="character-card-container">
+  @for (card of [0,1,2,3,4,5]; track card){ @if(characters[card]){
+  <character-card
+    [character]="characters[card].name"
+    (select)="selectCharacter(characters[card])"
+    (delete)="open(content, card)"
+  ></character-card>
+  }@else {
+  <div class="card-placeholder" (click)="addCharacter()">
+    <!-- <icon [size]="'l'" [type]="'UI'" [icon]="'add'"></icon> -->
+    <img
+      src="assets/icons/UIIcons/add.svg"
+      style="width: 6%"
+      alt="Add Button"
+    />
   </div>
-
-  <button (click)="addCharacter()">Add Character</button>
-  <button (click)="getCharacters()">Print Characters</button>
+  } }
 </div>
+
+<ng-template #content let-modal>
+  <div class="modal-header">
+    <h4 class="modal-title" id="modal-basic-title">Charakter löschen</h4>
+    <button
+      type="button"
+      class="btn-close"
+      aria-label="Close"
+      (click)="modal.dismiss('dismiss')"
+    ></button>
+  </div>
+  <div class="modal-body">
+    Möchest du <b>{{ currentCharacter }}</b> unwiderruflich löschen?
+  </div>
+  <div class="modal-footer">
+    <div class="button-row">
+      <button class="delete-button" (click)="modal.dismiss('delete')">
+        Löschen
+      </button>
+    </div>
+  </div>
+</ng-template>

+ 71 - 5
src/app/character/character-picker/character-picker.component.scss

@@ -1,10 +1,76 @@
+// HEADER
+.header {
+    background-color: var(--header);
+    height: 8rem;
+    box-shadow: var(--shadow);
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+::ng-deep body {
+    background-color: var(--background-color);
+}
+
+// CARDS
+
 .character-card-container {
     display: flex;
     flex-direction: row;
-    align-items: center;
+    justify-content: space-evenly;
     flex-wrap: wrap;
-    column-gap: 2.5vw;
-    row-gap: 2.5vh;
+    padding-top: 2.5rem;
+    row-gap: 2.5rem;
+    overflow: auto;
+    height: calc(100% - 8rem);
+    background-color: var(--background-color);
+}
+
+character-card {
+    cursor: pointer;
+    max-height: 20rem;
+}
+
+.card-placeholder {
+    height: 20rem;
+    width: 35rem;
+    background-color: lightgrey;
+    border-radius: 10px;
+    box-shadow: var(--shadow);
+    display: flex;
     justify-content: center;
-    width: 100%;
-}
+    align-items: center;
+    font-size: 1.5rem;
+    font-weight: 600;
+    transition: all 0.2s ease-in-out;
+    &:hover {
+        background-color: rgb(191, 191, 191);
+    }
+}
+
+@mixin button {
+    color: black;
+    border: none;
+    border-radius: 10px;
+    box-shadow: var(--shadow);
+    height: 4rem;
+    width: 10rem;
+    font-size: 1.125rem;
+    font-weight: 600;
+    transition: all 0.2s ease-in-out;
+}
+
+.button-row {
+    display: flex;
+    justify-content: space-around;
+    margin-top: 1rem;
+}
+.delete-button {
+    background: var(--delete);
+    @include button;
+    &:hover {
+        background: var(--delete-hover);
+        scale: 1.03;
+    }
+}

+ 33 - 14
src/app/character/character-picker/character-picker.component.ts

@@ -1,7 +1,7 @@
-import { Component } from '@angular/core';
+import { Component, inject, TemplateRef } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
 import { DataService } from 'src/services/data/data.service';
 import { Router } from '@angular/router';
-import { Character } from 'src/interfaces/character';
 
 @Component({
   selector: 'app-character-picker',
@@ -9,18 +9,13 @@ import { Character } from 'src/interfaces/character';
   styleUrls: ['./character-picker.component.scss'],
 })
 export class CharacterPickerComponent {
-  public constructor(public dataService: DataService, private Router: Router) {
-    this.getCharacters();
-  }
+  public characters: any[] = [];
+  public currentCharacter: string = '';
+  private modalService = inject(NgbModal);
 
-  public characters: string[] = [];
-  public index = 0;
-
-  public getCharacters() {
+  public constructor(public dataService: DataService, private Router: Router) {
     this.dataService.getCollection('characters').then((characters: any) => {
-      characters.forEach((character: any) => {
-        this.characters.push(character.name);
-      });
+      this.characters = characters;
     });
   }
 
@@ -28,8 +23,32 @@ export class CharacterPickerComponent {
     this.Router.navigate(['character/creator']);
   }
 
-  public selectCharacter(character: string) {
-    sessionStorage.setItem('characterName', character);
+  open(content: TemplateRef<any>, index: number) {
+    this.currentCharacter = this.characters[index].name;
+    this.modalService
+      .open(content, { ariaLabelledBy: 'modal-basic-title' })
+      .result.then(
+        (result) => {},
+        (reason) => {
+          if (reason == 'delete') {
+            this.deleteCharacter(index);
+          }
+        }
+      );
+  }
+
+  public deleteCharacter(index: number) {
+    this.characters.splice(index, 1);
+    this.dataService.deleteCollection(this.currentCharacter);
+    this.dataService.deleteCollection('characters');
+    setTimeout(() => {
+      this.dataService.setCollection('characters', this.characters);
+    }, 1000);
+  }
+
+  public selectCharacter(character: any) {
+    console.log(character);
+    sessionStorage.setItem('characterName', character.name);
     this.Router.navigate(['journal']);
   }
 }

+ 7 - 0
src/app/character/character-picker/deletion-confirm/deletion-confirm.component.html

@@ -0,0 +1,7 @@
+<div class="modal-dimensions">
+  Wollen Sie {{ name }} endgültig löschen?
+
+  <button (click)="delete()">Ja</button>
+
+  <button (click)="cancel()">Nein</button>
+</div>

+ 7 - 0
src/app/character/character-picker/deletion-confirm/deletion-confirm.component.scss

@@ -0,0 +1,7 @@
+.modal-dimensions {
+    width: 15rem;
+    background-color: var(--modal-background);
+    border-radius: 10px;
+    border: 1px solid var(--border-color);
+    padding: 1rem;
+}

+ 23 - 0
src/app/character/character-picker/deletion-confirm/deletion-confirm.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DeletionConfirmComponent } from './deletion-confirm.component';
+
+describe('DeletionConfirmComponent', () => {
+  let component: DeletionConfirmComponent;
+  let fixture: ComponentFixture<DeletionConfirmComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [DeletionConfirmComponent]
+    })
+    .compileComponents();
+    
+    fixture = TestBed.createComponent(DeletionConfirmComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 27 - 0
src/app/character/character-picker/deletion-confirm/deletion-confirm.component.ts

@@ -0,0 +1,27 @@
+import { Component, Input } from '@angular/core';
+import { ModalService } from 'src/services/modal/modal.service';
+
+@Component({
+  selector: 'deletion-confirm',
+  templateUrl: './deletion-confirm.component.html',
+  styleUrl: './deletion-confirm.component.scss',
+})
+export class DeletionConfirmComponent {
+  @Input() name: string = '';
+
+  public constructor(private modalAccessor: ModalService) {}
+
+  ngOnInit() {
+    console.log('DeletionConfirmComponent initialized');
+  }
+
+  // RESPONSES
+
+  public cancel(): void {
+    this.modalAccessor.handleModalClosing('cancel', undefined);
+  }
+
+  public delete(): void {
+    this.modalAccessor.handleModalClosing('add', undefined);
+  }
+}

+ 14 - 1
src/app/character/character.module.ts

@@ -1,23 +1,36 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { CharacterRoutingModule } from './character-routing.module';
 import { CharacterPickerComponent } from './character-picker/character-picker.component';
 import { CharacterCreatorComponent } from './character-creator/character-creator.component';
 import { CharacterCardComponent } from './character-picker/character-card/character-card.component';
 import { MatSlideToggleModule } from '@angular/material/slide-toggle';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { DeletionConfirmComponent } from './character-picker/deletion-confirm/deletion-confirm.component';
 
 @NgModule({
   declarations: [
     CharacterPickerComponent,
     CharacterCreatorComponent,
     CharacterCardComponent,
+    DeletionConfirmComponent,
   ],
   imports: [
     CommonModule,
     CharacterRoutingModule,
     FormsModule,
+    ReactiveFormsModule,
     MatSlideToggleModule,
+    MatIconModule,
+    MatInputModule,
+    MatFormFieldModule,
+    MatSelectModule,
+    MatAutocompleteModule,
   ],
 })
 export class CharacterModule {}

+ 13 - 193
src/app/journal/journal-character/class/class.component.ts

@@ -1,4 +1,6 @@
 import { Component } from '@angular/core';
+import { ClassService } from 'src/services/class/class.service';
+import { DataService } from 'src/services/data/data.service';
 
 @Component({
   selector: 'class',
@@ -6,197 +8,15 @@ import { Component } from '@angular/core';
   styleUrl: './class.component.scss',
 })
 export class ClassComponent {
-  public class = {
-    title: 'Kämpfer',
-    description: `
-    Fighters share an unparalleled mastery with weapons and armor, and a thorough knowledge of the skills of combat. They are well acquainted with death, both meting it out and staring it defiantly in the face.
-
-
-    ### Class Features
-
-    As a fighter, you gain the following class features.
-
-    #### Hit Points
-
-    **Hit Dice:** 1d10 per fighter level
-    
-    **Hit Points at 1st Level:** 10 + your Constitution modifier
-    
-    **Hit Points at Higher Levels:** 1d10 (or 6) + your Constitution modifier per fighter level after 1st
-
-    #### Proficiencies
-    **Armor:** All armor, shields
-
-    **Weapons:** Simple weapons, martial weapons
-
-    **Tools:** None
-
-    **Saving Throws:** Strength, Constitution
-
-    **Skills:** Choose two skills from Acrobatics, Animal Handling, Athletics, History, Insight, Intimidation, Perception, and Survival
-
-    #### Equipment
-    - (a) chain mail or (b) leather, longbow, and 20 arrows
-    - (a) a martial weapon and a shield or (b) two martial weapons
-    - (a) a light crossbow and 20 bolts or (b) two handaxes
-    - (a) a dungeoneer's pack or (b) an explorer's pack
-    `,
-    features: [
-      {
-        name: 'Fighting Style',
-        level: 1,
-        description: `
-
-      You adopt a particular style of fighting as your specialty. Choose one of the following options. You can't take a Fighting Style option more than once, even if you later get to choose again.
-
-      - Archery (PHB). You gain a +2 bonus to attack rolls you make with ranged weapons.
-      - Blind Fighting (TCE). You have blindsight with a range of 10 feet. Within that range, you can effectively see anything that isn't behind total cover, even if you're blinded or in darkness. Moreover, you can see an invisible creature within that range, unless the creature successfully hides from you.
-      - Defense (PHB). While you are wearing armor, you gain a +1 bonus to AC.
-      - Dueling (PHB). When you are wielding a melee weapon in one hand and no other weapons, you gain a +2 bonus to damage rolls with that weapon.
-      - Great Weapon Fighting (PHB). When you roll a 1 or 2 on a damage die for an attack you make with a melee weapon that you are wielding with two hands, you can reroll the die and must use the new roll, even if the new roll is a 1 or a 2. The weapon must have the two-handed or versatile property for you to gain this benefit.
-      - Interception (TCE). When a creature you can see hits a target, other than you, within 5 feet of you with an attack, you can use your reaction to reduce the damage the target takes by 1d10 + your proficiency bonus (to a minimum of 0 damage). You must be wielding a shield or a simple or martial weapon to use this reaction.
-      - Protection (PHB). When a creature you can see attacks a target other than you that is within 5 feet of you, you can use your reaction to impose disadvantage on the attack roll. You must be wielding a shield.
-      - Superior Technique (TCE). You learn one maneuver of your choice from among those available to the Battle Master archetype. If a maneuver you use requires your target to make a saving throw to resist the maneuver's effects, the saving throw DC equals 8 + your proficiency bonus + your Strength or Dexterity modifier (your choice.)
-      - You gain one superiority die, which is a d6 (this die is added to any superiority dice you have from another source). This die is used to fuel your maneuvers. A superiority die is expended when you use it. You regain your expended superiority dice when you finish a short or long rest.
-      - Thrown Weapon Fighting (TCE). You can draw a weapon that has the thrown property as part of the attack you make with the weapon.
-      - In addition, when you hit with a ranged attack using a thrown weapon, you gain a +2 bonus to the damage roll.
-      - Two-Weapon Fighting (PHB). When you engage in two-weapon fighting, you can add your ability modifier to the damage of the second attack.
-      - Unarmed Fighting (TCE). Your unarmed strikes can deal bludgeoning damage equal to 1d6 + your Strength modifier on a hit. If you aren't wielding any weapons or a shield when you make the attack roll, the d6 becomes a d8.
-      - At the start of each of your turns, you can deal 1d4 bludgeoning damage to one creature grappled by you.
-      - Close Quarters Shooter (UA). When making a ranged attack while you are within 5 feet of a hostile creature, you do not have disadvantage on the attack roll. Your ranged attacks ignore half cover and three-quarters cover against targets within 30 feet of you. You have a +1 bonus to attack rolls on ranged attacks.
-      - Mariner (UA). As long as you are not wearing heavy armor or using a shield, you have a swimming speed and a climbing speed equal to your normal speed, and you gain a +1 bonus to armor class.
-      - Tunnel Fighter (UA). As a bonus action, you can enter a defensive stance that lasts until the start of your next turn. While in your defensive stance, you can make opportunity attacks without using your reaction, and you can use your reaction to make a melee attack against a creature that moves more than 5 feet while within your reach.
-      
-      `,
-      },
-      {
-        name: 'Second Wind',
-        level: 1,
-        description: `
-          You have a limited well of stamina that you can draw on to protect yourself from harm. On your turn, you can use a bonus action to regain hit points equal to 1d10 + your fighter level.
-
-          Once you use this feature, you must finish a short or long rest before you can use it again.
-      
-        `,
-      },
-      {
-        name: 'Action Surge',
-        level: 2,
-        description: `
-          Starting at 2nd level, you can push yourself beyond your normal limits for a moment. On your turn, you can take one additional action.
-
-          Once you use this feature, you must finish a short or long rest before you can use it again. Starting at 17th level, you can use it twice before a rest, but only once on the same turn.
-      
-        `,
-      },
-      {
-        name: 'Martial Archetype',
-        level: 3,
-        description: `
-          At 3rd level, you choose an archetype that you strive to emulate in your combat styles and techniques. The archetype you choose grants you features at 3rd level and again at 7th, 10th, 15th, and 18th level.    
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 4,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Extra Attack',
-        level: 5,
-        description: `
-          Beginning at 5th level, you can attack twice, instead of once, whenever you take the Attack action on your turn.
-
-          The number of attacks increases to three when you reach 11th level in this class and to four when you reach 20th level in this class.    
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 6,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 8,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Indomitable',
-        level: 9,
-        description: `
-          Beginning at 9th level, you can reroll a saving throw that you fail. If you do so, you must use the new roll, and you can't use this feature again until you finish a long rest.  
-        `,
-      },
-      {
-        name: 'Extra Attack (x3)',
-        level: 11,
-        description: `
-          You can now attack thrice whenever you take the Attack action on your turn.   
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 12,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Indomitable (x2)',
-        level: 13,
-        description: `
-          You can reroll a saving throw that you fail. If you do so, you must use the new roll, and you can't use this feature again until you finish a long rest. You can now use this feature twice between long rests.  
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 14,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 16,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Indomitable (x3)',
-        level: 17,
-        description: `
-          You can reroll a saving throw that you fail. If you do so, you must use the new roll, and you can't use this feature again until you finish a long rest. You can now use this feature thrice between long rests.  
-        `,
-      },
-      {
-        name: 'Action Surge (x2)',
-        level: 17,
-        description: `
-          Starting at 17th level, you can use it twice before a rest, but only once on the same turn.
-      
-        `,
-      },
-      {
-        name: 'Ability Score Improvement',
-        level: 19,
-        description: `
-          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
-        `,
-      },
-      {
-        name: 'Extra Attack (x4)',
-        level: 20,
-        description: `
-          You can now attack four times whenever you take the Attack action on your turn. 
-        `,
-      },
-    ],
-  };
+  public className: string = '';
+  public class: any;
+  public constructor(
+    private classAccessor: ClassService,
+    private dataAccessor: DataService
+  ) {}
+
+  public ngOnInit(): void {
+    this.className = this.dataAccessor.characterData.class;
+    this.class = this.classAccessor.getClassDetails(this.className);
+  }
 }

+ 1 - 0
src/assets/icons/UIIcons/delete.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>

BIN
src/assets/images/character_coming_soon.jpeg


BIN
src/assets/images/diverse.jpg


BIN
src/assets/images/female.jpg


BIN
src/assets/images/male.jpg


+ 420 - 2
src/services/class/class.service.ts

@@ -1,9 +1,427 @@
 import { Injectable } from '@angular/core';
 
 @Injectable({
-  providedIn: 'root'
+  providedIn: 'root',
 })
 export class ClassService {
+  constructor() {}
 
-  constructor() { }
+  // FUNCTIONS
+
+  public getClassDetails(className: string): any {
+    switch (className) {
+      case 'fighter':
+        return this.fighter;
+      case 'barbarian':
+        return this.barbarian;
+      case 'cleric':
+        return this.cleric;
+      default:
+        throw new Error('DND-Error: Class not found in class.service.ts');
+    }
+  }
+
+  // CLASS DETAILS
+
+  public fighter: any = {
+    title: 'Kämpfer',
+    description: `
+    Fighters share an unparalleled mastery with weapons and armor, and a thorough knowledge of the skills of combat. They are well acquainted with death, both meting it out and staring it defiantly in the face.
+
+
+    ### Class Features
+
+    As a fighter, you gain the following class features.
+
+    #### Hit Points
+
+    **Hit Dice:** 1d10 per fighter level
+    
+    **Hit Points at 1st Level:** 10 + your Constitution modifier
+    
+    **Hit Points at Higher Levels:** 1d10 (or 6) + your Constitution modifier per fighter level after 1st
+
+    #### Proficiencies
+    **Armor:** All armor, shields
+
+    **Weapons:** Simple weapons, martial weapons
+
+    **Tools:** None
+
+    **Saving Throws:** Strength, Constitution
+
+    **Skills:** Choose two skills from Acrobatics, Animal Handling, Athletics, History, Insight, Intimidation, Perception, and Survival
+
+    #### Equipment
+    - (a) chain mail or (b) leather, longbow, and 20 arrows
+    - (a) a martial weapon and a shield or (b) two martial weapons
+    - (a) a light crossbow and 20 bolts or (b) two handaxes
+    - (a) a dungeoneer's pack or (b) an explorer's pack
+    `,
+    features: [
+      {
+        name: 'Fighting Style',
+        level: 1,
+        description: `
+
+      You adopt a particular style of fighting as your specialty. Choose one of the following options. You can't take a Fighting Style option more than once, even if you later get to choose again.
+
+      - Archery (PHB). You gain a +2 bonus to attack rolls you make with ranged weapons.
+      - Blind Fighting (TCE). You have blindsight with a range of 10 feet. Within that range, you can effectively see anything that isn't behind total cover, even if you're blinded or in darkness. Moreover, you can see an invisible creature within that range, unless the creature successfully hides from you.
+      - Defense (PHB). While you are wearing armor, you gain a +1 bonus to AC.
+      - Dueling (PHB). When you are wielding a melee weapon in one hand and no other weapons, you gain a +2 bonus to damage rolls with that weapon.
+      - Great Weapon Fighting (PHB). When you roll a 1 or 2 on a damage die for an attack you make with a melee weapon that you are wielding with two hands, you can reroll the die and must use the new roll, even if the new roll is a 1 or a 2. The weapon must have the two-handed or versatile property for you to gain this benefit.
+      - Interception (TCE). When a creature you can see hits a target, other than you, within 5 feet of you with an attack, you can use your reaction to reduce the damage the target takes by 1d10 + your proficiency bonus (to a minimum of 0 damage). You must be wielding a shield or a simple or martial weapon to use this reaction.
+      - Protection (PHB). When a creature you can see attacks a target other than you that is within 5 feet of you, you can use your reaction to impose disadvantage on the attack roll. You must be wielding a shield.
+      - Superior Technique (TCE). You learn one maneuver of your choice from among those available to the Battle Master archetype. If a maneuver you use requires your target to make a saving throw to resist the maneuver's effects, the saving throw DC equals 8 + your proficiency bonus + your Strength or Dexterity modifier (your choice.)
+      - You gain one superiority die, which is a d6 (this die is added to any superiority dice you have from another source). This die is used to fuel your maneuvers. A superiority die is expended when you use it. You regain your expended superiority dice when you finish a short or long rest.
+      - Thrown Weapon Fighting (TCE). You can draw a weapon that has the thrown property as part of the attack you make with the weapon.
+      - In addition, when you hit with a ranged attack using a thrown weapon, you gain a +2 bonus to the damage roll.
+      - Two-Weapon Fighting (PHB). When you engage in two-weapon fighting, you can add your ability modifier to the damage of the second attack.
+      - Unarmed Fighting (TCE). Your unarmed strikes can deal bludgeoning damage equal to 1d6 + your Strength modifier on a hit. If you aren't wielding any weapons or a shield when you make the attack roll, the d6 becomes a d8.
+      - At the start of each of your turns, you can deal 1d4 bludgeoning damage to one creature grappled by you.
+      - Close Quarters Shooter (UA). When making a ranged attack while you are within 5 feet of a hostile creature, you do not have disadvantage on the attack roll. Your ranged attacks ignore half cover and three-quarters cover against targets within 30 feet of you. You have a +1 bonus to attack rolls on ranged attacks.
+      - Mariner (UA). As long as you are not wearing heavy armor or using a shield, you have a swimming speed and a climbing speed equal to your normal speed, and you gain a +1 bonus to armor class.
+      - Tunnel Fighter (UA). As a bonus action, you can enter a defensive stance that lasts until the start of your next turn. While in your defensive stance, you can make opportunity attacks without using your reaction, and you can use your reaction to make a melee attack against a creature that moves more than 5 feet while within your reach.
+      
+      `,
+      },
+      {
+        name: 'Second Wind',
+        level: 1,
+        description: `
+          You have a limited well of stamina that you can draw on to protect yourself from harm. On your turn, you can use a bonus action to regain hit points equal to 1d10 + your fighter level.
+
+          Once you use this feature, you must finish a short or long rest before you can use it again.
+      
+        `,
+      },
+      {
+        name: 'Action Surge',
+        level: 2,
+        description: `
+          Starting at 2nd level, you can push yourself beyond your normal limits for a moment. On your turn, you can take one additional action.
+
+          Once you use this feature, you must finish a short or long rest before you can use it again. Starting at 17th level, you can use it twice before a rest, but only once on the same turn.
+      
+        `,
+      },
+      {
+        name: 'Martial Archetype',
+        level: 3,
+        description: `
+          At 3rd level, you choose an archetype that you strive to emulate in your combat styles and techniques. The archetype you choose grants you features at 3rd level and again at 7th, 10th, 15th, and 18th level.    
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 4,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Extra Attack',
+        level: 5,
+        description: `
+          Beginning at 5th level, you can attack twice, instead of once, whenever you take the Attack action on your turn.
+
+          The number of attacks increases to three when you reach 11th level in this class and to four when you reach 20th level in this class.    
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 6,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 8,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Indomitable',
+        level: 9,
+        description: `
+          Beginning at 9th level, you can reroll a saving throw that you fail. If you do so, you must use the new roll, and you can't use this feature again until you finish a long rest.  
+        `,
+      },
+      {
+        name: 'Extra Attack (x3)',
+        level: 11,
+        description: `
+          You can now attack thrice whenever you take the Attack action on your turn.   
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 12,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Indomitable (x2)',
+        level: 13,
+        description: `
+          You can reroll a saving throw that you fail. If you do so, you must use the new roll, and you can't use this feature again until you finish a long rest. You can now use this feature twice between long rests.  
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 14,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 16,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Indomitable (x3)',
+        level: 17,
+        description: `
+          You can reroll a saving throw that you fail. If you do so, you must use the new roll, and you can't use this feature again until you finish a long rest. You can now use this feature thrice between long rests.  
+        `,
+      },
+      {
+        name: 'Action Surge (x2)',
+        level: 17,
+        description: `
+          Starting at 17th level, you can use it twice before a rest, but only once on the same turn.
+      
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 19,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Extra Attack (x4)',
+        level: 20,
+        description: `
+          You can now attack four times whenever you take the Attack action on your turn. 
+        `,
+      },
+    ],
+  };
+
+  public barbarian: any = {
+    title: 'Barbar',
+    description: `
+    Barbarians are savage warriors who deal with their opponents through a combination of sheer brute force and terrifying rage. Their strength and ferocity make them well suited for melee combat. Barbarians are also able to wreak havoc on their enemies using unorthodox methods, such as throwing improvised weapons or even their own bodies.
+
+    ### Class Features
+
+    As a barbarian, you gain the following class features.
+
+    #### Hit Points
+
+    **Hit Dice:** 1d12 per barbarian level
+    
+    **Hit Points at 1st Level:** 12 + your Constitution modifier
+    
+    **Hit Points at Higher Levels:** 1d12 (or 7) + your Constitution modifier per barbarian level after 1st
+
+    #### Proficiencies
+    **Armor:** Light armor, medium armor, shields
+
+    **Weapons:** Simple weapons, martial weapons
+
+    **Tools:** None
+
+    **Saving Throws:** Strength, Constitution
+
+    **Skills:** Choose two skills from Animal Handling, Athletics, Intimidation, Nature, Perception, and Survival
+
+    #### Equipment
+    - (a) a greataxe or (b) any martial melee weapon
+    - (a) two handaxes or (b) any simple weapon
+    - An explorer's pack and four javelins
+    `,
+    features: [
+      {
+        name: 'Rage',
+        level: 1,
+        description: `
+          In battle, you fight with primal ferocity. On your turn, you can enter a rage as a bonus action.
+
+          While raging, you gain the following benefits if you aren't wearing heavy armor:
+
+          - You have advantage on Strength checks and Strength saving throws.
+          - When you make a melee weapon attack using Strength, you gain a bonus to the damage roll that increases as you gain levels as a barbarian, as shown in the Rage Damage column of the Barbarian table.
+          - You have resistance to bludgeoning, piercing, and slashing damage.
+          - If you are able to cast spells, you can't cast them or concentrate on them while raging.
+          - Your rage lasts for 1 minute. It ends early if you are knocked unconscious or if your turn ends and you haven't attacked a hostile creature since your last turn or taken damage since then. You can also end your rage on your turn as a bonus action.
+          - Once you have raged the number of times shown for your barbarian level in the Rages column of the Barbarian table, you must finish a long rest before you can rage again.
+        `,
+      },
+      {
+        name: 'Unarmored Defense',
+        level: 1,
+        description: `
+          While you are not wearing any armor, your Armor Class equals 10 + your Dexterity modifier + your Constitution modifier. You can use a shield and still gain this benefit.
+        `,
+      },
+      {
+        name: 'Reckless Attack',
+        level: 2,
+        description: `
+          Starting at 2nd level, you can throw aside all concern for defense to attack with fierce desperation. When you make your first attack on your turn, you can decide to attack recklessly. Doing so gives you advantage on melee weapon attack rolls using Strength during this turn, but attack rolls against you have advantage until your next turn.
+        `,
+      },
+      {
+        name: 'Danger Sense',
+        level: 2,
+        description: `
+          At 2nd level, you gain an uncanny sense of when things nearby aren't as they should be, giving you an edge when you dodge away from danger.
+
+          You have advantage on Dexterity saving throws against effects that you can see, such as traps and spells. To gain this benefit, you can't be blinded, deafened, or incapacitated.
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 4,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Extra Attack',
+        level: 5,
+        description: `
+          Beginning at 5th level, you can attack twice, instead of once, whenever you take the Attack action on your turn.
+
+          The number of attacks increases to three when you reach 11th level in this class and to four when you reach 20th level in this class.    
+        `,
+      },
+      {
+        name: 'Fast Movement',
+        level: 5,
+        description: `
+          Starting at 5th level, your speed increases by 10 feet while you aren't wearing heavy armor.
+        `,
+      },
+      {
+        name: 'Feral Instinct',
+        level: 7,
+        description: `
+          By 7th level, your instincts are so honed that you have advantage on initiative rolls.
+
+          Additionally, if you are surprised at the beginning of combat and aren't incapacitated, you can act normally on your first turn, but only if you enter your rage before doing anything else on that turn.
+        `,
+      },
+      {
+        name: 'Brutal Critical',
+        level: 9,
+        description: `
+          Beginning at 9th level, you can roll one additional weapon damage die when determining the extra damage for a critical hit with a melee attack.
+
+          This increases to two additional dice at 13th level and three additional dice at 17th level.
+        `,
+      },
+      {
+        name: 'Relentless Rage',
+        level: 11,
+        description: `
+          Starting at 11th level, your rage can keep you fighting despite grievous wounds. If you drop to 0 hit points while you're raging and don't die outright, you can make a DC 10 Constitution saving throw. If you succeed, you drop to 1 hit point instead.
+
+          Each time you use this feature after the first, the DC increases by 5. When you finish a short or long rest, the DC resets to 10.
+        `,
+      },
+      {
+        name: 'Ability Score Improvement',
+        level: 12,
+        description: `
+          When you reach 4th level, and again at 6th, 8th, 12th, 14th, 16th, and 19th level, you can increase one ability score of your choice by 2, or you can increase two ability scores of your choice by 1. As normal, you can't increase an ability score above 20 using this feature.  
+        `,
+      },
+      {
+        name: 'Persistent Rage',
+        level: 15,
+        description: `
+          Beginning at 15th level, your rage is so fierce that it ends early only if you fall unconscious or if you choose to end it.
+        `,
+      },
+      {
+        name: 'Indomitable Might',
+        level: 18,
+        description: `
+          Beginning at 18th level, if your total for a Strength check is less than your Strength score, you can use that score in place of the total.
+
+          ### Primal Champion
+
+          At 20th level, you embody the power of the wilds. Your Strength and Constitution scores increase by 4. Your maximum for those scores is now 24.
+        `,
+      },
+    ],
+  };
+
+  public cleric: any = {
+    title: 'Kleriker',
+    description: `
+    Clerics act as conduits for that power, manifesting it as miraculous effects. The gods don't grant this power to everyone who seeks it, but only to those chosen to fulfill a high calling.
+
+    ### Class Features
+
+    As a cleric, you gain the following class features.
+
+    #### Hit Points
+
+    **Hit Dice:** 1d8 per cleric level
+    
+    **Hit Points at 1st Level:** 8 + your Constitution modifier
+    
+    **Hit Points at Higher Levels:** 1d8 (or 5) + your Constitution modifier per cleric level after 1st
+
+    #### Proficiencies
+    **Armor:** Light armor, medium armor, shields
+
+    **Weapons:** Simple weapons
+
+    **Tools:** None
+
+    **Saving Throws:** Wisdom, Charisma
+
+    **Skills:** Choose two from History, Insight, Medicine, Persuasion, and Religion
+
+    #### Equipment
+    - (a) a mace or (b) a warhammer (if proficient)
+    - (a) scale mail, (b) leather armor, or (c) chain mail (if proficient)
+    - (a) a light crossbow and 20 bolts or (b) any simple weapon
+    - (a) a priest's pack or (b) an explorer's pack
+    - A shield and a holy symbol
+    `,
+    features: [
+      {
+        name: 'Spellcasting',
+        level: 1,
+        description: `
+          As a conduit for divine power, you can cast cleric spells.
+
+          Cantrips
+
+          At 1st level, you know three cantrips of your choice from the cleric spell list. You learn additional cleric cantrips of your choice at higher levels, as shown in the Cantrips Known column of the Cleric table.
+
+          Preparing and Casting Spells
+
+          The Cleric table shows how many spell slots you have to cast your cleric spells of 1st level and higher. To cast one of these spells, you must expend a slot of the spell's level or higher. You regain all expended spell slots when you finish a long rest.
+
+          You prepare the list of cleric spells that are available for you to cast, choosing from the cleric spell list. When you do so, choose a number of cleric spells equal to your Wisdom modifier + your cleric level (minimum of one spell).
+          The spells must be of a level for which you have spell slots.
+          `,
+      },
+    ],
+  };
 }

+ 6 - 0
src/services/data/data.service.ts

@@ -819,6 +819,10 @@ export class DataService {
     return this.db.collection(collection).get({ keys: true });
   }
 
+  public setCollection(collection: string, data: any) {
+    return this.db.collection(collection).set(data);
+  }
+
   public setData(key: string, data: any) {
     return this.db
       .collection(this.characterName)
@@ -828,6 +832,8 @@ export class DataService {
   }
 
   public deleteCollection(collection: string) {
+    console.log('delete collection', collection);
+
     this.db.collection(collection).delete();
   }
 

+ 1 - 0
src/services/modal/modal.service.ts

@@ -15,6 +15,7 @@ export class ModalService {
   result$ = this._resultSubject.asObservable();
 
   public openModal(component: any, data: any) {
+    console.log('ModalService: openModal');
     this._modalSubject.next({ component, data });
   }
 

+ 4 - 0
src/styles.scss

@@ -65,6 +65,10 @@
     }
 
     //
+
+    // input {
+
+    // }
     .responsive-small {
         display: none;
     }