From a0fa6520c77e46b7a2e55b87e9994df3af74f149 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 29 Nov 2023 17:57:28 -0400 Subject: content, client, css: basic (absolute) datetimestamp tooltips --- .../dependencies/generateAbsoluteDatetimestamp.js | 41 +++++++++++++++ .../dependencies/generateDatetimestampTemplate.js | 28 ++++++++++ src/static/client3.js | 53 +++++++++++++++---- src/static/site6.css | 59 ++++++++++++++++------ 4 files changed, 156 insertions(+), 25 deletions(-) create mode 100644 src/content/dependencies/generateAbsoluteDatetimestamp.js create mode 100644 src/content/dependencies/generateDatetimestampTemplate.js diff --git a/src/content/dependencies/generateAbsoluteDatetimestamp.js b/src/content/dependencies/generateAbsoluteDatetimestamp.js new file mode 100644 index 00000000..63acecf2 --- /dev/null +++ b/src/content/dependencies/generateAbsoluteDatetimestamp.js @@ -0,0 +1,41 @@ +export default { + contentDependencies: ['generateDatetimestampTemplate'], + extraDependencies: ['html', 'language'], + + data: (date) => + ({date}), + + relations: (relation) => + ({template: relation('generateDatetimestampTemplate')}), + + slots: { + style: { + validate: v => v.is('full', 'year'), + default: 'full', + }, + + // Only has an effect for 'year' style. + tooltip: { + type: 'boolean', + default: false, + }, + }, + + generate: (data, relations, slots, {language}) => + relations.template.slots({ + mainContent: + (slots.style === 'full' + ? language.formatDate(data.date) + : slots.style === 'year' + ? data.date.getFullYear().toString() + : null), + + tooltipContent: + slots.tooltip && + slots.style === 'year' && + language.formatDate(data.date), + + datetime: + data.date.toISOString(), + }), +}; diff --git a/src/content/dependencies/generateDatetimestampTemplate.js b/src/content/dependencies/generateDatetimestampTemplate.js new file mode 100644 index 00000000..bfba647f --- /dev/null +++ b/src/content/dependencies/generateDatetimestampTemplate.js @@ -0,0 +1,28 @@ +export default { + extraDependencies: ['html'], + + slots: { + mainContent: {type: 'html'}, + tooltipContent: {type: 'html'}, + datetime: {type: 'string'}, + }, + + generate: (slots, {html}) => + html.tag('span', { + [html.joinChildren]: '', + + class: [ + 'datetimestamp', + slots.tooltipContent && 'has-tooltip', + ], + }, [ + html.tag('time', + {datetime: slots.datetime}, + slots.mainContent), + + slots.tooltipContent && + html.tag('span', {class: 'datetimestamp-tooltip'}, + html.tag('span', {class: 'datetimestamp-tooltip-content'}, + slots.tooltipContent)), + ]), +}; diff --git a/src/static/client3.js b/src/static/client3.js index 1e64ebe1..ce057712 100644 --- a/src/static/client3.js +++ b/src/static/client3.js @@ -1981,8 +1981,8 @@ for (const info of groupContributionsTableInfo) { // Artist link icon tooltips ------------------------------ const externalIconTooltipInfo = clientInfo.externalIconTooltipInfo = { - hoverableLinks: null, - iconContainers: null, + hoverables: null, + tooltips: null, }; function getExternalIconTooltipReferences() { @@ -1991,21 +1991,19 @@ function getExternalIconTooltipReferences() { const spans = Array.from(document.querySelectorAll('span.contribution.has-tooltip')); - info.hoverableLinks = - spans - .map(span => span.querySelector('a')); + info.hoverables = + spans.map(span => span.querySelector('a')); - info.iconContainers = - spans - .map(span => span.querySelector('span.icons-tooltip')); + info.tooltips = + spans.map(span => span.querySelector('span.icons-tooltip')); } function addExternalIconTooltipPageListeners() { const info = externalIconTooltipInfo; for (const {hoverable, tooltip} of stitchArrays({ - hoverable: info.hoverableLinks, - tooltip: info.iconContainers, + hoverable: info.hoverables, + tooltip: info.tooltips, })) { registerTooltipElement(tooltip); registerTooltipHoverableElement(hoverable, tooltip); @@ -2015,6 +2013,41 @@ function addExternalIconTooltipPageListeners() { clientSteps.getPageReferences.push(getExternalIconTooltipReferences); clientSteps.addPageListeners.push(addExternalIconTooltipPageListeners); +// Datetimestamp tooltips --------------------------------- + +const datetimestampTooltipInfo = clientInfo.datetimestampTooltipInfo = { + hoverables: null, + tooltips: null, +}; + +function getDatestampTooltipReferences() { + const info = datetimestampTooltipInfo; + + const spans = + Array.from(document.querySelectorAll('span.datetimestamp.has-tooltip')); + + info.hoverables = + spans.map(span => span.querySelector('time')); + + info.tooltips = + spans.map(span => span.querySelector('span.datetimestamp-tooltip')); +} + +function addDatestampTooltipPageListeners() { + const info = datetimestampTooltipInfo; + + for (const {hoverable, tooltip} of stitchArrays({ + hoverable: info.hoverables, + tooltip: info.tooltips, + })) { + registerTooltipElement(tooltip); + registerTooltipHoverableElement(hoverable, tooltip); + } +} + +clientSteps.getPageReferences.push(getDatestampTooltipReferences); +clientSteps.addPageListeners.push(addDatestampTooltipPageListeners); + // Sticky commentary sidebar ------------------------------ const albumCommentarySidebarInfo = clientInfo.albumCommentarySidebarInfo = { diff --git a/src/static/site6.css b/src/static/site6.css index 76b58f32..b7d5ce04 100644 --- a/src/static/site6.css +++ b/src/static/site6.css @@ -473,37 +473,51 @@ a:not([href]):hover { white-space: nowrap; } -.contribution { +.contribution.has-tooltip, +.datetimestamp.has-tooltip { position: relative; } -.contribution.has-tooltip > a { +.contribution.has-tooltip > a, +.datetimestamp.has-tooltip > time { text-decoration: underline; text-decoration-style: dotted; } -.contribution.has-tooltip > a:hover, -.contribution.has-tooltip > a.has-visible-tooltip { - text-decoration-style: wavy !important; +.datetimestamp.has-tooltip > time { + cursor: default; } -.icons { - font-style: normal; - white-space: nowrap; +.contribution.has-tooltip > a:hover, +.contribution.has-tooltip > a.has-visible-tooltip, +.datetimestamp.has-tooltip > time:hover, +.datetimestamp.has-tooltip > time.has-visible-tooltip { + text-decoration-style: wavy !important; } -.icons-tooltip { +.icons-tooltip, +.datetimestamp-tooltip { position: absolute; z-index: 3; left: -34px; top: calc(1em + 1px); - padding: 3px 6px 6px 6px; display: none; } -.icons-tooltip-content { +.icons-tooltip { + padding: 3px 6px 6px 6px; + left: -34px; +} + +.datetimestamp-tooltip { + padding: 3px 4px 2px 2px; + left: 14px; +} + +.icons-tooltip-content, +.datetimestamp-tooltip-content { display: block; - padding: 6px 2px 2px 2px; + background: var(--bg-black-color); border: 1px dotted var(--primary-color); border-radius: 6px; @@ -514,16 +528,31 @@ a:not([href]):hover { backdrop-filter: brightness(1.5) saturate(1.4) blur(4px); - -webkit-user-select: none; - user-select: none; - box-shadow: 0 3px 4px 4px #000000aa, 0 -2px 4px -2px var(--primary-color) inset; +} + +.icons-tooltip-content { + padding: 6px 2px 2px 2px; + + -webkit-user-select: none; + user-select: none; cursor: default; } +.datetimestamp-tooltip-content { + padding: 5px 6px; + white-space: nowrap; + font-size: 0.9em; +} + +.icons { + font-style: normal; + white-space: nowrap; +} + .icons a:hover { filter: brightness(1.4); } -- cgit 1.3.0-6-gf8a5