diff --git a/client/css/colors.styl b/client/css/colors.styl index d49033a9..b4b27560 100644 --- a/client/css/colors.styl +++ b/client/css/colors.styl @@ -32,3 +32,8 @@ $new-tag-text-color = black $default-tag-category-background-color = $active-tab-background-color $duplicate-tag-background-color = #FDC $duplicate-tag-text-color = black +$note-overlay-background-color = rgba(255, 255, 255, 0.3) +$note-overlay-border-color = rgba(0, 0, 0, 0.3) +$note-text-background-color = lemonchiffon +$note-text-border-color = black +$note-text-text-color = black diff --git a/client/css/posts.styl b/client/css/posts.styl index 3ea0f8b8..38123ca2 100644 --- a/client/css/posts.styl +++ b/client/css/posts.styl @@ -27,3 +27,27 @@ bottom: 0 width: 100% height: 100% + + .notes + stroke-width: 1px + polygon + fill: $note-overlay-background-color + stroke: $note-overlay-border-color + +.note-text + position: absolute + max-width: 22.5em + margin-top: -0.5em + display: none + + &>.wrapper + background: $note-text-background-color + padding: 0.5em + border: 1px solid $note-text-border-color + color: $note-text-text-color + margin-top: 1em + + p:last-of-type + margin-bottom: 0 + p:first-of-type + margin-top: 0 diff --git a/client/js/controls/post_notes_overlay_control.js b/client/js/controls/post_notes_overlay_control.js new file mode 100644 index 00000000..945dab45 --- /dev/null +++ b/client/js/controls/post_notes_overlay_control.js @@ -0,0 +1,79 @@ +'use strict'; + +const views = require('../util/views.js'); +const misc = require('../util/misc.js'); +const svgNS = 'http://www.w3.org/2000/svg'; + +class PostNotesOverlayControl { + constructor(postOverlayNode, post) { + this._post = post; + this._postOverlayNode = postOverlayNode; + this._install(); + } + + _evtMouseEnter(e) { + const bodyRect = document.body.getBoundingClientRect(); + const svgRect = this._svgNode.getBoundingClientRect(); + const polygonRect = e.target.getBBox(); + this._textNode.querySelector('.wrapper').innerHTML + = misc.formatMarkdown(e.target.getAttribute('data-text')); + this._textNode.style.left = ( + svgRect.left + svgRect.width * polygonRect.x) + 'px'; + this._textNode.style.top = ( + svgRect.top + svgRect.height * ( + polygonRect.y + polygonRect.height)) + 'px'; + this._textNode.style.display = 'block'; + } + + _evtMouseLeave(e) { + const newElement = e.relatedTarget; + if (newElement === this._svgNode || + (!this._svgNode.contains(newElement) + && !this._textNode.contains(newElement) + && newElement !== this._textNode)) { + this._textNode.style.display = 'none'; + } + } + + _install() { + this._svgNode = document.createElementNS(svgNS, 'svg'); + this._svgNode.classList.add('notes'); + this._svgNode.setAttribute('preserveAspectRatio', 'none'); + this._svgNode.setAttribute('viewBox', '0 0 1 1'); + for (let note of this._post.notes) { + const polygonNode = document.createElementNS(svgNS, 'polygon'); + polygonNode.setAttribute( + 'vector-effect', 'non-scaling-stroke'); + polygonNode.setAttribute( + 'stroke-alignment', 'inside'); + polygonNode.setAttribute( + 'points', note.polygon.map(point => point.join(',')).join(' ')); + polygonNode.setAttribute('data-text', note.text); + polygonNode.addEventListener( + 'mouseenter', e => this._evtMouseEnter(e)); + polygonNode.addEventListener( + 'mouseleave', e => this._evtMouseLeave(e)); + this._svgNode.appendChild(polygonNode); + } + this._postOverlayNode.appendChild(this._svgNode); + + const wrapperNode = document.createElement('div'); + wrapperNode.classList.add('wrapper'); + this._textNode = document.createElement('div'); + this._textNode.classList.add('note-text'); + this._textNode.appendChild(wrapperNode); + this._textNode.addEventListener( + 'mouseleave', e => this._evtMouseLeave(e)); + document.body.appendChild(this._textNode); + + views.monitorNodeRemoval( + this._postOverlayNode, () => { this._uninstall(); }); + } + + _uninstall() { + this._postOverlayNode.removeChild(this._svgNode); + document.body.removeChild(this._textNode); + } +}; + +module.exports = PostNotesOverlayControl; diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js index 1cf81cf3..7b20f3be 100644 --- a/client/js/views/home_view.js +++ b/client/js/views/home_view.js @@ -5,6 +5,8 @@ const config = require('../config.js'); const misc = require('../util/misc.js'); const views = require('../util/views.js'); const PostContentControl = require('../controls/post_content_control.js'); +const PostNotesOverlayControl + = require('../controls/post_notes_overlay_control.js'); const TagAutoCompleteControl = require('../controls/tag_auto_complete_control.js'); @@ -49,6 +51,10 @@ class HomeView { window.innerHeight * 0.7, ]; }); + + new PostNotesOverlayControl( + postContainerNode.querySelector('.post-overlay'), + ctx.featuredPost); } } }