From a13322dcee25172b5a03af4b7a6a4ea7ee6fece8 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Thu, 5 Aug 2021 18:30:44 +0200 Subject: [PATCH 1/7] Add share option to answers --- .../stylesheets/components/_answerbox.scss | 6 ++++++ .../retrospring/initializers/share.ts | 20 +++++++++++++++++++ app/views/answerbox/_actions.haml | 2 ++ 3 files changed, 28 insertions(+) create mode 100644 app/javascript/retrospring/initializers/share.ts diff --git a/app/assets/stylesheets/components/_answerbox.scss b/app/assets/stylesheets/components/_answerbox.scss index d13f672f..cc892099 100644 --- a/app/assets/stylesheets/components/_answerbox.scss +++ b/app/assets/stylesheets/components/_answerbox.scss @@ -61,4 +61,10 @@ } } } +} + +body:not(.cap-web-share) { + .answerbox__action[name="ab-share"] { + display: none; + } } \ No newline at end of file diff --git a/app/javascript/retrospring/initializers/share.ts b/app/javascript/retrospring/initializers/share.ts new file mode 100644 index 00000000..26b0716f --- /dev/null +++ b/app/javascript/retrospring/initializers/share.ts @@ -0,0 +1,20 @@ +import $ from 'jquery'; + +export default (): void => { + document.addEventListener('turbolinks:load', function () { + if (navigator.share) { + document.body.classList.add('cap-web-share') + $(document).on('click', 'button[name=ab-share]', function () { + const card = $(this).closest('.card') + + navigator.share({ + url: card.find('.answerbox__answer-date a')[0].href + }).then(() => { + // do nothing, prevents exception from being thrown + }).catch(() => { + // do nothing, prevents exception from being thrown + }) + }) + } + }) +} \ No newline at end of file diff --git a/app/views/answerbox/_actions.haml b/app/views/answerbox/_actions.haml index f6f99c12..8287f749 100644 --- a/app/views/answerbox/_actions.haml +++ b/app/views/answerbox/_actions.haml @@ -16,6 +16,8 @@ %button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-comments', data: { a_id: a.id, state: :hidden } } %i.fa.fa-fw.fa-comments %span{ id: "ab-comment-count-#{a.id}" }= a.comment_count +%button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-share'} + %i.fa.fa-fw.fa-share-alt{ title: 'Share' } - if user_signed_in? .btn-group %button.btn.btn-default.btn-sm.dropdown-toggle{ data: { toggle: :dropdown }, aria: { expanded: false } } From 08822b0f05a66849c99a0adbba5299503c409512 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Fri, 6 Aug 2021 01:09:28 +0200 Subject: [PATCH 2/7] Move answerbox actions on to seperate row on mobile --- app/assets/stylesheets/components/_answerbox.scss | 14 ++++++++++++++ app/views/application/_answerbox.haml | 8 ++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/components/_answerbox.scss b/app/assets/stylesheets/components/_answerbox.scss index cc892099..df2a9c64 100644 --- a/app/assets/stylesheets/components/_answerbox.scss +++ b/app/assets/stylesheets/components/_answerbox.scss @@ -61,6 +61,20 @@ } } } + + &__actions { + text-align: right; + @include media-breakpoint-down('md') { + justify-content: space-between; + padding-top: 10px; + } + } + + @include media-breakpoint-down('md') { + .card-body { + padding-bottom: .6rem; + } + } } body:not(.cap-web-share) { diff --git a/app/views/application/_answerbox.haml b/app/views/application/_answerbox.haml index 1f427b7d..781754e4 100644 --- a/app/views/application/_answerbox.haml +++ b/app/views/application/_answerbox.haml @@ -16,7 +16,7 @@ = markdown a.content - if @user.nil? .row - .col.col-sm-4.col-md-6.text-left.text-muted + .col-sm-6.text-left.text-muted .media .pull-left %a{ href: show_user_profile_path(a.user.screen_name) } @@ -26,14 +26,14 @@ = raw t('views.answerbox.answered', hide: hidespan(t('views.answerbox.hide'), 'd-none d-sm-inline'), user: user_screen_name(a.user)) .answerbox__answer-date = link_to(raw(t('views.answerbox.time', time: time_tooltip(a))), show_user_answer_path(a.user.screen_name, a.id)) - .col.col-sm-8.col-md-6.text-right + .col-md-6.d-flex.d-md-block.answerbox__actions = render 'answerbox/actions', a: a, display_all: display_all - else .row - .col-4.col-sm-4.col-md-6.text-left.text-muted + .col-md-6.text-left.text-muted %i.fa.fa-clock-o = link_to(raw(t('views.answerbox.time', time: time_tooltip(a))), show_user_answer_path(a.user.screen_name, a.id)) - .col-8.col-sm-8.col-md-6.text-right + .col-md-6.d-md-flex.answerbox__actions = render 'answerbox/actions', a: a, display_all: display_all .card-footer{ id: "ab-comments-section-#{a.id}", style: display_all.nil? ? 'display: none' : nil } %div{ id: "ab-smiles-#{a.id}" }= render 'answerbox/smiles', a: a From 8f230882449c69c7ed0aa51ac9c8d59e17e3a919 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Fri, 6 Aug 2021 11:04:57 +0200 Subject: [PATCH 3/7] Lint: Add missing space to attributes --- app/views/answerbox/_actions.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/answerbox/_actions.haml b/app/views/answerbox/_actions.haml index 8287f749..d17fbf9d 100644 --- a/app/views/answerbox/_actions.haml +++ b/app/views/answerbox/_actions.haml @@ -16,7 +16,7 @@ %button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-comments', data: { a_id: a.id, state: :hidden } } %i.fa.fa-fw.fa-comments %span{ id: "ab-comment-count-#{a.id}" }= a.comment_count -%button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-share'} +%button.btn.btn-link.answerbox__action{ type: :button, name: 'ab-share' } %i.fa.fa-fw.fa-share-alt{ title: 'Share' } - if user_signed_in? .btn-group From a246083b155a42ca3abc8e0ea91a2baf08835f2d Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Tue, 10 Aug 2021 13:16:40 +0200 Subject: [PATCH 4/7] Refactor sharing using feature pattern --- app/javascript/packs/application.ts | 4 ++++ .../retrospring/features/answerbox/index.ts | 20 +++++++++++++++++++ .../retrospring/features/answerbox/share.ts | 11 ++++++++++ .../retrospring/initializers/share.ts | 20 ------------------- .../retrospring/utilities/registerEvents.ts | 17 ++++++++++++++++ 5 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 app/javascript/retrospring/features/answerbox/index.ts create mode 100644 app/javascript/retrospring/features/answerbox/share.ts delete mode 100644 app/javascript/retrospring/initializers/share.ts create mode 100644 app/javascript/retrospring/utilities/registerEvents.ts diff --git a/app/javascript/packs/application.ts b/app/javascript/packs/application.ts index 451567d3..16e991ae 100644 --- a/app/javascript/packs/application.ts +++ b/app/javascript/packs/application.ts @@ -1,3 +1,7 @@ import start from '../retrospring/common'; +import initAnswerbox from '../retrospring/features/answerbox/index'; start(); +document.addEventListener('turbolinks:load', initAnswerbox); +document.addEventListener('turbolinks:load', initAnswerbox); +document.addEventListener('turbolinks:load', initAnswerbox); \ No newline at end of file diff --git a/app/javascript/retrospring/features/answerbox/index.ts b/app/javascript/retrospring/features/answerbox/index.ts new file mode 100644 index 00000000..657dd646 --- /dev/null +++ b/app/javascript/retrospring/features/answerbox/index.ts @@ -0,0 +1,20 @@ +import registerEvents from "retrospring/utilities/registerEvents"; +import {createShareEvent} from "./share"; + +export default (): void => { + if (!('share' in navigator)) { + return; + } + + document.body.classList.add('cap-web-share'); + const entries: NodeList = document.querySelectorAll('.answerbox:not(.js-initialized)'); + + entries.forEach((element: HTMLElement) => { + console.log(element) + registerEvents([ + { type: 'click', target: element.querySelector('[data-action=ab-share]'), handler: createShareEvent(element) } + ]); + + element.classList.add('js-initialized'); + }); +} \ No newline at end of file diff --git a/app/javascript/retrospring/features/answerbox/share.ts b/app/javascript/retrospring/features/answerbox/share.ts new file mode 100644 index 00000000..fd6c8d8f --- /dev/null +++ b/app/javascript/retrospring/features/answerbox/share.ts @@ -0,0 +1,11 @@ +export function createShareEvent(answerbox: HTMLElement): () => void { + return function (): void { + navigator.share({ + url: answerbox.querySelector('.answerbox__answer-date > a').href + }).then(() => { + // do nothing, prevents exce ption from being thrown + }).catch(() => { + // do nothing, prevents exception from being thrown + }) + } +} diff --git a/app/javascript/retrospring/initializers/share.ts b/app/javascript/retrospring/initializers/share.ts deleted file mode 100644 index 26b0716f..00000000 --- a/app/javascript/retrospring/initializers/share.ts +++ /dev/null @@ -1,20 +0,0 @@ -import $ from 'jquery'; - -export default (): void => { - document.addEventListener('turbolinks:load', function () { - if (navigator.share) { - document.body.classList.add('cap-web-share') - $(document).on('click', 'button[name=ab-share]', function () { - const card = $(this).closest('.card') - - navigator.share({ - url: card.find('.answerbox__answer-date a')[0].href - }).then(() => { - // do nothing, prevents exception from being thrown - }).catch(() => { - // do nothing, prevents exception from being thrown - }) - }) - } - }) -} \ No newline at end of file diff --git a/app/javascript/retrospring/utilities/registerEvents.ts b/app/javascript/retrospring/utilities/registerEvents.ts new file mode 100644 index 00000000..a0991cce --- /dev/null +++ b/app/javascript/retrospring/utilities/registerEvents.ts @@ -0,0 +1,17 @@ +interface EventDef { + type: string; + target: Node | NodeList; + handler: EventListenerOrEventListenerObject; +} + +export default function registerEvents(events: EventDef[]): void { + events.forEach(event => { + if (event.target instanceof NodeList) { + event.target.forEach(element => { + element.addEventListener(event.type, event.handler); + }); + } else if (event.target instanceof Node) { + event.target.addEventListener(event.type, event.handler); + } + }); +} \ No newline at end of file From b4f87a288ae38217e9e4194f50fa861bc9ef346d Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Tue, 10 Aug 2021 13:17:05 +0200 Subject: [PATCH 5/7] Invert answerbox action CSS to be mobile first --- app/assets/stylesheets/components/_answerbox.scss | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/assets/stylesheets/components/_answerbox.scss b/app/assets/stylesheets/components/_answerbox.scss index df2a9c64..bb91cd36 100644 --- a/app/assets/stylesheets/components/_answerbox.scss +++ b/app/assets/stylesheets/components/_answerbox.scss @@ -64,16 +64,17 @@ &__actions { text-align: right; - @include media-breakpoint-down('md') { - justify-content: space-between; - padding-top: 10px; + justify-content: space-between; + padding-top: 10px; + + @include media-breakpoint-up('sm') { + justify-content: unset; + padding-top: 0; } } - @include media-breakpoint-down('md') { - .card-body { - padding-bottom: .6rem; - } + .card-body { + padding-bottom: .6rem; } } From 016f369ba27c6b0a08b68c37f1c9833fdfcb2220 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Tue, 10 Aug 2021 15:50:17 +0200 Subject: [PATCH 6/7] Address review comments --- app/javascript/packs/application.ts | 2 -- .../retrospring/features/answerbox/index.ts | 28 +++++++++---------- .../retrospring/features/answerbox/share.ts | 8 +++--- app/javascript/retrospring/utilities/noop.ts | 3 ++ 4 files changed, 20 insertions(+), 21 deletions(-) create mode 100644 app/javascript/retrospring/utilities/noop.ts diff --git a/app/javascript/packs/application.ts b/app/javascript/packs/application.ts index 16e991ae..bcfeddc4 100644 --- a/app/javascript/packs/application.ts +++ b/app/javascript/packs/application.ts @@ -3,5 +3,3 @@ import initAnswerbox from '../retrospring/features/answerbox/index'; start(); document.addEventListener('turbolinks:load', initAnswerbox); -document.addEventListener('turbolinks:load', initAnswerbox); -document.addEventListener('turbolinks:load', initAnswerbox); \ No newline at end of file diff --git a/app/javascript/retrospring/features/answerbox/index.ts b/app/javascript/retrospring/features/answerbox/index.ts index 657dd646..1f1a2ff9 100644 --- a/app/javascript/retrospring/features/answerbox/index.ts +++ b/app/javascript/retrospring/features/answerbox/index.ts @@ -2,19 +2,17 @@ import registerEvents from "retrospring/utilities/registerEvents"; import {createShareEvent} from "./share"; export default (): void => { - if (!('share' in navigator)) { - return; + if ('share' in navigator) { + document.body.classList.add('cap-web-share'); + const entries: NodeList = document.querySelectorAll('.answerbox:not(.js-initialized)'); + + entries.forEach((element: HTMLElement) => { + console.log(element) + registerEvents([ + { type: 'click', target: element.querySelector('[data-action=ab-share]'), handler: createShareEvent(element) } + ]); + + element.classList.add('js-initialized'); + }); } - - document.body.classList.add('cap-web-share'); - const entries: NodeList = document.querySelectorAll('.answerbox:not(.js-initialized)'); - - entries.forEach((element: HTMLElement) => { - console.log(element) - registerEvents([ - { type: 'click', target: element.querySelector('[data-action=ab-share]'), handler: createShareEvent(element) } - ]); - - element.classList.add('js-initialized'); - }); -} \ No newline at end of file +} diff --git a/app/javascript/retrospring/features/answerbox/share.ts b/app/javascript/retrospring/features/answerbox/share.ts index fd6c8d8f..351eea27 100644 --- a/app/javascript/retrospring/features/answerbox/share.ts +++ b/app/javascript/retrospring/features/answerbox/share.ts @@ -1,11 +1,11 @@ +import noop from 'retrospring/utilities/noop'; + export function createShareEvent(answerbox: HTMLElement): () => void { return function (): void { navigator.share({ url: answerbox.querySelector('.answerbox__answer-date > a').href - }).then(() => { - // do nothing, prevents exce ption from being thrown - }).catch(() => { - // do nothing, prevents exception from being thrown }) + .then(noop) + .catch(noop) } } diff --git a/app/javascript/retrospring/utilities/noop.ts b/app/javascript/retrospring/utilities/noop.ts new file mode 100644 index 00000000..260582c8 --- /dev/null +++ b/app/javascript/retrospring/utilities/noop.ts @@ -0,0 +1,3 @@ +export default () => void { + // do nothing +} From aa9fc54ad2e750062cc30611d1bed121597725b7 Mon Sep 17 00:00:00 2001 From: Karina Kwiatek Date: Tue, 10 Aug 2021 18:07:33 +0200 Subject: [PATCH 7/7] Ensure answerboxes on profiles can properly attach sharing functionality --- app/assets/stylesheets/components/_answerbox.scss | 2 +- app/javascript/retrospring/features/answerbox/index.ts | 3 +-- app/javascript/retrospring/features/answerbox/share.ts | 2 +- app/javascript/retrospring/utilities/noop.ts | 2 +- app/views/application/_answerbox.haml | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/components/_answerbox.scss b/app/assets/stylesheets/components/_answerbox.scss index bb91cd36..c45dc613 100644 --- a/app/assets/stylesheets/components/_answerbox.scss +++ b/app/assets/stylesheets/components/_answerbox.scss @@ -68,7 +68,7 @@ padding-top: 10px; @include media-breakpoint-up('sm') { - justify-content: unset; + justify-content: flex-end; padding-top: 0; } } diff --git a/app/javascript/retrospring/features/answerbox/index.ts b/app/javascript/retrospring/features/answerbox/index.ts index 1f1a2ff9..45c8cd68 100644 --- a/app/javascript/retrospring/features/answerbox/index.ts +++ b/app/javascript/retrospring/features/answerbox/index.ts @@ -7,9 +7,8 @@ export default (): void => { const entries: NodeList = document.querySelectorAll('.answerbox:not(.js-initialized)'); entries.forEach((element: HTMLElement) => { - console.log(element) registerEvents([ - { type: 'click', target: element.querySelector('[data-action=ab-share]'), handler: createShareEvent(element) } + { type: 'click', target: element.querySelector('[name=ab-share]'), handler: createShareEvent(element) } ]); element.classList.add('js-initialized'); diff --git a/app/javascript/retrospring/features/answerbox/share.ts b/app/javascript/retrospring/features/answerbox/share.ts index 351eea27..6d74815e 100644 --- a/app/javascript/retrospring/features/answerbox/share.ts +++ b/app/javascript/retrospring/features/answerbox/share.ts @@ -3,7 +3,7 @@ import noop from 'retrospring/utilities/noop'; export function createShareEvent(answerbox: HTMLElement): () => void { return function (): void { navigator.share({ - url: answerbox.querySelector('.answerbox__answer-date > a').href + url: answerbox.querySelector('.answerbox__answer-date > a, a.answerbox__permalink').href }) .then(noop) .catch(noop) diff --git a/app/javascript/retrospring/utilities/noop.ts b/app/javascript/retrospring/utilities/noop.ts index 260582c8..85f1db46 100644 --- a/app/javascript/retrospring/utilities/noop.ts +++ b/app/javascript/retrospring/utilities/noop.ts @@ -1,3 +1,3 @@ -export default () => void { +export default (): void => { // do nothing } diff --git a/app/views/application/_answerbox.haml b/app/views/application/_answerbox.haml index 781754e4..e33da4b8 100644 --- a/app/views/application/_answerbox.haml +++ b/app/views/application/_answerbox.haml @@ -32,7 +32,7 @@ .row .col-md-6.text-left.text-muted %i.fa.fa-clock-o - = link_to(raw(t('views.answerbox.time', time: time_tooltip(a))), show_user_answer_path(a.user.screen_name, a.id)) + = link_to(raw(t('views.answerbox.time', time: time_tooltip(a))), show_user_answer_path(a.user.screen_name, a.id), class: 'answerbox__permalink') .col-md-6.d-md-flex.answerbox__actions = render 'answerbox/actions', a: a, display_all: display_all .card-footer{ id: "ab-comments-section-#{a.id}", style: display_all.nil? ? 'display: none' : nil }