From 338ee0b27873053afb5d657f2de419faad0995c2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 30 Apr 2024 10:48:51 +0100 Subject: [PATCH] Add 'share' button for browsers supporting Web Share API --- snikket_web/scss/app.scss | 7 +-- snikket_web/static/img/icons.svg | 5 ++ snikket_web/templates/admin_edit_invite.html | 7 ++- snikket_web/templates/admin_invites.html | 5 +- .../templates/admin_reset_user_password.html | 2 +- snikket_web/templates/base.html | 2 +- snikket_web/templates/copy-snippet.html | 55 +++++++++++++++++++ snikket_web/templates/library.j2 | 25 ++++++++- tools/icons.list | 1 + 9 files changed, 97 insertions(+), 12 deletions(-) diff --git a/snikket_web/scss/app.scss b/snikket_web/scss/app.scss index 22c89b2..13d4140 100644 --- a/snikket_web/scss/app.scss +++ b/snikket_web/scss/app.scss @@ -992,19 +992,18 @@ div.profile-card { } } -/* clipboard button */ +/* clipboard and share buttons */ -.copy-to-clipboard { +.copy-to-clipboard, .share-button { cursor: pointer; font-style: normal; text-decoration: none; } -body.no-copy .copy-to-clipboard { +body.no-copy .copy-to-clipboard, body.no-share .share-button { display: none !important; } - /* magic */ pre.guru-meditation { diff --git a/snikket_web/static/img/icons.svg b/snikket_web/static/img/icons.svg index f2a0c88..01569a6 100644 --- a/snikket_web/static/img/icons.svg +++ b/snikket_web/static/img/icons.svg @@ -193,4 +193,9 @@ licensed under the terms of the Apache 2.0 License --> + + + + + diff --git a/snikket_web/templates/admin_edit_invite.html b/snikket_web/templates/admin_edit_invite.html index 2b20998..a66690c 100644 --- a/snikket_web/templates/admin_edit_invite.html +++ b/snikket_web/templates/admin_edit_invite.html @@ -1,5 +1,5 @@ {% extends "admin_app.html" %} -{% from "library.j2" import showuri, form_button, standard_button, extract_circle_name, invite_type_description %} +{% from "library.j2" import showuri, form_button, standard_button, extract_circle_name, invite_type_name, invite_type_description %} {% block head_lead %} {{ super() }} {% include "copy-snippet.html" %} @@ -13,9 +13,10 @@
{% trans %}Valid until{% endtrans %}
{{ invite.expires | format_date }}
-
{% call showuri(invite.landing_page, id_="link-field") %}{% endcall %}
+
{% call showuri(invite.landing_page, id_="link-field") %}{% trans %}Invitation to Snikket{% endtrans %}{% endcall %}
{% trans %}Invitation type{% endtrans %}
-
{% call invite_type_description(invite) %}{% endcall %}
+ {% set invite_type = invite.reusable and "group" or "account" %} +
{% call invite_type_name(invite_type) %}{% endcall %}
{%- set ngroups = invite.group_ids | length -%} {%- if ngroups > 1 -%} {#- not supported via the web UI, but we should still display it properly -#} diff --git a/snikket_web/templates/admin_invites.html b/snikket_web/templates/admin_invites.html index 34d5eeb..d4a8438 100644 --- a/snikket_web/templates/admin_invites.html +++ b/snikket_web/templates/admin_invites.html @@ -1,5 +1,5 @@ {% extends "admin_app.html" %} -{% from "library.j2" import action_button, icon, clipboard_button, form_button, custom_form_button, extract_circle_name, invite_type_name, invite_type_description %} +{% from "library.j2" import action_button, icon, clipboard_button, share_button, form_button, custom_form_button, extract_circle_name, invite_type_name, invite_type_description %} {% block head_lead %} {{ super() }} {% include "copy-snippet.html" %} @@ -48,6 +48,9 @@ {%- call clipboard_button(invite.landing_page, class="primary") -%} {% trans %}Copy invite link to clipboard{% endtrans %} {%- endcall -%} + {%- call share_button("Invitation to Snikket", invite.landing_page, class="primary") -%} + {% trans %}Share invitation link{% endtrans %} + {%- endcall -%} {%- call custom_form_button("remove_link", form.action_revoke.name, invite.id_, class="secondary danger", slim=True) -%} {% trans %}Delete invitation{% endtrans %} {%- endcall -%} diff --git a/snikket_web/templates/admin_reset_user_password.html b/snikket_web/templates/admin_reset_user_password.html index 3262b94..614cab0 100644 --- a/snikket_web/templates/admin_reset_user_password.html +++ b/snikket_web/templates/admin_reset_user_password.html @@ -15,7 +15,7 @@
{% trans %}Valid until{% endtrans %}
{{ reset_link.expires | format_date }}
-
{% call showuri(reset_link.landing_page, id_="link-field") %}{% endcall %}
+
{% call showuri(reset_link.landing_page, id_="link-field") %}Reset your Snikket password{% endcall %}
{%- call custom_form_button("remove_link", form.action_revoke.name, reset_link.id_, class="secondary danger") -%} diff --git a/snikket_web/templates/base.html b/snikket_web/templates/base.html index c42b42f..7272dc3 100644 --- a/snikket_web/templates/base.html +++ b/snikket_web/templates/base.html @@ -16,5 +16,5 @@ - {% block body %}{% endblock %} + {% block body %}{% endblock %} diff --git a/snikket_web/templates/copy-snippet.html b/snikket_web/templates/copy-snippet.html index d37d9ce..6113883 100644 --- a/snikket_web/templates/copy-snippet.html +++ b/snikket_web/templates/copy-snippet.html @@ -115,8 +115,63 @@ var copy_to_clipboard_btn = function(el) { }); }; +var copy_to_clipboard_btn = function(el) { + var text = el.dataset.cliptext; + if (!text) { + console.error('copy_to_clipboard used on element without text to copy'); + } + copyTextToClipboard(text, el, function(success) { + var existing_result_el = document.getElementById("clipboard-result"); + if (existing_result_el !== null) { + existing_result_el.parentNode.removeChild(existing_result_el); + } + + var icon = "done"; + if (!success) { + icon = "cancel"; + } + var icon_bak = get_current_icon(el.firstChild); + change_icon(el.firstChild, icon); + setTimeout(function() { + change_icon(el.firstChild, icon_bak); + el.blur(); + }, 1500); + }); +}; + +var share_url_btn = function(el) { + let data = { + "title": el.dataset.shareTitle, + "url": el.dataset.shareUrl, + } + + let icon_bak = get_current_icon(el.firstChild); + + new Promise(function (resolve, reject) { + if(!navigator.canShare || !navigator.canShare(data)) { + return reject(); + } + return resolve(navigator.share(data)); + }).then(function () { + // Success + change_icon(el.firstChild, "done"); + }, function () { + // Failure + change_icon(el.firstChild, "cancel"); + }).finally(function () { + // Either way, clear status icon after 1.5s + setTimeout(function() { + change_icon(el.firstChild, icon_bak); + el.blur(); + }, 1500); + }); +} + window.addEventListener('load', function() { document.body.classList.remove("no-copy"); + if(navigator.share) { + document.body.classList.remove("no-share"); + } }); diff --git a/snikket_web/templates/library.j2 b/snikket_web/templates/library.j2 index 1ddee5f..8b101c5 100644 --- a/snikket_web/templates/library.j2 +++ b/snikket_web/templates/library.j2 @@ -38,7 +38,10 @@ {%- else -%}
-
{% call clipboard_button(uri, show_label=True) %}{% trans %}Copy link{% endtrans %}{% endcall %}
+
+ {% call clipboard_button(uri, show_label=True) %}{% trans %}Copy link{% endtrans %}{% endcall %} + {% call share_button(caller() if caller is not none else None, uri, show_label=True) %}{% trans %}Share{% endtrans %}{% endcall %} +
{%- endif -%} {% endmacro %} @@ -82,7 +85,7 @@ {% macro clipboard_button(data, show_label=False, caller=None, class=None) -%} {%- set label = caller() -%} - {%- endmacro %} +{% macro share_button(title, url, show_label=False, caller=None, class=None) -%} +{%- set label = caller() -%} + +{%- endmacro %} + {% macro render_errors(field, caller=None) -%} {%- set error_list = field.errors if field.errors is not mapping else (field.errors.values() | flatten | list) -%} {%- if error_list -%} diff --git a/tools/icons.list b/tools/icons.list index a17999e..e88f5b3 100644 --- a/tools/icons.list +++ b/tools/icons.list @@ -36,3 +36,4 @@ image/edit:edit action/admin_panel_settings:admin content/link:link content/insights:insights +social/share:share