From ecda4e1d6f42108fef9c62ff4a9a73a056caa089 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 26 Apr 2025 21:05:54 +0100 Subject: [PATCH] Comments: Added reference marker to comments --- resources/icons/bookmark.svg | 1 + resources/js/components/page-comment.ts | 17 +++++++--- resources/js/components/page-display.js | 3 ++ resources/sass/_components.scss | 38 ++++++++++++++++++++++ resources/sass/_pages.scss | 3 ++ resources/views/comments/comment.blade.php | 5 +++ 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 resources/icons/bookmark.svg diff --git a/resources/icons/bookmark.svg b/resources/icons/bookmark.svg new file mode 100644 index 000000000..30e487c52 --- /dev/null +++ b/resources/icons/bookmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/js/components/page-comment.ts b/resources/js/components/page-comment.ts index 9192c7c56..24964bf5c 100644 --- a/resources/js/components/page-comment.ts +++ b/resources/js/components/page-comment.ts @@ -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 { diff --git a/resources/js/components/page-display.js b/resources/js/components/page-display.js index d3ac78a4a..13670c4bf 100644 --- a/resources/js/components/page-display.js +++ b/resources/js/components/page-display.js @@ -57,6 +57,9 @@ export class PageDisplay extends Component { } } + /** + * @public + */ goToText(text) { const idElem = document.getElementById(text); diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index 26b051827..5486d6112 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -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; } diff --git a/resources/sass/_pages.scss b/resources/sass/_pages.scss index be5a0f7c3..dbdcc0665 100755 --- a/resources/sass/_pages.scss +++ b/resources/sass/_pages.scss @@ -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; diff --git a/resources/views/comments/comment.blade.php b/resources/views/comments/comment.blade.php index 5b79da4ac..7cc84a54c 100644 --- a/resources/views/comments/comment.blade.php +++ b/resources/views/comments/comment.blade.php @@ -77,6 +77,11 @@ @icon('reply'){{ trans('entities.comment_in_reply_to', ['commentId' => '#' . $comment->parent_id]) }}

@endif + @if($comment->content_ref) +
+ @icon('bookmark')Reference - Outdated +
+ @endif {!! $commentHtml !!}