diff --git a/static/css/style.css b/static/css/style.css index 93672c0..69eaa44 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -97,6 +97,8 @@ header { } header h1 { + font-family: "Raleway"; + font-weight: normal; background: var(--color-fg2); padding: 10px 7px 7px 7px; font-size: 130%; @@ -104,6 +106,12 @@ header h1 { color: var(--color-fg1); } +header h1 img { + display: inline; + vertical-align: top; + margin: 0 3px 0 0; +} + header a { color: inherit; text-decoration: none; @@ -117,8 +125,9 @@ header menu { } header menu li { - padding: 20px 10px 7px 10px; + padding: 10px 10px 7px 10px; color: #eee; + line-height: 32px; } main { @@ -150,10 +159,28 @@ main { .modal .option { display: block; - padding: 20px 30px; + padding: 15px 20px; color: var(--color-text-main); text-decoration: none; border-left: 3px solid transparent; + line-height: 32px; +} + +.modal .option img { + display: inline; + vertical-align: middle; + margin: 0 10px 3px 0; +} + +.modal .option i { + display: inline-block; + vertical-align: middle; + width: 32px; + height: 32px; + text-align: center; + line-height: 32px; + font-size: 150%; + margin: 0 10px 3px 0; } .modal a.option:hover { @@ -165,6 +192,11 @@ main { color: var(--color-text-dull); } +.modal .option small { + margin: 0 0 0 5px; + color: var(--color-text-dull); +} + .modal form { padding: 10px 10px 1px 10px; } diff --git a/static/img/unknown-icon-128.png b/static/img/unknown-icon-128.png new file mode 100644 index 0000000..0bfef8e Binary files /dev/null and b/static/img/unknown-icon-128.png differ diff --git a/static/img/unknown_icon.svg b/static/img/unknown_icon.svg new file mode 100644 index 0000000..0801de8 --- /dev/null +++ b/static/img/unknown_icon.svg @@ -0,0 +1,67 @@ + + + +? diff --git a/takahe/urls.py b/takahe/urls.py index c43e4fa..d6e4d8f 100644 --- a/takahe/urls.py +++ b/takahe/urls.py @@ -14,6 +14,7 @@ urlpatterns = [ path("@/actor/", identity.Actor.as_view()), path("@/actor/inbox/", identity.Inbox.as_view()), # Identity selection + path("@/activate/", identity.ActivateIdentity.as_view()), path("identity/select/", identity.SelectIdentity.as_view()), path("identity/create/", identity.CreateIdentity.as_view()), # Well-known endpoints diff --git a/templates/base.html b/templates/base.html index 4dc62ca..af2887f 100644 --- a/templates/base.html +++ b/templates/base.html @@ -13,11 +13,25 @@
-

{{ config.site_name }}

+

+ + + {{ config.site_name }} + +

+
  • + +
  • {% if user.is_authenticated %} - Logout + + {% if user.icon_uri %} + + {% else %} + + {% endif %} + {% else %} Login {% endif %} diff --git a/templates/identity/select.html b/templates/identity/select.html index f5be401..dae1ca1 100644 --- a/templates/identity/select.html +++ b/templates/identity/select.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load static %} {% block title %}Select Identity{% endblock %} @@ -6,12 +7,23 @@ {% endblock %} diff --git a/templates/identity/view.html b/templates/identity/view.html index 68bb7a3..deb7ae5 100644 --- a/templates/identity/view.html +++ b/templates/identity/view.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load static %} {% block title %}{{ identity }}{% endblock %} @@ -6,6 +7,8 @@

    {% if identity.icon_uri %} + {% else %} + {% endif %} {{ identity }} {{ identity.handle }}

    diff --git a/users/views/identity.py b/users/views/identity.py index 9f2a7f9..fff521b 100644 --- a/users/views/identity.py +++ b/users/views/identity.py @@ -1,3 +1,5 @@ +import string + from django import forms from django.conf import settings from django.contrib.auth.decorators import login_required @@ -36,6 +38,20 @@ class SelectIdentity(TemplateView): } +@method_decorator(login_required, name="dispatch") +class ActivateIdentity(View): + def get(self, request, handle): + identity = by_handle_or_404(request, handle) + if not identity.users.filter(pk=request.user.pk).exists(): + raise Http404() + request.session["identity_id"] = identity.id + # Get next URL, not allowing offsite links + next = request.GET.get("next") or "/" + if ":" in next: + next = "/" + return redirect("/") + + @method_decorator(login_required, name="dispatch") class CreateIdentity(FormView): @@ -50,10 +66,16 @@ class CreateIdentity(FormView): def clean_handle(self): # Remove any leading @ value = self.cleaned_data["handle"].lstrip("@") + # Validate it's all ascii characters + for character in value: + if character not in string.ascii_letters + string.digits + "_-": + raise forms.ValidationError( + "Only the letters a-z, numbers 0-9, dashes and underscores are allowed." + ) # Don't allow custom domains here quite yet if "@" in value: raise forms.ValidationError( - "You are not allowed an @ sign in your handle" + "You are not allowed an @ sign in your handle." ) # Ensure there is a domain on the end if "@" not in value: