Эх сурвалжийг харах

Tables finished with details panel

Christopher Giese 1 жил өмнө
parent
commit
8ee8116a23

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

@@ -459255,3 +459255,77 @@ To fix this, set a unique name for each project in a project.json inside the pro
 [NX Daemon Server] - 2023-11-14T20:34:02.204Z - Time taken for 'hash changed files from watcher' 165.97729992866516ms
 [NX Daemon Server] - 2023-11-14T20:34:02.204Z - [WATCHER]: Processing file changes in outputs
 [NX Daemon Server] - 2023-11-14T20:34:02.204Z - Done responding to the client null
+[NX Daemon Server] - 2023-11-15T06:10:58.471Z - Started listening on: \\.\pipe\nx\C:\Users\chris\AppData\Local\Temp\b99a3e5445b3962b8dd8\d.sock
+[NX Daemon Server] - 2023-11-15T06:10:58.479Z - [WATCHER]: Subscribed to changes within: c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools (native)
+[NX Daemon Server] - 2023-11-15T06:10:58.487Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2023-11-15T06:10:58.489Z - Closed a connection. Number of open connections: 0
+[NX Daemon Server] - 2023-11-15T06:10:58.489Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2023-11-15T06:10:58.491Z - [REQUEST]: Client Request for Project Graph Received
+[NX Daemon Server] - 2023-11-15T06:10:59.021Z - 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] - 2023-11-15T06:10:59.021Z - [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:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:97:15)
+    at buildProjectsConfigurationsFromProjectPathsAndPlugins (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:70:19)
+    at createProjectConfigurations (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:131:129)
+    at WorkspaceContext.<anonymous> (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:82:39)
+    at getProjectConfigurationsFromContext (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\utils\workspace-context.js:26:29)
+    at _retrieveProjectConfigurations (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:81:72)
+    at retrieveProjectConfigurations (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\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:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:102:34)
+    at async processFilesAndCreateAndSerializeProjectGraph (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:138:17)
+[NX Daemon Server] - 2023-11-15T06:10:59.023Z - Time taken for 'hash changed files from watcher' 85.1304999999702ms
+[NX Daemon Server] - 2023-11-15T06:10:59.023Z - [WATCHER]: Processing file changes in outputs
+[NX Daemon Server] - 2023-11-15T06:10:59.023Z - Done responding to the client null
+[NX Daemon Server] - 2023-11-15T09:58:45.765Z - Started listening on: \\.\pipe\nx\C:\Users\chris\AppData\Local\Temp\b99a3e5445b3962b8dd8\d.sock
+[NX Daemon Server] - 2023-11-15T09:58:45.773Z - [WATCHER]: Subscribed to changes within: c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools (native)
+[NX Daemon Server] - 2023-11-15T09:58:45.774Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2023-11-15T09:58:45.776Z - Closed a connection. Number of open connections: 0
+[NX Daemon Server] - 2023-11-15T09:58:45.776Z - Established a connection. Number of open connections: 1
+[NX Daemon Server] - 2023-11-15T09:58:45.778Z - [REQUEST]: Client Request for Project Graph Received
+[NX Daemon Server] - 2023-11-15T09:58:46.403Z - 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] - 2023-11-15T09:58:46.403Z - [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:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:97:15)
+    at buildProjectsConfigurationsFromProjectPathsAndPlugins (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\project-configuration-utils.js:70:19)
+    at createProjectConfigurations (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:131:129)
+    at WorkspaceContext.<anonymous> (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:82:39)
+    at getProjectConfigurationsFromContext (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\utils\workspace-context.js:26:29)
+    at _retrieveProjectConfigurations (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\project-graph\utils\retrieve-workspace-files.js:81:72)
+    at retrieveProjectConfigurations (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\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:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:102:34)
+    at async processFilesAndCreateAndSerializeProjectGraph (c:\Users\chris\Softwareprojekte\CharacterJournal\DnDTools\node_modules\nx\src\daemon\server\project-graph-incremental-recomputation.js:138:17)
+[NX Daemon Server] - 2023-11-15T09:58:46.405Z - Time taken for 'hash changed files from watcher' 103.82279999926686ms
+[NX Daemon Server] - 2023-11-15T09:58:46.405Z - [WATCHER]: Processing file changes in outputs
+[NX Daemon Server] - 2023-11-15T09:58:46.405Z - Done responding to the client null

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

@@ -1 +1 @@
-{"processId":17628}
+{"processId":18412}

+ 65 - 1
src/app/journal/journal-stats/weapons-container/spell-table/spell-details/spell-details.component.html

@@ -1,4 +1,68 @@
-<p>spell-details works!</p>
+<div class="details-title">{{ spell.name }}</div>
+
+<div class="details-subheading">
+  Beschreibung
+  <div class="details-content">
+    {{ spell.description }}
+  </div>
+</div>
+
+<div class="details-subheading">
+  Komponenten:
+  <div class="details-content">
+    <span *ngIf="spell.needsVerbal"> Verbal </span>
+    <span *ngIf="spell.needsSomatic"> Geste </span>
+    <span *ngIf="spell.needsMaterial"> Material </span>
+  </div>
+</div>
+
+<div class="details-subheading">
+  Eigenschaften
+  <div class="details-content">
+    <div *ngIf="spell.canRitual">Kann als Ritual gewirkt werden</div>
+    <div *ngIf="spell.needsConcentration">Benötigt Konzentration</div>
+    <div>Schule: {{ spell.school }}</div>
+  </div>
+</div>
+
+<div class="details-subheading">
+  Reichweite
+  <div class="details-content">
+    <div>Reichweite: {{ spell.range }} ft.</div>
+    <div *ngIf="spell.hasAreaOfEffect">
+      Flächeneffekt: {{ spell.radius }} ft. {{ spell.areaOfEffectType }}
+    </div>
+  </div>
+</div>
+
+<!-- Angriff /Rettungswurf -->
+
+<div class="details-subheading">
+  Effekte
+  <div class="details-content">
+    <div *ngIf="spell.needsSavingThrow">
+      {{ spell.savingThrowAttribute }} Rettungswurf: DC: {{ modifiers.saveDC }}
+    </div>
+    <div *ngIf="spell.needsAttackRoll">
+      Anfgriffsmodifikator: {{ modifiers.attackBonus }}
+    </div>
+    <ng-container *ngIf="spell.doesDamage">
+      Schaden:
+      <div *ngFor="let damage of spell.damage">
+        {{ damage.diceNumber }} {{ damage.diceType }}
+        {{ damage.additionalDamage }} {{ damage.damageType }}
+      </div>
+    </ng-container>
+  </div>
+</div>
+
+<div class="details-subheading" *ngIf="spell.doesHeal">
+  Heilung
+  <div class="details-content">
+    {{ spell.healAmount!.diceNumber }} {{ spell.healAmount!.diceType }}
+    {{ spell.healAmount?.additionalHeal }}
+  </div>
+</div>
 
 <div class="vertical-button-wrapper-3">
   <ui-button

