Procházet zdrojové kódy

step to tooltipify

Warafear před 1 měsícem
rodič
revize
a7e8581845

+ 4 - 11
src/app/journal/journal-maps/journal-maps.component.html

@@ -1,11 +1,4 @@
-<div
-  style="
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    height: 100%;
-    width: 100%;
-  "
->
-  <img style="height: 100%" src="assets/images/maps_coming_soon.jpeg" alt="" />
-</div>
+<ng-template #tooltip><div [innerHTML]="currentText"></div></ng-template>
+
+<button [ngbTooltip]="tooltip" (mouseover)="setNewText('hans')">Hans</button>
+<button [ngbTooltip]="tooltip" (mouseover)="setNewText('peter')">Peter</button>

+ 12 - 1
src/app/journal/journal-maps/journal-maps.component.ts

@@ -5,4 +5,15 @@ import { Component } from '@angular/core';
   templateUrl: './journal-maps.component.html',
   styleUrl: './journal-maps.component.scss',
 })
-export class JournalMapsComponent {}
+export class JournalMapsComponent {
+  currentText = 'Initial';
+
+  texts: any = {
+    hans: '<b>hans</b>',
+    peter: '<b>peter</b>',
+  };
+
+  setNewText(key: string) {
+    this.currentText = this.texts[key];
+  }
+}

+ 17 - 1
src/app/journal/journal-notes/journal-notes.component.html

@@ -1,6 +1,17 @@
 <div class="entries-list">
   <div class="title t-0">{{ "notes.sessions" | translate }}</div>
   <divider appearance="gold-2" style="padding: 0 1rem"></divider>
+
+  <button
+    type="button"
+    class="btn btn-outline-secondary"
+    (click)="addHighlightsToText('Edeltraut')"
+  >
+    I've got markup and bindings in my tooltip!
+  </button>
+
+  <!-- TODO: Delete or make display: none -->
+  <div #test>Hallo, ich hoffe hier wird gleich was rein geschrieben...</div>
   <!-- Add Button or temporary unsaved new entry -->
   @if (isNewEntry) {
     <div class="entry active">
@@ -99,7 +110,11 @@
           </div>
         </div>
         <divider appearance="gold-2"></divider>
-        <div class="content-read" [innerHTML]="currentEntry.content"></div>
+        <!-- <div class="content-read" [innerHTML]="currentEntry.content"></div> -->
+        <div
+          class="content-read"
+          [innerHTML]="tooltipifiedEntries[currentEntryIndex].content"
+        ></div>
       </div>
     }
     <div class="button-row">
@@ -126,3 +141,4 @@
     {{ "notes.empty" | translate }}
   </div>
 }
+<ng-template #tooltip><div [innerHTML]="tooltipText"></div></ng-template>

+ 99 - 10
src/app/journal/journal-notes/journal-notes.component.ts

@@ -1,10 +1,24 @@
-import { Component, OnInit, OnDestroy } from '@angular/core';
+import {
+  Component,
+  OnInit,
+  OnDestroy,
+  inject,
+  ComponentFactoryResolver,
+  TemplateRef,
+  ViewChild,
+  ViewContainerRef,
+  Renderer2,
+  ElementRef,
+} from '@angular/core';
 import { Editor } from 'ngx-editor';
 import { DateAdapter } from '@angular/material/core';
 import { JournalEntry } from 'src/interfaces/interfaces';
 import localeDe from '@angular/common/locales/de';
 import { registerLocaleData } from '@angular/common';
 import { DataService } from 'src/services/data/data.service';
