From 2154e6f02252576d8652e66f26fa4ae635d0f8ee Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Thu, 17 Nov 2022 17:43:00 -0700 Subject: [PATCH] Rework UI to have vertical menus --- activities/views/timelines.py | 6 +- core/models/config.py | 1 + static/css/style.css | 137 ++++++++++++++---- templates/activities/_home_menu.html | 29 +++- templates/activities/compose.html | 13 +- templates/activities/federated.html | 20 +-- templates/activities/home.html | 49 ++----- templates/activities/local.html | 20 +-- templates/activities/notifications.html | 21 +-- templates/admin/_menu.html | 6 - templates/admin/domain_create.html | 20 +-- templates/admin/domain_delete.html | 7 +- templates/admin/domain_edit.html | 19 ++- templates/admin/domains.html | 7 +- templates/admin/identities.html | 15 +- templates/admin/settings.html | 18 --- templates/admin/users.html | 15 +- templates/base.html | 21 ++- templates/forms/_field.html | 25 ++-- .../{_identity_menu.html => _menu.html} | 0 templates/identity/base.html | 7 + templates/identity/create.html | 12 +- templates/identity/select.html | 10 +- templates/settings/_menu.html | 29 +++- templates/settings/base.html | 7 + templates/settings/profile.html | 22 +-- templates/settings/settings.html | 16 +- users/views/admin.py | 10 +- users/views/settings.py | 28 +++- 29 files changed, 344 insertions(+), 246 deletions(-) delete mode 100644 templates/admin/_menu.html delete mode 100644 templates/admin/settings.html rename templates/identity/{_identity_menu.html => _menu.html} (100%) create mode 100644 templates/identity/base.html create mode 100644 templates/settings/base.html diff --git a/activities/views/timelines.py b/activities/views/timelines.py index ae01a45..02afc2c 100644 --- a/activities/views/timelines.py +++ b/activities/views/timelines.py @@ -40,7 +40,7 @@ class Home(FormView): ) .select_related("subject_post", "subject_post__author") .prefetch_related("subject_post__attachments") - .order_by("-created")[:100] + .order_by("-created")[:50] ) context["interactions"] = PostInteraction.get_event_interactions( context["events"], self.request.identity @@ -68,7 +68,7 @@ class Local(TemplateView): Post.objects.filter(visibility=Post.Visibilities.public, author__local=True) .select_related("author") .prefetch_related("attachments") - .order_by("-created")[:100] + .order_by("-created")[:50] ) context["current_page"] = "local" return context @@ -85,7 +85,7 @@ class Federated(TemplateView): Post.objects.filter(visibility=Post.Visibilities.public) .select_related("author") .prefetch_related("attachments") - .order_by("-created")[:100] + .order_by("-created")[:50] ) context["current_page"] = "federated" return context diff --git a/core/models/config.py b/core/models/config.py index 8a2e40b..19ac85d 100644 --- a/core/models/config.py +++ b/core/models/config.py @@ -100,6 +100,7 @@ class Config(models.Model): site_name: str = "takahē" highlight_color: str = "#449c8c" + post_length: int = 500 identity_max_age: int = 24 * 60 * 60 class UserOptions(pydantic.BaseModel): diff --git a/static/css/style.css b/static/css/style.css index b3495b5..fba7f97 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -16,6 +16,7 @@ figure, blockquote, dl, dd, +fieldset, menu { margin: 0; padding: 0; @@ -166,6 +167,9 @@ header menu a.identity { border-right: 0; text-align: right; padding-right: 10px; + background: var(--color-bg-menu); + border-radius: 0 5px 0 0; + width: 250px; } header menu a i { @@ -188,26 +192,47 @@ header menu a small { } nav { - display: flex; - height: 40px; - background: var(--color-bg-menu); + padding: 10px 10px 20px 0; +} + +nav h3 { + text-transform: uppercase; + font-weight: bold; + font-size: 90%; + padding: 15px 18px 7px 16px; +} + +nav h3:first-child { + padding-top: 0; } nav a { display: block; color: var(--color-text-dull); - text-transform: uppercase; - font-weight: bold; - padding: 9px 18px 9px 18px; + padding: 7px 18px 7px 13px; + border-left: 3px solid transparent; } nav a.selected { color: var(--color-text-main); - border-bottom: 3px solid var(--color-highlight); + background: var(--color-bg-main); + border-radius: 0 5px 5px 0; } nav a:hover { color: var(--color-text-main); + border-left: 3px solid var(--color-highlight); +} + +nav a.selected:hover { + border-left: 3px solid transparent; +} + +nav a i { + width: 20px; + text-align: center; + margin-right: 4px; + display: inline-block; } /* Left-right columns */ @@ -225,6 +250,7 @@ nav a:hover { .right-column { width: 250px; background: var(--color-bg-menu); + border-radius: 0 0 5px 0; } .right-column h2 { @@ -237,22 +263,16 @@ nav a:hover { /* Icon menus */ -.icon-menu { - display: flex; - flex-wrap: wrap; - padding: 30px 0 0 30px; -} +.icon-menu {} .icon-menu>a { - margin: 0px 40px 40px 0; + display: block; + margin: 0px 0 20px 0; background: var(--color-bg-box); box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1); - width: 370px; - height: 100px; - line-height: 100px; color: inherit; text-decoration: none; - padding: 0 20px; + padding: 10px 20px; border: 2px solid rgba(255, 255, 255, 0); border-radius: 3px; } @@ -291,8 +311,21 @@ nav a:hover { /* Forms */ -form { - padding: 20px 40px 20px 30px; +fieldset { + border: 0; + background: var(--color-bg-box); + box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1); + margin: 25px 0 45px 0; + padding: 5px 15px; +} + +fieldset legend { + position: relative; + top: -15px; + left: -15px; + font-weight: bold; + text-transform: uppercase; + color: var(--color-text-dull); } .right-column form, @@ -316,10 +349,16 @@ form p { } form .field { - margin: 25px 0 25px 0; - background: var(--color-bg-box); - box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1); - padding: 10px 10px; + margin: 0 0 25px 0; + display: flex; +} + +form .field:last-of-type { + margin-bottom: 10px; +} + +form .field .label-input { + flex-grow: 1; } .right-column form .field { @@ -334,6 +373,7 @@ form label { text-transform: uppercase; font-size: 100%; font-weight: bold; + margin: 0 0 5px 0; } form label small { @@ -349,7 +389,7 @@ form label small { form .help { color: var(--color-text-dull); font-size: 90%; - margin: 2px 0 6px 0; + margin: -5px 0 5px 0; } form .errorlist { @@ -422,9 +462,16 @@ form input[type=submit]:hover { background: var(--color-button-main-hover); } +form img.preview { + max-height: 100%; + max-width: 100px; + margin: 0 0 0 20px; + align-self: center; +} + form .buttons { text-align: right; - margin: 25px 0 15px 0; + margin: -20px 0 15px 0; } .right-column form .buttons { @@ -459,6 +506,12 @@ form .button.toggle { background: var(--color-bg-main); } +form button.left, +form .button.left { + float: left; + margin: 0 5px 0 0; +} + form button.toggle.enabled, form .button.toggle.enabled { background: var(--color-highlight); @@ -661,3 +714,37 @@ h1.identity small { font-size: 20px; } } + + +@media (max-width: 700px) { + header menu a.identity { + width: 50px; + padding: 10px 10px 0 0; + } + + .right-column { + width: 50px; + } + + .right-column nav { + padding-right: 0; + } + + .right-column nav a { + font-size: 0; + padding: 10px 0 10px 10px; + } + + .right-column nav a i { + font-size: 22px; + } + + .right-column h3 { + visibility: hidden; + } + + .right-column h2, + .right-column .compose { + display: none; + } +} diff --git a/templates/activities/_home_menu.html b/templates/activities/_home_menu.html index c88a1d7..db441a2 100644 --- a/templates/activities/_home_menu.html +++ b/templates/activities/_home_menu.html @@ -1,6 +1,27 @@ + +{% if current_page == "home" %} +

Compose

+
+ {% csrf_token %} + {{ form.text }} + {{ form.content_warning }} +
+ CW + +
+
+{% endif %} diff --git a/templates/activities/compose.html b/templates/activities/compose.html index dfa6d1e..55b4eb3 100644 --- a/templates/activities/compose.html +++ b/templates/activities/compose.html @@ -3,15 +3,14 @@ {% block title %}Compose{% endblock %} {% block content %} - -
{% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} - {% endfor %} +
+ Content + {% include "forms/_field.html" with field=form.text %} + {% include "forms/_field.html" with field=form.content_warning %} + {% include "forms/_field.html" with field=form.visibility %} +
diff --git a/templates/activities/federated.html b/templates/activities/federated.html index b6143c3..4b57b9d 100644 --- a/templates/activities/federated.html +++ b/templates/activities/federated.html @@ -3,19 +3,9 @@ {% block title %}Federated Timeline{% endblock %} {% block content %} - {% include "activities/_home_menu.html" %} - -
-
- {% for post in posts %} - {% include "activities/_post.html" %} - {% empty %} - No posts yet. - {% endfor %} -
-
-

?

-
- -
+ {% for post in posts %} + {% include "activities/_post.html" %} + {% empty %} + No posts yet. + {% endfor %} {% endblock %} diff --git a/templates/activities/home.html b/templates/activities/home.html index 08e338e..5171842 100644 --- a/templates/activities/home.html +++ b/templates/activities/home.html @@ -3,39 +3,18 @@ {% block title %}Home{% endblock %} {% block content %} - {% include "activities/_home_menu.html" %} - -
- -
- {% for event in events %} - {% if event.type == "post" %} - {% include "activities/_post.html" with post=event.subject_post %} - {% elif event.type == "boost" %} - - {% include "activities/_post.html" with post=event.subject_post %} - {% endif %} - {% empty %} - Nothing to show yet. - {% endfor %} -
- -
-

Compose

- - {% csrf_token %} - {{ form.text }} - {{ form.content_warning }} -
- CW - -
- -
- -
+ {% for event in events %} + {% if event.type == "post" %} + {% include "activities/_post.html" with post=event.subject_post %} + {% elif event.type == "boost" %} +
+ + {{ event.subject_identity.name_or_handle }} + boosted +
+ {% include "activities/_post.html" with post=event.subject_post %} + {% endif %} + {% empty %} + Nothing to show yet. + {% endfor %} {% endblock %} diff --git a/templates/activities/local.html b/templates/activities/local.html index 520a0ce..79ce9a3 100644 --- a/templates/activities/local.html +++ b/templates/activities/local.html @@ -3,19 +3,9 @@ {% block title %}Local Timeline{% endblock %} {% block content %} - {% include "activities/_home_menu.html" %} - -
-
- {% for post in posts %} - {% include "activities/_post.html" %} - {% empty %} - No posts yet. - {% endfor %} -
-
-

?

-
- -
+ {% for post in posts %} + {% include "activities/_post.html" %} + {% empty %} + No posts yet. + {% endfor %} {% endblock %} diff --git a/templates/activities/notifications.html b/templates/activities/notifications.html index c071a49..9bf66bb 100644 --- a/templates/activities/notifications.html +++ b/templates/activities/notifications.html @@ -3,20 +3,9 @@ {% block title %}Notifications{% endblock %} {% block content %} - {% include "activities/_home_menu.html" %} - -
-
- {% for event in events %} - {% include "activities/_event.html" %} - {% empty %} - No events yet. - {% endfor %} -
- -
-

?

-
- -
+ {% for event in events %} + {% include "activities/_event.html" %} + {% empty %} + No events yet. + {% endfor %} {% endblock %} diff --git a/templates/admin/_menu.html b/templates/admin/_menu.html deleted file mode 100644 index 8f0bc60..0000000 --- a/templates/admin/_menu.html +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/templates/admin/domain_create.html b/templates/admin/domain_create.html index 09dbc23..dcc57fa 100644 --- a/templates/admin/domain_create.html +++ b/templates/admin/domain_create.html @@ -1,11 +1,8 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} {% block title %}Add Domain - Admin{% endblock %} {% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %}

Add A Domain

@@ -28,12 +25,17 @@ service domain.

{% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} - {% endfor %} +
+ Domain Details + {% include "forms/_field.html" with field=form.domain %} + {% include "forms/_field.html" with field=form.service_domain %} +
+
+ Access Control + {% include "forms/_field.html" with field=form.public %} +
- Delete - +
{% endblock %} diff --git a/templates/admin/domain_delete.html b/templates/admin/domain_delete.html index d47a673..5d077a5 100644 --- a/templates/admin/domain_delete.html +++ b/templates/admin/domain_delete.html @@ -1,12 +1,8 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} {% block title %}Delete {{ domain.domain }} - Admin{% endblock %} {% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %} -
{% csrf_token %} @@ -28,6 +24,5 @@ {% endif %} -
{% endblock %} diff --git a/templates/admin/domain_edit.html b/templates/admin/domain_edit.html index 64e195c..59bb8a2 100644 --- a/templates/admin/domain_edit.html +++ b/templates/admin/domain_edit.html @@ -1,16 +1,19 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} -{% block title %}{{ domain.domain }} - Admin{% endblock %} +{% block subtitle %}{{ domain.domain }}{% endblock %} {% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %}
{% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} - {% endfor %} +
+ Domain Details + {% include "forms/_field.html" with field=form.domain %} + {% include "forms/_field.html" with field=form.service_domain %} +
+
+ Access Control + {% include "forms/_field.html" with field=form.public %} +
Delete diff --git a/templates/admin/domains.html b/templates/admin/domains.html index b7925da..bb7d8e4 100644 --- a/templates/admin/domains.html +++ b/templates/admin/domains.html @@ -1,11 +1,8 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} -{% block title %}{{ section.title }} - Admin{% endblock %} +{% block subtitle %}Domains{% endblock %} {% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %}
{% for domain in domains %} diff --git a/templates/admin/identities.html b/templates/admin/identities.html index 86e70db..556e915 100644 --- a/templates/admin/identities.html +++ b/templates/admin/identities.html @@ -1,14 +1,9 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} -{% block title %}Identities - Admin{% endblock %} +{% block subtitle %}Identities{% endblock %} {% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %} - -

- Please use the Django Admin for now. -

- +

+ Please use the Django Admin for now. +

{% endblock %} diff --git a/templates/admin/settings.html b/templates/admin/settings.html deleted file mode 100644 index e031347..0000000 --- a/templates/admin/settings.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "base.html" %} - -{% block title %}{{ section.title }} - Admin{% endblock %} - -{% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %} -
- {% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} - {% endfor %} -
- -
-
-{% endblock %} diff --git a/templates/admin/users.html b/templates/admin/users.html index 0b75b88..f2dc864 100644 --- a/templates/admin/users.html +++ b/templates/admin/users.html @@ -1,14 +1,9 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} -{% block title %}Users - Admin{% endblock %} +{% block subtitle %}Users{% endblock %} {% block content %} - {% block menu %} - {% include "admin/_menu.html" %} - {% endblock %} -
-

- Please use the Django Admin for now. -

-
+

+ Please use the Django Admin for now. +

{% endblock %} diff --git a/templates/base.html b/templates/base.html index 616d5b6..31bbc7b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -31,14 +31,12 @@ Compose + + Search + Settings - {% if request.user.admin %} - - Admin - - {% endif %}
{% if not request.identity %} @@ -61,7 +59,18 @@ - {% block content %} + {% block full_content %} +
+
+ {% block content %} + {% endblock %} +
+
+ {% block right_content %} + {% include "activities/_home_menu.html" %} + {% endblock %} +
+
{% endblock %} diff --git a/templates/forms/_field.html b/templates/forms/_field.html index 740432d..595546d 100644 --- a/templates/forms/_field.html +++ b/templates/forms/_field.html @@ -1,13 +1,18 @@
- - {% if field.help_text %} -

- {{ field.help_text|linebreaksbr }} -

+
+ + {% if field.help_text %} +

+ {{ field.help_text|linebreaksbr }} +

+ {% endif %} + {{ field.errors }} + {{ field }} +
+ {% if preview %} + {% endif %} - {{ field.errors }} - {{ field }}
diff --git a/templates/identity/_identity_menu.html b/templates/identity/_menu.html similarity index 100% rename from templates/identity/_identity_menu.html rename to templates/identity/_menu.html diff --git a/templates/identity/base.html b/templates/identity/base.html new file mode 100644 index 0000000..baff37f --- /dev/null +++ b/templates/identity/base.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block title %}{% block subtitle %}{% endblock %} - Settings{% endblock %} + +{% block right_content %} + {% include "identity/_menu.html" %} +{% endblock %} diff --git a/templates/identity/create.html b/templates/identity/create.html index c69b55f..fbdd66c 100644 --- a/templates/identity/create.html +++ b/templates/identity/create.html @@ -1,17 +1,19 @@ -{% extends "base.html" %} +{% extends "identity/base.html" %} {% block title %}Create Identity{% endblock %} {% block content %} - {% include "identity/_identity_menu.html" %}

Create New Identity

You can have multiple identities - they are totally separate, and share nothing apart from your login details. Use them for alternates, projects, and more.

{% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} - {% endfor %} +
+ Identity Details + {% include "forms/_field.html" with field=form.username %} + {% include "forms/_field.html" with field=form.domain %} + {% include "forms/_field.html" with field=form.name %} +
diff --git a/templates/identity/select.html b/templates/identity/select.html index d9959ab..c4fb569 100644 --- a/templates/identity/select.html +++ b/templates/identity/select.html @@ -1,18 +1,12 @@ -{% extends "base.html" %} -{% load static %} +{% extends "identity/base.html" %} {% block title %}Select Identity{% endblock %} {% block content %} - {% include "identity/_identity_menu.html" %}
{% for identity in identities %} - {% if identity.icon_uri %} - - {% else %} - - {% endif %} + {{ identity.name_or_handle }} @{{ identity.handle }} diff --git a/templates/settings/_menu.html b/templates/settings/_menu.html index 4f71651..e2dc70b 100644 --- a/templates/settings/_menu.html +++ b/templates/settings/_menu.html @@ -1,5 +1,28 @@ diff --git a/templates/settings/base.html b/templates/settings/base.html new file mode 100644 index 0000000..d5efa69 --- /dev/null +++ b/templates/settings/base.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block title %}{% block subtitle %}{% endblock %} - Settings{% endblock %} + +{% block right_content %} + {% include "settings/_menu.html" %} +{% endblock %} diff --git a/templates/settings/profile.html b/templates/settings/profile.html index 1a7c29f..5c00557 100644 --- a/templates/settings/profile.html +++ b/templates/settings/profile.html @@ -1,18 +1,22 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} -{% block title %}Profile - Settings{% endblock %} +{% block subtitle %}Profile{% endblock %} {% block content %} - {% block menu %} - {% include "settings/_menu.html" %} - {% endblock %} {% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} - {% endfor %} +
+ Details + {% include "forms/_field.html" with field=form.name %} + {% include "forms/_field.html" with field=form.summary %} +
+
+ Images + {% include "forms/_field.html" with field=form.icon preview=request.identity.icon.url %} + {% include "forms/_field.html" with field=form.image preview=request.identity.image.url %} +
diff --git a/templates/settings/settings.html b/templates/settings/settings.html index 016eebb..a933627 100644 --- a/templates/settings/settings.html +++ b/templates/settings/settings.html @@ -1,15 +1,17 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} -{% block title %}{{ section.title }} - Settings{% endblock %} +{% block subtitle %}{{ section.title }}{% endblock %} {% block content %} - {% block menu %} - {% include "settings/_menu.html" %} - {% endblock %}
{% csrf_token %} - {% for field in form %} - {% include "forms/_field.html" %} + {% for title, fields in fieldsets.items %} +
+ {{ title }} + {% for field in fields %} + {% include "forms/_field.html" %} + {% endfor %} +
{% endfor %}
diff --git a/users/views/admin.py b/users/views/admin.py index 165572c..9476417 100644 --- a/users/views/admin.py +++ b/users/views/admin.py @@ -24,7 +24,6 @@ class AdminSettingsPage(SettingsPage): at the bottom of the page. Don't add this to a URL directly - subclass! """ - template_name = "admin/settings.html" options_class = Config.SystemOptions def load_config(self): @@ -47,6 +46,15 @@ class BasicPage(AdminSettingsPage): "title": "Highlight Color", "help_text": "Used for logo background and other highlights", }, + "post_length": { + "title": "Maximum Post Length", + "help_text": "The maximum number of characters allowed per post", + }, + } + + layout = { + "Branding": ["site_name", "highlight_color"], + "Posts": ["post_length"], } diff --git a/users/views/settings.py b/users/views/settings.py index c3c166b..88e4cd3 100644 --- a/users/views/settings.py +++ b/users/views/settings.py @@ -1,5 +1,5 @@ from functools import partial -from typing import ClassVar, Dict +from typing import ClassVar, Dict, List from django import forms from django.shortcuts import redirect @@ -27,6 +27,7 @@ class SettingsPage(FormView): template_name = "settings/settings.html" section: ClassVar[str] options: Dict[str, Dict[str, str]] + layout: Dict[str, List[str]] def get_form_class(self): # Create the fields dict from the config object @@ -42,6 +43,8 @@ class SettingsPage(FormView): ) elif config_field.type_ is str: form_field = forms.CharField + elif config_field.type_ is int: + form_field = forms.IntegerField else: raise ValueError(f"Cannot render settings type {config_field.type_}") fields[key] = form_field( @@ -68,6 +71,10 @@ class SettingsPage(FormView): def get_context_data(self): context = super().get_context_data() context["section"] = self.section + # Gather fields into fieldsets + context["fieldsets"] = {} + for title, fields in self.layout.items(): + context["fieldsets"][title] = [context["form"][field] for field in fields] return context def form_valid(self, form): @@ -87,10 +94,12 @@ class InterfacePage(SettingsPage): options = { "toot_mode": { "title": "I Will Toot As I Please", - "help_text": "If enabled, changes all 'Post' buttons to 'Toot!'", + "help_text": "Changes all 'Post' buttons to 'Toot!'", } } + layout = {"Posting": ["toot_mode"]} + @method_decorator(identity_required, name="dispatch") class ProfilePage(FormView): @@ -102,9 +111,18 @@ class ProfilePage(FormView): class form_class(forms.Form): name = forms.CharField(max_length=500) - summary = forms.CharField(widget=forms.Textarea, required=False) - icon = forms.ImageField(required=False) - image = forms.ImageField(required=False) + summary = forms.CharField( + widget=forms.Textarea, + required=False, + help_text="Describe you and your interests", + label="Bio", + ) + icon = forms.ImageField( + required=False, help_text="Shown next to all your posts and activities" + ) + image = forms.ImageField( + required=False, help_text="Shown at the top of your profile" + ) def get_initial(self): return {