Implement Web Assets' theme system and selection, and add 'light' theme #118

Merged
Márton Lente merged 97 commits from martonlente/extensions-website:ui/theme-light into main 2024-05-08 14:20:07 +02:00
14 changed files with 87 additions and 58 deletions
Showing only changes of commit 9e11c79a3d - Show all commits

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.11 on 2024-05-06 13:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('abuse', '0006_remove_abusereport_date_deleted'),
]
operations = [
migrations.AlterField(
model_name='abusereport',
name='status',
field=models.PositiveSmallIntegerField(choices=[(1, 'Untriaged'), (2, 'Confirmed'), (3, 'Resolved')], default=1),
),
]

View File

@ -29,8 +29,8 @@ class AbuseReport(CreatedModifiedMixin, TrackChangesMixin, models.Model):
STATUSES = Choices( STATUSES = Choices(
('UNTRIAGED', 1, 'Untriaged'), ('UNTRIAGED', 1, 'Untriaged'),
('VALID', 2, 'Valid'), ('CONFIRMED', 2, 'Confirmed'),
('SUSPICIOUS', 3, 'Suspicious'), ('RESOLVED', 3, 'Resolved'),
) )
# NULL if the reporter is anonymous. # NULL if the reporter is anonymous.

@ -1 +1 @@
Subproject commit 17202dce8fa90182ccdb891fc23ca04efea782b3 Subproject commit 1126f102d8542ffb76af0269854048f276d9e50b

View File

@ -263,8 +263,6 @@
+margin(3, left) +margin(3, left)
details details
padding: 0
&[open] &[open]
.show-on-collapse .show-on-collapse
display: none display: none

View File

@ -1,4 +1,7 @@
/* Aliases to use existing icons as permission slugs. */ /* Aliases to use existing icons as permission slugs. */
.i-permission-clipboard
@extend .i-copy
.i-permission-files .i-permission-files
@extend .i-folder @extend .i-folder

View File

@ -9,6 +9,11 @@
--nav-global-spacer-sm: var(--spacer-2) --nav-global-spacer-sm: var(--spacer-2)
--nav-global-spacer-xs: var(--spacer-1) --nav-global-spacer-xs: var(--spacer-1)
.btn
&:hover
background-color: var(--nav-global-color-button-bg-hover)
color: var(--nav-global-color-text-hover) !important
.btn-primary .btn-primary
color: var(--color-accent) !important color: var(--color-accent) !important

View File

@ -126,7 +126,7 @@
</li> </li>
{% block nav-upload %} {% block nav-upload %}
<li class="me-2"> <li>
<a href="{% url 'extensions:submit' %}" class="btn btn-primary"> <a href="{% url 'extensions:submit' %}" class="btn btn-primary">
<i class="i-upload"></i> <i class="i-upload"></i>
<span>Upload Extension</span> <span>Upload Extension</span>
@ -135,11 +135,13 @@
{% endblock nav-upload %} {% endblock nav-upload %}
{% if user.is_authenticated %} {% if user.is_authenticated %}
<a href="{% url 'notifications:notifications' %}"> <li>
<a class="btn btn-link px-2" href="{% url 'notifications:notifications' %}">
<i class="i-bell {% if user|unread_notification_count %}text-accent{% endif %}"></i> <i class="i-bell {% if user|unread_notification_count %}text-accent{% endif %}"></i>
</a> </a>
</li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<button id="navbarDropdown" aria-expanded="false" aria-haspopup="true" data-toggle-menu-id="nav-account-dropdown" role="button" class="nav-link dropdown-toggle js-dropdown-toggle"> <button id="navbarDropdown" aria-expanded="false" aria-haspopup="true" data-toggle-menu-id="nav-account-dropdown" role="button" class="nav-link dropdown-toggle js-dropdown-toggle pe-3 px-2">
<i class="i-user"></i> <i class="i-user"></i>
<i class="i-chevron-down"></i> <i class="i-chevron-down"></i>
</button> </button>
@ -202,7 +204,10 @@
</ul> </ul>
</li> </li>
{% elif page_id != 'login' and page_id != 'register' %} {% elif page_id != 'login' and page_id != 'register' %}
{% include "common/components/nav_item.html" with name="oauth:login" title="Sign in" %} <a href="{% url 'oauth:login' %}" class="btn btn-link">
<i class="i-log-in"></i>
<span>{% trans "Sign in" %}</span>
</a>
{% endif %} {% endif %}
<li> <li>

View File

@ -29,17 +29,17 @@
<span>{{ status }}</span> <span>{{ status }}</span>
</div> </div>
{% elif 'untriaged' in status.lower %} {% elif 'confirmed' in status.lower %}
<div class="badge badge-danger {{ class }}"> <div class="badge badge-danger {{ class }}">
<span>{{ status }}</span> <span>{{ status }}</span>
</div> </div>
{% elif 'suspicious' in status.lower %} {% elif 'untriaged' in status.lower %}
<div class="badge badge-warning {{ class }}"> <div class="badge badge-warning {{ class }}">
<span>{{ status }}</span> <span>{{ status }}</span>
</div> </div>
{% elif 'valid' in status.lower %} {% elif 'resolved' in status.lower %}
<div class="badge badge-success {{ class }}"> <div class="badge badge-success {{ class }}">
<span>{{ status }}</span> <span>{{ status }}</span>
</div> </div>

View File

