浏览代码

-added the spell table
-dynamic computation of attack and dc pending
-just created the spell- modal

Christopher Giese 1 年之前
父节点
当前提交
85adfdfec4
共有 54 个文件被更改,包括 1270 次插入398 次删除
  1. 2 1
      package.json
  2. 1 1
      src/app/journal/icon/icon.component.html
  3. 11 0
      src/app/journal/icon/icon.component.scss
  4. 17 5
      src/app/journal/icon/icon.component.ts
  5. 153 0
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.html
  6. 140 0
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.scss
  7. 21 0
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.spec.ts
  8. 43 0
      src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.ts
  9. 0 1
      src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.html
  10. 0 21
      src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.spec.ts
  11. 0 10
      src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.ts
  12. 64 0
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.html
  13. 108 0
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.scss
  14. 21 0
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.spec.ts
  15. 42 0
      src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.ts
  16. 7 182
      src/app/journal/journal-stats/weapons-container/weapons-container.component.html
  17. 17 49
      src/app/journal/journal-stats/weapons-container/weapons-container.component.scss
  18. 49 94
      src/app/journal/journal-stats/weapons-container/weapons-container.component.ts
  19. 8 2
      src/app/journal/journal.module.ts
  20. 1 0
      src/app/journal/spell-modal/spell-modal.component.html
  21. 0 0
      src/app/journal/spell-modal/spell-modal.component.scss
  22. 21 0
      src/app/journal/spell-modal/spell-modal.component.spec.ts
  23. 10 0
      src/app/journal/spell-modal/spell-modal.component.ts
  24. 147 0
      src/app/journal/weapon-modal/weapon-modal.component.html
  25. 66 0
      src/app/journal/weapon-modal/weapon-modal.component.scss
  26. 21 0
      src/app/journal/weapon-modal/weapon-modal.component.spec.ts
  27. 103 0
      src/app/journal/weapon-modal/weapon-modal.component.ts
  28. 1 0
      src/assets/icons/UIIcons/add.svg
  29. 0 0
      src/assets/icons/UIIcons/check.svg
  30. 0 0
      src/assets/icons/UIIcons/cross.svg
  31. 0 0
      src/assets/icons/UIIcons/edit.svg
  32. 1 0
      src/assets/icons/UIIcons/life-minus.svg
  33. 1 0
      src/assets/icons/UIIcons/life-plus.svg
  34. 1 0
      src/assets/icons/UIIcons/life-temporary.svg
  35. 二进制
      src/assets/icons/UIIcons/minus.png
  36. 二进制
      src/assets/icons/UIIcons/plus.png
  37. 1 0
      src/assets/icons/UIIcons/remove.svg
  38. 1 0
      src/assets/icons/spellIcons/action.svg
  39. 1 0
      src/assets/icons/spellIcons/bonus.svg
  40. 1 0
      src/assets/icons/spellIcons/concentration.svg
  41. 1 0
      src/assets/icons/spellIcons/material.svg
  42. 1 0
      src/assets/icons/spellIcons/reaction.svg
  43. 1 0
      src/assets/icons/spellIcons/ritual.svg
  44. 1 0
      src/assets/icons/spellIcons/somatic.svg
  45. 1 0
      src/assets/icons/spellIcons/verbal.svg
  46. 0 0
      src/assets/icons/weaponIcons/distance.svg
  47. 0 0
      src/assets/icons/weaponIcons/meele.svg
  48. 0 0
      src/assets/icons/weaponIcons/ranged.svg
  49. 0 0
      src/assets/icons/weaponIcons/touch.svg
  50. 3 2
      src/interfaces/damage.ts
  51. 23 5
      src/interfaces/spell.ts
  52. 4 2
      src/interfaces/weapon.ts
  53. 48 21
      src/services/data/data.service.ts
  54. 106 2
      src/styles.scss

+ 2 - 1
package.json

@@ -6,7 +6,8 @@
     "start": "nx serve",
     "build": "nx build",
     "watch": "nx build --watch --configuration development",
