Kaynağa Gözat

reworked dahboard

Warafear 1 yıl önce
ebeveyn
işleme
946b4fa254
28 değiştirilmiş dosya ile 951 ekleme ve 537 silme
  1. 36 0
      .nx/cache/d/daemon.log
  2. 1 1
      .nx/cache/d/server-process.json
  3. 7 5
      src/app/journal/journal-stats/ability-panel/ability-table/ability-modal/ability-modal.component.html
  4. 0 5
      src/app/journal/journal-stats/ability-panel/ability-table/ability-modal/ability-modal.component.scss
  5. 1 1
      src/app/journal/journal-stats/ability-panel/proficiencies-table/tools-modal/tools-modal.component.scss
  6. 1 1
      src/app/journal/journal-stats/ability-panel/spellslots/spellslots-modal/spellslots-modal.component.scss
  7. 6 4
      src/app/journal/journal-stats/ability-panel/trait-table/trait-modal/trait-modal.component.html
  8. 0 7
      src/app/journal/journal-stats/ability-panel/trait-table/trait-modal/trait-modal.component.scss
  9. 167 0
      src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.html
  10. 98 0
      src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.scss
  11. 23 0
      src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.spec.ts
  12. 60 0
      src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.ts
  13. 80 92
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.html
  14. 0 1
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.scss
  15. 31 83
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.ts
  16. 45 61
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-details/weapon-details.component.html
  17. 8 3
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-details/weapon-details.component.scss
  18. 252 182
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-modal/weapon-modal.component.html
  19. 81 54
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-modal/weapon-modal.component.scss
  20. 21 4
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-modal/weapon-modal.component.ts
  21. 3 1
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.html
  22. 1 1
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.scss
  23. 0 1
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.ts
  24. 4 0
      src/app/journal/journal.module.ts
  25. 15 17
      src/app/journal/spell-modal/spell-modal.component.scss
  26. 1 1
      src/app/shared-components/full-spellcard/full-spellcard.component.html
  27. 2 0
      src/interfaces/weapon.ts
  28. 7 12
      src/styles.scss

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

@@ -466855,3 +466855,39 @@ 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] - 2024-02-13T06:38:54.930Z - Time taken for 'hash changed files from watcher' 44.179800033569336ms
 [NX Daemon Server] - 2024-02-13T06:38:54.930Z - Done responding to the client null
+[NX Daemon Server] - 2024-02-13T10:42:10.357Z - Started listening on: \\.\pipe\nx\C:\Users\chris\AppData\Local\Temp\83d14e7134fc08a15480\d.sock
+[NX Daemon Server] - 2024-02-13T10:42:10.362Z - [WATCHER]: Subscribed to changes within: c:\Softwareprojekte\DnD (native)
+[NX Daemon Server] - 2024-02-13T10:42:10.363Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-02-13T10:42:10.364Z - Established a connection. Number of open connections: 2
+[NX Daemon Server] - 2024-02-13T10:42:10.364Z - Closed a connection. Number of open connections: 1
+[NX Daemon Server] - 2024-02-13T10:42:10.367Z - [REQUEST]: Client Request for Project Graph Received
+[NX Daemon Server] - 2024-02-13T10:42:10.453Z - 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-02-13T10:42:10.453Z - [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-02-13T10:42:10.453Z - Time taken for 'hash changed files from watcher' 28.785999953746796ms
+[NX Daemon Server] - 2024-02-13T10:42:10.454Z - Done responding to the client null

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

@@ -1 +1 @@
-{"processId":25548}
+{"processId":25956}

+ 7 - 5
src/app/journal/journal-stats/ability-panel/ability-table/ability-modal/ability-modal.component.html

@@ -3,33 +3,35 @@
 
   <div class="flex-form t-15">
     <div>
-      <div class="name">Name</div>
+      <div class="input-label">Name</div>
       <mat-form-field appearance="outline" class="w-50">
         <input matInput [(ngModel)]="name" />
       </mat-form-field>
     </div>
 
     <div>
-      <div class="name">Kurze Beschreibung</div>
+      <div class="input-label">Kurze Beschreibung</div>
       <div class="NgxEditor__Wrapper">
         <ngx-editor-menu [editor]="shortEditor" [toolbar]="toolbar">
         </ngx-editor-menu>
         <ngx-editor
           [editor]="shortEditor"
           [(ngModel)]="shortDescription"
+          placeholder="Kurze Beschreibung der Fähigkeit"
         ></ngx-editor>
       </div>
       <div class="hint">Wird in der Übersicht angezeigt</div>
     </div>
 
     <div>
-      <div class="name">Ausführliche Beschreibung</div>
+      <div class="input-label">Ausführliche Beschreibung</div>
       <div class="NgxEditor__Wrapper">
         <ngx-editor-menu [editor]="longEditor" [toolbar]="toolbar">
         </ngx-editor-menu>
         <ngx-editor
           [editor]="longEditor"
           [(ngModel)]="longDescription"
+          placeholder="Ausführliche Beschreibung der Fähigkeit"
         ></ngx-editor>
       </div>
       <div class="hint">Wird in der Detailansicht angezeigt</div>
@@ -37,7 +39,7 @@
 
     <div class="flex-row">
       <div class="w-100">
-        <div class="name">Kosten</div>
+        <div class="input-label">Kosten</div>
 
         <mat-form-field appearance="outline" class="w-100">
           <!-- <mat-label>Kosten</mat-label> -->
@@ -50,7 +52,7 @@
       </div>
 
       <div class="w-100">
-        <div class="name">Nutzungen</div>
+        <div class="input-label">Nutzungen</div>
         <mat-form-field appearance="outline" class="w-100">
           <!-- <mat-label>Nutzungen</mat-label> -->
           <mat-select [(ngModel)]="charges">

+ 0 - 5
src/app/journal/journal-stats/ability-panel/ability-table/ability-modal/ability-modal.component.scss

@@ -6,8 +6,3 @@
     box-shadow: var(--shadow);
     padding: 0 2rem;
 }
-
-.name {
-    font-weight: 600;
-    padding-left: 0.25rem;
-}

+ 1 - 1
src/app/journal/journal-stats/ability-panel/proficiencies-table/tools-modal/tools-modal.component.scss

