diff --git a/snikket_web/scss/app.scss b/snikket_web/scss/app.scss
index 681e1f3..caa2f43 100644
--- a/snikket_web/scss/app.scss
+++ b/snikket_web/scss/app.scss
@@ -402,24 +402,21 @@ div.form.layout-expanded {
}
+/* icon support */
+
+svg.icon {
+ display: inline-block;
+ vertical-align: middle;
+ width: 1em;
+ height: 1em;
+ stroke-width: 0;
+ stroke: currentColor;
+ fill: currentColor;
+}
+
+
/* form buttons */
-.btn-edit:before {
- content: '✎';
-}
-
-.btn-delete:before {
- content: '🗑';
-}
-
-.btn-link:before {
- content: '+';
-}
-
-.btn-more:before {
- content: '…';
-}
-
input[type="submit"], button, .button {
margin: 0 $w-s2;
padding: $w-s3 $w-s1;
@@ -430,6 +427,23 @@ input[type="submit"], button, .button {
margin: 0 $w-s4;
padding: $w-s4 $w-s2;
}
+
+ & > svg.icon:first-child {
+ margin-right: $w-s2;
+
+ td & {
+ margin-right: $w-s3;
+ }
+ }
+
+ & > svg.icon:last-child {
+ margin-right: 0;
+ margin-top: -$w-s4;
+
+ td & {
+ margin-right: 0;
+ }
+ }
}
a.button {
diff --git a/snikket_web/static/img/icons.svg b/snikket_web/static/img/icons.svg
new file mode 100644
index 0000000..4419117
--- /dev/null
+++ b/snikket_web/static/img/icons.svg
@@ -0,0 +1,90 @@
+
diff --git a/snikket_web/templates/admin_delete_user.html b/snikket_web/templates/admin_delete_user.html
index 8bed98a..0173d26 100644
--- a/snikket_web/templates/admin_delete_user.html
+++ b/snikket_web/templates/admin_delete_user.html
@@ -1,5 +1,5 @@
{% extends "admin_app.html" %}
-{% from "library.j2" import box %}
+{% from "library.j2" import box, form_button, standard_button %}
{% block content %}
{% trans user_name=target_user.localpart %}Delete user {{ user_name }}{% endtrans %}
{% endblock %}
diff --git a/snikket_web/templates/admin_edit_invite.html b/snikket_web/templates/admin_edit_invite.html
index 8c8e60e..b1ceaaf 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 %}
+{% from "library.j2" import showuri, form_button, standard_button %}
{% block head_lead %}
{{ super() }}
{% include "copy-snippet.html" %}
@@ -18,11 +18,10 @@
{% call showuri(invite.landing_page) %}{% endcall %}
- {#- -#}
- {{ form.action_revoke(class="button secondary danger") }}
- {#- -#}
-
{% trans %}Back{% endtrans %}
- {#- -#}
+ {%- call form_button("remove_link", form.action_revoke, class="secondary danger") %}{% endcall -%}
+ {%- call standard_button("back", url_for(".invitations"), class="primary") %}
+ {% trans %}Back{% endtrans %}
+ {%- endcall %}
diff --git a/snikket_web/templates/admin_invites.html b/snikket_web/templates/admin_invites.html
index 1c140c8..38007dc 100644
--- a/snikket_web/templates/admin_invites.html
+++ b/snikket_web/templates/admin_invites.html
@@ -1,4 +1,5 @@
{% extends "admin_app.html" %}
+{% from "library.j2" import action_button, icon, clipboard_button, form_button, custom_form_button %}
{% block head_lead %}
{{ super() }}
{% include "copy-snippet.html" %}
@@ -10,7 +11,7 @@
{% trans %}Create a new invitation link to invite more users to your Snikket instance by clicking the button below.{% endtrans %}
- {{ form.action_create_invite(class="primary") }}
+ {%- call form_button("create_link", form.action_create_invite, class="primary") %}{% endcall -%}
{% trans %}Pending invitations{% endtrans %}
@@ -32,13 +33,15 @@
{{ invite.created_at | format_date }} |
{{ (invite.expires - now) | format_timedelta(add_direction=True) }} |
- {#- -#}
- {% trans %}Show invite details{% endtrans %}
- {#- -#}
- 📋
- {#- -#}
-
- {#- -#}
+ {%- call action_button("more", url_for(".edit_invite", id_=invite.id_), class="secondary") -%}
+ {% trans %}Show invite details{% endtrans %}
+ {%- endcall -%}
+ {%- call clipboard_button(invite.landing_page, class="primary") -%}
+ {% trans %}Copy invite link to clipboard{% endtrans %}
+ {%- endcall -%}
+ {%- call custom_form_button("remove_link", form.action_revoke.name, invite.id_, class="secondary danger", slim=True) -%}
+ {% trans %}Delete invitation{% endtrans %}
+ {%- endcall -%}
|
{% endfor %}
diff --git a/snikket_web/templates/admin_users.html b/snikket_web/templates/admin_users.html
index 36da7d4..dcc4d63 100644
--- a/snikket_web/templates/admin_users.html
+++ b/snikket_web/templates/admin_users.html
@@ -1,4 +1,5 @@
{% extends "admin_app.html" %}
+{% from "library.j2" import icon %}
{% macro value_or_hint(v, caller=None) %}
{%- if v is not none -%}
{{- v -}}
@@ -26,7 +27,7 @@
{% call value_or_hint(user.email) %}{% endcall %} |
{% call value_or_hint(user.phone) %}{% endcall %} |
- {#- -#}{% trans user_name=user.localpart %}Delete user {{ user_name }}{% endtrans %}
+ {#- -#}{% call icon("remove") %}{% trans user_name=user.localpart %}Delete user {{ user_name }}{% endtrans %}{% endcall %}
{#- -#}
|
diff --git a/snikket_web/templates/base.html b/snikket_web/templates/base.html
index 8510912..769ea82 100644
--- a/snikket_web/templates/base.html
+++ b/snikket_web/templates/base.html
@@ -1,5 +1,5 @@
-
+
{% block head_lead %}{% endblock %}
diff --git a/snikket_web/templates/copy-snippet.html b/snikket_web/templates/copy-snippet.html
index c2f9eda..08975da 100644
--- a/snikket_web/templates/copy-snippet.html
+++ b/snikket_web/templates/copy-snippet.html
@@ -73,6 +73,50 @@ var copy_to_clipboard = function(el) {
});
};
+var get_current_icon = function(svg_el) {
+ var use_el = svg_el.firstChild;
+ // don’t ask. I hate js.
+ var tmp = "" + use_el.getAttribute("xlink:href");
+ return tmp.split("#")[1].split("-")[1];
+}
+
+var change_icon = function(svg_el, new_icon) {
+ var use_el = svg_el.firstChild;
+ // don’t ask. I hate js.
+ var tmp = "" + use_el.getAttribute("xlink:href");
+ var base_url = tmp.split("#")[0];
+ use_el.setAttributeNS(
+ "http://www.w3.org/1999/xlink", "xlink:href",
+ base_url + "#icon-" + new_icon
+ );
+}
+
+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";
+ var label = "{% trans %}Copied to clipboard{% endtrans %}";
+ if (!success) {
+ icon = "cancel";
+ label = "{% trans %}Copy operation failed{% endtrans %}";
+ }
+ var icon_bak = get_current_icon(el.firstChild);
+ change_icon(el.firstChild, icon);
+ setTimeout(function() {
+ change_icon(el.firstChild, icon_bak);
+ el.blur();
+ }, 1500);
+ });
+};
+
window.addEventListener('load', function() {
document.body.classList.remove("no-copy");
});
diff --git a/snikket_web/templates/demo.html b/snikket_web/templates/demo.html
index eda56b5..504a6c6 100644
--- a/snikket_web/templates/demo.html
+++ b/snikket_web/templates/demo.html
@@ -1,5 +1,5 @@
{% extends "base.html" %}
-{% from "library.j2" import box %}
+{% from "library.j2" import box, icon %}
{% set body_id = "no-lines" %}
{% block head_lead %}
Theme Demo – Snikket Web Portal
@@ -238,5 +238,22 @@
{% endfor %}
#}
+Icons
+Icons can be used in a variety of ways. For example in an enumeration:
+
+ - {% call icon("add") %}{% endcall %} Yaycon
+ - {% call icon("remove") %}{% endcall %} Naycon
+
+Or, more importantly, on buttons:
+
{% endblock %}
diff --git a/snikket_web/templates/library.j2 b/snikket_web/templates/library.j2
index 643f487..77d0a9e 100644
--- a/snikket_web/templates/library.j2
+++ b/snikket_web/templates/library.j2
@@ -10,16 +10,65 @@
{%- endif -%}
{%- endmacro %}
-{% macro clipboard_button(label=_("Copy link"), caller=None) -%}
-{%- set text = caller() -%}
-{{ label }}
-{%- endmacro %}
-
{% macro showuri(uri, caller=None) %}
{%- if uri is none -%}
—
{%- else -%}
-{% call clipboard_button() %}{{ uri }}{% endcall %}
+{% call clipboard_button(uri, show_label=True) %}{% trans %}Copy link{% endtrans %}{% endcall %}
{%- endif -%}
{% endmacro %}
+
+{% macro icon(name, caller=None) -%}
+{%- set alt = "" if caller is none else caller() -%}
+{%- if alt %}{{ alt }}{% endif %}
+{%- endmacro %}
+
+{% macro standard_button(icon_name, href, caller=None, class=None) -%}
+{%- set label = caller() -%}
+{% call icon(icon_name) %}{% endcall %}{{ label }}
+{%- endmacro %}
+
+{% macro form_button(icon_name, button_obj, caller=None, class=None) -%}
+
+{%- endmacro %}
+
+{% macro custom_form_button(icon_name, name, value, caller=None, slim=False, class=None) -%}
+{%- set text = caller() -%}
+
+{%- endmacro %}
+
+{% macro action_button(icon_name, href, caller=None, class=None) -%}
+{%- set a11y = caller() -%}
+{% call icon(icon_name) %}{% endcall %}
+{%- endmacro %}
+
+{% macro clipboard_button(data, show_label=False, caller=None, class=None) -%}
+{%- set label = caller() -%}
+
+ {%- call icon("copy") %}{% endcall -%}
+{%- if show_label %}
+ {{ label }}
+{% endif -%}
+
+{%- endmacro %}
diff --git a/snikket_web/templates/login.html b/snikket_web/templates/login.html
index 80d31c0..e96ce08 100644
--- a/snikket_web/templates/login.html
+++ b/snikket_web/templates/login.html
@@ -1,5 +1,5 @@
{% extends "base.html" %}
-{% from "library.j2" import box %}
+{% from "library.j2" import box, icon %}
{% set body_id = "login" %}
{% block head_lead %}
{{ _("Snikket Login") }}
@@ -28,7 +28,7 @@
{{ form.password(placeholder=form.password.label.text) }}
-
+
diff --git a/snikket_web/templates/user_logout.html b/snikket_web/templates/user_logout.html
index 94637ca..b33cb7e 100644
--- a/snikket_web/templates/user_logout.html
+++ b/snikket_web/templates/user_logout.html
@@ -1,4 +1,5 @@
{% extends "app.html" %}
+{% from "library.j2" import icon %}
{% block head_lead %}
Snikket Web Portal
{% endblock %}
@@ -9,9 +10,9 @@
{{ form.csrf_token }}
diff --git a/snikket_web/templates/user_passwd.html b/snikket_web/templates/user_passwd.html
index 5463bff..4f1b342 100644
--- a/snikket_web/templates/user_passwd.html
+++ b/snikket_web/templates/user_passwd.html
@@ -1,4 +1,5 @@
{% extends "app.html" %}
+{% from "library.j2" import standard_button, custom_form_button %}
{% block head_lead %}
Snikket Web Portal
{% endblock %}
@@ -36,8 +37,10 @@
{% trans %}After changing your password, you will have to enter the new password on all of your devices.{% endtrans %}
-
{% trans %}Back{% endtrans %}
-
+ {%- call standard_button("back", url_for('.index'), class="secondary") %}{% trans %}Back{% endtrans %}{% endcall -%}
+ {%- call custom_form_button("done", "", "", class="primary") -%}
+ {% trans %}Change password{% endtrans %}
+ {%- endcall -%}
{% endblock %}
diff --git a/snikket_web/templates/user_profile.html b/snikket_web/templates/user_profile.html
index e3467f2..2baf111 100644
--- a/snikket_web/templates/user_profile.html
+++ b/snikket_web/templates/user_profile.html
@@ -1,4 +1,5 @@
{% extends "app.html" %}
+{% from "library.j2" import standard_button, form_button %}
{% block head_lead %}
Snikket Web Portal
{% endblock %}
@@ -21,7 +22,8 @@
{{ form.profile_access_model }}
-
{% trans %}Back{% endtrans %}
+ {%- call standard_button("back", url_for('.index'), class="secondary") %}{% trans %}Back{% endtrans %}{% endcall -%}
+ {%- call form_button("done", form.action_save, class="primary") %}{% endcall -%}
{% endblock %}
diff --git a/snikket_web/user.py b/snikket_web/user.py
index 0ea074a..20db824 100644
--- a/snikket_web/user.py
+++ b/snikket_web/user.py
@@ -67,6 +67,10 @@ class ProfileForm(flask_wtf.FlaskForm): # type:ignore
choices=_ACCESS_MODEL_CHOICES,
)
+ action_save = wtforms.SubmitField(
+ _l("Apply"),
+ )
+
@bp.route("/")
@client.require_session()
diff --git a/tools/icons.list b/tools/icons.list
new file mode 100644
index 0000000..644730a
--- /dev/null
+++ b/tools/icons.list
@@ -0,0 +1,17 @@
+action/account_circle:profile
+action/done:done
+action/logout:logout
+action/login:login
+communication/vpn_key:passwd
+content/add_circle_outline:add
+content/add_link:create_link
+content/create:edit
+content/remove_circle_outline:remove
+content/content_copy:copy
+content/link_off:remove_link
+navigation/arrow_back:back
+navigation/arrow_forward:forward
+navigation/cancel:cancel
+navigation/more_vert:more
+social/groups:groups
+social/group_add:create_group
diff --git a/tools/import-icons.sh b/tools/import-icons.sh
new file mode 100644
index 0000000..92c869b
--- /dev/null
+++ b/tools/import-icons.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+set -euo pipefail
+# usage: import-icons.sh ROOT ICONLIST FLAVOR SVGOUT
+#
+# positional arguments:
+#
+# ROOT path to the checkout of https://github.com/google/material-design-icons
+# ICONLIST path to the icons.list file in the snikket-web-portal repository
+# FLAVOR one of '', 'round', 'sharp', 'outlined', 'twoshade'
+# SVGOUT path to the newly created SVG file
+root="$1/src"
+iconlist_file="$2"
+flavor="$3"
+output_file="$4"
+
+printf '\n' >> "$output_file"