+import { TooltipService } from 'src/services/tooltip/tooltip.service';
+import { HighlightComponent } from 'src/app/shared-components/highlight/highlight.component';
+import { DomSanitizer } from '@angular/platform-browser';
 
 @Component({
   selector: 'app-journal-notes',
@@ -12,6 +26,11 @@ import { DataService } from 'src/services/data/data.service';
   styleUrl: './journal-notes.component.scss',
 })
 export class JournalNotesComponent implements OnInit, OnDestroy {
+  @ViewChild('tooltip', { read: TemplateRef }) tooltip!: TemplateRef<any>;
+  @ViewChild('test', { read: ViewContainerRef }) test!: ViewContainerRef;
+
+  tooltipText = 'Initial';
+
   editor: Editor = new Editor();
   toolbar: any = [
     // default value
@@ -33,6 +52,14 @@ export class JournalNotesComponent implements OnInit, OnDestroy {
   /**The array of JournalEntries, synched to the   */
   public entries: JournalEntry[] = [];
 
+  public tooltipifiedEntries: JournalEntry[] = [];
+
+  tooltipifiedEntry: JournalEntry = {
+    title: 'Title',
+    content: 'Content',
+    created: new Date(),
+  };
+
   /** Holds the data for the current entry */
   public currentEntry: JournalEntry = {
     title: '',
@@ -40,18 +67,18 @@ export class JournalNotesComponent implements OnInit, OnDestroy {
     created: new Date(),
   };
 
-  constructor(
-    private _adapter: DateAdapter<any>,
-    private dataService: DataService,
-  ) {
-    registerLocaleData(localeDe);
-    this.entries = this.dataService.notesData;
-  }
+  private _adapter: DateAdapter<any> = inject(DateAdapter);
+  private dataService: DataService = inject(DataService);
+  private tooltipService: TooltipService = inject(TooltipService);
+  private sanitizer: DomSanitizer = inject(DomSanitizer);
+  private renderer: Renderer2 = inject(Renderer2);
+  private el: ElementRef = inject(ElementRef);
 
   ngOnInit(): void {
+    registerLocaleData(localeDe);
     this._adapter.setLocale('de');
     this.entries = this.dataService.notesData;
-    console.log('JournalNotesComponent: ', this.entries);
+    this.tooltipifiedEntries = this.entries;
 
     // if the list is empty, set the currentEntryIndex to -1 to hide the entry-container
     if (this.entries.length === 0) {
@@ -59,6 +86,7 @@ export class JournalNotesComponent implements OnInit, OnDestroy {
     } else {
       this.currentEntry = this.entries[0];
     }
+    this.tooltipify();
   }
 
   /**
@@ -70,6 +98,10 @@ export class JournalNotesComponent implements OnInit, OnDestroy {
     this.currentEntry = this.getEntryAt(index);
     this.isNewEntry = false;
     this.isInEditMode = false;
+    // this.tooltipify();
+    this.collectNamesFromEntry().forEach((name) => {
+      this.addHighlightsToText(name);
+    });
   }
 
   // DONE
@@ -100,6 +132,7 @@ export class JournalNotesComponent implements OnInit, OnDestroy {
     }
     this.isInEditMode = false;
     this.entries[this.currentEntryIndex] = this.currentEntry;
+    this.tooltipify();
     this.uploadNotes();
   }
 
@@ -131,10 +164,66 @@ export class JournalNotesComponent implements OnInit, OnDestroy {
   }
 
   private uploadNotes(): void {
-    console.log('Uploading notes to the server: ', this.entries);
     this.dataService.notesData = this.entries;
   }
 
+  ////////////////////////////////////////////////////
+
+  tooltipify() {
+    let result: any = this.tooltipService.tooltipifyEntry(
+      JSON.parse(JSON.stringify(this.currentEntry.content)),
+    );
+    console.log(result);
+    this.tooltipifiedEntry = result.content;
+    result.npcs.forEach((name: string) => {
+      this.addHighlightsToText(name);
+    });
+
+    // result = {
+    //   enntryContent: string;
+    //   npcs: string[] = [xyz];
+    //   npcDescriptions: {
+    //     name1: 'description1',
+    //     name2: 'description2',
+    //   }
+    //   }
+    // result.forEach((entry: any) => {
+    //   entry.content = this.sanitizer.bypassSecurityTrustHtml(entry.content);
+    // });
+    // this.tooltipifiedEntries = result;
+  }
+
+  /**
+   * Searches the current entry for names that are mentioned in the text.
+   * @returns An array of all the names that are mentioned in the current entry.
+   */
+  private collectNamesFromEntry(): string[] {
+    const matches = this.currentEntry.content.match(/(?<=@)\w+/g);
+    const uniqueMatches = [...new Set(matches)];
+    return uniqueMatches;
+  }
+
+  /**
+   * Highlights and adds tooltips to the names that are mentioned in the current entry.
+   * @param name The name of the person which mentionings are to be highlighted.
+   */
+  addHighlightsToText(name: string) {
+    // Target the correct containers
+    const parent = this.el.nativeElement.querySelectorAll('.' + name);
+    parent.forEach((element: any) => {
+      const componentRef = this.test.createComponent(HighlightComponent);
+      // The name
+      componentRef.instance.text = name;
+      // A reference to the tooltip template
+      componentRef.instance.tooltip = this.tooltip;
+      // Appends it at the right spot
+      this.renderer.appendChild(element, componentRef.location.nativeElement);
+    });
+    // Modufies the text inside the tooltip template
+    // Muss auf mouseover erfolgen
+    this.tooltipText = 'Neuer Tooltip <b>text</b>';
+  }
+
   ngOnDestroy(): void {
     this.editor.destroy();
   }

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

@@ -8,6 +8,7 @@ import { ReactiveFormsModule } from '@angular/forms';
 import { MarkdownModule } from 'ngx-markdown';
 import { NgxEditorModule } from 'ngx-editor';
 import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
 import { TranslateModule, TranslatePipe } from '@ngx-translate/core';
 
 // Material Design
@@ -100,6 +101,7 @@ import { CustomSpellsModalComponent } from './journal-spellbook/custom-spells-mo
 import { DurationPipe } from '../../pipes/duration/duration.pipe';
 import { CombinedComponent } from './journal-character/combined/combined.component';
 import { DividerComponent } from '../shared-components/divider/divider.component';
+import { TooltipDirective } from 'src/directives/tooltip/tooltip.directive';
 
 @NgModule({
   declarations: [
@@ -205,6 +207,8 @@ import { DividerComponent } from '../shared-components/divider/divider.component
     NgbCollapseModule,
     MatButtonToggleModule,
     MatIconModule,
+    TooltipDirective,
+    NgbTooltipModule,
   ],
 })
 export class JournalModule {}

+ 1 - 0
src/app/shared-components/highlight/highlight.component.html

@@ -0,0 +1 @@
+<span [ngbTooltip]="tooltip!">{{ text }}</span>

+ 3 - 0
src/app/shared-components/highlight/highlight.component.scss

@@ -0,0 +1,3 @@
+span {
+  font-weight: 600;
+}

+ 23 - 0
src/app/shared-components/highlight/highlight.component.spec.ts

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

+ 15 - 0
src/app/shared-components/highlight/highlight.component.ts

@@ -0,0 +1,15 @@
+import { Component, Input, TemplateRef } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
+
+@Component({
+  selector: 'app-highlight',
+  standalone: true,
+  imports: [CommonModule, NgbTooltipModule],
+  templateUrl: './highlight.component.html',
+  styleUrl: './highlight.component.scss',
+})
+export class HighlightComponent {
+  @Input() text: string = 'Initial';
+  @Input() tooltip!: TemplateRef<any>;
+}

+ 8 - 0
src/directives/tooltip/tooltip.directive.spec.ts

@@ -0,0 +1,8 @@
+import { TooltipDirective } from './tooltip.directive';
+
+describe('TooltipDirective', () => {
+  it('should create an instance', () => {
+    const directive = new TooltipDirective();
+    expect(directive).toBeTruthy();
+  });
+});

+ 35 - 0
src/directives/tooltip/tooltip.directive.ts

@@ -0,0 +1,35 @@
+import {
+  Directive,
+  ViewContainerRef,
+  ComponentFactoryResolver,
+  Renderer2,
+  ElementRef,
+} from '@angular/core';
+// import { TooltipComponent } from 'src/app/shared-components/tooltip/tooltip/tooltip.component';
+
+@Directive({
+  selector: '[tooltip]',
+  standalone: true,
+})
+export class TooltipDirective {
+  constructor(
+    private viewContainerRef: ViewContainerRef,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private renderer: Renderer2,
+    private el: ElementRef,
+  ) {
+    // this.showTooltip();
+  }
+
+  // showTooltip() {
+  //   const factory =
+  //     this.componentFactoryResolver.resolveComponentFactory(TooltipComponent);
+  //   const componentRef = this.viewContainerRef.createComponent(factory);
+  //   componentRef.instance.content = 'This is a tooltip';
+
+  //   this.renderer.appendChild(
+  //     this.el.nativeElement,
+  //     componentRef.location.nativeElement,
+  //   );
+  // }
+}

+ 2 - 0
src/interfaces/interfaces.ts

@@ -1,3 +1,5 @@
+import { SafeHtml } from '@angular/platform-browser';
+
 // #region CHARACTER DATA
 export interface Ability {
   name: string;

+ 16 - 0
src/services/tooltip/tooltip.service.spec.ts

@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { TooltipService } from './tooltip.service';
+
+describe('TooltipService', () => {
+  let service: TooltipService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(TooltipService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});

+ 28 - 0
src/services/tooltip/tooltip.service.ts

@@ -0,0 +1,28 @@
+import { Injectable, inject } from '@angular/core';
+import { JournalEntry, Npcs, Npc } from 'src/interfaces/interfaces';
+import { DataService } from 'src/services/data/data.service';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class TooltipService {
+  private dataService: DataService = inject(DataService);
+
+  public tooltipifyEntry(entry: string): any {
+    const content = this.tootipifyNpc(entry);
+    const matches = entry.match(/(?<=@)\w+/g);
+    const uniqueMatches = [...new Set(matches)];
+    // get the descriptions from the data service
+
+    return {
+      content: content,
+      npcs: uniqueMatches,
+      npcDescriptions: {},
+    };
+  }
+
+  private tootipifyNpc(content: string): string {
+    // Add a search that collects all the names of the npcs that occur and send it with the strings
+    return content.replace(/@(\w+)/g, "<span class='$1'></span>");
+  }
+}

+ 4 - 0
src/styles.scss

@@ -270,6 +270,10 @@ input[type="checkbox"]:checked::after {
   padding-left: 0.25rem;
 }
 
+.highlighted {
+  font-weight: 800;
+}
+
 // RICH TEXT EDITOR
 .ProseMirror {
   padding-left: 1rem !important;