@ -202,8 +202,13 @@ class TagAdmin(admin.ModelAdmin):
return () return ()
class VersionPermissionAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
admin.site.register(models.Extension, ExtensionAdmin) admin.site.register(models.Extension, ExtensionAdmin)
admin.site.register(models.Version, VersionAdmin) admin.site.register(models.Version, VersionAdmin)
admin.site.register(models.Maintainer, MaintainerAdmin) admin.site.register(models.Maintainer, MaintainerAdmin)
admin.site.register(models.License, LicenseAdmin) admin.site.register(models.License, LicenseAdmin)
admin.site.register(models.Tag, TagAdmin) admin.site.register(models.Tag, TagAdmin)
admin.site.register(models.VersionPermission, VersionPermissionAdmin)

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.11 on 2024-05-06 12:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('extensions', '0027_unique_preview_files'),
]
operations = [
migrations.AlterField(
model_name='license',
name='slug',
field=models.SlugField(help_text='Should be taken from https://spdx.org/licenses/', unique=True),
),
migrations.AlterField(
model_name='versionpermission',
name='slug',
field=models.SlugField(help_text='Permissions add-ons are expected to need.', unique=True),
),
]

View File

@ -19,8 +19,6 @@ from constants.base import (
EXTENSION_TYPE_SLUGS, EXTENSION_TYPE_SLUGS,
FILE_STATUS_CHOICES, FILE_STATUS_CHOICES,
) )
from constants.licenses import ALL_LICENSES
from constants.version_permissions import ALL_VERSION_PERMISSIONS
import common.help_texts import common.help_texts
import extensions.fields import extensions.fields
@ -90,22 +88,13 @@ class License(CreatedModifiedMixin, models.Model):
blank=False, blank=False,
null=False, null=False,
help_text='Should be taken from https://spdx.org/licenses/', help_text='Should be taken from https://spdx.org/licenses/',
unique=True,
) )
url = models.URLField(blank=False, null=False) url = models.URLField(blank=False, null=False)
def __str__(self) -> str: def __str__(self) -> str:
return f'{self.name}' return f'{self.name}'
@classmethod
def generate(cls):
"""Generate License records from constants."""
licenses = [cls(id=li.id, name=li.name, slug=li.slug, url=li.url) for li in ALL_LICENSES]
cls.objects.bulk_create(licenses)
@classmethod
def get_by_name(cls, name: str):
return cls.objects.filter(name__startswith=name).first()
@classmethod @classmethod
def get_by_slug(cls, slug: str): def get_by_slug(cls, slug: str):
return cls.objects.filter(slug__startswith=slug).first() return cls.objects.filter(slug__startswith=slug).first()
@ -386,28 +375,16 @@ class VersionPermission(CreatedModifiedMixin, models.Model):
blank=False, blank=False,
null=False, null=False,
help_text='Permissions add-ons are expected to need.', help_text='Permissions add-ons are expected to need.',
unique=True,
) )
help = models.CharField(max_length=128, null=False, blank=False, unique=True) help = models.CharField(max_length=128, null=False, blank=False, unique=True)
def __str__(self) -> str: def __str__(self) -> str:
return f'{self.name}' return f'{self.name}'
@classmethod
def generate(cls):
"""Generate Permission records from constants."""
permissions = [
cls(id=li.id, name=li.name, slug=li.slug, help=li.help)
for li in ALL_VERSION_PERMISSIONS
]
cls.objects.bulk_create(permissions)
@classmethod
def get_by_name(cls, name: str):
return cls.objects.filter(name__startswith=name).first()
@classmethod @classmethod
def get_by_slug(cls, slug: str): def get_by_slug(cls, slug: str):
return cls.objects.filter(slug__startswith=slug).first() return cls.objects.get(slug=slug)
class Tag(CreatedModifiedMixin, models.Model): class Tag(CreatedModifiedMixin, models.Model):
@ -537,12 +514,7 @@ class Version(CreatedModifiedMixin, RatingMixin, TrackChangesMixin, models.Model
return return
for permission_name in _permissions: for permission_name in _permissions:
permission = VersionPermission.get_by_name(permission_name) permission = VersionPermission.get_by_slug(permission_name)
# Just ignore versions that are incompatible.
if not permission:
continue
self.permissions.add(permission) self.permissions.add(permission)
def set_initial_licenses(self, _licenses): def set_initial_licenses(self, _licenses):

View File

@ -42,7 +42,7 @@
</span> </span>
</summary> </summary>
<div class="px-4"> <div>
{{ latest.release_notes|markdown }} {{ latest.release_notes|markdown }}
</div> </div>
</details> </details>

View File

@ -42,7 +42,7 @@
<div class="row"> <div class="row">
<div class="col-md-7"> <div class="col-md-7">
<div class="px-4"> <div>
{% if version.release_notes %} {% if version.release_notes %}
<h3 class="mb-3">Changelog</h3> <h3 class="mb-3">Changelog</h3>
{{ version.release_notes|markdown }} {{ version.release_notes|markdown }}

View File

@ -54,8 +54,7 @@ class FileMIMETypeValidator:
class ExtensionIDManifestValidator: class ExtensionIDManifestValidator:
""" """Make sure the extension id is valid:
Make sure the extension id is valid:
* Extension id consists of Unicode letters, numbers or underscores. * Extension id consists of Unicode letters, numbers or underscores.
* Neither hyphens nor spaces are supported. * Neither hyphens nor spaces are supported.
* Each extension id most be unique across all extensions. * Each extension id most be unique across all extensions.
@ -307,8 +306,9 @@ class PermissionsValidator:
is_error = True is_error = True
else: else:
for permission in value: for permission in value:
if VersionPermission.get_by_slug(permission): try:
continue VersionPermission.get_by_slug(permission)
except VersionPermission.DoesNotExist:
is_error = True is_error = True
logger.info(f'Permission unavailable: {permission}') logger.info(f'Permission unavailable: {permission}')