+ 3 - 2
src/app/journal/journal-stats/weapons-container/spell-table/spell-details/spell-details.component.ts

@@ -1,5 +1,6 @@
 import { Component, Input } from '@angular/core';
 import { DetailsService } from 'src/services/details/details.service';
+import { Spell } from 'src/interfaces/spell';
 
 @Component({
   selector: 'app-spell-details',
@@ -9,8 +10,8 @@ import { DetailsService } from 'src/services/details/details.service';
 export class SpellDetailsComponent {
   public constructor(public detailsAccessor: DetailsService) {}
 
-  @Input() spell = {};
-  @Input() modifiers = {};
+  @Input() spell!: Spell;
+  @Input() modifiers: any = {};
 
   public close(result: string): void {
     this.detailsAccessor.closePanel(result);

+ 133 - 111
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.html

@@ -4,142 +4,164 @@
   class="example-list"
   (cdkDropListDropped)="dropSpells($event)"
 >
+  <div class="heading-list">
+    <div>Typ</div>
+    <div>Name</div>
+    <div>Stufe</div>
+    <div>
+      <div>Bonus/</div>
+      <div>Save</div>
+    </div>
+    <div>Schaden</div>
+    <div>Reichweite</div>
+  </div>
   <div
     class="example-box"
     *ngFor="let spell of spells; let index = index"
     cdkDrag
     (click)="openDetailsPanel(index)"
   >
-    <div class="spell-type">
-      <icon
-        [size]="'s'"
-        [type]="'weapon'"
-        [icon]="spell.isRanged ? 'distance' : 'touch'"
-      ></icon>
-    </div>
+    <!--  Range Icon -->
+    <ng-container
+      [ngTemplateOutlet]="distanceIconTemplate"
+      [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>
-    <!--  -->
-
-    <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>
-    </div>
 
+    <!-- Level -->
+    <ng-container
+      [ngTemplateOutlet]="spellLevelTemplate"
+      [ngTemplateOutletContext]="{ spell: spell }"
+    ></ng-container>
     <div class="vertical-line"></div>
-    <!--  -->
 
-    <div class="spell-level">{{ spell.level }}</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>
-    <!--  -->
-
-    <div class="attack-container">
-      <div *ngIf="spell.needsSavingThrow" class="saving-throw">
-        <div class="saving-throw-attribute">
-          {{ attributes[spell.savingThrowAttribute!] }}
-        </div>
-        <div class="saving-throw-dc">{{ spellSaveDC }}</div>
-      </div>
 
-      <div *ngIf="!spell.needsSavingThrow" class="attack-roll">
-        <div class="attack-roll-bonus">{{ spellAttackBonus }}</div>
-      </div>
+    <!-- Range -->
+    <ng-container
+      [ngTemplateOutlet]="spellRangeTemplate"
+      [ngTemplateOutletContext]="{ spell: spell }"
+    ></ng-container>
+  </div>
+
+  <!-- Add Button -->
+  <ui-button
+    style="margin: 1rem"
+    [type]="'add'"
+    [size]="'xlarge'"
+    [color]="'primary'"
+    (click)="openSpellModal()"
+  >
+  </ui-button>
+</div>
+
+<!-- Templates -->
+
+<!-- ICON -->
+<ng-template #distanceIconTemplate let-spell="spell">
+  <icon
+    [size]="'s'"
+    [type]="'weapon'"
+    [icon]="spell.isRanged ? 'distance' : 'touch'"
+  ></icon>
+</ng-template>
+
+<!-- NAME -->
+<ng-template #spellNameTemplate let-spell="spell">
+  <div>
+    <div class="bold">{{ spell.name }}</div>
+    <div class="bold small">
+      <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>
 
-    <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>
+<!-- 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>
 
-    <div class="vertical-line"></div>
-    <!--  -->
-
-    <div class="spell-range">
-      <div *ngIf="spell.isRanged">{{ spell.range }}</div>
-      <div *ngIf="!spell.isRanged">5 ft.</div>
+<!-- Damage/Heal -->
+<ng-template #spellDamageTemplate let-spell="spell">
+  <div>
+    <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>
 
-    <div class="vertical-line"></div>
-    <!--  -->
-
-    <div class="spell-edit">
-      <icon
-        [size]="'s'"
-        [type]="'UI'"
-        [icon]="'edit'"
-        [class]="'pointer'"
-      ></icon>
+    <div *ngIf="spell.doesHeal" class="heal">
+      <span
+        >{{ spell.healAmount.diceNumber }} {{ spell.healAmount.diceType }}
+      </span>
+      <span *ngIf="spell.healAmount.additionalHeal"
+        >+{{ spell.healAmount.additionalHeal }}
+      </span>
+      <span>
+        <icon [size]="'xs'" [type]="'damage'" [icon]="'heal'"></icon>
+      </span>
     </div>
   </div>
-  <div class="add-box">
-    <button (click)="openSpellModal()">+</button>
+</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">5 ft.</div>
+
+    <div *ngIf="spell.hasAreaOfEffect">
+      <span>{{ spell.radius }} ft. {{ areas[spell.areaTypeOfEffect] }}</span>
+    </div>
   </div>
-</div>
+</ng-template>
 
+<!-- Modal -->
 <spell-modal
   #spellModal
   (spellCreated)="addSpell($event)"

+ 34 - 84
src/app/journal/journal-stats/weapons-container/spell-table/spell-table.component.scss

@@ -9,115 +9,65 @@
 }
 
 .example-box {
-  padding: 20px 10px;
+  margin: 15px 10px;
   border-bottom: solid 1px #ccc;
   color: rgba(0, 0, 0, 0.87);
-  display: flex;
-  flex-direction: row;
+  display: grid;
+  grid-template-columns: 6fr .1fr 20fr .1fr 10fr .1fr 8fr .1fr 20fr .1fr 16fr;
   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;
+  background: var(--primary-color-light);
+  border-radius: 10px;;
+  font-size: 1rem;
+  font-weight:600;
   text-align: center;
-  flex-basis: 8%;
+  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);
 }
 
-.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;
+.heading-list{
+  margin: 10px;
+  display: grid;
+  grid-template-columns: 6fr 20fr 10fr 8fr 20fr 16fr;
+  text-align:center;
+  font-weight: 700;
 }
 
-.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;
-        }    
-    }
-
-
+.bold{
+  font-weight: bold;
 }
 
-// .spell-attack-bonus{
-//   width: 2rem;
-//   text-align: center;
-// }
-
-
-.damage-list{
-flex-basis: 15%;
-display: flex;
-flex-direction: column;
+.small{
+  font-size: .625rem;
 }
 
-.damage-row{
-display: flex;
-flex-direction: row;
-justify-content: center;
-align-items: center;
-gap: 0.1rem;
+.large{
+  font-size: 1.125rem;
 }
 
-
-.spell-range{
- flex-basis: 10%;
-  text-align: center;
+.vertical-line{
+  position: relative;
+  width: 1px;
+  height: 3.5rem;
 }
 
-.spell-edit{
-  flex-basis: 8%;
-  text-align: center;
+.vertical-line::before {
+  content: "";
+  position: absolute;
+  top: 15%; 
+  bottom: 15%; 
+  left: 0;
+  border-left: 1px solid black;
 }
 
 //// Drag and Drop
 
 .cdk-drag-preview {
   box-sizing: border-box;
-  border-radius: 4px;
+  border-radius: 10px;
   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);

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

@@ -35,6 +35,15 @@ export class SpellTableComponent {
     charisma: 'CHA',
   };
 
+  public areas: any = {
+    cone: 'Kegel',
+    sphere: 'Kugel',
+    circle: 'Kreis',
+    line: 'Linie',
+    square: 'Quadrat',
+    cube: 'Würfel',
+  };
+
   public ngOnInit(): void {
     this.spells = this.dataAccessor.getSpells();
     this.subscribeToData();

+ 80 - 54
src/app/journal/journal-stats/weapons-container/weapon-table/weapon-table.component.html

@@ -4,75 +4,101 @@
   class="example-list"
   (cdkDropListDropped)="dropWeapons($event)"
 >
+  <div class="heading-list">
+    <div>Typ</div>
+    <div>Name</div>
+    <div>Bonus</div>
+    <div>Schaden</div>
+    <div>Reichweite</div>
+  </div>
   <div
     class="example-box"
     *ngFor="let weapon of weapons; let index = index"
     cdkDrag
     (click)="openDetailsPanel(index)"
   >
-    <div class="weapon-type">
-      <icon
-        [size]="'s'"
-        [type]="'weapon'"
-        [icon]="weapon.isRanged ? 'ranged' : 'meele'"
-      ></icon>
-    </div>
+    <!--  Range Icon -->
+    <ng-container
+      [ngTemplateOutlet]="distanceIconTemplate"
+      [ngTemplateOutletContext]="{ weapon: weapon }"
+    ></ng-container>
     <div class="vertical-line"></div>
-
-    <div class="weapon-proficient">
-      <icon
-        [size]="'s'"
-        [type]="'UI'"
-        [icon]="weapon.proficient ? 'check' : 'cross'"
-      ></icon>
-    </div>
+    <ng-container
+      [ngTemplateOutlet]="weaponNameTemplate"
+      [ngTemplateOutletContext]="{ weapon: weapon }"
+    ></ng-container>
     <div class="vertical-line"></div>
-
-    <div class="weapon-name">{{ weapon.name }}</div>
+    <ng-container
+      [ngTemplateOutlet]="weaponAttackTemplate"
+      [ngTemplateOutletContext]="{ weapon: weapon }"
+    ></ng-container>
     <div class="vertical-line"></div>
-
-    <div class="weapon-attack-bonus">{{ weapon.attackBonus }}</div>
+    <ng-container
+      [ngTemplateOutlet]="weaponDamageTemplate"
+      [ngTemplateOutletContext]="{ weapon: weapon, index: index }"
+    ></ng-container>
     <div class="vertical-line"></div>
+    <ng-container
+      [ngTemplateOutlet]="weaponRangeTemplate"
+      [ngTemplateOutletContext]="{ weapon: weapon }"
+    ></ng-container>
+  </div>
 
-    <div class="damage-list">
-      <div
-        class="damage-row"
-        *ngFor="let damage of weapon.damage; let damageIndex = index"
-      >
-        <span>{{ damage.diceNumber }} {{ damage.diceType }}</span>
-        <span *ngIf="weapon.isVersatile && damageIndex === 0"
-          >({{ weapon.versatileDamage }})</span
-        >
-        <span *ngIf="damageIndex === 0 && damageModifiers[index] !== '0'">
-          {{ damageModifiers[index] }}
-        </span>
-        <span>
-          <icon
-            [size]="'xs'"
-            [type]="'damage'"
-            [icon]="damage.damageType"
-          ></icon>
-        </span>
-      </div>
-    </div>
-    <div class="vertical-line"></div>
+  <ui-button
+    style="margin: 1rem"
+    [type]="'add'"
+    [size]="'xlarge'"
+    [color]="'primary'"
+    (click)="openWeaponModal()"
+  ></ui-button>
+</div>
 
-    <div class="weapon-range">{{ weapon.range }}</div>
-    <div class="vertical-line"></div>
+<!-- Templates -->
+
+<!-- Distance Icons -->
+<ng-template #distanceIconTemplate let-weapon="weapon">
+  <icon
+    [size]="'s'"
+    [type]="'weapon'"
+    [icon]="weapon.isRanged ? 'ranged' : 'meele'"
+  ></icon>
+</ng-template>
+
+<!-- Name -->
+<ng-template #weaponNameTemplate let-weapon="weapon">
+  <div class="bold">{{ weapon.name }}</div>
+</ng-template>
+
+<!-- Attack Bonus -->
+<ng-template #weaponAttackTemplate let-weapon="weapon">
+  <div class="weapon-attack-bonus">{{ weapon.attackBonus }}</div>
+</ng-template>
 
-    <div class="weapon-edit">
-      <icon
-        [size]="'s'"
-        [type]="'UI'"
-        [icon]="'edit'"
-        [class]="'pointer'"
-      ></icon>
+<!-- Damage -->
+<ng-template #weaponDamageTemplate let-weapon="weapon" let-index="index">
+  <div class="damage-list">
+    <div
+      class="damage-row"
+      *ngFor="let damage of weapon.damage; let damageIndex = index"
+    >
+      <span>{{ damage.diceNumber }} {{ damage.diceType }}</span>
+      <span *ngIf="weapon.isVersatile && damageIndex === 0"
+        >({{ weapon.versatileDamage }})</span
+      >
+      <span *ngIf="damageIndex === 0 && damageModifiers[index] !== '0'">
+        {{ damageModifiers[index] }}
+      </span>
+      <span>
+        <icon [size]="'xs'" [type]="'damage'" [icon]="damage.damageType"></icon>
+      </span>
     </div>
   </div>
-  <div class="add-box">
-    <button (click)="openWeaponModal()">+</button>
-  </div>
-</div>
+</ng-template>
+
+<!-- Range -->
+<ng-template #weaponRangeTemplate let-weapon="weapon">
+  <div class="weapon-range">{{ weapon.range }}</div>
+</ng-template>
 
 <weapon-modal
   #weaponTable

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

@@ -9,83 +9,113 @@
 }
 
 .example-box {
-  padding: 20px 10px;
-  border-bottom: solid 1px #ccc;
-  color: rgba(0, 0, 0, 0.87);
-  display: flex;
-  flex-direction: row;
+  margin: 15px 10px;
+  display: grid;
+  grid-template-columns: 6fr .1fr 20fr .1fr 8fr .1fr 16fr .1fr 10fr;
   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;
+  background: var(--primary-color-light);
+  border-radius: 10px;;
+  font-size: 1rem;
+  font-weight: 600;
   text-align: center;
+  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);
 }
 
-.weapon-proficient{
-  width: 2rem;
-  text-align: center;
+.heading-list{
+  margin: 10px;
+  display: grid;
+  grid-template-columns: 6fr  20fr  8fr  16fr  10fr;
+  text-align:center;
+  font-weight: 700;
 }
 
-.weapon-name{
-  width: 6rem;
-  text-align: center;
+.bold{
+  font-weight: bold;
 }
 
-.weapon-attack-bonus{
-  width: 2rem;
-  text-align: center;
+.small{
+  font-size: .625rem;
 }
 
-.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;
-  }
+.large{
+  font-size: 1.125rem;
 }
 
-.weapon-range{
-  width: 4rem;
-  text-align: center;
+.vertical-line{
+  position: relative;
+  width: 1px;
+  height: 3.5rem;
 }
 
-.weapon-edit{
-  width: 3rem;
-  text-align: center;
+.vertical-line::before {
+  content: "";
+  position: absolute;
+  top: 15%; 
+  bottom: 15%; 
+  left: 0;
+  border-left: 1px solid black;
 }
 
+// 
+
+// .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;
+  border-radius: 10px;
   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);

+ 175 - 105
src/app/journal/spell-modal/spell-modal.component.html

@@ -51,6 +51,27 @@
           <input type="checkbox" [(ngModel)]="newSpellCanRitual" />
           <label>Ritual möglich?</label>
         </div>
+
+        <div class="checkbox-element">
+          <select [(ngModel)]="newSpellLevel">
+            <option
+              *ngFor="let level of [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
+              [value]="level"
+            >
+              {{ level }}
+            </option>
+          </select>
+          <label>Stufe</label>
+        </div>
+
+        <div class="checkbox-element">
+          <select [(ngModel)]="newSpellSchool">
+            <option *ngFor="let school of schools" [value]="school.value">
+              {{ school.display }}
+            </option>
+          </select>
+          <label>Schule</label>
+        </div>
       </div>
 
       <!-- ranged and area -->
@@ -91,9 +112,48 @@
         </div>
       </div>
 
-      <!-- Effects -->
+      <div style="display: flex">
+        <div>
+          <input type="checkbox" [(ngModel)]="newSpellDoesDamage" />
+          <label>Schaden?</label>
+        </div>
+
+        <div>
+          <input type="checkbox" [(ngModel)]="newSpellDoesHeal" />
+          <label>Heilung?</label>
+        </div>
+
+        <div>
+          <input type="checkbox" [(ngModel)]="newSpellNeedsSavingThrow" />
+          <label>Rettungswurf?</label>
+        </div>
+
+        <div>
+          <input type="checkbox" [(ngModel)]="newSpellNeedsAttackThrow" />
+          <label>Angriff?</label>
+        </div>
+      </div>
+
+      <ng-container
+        *ngIf="newSpellNeedsSavingThrow"
+        [ngTemplateOutlet]="attackTabContent"
+      ></ng-container>
+
+      <ng-container
+        *ngIf="newSpellDoesDamage"
+        [ngTemplateOutlet]="damageTabContent"
+      ></ng-container>
+
+      <ng-container
+        *ngIf="newSpellDoesHeal"
+        [ngTemplateOutlet]="healTabContent"
+      ></ng-container>
+
+      <ng-container [ngTemplateOutlet]="descriptionTabContent"></ng-container>
+
+      <!-- Navbar -->
 
-      <div class="d-flex">
+      <!-- <div class="d-flex">
         <div
           ngbNav
           #nav="ngbNav"
@@ -101,127 +161,36 @@
           class="nav-pills flex-column"
           orientation="vertical"
         >
+
           <ng-container ngbNavItem="top">
             <button ngbNavLink>Angriff</button>
             <ng-template ngbNavContent>
-              <div>
-                <div class="checkbox-element">
-                  <input
-                    type="checkbox"
-                    [(ngModel)]="newSpellNeedsSavingThrow"
-                  />
-                  <label>Erfordert Rettungswurf</label>
-                </div>
-                <select
-                  [(ngModel)]="newSpellSavingThrowAttribute"
-                  *ngIf="newSpellNeedsSavingThrow"
-                >
-                  <option
-                    *ngFor="let attribute of savingThrowAttributes"
-                    [value]="attribute.value"
-                  >
-                    {{ attribute.display }}
-                  </option>
-                </select>
-                <label *ngIf="newSpellNeedsSavingThrow">Attribut</label>
-              </div>
+              <ng-container
+                [ngTemplateOutlet]="attackTabContent"
+              ></ng-container>
             </ng-template>
           </ng-container>
+
           <ng-container ngbNavItem="middle">
             <button ngbNavLink>Schaden</button>
             <ng-template ngbNavContent>
-              <div class="damage-container">
-                <div
-                  class="damage-box"
-                  *ngFor="let damage of newSpellDamage; let index = index"
-                >
-                  <div class="dice-row">
-                    <div class="flex-column">
-                      <label>Anzahl</label>
-                      <select [(ngModel)]="newSpellDamage[index].diceNumber">
-                        <option *ngFor="let number of numbers" [value]="number">
-                          {{ number }}
-                        </option>
-                      </select>
-                    </div>
-
-                    <div class="flex-column">
-                      <label>Würfel</label>
-                      <select [(ngModel)]="newSpellDamage[index].diceType">
-                        <option *ngFor="let die of dice" [value]="die">
-                          {{ die }}
-                        </option>
-                      </select>
-                    </div>
-                  </div>
-
-                  <label for="damageType">Schadensart</label>
-                  <select [(ngModel)]="newSpellDamage[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="newSpellDamage.length < 3"
-                  (click)="addDamage()"
-                  [size]="'m'"
-                  [type]="'UI'"
-                  [icon]="'add'"
-                  [class]="'pointer'"
-                ></icon>
-              </div>
+              <ng-container
+                [ngTemplateOutlet]="damageTabContent"
+              ></ng-container>
             </ng-template>
           </ng-container>
+
           <ng-container ngbNavItem="bottom">
             <button ngbNavLink>Heilung</button>
             <ng-template ngbNavContent>
-              <p>
-                Sed commodo, leo at suscipit dictum, quam est porttitor sapien,
-                eget sodales nibh elit id diam. Nulla facilisi. Donec egestas
-                ligula vitae odio interdum aliquet. Duis lectus turpis, luctus
-                eget tincidunt eu, congue et odio. Duis pharetra et nisl at fau
-              </p>
+              <ng-container [ngTemplateOutlet]="healTabContent"></ng-container>
             </ng-template>
           </ng-container>
         </div>
-
         <div [ngbNavOutlet]="nav" class="ms-4"></div>
-      </div>
-
-      <!-- <h3 style="text-align: center; margin-top: 1.5rem">
-        Angriff und Schaden
-      </h3>
-
-      <div class="checkbox-element">
-        <input type="checkbox" [(ngModel)]="newSpellNeedsSavingThrow" />
-        <label>Erfordert Rettungswurf</label>
-      </div>
-      <select
-        [(ngModel)]="newSpellSavingThrowAttribute"
-        *ngIf="newSpellNeedsSavingThrow"
-      >
-        <option
-          *ngFor="let attribute of savingThrowAttributes"
-          [value]="attribute.value"
-        >
-          {{ attribute.display }}
-        </option>
-      </select>
-      <label *ngIf="newSpellNeedsSavingThrow">Attribut</label> -->
+      </div> -->
 
+      <!-- Button section -->
       <div class="button-wrapper">
         <ui-button
           *ngIf="isUpdate"
@@ -248,3 +217,104 @@
     </div>
   </div>
 </ngx-smart-modal>
+
+<!-- templates -->
+
+<ng-template #attackTabContent>
+  <div>
+    <select
+      [(ngModel)]="newSpellSavingThrowAttribute"
+      *ngIf="newSpellNeedsSavingThrow"
+    >
+      <option
+        *ngFor="let attribute of savingThrowAttributes"
+        [value]="attribute.value"
+      >
+        {{ attribute.display }}
+      </option>
+    </select>
+    <label *ngIf="newSpellNeedsSavingThrow">Attribut</label>
+  </div>
+</ng-template>
+
+<ng-template #damageTabContent>
+  <div class="damage-container">
+    <div
+      class="damage-box"
+      *ngFor="let damage of newSpellDamage; let index = index"
+    >
+      <div class="dice-row">
+        <div class="flex-column">
+          <label>Anzahl</label>
+          <select [(ngModel)]="newSpellDamage[index].diceNumber">
+            <option *ngFor="let number of numbers" [value]="number">
+              {{ number }}
+            </option>
+          </select>
+        </div>
+
+        <div class="flex-column">
+          <label>Würfel</label>
+          <select [(ngModel)]="newSpellDamage[index].diceType">
+            <option *ngFor="let die of dice" [value]="die">
+              {{ die }}
+            </option>
+          </select>
+        </div>
+      </div>
+
+      <label for="damageType">Schadensart</label>
+      <select [(ngModel)]="newSpellDamage[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="newSpellDamage.length < 3"
+      (click)="addDamage()"
+      [size]="'m'"
+      [type]="'UI'"
+      [icon]="'add'"
+      [class]="'pointer'"
+    ></icon>
+  </div>
+</ng-template>
+
+<ng-template #healTabContent>
+  <div class="heal-container">
+    <div class="dice-row">
+      <div class="flex-column">
+        <label>Anzahl</label>
+        <select [(ngModel)]="newSpellHeal.diceNumber">
+          <option *ngFor="let number of numbers" [value]="number">
+            {{ number }}
+          </option>
+        </select>
+      </div>
+
+      <div class="flex-column">
+        <label>Würfel</label>
+        <select [(ngModel)]="newSpellHeal.diceType">
+          <option *ngFor="let die of dice" [value]="die">
+            {{ die }}
+          </option>
+        </select>
+      </div>
+    </div>
+    <label>Heilung</label>
+  </div>
+</ng-template>
+
+<ng-template #descriptionTabContent>
+  <textarea style="height: 20rem" [(ngModel)]="newSpellDescription"></textarea>
+</ng-template>

+ 29 - 25
src/app/journal/spell-modal/spell-modal.component.ts

@@ -1,6 +1,7 @@
 import { Component, EventEmitter, Output } from '@angular/core';
 import { NgxSmartModalService } from 'ngx-smart-modal';
 import { Damage } from 'src/interfaces/damage';
+import { Heal } from 'src/interfaces/heal';
 import { Spell } from 'src/interfaces/spell';
 
 @Component({
@@ -27,22 +28,27 @@ export class SpellModalComponent {
   public newSpellNeedsVerbal: boolean = false;
   public newSpellNeedsSomatic: boolean = false;
   public newSpellNeedsMaterial: boolean = false;
-  public newSpellSchool: string | undefined;
-  public newSpellDescription: string | undefined;
+  public newSpellSchool: string = '';
+  public newSpellDescription: string = '';
   public newSpellDoesDamage: boolean = true;
   public newSpellDoesHeal: boolean = false;
-  public newSpellHasOtherEffect: boolean = false;
-
+  public newSpellNeedsAttackRoll: boolean = false;
   public newSpellNeedsSavingThrow: boolean = false;
   public newSpellSavingThrowAttribute: string | undefined;
+  public newSpellNeedsAttackThrow: boolean = false;
+  public newSpellHeal: Heal = {
+    diceNumber: '',
+    diceType: '',
+    additionalHeal: 0,
+  };
   public newSpellAttackBonus: string = '';
   public newSpellDamage: Damage[] = [
     { diceNumber: '', diceType: '', damageType: '' },
   ];
   public newSpellIsRanged: boolean = false;
-  public newSpellRange: string = '5ft';
+  public newSpellRange: number = 5;
   public newSpellHasAreaOfEffect: boolean = false;
-  public newSpellRadius: string | undefined;
+  public newSpellRadius: number | undefined;
   public newSpellAreaOfEffectType: string | undefined;
 
   public isUpdate: boolean = false;
@@ -126,13 +132,15 @@ export class SpellModalComponent {
       needsVerbal: this.newSpellNeedsVerbal,
       needsSomatic: this.newSpellNeedsSomatic,
       needsMaterial: this.newSpellNeedsMaterial,
+      needsAttackRoll: this.newSpellNeedsAttackRoll,
       needsSavingThrow: this.newSpellNeedsSavingThrow,
       isRanged: this.newSpellIsRanged,
       range: this.newSpellRange,
       hasAreaOfEffect: this.newSpellHasAreaOfEffect,
       doesDamage: this.newSpellDoesDamage,
       doesHeal: this.newSpellDoesHeal,
-      hasOtherEffect: this.newSpellHasOtherEffect,
+      description: this.newSpellDescription,
+      school: this.newSpellSchool,
     };
     if (this.newSpellDescription) {
       newspell.description = this.newSpellDescription;
@@ -173,17 +181,18 @@ export class SpellModalComponent {
     this.newSpellNeedsVerbal = false;
     this.newSpellNeedsSomatic = false;
     this.newSpellNeedsMaterial = false;
-    this.newSpellSchool = undefined;
-    this.newSpellDescription = undefined;
+    this.newSpellSchool = '';
+    this.newSpellDescription = '';
+    this.newSpellNeedsAttackRoll = false;
     this.newSpellNeedsSavingThrow = false;
     this.newSpellSavingThrowAttribute = undefined;
     this.newSpellDoesDamage = false;
     this.newSpellDoesHeal = false;
-    this.newSpellHasOtherEffect = false;
+    this.newSpellHeal = { diceNumber: '', diceType: '' };
     this.newSpellAttackBonus = '';
     this.newSpellDamage = [{ diceNumber: '', diceType: '', damageType: '' }];
     this.newSpellIsRanged = false;
-    this.newSpellRange = '5ft';
+    this.newSpellRange = 5;
     this.newSpellHasAreaOfEffect = false;
     this.newSpellRadius = undefined;
     this.newSpellAreaOfEffectType = undefined;
@@ -208,9 +217,9 @@ export class SpellModalComponent {
       this.newSpellNeedsMaterial = spell.needsMaterial;
       this.newSpellSchool = spell.school;
       this.newSpellDescription = spell.description;
+      this.newSpellDoesDamage = spell.doesDamage;
       this.newSpellNeedsSavingThrow = spell.needsSavingThrow;
       this.newSpellSavingThrowAttribute = spell.savingThrowAttribute;
-      this.newSpellAttackBonus = spell.attackBonus;
       this.newSpellDamage = spell.damage;
       this.newSpellIsRanged = spell.isRanged;
       this.newSpellRange = spell.range;
@@ -222,6 +231,7 @@ export class SpellModalComponent {
     }
   }
 
+  // überarbeiten
   public updateSpell(): void {
     const newspell: Spell = {
       name: this.newSpellName,
@@ -229,36 +239,30 @@ export class SpellModalComponent {
       level: this.newSpellLevel,
       cost: this.newSpellCost,
       canRitual: this.newSpellCanRitual,
+      school: this.newSpellSchool,
+      description: this.newSpellDescription,
       needsConcentration: this.newSpellNeedsConcentration,
       needsVerbal: this.newSpellNeedsVerbal,
       needsSomatic: this.newSpellNeedsSomatic,
       needsMaterial: this.newSpellNeedsMaterial,
+      needsAttackRoll: this.newSpellNeedsAttackRoll,
       needsSavingThrow: this.newSpellNeedsSavingThrow,
       isRanged: this.newSpellIsRanged,
       range: this.newSpellRange,
       hasAreaOfEffect: this.newSpellHasAreaOfEffect,
       doesDamage: this.newSpellDoesDamage,
       doesHeal: this.newSpellDoesHeal,
-      hasOtherEffect: this.newSpellHasOtherEffect,
     };
-    if (this.newSpellDescription) {
-      newspell.description = this.newSpellDescription;
-    }
-    if (this.newSpellSchool) {
-      newspell.school = this.newSpellSchool;
-    }
-    if (this.newSpellSavingThrowAttribute) {
+    if (this.newSpellNeedsSavingThrow) {
       newspell.savingThrowAttribute = this.newSpellSavingThrowAttribute;
     }
-    if (this.newSpellAttackBonus) {
-      newspell.attackBonus = this.newSpellAttackBonus;
-    }
     if (this.newSpellHasAreaOfEffect) {
       newspell.radius = this.newSpellRadius;
-    }
-    if (this.newSpellHasAreaOfEffect) {
       newspell.areaOfEffectType = this.newSpellAreaOfEffectType;
     }
+    if (this.newSpellDoesHeal) {
+      newspell.healAmount = this.newSpellHeal;
+    }
     this.spellUpdated.emit({ spell: newspell, index: this.indexForUpdate });
     this.ngxSmartModalService.closeLatestModal();
     this.removeData();

+ 1 - 0
src/assets/icons/damageIcons/heal.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="M196 16a30 30 0 0 0-30 30v120H46a30 30 0 0 0-30 30v120a30 30 0 0 0 30 30h120v120a30 30 0 0 0 30 30h120a30 30 0 0 0 30-30V346h120a30 30 0 0 0 30-30V196a30 30 0 0 0-30-30H346V46a30 30 0 0 0-30-30H196z" fill="#508f06" fill-opacity="1"></path></g></svg>

+ 8 - 0
src/enums/area-types.ts

@@ -0,0 +1,8 @@
+export enum AreaTypes {
+  cone = 'Kegel',
+  sphere = 'Kugel',
+  circle = 'Kreis',
+  line = 'Linie',
+  square = 'Quadrat',
+  cube = 'Würfel',
+}

+ 16 - 0
src/enums/damage-types.ts

@@ -0,0 +1,16 @@
+export enum DamageTypes {
+  acid = 'Säure',
+  bludgeoning = 'Wucht',
+  cold = 'Kälte',
+  fire = 'Feuer',
+  force = 'Energie',
+  lightning = 'Blitz',
+  necrotic = 'Nekrotisch',
+  piercing = 'Stich',
+  poison = 'Gift',
+  psychic = 'Psychisch',
+  radiant = 'Gleißend',
+  slashing = 'Hieb',
+  thunder = 'Donner',
+  holy = 'Heilig',
+}

+ 10 - 0
src/enums/schools.ts

@@ -0,0 +1,10 @@
+export enum Schools {
+  divination = 'Wahrsagerei',
+  transmutation = 'Verwandlung',
+  abjuration = 'Abjuration',
+  conjuration = 'Beschwörung',
+  enchantment = 'Verzauberung',
+  evocation = 'Hervorrufung',
+  illusion = 'Illusion',
+  necromancy = 'Nekromantie',
+}

+ 1 - 1
src/interfaces/heal.ts

@@ -1,5 +1,5 @@
 export interface Heal {
   diceNumber: string;
   diceType: string;
-  additionalHeal?: string;
+  additionalHeal?: number;
 }

+ 12 - 7
src/interfaces/spell.ts

@@ -7,23 +7,22 @@ export interface Spell {
   needsVerbal: boolean;
   needsSomatic: boolean;
   needsMaterial: boolean;
-  school?: string;
-  description?: string;
+  school: string;
+  description: string;
+  needsAttackRoll: boolean;
   needsSavingThrow: boolean;
   savingThrowAttribute?: string;
   isRanged: boolean;
-  range?: string;
+  range?: number;
   hasAreaOfEffect: boolean;
-  radius?: string;
+  radius?: number;
   areaOfEffectType?: string;
-  numberOfTargets?: number;
 
   doesDamage: boolean;
   attackBonus?: string;
   damage?: Damage[];
   doesHeal: boolean;
-  healAmount?: string;
-  hasOtherEffect: boolean;
+  healAmount?: Heal;
 }
 
 interface Damage {
@@ -32,3 +31,9 @@ interface Damage {
   damageType: string;
   additionalDamage?: string;
 }
+
+interface Heal {
+  diceNumber: string;
+  diceType: string;
+  additionalHeal?: number;
+}

+ 39 - 9
src/services/data/data.service.ts

@@ -212,21 +212,26 @@ export class DataService {
       needsSomatic: true,
       needsMaterial: true,
       needsConcentration: false,
+      needsAttackRoll: false,
       needsSavingThrow: true,
       savingThrowAttribute: 'dexterity',
       school: 'Evocation',
       doesDamage: true,
-      damage: [{ diceNumber: '8', diceType: 'd6', damageType: 'fire' }],
+      damage: [
+        { diceNumber: '8', diceType: 'd6', damageType: 'fire' },
+        { diceNumber: '8', diceType: 'd6', damageType: 'fire' },
+      ],
       isRanged: true,
       doesHeal: false,
-      hasOtherEffect: false,
-      range: '150ft',
+      description:
+        'Ein heller Strahl schießt von deinem Zeigefinger zu einem von dir gewählten Punkt in Reichweite und blüht dann mit einem tiefen Brüllen zu einer Flammenexplosion auf. Jede Kreatur in einem Umkreis von 6 Metern um diesen Punkt muss einen Rettungswurf auf Geschicklichkeit machen. Bei einem misslungenen Rettungswurf erleidet das Ziel 8W6 Feuerschaden, bei einem erfolgreichen Wurf die Hälfte des Schadens. Das Feuer breitet sich um Ecken aus. Es entzündet brennbare Gegenstände in der Umgebung, die nicht getragen werden. Wenn du diesen Zauber mit einem Zauberplatz des 4. Grades oder höher wirkst, erhöht sich der Schaden um 1W6 für jeden Grad über dem 3.',
+      range: 150,
       hasAreaOfEffect: true,
-      radius: '20ft',
+      radius: 20,
       areaOfEffectType: 'sphere',
     },
     {
-      name: 'Flammenpfeil',
+      name: 'Feuerpfeil',
       level: 0,
       cost: 'action',
       canRitual: false,
@@ -234,14 +239,16 @@ export class DataService {
       needsSomatic: true,
       needsMaterial: true,
       needsConcentration: false,
+      needsAttackRoll: true,
       needsSavingThrow: false,
       school: 'Evocation',
       doesDamage: true,
       doesHeal: false,
-      hasOtherEffect: false,
+      description:
+        'Du schleuderst einen Splitter aus Feuer auf eine Kreatur in Reichweite. Lege einen Fernkampf-Zauberangriff gegen das Ziel ab. Bei einem Treffer erleidet das Ziel 1W10 Feuerschaden. Ein brennbarer Gegenstand, der von diesem Zauber getroffen wird, geht in Flammen auf, wenn er nicht getragen oder in der Hand gehalten wird. Der Schaden dieses Zaubers steigt um 1W10, wenn du die 5. Stufe (2W10), die 11. Stufe (3W10) und die 17. Stufe (4W10) erreichst.  ',
       damage: [{ diceNumber: '1', diceType: 'd10', damageType: 'fire' }],
       isRanged: true,
-      range: '120ft',
+      range: 120,
       hasAreaOfEffect: false,
     },
     {
@@ -253,14 +260,37 @@ export class DataService {
       needsSomatic: true,
       needsMaterial: false,
       needsConcentration: true,
+      needsAttackRoll: true,
       needsSavingThrow: false,
       doesDamage: true,
       doesHeal: false,
-      hasOtherEffect: false,
+      description:
+        'Die Berührung deiner schattenumrankten Hand kann anderen die Lebenskraft entziehen, um deine Wunden zu heilen. Führe einen Nahkampf-Zauberangriff gegen eine Kreatur in deiner Reichweite aus. Bei einem Treffer erleidet das Ziel 3W6 nekrotischen Schaden, und du erhältst Trefferpunkte in Höhe der Hälfte des zugefügten nekrotischen Schadens zurück. Bis der Zauber endet, kannst du den Angriff in jeder deiner Runden als Aktion wiederholen. Wenn du diesen Zauber mit einem Zauberplatz des 4. Grades oder höher wirkst, erhöht sich der Schaden um 1W6 für jeden Grad über dem 3.',
       school: 'Necromancy',
       damage: [{ diceNumber: '3', diceType: 'd6', damageType: 'necrotic' }],
       isRanged: false,
-      range: 'Touch',
+      range: 5,
+      hasAreaOfEffect: false,
+    },
+    {
+      name: 'Heilende Berührung',
+      level: 1,
+      cost: 'action',
+      canRitual: false,
+      needsVerbal: true,
+      needsSomatic: true,
+      needsMaterial: false,
+      needsConcentration: false,
+      needsAttackRoll: false,
+      needsSavingThrow: false,
+      doesDamage: false,
+      doesHeal: true,
+      healAmount: { diceNumber: '1', diceType: 'd8', additionalHeal: 5 },
+      description:
+        'Deine Berührung kann Wunden heilen. Berühre eine Kreatur und spende ihr 1W8 + deinem Fertigkeitsbonus Trefferpunkte. Dieser Zauber hat keine Wirkung auf Untote oder Konstrukte. Wenn du diesen Zauber mit einem Zauberplatz des 2. Grades oder höher wirkst, erhöht sich die Heilung um 1W8 für jeden Grad über dem 1.',
+      school: 'Evocation',
+      isRanged: false,
+      range: 5,
       hasAreaOfEffect: false,
     },
   ];

+ 26 - 8
src/styles.scss

@@ -64,26 +64,44 @@ $dialog-position-right: 20%;
     justify-content: center;
 }
 
-.details-name{
+
+.details-title{
+    text-align: center;
+    font-size: 2rem;
+    font-weight: bold;
+    margin-top: 1.5rem;
+}
+
+.details-heading{
     font-size: 1.5rem;
     font-weight: bold;
     margin-top: 1.5rem;
-    text-align:center;
 }
 
-.details-long-description{
-    margin: 2rem 1rem;
+.details-subheading{
+    font-size: 1.25rem;
+    font-weight: bold;
+    margin-top: 1.5rem;
+}
+
+.details-content{
     font-size: 1rem;
-    // margin-top: 2rem;
+    margin-top: .5rem;
+    font-weight: 400;
 }
 
-.details-title{
-    text-align: center;
-    font-size: 2rem;
+.details-name{
+    font-size: 1.5rem;
     font-weight: bold;
     margin-top: 1.5rem;
+    text-align:center;
 }
 
+.details-long-description{
+    margin: 2rem 1rem;
+    font-size: 1rem;
+    // margin-top: 2rem;
+}