@@ -1,5 +1,5 @@
 .dimensions {
-  width: 40vw;
+  width: 35rem;
   background-color: var(--modal-background);
   border-radius: 10px;
   border: 1px solid var(--border-color);

+ 1 - 1
src/app/journal/journal-stats/ability-panel/spellslots/spellslots-modal/spellslots-modal.component.scss

@@ -1,5 +1,5 @@
 .dimensions {
-    width: 40vw;
+    width: 35rem;
     background-color: var(--modal-background);
     border-radius: 10px;
     border: 1px solid var(--border-color);

+ 6 - 4
src/app/journal/journal-stats/ability-panel/trait-table/trait-modal/trait-modal.component.html

@@ -1,37 +1,39 @@
-<div class="modal-dimensions">
+<div class="dimensions">
   <div class="title">
     <h3 *ngIf="!isUpdate">Eigenschaft erstellen</h3>
     <h3 *ngIf="isUpdate">Eigenschaft anpassen</h3>
   </div>
   <div class="flex-form t-15">
     <div>
-      <div class="name">Name</div>
+      <div class="input-label">Name</div>
       <mat-form-field appearance="outline" class="w-50">
         <input matInput [(ngModel)]="name" />
       </mat-form-field>
     </div>
 
     <div>
-      <div class="name">Kurze Beschreibung</div>
+      <div class="input-label">Kurze Beschreibung</div>
       <div class="NgxEditor__Wrapper">
         <ngx-editor-menu [editor]="shortEditor" [toolbar]="toolbar">
         </ngx-editor-menu>
         <ngx-editor
           [editor]="shortEditor"
           [(ngModel)]="shortDescription"
+          placeholder="Kurze Beschreibung der Eigenschaft"
         ></ngx-editor>
       </div>
       <div class="hint">Wird in der Übersicht angezeigt</div>
     </div>
 
     <div>
-      <div class="name">Ausführliche Beschreibung</div>
+      <div class="input-label">Ausführliche Beschreibung</div>
       <div class="NgxEditor__Wrapper">
         <ngx-editor-menu [editor]="longEditor" [toolbar]="toolbar">
         </ngx-editor-menu>
         <ngx-editor
           [editor]="longEditor"
           [(ngModel)]="longDescription"
+          placeholder="Ausführliche Beschreibung der Eigenschaft"
         ></ngx-editor>
       </div>
       <div class="hint">Wird in der Detailansicht angezeigt</div>

+ 0 - 7
src/app/journal/journal-stats/ability-panel/trait-table/trait-modal/trait-modal.component.scss

@@ -1,10 +1,3 @@
-.modal-dimensions {
-    width: 50vw;
-    background-color: var(--modal-background);
-    border-radius: 10px;
-    border: 1px solid var(--border-color);
-    padding: 0 2rem;
-}
 .modal-input {
     display: flex;
     flex-direction: column;

+ 167 - 0
src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.html

@@ -0,0 +1,167 @@
+<div class="dimensions">
+  <div class="shadow-box">
+    <div class="title t-0">Ausgewählte Zauber</div>
+    <hr style="margin-bottom: 0; margin: 1.5rem 2rem 0 2rem" />
+    <div class="heading-list">
+      <div>Kosten</div>
+      <div>Name</div>
+      <div>Stufe</div>
+      <div>Bonus</div>
+      <div>Effekt</div>
+      <div>Reichweite</div>
+    </div>
+  </div>
+  <div id="spells-table" class="item-list table-content">
+    @for(spell of preparedSpells; let index = $index; track spell){
+    <div
+      matRipple
+      class="spell-item"
+      [ngClass]="{ selected: checkedSpells[index] }"
+      (click)="checkedSpells[index] = !checkedSpells[index]"
+    >
+      <!--  Range Icon -->
+      <ng-container
+        [ngTemplateOutlet]="costTemplate"
+        [ngTemplateOutletContext]="{ spell: spell }"
+      ></ng-container>
+      <div class="vertical-line"></div>
+
+      <!-- Name -->
+      <ng-container
+        [ngTemplateOutlet]="spellNameTemplate"
+        [ngTemplateOutletContext]="{ spell: spell }"
+      ></ng-container>
+      <div class="vertical-line"></div>
+
+      <!-- Level -->
+      <ng-container
+        [ngTemplateOutlet]="spellLevelTemplate"
+        [ngTemplateOutletContext]="{ spell: spell }"
+      ></ng-container>
+      <div class="vertical-line"></div>
+
+      <!-- Attack -->
+      <ng-container
+        [ngTemplateOutlet]="spellAttackTemplate"
+        [ngTemplateOutletContext]="{ spell: spell }"
+      ></ng-container>
+      <div class="vertical-line"></div>
+
+      <!-- Damage/Heal -->
+      <ng-container
+        [ngTemplateOutlet]="spellDamageTemplate"
+        [ngTemplateOutletContext]="{ spell: spell }"
+      ></ng-container>
+      <div class="vertical-line"></div>
+
+      <!-- Range -->
+      <ng-container
+        [ngTemplateOutlet]="spellRangeTemplate"
+        [ngTemplateOutletContext]="{ spell: spell }"
+      ></ng-container>
+    </div>
+    }@empty{
+    <div
+      style="
+        text-align: center;
+        margin-top: 3rem;
+        font-size: 1.25rem;
+        font-weight: 500;
+      "
+    >
+      Noch keine Zauber hinzugefügt
+    </div>
+    }
+  </div>
+
+  <div class="horizontal-buttons">
+    <ui-button [color]="'green'" style="width: 40%" (click)="update()">
+      Bestätigen
+    </ui-button>
+    <ui-button [color]="'red'" style="width: 40%" (click)="cancel()">
+      Abbrechen
+    </ui-button>
+  </div>
+</div>
+<!-- Templates -->
+
+<!-- COST -->
+<ng-template #costTemplate let-spell="spell">
+  <div class="bold">
+    <span *ngIf="spell.cost === 'action'">A</span>
+    <span *ngIf="spell.cost === 'bonus'">B</span>
+    <span *ngIf="spell.cost === 'reaction'">R</span>
+  </div>
+</ng-template>
+
+<!-- NAME -->
+<ng-template #spellNameTemplate let-spell="spell">
+  <div>
+    <div class="bold">{{ spell.german }}</div>
+    <div class="bold small">
+      <span *ngIf="spell.needsConcentration">C | </span>
+      <span *ngIf="spell.needsVerbal">V </span>
+      <span *ngIf="spell.needsSomatic">G </span>
+      <span *ngIf="spell.needsMaterial">M </span>
+      <div></div>
+    </div>
+  </div>
+</ng-template>
+
+<!-- Level -->
+<ng-template #spellLevelTemplate let-spell="spell">
+  <div *ngIf="spell.level !== 0" class="bold">{{ spell.level }}</div>
+  <div *ngIf="spell.level === 0" class="bold">Trick</div>
+</ng-template>
+
+<!-- Attack -->
+<ng-template #spellAttackTemplate let-spell="spell">
+  <div>
+    <div *ngIf="spell.needsSavingThrow">
+      <div>
+        {{ attributes[spell.savingThrowAttribute!] }}
+      </div>
+      <div>{{ spellSaveDC }}</div>
+    </div>
+    <div *ngIf="spell.needsAttackRoll">
+      <div>{{ spellAttackBonus }}</div>
+    </div>
+    <div *ngIf="!spell.needsSavingThrow && !spell.needsAttackRoll">-</div>
+  </div>
+</ng-template>
+
+<!-- Damage/Heal -->
+<ng-template #spellDamageTemplate let-spell="spell">
+  <div>
+    @if(spell.doesDamage){
+    <div *ngFor="let damage of spell.damage; let index = index">
+      <span>{{ damage.diceNumber }} {{ damage.diceType }} </span>
+      <span>
+        <icon [size]="'xs'" [type]="'damage'" [icon]="damage.damageType"></icon>
+      </span>
+    </div>
+    } @if(spell.doesHeal){
+    <div class="heal">
+      <span>{{ spell.heal.diceNumber }} {{ spell.heal.diceType }} </span>
+      <span *ngIf="spell.heal.additionalHeal"
+        >+{{ spell.heal.additionalHeal }}
+      </span>
+      <span>
+        <icon [size]="'xs'" [type]="'damage'" [icon]="'heal'"></icon>
+      </span>
+    </div>
+    }
+  </div>
+</ng-template>
+
+<!-- Range -->
+<ng-template #spellRangeTemplate let-spell="spell">
+  <div class="spell-range">
+    <div *ngIf="spell.isRanged">{{ spell.range }} ft.</div>
+    <div *ngIf="!spell.isRanged">Berührung</div>
+
+    <div *ngIf="spell.hasAreaOfEffect">
+      <span>{{ spell.radius }} ft. {{ areas[spell.areaOfEffectType] }} </span>
+    </div>
+  </div>
+</ng-template>

+ 98 - 0
src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.scss

@@ -0,0 +1,98 @@
+.dimensions {
+    height: 50rem;
+    width: 45rem;
+    padding: 0;
+    overflow: hidden;
+}
+
+.heading-list {
+    flex: 0 0 3rem;
+    padding: 10px 2rem;
+    // margin-top: 1.5rem;
+    display: grid;
+    grid-template-columns: 6fr 18fr 11fr 8fr 20fr 16fr;
+    text-align: center;
+    font-weight: 700;
+}
+
+.shadow-box {
+    box-shadow: var(--shadow-bottom);
+    position: relative;
+    padding-top: 1rem;
+}
+
+.item-list {
+    height: 36rem;
+    padding: 0 1rem;
+    display: block;
+    background: transparent;
+    border-radius: 4px;
+    overflow: auto;
+}
+
+.spell-item {
+    box-sizing: border-box;
+    margin: 15px 10px;
+    color: rgba(0, 0, 0, 0.87);
+    display: grid;
+    grid-template-columns: 6fr 0.1fr 20fr 0.1fr 10fr 0.1fr 8fr 0.1fr 20fr 0.1fr 16fr;
+    align-items: center;
+    justify-content: space-between;
+    box-sizing: border-box;
+    background: var(--items);
+    border-radius: 10px;
+    border: var(--border);
+    font-size: 1rem;
+    font-weight: 600;
+    text-align: center;
+    cursor: pointer;
+    box-shadow:
+        0 5px 5px -3px rgba(0, 0, 0, 0.2),
+        0 8px 8px 1px rgba(0, 0, 0, 0.14),
+        0 3px 10px 2px rgba(0, 0, 0, 0.12);
+    transition: background-color 0.2s ease-in-out;
+    &:hover {
+        background-color: #f8d8c6;
+    }
+}
+
+.selected {
+    background-color: #f8d8c6;
+    border: 3px solid #bc8567;
+    &:hover {
+        background-color: var(--items);
+    }
+}
+
+.bold {
+    font-weight: bold;
+}
+
+.small {
+    font-size: 0.625rem;
+}
+
+.large {
+    font-size: 1.125rem;
+}
+
+.vertical-line {
+    position: relative;
+    width: 1px;
+    height: 3.5rem;
+}
+
+.vertical-line::before {
+    content: "";
+    position: absolute;
+    top: 15%;
+    bottom: 15%;
+    left: 0;
+    border-left: 1px solid black;
+}
+
+.horizontal-buttons {
+    box-shadow: var(--shadow-top);
+    position: relative;
+    padding: 1.5rem 3rem;
+}

+ 23 - 0
src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.spec.ts

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

+ 60 - 0
src/app/journal/journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component.ts

@@ -0,0 +1,60 @@
+import { Component, Input } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Spell } from 'src/interfaces/spell';
+import { ModalService } from 'src/services/modal/modal.service';
+
+@Component({
+  selector: 'app-favorite-spells-modal',
+  templateUrl: './favorite-spells-modal.component.html',
+  styleUrl: './favorite-spells-modal.component.scss',
+})
+export class FavoriteSpellsModalComponent {
+  @Input() public preparedSpells: Spell[] = [];
+  @Input() public selectedSpells: Spell[] = [];
+  @Input() public spellAttackBonus: string = '0';
+  @Input() public spellSaveDC: number = 0;
+
+  checkedSpells: boolean[] = [];
+
+  public attributes: any = {
+    strength: 'STR',
+    dexterity: 'DEX',
+    constitution: 'CON',
+    intelligence: 'INT',
+    wisdom: 'WIS',
+    charisma: 'CHA',
+  };
+
+  public areas: any = {
+    cone: 'Kegel',
+    sphere: 'Kugel',
+    circle: 'Kreis',
+    line: 'Linie',
+    square: 'Quadrat',
+    cube: 'Würfel',
+  };
+
+  public constructor(private modalAccessor: ModalService) {}
+
+  public ngOnInit(): void {
+    this.checkedSpells = Array(this.preparedSpells.length).fill(false);
+    this.preparedSpells.forEach((spell, index) => {
+      this.checkedSpells[index] = this.selectedSpells.some(
+        (selectedSpell) => selectedSpell.id === spell.id
+      );
+    });
+  }
+
+  public update(): void {
+    const spells: Spell[] = this.preparedSpells.filter(
+      (spell, index) => this.checkedSpells[index]
+    );
+    this.modalAccessor.handleModalClosing('update', spells);
+    this.checkedSpells = [];
+  }
+
+  public cancel(): void {
+    this.modalAccessor.handleModalClosing('cancel', undefined);
+    this.checkedSpells = [];
+  }
+}

+ 80 - 92
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.html

@@ -1,6 +1,6 @@
 <div class="spell-box">
   <div class="heading-list">
-    <div>Typ</div>
+    <div>Kosten</div>
     <div>Name</div>
     <div>Stufe</div>
     <div>Bonus</div>
@@ -17,7 +17,7 @@
     <div class="item" cdkDrag (click)="showFullSpellcard(index)">
       <!--  Range Icon -->
       <ng-container
-        [ngTemplateOutlet]="distanceIconTemplate"
+        [ngTemplateOutlet]="costTemplate"
         [ngTemplateOutletContext]="{ spell: spell }"
       ></ng-container>
       <div class="vertical-line"></div>
@@ -69,108 +69,96 @@
     </div>
     }
   </div>
-  <input
-    id="typeahead-basic"
-    type="text"
-    [class]="showInput ? 'spellInput' : 'spellInput hidden'"
-    (selectItem)="onSpellSelect($event.item); $event.preventDefault()"
-    [(ngModel)]="newSpellName"
-    [ngbTypeahead]="search"
-    placement="top-start"
-    placeholder="Name des vorbereiteten Zaubers"
-  />
-  <div class="footer"></div>
-  <button
-    [class]="showInput ? 'slide-button cancel-button' : 'slide-button'"
-    (click)="toggleInput()"
-  >
-    @if(showInput){ Abbrechen} @else { Hinzufügen}
-  </button>
-</div>
-
-<!-- Templates -->
+  <div class="footer">
+    <ui-button [color]="'green'" style="width: 80%" (click)="openModal()">
+      Bearbeiten
+    </ui-button>
+  </div>
 
-<!-- ICON -->
-<ng-template #distanceIconTemplate let-spell="spell">
-  <icon
-    [size]="'s'"
-    [type]="'weapon'"
-    [icon]="spell.isRanged ? 'distance' : 'touch'"
-  ></icon>
-</ng-template>
+  <!-- Templates -->
 
-<!-- NAME -->
-<ng-template #spellNameTemplate let-spell="spell">
-  <div>
-    <div class="bold">{{ spell.german }}</div>
-    <div class="bold small">
+  <!-- COST -->
+  <ng-template #costTemplate let-spell="spell">
+    <div class="bold">
       <span *ngIf="spell.cost === 'action'">A</span>
       <span *ngIf="spell.cost === 'bonus'">B</span>
       <span *ngIf="spell.cost === 'reaction'">R</span>
-      <span> | </span>
-      <span *ngIf="spell.needsConcentration">C | </span>
-      <span *ngIf="spell.needsVerbal">V </span>
-      <span *ngIf="spell.needsSomatic">G </span>
-      <span *ngIf="spell.needsMaterial">M </span>
-      <div></div>
     </div>
-  </div>
-</ng-template>
+  </ng-template>
 
-<!-- Level -->
-<ng-template #spellLevelTemplate let-spell="spell">
-  <div *ngIf="spell.level !== 0" class="bold">{{ spell.level }}</div>
-  <div *ngIf="spell.level === 0" class="bold">Trick</div>
-</ng-template>
-
-<!-- Attack -->
-<ng-template #spellAttackTemplate let-spell="spell">
-  <div>
-    <div *ngIf="spell.needsSavingThrow">
-      <div>
-        {{ attributes[spell.savingThrowAttribute!] }}
+  <!-- NAME -->
+  <ng-template #spellNameTemplate let-spell="spell">
+    <div>
+      <div class="bold">{{ spell.german }}</div>
+      <div class="bold small">
+        <span *ngIf="spell.needsConcentration">C | </span>
+        <span *ngIf="spell.needsVerbal">V </span>
+        <span *ngIf="spell.needsSomatic">G </span>
+        <span *ngIf="spell.needsMaterial">M </span>
+        <div></div>
       </div>
-      <div>{{ spellSaveDC }}</div>
-    </div>
-    <div *ngIf="spell.needsAttackRoll">
-      <div>{{ spellAttackBonus }}</div>
     </div>
-    <div *ngIf="!spell.needsSavingThrow && !spell.needsAttackRoll">-</div>
-  </div>
-</ng-template>
+  </ng-template>
 
-<!-- Damage/Heal -->
-<ng-template #spellDamageTemplate let-spell="spell">
-  <div>
-    @if(spell.doesDamage){
-    <div *ngFor="let damage of spell.damage; let index = index">
-      <span>{{ damage.diceNumber }} {{ damage.diceType }} </span>
-      <span>
-        <icon [size]="'xs'" [type]="'damage'" [icon]="damage.damageType"></icon>
-      </span>
+  <!-- Level -->
+  <ng-template #spellLevelTemplate let-spell="spell">
+    <div *ngIf="spell.level !== 0" class="bold">{{ spell.level }}</div>
+    <div *ngIf="spell.level === 0" class="bold">Trick</div>
+  </ng-template>
+
+  <!-- Attack -->
+  <ng-template #spellAttackTemplate let-spell="spell">
+    <div>
+      <div *ngIf="spell.needsSavingThrow">
+        <div>
+          {{ attributes[spell.savingThrowAttribute!] }}
+        </div>
+        <div>{{ spellSaveDC }}</div>
+      </div>
+      <div *ngIf="spell.needsAttackRoll">
+        <div>{{ spellAttackBonus }}</div>
+      </div>
+      <div *ngIf="!spell.needsSavingThrow && !spell.needsAttackRoll">-</div>
     </div>
-    } @if(spell.doesHeal){
-    <div class="heal">
-      <span>{{ spell.heal.diceNumber }} {{ spell.heal.diceType }} </span>
-      <span *ngIf="spell.heal.additionalHeal"
-        >+{{ spell.heal.additionalHeal }}
-      </span>
-      <span>
-        <icon [size]="'xs'" [type]="'damage'" [icon]="'heal'"></icon>
-      </span>
+  </ng-template>
+
+  <!-- Damage/Heal -->
+  <ng-template #spellDamageTemplate let-spell="spell">
+    <div>
+      @if(spell.doesDamage){
+      <div *ngFor="let damage of spell.damage; let index = index">
+        <span>{{ damage.diceNumber }} {{ damage.diceType }} </span>
+        <span>
+          <icon
+            [size]="'xs'"
+            [type]="'damage'"
+            [icon]="damage.damageType"
+          ></icon>
+        </span>
+      </div>
+      } @if(spell.doesHeal){
+      <div class="heal">
+        <span>{{ spell.heal.diceNumber }} {{ spell.heal.diceType }} </span>
+        <span *ngIf="spell.heal.additionalHeal"
+          >+{{ spell.heal.additionalHeal }}
+        </span>
+        <span>
+          <icon [size]="'xs'" [type]="'damage'" [icon]="'heal'"></icon>
+        </span>
+      </div>
+      }
     </div>
-    }
-  </div>
-</ng-template>
+  </ng-template>
 
-<!-- Range -->
-<ng-template #spellRangeTemplate let-spell="spell">
-  <div class="spell-range">
-    <div *ngIf="spell.isRanged">{{ spell.range }} ft.</div>
-    <div *ngIf="!spell.isRanged">Berührung</div>
+  <!-- Range -->
+  <ng-template #spellRangeTemplate let-spell="spell">
+    <div class="spell-range">
+      <div *ngIf="spell.isRanged">{{ spell.range }} ft.</div>
+      <div *ngIf="!spell.isRanged">Berührung</div>
 
-    <div *ngIf="spell.hasAreaOfEffect">
-      <span>{{ spell.radius }} ft. {{ areas[spell.areaOfEffectType] }} </span>
+      <div *ngIf="spell.hasAreaOfEffect">
+        <span>{{ spell.radius }} ft. {{ areas[spell.areaOfEffectType] }} </span>
+      </div>
     </div>
-  </div>
-</ng-template>
+  </ng-template>
+</div>

+ 0 - 1
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.scss

@@ -1,6 +1,5 @@
 .heading-list {
   flex: 0 0 3rem;
-  // padding: 0.5rem 0.625rem;
   padding: 10px 0.625rem;
   display: grid;
   grid-template-columns: 6fr 20fr 10fr 8fr 20fr 16fr;

+ 31 - 83
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.ts

@@ -9,6 +9,7 @@ import { SpellModalComponent } from 'src/app/journal/spell-modal/spell-modal.com
 import { FullSpellcardComponent } from 'src/app/shared-components/full-spellcard/full-spellcard.component';
 import { Observable, OperatorFunction } from 'rxjs';
 import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
+import { FavoriteSpellsModalComponent } from './favorite-spells-modal/favorite-spells-modal.component';
 
 @Component({
   selector: 'spell-table',
@@ -24,9 +25,8 @@ export class SpellTableComponent {
 
   public spells!: Spell[];
   private preparedSpells!: Spell[];
-  private preparedSpellsNames: string[] = [];
+  // private preparedSpellsNames: string[] = [];
   public newSpellName: string = '';
-  public showInput: boolean = false;
 
   public attributes: any = {
     strength: 'STR',
@@ -55,7 +55,6 @@ export class SpellTableComponent {
   public ngOnInit(): void {
     this.spells = this.dataAccessor.favoriteSpells;
     this.preparedSpells = this.dataAccessor.getAllPreparedSpells();
-    this.preparedSpellsNames = this.preparedSpells.map((spell) => spell.german);
     this.subscribeToData();
   }
 
@@ -67,7 +66,7 @@ export class SpellTableComponent {
     const resultSubscription = this.modalAccessor.result$.subscribe(
       (result) => {
         resultSubscription.unsubscribe();
-        if (result.state === 'delete') {
+        if (result.state === 'remove') {
           this.spells.splice(spellIndex, 1);
           this.updateSpellsInDatabase();
         }
@@ -75,75 +74,24 @@ export class SpellTableComponent {
     );
   }
 
-  // LEGACY CODE
-  public openDetailsPanel(index: number): void {
-    this.detailsAccessor.openPanel(SpellDetailsComponent, {
-      spell: this.spells[index],
-      modifiers: {
-        attackBonus: this.spellAttackBonus,
-        saveDC: this.spellSaveDC,
-      },
-    });
-    const resultSubscription = this.detailsAccessor.result$.subscribe(
-      (result) => {
-        if (result.state === 'delete') {
-          this.deleteSpell(index);
-        } else if (result.state === 'update') {
-          this.openModal(true, index);
-        }
-        resultSubscription.unsubscribe();
-      }
-    );
-  }
-  //
-
-  public openModal(isUpdate: boolean, index?: number): void {
-    this.modalAccessor.openModal(SpellModalComponent, {
-      spell:
-        index !== undefined
-          ? JSON.parse(JSON.stringify(this.spells[index]))
-          : undefined,
-      isUpdate: isUpdate,
+  public openModal(): void {
+    this.modalAccessor.openModal(FavoriteSpellsModalComponent, {
+      preparedSpells: this.preparedSpells,
+      selectedSpells: this.spells,
+      spellAttackBonus: this.spellAttackBonus,
+      spellSaveDC: this.spellSaveDC,
     });
     const resultSubscription = this.modalAccessor.result$.subscribe(
       (result) => {
         if (result.state === 'update') {
-          this.updateSpell(result.data, index!);
-        } else if (result.state === 'add') {
-          this.addSpell(result.data);
+          this.spells = result.data;
+          this.updateSpellsInDatabase();
         }
         resultSubscription.unsubscribe();
       }
     );
   }
 
-  public toggleInput(): void {
-    this.showInput = !this.showInput;
-    this.newSpellName = '';
-  }
-
-  public onSpellSelect(spellname: any): void {
-    const newSpell = this.preparedSpells.filter(
-      (spell) => spell.german === spellname
-    );
-    if (newSpell.length !== 1) {
-      console.warn('Spell not found');
-    } else {
-      this.addSpell(newSpell[0]);
-    }
-    this.newSpellName = '';
-  }
-
-  public addSpell(spell: Spell) {
-    this.spells.push(spell);
-    this.updateSpellsInDatabase();
-  }
-
-  public updateSpell(spell: Spell, index: number): void {
-    this.spells[index] = spell;
-    this.updateSpellsInDatabase();
-  }
-
   public deleteSpell(index: number): void {
     this.spells.splice(index, 1);
     this.updateSpellsInDatabase();
@@ -188,24 +136,24 @@ export class SpellTableComponent {
     });
   }
 
-  public search: OperatorFunction<string, readonly string[]> = (
-    text$: Observable<string>
-  ) =>
-    text$.pipe(
-      debounceTime(200),
-      distinctUntilChanged(),
-      map((term) =>
-        term.length < 2
-          ? []
-          : this.preparedSpellsNames
-              .filter((v) => v.toLowerCase().indexOf(term.toLowerCase()) > -1)
-              .filter(
-                (v) =>
-                  !this.spells.some(
-                    (spell) => spell.german.toLowerCase() === v.toLowerCase()
-                  )
-              )
-              .slice(0, 5)
-      )
-    );
+  // public search: OperatorFunction<string, readonly string[]> = (
+  //   text$: Observable<string>
+  // ) =>
+  //   text$.pipe(
+  //     debounceTime(200),
+  //     distinctUntilChanged(),
+  //     map((term) =>
+  //       term.length < 2
+  //         ? []
+  //         : this.preparedSpellsNames
+  //             .filter((v) => v.toLowerCase().indexOf(term.toLowerCase()) > -1)
+  //             .filter(
+  //               (v) =>
+  //                 !this.spells.some(
+  //                   (spell) => spell.german.toLowerCase() === v.toLowerCase()
+  //                 )
+  //             )
+  //             .slice(0, 5)
+  //     )
+  //   );
 }

+ 45 - 61
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-details/weapon-details.component.html

@@ -1,23 +1,28 @@
-<div class="details-title">{{ weapon?.name }}</div>
+<div class="title">{{ weapon?.name }}</div>
 
-<div class="property-title">Angriff</div>
+<div class="subheading left">Angriff</div>
 
-<div>Angriffsmodifikator:</div>
-{{ weapon?.attackBonus }}
+<div class="flex-row">
+  <div class="label">Modifikator:</div>
+  <span>{{ weapon?.attackBonus }}</span>
+</div>
 
 <!-- Singel Damage -->
-<div *ngIf="!weapon?.isVersatile">
-  Schaden:
-  <div *ngFor="let damage of weapon?.damage; let index = index">
-    {{ damage.diceNumber }} {{ damage.diceType }} {{ damage.damageType }}
-    <span *ngIf="index === 0 && damageModifier !== '0'">
-      {{ damageModifier }}
-    </span>
-  </div>
+@if(!weapon?.isVersatile){
+<div class="flex-row">
+  <div class="label">Schaden:</div>
+  @for(damage of weapon?.damage; let index = $index; track damage){
+  {{ damage.diceNumber }} {{ damage.diceType }} {{ damage.damageType }}
+  <span *ngIf="index === 0 && damageModifier !== '0'">
+    {{ damageModifier }}
+  </span>
+
+  }
 </div>
+}
 
 <!-- Versatility Damage -->
-<div *ngIf="weapon?.isVersatile">
+<div *ngIf="weapon?.isVersatile" class="label">
   Einhändiger Schaden:
   <div *ngFor="let damage of weapon?.damage">
     {{ damage.diceNumber }} {{ damage.diceType }} {{ damage.damageType }}
@@ -32,32 +37,9 @@
   </div>
 </div>
 
-<!-- Ranged -->
-<div *ngIf="weapon?.isRanged">
-  Reichweite:
-  {{ weapon?.range }}
-</div>
-
-<!-- Thrown -->
-<div *ngIf="weapon?.canBeThrown">
-  Wurfweite:
-  {{ weapon?.throwRange }}
-</div>
-
 <!-- Magical -->
 
-<div *ngIf="weapon?.isMagical">
-  Magischer Modifikator:
-  {{ weapon?.magicBonus }}
-</div>
-
-<!-- Weight -->
-<div>
-  Gewicht:
-  {{ weapon?.weight }}
-</div>
-
-<div class="property-title">Eigenschaften</div>
+<div class="subheading left">Eigenschaften</div>
 <div class="weapon-properties">
   <span *ngIf="weapon?.proficient">Geübt </span>
   <span *ngIf="weapon?.isRanged">Fernkampf </span>
@@ -68,30 +50,32 @@
   <span *ngIf="weapon?.isMagical">Magisch </span>
 </div>
 
-<!-- Description -->
-<div class="property-title">Beschreibung</div>
-<div class="weapon-description">
-  <!-- TODO: realize -->
-  bla
+@if(weapon?.isRanged || weapon?.canBeThrown){
+<div class="subheading left">Reichweite</div>
+
+<!-- Ranged -->
+<div *ngIf="weapon?.isRanged">
+  Reichweite:
+  {{ weapon?.range }}
+</div>
+
+<!-- Thrown -->
+<div *ngIf="weapon?.canBeThrown">
+  Wurfweite:
+  {{ weapon?.throwRange }}
 </div>
+}
 
-<div class="vertical-button-wrapper-3">
-  <ui-button
-    [type]="'edit'"
-    [size]="'xlarge'"
-    [color]="'primary'"
-    (click)="close('update')"
-  ></ui-button>
-  <ui-button
-    [type]="'delete'"
-    [size]="'xlarge'"
-    [color]="'primary'"
-    (click)="close('delete')"
-  ></ui-button>
-  <ui-button
-    [type]="'cancel'"
-    [size]="'xlarge'"
-    [color]="'primary'"
-    (click)="close('cancel')"
-  ></ui-button>
+<!-- Description -->
+@if(weapon?.description != ""){
+<div class="subheading left">Beschreibung</div>
+<p class="content" [innerHTML]="weapon?.description"></p>
+}
+<div class="vertical-buttons bottom">
+  <ui-button [color]="'green'" [width]="'w20'" (click)="close('update')">
+    Anpassen
+  </ui-button>
+  <ui-button [color]="'red'" [width]="'w20'" (click)="close('delete')">
+    Löschen
+  </ui-button>
 </div>

+ 8 - 3
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-details/weapon-details.component.scss

@@ -1,6 +1,11 @@
-.property-title{
+.property-title {
     font-size: 1.25rem;
     font-weight: bold;
     margin-top: 1.5rem;
-    text-align:center;
-}
+    text-align: center;
+}
+
+.label {
+    width: 8rem;
+    font-weight: 500;
+}

+ 252 - 182
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-modal/weapon-modal.component.html

@@ -1,200 +1,270 @@
-<div class="modal-dimensions">
-  <h2 style="text-align: center">
+<div class="dimensions">
+  <div class="title">
     @if(isUpdate){Waffe bearbeiten} @else{Waffe hinzufügen}
-  </h2>
-
-  <div class="add-form-group">
-    <div class="input-element">
-      <label for="weaponName">Name</label>
-      <input type="text" class="add-input" id="weaponName" [(ngModel)]="name" />
-    </div>
-    <div class="form-element-row">
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="proficient" />
-        <label for="weaponProficient">Geübt</label>
-      </div>
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="isFinesse" />
-        <label for="weaponFinesse">Finesse</label>
-      </div>
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="isVersatile" />
-        <label for="Vielseitig">Vielseitig</label>
-      </div>
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="isTwoHanded" />
-        <label for="weaponTwoHanded">Zweihändig</label>
-      </div>
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="isRanged" />
-        <label for="weaponRanged">Fernkampf</label>
-      </div>
-      <div class="checkbox-element">
-        <select [(ngModel)]="weight">
-          <option *ngFor="let weight of weights" [value]="weight">
-            {{ weight }}
-          </option>
-        </select>
-        <label>Gewicht</label>
-      </div>
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="canBeThrown" />
-        <label for="weaponRanged">Wurfwaffe</label>
-      </div>
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="isMagical" />
-        <label>Magisch</label>
-      </div>
-    </div>
+  </div>
 
-    <div class="input-element">
-      <label for="weaponAttackBonus">Angriffsbonus</label>
-      <select [(ngModel)]="attackBonus">
-        <option *ngFor="let attackBonus of attackBonuses" [value]="attackBonus">
-          {{ attackBonus }}
-        </option>
-      </select>
-    </div>
+  <div class="content">
+    <div class="input-label">Name</div>
+    <mat-form-field appearance="outline" class="w-100">
+      <input matInput [(ngModel)]="name" />
+    </mat-form-field>
+    <hr />
 
-    <div class="input-element" *ngIf="isMagical">
-      <label>Magischer Modifikator</label>
-      <select [(ngModel)]="magicBonus">
-        <option
-          *ngFor="let magicBonus of magicBonuses"
-          [value]="magicBonus.value"
-        >
-          {{ magicBonus.display }}
-        </option>
-      </select>
-    </div>
+    <div class="flex-row t-1">
+      <div class="checkbox-column">
+        <div class="checkbox-row">
+          <input id="proficient" type="checkbox" [(ngModel)]="proficient" />
+          <label for="proficient">Geübt</label>
+        </div>
+        <div class="checkbox-row">
+          <input id="finesse" type="checkbox" [(ngModel)]="isFinesse" />
+          <label for="finesse">Finesse</label>
+        </div>
+        <div class="checkbox-row">
+          <input id="versatile" type="checkbox" [(ngModel)]="isVersatile" />
+          <label for="versatile">Vielseitig</label>
+        </div>
+        <div class="checkbox-row">
+          <input id="isTwohanded" type="checkbox" [(ngModel)]="isTwoHanded" />
+          <label for="isTwohanded">Zweihändig</label>
+        </div>
+      </div>
+      <div class="checkbox-column">
+        <div class="checkbox-row">
+          <input id="hasReach" type="checkbox" [(ngModel)]="hasReach" />
+          <label for="hasReach">Reichweite</label>
+        </div>
+        <div class="checkbox-row">
+          <input id="isRanged" type="checkbox" [(ngModel)]="isRanged" />
+          <label for="isRanged">Fernkampf</label>
+        </div>
 
-    <div class="input-element" *ngIf="isRanged">
-      <label for="weaponRange">Normale Reichweite</label>
-      <input
-        type="number"
-        class="add-input"
-        id="weaponRange"
-        [(ngModel)]="range[0]"
-      />
+        <div class="checkbox-row">
+          <input id="canBeThrown" type="checkbox" [(ngModel)]="canBeThrown" />
+          <label for="canBeThrown">Wurfwaffe</label>
+        </div>
+        <div class="checkbox-row">
+          <input id="isMagical" type="checkbox" [(ngModel)]="isMagical" />
+          <label for="isMagical">Magisch</label>
+        </div>
+      </div>
     </div>
 
-    <div class="input-element" *ngIf="isRanged">
-      <label for="weaponRange">Große Reichweite</label>
-      <input
-        type="number"
-        class="add-input"
-        id="weaponRange"
-        [(ngModel)]="range[1]"
-      />
-    </div>
+    <hr />
 
-    <div class="input-element" *ngIf="canBeThrown">
-      <label for="weaponRange">Normale Wurfreichweite</label>
-      <input
-        type="number"
-        class="add-input"
-        id="weaponRange"
-        [(ngModel)]="throwRange[0]"
-      />
-    </div>
+    <!-- TAB-PANEL -->
+    <div class="d-flex">
+      <div
+        ngbNav
+        #nav="ngbNav"
+        [(activeId)]="active"
+        class="flex-column navigation-bar"
+        orientation="vertical"
+      >
+        <ng-container ngbNavItem="damage">
+          <button ngbNavLink>Schaden</button>
+          <ng-template ngbNavContent>
+            <div class="flex-row">
+              <div class="w-50">
+                <div class="input-label">Angriffsbonus</div>
+                <mat-form-field appearance="outline">
+                  <mat-select [(ngModel)]="attackBonus">
+                    @for (attackBonus of attackBonuses; track attackBonus) {
+                    <mat-option [value]="attackBonus">{{
+                      attackBonus
+                    }}</mat-option
+                    >}
+                  </mat-select>
+                </mat-form-field>
+              </div>
 
-    <div class="input-element" *ngIf="canBeThrown">
-      <label for="weaponRange">Große Wurfreichweite</label>
-      <input
-        type="number"
-        class="add-input"
-        id="weaponRange"
-        [(ngModel)]="throwRange[1]"
-      />
-    </div>
+              <div *ngIf="isMagical">
+                <div class="input-label">Magischer Modifikator</div>
+                <mat-form-field appearance="outline">
+                  <mat-select [(ngModel)]="magicBonus">
+                    @for (magicBonus of magicBonuses; track magicBonus) {
+                    <mat-option [value]="magicBonus.value">
+                      {{ magicBonus.display }} </mat-option
+                    >}
+                  </mat-select>
+                </mat-form-field>
+              </div>
+            </div>
 
-    <h3 style="text-align: center">Schaden</h3>
+            <div class="flex-row t-05">
+              @for(damageEntry of damage; let index = $index; track
+              damageEntry){
 
-    <div class="damage-container">
-      <div class="damage-box" *ngFor="let damage of damage; let index = index">
-        <div class="dice-row">
-          <div class="flex-column">
-            <label>Anzahl</label>
-            <select [(ngModel)]="damage.diceNumber">
-              <option *ngFor="let number of numbers" [value]="number">
-                {{ number }}
-              </option>
-            </select>
-          </div>
+              <div class="damage-box">
+                <div class="subheading left t-025">
+                  @if(index == 0){Schaden} @else {Zusatzschaden}
+                </div>
+                <div class="input-label">Anzahl Würfel</div>
+                <mat-form-field appearance="outline">
+                  <mat-select [(ngModel)]="damageEntry.diceNumber">
+                    @for (number of numbers; track number) {
+                    <mat-option [value]="number"> {{ number }} </mat-option>}
+                  </mat-select>
+                </mat-form-field>
 
-          <div class="flex-column">
-            <label>Würfel</label>
-            <select [(ngModel)]="damage.diceType">
-              <option *ngFor="let die of dice" [value]="die">
-                {{ die }}
-              </option>
-            </select>
-          </div>
-        </div>
+                <div class="input-label t-05">
+                  Würfelart @if(isVersatile && index === 0){ (Einhändig)}
+                </div>
+                <mat-form-field appearance="outline">
+                  <mat-select [(ngModel)]="damageEntry.diceType">
+                    @for (die of dice; track die) {
+                    <mat-option [value]="die"> {{ die }} </mat-option>}
+                  </mat-select>
+                </mat-form-field>
+                @if(isVersatile && index === 0){
+                <div class="input-label t-05">Würfelart (Zweihändig)</div>
+                <mat-form-field appearance="outline">
+                  <mat-select [(ngModel)]="versatileDamage">
+                    @for (die of dice; track die) {
+                    <mat-option [value]="die"> {{ die }} </mat-option>}
+                  </mat-select>
+                </mat-form-field>
+                }
 
-        <div *ngIf="isVersatile && index === 0">
-          Zweihändiger Schaden
-          <div class="flex-row gap-10">
-            <div class="flex-column">
-              <label>Würfel</label>
-              <select [(ngModel)]="versatileDamage">
-                <option *ngFor="let die of dice" [value]="die">
-                  {{ die }}
-                </option>
-              </select>
+                <div class="input-label t-05">Schadensart</div>
+                <mat-form-field appearance="outline">
+                  <mat-select [(ngModel)]="damageEntry.damageType">
+                    @for (type of damageTypes; track type) {
+                    <mat-option [value]="type.value">
+                      {{ type.display }}
+                    </mat-option>
+                    }
+                  </mat-select>
+                </mat-form-field>
+                @if(index !== 0){
+                <icon-button
+                  [icon]="'delete'"
+                  (click)="removeDamage(index)"
+                ></icon-button>
+                }
+              </div>
+              @if(damage.length < 2){
+              <icon-button
+                [icon]="'add'"
+                style="margin-top: 7rem; margin-left: 5rem"
+                (click)="addDamage()"
+              ></icon-button>
+              } }
             </div>
-          </div>
-        </div>
-
-        <label for="damageType">Schadensart</label>
-        <select [(ngModel)]="damage.damageType">
-          <option *ngFor="let type of damageTypes" [value]="type.value">
-            {{ type.display }}
-          </option>
-        </select>
-
-        <icon
-          *ngIf="index > 0"
-          (click)="removeDamage(index)"
-          [size]="'m'"
-          [type]="'UI'"
-          [icon]="'remove'"
-          [class]="'pointer'"
-        ></icon>
+          </ng-template>
+        </ng-container>
+        <ng-container ngbNavItem="range">
+          @if(isRanged || canBeThrown){
+          <button ngbNavLink>Reichweite</button>
+          } @else {
+          <button class="disabled-button" disabled>Reichweite</button>
+          }
+          <ng-template ngbNavContent>
+            <div class="numbers">
+              @if(isRanged){
+              <div class="flex-row t-1">
+                <div class="w-50">
+                  <div class="input-label">Normale Reichweite</div>
+                  <mat-form-field appearance="outline">
+                    <input
+                      class="right"
+                      type="number"
+                      matInput
+                      [(ngModel)]="range[0]"
+                    />
+                    <span class="input-value" matTextSuffix>Fuß</span>
+                  </mat-form-field>
+                </div>
+                <div>
+                  <div class="input-label">Erweiterte Reichweite</div>
+                  <mat-form-field appearance="outline">
+                    <input
+                      class="right"
+                      type="number"
+                      matInput
+                      [(ngModel)]="range[1]"
+                    />
+                    <span class="input-value" matTextSuffix>Fuß</span>
+                  </mat-form-field>
+                </div>
+              </div>
+              } @if(canBeThrown){
+              <div class="flex-row t-2">
+                <div class="w-50">
+                  <div class="input-label">Normale Wurfreichweite</div>
+                  <mat-form-field appearance="outline">
+                    <input
+                      class="right"
+                      type="number"
+                      matInput
+                      [(ngModel)]="throwRange[0]"
+                    />
+                    <span class="input-value" matTextSuffix>Fuß</span>
+                  </mat-form-field>
+                </div>
+                <div>
+                  <div class="input-label">Erweiterte Wurfreichweite</div>
+                  <mat-form-field appearance="outline">
+                    <input
+                      class="right"
+                      type="number"
+                      matInput
+                      [(ngModel)]="throwRange[1]"
+                    />
+                    <span class="input-value" matTextSuffix>Fuß</span>
+                  </mat-form-field>
+                </div>
+              </div>
+              }
+            </div>
+          </ng-template>
+        </ng-container>
+        <ng-container ngbNavItem="description">
+          <button ngbNavLink>Beschreibung</button>
+          <ng-template ngbNavContent>
+            <div class="NgxEditor__Wrapper">
+              <ngx-editor-menu [editor]="editor" [toolbar]="toolbar">
+              </ngx-editor-menu>
+              <ngx-editor
+                [editor]="editor"
+                [(ngModel)]="description"
+                placeholder="Beschreibung der Waffe"
+              ></ngx-editor>
+            </div>
+          </ng-template>
+        </ng-container>
       </div>
-      <icon
-        *ngIf="damage.length < 3"
-        (click)="addDamage()"
-        [size]="'m'"
-        [type]="'UI'"
-        [icon]="'add'"
-        [class]="'pointer'"
-      ></icon>
-    </div>
 
-    <div class="button-wrapper-2-block">
-      @if(isUpdate){
-      <ui-button
-        [type]="'update'"
-        [size]="'xlarge'"
-        [color]="'primary'"
-        (click)="update()"
-      ></ui-button>
-      }@else{
-      <ui-button
-        *ngIf="!isUpdate"
-        [type]="'add'"
-        [size]="'xlarge'"
-        [color]="'primary'"
-        (click)="add()"
-      ></ui-button>
-      }
-      <ui-button
-        [type]="'cancel'"
-        [size]="'xlarge'"
-        [color]="'primary'"
-        (click)="cancel()"
-      ></ui-button>
+      <div
+        [ngbNavOutlet]="nav"
+        style="
+          width: 100%;
+          min-height: 20rem;
+          max-height: 26rem;
+          overflow-y: auto;
+          overflow-x: hidden;
+        "
+        class="ms-4"
+      ></div>
     </div>
+
+    <hr />
+  </div>
+
+  <div class="horizontal-buttons">
+    @if(isUpdate){
+    <ui-button [color]="'green'" style="width: 40%" (click)="update()">
+      Anpassen
+    </ui-button>
+    }@else{
+    <ui-button [color]="'green'" style="width: 40%" (click)="add()">
+      Erstellen
+    </ui-button>
+    }
+    <ui-button [color]="'red'" style="width: 40%" (click)="cancel()">
+      Abbrechen
+    </ui-button>
   </div>
 </div>
+
+Hallo, was geht ab ? Ich möchte gerne

+ 81 - 54
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-modal/weapon-modal.component.scss

@@ -1,75 +1,102 @@
-.modal-dimensions {
-    width: 40vw;
-    background-color: var(--modal-background);
-    border-radius: 10px;
-    border: 1px solid var(--border-color);
-    padding: 1rem;
-}
-
-.add-form-group {
+.checkbox-row {
     display: flex;
-    flex-direction: column;
+    flex-direction: row;
     gap: 1rem;
+    align-items: center;
 }
-.input-element {
+
+.checkbox-column {
+    width: 50%;
     display: flex;
     flex-direction: column;
+    gap: 0.5rem;
+    padding-left: 0.5rem;
 }
 
-.checkbox-element {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    flex-basis: 33.33%;
+.damage-box {
+    width: 50%;
 }
 
-.form-element-row {
-    display: flex;
-    flex-direction: row;
-    flex-wrap: wrap;
-    justify-content: space-around;
-    text-align: center;
-    row-gap: 1rem;
+.damage-box {
+    icon-button {
+        padding-left: 5.5rem;
+        margin-bottom: 1rem;
+        margin-top: 0.5rem;
+    }
 }
 
-.damage-container {
-    display: flex;
-    flex-direction: row;
-    gap: 1rem;
+::ng-deep div.d-flex {
+    .mat-mdc-form-field-infix {
+        height: 40px !important;
+        min-height: 40px !important;
+        padding-top: 8px !important;
+    }
 }
 
-.damage-row {
-    display: flex;
-    flex-direction: row;
-    justify-content: center;
-    align-items: center;
-    gap: 0.1rem;
+.numbers {
+    input::-webkit-outer-spin-button,
+    input::-webkit-inner-spin-button {
+        display: none;
+    }
+
+    input {
+        -moz-appearance: textfield;
+    }
+
+    .input-value {
+        padding-left: 0.5rem;
+    }
+
+    span {
+        color: darkgrey;
+    }
+    ::ng-deep .mat-mdc-text-field-wrapper {
+        width: 12rem !important;
+    }
 }
 
-.damage-box {
-    display: flex;
-    flex-direction: column;
-    align-items: left;
-    gap: 0.5rem;
-    flex-basis: 30%;
+div.nav-pills.flex-column.nav {
+    border-right: 1px solid darkgray;
+    padding-right: 4px;
 }
 
-.dice-row {
-    display: flex;
-    flex-direction: row;
-    gap: 1rem;
-    margin-bottom: 1rem;
+::ng-deep .ProseMirror {
+    height: 17.5rem !important;
+    overflow-y: auto;
 }
 
-.button-wrapper {
-    width: 100%;
-    display: grid;
-    grid-template-rows: 1fr 1fr;
-    grid-template-columns: 1fr;
-    gap: 10px;
-    margin-top: 2rem;
-    margin-top: 2rem;
+.navigation-bar {
+    padding-top: 0.5rem;
+    gap: 1rem;
+    height: 20rem;
     align-items: center;
-    justify-content: center;
+    border-right: 1px solid rgba(0, 0, 0, 0.125);
+    padding-right: 4px;
+    width: 11rem;
+    // box-shadow: var(--shadow);
+
+    .nav-link {
+        width: 100%;
+        border-radius: 10px;
+        transition: all 0.25s ease-in-out;
+        // font-size: 1.25rem;
+        font-weight: 600;
+        color: var(--text);
+        // padding: 0;
+
+        &.active,
+        &:hover {
+            background-color: var(--tab-active);
+            box-shadow: var(--shadow);
+        }
+    }
+
+    .disabled-button {
+        padding: 8px 0;
+        border: none;
+        font-weight: 600;
+        color: black;
+        cursor: not-allowed;
+        opacity: 0.5;
+    }
 }

+ 21 - 4
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-modal/weapon-modal.component.ts

@@ -2,6 +2,7 @@ import { Component, Input } from '@angular/core';
 import { Weapon } from 'src/interfaces/weapon';
 import { Damage } from 'src/interfaces/damage';
 import { ModalService } from 'src/services/modal/modal.service';
+import { Editor } from 'ngx-editor';
 
 @Component({
   selector: 'app-weapon-modal',
@@ -15,6 +16,7 @@ export class WeaponModalComponent {
 
   public name: string = '';
   public range: number[] = [5, 5];
+  public hasReach: boolean = false;
   public throwRange: number[] = [5, 5];
   public attackBonus: string = '+0';
   public damage: Damage[] = [{ diceNumber: '', diceType: '', damageType: '' }];
@@ -28,6 +30,17 @@ export class WeaponModalComponent {
   public weight: string = 'normal';
   public isMagical: boolean = false;
   public magicBonus: number = 0;
+  public description: string = '';
+
+  active = 'damage';
+  editor: Editor = new Editor();
+  html = '';
+  toolbar: any = [
+    // default value
+    ['bold', 'italic'],
+    ['bullet_list'],
+    [{ heading: ['h3', 'h4', 'h5', 'h6'] }],
+  ];
 
   // Options for the select boxes
   public weights: string[] = ['leicht', 'normal', 'schwer'];
@@ -48,7 +61,7 @@ export class WeaponModalComponent {
     { display: 'Kraft', value: 'force' },
   ];
 
-  public dice: string[] = ['d4', 'd6', 'd8', 'd10', 'd12', 'd20', 'd100'];
+  public dice: string[] = ['W4', 'W6', 'W8', 'W10', 'W12', 'W20', 'W100'];
 
   public numbers: string[] = [
     '1',
@@ -64,9 +77,6 @@ export class WeaponModalComponent {
   ];
 
   public attackBonuses: string[] = [
-    '-5',
-    '-4',
-    '-3',
     '-2',
     '-1',
     '+0',
@@ -109,6 +119,7 @@ export class WeaponModalComponent {
   public loadItem(): void {
     this.name = this.item.name;
     this.range = this.item.range;
+    this.hasReach = this.item.hasReach;
     this.throwRange = this.item.throwRange;
     this.attackBonus = this.item.attackBonus;
     this.damage = this.item.damage;
@@ -122,6 +133,7 @@ export class WeaponModalComponent {
     this.weight = this.item.weight;
     this.isMagical = this.item.isMagical;
     this.magicBonus = this.item.magicBonus;
+    this.description = this.item.description;
   }
 
   // RESPONSES
@@ -132,6 +144,7 @@ export class WeaponModalComponent {
   }
 
   public add(): void {
+    console.log(this.createItem());
     this.modalAccessor.handleModalClosing('add', this.createItem());
     this.resetItem();
   }
@@ -145,6 +158,7 @@ export class WeaponModalComponent {
     return {
       name: this.name,
       range: this.range,
+      hasReach: this.hasReach,
       throwRange: this.throwRange,
       attackBonus: this.attackBonus,
       damage: this.damage,
@@ -158,6 +172,7 @@ export class WeaponModalComponent {
       weight: this.weight,
       isMagical: this.isMagical,
       magicBonus: this.magicBonus,
+      description: this.description,
     };
   }
 
@@ -167,6 +182,7 @@ export class WeaponModalComponent {
   public resetItem(): void {
     this.name = '';
     this.range = [5, 5];
+    this.hasReach = false;
     this.throwRange = [5, 5];
     this.attackBonus = '+0';
     this.damage = [{ diceNumber: '', diceType: '', damageType: '' }];
@@ -180,6 +196,7 @@ export class WeaponModalComponent {
     this.weight = 'normal';
     this.isMagical = false;
     this.magicBonus = 0;
+    this.description = '';
   }
 
   // COMPONENT LOGIC

+ 3 - 1
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.html

@@ -54,7 +54,9 @@
     }
   </div>
   <div class="footer">
-    <button (click)="openModal(false)">Hinzufügen</button>
+    <ui-button [color]="'green'" style="width: 80%" (click)="openModal(false)">
+      Hinzufügen
+    </ui-button>
   </div>
 </div>
 

+ 1 - 1
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.scss

@@ -1,7 +1,7 @@
 .heading-list {
   flex: 0 0 3rem;
   display: grid;
-  padding: 10px 20px;
+  padding: 10px 12px;
   grid-template-columns: 6fr 20fr 8fr 16fr 10fr;
   text-align: center;
   font-weight: 700;

+ 0 - 1
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.ts

@@ -83,7 +83,6 @@ export class WeaponTableComponent {
     }
     if (weapon.isMagical) {
       bonus = weapon.magicBonus!;
-      console.log(typeof weapon.magicBonus);
     }
     this.damageModifiers[index] = this.calculateModifier(value, bonus);
   }

+ 4 - 0
src/app/journal/journal.module.ts

@@ -93,6 +93,8 @@ import { SubclassComponent } from './journal-character/subclass/subclass.compone
 import { SpeciesComponent } from './journal-character/species/species.component';
 import { BackgroundComponent } from './journal-character/background/background.component';
 import { StoryComponent } from './journal-character/story/story.component';
+import { FavoriteSpellsModalComponent } from './journal-stats/weapons-container/spell-table/favorite-spells-modal/favorite-spells-modal.component';
+import { MatRippleModule } from '@angular/material/core';
 
 @NgModule({
   declarations: [
@@ -170,6 +172,7 @@ import { StoryComponent } from './journal-character/story/story.component';
     SpeciesComponent,
     BackgroundComponent,
     StoryComponent,
+    FavoriteSpellsModalComponent,
   ],
   imports: [
     CommonModule,
@@ -189,6 +192,7 @@ import { StoryComponent } from './journal-character/story/story.component';
     MatExpansionModule,
     MarkdownModule.forRoot(),
     NgxEditorModule,
+    MatRippleModule,
   ],
 })
 export class JournalModule {}

+ 15 - 17
src/app/journal/spell-modal/spell-modal.component.scss

@@ -1,4 +1,4 @@
-.modal-dimensions{
+.modal-dimensions {
     width: 40vw;
     background-color: antiquewhite;
     border-radius: 10px;
@@ -6,25 +6,25 @@
     padding: 1rem;
 }
 
-.range-area-container{
+.range-area-container {
     display: flex;
     flex-direction: row;
 }
 
-.range-box, .area-box{
+.range-box,
+.area-box {
     display: flex;
     flex-direction: column;
     flex-basis: 45%;
     gap: 1rem;
 }
 
-.add-form-group{
+.add-form-group {
     display: flex;
     flex-direction: column;
     gap: 1rem;
-    
 }
-.input-element{
+.input-element {
     display: flex;
     flex-direction: column;
     // gap: 0.1rem;
@@ -32,7 +32,7 @@
     // justify-content: center;
 }
 
-.checkbox-element{
+.checkbox-element {
     display: flex;
     flex-direction: column;
     align-items: center;
@@ -40,25 +40,24 @@
     flex-basis: 33.33%;
 }
 
-.form-element-row{
+.form-element-row {
     display: flex;
     flex-direction: row;
     flex-wrap: wrap;
     justify-content: space-around;
-    text-align:center;
+    text-align: center;
     row-gap: 1rem;
 }
 
-.damage-container{
+.damage-container {
     display: flex;
     flex-direction: row;
     gap: 1rem;
     // align-items: center;
     // justify-content: center;
-    
 }
 
-.damage-row{
+.damage-row {
     display: flex;
     flex-direction: row;
     justify-content: center;
@@ -66,15 +65,15 @@
     gap: 0.1rem;
 }
 
-.damage-box{
-    display:flex;
+.damage-box {
+    display: flex;
     flex-direction: column;
     align-items: left;
     gap: 0.5rem;
     flex-basis: 30%;
 }
 
-.dice-row{
+.dice-row {
     display: flex;
     flex-direction: row;
     // justify-content: center;
@@ -83,8 +82,7 @@
     margin-bottom: 1rem;
 }
 
-
-.button-wrapper{
+.button-wrapper {
     width: 100%;
     display: grid;
     grid-template-rows: 1fr 1fr;

+ 1 - 1
src/app/shared-components/full-spellcard/full-spellcard.component.html

@@ -114,7 +114,7 @@
 
   <div class="delete-row">
     @if(isFromDashboard){
-    <button class="delete-button" (click)="delete()">Entfernen</button>
+    <button class="delete-button" (click)="remove()">Entfernen</button>
     }@else {
 
     <!-- Add to favorites -->

+ 2 - 0
src/interfaces/weapon.ts

@@ -3,6 +3,7 @@ export interface Weapon {
   damage: Damage[];
   attackBonus: string;
   range: number[];
+  hasReach: boolean;
   throwRange?: number[];
   proficient: boolean;
   isVersatile: boolean;
@@ -14,6 +15,7 @@ export interface Weapon {
   versatileDamage?: string;
   isMagical: boolean;
   magicBonus?: number;
+  description: string;
 }
 
 interface Damage {

+ 7 - 12
src/styles.scss

@@ -97,17 +97,6 @@
 
     --border: 1px solid var(--border-color);
 
-    // Auslagern in UI-Button
-    // .standard-button {
-    //     border: var(--border);
-    //     border-radius: 10px;
-    //     font-size: 1.25rem;
-    //     height: 3rem;
-    //     font-weight: 600;
-    //     box-shadow: var(--shadow);
-    //     transition: background-color 0.25s ease-in-out;
-    // }
-
     // Responsiveness
     .responsive-small {
         display: none;
@@ -279,7 +268,7 @@ input[type="checkbox"] {
 // DETAILS + MODAL
 
 .dimensions {
-    width: 50vw;
+    width: 50rem;
     background-color: var(--modal-background);
     border-radius: 10px;
     border: 1px solid var(--border-color);
@@ -313,6 +302,11 @@ input[type="checkbox"] {
     margin-bottom: 1.5rem;
 }
 
+.input-label {
+    font-weight: 600;
+    padding-left: 0.25rem;
+}
+
 .value-row {
     display: flex;
     flex-direction: row;
@@ -346,6 +340,7 @@ input[type="checkbox"] {
 // RICH TEXT EDITOR
 .ProseMirror {
     padding-left: 1rem !important;
+    height: 8rem;
 }
 
 // Used to remove the empty space under form fields