diff --git a/nonpacks/announcements/migrations/0002_alter_announcementcomment_created_at_and_more.py b/nonpacks/announcements/migrations/0002_alter_announcementcomment_created_at_and_more.py new file mode 100644 index 0000000..a5c2daf --- /dev/null +++ b/nonpacks/announcements/migrations/0002_alter_announcementcomment_created_at_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 6.0.3 on 2026-08-05 20:54 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('announcements', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='announcementcomment', + name='created_at', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AlterField( + model_name='announcementcomment', + name='updated_at', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/nonpacks/announcements/models.py b/nonpacks/announcements/models.py index 9720a16..8e0e7b8 100644 --- a/nonpacks/announcements/models.py +++ b/nonpacks/announcements/models.py @@ -1,5 +1,6 @@ from django.conf import settings from django.db import models +from django.utils import timezone from library.models import Project @@ -63,12 +64,21 @@ class AnnouncementComment(models.Model): related_name='announcement_comments', ) body = models.TextField() - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) + created_at = models.DateTimeField(default=timezone.now) + updated_at = models.DateTimeField(default=timezone.now) class Meta: ordering = ['created_at', 'pk'] + def save(self, *args, **kwargs): + if self._state.adding: + now = timezone.now() + self.created_at = now + self.updated_at = now + else: + self.updated_at = timezone.now() + super().save(*args, **kwargs) + def __str__(self): return f'{self.user.username}: {self.body[:40]}' diff --git a/nonpacks/library/migrations/0014_alter_comment_created_at_alter_comment_updated_at.py b/nonpacks/library/migrations/0014_alter_comment_created_at_alter_comment_updated_at.py new file mode 100644 index 0000000..8a985fb --- /dev/null +++ b/nonpacks/library/migrations/0014_alter_comment_created_at_alter_comment_updated_at.py @@ -0,0 +1,24 @@ +# Generated by Django 6.0.3 on 2026-08-05 20:54 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('library', '0013_project_rating_count_project_rating_score_comment_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='comment', + name='created_at', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + migrations.AlterField( + model_name='comment', + name='updated_at', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/nonpacks/library/models.py b/nonpacks/library/models.py index d9a647d..9f65d4f 100644 --- a/nonpacks/library/models.py +++ b/nonpacks/library/models.py @@ -4,6 +4,7 @@ import uuid from django.conf import settings from django.db import models from django.urls import reverse +from django.utils import timezone def slugify_tag(value): @@ -374,8 +375,17 @@ class Comment(models.Model): settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='comments', ) body = models.TextField() - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) + created_at = models.DateTimeField(default=timezone.now) + updated_at = models.DateTimeField(default=timezone.now) + + def save(self, *args, **kwargs): + if self._state.adding: + now = timezone.now() + self.created_at = now + self.updated_at = now + else: + self.updated_at = timezone.now() + super().save(*args, **kwargs) def __str__(self): return f'{self.user.username} on {self.project.slug}: {self.body[:40]}' diff --git a/nonpacks/library/views.py b/nonpacks/library/views.py index 7a6b614..c2b4bb3 100644 --- a/nonpacks/library/views.py +++ b/nonpacks/library/views.py @@ -297,8 +297,10 @@ def browse(request): if not tags: continue items = [] + has_active = False for tag in tags: active = tag.name in tag_names + has_active = has_active or active if active: remaining = [t for t in tag_names if t != tag.name] url = f'?{_qs(tag=remaining)}' @@ -311,7 +313,7 @@ def browse(request): 'active': active, 'url': url, }) - tag_groups.append({'category': cat, 'items': items}) + tag_groups.append({'category': cat, 'items': items, 'has_active': has_active}) paginator = Paginator(projects, 12) page_obj = paginator.get_page(request.GET.get('page')) diff --git a/nonpacks/static/css/style.css b/nonpacks/static/css/style.css index f7f0258..b246a0a 100644 --- a/nonpacks/static/css/style.css +++ b/nonpacks/static/css/style.css @@ -2054,6 +2054,31 @@ a.deletelink { margin-top: 0; font-size: 0.95rem; } +.filter-group-toggle { + position: relative; + width: 100%; display: flex; align-items: center; gap: 6px; + background: none; border: none; color: inherit; cursor: pointer; + font-size: 0.95rem; font-weight: 600; padding: 4px 0; text-align: left; +} +.filter-group-toggle::before { + content: ''; + position: absolute; + inset: 2px -16px; + border-radius: 8px; + background: transparent; + pointer-events: none; +} +.filter-group-toggle:hover, +.filter-group-toggle:focus-visible { + background: transparent; +} +.filter-group-toggle:hover::before, +.filter-group-toggle:focus-visible::before { + background: rgba(255, 255, 255, 0.07); +} +.filter-chevron { margin-left: auto; transition: transform 0.2s ease; } +.filter-group-toggle[aria-expanded="true"] .filter-chevron { transform: rotate(180deg); } +.filter-tags.collapsed { display: none; } .filter-category { display: flex; flex-direction: column; @@ -3797,7 +3822,7 @@ a.deletelink { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--md-sys-color-on-surface, #cdd6f4); } -.announce-item.announce-unread { outline: 1px solid var(--md-sys-color-primary, #89b4fa); } +.announce-item.announce-unread a { color: var(--ctp-mocha-blue, #1e66f5); font-weight: 600; } .announce-meta { color: var(--md-sys-color-on-surface-variant, #a6adc8); font-size: 0.68rem; white-space: nowrap; flex-shrink: 0; @@ -3837,11 +3862,11 @@ a.deletelink { background: var(--md-sys-color-surface, #1e1e2e); color: var(--md-sys-color-on-surface, #cdd6f4); font-family: inherit; } -.notify-list { list-style: none; margin: 0; padding: 0; } +.notify-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; } .notify-item { - padding: 0.6rem 0.5rem; border-bottom: 1px solid var(--md-sys-color-outline-variant, #45475a); - font-size: 0.85rem; + padding: 0.55rem 0.6rem; border-radius: 8px; font-size: 0.85rem; + background: var(--md-sys-color-surface-variant, #45475a); } -.notify-item:last-child { border-bottom: none; } -.notify-item.notify-unread { background: var(--md-sys-color-surface-variant, #45475a); border-radius: 8px; } +.notify-item a { color: var(--md-sys-color-on-surface, #cdd6f4); } +.notify-item.notify-unread a { color: var(--ctp-mocha-blue, #1e66f5); font-weight: 600; } .notify-new { color: var(--ctp-mocha-red); font-weight: 600; } diff --git a/nonpacks/templates/base.html b/nonpacks/templates/base.html index 696c2fd..20fb5a0 100644 --- a/nonpacks/templates/base.html +++ b/nonpacks/templates/base.html @@ -48,6 +48,11 @@ Announcements + {% if user.is_authenticated %} + + Upload + + {% endif %} {% endif %} @@ -146,6 +151,21 @@ {% endif %} {% endif %} + {% block extra_js %}{% endblock %} \ No newline at end of file diff --git a/nonpacks/templates/library/browse.html b/nonpacks/templates/library/browse.html index b8f537b..9a26fec 100644 --- a/nonpacks/templates/library/browse.html +++ b/nonpacks/templates/library/browse.html @@ -26,12 +26,13 @@ {% for group in tag_groups %} -
-

+
+

-
+ + +
{% for item in group.items %} @@ -89,3 +90,17 @@
{% endblock %} + +{% block extra_js %} + +{% endblock %}