click corner action icon to add to wishlist

This commit is contained in:
Your Name 2022-04-06 00:59:30 -04:00
parent 99724bbe0d
commit 44cd271127
23 changed files with 537 additions and 23 deletions

View file

@ -111,6 +111,10 @@ class Book(Entity):
def verbose_category_name(self):
return _("书籍")
@property
def mark_class(self):
return BookMark
class BookMark(Mark):
book = models.ForeignKey(

View file

@ -9,6 +9,7 @@ urlpatterns = [
path('update/<int:id>/', update, name='update'),
path('delete/<int:id>/', delete, name='delete'),
path('mark/', create_update_mark, name='create_update_mark'),
path('wish/<int:id>/', wish, name='wish'),
re_path('(?P<book_id>[0-9]+)/mark/list/(?:(?P<following_only>\\d+))?', retrieve_mark_list, name='retrieve_mark_list'),
path('mark/delete/<int:id>/', delete_mark, name='delete_mark'),
path('<int:book_id>/review/create/', create_review, name='create_review'),

View file

@ -2,7 +2,7 @@ import logging
from django.shortcuts import render, get_object_or_404, redirect, reverse
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseBadRequest, HttpResponseServerError
from django.http import HttpResponseBadRequest, HttpResponseServerError, HttpResponse
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import IntegrityError, transaction
from django.db.models import Count
@ -335,6 +335,26 @@ def create_update_mark(request):
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish(request, id):
if request.method == 'POST':
book = get_object_or_404(Book, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'book': book,
}
try:
BookMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_mark_list(request, book_id, following_only=False):

View file

@ -170,6 +170,10 @@ class Entity(models.Model):
def verbose_category_name(self):
raise NotImplementedError("Subclass should implement this.")
@property
def mark_class(self):
raise NotImplementedError("Subclass should implement this.")
class UserOwnedEntity(models.Model):
is_private = models.BooleanField(default=False, null=True) # first set allow null, then migration, finally (in a few days) remove for good
@ -187,7 +191,7 @@ class UserOwnedEntity(models.Model):
owner = self.owner
if owner == viewer:
return True
if owner.is_active == False:
if not owner.is_active:
return False
if self.visibility == 2:
return False
@ -233,6 +237,11 @@ class UserOwnedEntity(models.Model):
user_owned_entities = user_owned_entities.filter(visibility=0)
return user_owned_entities
@property
def item(self):
attr = re.findall(r'[A-Z](?:[a-z]+|[A-Z]*(?=[A-Z]|$))', self.__class__.__name__)[0].lower()
return getattr(self, attr)
# commonly used entity classes
###################################
@ -258,7 +267,7 @@ class Mark(UserOwnedEntity):
models.CheckConstraint(check=models.Q(
rating__lte=10), name='mark_rating_upperbound'),
]
# TODO update entity rating when save
# TODO update tags

View file

@ -14,6 +14,23 @@
vertical-align: text-bottom;
}
.entity-list__entity-img-wrapper {
position: relative;
}
.entity-list__entity-action-icon {
position: absolute;
top:0;
right:0;
mix-blend-mode: hard-light;
text-stroke: 1px black;
background-color: lightgray;
border-radius: 0 0 0 8px;
padding: 0 4px;
cursor: pointer;
}
/***** MODAL DIALOG ****/
#modal {
/* Underlay covers entire screen. */

View file

@ -21,6 +21,7 @@
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/neo.css' %}">
</head>
<body>
@ -222,7 +223,9 @@
{% endcomment %}
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
</body>

View file