-    "test": "nx test"
+    "test": "nx test",
+    "network":  "ng serve --host 0.0.0.0"
   },
   "private": true,
   "dependencies": {

+ 1 - 1
src/app/journal/icon/icon.component.html

@@ -1 +1 @@
-<img [class]="size" [src]="iconUrl" alt="" />
+<img [class]="size + ' ' + class" [src]="iconUrl" alt="" />

+ 11 - 0
src/app/journal/icon/icon.component.scss

@@ -1,3 +1,8 @@
+// size
+.xxs{
+    height: 0.5rem;
+    width: 0.5rem;
+}
 .xs{
     height: 1rem;
     width: 1rem;
@@ -31,4 +36,10 @@
 .xxxl{
     height: 4rem;
     width: 4rem;
+}
+
+// cursors
+
+.pointer{
+    cursor: pointer;
 }

+ 17 - 5
src/app/journal/icon/icon.component.ts

@@ -1,7 +1,7 @@
 import { Component, Input } from '@angular/core';
 
 @Component({
-  selector: 'app-icon',
+  selector: 'icon',
   templateUrl: './icon.component.html',
   styleUrls: ['./icon.component.scss'],
 })
@@ -10,12 +10,24 @@ export class IconComponent {
   //   this.iconUrl = this.iconPrefix + this.icon + 'Damage.svg';
   // }
   @Input() public icon: string = '';
-  @Input() public size: string = 'xs';
-  @Input() public type: string = 'weapon';
-  private weaponIconPrefix: string = 'assets/icons/damageIcons/';
+  @Input() public size: string = '';
+  @Input() public type: string = '';
+  @Input() public class: string = '';
+  private damageIconPrefix: string = 'assets/icons/damageIcons/';
+  private weaponIconPrefix: string = 'assets/icons/weaponIcons/';
+  private UIIconPrefix: string = 'assets/icons/UIIcons/';
+  private spellIconPrefix: string = 'assets/icons/spellIcons/';
   public iconUrl: string = '';
 
   ngOnChanges() {
-    this.iconUrl = this.weaponIconPrefix + this.icon + '.svg';
+    if (this.type === 'damage') {
+      this.iconUrl = this.damageIconPrefix + this.icon + '.svg';
+    } else if (this.type === 'weapon') {
+      this.iconUrl = this.weaponIconPrefix + this.icon + '.svg';
+    } else if (this.type === 'UI') {
+      this.iconUrl = this.UIIconPrefix + this.icon + '.svg';
+    } else if (this.type === 'spell') {
+      this.iconUrl = this.spellIconPrefix + this.icon + '.svg';
+    }
   }
 }

+ 153 - 0
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.html

@@ -0,0 +1,153 @@
+<div
+  id="spells-table"
+  cdkDropList
+  class="example-list"
+  (cdkDropListDropped)="dropWeapons($event)"
+>
+  <div
+    class="example-box"
+    *ngFor="let spell of spells; let index = index"
+    cdkDrag
+    (change)="updateSpells()"
+  >
+    <div class="spell-type">
+      <icon
+        [size]="'s'"
+        [type]="'weapon'"
+        [icon]="spell.isRanged ? 'distance' : 'touch'"
+      ></icon>
+    </div>
+
+    <div class="vertical-line"></div>
+    <!--  -->
+
+    <div class="name-box">
+      <div class="spell-name">{{ spell.name }}</div>
+      <div class="icon-bar">
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'action'"
+          *ngIf="spell.cost === 'action'"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'bonus'"
+          *ngIf="spell.cost === 'bonus'"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'reaction'"
+          *ngIf="spell.cost === 'reaction'"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'ritual'"
+          *ngIf="spell.canRitual"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'concentration'"
+          *ngIf="spell.needsConcentration"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'verbal'"
+          *ngIf="spell.needsVerbal"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'somatic'"
+          *ngIf="spell.needsSomatic"
+        ></icon>
+        <icon
+          [size]="'xxs'"
+          [type]="'spell'"
+          [icon]="'material'"
+          *ngIf="spell.needsMaterial"
+        ></icon>
+      </div>
+      <!-- Add bar with costs, components and ritual concentration -->
+      <!-- <icon
+      *ngIf="spell.canRitual"
+      [size]="'s'"
+      [type]="'spell'"
+      [icon]="'ritual'"
+    ></icon>
+    <icon
+      *ngIf="spell.needsConcentration"
+      [size]="'s'"
+      [type]="'spell'"
+      [icon]="'concentration'"
+    ></icon> -->
+    </div>
+
+    <div class="vertical-line"></div>
+    <!--  -->
+
+    <div class="spell-level">{{ spell.level }}</div>
+
+    <div class="vertical-line"></div>
+    <!--  -->
+
+    <div class="attack-container">
+      <!-- <div *ngIf="spell.needsSavingThrow" class="saving-throw">
+            <div class="saving-throw-attribute">{{ spell.savingThrowAttribute }}</div>
+            <div class="saving-throw-dc">{{ spell.savingThrowDC }}</div>
+        </div> -->
+      <div *ngIf="spell.needsSavingThrow" class="saving-throw">
+        <div class="saving-throw-attribute">
+          {{ spell.savingThrowAttribute }}
+        </div>
+        <div class="saving-throw-dc">15</div>
+      </div>
+
+      <div *ngIf="!spell.needsSavingThrow" class="attack-roll">
+        <div class="attack-roll-bonus">+7</div>
+      </div>
+    </div>
+
+    <div class="vertical-line"></div>
+    <!--  -->
+
+    <div class="damage-list">
+      <div
+        class="damage-row"
+        *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>
+    </div>
+
+    <div class="vertical-line"></div>
+    <!--  -->
+
+    <div class="spell-range">
+      <div *ngIf="spell.isRanged">{{ spell.range }}</div>
+      <div *ngIf="!spell.isRanged">5 ft.</div>
+    </div>
+
+    <div class="vertical-line"></div>
+    <!--  -->
+
+    <div class="spell-edit">
+      <icon [size]="'s'" [type]="'UI'" [icon]="'edit'"></icon>
+    </div>
+  </div>
+  <div class="add-box">
+    <button (click)="createWeapon()">+</button>
+  </div>
+</div>

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

@@ -0,0 +1,140 @@
+.example-list { 
+  max-width: 100%;
+  border: solid 1px #323232;
+  min-height: 60px;
+  display: block;
+  background: transparent;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.example-box {
+  padding: 20px 10px;
+  border-bottom: solid 1px #ccc;
+  color: rgba(0, 0, 0, 0.87);
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  box-sizing: border-box;
+  cursor: move;
+  background: white;
+  font-size: 14px;
+  input{
+    border: none;
+    background: transparent;
+    text-align: center;
+  }
+}
+
+.vertical-line{
+  width: 1px;
+  height: 3rem;
+  border-left: solid 1px rgb(121, 121, 121)
+}
+
+.spell-type{
+//   width: 2rem;
+  text-align: center;
+  flex-basis: 8%;
+}
+
+.name-box{
+    flex-basis: 20%;
+    text-align: center;
+  .spell-name{}
+  .icon-bar{
+        // display: flex;
+        // flex-direction: row;
+        // justify-content: center;
+        // align-items: center;
+        // gap: 0.1rem;
+    }
+  
+}   
+
+.spell-level{
+    flex-basis: 5%;
+// width: 2rem;
+  text-align: center;
+}
+
+.attack-container{
+    // width: 3rem;
+    flex-basis: 5%;
+
+    .saving-throw{
+
+        .saving-throw-attribute{
+            text-align: center;
+        }
+        .saving-throw-dc{
+            text-align: center;
+        }
+    }
+
+    .attack-roll{
+        .attack-roll-bonus{
+            text-align: center;
+        }    
+    }
+
+
+}
+
+// .spell-attack-bonus{
+//   width: 2rem;
+//   text-align: center;
+// }
+
+
+.damage-list{
+flex-basis: 15%;
+display: flex;
+flex-direction: column;
+}
+
+.damage-row{
+display: flex;
+flex-direction: row;
+justify-content: center;
+align-items: center;
+gap: 0.1rem;
+}
+
+
+.spell-range{
+ flex-basis: 10%;
+  text-align: center;
+}
+
+.spell-edit{
+  flex-basis: 8%;
+  text-align: center;
+}
+
+//// Drag and Drop
+
+.cdk-drag-preview {
+  box-sizing: border-box;
+  border-radius: 4px;
+  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
+              0 8px 10px 1px rgba(0, 0, 0, 0.14),
+              0 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+
+.cdk-drag-placeholder {
+  opacity: 0;
+}
+
+.cdk-drag-animating {
+  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.example-box:last-child {
+  border: none;
+}
+
+.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
+  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}

+ 21 - 0
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SpellTableComponent } from './spell-table.component';
+
+describe('SpellTableComponent', () => {
+  let component: SpellTableComponent;
+  let fixture: ComponentFixture<SpellTableComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [SpellTableComponent]
+    });
+    fixture = TestBed.createComponent(SpellTableComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 43 - 0
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.ts

@@ -0,0 +1,43 @@
+import { Component, EventEmitter, Output } from '@angular/core';
+import { DataService } from 'src/services/data/data.service';
+import { Weapon } from 'src/interfaces/weapon';
+import { Damage } from 'src/interfaces/damage';
+import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
+import { Spell } from 'src/interfaces/spell';
+
+@Component({
+  selector: 'spell-table',
+  templateUrl: './spell-table.component.html',
+  styleUrls: ['./spell-table.component.scss'],
+})
+export class SpellTableComponent {
+  public constructor(public dataAccessor: DataService) {}
+
+  @Output() public createNewSpell: EventEmitter<void> =
+    new EventEmitter<void>();
+
+  public spells!: Spell[];
+
+  public ngOnInit(): void {
+    this.spells = this.dataAccessor.getSpells();
+  }
+
+  public dropWeapons(event: CdkDragDrop<string[]>): void {
+    moveItemInArray(this.spells, event.previousIndex, event.currentIndex);
+    this.updateSpells();
+  }
+
+  public updateSpells(): void {
+    this.dataAccessor.setSpells(this.spells);
+  }
+
+  public createWeapon(): void {
+    console.log('createWeapon()');
+    this.createNewSpell.emit();
+  }
+
+  public addWeapon(spell: Spell) {
+    this.spells.push(spell);
+    this.updateSpells();
+  }
+}

+ 0 - 1
src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.html

@@ -1 +0,0 @@
-<p>weapon-row works!</p>

+ 0 - 21
src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.spec.ts

@@ -1,21 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { WeaponRowComponent } from './weapon-row.component';
-
-describe('WeaponRowComponent', () => {
-  let component: WeaponRowComponent;
-  let fixture: ComponentFixture<WeaponRowComponent>;
-
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      declarations: [WeaponRowComponent]
-    });
-    fixture = TestBed.createComponent(WeaponRowComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 10
src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.ts

@@ -1,10 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
-  selector: 'app-weapon-row',
-  templateUrl: './weapon-row.component.html',
-  styleUrls: ['./weapon-row.component.scss']
-})
-export class WeaponRowComponent {
-
-}

+ 64 - 0
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.html

@@ -0,0 +1,64 @@
+<div
+  id="weapons-table"
+  cdkDropList
+  class="example-list"
+  (cdkDropListDropped)="dropWeapons($event)"
+>
+  <div
+    class="example-box"
+    *ngFor="let weapon of weapons; let index = index"
+    cdkDrag
+    (change)="updateWeapons()"
+  >
+    <div class="weapon-type">
+      <icon
+        [size]="'s'"
+        [type]="'weapon'"
+        [icon]="weapon.isRanged ? 'ranged' : 'meele'"
+      ></icon>
+    </div>
+    <div class="vertical-line"></div>
+
+    <div class="weapon-proficient">
+      <icon
+        [size]="'s'"
+        [type]="'UI'"
+        [icon]="weapon.proficient ? 'check' : 'cross'"
+      ></icon>
+    </div>
+    <div class="vertical-line"></div>
+
+    <div class="weapon-name">{{ weapon.name }}</div>
+    <div class="vertical-line"></div>
+
+    <div class="weapon-attack-bonus">{{ weapon.attackBonus }}</div>
+    <div class="vertical-line"></div>
+
+    <div class="damage-list">
+      <div
+        class="damage-row"
+        *ngFor="let damage of weapon.damage; let index = index"
+      >
+        <span>{{ damage.diceNumber }} {{ damage.diceType }} </span>
+        <span>
+          <icon
+            [size]="'xs'"
+            [type]="'damage'"
+            [icon]="damage.damageType"
+          ></icon>
+        </span>
+      </div>
+    </div>
+    <div class="vertical-line"></div>
+
+    <div class="weapon-range">{{ weapon.range }}</div>
+    <div class="vertical-line"></div>
+
+    <div class="weapon-edit">
+      <icon [size]="'s'" [type]="'UI'" [icon]="'edit'"></icon>
+    </div>
+  </div>
+  <div class="add-box">
+    <button (click)="createWeapon()">+</button>
+  </div>
+</div>

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

@@ -0,0 +1,108 @@
+.example-list { 
+  max-width: 100%;
+  border: solid 1px #323232;
+  min-height: 60px;
+  display: block;
+  background: transparent;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.example-box {
+  padding: 20px 10px;
+  border-bottom: solid 1px #ccc;
+  color: rgba(0, 0, 0, 0.87);
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  box-sizing: border-box;
+  cursor: move;
+  background: white;
+  font-size: 14px;
+  input{
+    border: none;
+    background: transparent;
+    text-align: center;
+  }
+}
+
+.vertical-line{
+  width: 1px;
+  height: 3rem;
+  border-left: solid 1px rgb(121, 121, 121)
+}
+
+.weapon-type{
+  width: 2rem;
+  text-align: center;
+}
+
+.weapon-proficient{
+  width: 2rem;
+  text-align: center;
+}
+
+.weapon-name{
+  width: 6rem;
+  text-align: center;
+}
+
+.weapon-attack-bonus{
+  width: 2rem;
+  text-align: center;
+}
+
+.weapon-damage{
+  width: 3rem;
+  text-align: center;
+
+  .damage-list{
+  display: flex;
+  flex-direction: column;
+  }
+
+  .damage-row{
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    gap: 0.1rem;
+  }
+}
+
+.weapon-range{
+  width: 4rem;
+  text-align: center;
+}
+
+.weapon-edit{
+  width: 3rem;
+  text-align: center;
+}
+
+//// Drag and Drop
+
+.cdk-drag-preview {
+  box-sizing: border-box;
+  border-radius: 4px;
+  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
+              0 8px 10px 1px rgba(0, 0, 0, 0.14),
+              0 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+
+.cdk-drag-placeholder {
+  opacity: 0;
+}
+
+.cdk-drag-animating {
+  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.example-box:last-child {
+  border: none;
+}
+
+.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
+  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}

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

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { WeaponTableComponent } from './weapon-table.component';
+
+describe('WeaponTableComponent', () => {
+  let component: WeaponTableComponent;
+  let fixture: ComponentFixture<WeaponTableComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [WeaponTableComponent]
+    });
+    fixture = TestBed.createComponent(WeaponTableComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

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

@@ -0,0 +1,42 @@
+import { Component, EventEmitter, Output } from '@angular/core';
+import { DataService } from 'src/services/data/data.service';
+import { Weapon } from 'src/interfaces/weapon';
+import { Damage } from 'src/interfaces/damage';
+import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
+
+@Component({
+  selector: 'weapon-table',
+  templateUrl: './weapon-table.component.html',
+  styleUrls: ['./weapon-table.component.scss'],
+})
+export class WeaponTableComponent {
+  public constructor(public dataAccessor: DataService) {}
+
+  @Output() public createNewWeapon: EventEmitter<void> =
+    new EventEmitter<void>();
+
+  public weapons!: Weapon[];
+
+  public ngOnInit(): void {
+    this.weapons = this.dataAccessor.getWeapons();
+  }
+
+  public dropWeapons(event: CdkDragDrop<string[]>): void {
+    moveItemInArray(this.weapons, event.previousIndex, event.currentIndex);
+    this.updateWeapons();
+  }
+
+  public updateWeapons(): void {
+    this.dataAccessor.setWeapons(this.weapons);
+  }
+
+  public createWeapon(): void {
+    console.log('createWeapon()');
+    this.createNewWeapon.emit();
+  }
+
+  public addWeapon(weapon: Weapon) {
+    this.weapons.push(weapon);
+    this.updateWeapons();
+  }
+}

+ 7 - 182
src/app/journal/journal-stats/weapons-container/weapons-container.component.html

@@ -3,200 +3,25 @@
     <li [ngbNavItem]="1">
       <button ngbNavLink>Waffen</button>
       <ng-template ngbNavContent>
-        <div
-          id="weapons-table"
-          cdkDropList
-          class="example-list"
-          (cdkDropListDropped)="dropWeapons($event)"
-        >
-          <div
-            class="example-box"
-            *ngFor="let weapon of weapons; let index = index"
-            cdkDrag
-            (change)="updateWeapons()"
-          >
-            <div class="weapon-type">
-              <app-icon
-                [size]="'s'"
-                [type]="'weapon'"
-                [icon]="weapon.isRanged ? 'meele' : 'ranged'"
-              ></app-icon>
-            </div>
-            <div class="vertical-line"></div>
-
-            <div class="weapon-proficient">
-              <app-icon
-                [size]="'s'"
-                [type]="'weapon'"
-                [icon]="weapon.proficient ? 'check' : 'cross'"
-              ></app-icon>
-            </div>
-            <div class="vertical-line"></div>
-
-            <div class="weapon-name">{{ weapon.name }}</div>
-            <div class="vertical-line"></div>
-
-            <div class="weapon-attack-bonus">{{ weapon.attackBonus }}</div>
-            <div class="vertical-line"></div>
-
-            <div class="damage-list">
-              <div
-                class="damage-row"
-                *ngFor="let damage of weapon.damage; let index = index"
-              >
-                <span>{{ damage.damage }} </span>
-                <span>
-                  <app-icon [size]="'xs'" [icon]="damage.damageType"></app-icon>
-                </span>
-              </div>
-            </div>
-            <div class="vertical-line"></div>
-
-            <div class="weapon-range">{{ weapon.range }}</div>
-            <div class="vertical-line"></div>
-
-            <div class="weapon-edit">
-              <app-icon
-                [size]="'s'"
-                [type]="'weapon'"
-                [icon]="'edit'"
-              ></app-icon>
-            </div>
-          </div>
-          <div class="add-box">
-            <button (click)="openWeaponModal()">+</button>
-          </div>
-        </div>
+        <weapon-table (createNewWeapon)="openWeaponModal()"></weapon-table>
       </ng-template>
     </li>
     <li [ngbNavItem]="2">
       <button ngbNavLink>Zauber</button>
       <ng-template ngbNavContent>
-        <div
-          id="spells-table"
-          cdkDropList
-          class="example-list"
-          (cdkDropListDropped)="dropSpells($event)"
-        >
-          <div
-            class="example-box"
-            *ngFor="let spell of spells; let index = index"
-            cdkDrag
-            (change)="updateSpells()"
-          >
-            <input class="name-input" [(ngModel)]="spell.name" />
-            <input class="attack-bonus-input" [(ngModel)]="spell.attackBonus" />
-            <input class="damage-input" [(ngModel)]="spell.damage" />
-            <input class="level-input" [(ngModel)]="spell.level" />
-            <input class="range-input" [(ngModel)]="spell.range" />
-            <input class="type-input" [(ngModel)]="spell.type" />
-          </div>
-          <div class="add-box">
-            <button (click)="openSpellModal()">+</button>
-          </div>
-        </div>
+        <spell-table (createNewSpell)="openSpellModal()"></spell-table>
       </ng-template>
     </li>
   </ul>
 
   <div [ngbNavOutlet]="nav" class="mt-2"></div>
 
-  <ngx-smart-modal #weaponModal identifier="weaponModal">
-    <div>
-      <h2>Waffe hinzufügen</h2>
-
-      <div class="add-form-group">
-        <div class="form-element">
-          <label for="weaponName">Name</label>
-          <input
-            type="text"
-            class="add-input"
-            id="weaponName"
-            [(ngModel)]="newWeaponName"
-          />
-        </div>
-        <div class="form-element-row">
-          <div class="form-element" style="width: 10%">
-            <input type="checkbox" [(ngModel)]="newWeaponProficient" />
-            <label for="weaponProficient">Geübt</label>
-          </div>
-          <div class="form-element" style="width: 10%">
-            <input type="checkbox" [(ngModel)]="newWeaponIsFinesse" />
-            <label for="weaponFinesse">Finesse</label>
-          </div>
-          <div class="form-element" style="width: 10%">
-            <input type="checkbox" [(ngModel)]="newWeaponIsVersatile" />
-            <label for="Vielseitig">Vielseitig</label>
-          </div>
-          <div class="form-element" style="width: 10%">
-            <input type="checkbox" [(ngModel)]="newWeaponIsTwoHanded" />
-            <label for="weaponTwoHanded">Zweihändig</label>
-          </div>
-          <div class="form-element" style="width: 10%">
-            <input type="checkbox" [(ngModel)]="newWeaponIsRanged" />
-            <label for="weaponRanged">Fernkampf</label>
-          </div>
-        </div>
+  <!-- Modals -->
 
-        <div class="form-element">
-          <label for="weaponAttackBonus">Angriffsbonus</label>
-          <input
-            type="text"
-            class="add-input"
-            id="weaponAttackBonus"
-            [(ngModel)]="newWeaponAttackBonus"
-          />
-        </div>
-
-        <div class="form-element">
-          <label for="weaponRange">Reichweite</label>
-          <input
-            type="text"
-            class="add-input"
-            id="weaponRange"
-            [(ngModel)]="newWeaponRange"
-          />
-        </div>
-
-        <div class="damage-container">
-          <ng-container
-            *ngFor="let damage of newWeaponDamage; let index = index"
-          >
-            <div class="form-element">
-              <label for="weaponDamage">Schaden</label>
-              <input
-                type="text"
-                class="add-input"
-                id="weaponDamage"
-                [(ngModel)]="newWeaponDamage[index].damage"
-              />
-            </div>
-
-            <div class="form-element" *ngIf="newWeaponIsVersatile">
-              <label for="weaponDamageVersatile">Schaden Einhändig</label>
-              <input
-                type="text"
-                class="add-input"
-                id="weaponDamagVersatile"
-                [(ngModel)]="newWeaponDamage[index].versatileDamage"
-              />
-            </div>
-
-            <div class="form-element">
-              <label for="damageType">Schadensart</label>
-              <select [(ngModel)]="newWeaponDamage[index].damage">
-                <option *ngFor="let type of damageTypes" [value]="type">
-                  {{ type }}
-                </option>
-              </select>
-            </div>
-          </ng-container>
-        </div>
-
-        <button (click)="addWeapon()">Add</button>
-      </div>
-    </div>
-  </ngx-smart-modal>
+  <weapon-modal
+    #weaponTable
+    (weaponCreated)="addNewlyCreatedWeapon($event)"
+  ></weapon-modal>
 
   <ngx-smart-modal #spellModal identifier="spellModal">
     <h1>Zauberspruch hinzufügen</h1>

+ 17 - 49
src/app/journal/journal-stats/weapons-container/weapons-container.component.scss

@@ -19,13 +19,6 @@
   justify-content: center;
   align-items: center;
   gap: 0.1rem;
-  // margin: 0.5rem;
-
-}
-
-.damage-icon{
-  height: 1rem;
-  width: 1rem;
 }
 
 
@@ -45,12 +38,28 @@
     border: none;
     background: transparent;
     text-align: center;
-  
   }
 }
 
 //////////////// list item elemens ////////////////
 
+
+
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////
+
+
+
+
 .vertical-line{
   width: 1px;
   height: 3rem;
@@ -102,47 +111,6 @@
 
 
 
-//////////////////////////////////////////////////
-
-
-.add-box{
-    text-align: center;
-}
-
-.add-form-group{
-    display: flex;
-    flex-direction: column;
-    gap: 1rem;
-    
-}
-.form-element{
-    display: flex;
-    flex-direction: column;
-    // gap: 0.1rem;
-    // align-items: center;
-    // justify-content: center;
-}
-
-.form-element-row{
-    display: flex;
-    flex-direction: row;
-    // gap: 2rem;
-    justify-content: space-around;
-    text-align:center;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
 // Drag and Drop
 
 .cdk-drag-preview {

+ 49 - 94
src/app/journal/journal-stats/weapons-container/weapons-container.component.ts

@@ -5,6 +5,7 @@ import { Spell } from 'src/interfaces/spell';
 import { Damage } from 'src/interfaces/damage';
 import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
 import { NgxSmartModalService, NgxSmartModalComponent } from 'ngx-smart-modal';
+import { WeaponTableComponent } from './weapon-table/weapon-table.component';
 
 @Component({
   selector: 'app-weapons-container',
@@ -17,6 +18,9 @@ export class WeaponsContainerComponent {
     public ngxSmartModalService: NgxSmartModalService
   ) {}
 
+  @ViewChild(WeaponTableComponent) weaponTable!: WeaponTableComponent;
+  // @ViewChild(SpellTableComponent) spellTable!: SpellTableComponent;
+
   public active: number = 1;
 
   public newWeaponName: string = '';
@@ -24,7 +28,9 @@ export class WeaponsContainerComponent {
   public newWeaponRange: string = '';
   public newWeaponAttackBonus: string = '';
 
-  public newWeaponDamage: Damage[] = [{ damage: '', damageType: '' }];
+  public newWeaponDamage: Damage[] = [
+    { diceNumber: '', diceType: '', damageType: '' },
+  ];
 
   public newWeaponProficient: boolean = false;
   public newWeaponAttribute: string = '';
@@ -32,46 +38,25 @@ export class WeaponsContainerComponent {
   public newWeaponIsTwoHanded: boolean = false;
   public newWeaponIsFinesse: boolean = false;
   public newWeaponIsRanged: boolean = false;
-  public newWeaponVersatileDamage: Damage[] = [{ damage: '', damageType: '' }];
-
-  // public weaponAttributes: string[] = [
-  //   'Strength',
-  //   'Dexterity',
-  //   'Constitution',
-  //   'Intelligence',
-  //   'Wisdom',
-  //   'Charisma',
-  // ];
-
-  public damageTypes: string[] = [
-    'Wucht',
-    'Stich',
-    'Hieb',
-    'Feuer',
-    'Kälte',
-    'Blitz',
-    'Gift',
-    'Säure',
-    'Nekrotisch',
-    'Psychisch',
-    'Heilig',
-    'Göttlich',
-    'Kraft',
+  public newWeaponVersatileDamage: Damage[] = [
+    { diceNumber: '', diceType: '', damageType: '' },
   ];
 
-  public weapons: Weapon[] = [
-    {
-      name: 'Dagger',
-      damage: [{ damage: '1d4', damageType: 'Stich' }],
-      attackBonus: '+5',
-      range: '20/60',
-      isFinesse: true,
-      proficient: true,
-      isTwoHanded: false,
-      isVersatile: false,
-      isRanged: false,
-    },
-  ];
+  // public damageTypes: string[] = [
+  //   'Wucht',
+  //   'Stich',
+  //   'Hieb',
+  //   'Feuer',
+  //   'Kälte',
+  //   'Blitz',
+  //   'Gift',
+  //   'Säure',
+  //   'Nekrotisch',
+  //   'Psychisch',
+  //   'Heilig',
+  //   'Göttlich',
+  //   'Kraft',
+  // ];
 
   public newSpellName: string = '';
   public newSpellAttackBonus: string = '';
@@ -81,81 +66,51 @@ export class WeaponsContainerComponent {
   public newSpellProficient: boolean = false;
   public newSpellAttribute: string = '';
 
-  public spells: Spell[] = [
-    {
-      name: 'Fireball',
-      damage: '8d6',
-      attackBonus: '0',
-      range: '150',
-      type: 'Fire',
-      attribute: 'Dexterity',
-      level: 3,
-    },
-  ];
+  public spells!: Spell[];
 
   public ngOnInit(): void {
-    this.weapons = this.dataAccessor.getWeapons();
     this.spells = this.dataAccessor.getSpells();
   }
 
-  public dropWeapons(event: CdkDragDrop<string[]>): void {
-    moveItemInArray(this.weapons, event.previousIndex, event.currentIndex);
-    this.updateWeapons();
-  }
-
   public dropSpells(event: CdkDragDrop<string[]>): void {
     moveItemInArray(this.spells, event.previousIndex, event.currentIndex);
     this.updateSpells();
   }
 
-  public updateWeapons(): void {
-    this.dataAccessor.setWeapons(this.weapons);
-  }
-
   public updateSpells(): void {
     this.dataAccessor.setSpells(this.spells);
   }
 
-  public openWeaponModal(): void {
-    this.ngxSmartModalService.getModal('weaponModal').open();
+  public addSpell(): void {
+    // this.spells.push({
+    //   name: this.newSpellName,
+    //   damage: this.newSpellDamage,
+    //   attackBonus: this.newSpellAttackBonus,
+    //   range: this.newSpellRange,
+    //   type: this.newSpellType,
+    //   level: 0,
+    //   attribute: this.newSpellAttribute,
+    // });
+    this.ngxSmartModalService.getModal('spellModal').close();
   }
 
-  public addWeapon(): void {
-    const newWeapon: Weapon = {
-      name: this.newWeaponName,
-      damage: this.newWeaponDamage,
-      attackBonus: this.newWeaponAttackBonus,
-      range: this.newWeaponRange,
-      proficient: this.newWeaponProficient,
-      isTwoHanded: this.newWeaponIsTwoHanded,
-      isVersatile: this.newWeaponIsVersatile,
-      isFinesse: this.newWeaponIsFinesse,
-      isRanged: this.newWeaponIsRanged,
-      versatileDamage: this.newWeaponIsVersatile
-        ? this.newWeaponVersatileDamage
-        : undefined,
-    };
-
-    console.log('test if versatileDamage is present?', newWeapon);
-
-    this.weapons.push(newWeapon);
-    this.ngxSmartModalService.getModal('weaponModal').close();
-  }
+  // spells
 
   public openSpellModal(): void {
     this.ngxSmartModalService.getModal('spellModal').open();
   }
 
-  public addSpell(): void {
-    this.spells.push({
-      name: this.newSpellName,
-      damage: this.newSpellDamage,
-      attackBonus: this.newSpellAttackBonus,
-      range: this.newSpellRange,
-      type: this.newSpellType,
-      level: 0,
-      attribute: this.newSpellAttribute,
-    });
-    this.ngxSmartModalService.getModal('spellModal').close();
+  // public addNewlyCreatedSpell(spell: Spell): void {
+  //   this.spellTable.addWeapon(spell);
+  // }
+
+  // weapons
+  public openWeaponModal(): void {
+    console.log('openWeaponModal()');
+    this.ngxSmartModalService.getModal('weaponModal').open();
+  }
+
+  public addNewlyCreatedWeapon(weapon: Weapon): void {
+    this.weaponTable.addWeapon(weapon);
   }
 }

+ 8 - 2
src/app/journal/journal.module.ts

@@ -30,7 +30,10 @@ import { ExhaustionComponent } from './journal-stats/life-container/exhaustion/e
 import { DeathSaveComponent } from './journal-stats/life-container/death-save/death-save.component';
 import { LifeComponent } from './journal-stats/life-container/life/life.component';
 import { IconComponent } from './icon/icon.component';
-import { WeaponRowComponent } from './journal-stats/weapons-container/weapon-row/weapon-row.component';
+import { WeaponTableComponent } from './journal-stats/weapons-container/weapon-table/weapon-table.component';
+import { WeaponModalComponent } from './weapon-modal/weapon-modal.component';
+import { SpellTableComponent } from './journal-stats/weapons-container/spell-table/spell-table.component';
+import { SpellModalComponent } from './spell-modal/spell-modal.component';
 
 @NgModule({
   declarations: [
@@ -57,7 +60,10 @@ import { WeaponRowComponent } from './journal-stats/weapons-container/weapon-row
     DeathSaveComponent,
     LifeComponent,
     IconComponent,
-    WeaponRowComponent,
+    WeaponTableComponent,
+    WeaponModalComponent,
+    SpellTableComponent,
+    SpellModalComponent,
   ],
   imports: [
     CommonModule,

+ 1 - 0
src/app/journal/spell-modal/spell-modal.component.html

@@ -0,0 +1 @@
+<p>spell-modal works!</p>

+ 0 - 0
src/app/journal/journal-stats/weapons-container/weapon-row/weapon-row.component.scss → src/app/journal/spell-modal/spell-modal.component.scss


+ 21 - 0
src/app/journal/spell-modal/spell-modal.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SpellModalComponent } from './spell-modal.component';
+
+describe('SpellModalComponent', () => {
+  let component: SpellModalComponent;
+  let fixture: ComponentFixture<SpellModalComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [SpellModalComponent]
+    });
+    fixture = TestBed.createComponent(SpellModalComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 10 - 0
src/app/journal/spell-modal/spell-modal.component.ts

@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-spell-modal',
+  templateUrl: './spell-modal.component.html',
+  styleUrls: ['./spell-modal.component.scss']
+})
+export class SpellModalComponent {
+
+}

+ 147 - 0
src/app/journal/weapon-modal/weapon-modal.component.html

@@ -0,0 +1,147 @@
+<ngx-smart-modal #weaponModal identifier="weaponModal">
+  <div>
+    <h2 style="text-align: center">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)]="newWeaponName"
+        />
+      </div>
+      <div class="form-element-row">
+        <div class="checkbox-element">
+          <input type="checkbox" [(ngModel)]="newWeaponProficient" />
+          <label for="weaponProficient">Geübt</label>
+        </div>
+        <div class="checkbox-element">
+          <input type="checkbox" [(ngModel)]="newWeaponIsFinesse" />
+          <label for="weaponFinesse">Finesse</label>
+        </div>
+        <div class="checkbox-element">
+          <input type="checkbox" [(ngModel)]="newWeaponIsVersatile" />
+          <label for="Vielseitig">Vielseitig</label>
+        </div>
+        <div class="checkbox-element">
+          <input type="checkbox" [(ngModel)]="newWeaponIsTwoHanded" />
+          <label for="weaponTwoHanded">Zweihändig</label>
+        </div>
+        <div class="checkbox-element">
+          <input type="checkbox" [(ngModel)]="newWeaponIsRanged" />
+          <label for="weaponRanged">Fernkampf</label>
+        </div>
+        <div class="checkbox-element">
+          <select [(ngModel)]="newWeaponWeight">
+            <option *ngFor="let weight of weights" [value]="weight">
+              {{ weight }}
+            </option>
+          </select>
+          <label>Gewicht</label>
+        </div>
+      </div>
+
+      <div class="input-element">
+        <label for="weaponAttackBonus">Angriffsbonus</label>
+        <input
+          type="text"
+          class="add-input"
+          id="weaponAttackBonus"
+          [(ngModel)]="newWeaponAttackBonus"
+        />
+      </div>
+
+      <div class="input-element" *ngIf="newWeaponIsRanged">
+        <label for="weaponRange">Reichweite</label>
+        <input
+          type="text"
+          class="add-input"
+          id="weaponRange"
+          [(ngModel)]="newWeaponRange"
+        />
+      </div>
+
+      <h3 style="text-align: center">Schaden</h3>
+
+      <div class="damage-container">
+        <div
+          class="damage-box"
+          *ngFor="let damage of newWeaponDamage; let index = index"
+        >
+          <div class="dice-row">
+            <div class="flex-column">
+              <label>Anzahl</label>
+              <select [(ngModel)]="newWeaponDamage[index].diceNumber">
+                <option *ngFor="let number of numbers" [value]="number">
+                  {{ number }}
+                </option>
+              </select>
+            </div>
+
+            <div class="flex-column">
+              <label>Würfel</label>
+              <select [(ngModel)]="newWeaponDamage[index].diceType">
+                <option *ngFor="let die of dice" [value]="die">
+                  {{ die }}
+                </option>
+              </select>
+            </div>
+          </div>
+
+          <div *ngIf="newWeaponIsVersatile">
+            Zweihändiger Schaden
+            <div class="flex-row gap-10">
+              <div class="flex-column">
+                <label>Anzahl</label>
+                <select
+                  [(ngModel)]="newWeaponVersatileDamage[index].diceNumber"
+                >
+                  <option *ngFor="let number of numbers" [value]="number">
+                    {{ number }}
+                  </option>
+                </select>
+              </div>
+
+              <div class="flex-column">
+                <label>Würfel</label>
+                <select [(ngModel)]="newWeaponVersatileDamage[index].diceType">
+                  <option *ngFor="let die of dice" [value]="die">
+                    {{ die }}
+                  </option>
+                </select>
+              </div>
+            </div>
+          </div>
+
+          <label for="damageType">Schadensart</label>
+          <select [(ngModel)]="newWeaponDamage[index].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>
+        </div>
+        <icon
+          *ngIf="newWeaponDamage.length < 3"
+          (click)="addDamage()"
+          [size]="'m'"
+          [type]="'UI'"
+          [icon]="'add'"
+          [class]="'pointer'"
+        ></icon>
+      </div>
+
+      <button (click)="createWeapon()">Add</button>
+    </div>
+  </div>
+</ngx-smart-modal>

+ 66 - 0
src/app/journal/weapon-modal/weapon-modal.component.scss

@@ -0,0 +1,66 @@
+.add-form-group{
+    display: flex;
+    flex-direction: column;
+    gap: 1rem;
+    
+}
+.input-element{
+    display: flex;
+    flex-direction: column;
+    // gap: 0.1rem;
+    // align-items: center;
+    // justify-content: center;
+}
+
+.checkbox-element{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    flex-basis: 33.33%;
+}
+
+.form-element-row{
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    justify-content: space-around;
+    text-align:center;
+    row-gap: 1rem;
+}
+
+.damage-container{
+    display: flex;
+    flex-direction: row;
+    gap: 1rem;
+    // align-items: center;
+    // justify-content: center;
+    
+}
+
+.damage-row{
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    gap: 0.1rem;
+}
+
+.damage-box{
+    display:flex;
+    flex-direction: column;
+    align-items: left;
+    gap: 0.5rem;
+    flex-basis: 30%;
+}
+
+.dice-row{
+    display: flex;
+    flex-direction: row;
+    // justify-content: center;
+    // align-items: center;
+    gap: 1rem;
+    margin-bottom: 1rem;
+}
+
+

+ 21 - 0
src/app/journal/weapon-modal/weapon-modal.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { WeaponModalComponent } from './weapon-modal.component';
+
+describe('WeaponModalComponent', () => {
+  let component: WeaponModalComponent;
+  let fixture: ComponentFixture<WeaponModalComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [WeaponModalComponent]
+    });
+    fixture = TestBed.createComponent(WeaponModalComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 103 - 0
src/app/journal/weapon-modal/weapon-modal.component.ts

@@ -0,0 +1,103 @@
+import { Component, EventEmitter, Output } from '@angular/core';
+import { NgxSmartModalService } from 'ngx-smart-modal';
+import { Damage } from 'src/interfaces/damage';
+import { Weapon } from 'src/interfaces/weapon';
+
+@Component({
+  selector: 'weapon-modal',
+  templateUrl: './weapon-modal.component.html',
+  styleUrls: ['./weapon-modal.component.scss'],
+})
+export class WeaponModalComponent {
+  public constructor(public ngxSmartModalService: NgxSmartModalService) {}
+
+  @Output() public weaponCreated: EventEmitter<Weapon> =
+    new EventEmitter<Weapon>();
+  public active: number = 1;
+
+  public newWeaponName: string = '';
+  public newWeaponDamageType: string = '';
+  public newWeaponRange: string = '';
+  public newWeaponAttackBonus: string = '';
+  public newWeaponDamage: Damage[] = [
+    { diceNumber: '', diceType: '', damageType: '' },
+  ];
+  public newWeaponProficient: boolean = false;
+  public newWeaponAttribute: string = '';
+  public newWeaponIsVersatile: boolean = false;
+  public newWeaponIsTwoHanded: boolean = false;
+  public newWeaponIsFinesse: boolean = false;
+  public newWeaponIsRanged: boolean = false;
+  public newWeaponVersatileDamage: Damage[] = [
+    { diceNumber: '', diceType: '', damageType: '' },
+  ];
+  public newWeaponWeight: string = 'normal';
+
+  // Options for the select boxes
+  public weights: string[] = ['leicht', 'normal', 'schwer'];
+
+  public damageTypes: any[] = [
+    { display: 'Wucht', value: 'bludgeoning' },
+    { display: 'Stich', value: 'piercing' },
+    { display: 'Hieb', value: 'slashing' },
+    { display: 'Feuer', value: 'fire' },
+    { display: 'Kälte', value: 'cold' },
+    { display: 'Blitz', value: 'lightning' },
+    { display: 'Gift', value: 'poison' },
+    { display: 'Säure', value: 'acid' },
+    { display: 'Nekrotisch', value: 'necrotic' },
+    { display: 'Psychisch', value: 'psychic' },
+    { display: 'Heilig', value: 'holy' },
+    { display: 'Göttlich', value: 'divine' },
+    { display: 'Kraft', value: 'force' },
+  ];
+
+  public dice: string[] = ['d4', 'd6', 'd8', 'd10', 'd12', 'd20', 'd100'];
+
+  public numbers: string[] = [
+    '1',
+    '2',
+    '3',
+    '4',
+    '5',
+    '6',
+    '7',
+    '8',
+    '9',
+    '10',
+  ];
+  //
+
+  public createWeapon(): void {
+    const newWeapon: Weapon = {
+      name: this.newWeaponName,
+      damage: this.newWeaponDamage,
+      attackBonus: this.newWeaponAttackBonus,
+      range: this.newWeaponRange,
+      isFinesse: this.newWeaponIsFinesse,
+      proficient: this.newWeaponProficient,
+      isTwoHanded: this.newWeaponIsTwoHanded,
+      isVersatile: this.newWeaponIsVersatile,
+      isRanged: this.newWeaponIsRanged,
+      versatileDamage: this.newWeaponVersatileDamage,
+      weight: this.newWeaponWeight,
+    };
+    this.weaponCreated.emit(newWeapon);
+    // remove modal
+    this.ngxSmartModalService.removeModal('weaponModal');
+  }
+
+  public addDamage(): void {
+    this.newWeaponDamage.push({ diceNumber: '', diceType: '', damageType: '' });
+    this.newWeaponVersatileDamage.push({
+      diceNumber: '',
+      diceType: '',
+      damageType: '',
+    });
+  }
+
+  public removeDamage(index: number): void {
+    this.newWeaponDamage.splice(index, 1);
+    this.newWeaponVersatileDamage.splice(index, 1);
+  }
+}

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

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H48c-17.7 0-32 14.3-32 32s14.3 32 32 32H192V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H400c17.7 0 32-14.3 32-32s-14.3-32-32-32H256V80z"/></svg>

+ 0 - 0
src/assets/icons/damageIcons/check.svg → src/assets/icons/UIIcons/check.svg


+ 0 - 0
src/assets/icons/damageIcons/cross.svg → src/assets/icons/UIIcons/cross.svg


+ 0 - 0
src/assets/icons/damageIcons/edit.svg → src/assets/icons/UIIcons/edit.svg


+ 1 - 0
src/assets/icons/UIIcons/life-minus.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><g class="" transform="translate(0,0)" style=""><path d="M372.48 31.215c-77.65 0-116.48 65.73-116.48 65.73s-38.83-65.72-116.48-65.72c-37.14 0-107.77 33.72-107.77 125.13 0 161.24 224.25 324.43 224.25 324.43s224.25-163.19 224.25-324.43c0-91.42-70.63-125.13-107.77-125.14zM146.924 225.65h220v60.7h-220z" fill="#060606" fill-opacity="1"></path></g></svg>

+ 1 - 0
src/assets/icons/UIIcons/life-plus.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><g class="" transform="translate(0,0)" style=""><path d="M372.48 31.215c-77.65 0-116.48 65.73-116.48 65.73s-38.83-65.72-116.48-65.72c-37.14 0-107.77 33.72-107.77 125.13 0 161.24 224.25 324.43 224.25 324.43s224.25-163.19 224.25-324.43c0-91.42-70.63-125.13-107.77-125.14zm-145.492 115.02h60.698v79.415h79.238v60.7h-79.238v79.884h-60.698V286.35h-80.064v-60.7h80.064z" fill="#060606" fill-opacity="1"></path></g></svg>

+ 1 - 0
src/assets/icons/UIIcons/life-temporary.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><g class="" transform="translate(0,0)" style=""><path d="M256 32c-64 48-128 64-224 96 0 128 160 320 224 368 64-48 224-240 224-368-96-32-160-48-224-96zm0 34.75l5.4 4.05c49.7 37.3 99.6 49.9 176.7 75.6l6.2 2v6.5c0 55-33.1 119.7-72 176.4-38.9 56.8-83.6 105-110.9 125.5l-5.4 4.1-5.4-4.1c-27.3-20.5-72-68.7-110.9-125.5-38.9-56.7-72-121.4-72-176.4v-6.5l6.15-2C150.9 120.7 200.9 108 250.6 70.8l5.4-4.05zm0 22.18c-49.4 35.37-99.8 49.17-170.05 72.37 2.58 46.7 32.35 107 68.65 159.9 35.3 51.5 76.6 96.3 101.4 116.8 24.8-20.5 66.1-65.3 101.4-116.8 36.3-52.9 66.1-113.2 68.6-159.9-70.3-23.2-120.6-37-170-72.37zm-45.5 54.97c19.7.5 38.1 14.4 45.5 48.1 18-86.3 110-42.5 110 22.5-1 63.9-92 107.7-110 162.1-19-54.4-108-98.2-110-162.1 0-39.6 33.8-71.3 64.5-70.6z" fill="#060606" fill-opacity="1"></path></g></svg>

二进制
src/assets/icons/UIIcons/minus.png


二进制
src/assets/icons/UIIcons/plus.png


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

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM184 232H328c13.3 0 24 10.7 24 24s-10.7 24-24 24H184c-13.3 0-24-10.7-24-24s10.7-24 24-24z"/></svg>

+ 1 - 0
src/assets/icons/spellIcons/action.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(40.500001, 770.884888)"><g><path d="M 719.5625 0 L 563.65625 0 L 507.234375 -172.84375 L 220.03125 -172.84375 L 163.609375 0 L 11.28125 0 L 270.28125 -749.828125 L 460.5625 -749.828125 Z M 356.453125 -593.40625 L 260.03125 -297.46875 L 466.203125 -297.46875 L 369.265625 -593.40625 Z M 356.453125 -593.40625 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/bonus.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(40.500001, 770.884888)"><g><path d="M 97.453125 0 L 97.453125 -749.828125 L 417.484375 -749.828125 C 463.640625 -749.828125 502.703125 -742.5625 534.671875 -728.03125 C 566.640625 -713.5 590.828125 -692.8125 607.234375 -665.96875 C 623.648438 -639.132812 631.859375 -607.421875 631.859375 -570.828125 C 631.859375 -537.660156 623.820312 -508.425781 607.75 -483.125 C 591.6875 -457.820312 568.609375 -437.476562 538.515625 -422.09375 L 538.515625 -411.328125 C 585.703125 -399.015625 622.117188 -376.617188 647.765625 -344.140625 C 673.410156 -311.660156 686.234375 -271.828125 686.234375 -224.640625 C 686.234375 -152.835938 664.601562 -97.445312 621.34375 -58.46875 C 578.09375 -19.488281 513.898438 0 428.765625 0 Z M 386.703125 -450.8125 C 455.773438 -450.8125 490.3125 -481.925781 490.3125 -544.15625 C 490.3125 -575.957031 481.765625 -599.632812 464.671875 -615.1875 C 447.578125 -630.75 421.585938 -638.53125 386.703125 -638.53125 L 245.671875 -638.53125 L 245.671875 -450.8125 Z M 413.890625 -117.453125 C 495.609375 -117.453125 536.46875 -154.550781 536.46875 -228.75 C 536.46875 -303.28125 495.609375 -340.546875 413.890625 -340.546875 L 245.671875 -340.546875 L 245.671875 -117.453125 Z M 413.890625 -117.453125 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/concentration.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(50.062961, 757.239642)"><g><path d="M 395.359375 10.390625 C 328.722656 10.390625 270.003906 -3.460938 219.203125 -31.171875 C 168.398438 -58.878906 128.648438 -100.523438 99.953125 -156.109375 C 71.253906 -211.703125 56.90625 -280.238281 56.90625 -361.71875 C 56.90625 -443.195312 71.253906 -511.722656 99.953125 -567.296875 C 128.648438 -622.878906 168.398438 -664.523438 219.203125 -692.234375 C 270.003906 -719.941406 328.722656 -733.796875 395.359375 -733.796875 C 464.960938 -733.796875 524.085938 -720.1875 572.734375 -692.96875 C 621.390625 -665.757812 656.109375 -624.28125 676.890625 -568.53125 L 572.484375 -504.71875 L 560.125 -505.203125 C 544.613281 -542.804688 523.582031 -569.769531 497.03125 -586.09375 C 470.488281 -602.425781 436.597656 -610.59375 395.359375 -610.59375 C 335.316406 -610.59375 288.472656 -590.71875 254.828125 -550.96875 C 221.179688 -511.226562 204.359375 -448.144531 204.359375 -361.71875 C 204.359375 -275.613281 221.179688 -212.6875 254.828125 -172.9375 C 288.472656 -133.1875 335.316406 -113.3125 395.359375 -113.3125 C 489.367188 -113.3125 546.925781 -159 568.03125 -250.375 L 580.40625 -250.375 L 685.796875 -195.453125 C 666.003906 -126.835938 632.191406 -75.375 584.359375 -41.0625 C 536.535156 -6.757812 473.535156 10.390625 395.359375 10.390625 Z M 395.359375 10.390625 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/material.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(-82.191168, 768.502554)"><g><path d="M 233.359375 0 L 97.453125 0 L 97.453125 -749.828125 L 291.3125 -749.828125 L 481.078125 -198.484375 L 491.84375 -198.484375 L 680.59375 -749.828125 L 869.84375 -749.828125 L 869.84375 0 L 729.3125 0 L 729.3125 -495.4375 L 716.484375 -497.484375 L 543.140625 0 L 419.53125 0 L 246.1875 -497.484375 L 233.359375 -495.4375 Z M 233.359375 0 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/reaction.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(40.092959, 775.649584)"><g><path d="M 97.453125 0 L 97.453125 -749.828125 L 398.5 -749.828125 C 476.125 -749.828125 534.679688 -731.960938 574.171875 -696.234375 C 613.660156 -660.503906 633.40625 -611.179688 633.40625 -548.265625 C 633.40625 -502.785156 621.863281 -465.515625 598.78125 -436.453125 C 575.707031 -407.390625 541.257812 -385.164062 495.4375 -369.78125 L 495.4375 -359.015625 C 519.03125 -348.753906 538.09375 -333.535156 552.625 -313.359375 C 567.15625 -293.191406 580.914062 -263.273438 593.90625 -223.609375 L 668.796875 0 L 516.46875 0 L 443.125 -224.125 C 435.601562 -246.695312 427.140625 -264.222656 417.734375 -276.703125 C 408.335938 -289.179688 396.375 -298.238281 381.84375 -303.875 C 367.3125 -309.519531 348.421875 -312.34375 325.171875 -312.34375 L 245.671875 -312.34375 L 245.671875 0 Z M 380.5625 -429.796875 C 452.363281 -429.796875 488.265625 -463.300781 488.265625 -530.3125 C 488.265625 -598.351562 452.363281 -632.375 380.5625 -632.375 L 245.671875 -632.375 L 245.671875 -429.796875 Z M 380.5625 -429.796875 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/ritual.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(5.951462, 572.431517)"><g><path d="M 46.671875 0 L 46.671875 -359.109375 L 190.859375 -359.109375 C 228.023438 -359.109375 256.0625 -350.550781 274.96875 -333.4375 C 293.882812 -316.320312 303.34375 -292.703125 303.34375 -262.578125 C 303.34375 -240.796875 297.816406 -222.945312 286.765625 -209.03125 C 275.710938 -195.113281 259.21875 -184.46875 237.28125 -177.09375 L 237.28125 -171.9375 C 248.570312 -167.03125 257.695312 -159.742188 264.65625 -150.078125 C 271.625 -140.421875 278.21875 -126.09375 284.4375 -107.09375 L 320.296875 0 L 247.34375 0 L 212.21875 -107.34375 C 208.613281 -118.144531 204.5625 -126.535156 200.0625 -132.515625 C 195.5625 -138.492188 189.832031 -142.832031 182.875 -145.53125 C 175.914062 -148.238281 166.867188 -149.59375 155.734375 -149.59375 L 117.65625 -149.59375 L 117.65625 0 Z M 182.25 -205.84375 C 216.644531 -205.84375 233.84375 -221.890625 233.84375 -253.984375 C 233.84375 -286.566406 216.644531 -302.859375 182.25 -302.859375 L 117.65625 -302.859375 L 117.65625 -205.84375 Z M 182.25 -205.84375 "/></g></g><g transform="translate(341.720918, 572.431517)"><g><path d="M 117.65625 0 L 46.671875 0 L 46.671875 -359.109375 L 117.65625 -359.109375 Z M 117.65625 0 "/></g></g><g transform="translate(506.289709, 572.431517)"><g><path d="M 287.875 -359.109375 L 287.875 -299.421875 L 184.21875 -299.421875 L 184.21875 0 L 113.484375 0 L 113.484375 -299.421875 L 9.828125 -299.421875 L 9.828125 -359.109375 Z M 287.875 -359.109375 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/somatic.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(91.221196, 768.502554)"><g><path d="M 332.34375 10.765625 C 280.375 10.765625 234.128906 4.351562 193.609375 -8.46875 C 153.085938 -21.289062 119.320312 -38.128906 92.3125 -58.984375 C 65.300781 -79.835938 44.617188 -102.742188 30.265625 -127.703125 L 111.8125 -227.203125 L 124.625 -227.203125 C 147.195312 -193.691406 175.832031 -167.019531 210.53125 -147.1875 C 245.238281 -127.363281 285.84375 -117.453125 332.34375 -117.453125 C 372.007812 -117.453125 401.925781 -125.828125 422.09375 -142.578125 C 442.269531 -159.335938 452.359375 -182.414062 452.359375 -211.8125 C 452.359375 -229.59375 449.109375 -244.46875 442.609375 -256.4375 C 436.117188 -268.40625 425.347656 -278.660156 410.296875 -287.203125 C 395.253906 -295.753906 374.910156 -303.109375 349.265625 -309.265625 L 252.84375 -331.3125 C 185.488281 -346.707031 135.3125 -372.269531 102.3125 -408 C 69.320312 -443.726562 52.828125 -490.140625 52.828125 -547.234375 C 52.828125 -589.640625 63.425781 -626.910156 84.625 -659.046875 C 105.820312 -691.191406 136.675781 -716.148438 177.1875 -733.921875 C 217.707031 -751.703125 266.175781 -760.59375 322.59375 -760.59375 C 380.382812 -760.59375 429.878906 -752.984375 471.078125 -737.765625 C 512.273438 -722.554688 547.066406 -699.222656 575.453125 -667.765625 L 502.109375 -567.25 L 489.28125 -567.25 C 468.082031 -589.46875 443.804688 -606.132812 416.453125 -617.25 C 389.097656 -628.363281 357.8125 -633.921875 322.59375 -633.921875 C 281.90625 -633.921875 250.960938 -626.738281 229.765625 -612.375 C 208.566406 -598.019531 197.96875 -578.191406 197.96875 -552.890625 C 197.96875 -529.296875 205.40625 -510.488281 220.28125 -496.46875 C 235.15625 -482.445312 260.882812 -471.503906 297.46875 -463.640625 L 395.9375 -443.125 C 468.769531 -427.738281 521.597656 -401.664062 554.421875 -364.90625 C 587.242188 -328.15625 603.65625 -280.203125 603.65625 -221.046875 C 603.65625 -174.203125 593.566406 -133.425781 573.390625 -98.71875 C 553.222656 -64.019531 522.796875 -37.097656 482.109375 -17.953125 C 441.421875 1.191406 391.5 10.765625 332.34375 10.765625 Z M 332.34375 10.765625 "/></g></g></g></svg>

+ 1 - 0
src/assets/icons/spellIcons/verbal.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1080" zoomAndPan="magnify" viewBox="0 0 810 809.999993" height="1080" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><g/></defs><g fill="#000000" fill-opacity="1"><g transform="translate(57.387236, 768.502554)"><g><path d="M 445.6875 0 L 266.703125 0 L 13.328125 -749.828125 L 170.78125 -749.828125 L 352.859375 -190.796875 L 365.6875 -190.796875 L 545.1875 -749.828125 L 698.546875 -749.828125 Z M 445.6875 0 "/></g></g></g></svg>

+ 0 - 0
src/assets/icons/damageIcons/distance.svg → src/assets/icons/weaponIcons/distance.svg


+ 0 - 0
src/assets/icons/damageIcons/meele.svg → src/assets/icons/weaponIcons/meele.svg


+ 0 - 0
src/assets/icons/damageIcons/ranged.svg → src/assets/icons/weaponIcons/ranged.svg


+ 0 - 0
src/assets/icons/damageIcons/touch.svg → src/assets/icons/weaponIcons/touch.svg


+ 3 - 2
src/interfaces/damage.ts

@@ -1,5 +1,6 @@
 export interface Damage {
-  damage: string;
+  diceNumber: string;
+  diceType: string;
   damageType: string;
-  versatileDamage?: string;
+  additionalDamage?: string;
 }

+ 23 - 5
src/interfaces/spell.ts

@@ -1,10 +1,28 @@
 export interface Spell {
   name: string;
-  damage: string;
-  attackBonus: string;
-  range: string;
-  type: string;
   level: number;
-  attribute?: string;
+  cost: string;
+  canRitual?: boolean;
+  needsConcentration: boolean;
+  needsVerbal: boolean;
+  needsSomatic: boolean;
+  needsMaterial: boolean;
+  school?: string;
+  description?: string;
+  needsSavingThrow: boolean;
+  savingThrowAttribute?: string;
+  attackBonus?: string;
+  damage: Damage[];
+  isRanged: boolean;
+  range?: string;
+  hasAreaOfEffect: boolean;
   radius?: string;
+  areaOfEffectType?: string;
+}
+
+interface Damage {
+  diceNumber: string;
+  diceType: string;
+  damageType: string;
+  additionalDamage?: string;
 }

+ 4 - 2
src/interfaces/weapon.ts

@@ -8,11 +8,13 @@ export interface Weapon {
   isTwoHanded: boolean;
   isFinesse: boolean;
   isRanged: boolean;
+  weight: string;
   versatileDamage?: Damage[];
 }
 
 interface Damage {
-  damage: string;
+  diceNumber: string;
+  diceType: string;
   damageType: string;
-  versatileDamage?: string;
+  additionalDamage?: string;
 }

+ 48 - 21
src/services/data/data.service.ts

@@ -142,35 +142,37 @@ export class DataService {
     {
       name: 'Großschwert',
       attackBonus: '+3',
-      damage: [{ damage: '2d6+1', damageType: 'slashing' }],
+      damage: [{ diceNumber: '2', diceType: 'd6', damageType: 'slashing' }],
       proficient: true,
       range: '5ft',
       isFinesse: false,
       isVersatile: false,
       isTwoHanded: true,
       isRanged: false,
+      weight: 'schwer',
     },
     {
       name: 'Kurzbogen',
       attackBonus: '+5',
-      damage: [{ damage: '1d6+3', damageType: 'piercing' }],
+      damage: [{ diceNumber: '1', diceType: 'd8', damageType: 'piercing' }],
       proficient: false,
       range: '80/320ft',
       isFinesse: false,
       isVersatile: false,
       isTwoHanded: true,
       isRanged: true,
+      weight: 'leicht',
     },
     {
       name: 'Feuerstab',
       attackBonus: '+5',
       damage: [
-        { damage: '1d6+3', damageType: 'bludgeoning' },
-        { damage: '1d4', damageType: 'fire' },
+        { diceNumber: '1', diceType: 'd6', damageType: 'bludgeoning' },
+        { diceNumber: '1', diceType: 'd4', damageType: 'fire' },
       ],
       versatileDamage: [
-        { damage: '1d8+3', damageType: 'bludgeoning' },
-        { damage: '1d4', damageType: 'fire' },
+        { diceNumber: '1', diceType: 'd8', damageType: 'bludgeoning' },
+        { diceNumber: '1', diceType: 'd4', damageType: 'fire' },
       ],
       proficient: true,
       range: '5ft',
@@ -178,6 +180,7 @@ export class DataService {
       isVersatile: true,
       isTwoHanded: false,
       isRanged: false,
+      weight: 'normal',
     },
   ];
 
@@ -192,27 +195,51 @@ export class DataService {
   private spells: Spell[] = [
     {
       name: 'Feuerball',
-      attackBonus: '+5',
-      damage: '8d6',
-      type: 'Feuer',
-      range: '150ft',
       level: 3,
+      cost: 'action',
+      needsVerbal: true,
+      needsSomatic: true,
+      needsMaterial: true,
+      needsConcentration: false,
+      needsSavingThrow: true,
+      savingThrowAttribute: 'DEX',
+      school: 'Evocation',
+      damage: [{ diceNumber: '8', diceType: 'd6', damageType: 'fire' }],
+      isRanged: true,
+      range: '150ft',
+      hasAreaOfEffect: true,
+      radius: '20ft',
+      areaOfEffectType: 'sphere',
     },
     {
-      name: 'Magische Geschosse',
-      attackBonus: '+5',
-      damage: '1d4+1',
-      type: 'Magisch',
+      name: 'Flammenpfeil',
+      level: 0,
+      cost: 'action',
+      needsVerbal: true,
+      needsSomatic: true,
+      needsMaterial: true,
+      needsConcentration: false,
+      needsSavingThrow: false,
+      school: 'Evocation',
+      damage: [{ diceNumber: '1', diceType: 'd10', damageType: 'fire' }],
+      isRanged: true,
       range: '120ft',
-      level: 1,
+      hasAreaOfEffect: false,
     },
     {
-      name: 'Flammenpfeil',
-      attackBonus: '+5',
-      damage: '1d6+3',
-      type: 'Feuer',
-      range: '90ft',
-      level: 2,
+      name: 'Vampiric Touch',
+      level: 3,
+      cost: 'action',
+      needsVerbal: true,
+      needsSomatic: true,
+      needsMaterial: false,
+      needsConcentration: true,
+      needsSavingThrow: false,
+      school: 'Necromancy',
+      damage: [{ diceNumber: '3', diceType: 'd6', damageType: 'necrotic' }],
+      isRanged: false,
+      range: 'Touch',
+      hasAreaOfEffect: false,
     },
   ];
 

+ 106 - 2
src/styles.scss

@@ -3,8 +3,112 @@
 /* Importing Bootstrap SCSS file. */
 @import 'bootstrap/scss/bootstrap';
 
-$dialog-position-top: 20%;
+$dialog-position-top: 10%;
 $dialog-position-left: 20%;
 $dialog-position-right: 20%;
 
-@import 'node_modules/ngx-smart-modal/styles/ngx-smart-modal.scss'
+@import 'node_modules/ngx-smart-modal/styles/ngx-smart-modal.scss';
+
+
+.flex-row{
+    display: flex;
+    flex-direction: row;
+}
+
+.flex-column{
+    display: flex;
+    flex-direction: column;
+}
+
+.flex-centered{
+    align-items: center;
+    justify-content: center;
+}
+
+.flex-left{
+    justify-content: start;
+}
+
+.flex-right{
+    justify-content: end;
+}
+
+.gap-01{
+    gap: 0.1rem;
+}
+
+.gap-02{
+    gap: 0.2rem;
+}
+
+.gap-03{
+    gap: 0.3rem;
+}
+
+.gap-04{
+    gap: 0.4rem;
+}
+
+.gap-05{
+    gap: 0.5rem;
+}
+
+.gap-06{
+    gap: 0.6rem;
+}
+
+.gap-07{
+    gap: 0.7rem;
+}
+
+.gap-08{
+    gap: 0.8rem;
+}
+
+.gap-09{
+    gap: 0.9rem;
+}
+
+.gap-10{
+    gap: 1rem;
+}
+
+.gap-11{
+    gap: 1.1rem;
+}
+
+.gap-12{
+    gap: 1.2rem;
+}
+
+.gap-13{
+    gap: 1.3rem;
+}
+
+.gap-14{
+    gap: 1.4rem;
+}
+
+.gap-15{
+    gap: 1.5rem;
+}
+
+.gap-16{
+    gap: 1.6rem;
+}
+
+.gap-17{
+    gap: 1.7rem;
+}
+
+.gap-18{
+    gap: 1.8rem;
+}
+
+.gap-19{
+    gap: 1.9rem;
+}
+
+.gap-20{
+    gap: 2rem;
+}