]> BookStack Code Mirror - bookstack/commitdiff
Comments: Added reference marker to comments
authorDan Brown <redacted>
Sat, 26 Apr 2025 20:05:54 +0000 (21:05 +0100)
committerDan Brown <redacted>
Sat, 26 Apr 2025 20:05:54 +0000 (21:05 +0100)
resources/icons/bookmark.svg [new file with mode: 0644]
resources/js/components/page-comment.ts
resources/js/components/page-display.js
resources/sass/_components.scss
resources/sass/_pages.scss
resources/views/comments/comment.blade.php

diff --git a/resources/icons/bookmark.svg b/resources/icons/bookmark.svg
new file mode 100644 (file)
index 0000000..30e487c
--- /dev/null
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120v-640q0-33 23.5-56.5T280-840h400q33 0 56.5 23.5T760-760v640L480-240 200-120Zm80-122 200-86 200 86v-518H280v518Zm0-518h400-400Z"/></svg>
\ No newline at end of file
index 9192c7c56afc846605f5a4adbeb3e3f59ade4ce3..24964bf5cba20697085b535e83921427057be77a 100644 (file)
@@ -5,6 +5,7 @@ import {el} from "../wysiwyg/utils/dom";
 
 import commentIcon from "@icons/comment.svg"
 import closeIcon from "@icons/close.svg"
+import {PageDisplay} from "./page-display";
 
 /**
  * Track the close function for the current open marker so it can be closed
@@ -35,6 +36,7 @@ export class PageComment extends Component {
     protected deleteButton: HTMLElement;
     protected replyButton: HTMLElement;
     protected input: HTMLInputElement;
+    protected contentRefLink: HTMLLinkElement|null;
 
     setup() {
         // Options
@@ -60,6 +62,7 @@ export class PageComment extends Component {
         this.deleteButton = this.$refs.deleteButton;
         this.replyButton = this.$refs.replyButton;
         this.input = this.$refs.input as HTMLInputElement;
+        this.contentRefLink = (this.$refs.contentRef || null) as HTMLLinkElement|null;
 
         this.setupListeners();
         this.positionForReference();
@@ -153,21 +156,20 @@ export class PageComment extends Component {
     }
 
     protected positionForReference() {
-        if (!this.commentContentRef) {
+        if (!this.commentContentRef || !this.contentRefLink) {
             return;
         }
 
         const [refId, refHash, refRange] = this.commentContentRef.split(':');
         const refEl = document.getElementById(refId);
         if (!refEl) {
-            // TODO - Show outdated marker for comment
+            this.contentRefLink.classList.add('outdated', 'missing');
             return;
         }
 
         const actualHash = hashElement(refEl);
         if (actualHash !== refHash) {
-            // TODO - Show outdated marker for comment
-            return;
+            this.contentRefLink.classList.add('outdated');
         }
 
         const refElBounds = refEl.getBoundingClientRect();
@@ -204,6 +206,13 @@ export class PageComment extends Component {
 
         refEl.style.position = 'relative';
         refEl.append(markerWrap);
+
+        this.contentRefLink.href = `#${refEl.id}`;
+        this.contentRefLink.addEventListener('click', (event: MouseEvent) => {
+            const pageDisplayComponent = window.$components.get('page-display')[0] as PageDisplay;
+            event.preventDefault();
+            pageDisplayComponent.goToText(refId);
+        });
     }
 
     protected showCommentAtMarker(marker: HTMLElement): void {
index d3ac78a4ad19347779583d1331cb470d6532959a..13670c4bf50e38b43053103a7c7cb89ac1eb3b25 100644 (file)
@@ -57,6 +57,9 @@ export class PageDisplay extends Component {
         }
     }
 
+    /**
+     * @public
+     */
     goToText(text) {
         const idElem = document.getElementById(text);
 
index 26b0518275b17d3ca8db4ea9a10624bcc239affb..5486d61128827c87a96e7a5b46ca8e6be05a56b3 100644 (file)
@@ -746,6 +746,44 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
   height: calc(100% - vars.$m);
 }
 
+.comment-reference-indicator-wrap a {
+  float: left;
+  margin-top: vars.$xs;
+  font-size: 12px;
+  display: inline-block;
+  font-weight: bold;
+  position: relative;
+  border-radius: 4px;
+  overflow: hidden;
+  padding: 2px 6px 2px 0;
+  margin-inline-end: vars.$xs;
+  color: var(--color-link);
+  span {
+    display: none;
+  }
+  &.outdated span {
+    display: inline;
+  }
+  &.outdated.missing {
+    color: var(--color-warning);
+    pointer-events: none;
+  }
+  svg {
+    width: 24px;
+    margin-inline-end: 0;
+  }
+  &:after {
+    background-color: currentColor;
+    content: '';
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    left: 0;
+    top: 0;
+    opacity: 0.15;
+  }
+}
+
 .comment-branch .comment-box {
   margin-bottom: vars.$m;
 }
index be5a0f7c36073760ac103b575881e6cb35ec1745..dbdcc06656da9869769e6b672666079e087db38f 100755 (executable)
@@ -280,6 +280,9 @@ body.tox-fullscreen, body.markdown-fullscreen {
   max-height: 200px;
   overflow-y: scroll;
 }
+.content-comment-window-content .comment-reference-indicator-wrap {
+  display: none;
+}
 .content-comment-marker {
   position: absolute;
   right: -16px;
index 5b79da4ac685ec059453cfedce5d7bc64135b153..7cc84a54cf10d2130377c3388f3048a2418bc2f8 100644 (file)
                 <a class="text-muted text-small" href="#comment{{ $comment->parent_id }}">@icon('reply'){{ trans('entities.comment_in_reply_to', ['commentId' => '#' . $comment->parent_id]) }}</a>
             </p>
         @endif
+        @if($comment->content_ref)
+            <div class="comment-reference-indicator-wrap">
+                <a href="#" refs="page-comment@content-ref">@icon('bookmark')Reference <span>- Outdated</span></a>
+            </div>
+        @endif
         {!! $commentHtml  !!}
     </div>
 
Morty Proxy This is a proxified and sanitized view of the page, visit original site.