@ -2,11 +2,16 @@
{% load highlight %}
{% load i18n %}
{% load l10n %}
{% load neo %}
{% current_user_marked_item book as marked %}
<li class="entity-list__entity">
<div class="entity-list__entity-img-wrapper">
<a href="{% url 'books:retrieve' book.id %}">
<img src="{{ book.cover|thumb:'normal' }}" alt="" class="entity-list__entity-img">
</a>
{% if not marked %}
<a class="entity-list__entity-action-icon" hx-post="{% url 'books:wish' book.id %}" title="加入想读"></a>
{% endif %}
</div>
<div class="entity-list__entity-text">
@ -30,9 +35,9 @@
{% else %}
{{ book.title }}
{% endif %}
</a>
{% if not request.GET.c or not request.GET.c in categories %}
{% if not request.GET.c and not hide_category %}
<span class="entity-list__entity-category">[{{book.verbose_category_name}}]</span>
{% endif %}
<a href="{{ book.source_url }}">
@ -104,7 +109,39 @@
</span>
{% endfor %}
</div>
{% if mark %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>
<div class="entity-marks" style="margin-bottom: 0;">
<ul class="entity-marks__mark-list">
<li class="entity-marks__mark">
{% if mark.rating %}
<span class="entity-marks__rating-star rating-star"
data-rating-score="{{ mark.rating | floatformat:"0" }}" style="left: -4px;"></span>
{% endif %}
{% if mark.visibility > 0 %}
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" />
</svg></span>
{% endif %}
<span class="entity-marks__mark-time">
{% trans '于' %} {{ mark.edited_time }}
{% if status == 'reviewed' %}
{% trans '评论' %}: <a href="{% url 'books:retrieve_review' mark.id %}">{{ mark.title }}</a>
{% else %}
{% trans '标记' %}
{% endif %}
</span>
{% if mark.text %}
<p class="entity-marks__mark-content">{{ mark.text }}</p>
{% endif %}
</li>
</ul>
</div>
{% endif %}
{% if collectionitem %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>

View file

@ -2,11 +2,16 @@
{% load highlight %}
{% load i18n %}
{% load l10n %}
{% load neo %}
{% current_user_marked_item game as marked %}
<li class="entity-list__entity">
<div class="entity-list__entity-img-wrapper">
<a href="{% url 'games:retrieve' game.id %}">
<img src="{{ game.cover|thumb:'normal' }}" alt="" class="entity-list__entity-img">
</a>
{% if not marked %}
<a class="entity-list__entity-action-icon" hx-post="{% url 'games:wish' game.id %}" title="加入想玩"></a>
{% endif %}
</div>
<div class="entity-list__entity-text">
{% if editable %}
@ -30,7 +35,7 @@
{% endif %}
</a>
{% if not request.GET.c or not request.GET.c in categories %}
{% if not request.GET.c and not hide_category %}
<span class="entity-list__entity-category">[{{item.verbose_category_name}}]</span>
{% endif %}
<a href="{{ game.source_url }}">
@ -83,7 +88,39 @@
</span>
{% endfor %}
</div>
{% if mark %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>
<div class="entity-marks" style="margin-bottom: 0;">
<ul class="entity-marks__mark-list">
<li class="entity-marks__mark">
{% if mark.rating %}
<span class="entity-marks__rating-star rating-star"
data-rating-score="{{ mark.rating | floatformat:"0" }}" style="left: -4px;"></span>
{% endif %}
{% if mark.visibility > 0 %}
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" />
</svg></span>
{% endif %}
<span class="entity-marks__mark-time">
{% trans '于' %} {{ mark.edited_time }}
{% if status == 'reviewed' %}
{% trans '评论' %}: <a href="{% url 'games:retrieve_review' mark.id %}">{{ mark.title }}</a>
{% else %}
{% trans '标记' %}
{% endif %}
</span>
{% if mark.text %}
<p class="entity-marks__mark-content">{{ mark.text }}</p>
{% endif %}
</li>
</ul>
</div>
{% endif %}
{% if collectionitem %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>

View file

@ -3,11 +3,16 @@
{% load i18n %}
{% load l10n %}
{% load humanize %}
{% load neo %}
{% current_user_marked_item movie as marked %}
<li class="entity-list__entity">
<div class="entity-list__entity-img-wrapper">
<a href="{% url 'movies:retrieve' movie.id %}">
<img src="{{ movie.cover|thumb:'normal' }}" alt="" class="entity-list__entity-img">
</a>
{% if not marked %}
<a class="entity-list__entity-action-icon" hx-post="{% url 'movies:wish' movie.id %}" title="加入想看"></a>
{% endif %}
</div>
<div class="entity-list__entity-text">
{% if editable %}
@ -47,7 +52,7 @@
{% endif %}
</a>
{% if not request.GET.c or not request.GET.c in categories %}
{% if not request.GET.c and not hide_category %}
<span class="entity-list__entity-category">[{{movie.verbose_category_name}}]</span>
{% endif %}
<a href="{{ movie.source_url }}">
@ -108,7 +113,39 @@
</span>
{% endfor %}
</div>
{% if mark %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>
<div class="entity-marks" style="margin-bottom: 0;">
<ul class="entity-marks__mark-list">
<li class="entity-marks__mark">
{% if mark.rating %}
<span class="entity-marks__rating-star rating-star"
data-rating-score="{{ mark.rating | floatformat:"0" }}" style="left: -4px;"></span>
{% endif %}
{% if mark.visibility > 0 %}
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" />
</svg></span>
{% endif %}
<span class="entity-marks__mark-time">
{% trans '于' %} {{ mark.edited_time }}
{% if status == 'reviewed' %}
{% trans '评论' %}: <a href="{% url 'movies:retrieve_review' mark.id %}">{{ mark.title }}</a>
{% else %}
{% trans '标记' %}
{% endif %}
</span>
{% if mark.text %}
<p class="entity-marks__mark-content">{{ mark.text }}</p>
{% endif %}
</li>
</ul>
</div>
{% endif %}
{% if collectionitem %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>

View file

@ -2,6 +2,8 @@
{% load highlight %}
{% load i18n %}
{% load l10n %}
{% load neo %}
{% current_user_marked_item music as marked %}
<li class="entity-list__entity">
<div class="entity-list__entity-img-wrapper">
@ -9,12 +11,17 @@
<a href="{% url 'music:retrieve_album' music.id %}">
<img src="{{ music.cover|thumb:'normal' }}" alt="" class="entity-list__entity-img">
</a>
{% if not marked %}
<a class="entity-list__entity-action-icon" hx-post="{% url 'music:wish_album' music.id %}" title="加入想听"></a>
{% endif %}
{% elif music.category_name|lower == 'song' %}
<a href="{% url 'music:retrieve_song' music.id %}">
<img src="{{ music.cover|thumb:'normal' }}" alt="" class="entity-list__entity-img">
</a>
{% if not marked %}
<a class="entity-list__entity-action-icon" hx-post="{% url 'music:wish_song' music.id %}" title="加入想听"></a>
{% endif %}
{% endif %}
</div>
<div class="entity-list__entity-text">
{% if editable %}
@ -50,7 +57,7 @@
{% endif %}
{% if not request.GET.c or not request.GET.c in categories %}
{% if not request.GET.c and not hide_category %}
<span class="entity-list__entity-category">[{{music.verbose_category_name}}]</span>
{% endif %}
<a href="{{ music.source_url }}">
@ -107,7 +114,44 @@
</span>
{% endfor %}
</div>
{% if mark %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>
<div class="entity-marks" style="margin-bottom: 0;">
<ul class="entity-marks__mark-list">
<li class="entity-marks__mark">
{% if mark.rating %}
<span class="entity-marks__rating-star rating-star"
data-rating-score="{{ mark.rating | floatformat:"0" }}" style="left: -4px;"></span>
{% endif %}
{% if mark.visibility > 0 %}
<span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" />
</svg></span>
{% endif %}
<span class="entity-marks__mark-time">
{% trans '于' %} {{ mark.edited_time }}
{% if status == 'reviewed' %}
{% trans '评论' %}:
{% if music.category_name|lower == 'album' %}
<a href="{% url 'music:retrieve_album_review' mark.id %}">{{ mark.title }}</a>
{% else %}
<a href="{% url 'music:retrieve_song_review' mark.id %}">{{ mark.title }}</a>
{% endif %}
{% else %}
{% trans '标记' %}
{% endif %}
</span>
{% if mark.text %}
<p class="entity-marks__mark-content">{{ mark.text }}</p>
{% endif %}
</li>
</ul>
</div>
{% endif %}
{% if collectionitem %}
<div class="clearfix"></div>
<div class="dividing-line dividing-line--dashed"></div>

View file

@ -0,0 +1,9 @@
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def current_user_marked_item(context, item):
return context['request'].user.get_mark_for_item(item)

View file

@ -97,6 +97,10 @@ class Game(Entity):
def verbose_category_name(self):
return _("游戏")
@property
def mark_class(self):
return GameMark
class GameMark(Mark):
game = models.ForeignKey(

View file

@ -9,6 +9,7 @@ urlpatterns = [
path('update/<int:id>/', update, name='update'),
path('delete/<int:id>/', delete, name='delete'),
path('mark/', create_update_mark, name='create_update_mark'),
path('wish/<int:id>/', wish, name='wish'),
re_path('(?P<game_id>[0-9]+)/mark/list/(?:(?P<following_only>\\d+))?', retrieve_mark_list, name='retrieve_mark_list'),
path('mark/delete/<int:id>/', delete_mark, name='delete_mark'),
path('<int:game_id>/review/create/', create_review, name='create_review'),

View file

@ -2,7 +2,7 @@ import logging
from django.shortcuts import render, get_object_or_404, redirect, reverse
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseBadRequest, HttpResponseServerError
from django.http import HttpResponseBadRequest, HttpResponseServerError, HttpResponse
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import IntegrityError, transaction
from django.db.models import Count
@ -338,6 +338,26 @@ def create_update_mark(request):
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish(request, id):
if request.method == 'POST':
game = get_object_or_404(Game, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'game': game,
}
try:
GameMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_mark_list(request, game_id, following_only=False):

View file

@ -224,6 +224,10 @@ class Movie(Entity):
else:
return _("电影")
@property
def mark_class(self):
return MovieMark
class MovieMark(Mark):
movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='movie_marks', null=True)

View file

@ -9,6 +9,7 @@ urlpatterns = [
path('update/<int:id>/', update, name='update'),
path('delete/<int:id>/', delete, name='delete'),
path('mark/', create_update_mark, name='create_update_mark'),
path('wish/<int:id>/', wish, name='wish'),
re_path('(?P<movie_id>[0-9]+)/mark/list/(?:(?P<following_only>\\d+))?', retrieve_mark_list, name='retrieve_mark_list'),
path('mark/delete/<int:id>/', delete_mark, name='delete_mark'),
path('<int:movie_id>/review/create/', create_review, name='create_review'),

View file

@ -2,7 +2,7 @@ import logging
from django.shortcuts import render, get_object_or_404, redirect, reverse
from django.contrib.auth.decorators import login_required, permission_required
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseBadRequest, HttpResponseServerError
from django.http import HttpResponseBadRequest, HttpResponseServerError, HttpResponse
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import IntegrityError, transaction
from django.db.models import Count
@ -337,6 +337,26 @@ def create_update_mark(request):
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish(request, id):
if request.method == 'POST':
movie = get_object_or_404(Movie, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'movie': movie,
}
try:
MovieMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_mark_list(request, movie_id, following_only=False):

View file

@ -76,6 +76,10 @@ class Album(Entity):
def verbose_category_name(self):
return _("专辑")
@property
def mark_class(self):
return AlbumMark
class Song(Entity):
'''
@ -122,11 +126,16 @@ class Song(Entity):
def get_tags_manager(self):
return self.song_tags
@property
def verbose_category_name(self):
return _("单曲")
@property
def mark_class(self):
return SongMark
class SongMark(Mark):
song = models.ForeignKey(
Song, on_delete=models.CASCADE, related_name='song_marks', null=True)

View file

@ -9,6 +9,7 @@ urlpatterns = [
path('song/update/<int:id>/', update_song, name='update_song'),
path('song/delete/<int:id>/', delete_song, name='delete_song'),
path('song/mark/', create_update_song_mark, name='create_update_song_mark'),
path('song/wish/<int:id>/', wish_song, name='wish_song'),
path('song/<int:song_id>/mark/list/',
retrieve_song_mark_list, name='retrieve_song_mark_list'),
path('song/mark/delete/<int:id>/', delete_song_mark, name='delete_song_mark'),
@ -19,12 +20,13 @@ urlpatterns = [
re_path('song/(?P<song_id>[0-9]+)/mark/list/(?:(?P<following_only>\\d+))?', retrieve_song_mark_list, name='retrieve_song_mark_list'),
# path('song/scrape/', scrape_song, name='scrape_song'),
path('song/click_to_scrape/', click_to_scrape_song, name='click_to_scrape_song'),
path('album/create/', create_album, name='create_album'),
path('album/<int:id>/', retrieve_album, name='retrieve_album'),
path('album/update/<int:id>/', update_album, name='update_album'),
path('album/delete/<int:id>/', delete_album, name='delete_album'),
path('album/mark/', create_update_album_mark, name='create_update_album_mark'),
path('album/wish/<int:id>/', wish_album, name='wish_album'),
re_path('album/(?P<album_id>[0-9]+)/mark/list/(?:(?P<following_only>\\d+))?', retrieve_album_mark_list, name='retrieve_album_mark_list'),
path('album/mark/delete/<int:id>/', delete_album_mark, name='delete_album_mark'),
path('album/<int:album_id>/review/create/', create_album_review, name='create_album_review'),

View file

@ -12,7 +12,7 @@ from django.utils import timezone
from django.db.models import Count
from django.db import IntegrityError, transaction
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import HttpResponseBadRequest, HttpResponseServerError
from django.http import HttpResponseBadRequest, HttpResponseServerError, HttpResponse
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import render, get_object_or_404, redirect, reverse
@ -356,6 +356,26 @@ def create_update_song_mark(request):
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish_song(request, id):
if request.method == 'POST':
song = get_object_or_404(Song, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'song': song,
}
try:
SongMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_song_mark_list(request, song_id, following_only=False):
@ -931,6 +951,26 @@ def create_update_album_mark(request):
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def wish_album(request, id):
if request.method == 'POST':
album = get_object_or_404(Album, pk=id)
params = {
'owner': request.user,
'status': MarkStatusEnum.WISH,
'visibility': 0,
'album': album,
}
try:
AlbumMark.objects.create(**params)
except Exception:
pass
return HttpResponse("✔️")
else:
return HttpResponseBadRequest("invalid method")
@mastodon_request_included
@login_required
def retrieve_album_mark_list(request, album_id, following_only=False):

View file

@ -100,6 +100,11 @@ class User(AbstractUser):
def is_followed_by(self, target):
return target.is_following(self)
def get_mark_for_item(self, item):
params = {item.__class__.__name__.lower() + '_id': item.id, 'owner': self}
mark = item.mark_class.objects.filter(**params).first()
return mark
class Preference(models.Model):
user = models.OneToOneField(User, models.CASCADE, primary_key=True)

View file

@ -0,0 +1,190 @@
{% load static %}
{% load i18n %}
{% load l10n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load thumb %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {{ user.mastodon_username }} {{ list_title }}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://unpkg.com/htmx.org@1.6.1"></script>
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<script src="{% static 'js/rating-star-readonly.js' %}"></script>
<script src="{% static 'js/mastodon.js' %}"></script>
<script src="{% static 'js/home.js' %}"></script>
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic.min.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/neo.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content" class="container">
<div class="grid grid--reverse-order">
<div class="grid__main grid__main--reverse-order">
<div class="main-section-wrapper">
<div class="entity-list">
<div class="set">
<h5 class="entity-list__title">
{{ user.mastodon_username }} {{ list_title }}
</h5>
</div>
<ul class="entity-list__entities">
{% for mark in marks %}
{% include "partial/list_item.html" with item=mark.item hide_category=True %}
{% empty %}
<div>{% trans '无结果' %}</div>
{% endfor %}
</ul>
</div>
<div class="pagination">
{% if marks.pagination.has_prev %}
<a href="?page=1" class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ marks.previous_page_number }}"
class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in marks.pagination.page_range %}
{% if page == marks.pagination.current_page %}
<a href="?page={{ page }}" class="pagination__page-link pagination__page-link--current">{{ page }}</a>
{% else %}
<a href="?page={{ page }}" class="pagination__page-link">{{ page }}</a>
{% endif %}
{% endfor %}
{% if marks.pagination.has_next %}
<a href="?page={{ marks.next_page_number }}"
class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ marks.pagination.last_page }}" class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>
</div>
</div>
<div class="grid__aside grid__aside--reverse-order grid__aside--tablet-column">
<div class="aside-section-wrapper aside-section-wrapper--no-margin">
<div class="user-profile" id="userInfoCard">
<div class="user-profile__header">
<!-- <img src="" class="user-profile__avatar mast-avatar" alt="{{ user.username }}"> -->
<img src="" class="user-profile__avatar mast-avatar">
<a href="{% url 'users:home' user.mastodon_username %}">
<h5 class="user-profile__username mast-displayname"></h5>
</a>
</div>
<p class="user-profile__bio mast-brief"></p>
<!-- <a href="#" class="follow">{% trans '关注TA' %}</a> -->
{% if request.user != user %}
<a href="{% url 'users:report' %}?user_id={{ user.id }}"
class="user-profile__report-link">{% trans '举报用户' %}</a>
{% endif %}
</div>
</div>
<div class="relation-dropdown">
<div class="relation-dropdown__button">
<span class="icon-arrow">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
<path d="M8.12,3.29,5,6.42,1.86,3.29H.45L5,7.84,9.55,3.29Z" />
</svg>
</span>
</div>
<div class="relation-dropdown__body">
<div class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse">
<div class="user-relation" id="followings">
<h5 class="user-relation__label">
{% trans '关注的人' %}
</h5>
<a href="{% url 'users:following' user.mastodon_username %}"
class="user-relation__more-link mast-following-more">{% trans '更多' %}</a>
<ul class="user-relation__related-user-list mast-following">
<li class="user-relation__related-user">
<a>
<img src="" alt="" class="user-relation__related-user-avatar">
<div class="user-relation__related-user-name mast-displayname">
</div>
</a>
</li>
</ul>
</div>
<div class="user-relation" id="followers">
<h5 class="user-relation__label">
{% trans '被他们关注' %}
</h5>
<a href="{% url 'users:followers' user.mastodon_username %}"
class="user-relation__more-link mast-followers-more">{% trans '更多' %}</a>
<ul class="user-relation__related-user-list mast-followers">
<li class="user-relation__related-user">
<a>
<img src="" alt="" class="user-relation__related-user-avatar">
<div class="user-relation__related-user-name mast-displayname">
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
<div id="oauth2Token" hidden="true">{% oauth_token %}</div>
<div id="mastodonURI" hidden="true">{% mastodon request.user.mastodon_site %}</div>
<!--current user mastodon id-->
{% if user == request.user %}
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
{% else %}
<div id="userMastodonID" hidden="true">{{ user.target_site_id }}</div>
{% endif %}
<div id="userPageURL" hidden="true">{% url 'users:home' 0 %}</div>
<div id="spinner" hidden>
<div class="spinner">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
</body>
</html>

View file

@ -644,7 +644,7 @@ def book_list(request, id, status):
list_title = str(BookMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的书"))
return render(
request,
'users/book_list.html',
'users/item_list.html',
{
'marks': marks,
'user': user,
@ -730,7 +730,7 @@ def movie_list(request, id, status):
return render(
request,
'users/movie_list.html',
'users/item_list.html',
{
'marks': marks,
'user': user,
@ -816,7 +816,7 @@ def game_list(request, id, status):
list_title = str(GameMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的游戏"))
return render(
request,
'users/game_list.html',
'users/item_list.html',
{
'marks': marks,
'user': user,
@ -915,7 +915,7 @@ def music_list(request, id, status):
list_title = str(MusicMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的音乐"))
return render(
request,
'users/music_list.html',
'users/item_list.html',
{
'marks': marks,
'user': user,