new style

* new style with picocss
* djlint
* rate distribution
* collection item drag to order
* discover available for guest
* search combine movie tv
This commit is contained in:
Henri Dickson 2023-05-20 11:01:18 -04:00 committed by GitHub
parent cef2e0e617
commit 0ffd47ca96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
163 changed files with 8699 additions and 5252 deletions

1
.gitignore vendored
View file

@ -23,6 +23,7 @@ tox.ini
# generated css
/common/static/css/boofilsic.min.css
/common/static/css/boofilsic.css
/common/static/scss/neodb.css
# debug log file
/log

View file

@ -10,3 +10,10 @@ repos:
hooks:
- id: black
language_version: python3.11
repos:
- repo: https://github.com/Riverside-Healthcare/djLint
rev: v1.28.0
hooks:
- id: djlint-reformat-django
- id: djlint-django

View file

@ -12,6 +12,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
import os
PROJECT_ROOT = os.path.abspath(os.path.dirname(__name__))
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -52,6 +53,7 @@ INSTALLED_APPS = [
"django_rq",
"django_bleach",
"tz_detect",
"sass_processor",
"simple_history",
"markdownx",
"polymorphic",
@ -210,6 +212,11 @@ STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
"sass_processor.finders.CssFinder",
]
AUTH_USER_MODEL = "users.User"
@ -221,9 +228,9 @@ SILENCED_SYSTEM_CHECKS = [
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
PROJECT_ROOT = os.path.abspath(os.path.dirname(__name__))
SITE_INFO = {
"site_name": "NiceDB",
"site_url": "https://nicedb.org",
"support_link": "https://github.com/doubaniux/boofilsic/issues",
"social_link": "https://donotban.com/@testie",
"donation_link": "https://patreon.com/tertius",
@ -237,6 +244,7 @@ CLIENT_NAME = os.environ.get("APP_NAME", "NiceDB")
SITE_INFO["site_name"] = os.environ.get("APP_NAME", "NiceDB")
APP_WEBSITE = os.environ.get("APP_URL", "https://nicedb.org")
REDIRECT_URIS = APP_WEBSITE + "/users/OAuth2_login/"
SITE_INFO["site_url"] = APP_WEBSITE
# Path to save report related images, ends with slash
@ -408,3 +416,5 @@ MAINTENANCE_MODE_IGNORE_ADMIN_SITE = True
MAINTENANCE_MODE_IGNORE_SUPERUSER = True
MAINTENANCE_MODE_IGNORE_ANONYMOUS_USER = True
MAINTENANCE_MODE_IGNORE_URLS = (r"^/users/connect/", r"^/users/OAuth2_login/")
DISCORD_WEBHOOKS = {}

View file

@ -277,9 +277,9 @@ class MockResponse:
return json.load(StringIO(self.text))
def html(self):
return html.fromstring(
return html.fromstring( # may throw exception unexpectedly due to OS bug, see https://github.com/neodb-social/neodb/issues/5
self.text
) # may throw exception unexpectedly due to OS bug, see https://github.com/neodb-social/neodb/issues/5
)
@property
def headers(self):

View file

@ -8,6 +8,9 @@ from django.utils import timezone
from django.db.models import Count
MAX_GALLERY_ITEMS = 42
class Command(BaseCommand):
help = "catalog app utilities"
@ -18,9 +21,21 @@ class Command(BaseCommand):
help="generate discover data",
)
def get_popular_item_ids(self, category, days):
self.stdout.write(f"Generating popular {category} items for {days} days...")
item_ids = [
m["item_id"]
for m in ShelfMember.objects.filter(query_item_category(category))
.filter(created_time__gt=timezone.now() - timedelta(days=days))
.values("item_id")
.annotate(num=Count("item_id"))
.order_by("-num")[:MAX_GALLERY_ITEMS]
]
return item_ids
def handle(self, *args, **options):
if options["update"]:
cache_key = "public_gallery_list"
cache_key = "public_gallery"
gallery_categories = [
ItemCategory.Book,
ItemCategory.Movie,
@ -31,22 +46,19 @@ class Command(BaseCommand):
]
gallery_list = []
for category in gallery_categories:
item_ids = [
m["item_id"]
for m in ShelfMember.objects.filter(query_item_category(category))
.filter(created_time__gt=timezone.now() - timedelta(days=42))
.values("item_id")
.annotate(num=Count("item_id"))
.order_by("-num")[:100]
]
days = 14
item_ids = []
while len(item_ids) < MAX_GALLERY_ITEMS / 2 and days < 150:
item_ids = self.get_popular_item_ids(category, days)
days *= 3
items = Item.objects.filter(id__in=item_ids)
gallery_list.append(
{
"name": "popular_" + category.value,
"title": "热门"
+ (category.label if category != ItemCategory.Book else "图书"),
"item_ids": item_ids,
"items": items,
}
)
cache.set(cache_key, gallery_list, timeout=None)
self.stdout.write(self.style.SUCCESS(f"Done."))

View file

@ -75,6 +75,16 @@ class Album(Item):
bandcamp_album_id = jsondata.CharField(blank=True, default="", max_length=500)
disc_count = jsondata.IntegerField(_("碟片数"), blank=True, default="", max_length=500)
def get_embed_link(self):
for res in self.external_resources.all():
if res.id_type == IdType.Bandcamp.value and res.metadata.get(
"bandcamp_album_id"
):
return f"https://bandcamp.com/EmbeddedPlayer/album={res.metadata.get('bandcamp_album_id')}/size=large/bgcol=ffffff/linkcol=19A2CA/artwork=small/transparent=true/"
if res.id_type == IdType.Spotify_Album.value:
return res.url.replace("open.spotify.com/", "open.spotify.com/embed/")
return None
@classmethod
def lookup_id_type_choices(cls):
id_types = [

View file

@ -16,19 +16,22 @@ class SearchResultItem:
self, category, source_site, source_url, title, subtitle, brief, cover_url
):
self.category = category
self.external_resources = {
"all": [{"url": source_url, "site_name": {"label": source_site}}]
}
self.source_site = source_site
self.source_url = source_url
self.title = title
self.subtitle = subtitle
self.brief = brief
self.cover_url = cover_url
self.cover_image_url = cover_url
@property
def verbose_category_name(self):
return self.category.label
@property
def link(self):
def url(self):
return f"/search?q={quote_plus(self.source_url)}"
@property
@ -272,7 +275,7 @@ class ExternalSources:
results = []
if c == "" or c is None:
c = "all"
if c == "all" or c == "movie" or c == "tv":
if c == "all" or c == "movietv":
results.extend(TheMovieDatabase.search(q, page))
if c == "all" or c == "book":
results.extend(GoogleBooks.search(q, page))

View file

@ -236,7 +236,10 @@ class Indexer:
def search(cls, q, page=1, category=None, tag=None, sort=None):
f = []
if category:
f.append("category:= " + category)
if category == "movietv":
f.append("category:= [movie,tv]")
else:
f.append("category:= " + category)
if tag:
f.append(f"tags:= '{tag}'")
filters = " && ".join(f)
@ -254,6 +257,7 @@ class Indexer:
try:
r = cls.instance().collections[INDEX_NAME].documents.search(options)
print(r)
results.items = list(
[
x

View file

@ -80,6 +80,7 @@ def fetch(request, url, is_refetch: bool = False, site: AbstractSite = None):
"fetch_pending.html",
{
"site": site,
"sites": SiteName.labels,
"job_id": job_id,
},
)
@ -99,6 +100,7 @@ def search(request):
"search_results.html",
{
"items": None,
"sites": SiteName.labels,
},
)
@ -150,7 +152,7 @@ def search(request):
),
"categories": ["book", "movie", "music", "game"],
"sites": SiteName.labels,
"hide_category": category is not None,
"hide_category": category is not None and category != "movietv",
},
)

View file

@ -14,8 +14,8 @@ _logger = logging.getLogger(__name__)
class Bandcamp(AbstractSite):
SITE_NAME = SiteName.Bandcamp
ID_TYPE = IdType.Bandcamp
URL_PATTERNS = [r"https://([a-z0-9\-]+.bandcamp.com/album/[^?#/]+)"]
URL_PATTERN_FALLBACK = r"https://([a-z0-9\-\.]+/album/[^?#/]+)"
URL_PATTERNS = [r"https://([a-z0-9\-]+.bandcamp.com/album/[^?#/]+).*"]
URL_PATTERN_FALLBACK = r"https://([a-z0-9\-\.]+/album/[^?#/]+).*"
WIKI_PROPERTY_ID = ""
DEFAULT_MODEL = Album

View file

@ -24,7 +24,7 @@ spotify_token_expire_time = time.time()
class Spotify(AbstractSite):
SITE_NAME = SiteName.Spotify
ID_TYPE = IdType.Spotify_Album
URL_PATTERNS = [r"\w+://open\.spotify\.com/album/([a-zA-Z0-9]+)"]
URL_PATTERNS = [r"\w+://open\.spotify\.com/album/([a-zA-Z0-9]+).*"]
WIKI_PROPERTY_ID = "?"
DEFAULT_MODEL = Album

57
catalog/static/podcast.js Normal file
View file

@ -0,0 +1,57 @@
function create_player(audio) {
window.player = new Shikwasa.Player({
container: () => document.querySelector('.player'),
preload: 'metadata',
autoplay: true,
themeColor: getComputedStyle(document.documentElement).getPropertyValue('--pico-primary'),
fixed: {
type: 'fixed',
position: 'bottom'
},
audio: audio
});
// $('.shk-title').on('click', e=>{
// window.location = "#";
// });
$('.footer').attr('style', 'margin-bottom: 120px !important');
}
function podcast_init(context) {
$('.episode', context).on('click', e=>{
e.preventDefault();
var ele = e.currentTarget;
var album = $(ele).data('album');
var artist = $(ele).data('hosts');
var title = $(ele).data('title');
var cover_url = $(ele).data('cover');
var media_url = $(ele).data('media');
var position = $(ele).data('position');
if (!media_url) return;
window.current_item_uuid = $(ele).data('uuid');
if (!window.player) {
create_player({
title: title,
cover: cover_url,
src: media_url,
album: album,
artist: artist
})
} else {
window.player.update({
title: title,
cover: cover_url,
src: media_url,
album: album,
artist: artist
})
}
if (position) window.player._initSeek = position;
window.player.play()
});
}
$(function() {
document.body.addEventListener('htmx:load', function(evt) {
podcast_init(evt.detail.elt);
});
podcast_init(document.body);
});

View file

@ -0,0 +1,121 @@
{% load humanize %}
{% load i18n %}
{% load highlight %}
{% if item.get_embed_link %}
<div class="item player">
<h5>
<a href="{{ item.url }}">{{ item.title }}</a>
<small>
{% if not hide_category %}<span class="category">[{{ item.category.label }}]</span>{% endif %}
<span class="site-list">
{% for res in item.external_resources.all %}
<a href="{{ res.url }}" class="{{ res.site_name }}">{{ res.site_name.label }}</a>
{% endfor %}
</span>
</small>
</h5>
<iframe src="{{ item.get_embed_link }}"
frameborder="0"
allowtransparency="true"
allow="encrypted-media"
style="width: 100%;
height: 120px"></iframe>
</div>
{% else %}
<div class="item">
<div class="cover">
<a href="{{ item.url }}">
<img src="{{ item.cover_image_url }}" alt="cover" />
</a>
</div>
<div>
<hgroup>
<h5>
<a href="{{ item.url }}">
{% if request.GET.q %}
{{ item.title | strip_season | highlight:request.GET.q }}
{% else %}
{{ item.title | strip_season }}
{% endif %}
</a>
<small>
{% if item.season_number %}第{{ item.season_number|apnumber }}季{% endif %}
{% if item.year %}({{ item.year }}){% endif %}
{% if not hide_category %}<span class="category">[{{ item.category.label }}]</span>{% endif %}
<span class="site-list">
{% for res in item.external_resources.all %}
<a href="{{ res.url }}" class="{{ res.site_name }}">{{ res.site_name.label }}</a>
{% endfor %}
</span>
</small>
</h5>
{% comment %}
<span class="site-list">
{% for res in item.external_resources.all %}
<a href="{{ res.url }}" class="{{ res.site_name }}">{{ res.site_name.label }}</a>
{% endfor %}
</span>
{% endcomment %}
<div>
<small>
{% if item.subtitle %}{{ item.subtitle }}{% endif %}
{% if item.orig_title %}
{{ item.orig_title }}
{% if item.season_number %}Season {{ item.season_number }}{% endif %}
{% endif %}
</small>
</div>
</hgroup>
<div>
<div class="metadata">
{% if item.rating %}
{{ item.rating | floatformat:1 }}分
{% else %}
{% endif %}
{% include '_people.html' with people=item.author role='' max=2 %}
{% include '_people.html' with people=item.translator role='' max=2 %}
{% include '_people.html' with people=item.director role='' max=2 %}
{% include '_people.html' with people=item.hosts role='' max=2 %}
{% include '_people.html' with people=item.artist role='' max=2 %}
{% include '_people.html' with people=item.developer role='' max=2 %}
{% if item.pub_house %}/ {{ item.pub_house }}{% endif %}
{% if item.pub_year %}
/ {{ item.pub_year }}{% trans '年' %}
{% if item.pub_month %}
{{ item.pub_month }}{% trans '月' %}
{% endif %}
{% endif %}
{% if item.release_date %}/ {{ item.release_date }}{% endif %}
{% include '_people.html' with people=item.genre role='' max=10 %}
{% include '_people.html' with people=item.platform role='' max=10 %}
</div>
<div class="brief">
{% if item.actor %}
{% include '_people.html' with people=item.actor role='主演' max=2 %}
<br>
{% endif %}
{% if item.other_title %}
{% include '_people.html' with people=item.other_title role='又名' max=2 %}
<br>
{% endif %}
{% if request.GET.q %}
{{ item.brief | linebreaksbr | highlight:request.GET.q }}
{% else %}
{{ item.brief | linebreaksbr }}
{% endif %}
</div>
{% if show_tags %}
<div class="tag-list">
{% for tag in item.tags %}
{% if forloop.counter <= 5 %}
<span>
<a href="{% url 'catalog:search' %}?tag={{ tag }}">{{ tag }}</a>
</span>
{% endif %}
{% endfor %}
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}

View file

@ -0,0 +1,11 @@
{% if people %}
{% if role %}{{ role }}:{% endif %}
{% for p in people %}
{% if forloop.counter <= max %}
{% if not forloop.first %}、{% endif %}
<span>{{ p }}</span>
{% elif forloop.last %}
{% endif %}
{% endfor %}
{% endif %}

View file

@ -10,114 +10,120 @@
{% load strip_scheme %}
{% load thumb %}
{% load duration %}
<!-- class specific details -->
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating and item.rating_count >= 5 %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:"0" }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.artist %}{% trans '艺术家:' %}
{% for artist in item.artist %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="artist">{{ artist }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.artist|length > 5 %}
<a href="javascript:void(0);" id="artistMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.artist %}
{% trans '艺术家:' %}
{% for artist in item.artist %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="artist">{{ artist }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.artist|length > 5 %}
<a href="javascript:void(0);" id="artistMore">{% trans '更多' %}</a>
<script>
$("#artistMore").on('click', function (e) {
$("span.artist:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.company %}{% trans '发行方:' %}
{% for company in item.company %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="company">{{ company }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.company|length > 5 %}
<a href="javascript:void(0);" id="companyMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.company %}
{% trans '发行方:' %}
{% for company in item.company %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="company">{{ company }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.company|length > 5 %}
<a href="javascript:void(0);" id="companyMore">{% trans '更多' %}</a>
<script>
$("#companyMore").on('click', function (e) {
$("span.company:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.release_date %}
{% trans '发行日期:' %}{{ item.release_date }}
{% endif %}
</div>
<div>{% if item.duration %}
{% trans '时长:' %}{{ item.duration|duration_format:1000 }}
{% endif %}
</div>
<div>{% if item.genre %}
{% trans '流派:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>{% if item.barcode %}
{% trans '条形码:' %}{{ item.barcode }}
{% endif %}
</div>
</div>
<div class="entity-detail__fields">
<div>{% if item.other_title %}
{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>{% if item.album_type %}
{% trans '专辑类型:' %}{{ item.album_type }}
{% endif %}
</div>
<div>{% if item.media %}
{% trans '介质:' %}{{ item.media }}
{% endif %}
</div>
<div>{% if item.disc_count %}
{% trans '碟片数:' %}{{ item.disc_count }}
{% endif %}
</div>
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
</div>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.release_date %}
{% trans '发行日期:' %}{{ item.release_date }}
{% endif %}
</div>
<div>
{% if item.duration %}
{% trans '时长:' %}{{ item.duration|duration_format:1000 }}
{% endif %}
</div>
<div>
{% if item.genre %}
{% trans '流派:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.barcode %}
{% trans '条形码:' %}{{ item.barcode }}
{% endif %}
</div>
<div>
{% if item.other_title %}
{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.album_type %}
{% trans '专辑类型:' %}{{ item.album_type }}
{% endif %}
</div>
<div>
{% if item.media %}
{% trans '介质:' %}{{ item.media }}
{% endif %}
</div>
<div>
{% if item.disc_count %}
{% trans '碟片数:' %}{{ item.disc_count }}
{% endif %}
</div>
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
{% if item.get_embed_link %}
<iframe src="{{ item.get_embed_link }}" height="320" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>
{% endif %}
{% block content %}
{% if item.track_list %}
<section>
<h5>曲目</h5>
<p class="tldr" _="on click toggle .tldr on me">{{ item.track_list | linebreaksbr }}</p>
</section>
{% endif %}
{% if item.get_embed_link %}
<section>
<h5>播放</h5>
<iframe src="{{ item.get_embed_link }}"
frameborder="0"
allowtransparency="true"
allow="encrypted-media"
style="width: 100%;
height: 50vh"></iframe>
</section>
{% endif %}
{% endblock %}

View file

@ -4,133 +4,148 @@
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% if form.instance.id %}{% trans '编辑' %} {{ form.instance.title }} {% else %}{% trans '添加' %}{% endif %}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content" class="container">
<div class="grid">
<div style="float:right;padding-left:16px">
{% if item %}
<div class="aside-section-wrapper">
{% for res in form.instance.external_resources.all %}
<div class="action-panel">
<div class="action-panel__label">{% trans '源网站' %}: <a href="{{ res.url }}">{{ res.site_name.label }}</a></div>
<div class="action-panel__button-group">
<form method="post" action="{% url 'catalog:refetch' %}">
{% csrf_token %}
<input type="hidden" name="id" value="{{ res.id }}" >
<input type="hidden" name="url" value="{{ res.url }}" >
<input class="button" type="submit" value="{% trans '重新抓取' %}">
</form>
</div>
<html lang="en" class="content-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} -
{% if form.instance.id %}
{% trans '编辑' %} {{ form.instance.title }}
{% else %}
{% trans '添加' %}
{% endif %}
</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
<style>
aside details {
margin-bottom: 1rem;
padding: 1rem;
border: var(--pico-muted-color) solid 1px;
}
aside summary {
cursor: pointer;
font-weight: bold;
}
main>div {
margin-bottom: 4rem;
}
</style>
</head>
<body>
{% include "_header.html" %}
<main>
<div class="grid__main">
<form action="{{ submit_url }}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form }}
<div class="grid">
<input type="submit" value="{% trans '保存' %}">
<input type="reset" value="{% trans '返回' %}" onclick="history.go(-1);">
</div>
</form>
</div>
<aside class="grid__aside">
<h5>进阶编辑选项</h5>
{% if item %}
{% for res in form.instance.external_resources.all %}
<details>
<summary>
{% trans '源网站' %}: <a href="{{ res.url }}">{{ res.site_name.label }}</a>
</summary>
<div class="grid">
<form method="post" action="{% url 'catalog:refetch' %}">
{% csrf_token %}
<input type="hidden" name="id" value="{{ res.id }}">
<input type="hidden" name="url" value="{{ res.url }}">
<input class="secondary" type="submit" value="{% trans '重新抓取' %}">
</form>
{% if request.user.is_staff %}
<div class="action-panel__button-group">
<form method="post" action="{% url 'catalog:unlink' %}">
{% csrf_token %}
<input type="hidden" name="id" value="{{ res.id }}" >
<input class="button" type="submit" value="{% trans '取消关联' %}">
<input type="hidden" name="id" value="{{ res.id }}">
<input class="contrast" type="submit" value="{% trans '取消关联' %}">
</form>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% if item.class_name == "movie" or item.class_name == "tvshow" %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__label">{% trans '切换分类' %} </div>
<div class="action-panel__button-group">
<form method="post" action="{% url 'catalog:recast' item.url_path item.uuid %}" onsubmit="return confirm('确认切换吗?');">
{% csrf_token %}
{% if item.class_name == "movie" %}
<input type="hidden" value="tvshow" name="class">
<input class="button" type="submit" value="{% trans '更改为剧集' %}">
{% endif %}
{% if item.class_name == "tvshow" %}
<input type="hidden" value="movie" name="class">
<input class="button" type="submit" value="{% trans '更改为电影' %}">
{% endif %}
</form>
</div>
</div>
</div>
{% endif %}
<div class="aside-section-wrapper">
<div class="action-panel">
{% if item.class_name == "tvseason" %}
{% if not item.show or request.user.is_superuser %}
<div class="action-panel__label">{% trans '将本季关联到电视剧' %} </div>
<div class="action-panel__button-group">
<form method="post" action="{% url 'catalog:assign_parent' item.url_path item.uuid %}" onsubmit="return confirm('本操作不可撤销。确认关联吗?');">
{% csrf_token %}
<input type="url" name="parent_item_url" placeholder="目标条目URL" value="{{ item.show.absolute_url }}" required><br>
<input class="button" type="submit" value="{% trans '提交' %}">
</form>
</div>
</details>
{% endfor %}
{% if item.class_name == "movie" or item.class_name == "tvshow" %}
<details>
<summary>{% trans '切换分类' %}</summary>
<form method="post"
action="{% url 'catalog:recast' item.url_path item.uuid %}"
onsubmit="return confirm('确认切换吗?');">
{% csrf_token %}
{% if item.class_name == "movie" %}
<input type="hidden" value="tvshow" name="class">
<input class="contrast" type="submit" value="{% trans '更改为剧集' %}">
{% endif %}
{% if item.class_name == "tvshow" %}
<input type="hidden" value="movie" name="class">
<input class="contrast" type="submit" value="{% trans '更改为电影' %}">
{% endif %}
{% if item.is_deleted and not request.user.is_superuser %}
<i>条目已被删除</i>
{% elif item.merged_to_item and not request.user.is_superuser %}
<i>条目已被合并</i>
{% elif not item.deletable and not request.user.is_superuser %}
<i>条目已被用户标记过</i>
{% else %}
<div class="action-panel__label">{% trans '合并到另一条目' %} </div>
<div class="action-panel__button-group">
<form method="post" action="{% url 'catalog:merge' item.url_path item.uuid %}" onsubmit="return confirm('本操作不可撤销。确认合并吗?');">
{% csrf_token %}
<input type="url" name="new_item_url" placeholder="目标条目URL" value="{{ item.merged_to_item.absolute_url }}" required><br>
<input class="button" type="submit" value="{% trans '提交' %}">
</form>
</div>
<div class="action-panel__label">{% trans '删除' %} </div>
<div class="action-panel__button-group">
<form method="post" action="{% url 'catalog:delete' item.url_path item.uuid %}" onsubmit="return confirm('本操作不可撤销。确认删除吗?');">
{% csrf_token %}
<input class="button" type="submit"
{% if item.is_deleted or item.merged_to_item %} disabled {% endif %} value="{% trans '提交' %}">
</form>
</div>
{% endif %}
</div>
</div>
</form>
</details>
{% endif %}
</div>
<div class="single-section-wrapper" id="main">
<form class="entity-form" action="{{ submit_url }}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form }}
<hr/>
<input class="button" type="submit" value="{% trans '提交' %}">
<a href="{{ item.url | default:'javascript:history.go(-1)' }}" style="float:right;">返回</a>
</form>
</div>
</section>
</div>
{% include "partial/_footer.html" %}
</div>
</body>
</html>
{% if item.class_name == "tvseason" %}
{% if not item.show or request.user.is_superuser %}
<details>
<summary>{% trans '将本季关联到电视剧' %}</summary>
<form method="post"
action="{% url 'catalog:assign_parent' item.url_path item.uuid %}"
onsubmit="return confirm('本操作不可撤销。确认关联吗?');">
{% csrf_token %}
<input type="url"
name="parent_item_url"
placeholder="目标条目URL"
value="{{ item.show.absolute_url }}"
required>
<br>
<input class="contrast" type="submit" value="{% trans '提交' %}">
</form>
</details>
{% endif %}
{% endif %}
{% if item.is_deleted and not request.user.is_superuser %}
<i>条目已被删除</i>
{% elif item.merged_to_item and not request.user.is_superuser %}
<i>条目已被合并</i>
{% elif not item.deletable and not request.user.is_superuser %}
<i>条目已被用户标记过</i>
{% else %}
<details>
<summary>{% trans '合并到另一条目' %}</summary>
<form method="post"
action="{% url 'catalog:merge' item.url_path item.uuid %}"
onsubmit="return confirm('本操作不可撤销。确认合并吗?');">
{% csrf_token %}
<input type="url"
name="new_item_url"
placeholder="目标条目URL"
value="{{ item.merged_to_item.absolute_url }}"
required>
<br>
<input class="contrast" type="submit" value="{% trans '提交' %}">
</form>
</details>
<details>
<summary>{% trans '删除' %}</summary>
<form method="post"
action="{% url 'catalog:delete' item.url_path item.uuid %}"
onsubmit="return confirm('本操作不可撤销。确认删除吗?');">
{% csrf_token %}
<input class="contrast"
type="submit"
{% if item.is_deleted or item.merged_to_item %}disabled{% endif %}
value="{% trans '提交' %}">
</form>
</details>
{% endif %}
{% endif %}
</aside>
</main>
{% include "partial/_footer.html" %}
</body>
</html>

View file

@ -1,42 +1,38 @@
{% load static %}
{% load sass_tags %}
{% load tz_detect %}
{% tz_detect %}
{% if sentry_dsn %}
<script src="https://browser.sentry-cdn.com/7.7.0/bundle.min.js"></script>
<script>
if (window.Sentry) Sentry.init({
dsn: "{{ sentry_dsn }}",
release: "{{ version_hash }}",
environment: "{{ settings_module }}",
tracesSampleRate: 1.0,
});
</script>
{% if request.user.is_authenticated %}
{% tz_detect %}
{% endif %}
{% if jquery %}
<script src="https://cdn.staticfile.org/jquery/3.6.3/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/jquery/3.6.3/jquery.min.js"></script>
{% else %}
<script src="https://cdn.staticfile.org/cash/8.1.3/cash.min.js"></script>
<script src="https://cdn.staticfile.org/cash/8.1.5/cash.min.js"></script>
{% endif %}
<script type="text/javascript">
if (!$.fn.is_visible) $.fn.is_visible = function () {
return this.filter((_, elt) => (elt.offsetWidth || elt.offsetHeight || elt.getClientRects().length)).length > 0;
return this.filter((_, elt) => (elt.offsetWidth || elt.offsetHeight || elt.getClientRects().length)).length > 0;
};
if (!$.fn.submit) $.fn.submit = function () {
this.each(function () {
$(this).trigger('submit');
this.submit();
});
return this;
this.each(function () {
$(this).trigger('submit');
this.submit();
});
return this;
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/htmx/1.8.5/htmx.min.js"></script>
<script src="https://cdn.staticfile.org/htmx/1.9.2/htmx.min.js"></script>
<script src="{% static 'lib/js/hyperscript-0.9.7.min.js' %}"></script>
<script src="{% static 'lib/js/rating-star.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/boofilsic.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}">
<link rel="stylesheet" href="{% static 'lib/css/collection.css' %}">
<link rel="search" type="application/opensearchdescription+xml" title="{{ site_name }}" href="{% static 'opensearch.xml' %}">
<script src="{% static 'catalog.js' %}"></script>
<script src="{% static 'lib/js/tag-input.js' %}"></script>
<link href="{% static 'lib/css/tag-input.css' %}" type="text/css" media="all" rel="stylesheet">
<link href="{% static 'fontawesomefree/css/all.min.css' %}" rel="stylesheet" type="text/css">
<link rel="stylesheet"
href="https://unpkg.com/@picocss/pico@next/css/pico.min.css" />
<link href="{% sass_src 'scss/neodb.scss' %}"
rel="stylesheet"
type="text/css" />
<link href="{% static 'fontawesomefree/css/all.min.css' %}"
rel="stylesheet"
type="text/css">
<link rel="search"
type="application/opensearchdescription+xml"
title="{{ site_name }}"
href="{% static 'opensearch.xml' %}">

View file

@ -6,118 +6,111 @@
{% 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 }} - {% trans '发现' %}</title>
<link rel="alternate" type="application/rss+xml" title="{{ site_name }} - {{ user.mastodon_username }}的评论" href="{{ request.build_absolute_uri }}feed/reviews/">
{% include "common_libs.html" with jquery=0 %}
<script src="{% static 'js/mastodon.js' %}" defer></script>
<script src="{% static 'js/home.js' %}" defer></script>
<html lang="en" class="classic-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="{{ site_name }} - 联邦宇宙书影音游戏标注平台">
<meta name="description"
property="og:description"
content="{{ site_name }}致力于为联邦宇宙居民提供一个自由、开放、互联的书籍、电影、音乐和游戏收藏评论空间">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ site_url }}">
<meta property="og:image"
content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/logo_square.jpg' %}">
<meta property="og:site_name" content="{{ site_name }}">
<title>{{ site_name }} - {% trans '发现' %}</title>
<link rel="alternate"
type="application/rss+xml"
title="{{ site_name }} - {{ user.mastodon_username }}的评论"
href="{{ request.build_absolute_uri }}feed/reviews/">
{% include "common_libs.html" with jquery=0 v2=1 %}
<script src="https://cdn.jsdelivr.net/npm/shikwasa@2.2.1/dist/shikwasa.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/shikwasa@2.2.1/dist/style.min.css"
rel="stylesheet"></link>
<script src="{% static 'podcast.js' %}"></script>
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" with current="discover" %}
<section id="content">
<div class="grid grid--reverse-order">
<div class="grid__main grid__main--reverse-order">
<div class="main-section-wrapper sortable">
{% for gallery in gallery_list %}
<div class="entity-sort" id="{{ gallery.name }}" {% if not gallery.items %}style="display:none;"{% endif %}>
<h5 class="entity-sort__label">
{{ gallery.title }}
</h5>
<ul class="entity-sort__entity-list">
{% for item in gallery.items %}
<li class="entity-sort__entity">
<a href="{{ item.url }}">
<img src="{{ item.cover_image_url | default:item.cover.url }}" alt="{{ item.title }}" class="entity-sort__entity-img">
<div class="entity-sort__entity-name" title="{{ item.title }}"> {{ item.title }}</div>
</a>
</li>
{% empty %}
<div>暂无记录</div>
{% endfor %}
</ul>
</div>
{% include "_header.html" with current="discover" %}
<main>
<div class="grid__main">
<div class="sortable">
{% for gallery in gallery_list %}
<section class="entity-sort shelf"
id="{{ gallery.name }}"
{% if not gallery.items %}style="display:none;"{% endif %}>
<h5>{{ gallery.title }}</h5>
<ul class="cards">
{% for item in gallery.items %}
<li class="card">
<a href="{{ item.url }}" title="{{ item.title }}">
<img src="{{ item.cover|thumb:'normal' }}"
alt="{{ item.title }}"
loading="lazy">
<div class="card-title">{{ item.title }}</div>
</a>
</li>
{% endfor %}
</div>
{% if user == request.user %}
<div class="entity-sort-control">
<div class="entity-sort-control__button" id="sortEditButton">
<span class="entity-sort-control__text" id="sortEditText">
{% trans '编辑布局' %}
</span>
<span class="entity-sort-control__text" id="sortSaveText" style="display: none;">
{% trans '保存' %}
</span>
<span class="icon-edit" id="sortEditIcon">
<i class="fa-solid fa-pencil"></i>
</span>
<span class="icon-save" id="sortSaveIcon" style="display: none;">
<i class="fa-regular fa-floppy-disk"></i>
</span>
</div>
<div class="entity-sort-control__button" id="sortExitButton" style="display: none;">
<span class="entity-sort-control__text">
{% trans '取消' %}
</span>
</div>
</div>
<div class="entity-sort-control__button entity-sort-control__button--float-right" id="toggleDisplayButtonTemplate" style="display: none;">
<span class="showText" style="display: none;">
{% trans '显示' %}
</span>
<span class="hideText" style="display: none;">
{% trans '隐藏' %}
</span>
</div>
<form action="{% url 'users:set_layout' %}" method="post" id="sortForm">
{% csrf_token %}
<input type="hidden" name="name" value="discover">
<input type="hidden" name="layout">
</form>
<script src="https://cdn.staticfile.org/html5sortable/0.13.3/html5sortable.min.js" crossorigin="anonymous"></script>
<script src="{% static 'js/sort_layout.js' %}"></script>
{% endif %}
{{ layout|json_script:"layout-data" }}
<script>
const initialLayoutData = JSON.parse(document.getElementById('layout-data').textContent);
// initialize sort element visibility and order
initialLayoutData.forEach(elem => {
// set visiblity
$('#' + elem.id).data('visibility', elem.visibility);
if (!elem.visibility) {
$('#' + elem.id).hide();
}
// order
$('#' + elem.id).appendTo('.main-section-wrapper');
});
</script>
</ul>
</section>
{% endfor %}
</div>
{% if request.user.is_authenticated %}
<div class="entity-sort-control">
<div class="entity-sort-control__button" id="sortEditButton">
<span class="entity-sort-control__text" id="sortEditText">{% trans '编辑布局' %}</span>
<span class="entity-sort-control__text"
id="sortSaveText"
style="display: none">{% trans '保存' %}</span>
<span class="icon-edit" id="sortEditIcon">
<i class="fa-solid fa-pencil"></i>
</span>
<span class="icon-save" id="sortSaveIcon" style="display: none;">
<i class="fa-regular fa-floppy-disk"></i>
</span>
</div>
<div class="entity-sort-control__button"
id="sortExitButton"
style="display: none">
<span class="entity-sort-control__text">{% trans '取消' %}</span>
</div>
{% include "partial/_sidebar.html" %}
</div>
</section>
<div class="entity-sort-control__button entity-sort-control__button--float-right"
id="toggleDisplayButtonTemplate"
style="display: none">
<span class="showText" style="display: none;">{% trans '显示' %}</span>
<span class="hideText" style="display: none;">{% trans '隐藏' %}</span>
</div>
<form action="{% url 'users:set_layout' %}" method="post" id="sortForm">
{% csrf_token %}
<input type="hidden" name="name" value="discover">
<input type="hidden" name="layout">
</form>
<script src="https://cdn.staticfile.org/html5sortable/0.13.3/html5sortable.min.js"
crossorigin="anonymous"></script>
<script src="{% static 'js/sort_layout.js' %}"></script>
{{ layout|json_script:"layout-data" }}
<script>
const initialLayoutData = JSON.parse(document.getElementById('layout-data').textContent);
// initialize sort element visibility and order
initialLayoutData.forEach(elem => {
// set visiblity
$('#' + elem.id).data('visibility', elem.visibility);
if (!elem.visibility) {
$('#' + elem.id).hide();
}
// order
$('#' + elem.id).appendTo('.sortable');
});
</script>
{% endif %}
</div>
{% include "partial/_footer.html" %}
</div>
{% if request.user.unread_announcements %}
{% include "partial/_announcement.html" %}
{% endif %}
{% if request.user.is_authenticated %}
{% include "_sidebar.html" with show_progress=1 %}
{% else %}
{% include "partial/_sidebar_anonymous.html" %}
{% endif %}
</main>
{% include "partial/_footer.html" %}
</body>
</html>

View file

@ -9,105 +9,153 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block head %}
{% if item.author %}
<meta property="og:book:author" content="{% for author in item.author %}{{ author }}{% if not forloop.last %},{% endif %}{% endfor %}">
{% endif %}
{% if item.isbn %}
<meta property="og:book:isbn" content="{{ item.isbn }}">
{% endif %}
{% if item.author %}
<meta property="og:book:author"
content="{% for author in item.author %}{{ author }}{% if not forloop.last %},{% endif %}{% endfor %}">
{% endif %}
{% if item.isbn %}<meta property="og:book:isbn" content="{{ item.isbn }}">{% endif %}
{% endblock %}
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.subtitle %}{% trans '副标题:' %}{{ item.subtitle }}{% endif %}</div>
<div>{% if item.isbn %}{% trans 'ISBN' %}{{ item.isbn }}{% endif %}</div>
<div>{% if item.author %}{% trans '作者:' %}
{% for author in item.author %}
<span>{{ author }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.pub_house %}{% trans '出版社:' %}{{ item.pub_house }}{% endif %}</div>
<div>{% if item.orig_title %}{% trans '原作名:' %}{{ item.orig_title }}{% endif %}</div>
<div>{% if item.translator %}{% trans '译者:' %}
{% for translator in item.translator %}
<span>{{ translator }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{%if item.pub_year %}{% trans '出版时间:' %}{{ item.pub_year }}{% trans '年' %}{% if item.pub_month %}{{ item.pub_month }}{% trans '月' %}{% endif %}{% endif %}</div>
<div>{% if item.series %}{% trans '丛书系列:' %}{{ item.series }}{% endif %}</div>
</div>
<div class="entity-detail__fields">
<div>{% if item.language %}{% trans '语言:' %}{{ item.language }}{% endif %}</div>
<div>{% if item.binding %}{% trans '装帧:' %}{{ item.binding }}{% endif %}</div>
<div>{% if item.price %}{% trans '定价:' %}{{ item.price }}{% endif %}</div>
<div>{% if item.pages %}{% trans '页数:' %}{{ item.pages }}{% endif %}</div>
<div>{% if item.imprint %}{% trans '出品方:' %}{{ item.imprint }}{% endif %}</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}
<div>
{{ k }}{{ v | urlize }}
</div>
{% endfor %}
{% endif %}
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
</div>
<!-- <div>{% if item.subtitle %}{% trans '副标题:' %}{{ item.subtitle }}{% endif %}</div>
<div>{% if item.orig_title %}{% trans '原作名:' %}{{ item.orig_title }}{% endif %}</div> -->
<div>
{% if item.isbn %}
{% trans 'ISBN' %}{{ item.isbn }}
{% endif %}
</div>
<div>
{% if item.author %}
{% trans '作者:' %}
{% for author in item.author %}
<span>{{ author }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.translator %}
{% trans '译者:' %}
{% for translator in item.translator %}
<span>{{ translator }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.pub_house %}
{% trans '出版社:' %}{{ item.pub_house }}
{% endif %}
</div>
<div>
{% if item.imprint %}
{% trans '出品方:' %}{{ item.imprint }}
{% endif %}
</div>
<div>
{% if item.pub_year %}
{% trans '出版时间:' %}{{ item.pub_year }}{% trans '年' %}
{% if item.pub_month %}
{{ item.pub_month }}{% trans '月' %}
{% endif %}
{% endif %}
</div>
<div>
{% if item.series %}
{% trans '丛书系列:' %}{{ item.series }}
{% endif %}
</div>
<div>
{% if item.language %}
{% trans '语言:' %}{{ item.language }}
{% endif %}
</div>
<div>
{% if item.binding %}
{% trans '装帧:' %}{{ item.binding }}
{% endif %}
</div>
<div>
{% if item.price %}
{% trans '定价:' %}{{ item.price }}
{% endif %}
</div>
<div>
{% if item.pages %}
{% trans '页数:' %}{{ item.pages }}
{% endif %}
</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}<div>{{ k }}{{ v|urlizetrunc:24 }}</div>{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% if item.contents %}
<section>
<h5>目录</h5>
<p class="tldr" _="on click toggle .tldr on me">{{ item.contents | linebreaksbr }}</p>
</section>
{% endif %}
{% endblock %}
{% block sidebar %}
{% with related_books=item.get_related_books %}
{% if related_books.count > 0 %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__label">{% trans '其它版本' %}</div>
<div >
{% for b in related_books %}
<p>
<a href="{{ b.url }}">{{ b.title }}</a>
<small>({{ b.pub_house | default:'' }} {{ b.pub_year | default:'' }})</small>
{% for res in b.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</p>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% endwith %}
{% if item.isbn %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__label">{% trans '借阅或购买' %}</div>
<div class="action-panel__button-group">
<a class="action-panel__button" target="_blank" rel="noopener" href="https://www.worldcat.org/isbn/{{ item.isbn }}">{% trans 'WorldCat' %}</a>
<a class="action-panel__button" target="_blank" rel="noopener" href="https://openlibrary.org/search?isbn={{ item.isbn }}">{% trans 'Open Library' %}</a>
</div>
</div>
</div>
{% endif %}
{% with related_books=item.get_related_books %}
{% if related_books.count > 0 %}
<section>
<h5>{% trans '其它版本' %}</h5>
{% for b in related_books %}
<p>
<a href="{{ b.url }}">{{ b.title }}</a>
<small>({{ b.pub_house | default:'' }} {{ b.pub_year | default:'' }})</small>
{% comment %} {% for res in b.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %} {% endcomment %}
</p>
{% endfor %}
</section>
{% endif %}
{% endwith %}
{% if item.isbn %}
<section>
<div class="action-panel">
<h5>{% trans '借阅或购买' %}</h5>
<div>
<ul>
<li>
<a target="_blank"
rel="noopener"
href="https://www.worldcat.org/isbn/{{ item.isbn }}">WorldCat</a>
</li>
<li>
<a target="_blank"
rel="noopener"
href="https://openlibrary.org/search?isbn={{ item.isbn }}">Open Library</a>
</li>
<li>
<a target="_blank"
rel="noopener"
href="https://library.oapen.org/discover?filtertype_1=isbn&filter_relational_operator_1=equals&filter_1={{ item.isbn }}">
OAPEN</a>
</li>
<li>
<a target="_blank"
rel="noopener"
href="https://bookshop.org/search?keywords={{ item.isbn }}">Bookshop.org</a>
</li>
<li>
<a target="_blank"
rel="noopener"
href="https://www.amazon.com/s?k={{ item.isbn }}">Amazon</a>
</li>
<li>
<a target="_blank"
rel="noopener"
href="https://www.duozhuayu.com/search/book/{{ item.isbn }}">多抓鱼</a>
</li>
</ul>
</div>
</div>
</section>
{% endif %}
{% endblock %}

View file

@ -8,17 +8,14 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.staticfile.org/cash/8.1.3/cash.min.js"></script>
{% block head %}
{% endblock %}
<title>{{ site_name }} - {% trans item.category.label %} | {{ item.title }}</title>
</head>
<body>
</body>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.staticfile.org/cash/8.1.3/cash.min.js"></script>
{% block head %}{% endblock %}
<title>{{ site_name }} - {% trans item.category.label %} | {{ item.title }}</title>
</head>
<body></body>
</html>

View file

@ -9,10 +9,10 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block head %}
<script src="https://cdn.jsdelivr.net/npm/shikwasa@2.2.0/dist/shikwasa.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/shikwasa@2.2.0/dist/style.min.css" rel="stylesheet"></link>
<script src="https://cdn.jsdelivr.net/npm/shikwasa@2.2.1/dist/shikwasa.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/shikwasa@2.2.1/dist/style.min.css"
rel="stylesheet"></link>
<style>
.shk-player {
font-family: sans-serif;

View file

@ -8,43 +8,6 @@
{% load truncate %}
{% load highlight %}
{% load thumb %}
{% for item in external_items %}
<li class="entity-list__entity">
<div class="entity-list__entity-img-wrapper">
<a href="{{ item.link }}">
{% if item.cover_url %}
<img src="{{ item.cover_url }}" alt="" class="entity-list__entity-img">
{% endif %}
</a>
</div>
<div class="entity-list__entity-text">
<div class="entity-list__entity-title" style="font-style:italic;">
<a href="{{ item.link }}" class="entity-list__entity-link">
{% if request.GET.q %}
{{ item.title | highlight:request.GET.q }}
{% else %}
{{ item.title }}
{% endif %}
</a>
{% if not request.GET.c or not request.GET.c in categories %}
<span class="entity-list__entity-category">[{{item.verbose_category_name}}]</span>
{% endif %}
<a href="{{ item.source_url }}">
<span class="source-label source-label__{{ item.source_site }}">{{ item.source_site.label }}</span>
</a>
</div>
<span class="entity-list__entity-info entity-list__entity-info--full-length">
{{item.subtitle}}
</span>
<p class="entity-list__entity-brief">
{{ item.brief }}
</p>
<div class="tag-collection">
</div>
</div>
</li>
<article class="item-card external">{% include "_item_card.html" with item=item %}</article>
{% endfor %}

View file

@ -1,3 +1,5 @@
<p>
无法加载条目。部分网站可能删除条目或隐藏条目为仅登录可见,欢迎在本站手工添加这些条目。
<i class="fa-solid fa-triangle-exclamation"></i>
无法加载条目,请确认链接正确。
部分网站可能删除条目或隐藏条目为仅登录可见,欢迎在本站手工添加这些条目。
</p>

View file

@ -9,51 +9,28 @@
{% load highlight %}
{% load thumb %}
<!DOCTYPE html>
<html lang="en">
<head>
<html lang="en" class="classic-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '搜索结果' %}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include 'partial/_navbar.html' %}
<section id="content">
<div class="grid">
<div class="grid__main">
<div class="main-section-wrapper">
<div>
{% trans '正在连线' %}{{ site.SITE_NAME.label }}
<div hx-get="{% url 'catalog:fetch_refresh' job_id %}" hx-trigger="load delay:2s" hx-swap="outerHTML"></div>
<i class="fas fa-fan fa-spin"></i>
</div>
</div>
</div>
{% include "search_sidebar.html" %}
</div>
</section>
</div>
{% include 'partial/_footer.html' %}
</div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
</body>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include '_header.html' %}
<main>
<div class="grid__main">
<article>
<h5>{% trans '正在连线' %}{{ site.SITE_NAME.label }}</h5>
<div hx-get="{% url 'catalog:fetch_refresh' job_id %}"
hx-trigger="load delay:2s"
hx-swap="outerHTML">
<i class="fa-solid fa-compact-disc fa-spin loading"></i>
</div>
</article>
</div>
{% include "search_sidebar.html" %}
</main>
{% include 'partial/_footer.html' %}
</body>
</html>

View file

@ -1 +1,5 @@
<div hx-get="{% url 'catalog:fetch_refresh' job_id %}?retry={{ retry }}" hx-trigger="load delay:{{ delay }}s" hx-swap="outerHTML"></div>
<div hx-get="{% url 'catalog:fetch_refresh' job_id %}?retry={{ retry }}"
hx-trigger="load delay:{{ delay }}s"
hx-swap="outerHTML">
<i class="fa-solid fa-compact-disc fa-spin loading"></i>
</div>

View file

@ -9,100 +9,75 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
<!-- class specific details -->
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating and item.rating_count >= 5 %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.other_title %}{% trans '别名:' %}
{% for other_title in item.other_title %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="other_title">{{ other_title }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.other_title|length > 5 %}
<a href="javascript:void(0);" id="otherTitleMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.other_title %}
{% trans '别名:' %}
{% for other_title in item.other_title %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="other_title">{{ other_title }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.other_title|length > 5 %}
<a href="javascript:void(0);" id="otherTitleMore">{% trans '更多' %}</a>
<script>
$("#otherTitleMore").on('click', function (e) {
$("span.other_title:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.developer %}{% trans '开发商:' %}
{% for developer in item.developer %}
<span>{{ developer }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.publisher %}{% trans '发行商:' %}
{% for publisher in item.publisher %}
<span>{{ publisher }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>{% if item.release_date %}
{% trans '发行日期:' %}{{ item.release_date }}
{% endif %}
</div>
<div>{% if item.official_site %}
{% trans '官方网站:' %}{{ item.official_site|urlizetrunc:42 }}
{% endif %}
</div>
</div>
<div class="entity-detail__fields">
<div>
{% if item.platform %}{% trans '平台:' %}
{% for platform in item.platform %}
<span>{{ platform }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
</div>
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}
{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.developer %}
{% trans '开发商:' %}
{% for developer in item.developer %}
<span>{{ developer }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.publisher %}
{% trans '发行商:' %}
{% for publisher in item.publisher %}
<span>{{ publisher }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.release_date %}
{% trans '发行日期:' %}{{ item.release_date }}
{% endif %}
</div>
<div>
{% if item.official_site %}
{% trans '官方网站:' %}{{ item.official_site|urlizetrunc:24 }}
{% endif %}
</div>
<div>
{% if item.platform %}
{% trans '平台:' %}
{% for platform in item.platform %}
<span>{{ platform }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
{% endblock %}

View file

@ -9,11 +9,7 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
<!-- class specific details -->
{% block details %}
{% endblock %}
{% block details %}{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
{% endblock %}
{% block sidebar %}{% endblock %}

View file

@ -9,325 +9,389 @@
{% load strip_scheme %}
{% load thumb %}
{% load user_actions %}
{% load duration %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="{{ site_name }}{% trans item.category.label %} - {{ item.title }}">
<meta property="og:type" content="{{ item.category }}">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
{% if item.has_cover %}
<meta property="og:image" content="{{ item.cover_image_url }}">
{% endif %}
<meta property="og:site_name" content="{{ site_name }}">
<meta property="og:description" content="{{ item.brief }}">
{% block head %}
{% endblock %}
<title>{{ site_name }} - {% trans item.category.label %} | {{ item.title }}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content">
<div class="grid">
<div class="grid__main" id="main">
<div class="main-section-wrapper">
<div class="entity-detail">
<a href="{{ item.cover.url }}" class="entity-detail__img-origin" target="_blank" rel="noopener" title="{% trans '查看原图' %}">
<img src="{{ item.cover|thumb:'normal' }}" class="entity-detail__img" alt="{{ item.title }}">
</a>
<div class="entity-detail__info">
{% if item.is_deleted %}
[DELETED]
{% endif %}
{% if item.merged_to_item %}
[MERGED <a href="{{ item.merged_to_item.url }}">{{ item.merged_to_item.title }}</a>]
{% endif %}
{% block title %}
<h5 class="entity-detail__title">
{{ item.title }}
{% for res in item.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</h5>
{% endblock %}
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>此类数据尚未支持</div>
<div>uuid: {{item.uuid}}</div>
<div>class: {{item.class_name}}</div>
<div>category: {{item.category}}</div>
</div>
{% endblock %}
<div class="tag-collection">
{% for tag in item.tags %}
<span class="tag-collection__tag">
<a href="{% url 'catalog:search' %}?tag={{ tag }}">{{ tag }}</a>
</span>
{% endfor %}
</div>
</div>
</div>
<div class="dividing-line"></div>
{% if item.brief %}
<div class="entity-desc" id="description">
<h5 class="entity-desc__title">{% trans '简介' %}</h5>
<p class="entity-desc__content">{{ item.brief | linebreaksbr }}</p>
<div class="entity-desc__unfold-button entity-desc__unfold-button--hidden">
<a href="javascript:void(0);">展开全部</a>
</div>
</div>
{% endif %}
{% block content %}
{% if item.contents %}
<div class="entity-desc" id="contents">
<h5 class="entity-desc__title">{% trans '目录' %}</h5>
<p class="entity-desc__content">{{ item.contents | linebreaksbr }}</p>
<div class="entity-desc__unfold-button entity-desc__unfold-button--hidden">
<a href="javascript:void(0);">展开全部</a>
</div>
</div>
{% endif %}
{% if item.track_list %}
<div class="entity-desc" id="description">
<h5 class="entity-desc__title">{% trans '曲目' %}</h5>
<p class="entity-desc__content">{{ item.track_list | linebreaksbr }}</p>
<div class="entity-desc__unfold-button entity-desc__unfold-button--hidden">
<a href="javascript:void(0);">展开全部</a>
</div>
</div>
{% endif %}
{% endblock %}
<div class="entity-marks">
<h5 class="entity-marks__title">{% trans '标记' %}</h5>
{% if mark_list %}
<a href="{% url 'catalog:mark_list' item.url_path item.uuid %}" class="entity-marks__more-link">{% trans '全部标记' %}</a>
<a href="{% url 'catalog:mark_list' item.url_path item.uuid 'following' %}" class="entity-marks__more-link">关注的人的标记</a>
{% endif %}
<ul class="entity-marks__mark-list">
{% for others_mark in mark_list %}
<li class="entity-marks__mark">
<a href="{% url 'journal:user_profile' others_mark.owner.mastodon_username %}" class="entity-marks__owner-link">{{ others_mark.owner.username }}</a>
<span>{{ others_mark.action_label }}</span>
{% if others_mark.rating %}
<span class="entity-marks__rating-star rating-star" data-rating-score="{{ others_mark.rating }}"></span>
{% endif %}
{% if others_mark.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
{% if others_mark.shelfmember.metadata.shared_link %}
<a href="{{ others_mark.shelfmember.metadata.shared_link }}" target="_blank" rel="noopener"><span class="entity-marks__mark-time">{{ others_mark.created_time | date }}</span></a>
{% else %}
<span class="entity-marks__mark-time">{{ others_mark.created_time | date }}</span>
{% endif %}
{% if others_mark.text %}
<p class="entity-marks__mark-content">{{ others_mark.comment_html|safe }}
<span class="action-bar inline">
<span>
{% liked_piece others_mark.shelfmember as liked %}
{% include 'like_stats.html' with liked=liked piece=others_mark.shelfmember %}
</span>
</span>
</p>
{% endif %}
</li>
{% empty %}
<div> {% trans '暂无标记' %} </div>
{% endfor %}
</ul>
</div>
<div class="entity-reviews">
<h5 class="entity-reviews__title">{% trans '评论' %}</h5>
{% if review_list %}
<a href="{% url 'catalog:review_list' item.url_path item.uuid %}" class="entity-reviews__more-link">{% trans '全部评论' %}</a>
{% endif %}
{% if review_list %}
<ul class="entity-reviews__review-list">
{% for others_review in review_list %}
<li class="entity-reviews__review">
<a href="{% url 'journal:user_profile' others_review.owner.mastodon_username %}" class="entity-reviews__owner-link">{{ others_review.owner.username }}</a>
{% if others_review.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
<span class="entity-reviews__review-time">{{ others_review.created_time | date }}</span>
<span class="entity-reviews__review-title"> <a href="{% url 'journal:review_retrieve' others_review.uuid %}">{{ others_review.title }}</a></span>
<span class="action-bar inline">
<span>
{% liked_piece others_review as liked %}
{% include 'like_stats.html' with liked=liked piece=others_review %}
</span>
</span>
<span>{{ others_review.get_plain_content | truncate:100 }}</span>
</li>
{% endfor %}
</ul>
{% else %}
<div>{% trans '暂无评论' %}</div>
{% endif %}
</div>
</div>
</div>
<div class="grid__aside" id="aside">
{% block sidebar_review %}
{% if user.is_authenticated %}
<div class="aside-section-wrapper">
{% if mark.shelf_type %}
<div class="mark-panel">
<span class="mark-panel__status">{% trans '我' %}{% trans mark.shelf_label %}</span>
{% if mark.rating %}
<span class="mark-panel__rating-star rating-star" data-rating-score="{{ mark.rating | floatformat:'0' }}"></span>
{% endif %}
{% if mark.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
<span class="mark-panel__actions">
<a href="#" hx-get="{% url 'journal:mark' item.uuid %}" class="edit" hx-target="body" hx-swap="beforeend">{% trans '修改' %}</a>
<form id="mark_delete" action="{% url 'journal:mark' item.uuid %}" method="post">
{% csrf_token %}
<input type="hidden" name="delete" value="1">
<a href="javascript:$('#mark_delete').submit()" class="delete">{% trans '删除' %}</a>
</form>
</span>
<div class="mark-panel__clear"></div>
<div class="mark-panel__time">
<!-- <div>
{% for log in mark.logs %}
{{ log.timestamp|date }} {{ log.action_label }}<br>
{% endfor %}
</div> -->
{% if mark.metadata.shared_link %}
<a href="{{ mark.metadata.shared_link }}">{{ mark.created_time|date }}</a>
{% else %}
{{ mark.created_time|date }}
{% endif %}
</div>
{% if mark.text %}
<p class="mark-panel__text">{{ mark.comment_html|safe }}</p>
{% endif %}
<div class="tag-collection">
{% for tag in mark.tags %}
<span class="tag-collection__tag"><a href="{% url 'journal:user_tag_member_list' user.mastodon_username tag %}">{{ tag }}</a></span>
{% endfor %}
</div>
</div>
{% else %}
<div class="action-panel" id="addMarkPanel">
<div class="action-panel__label">{% trans '标记' %}{% trans item.demonstrative %}</div>
<div class="action-panel__button-group">
{% for k, v in shelf_types %}
{% if v %}
<button class="action-panel__button" data-status="{{ k }}" hx-get="{% url 'journal:mark' item.uuid %}?shelf_type={{ k }}" class="edit" hx-target="body" hx-swap="beforeend">{% trans v %}</button>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
</div>
<div class="aside-section-wrapper">
<div class="review-panel action-panel">
{% if review %}
<span class="review-panel__label">{% trans '我的评论' %}</span>
{% if review.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
<span class="review-panel__actions">
<a href="{% url 'journal:review_edit' item.uuid review.uuid %}">{% trans '编辑' %}</a>
<a href="{% url 'journal:review_delete' review.uuid %}?return_url={{ item.url }}">{% trans '删除' %}</a>
</span>
<div class="review-panel__time">{{ review.edited_time }}</div>
<a href="{% url 'journal:review_retrieve' review.uuid %}" class="review-panel__review-title">
{{ review.title }}
</a>
{% else %}
<div class="action-panel__button-group action-panel__button-group--center">
<a href="{% url 'journal:review_create' item.uuid %}">
<button class="action-panel__button">{% trans '撰写评论' %}</button>
</a>
</div>
{% endif %}
</div>
</div>
{% else %}
<div class="aside-section-wrapper">
<div class="mark-panel">
<span>{% trans '登录后可管理标记和评论' %}</span>
</div>
</div>
<html lang="en" id="item-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title"
content="{{ site_name }}{% trans item.category.label %} - {{ item.title }}">
<meta property="og:type" content="{{ item.category }}">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
{% if item.has_cover %}<meta property="og:image" content="{{ item.cover_image_url }}">{% endif %}
<meta property="og:site_name" content="{{ site_name }}">
<meta property="og:description" content="{{ item.brief }}">
{% if item.is_deleted or item.merged_to_item %}<meta name="robots" content="noindex">{% endif %}
<title>{{ site_name }} - {% trans item.category.label %} | {{ item.title }}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
{% block head %}{% endblock %}
</head>
<body>
{% include "_header.html" %}
<main class="container-fluid">
<div id="item-title" class="middle">
{% if item.is_deleted %}[DELETED]{% endif %}
{% if item.merged_to_item %}
[MERGED TO <a href="{{ item.merged_to_item.url }}">{{ item.merged_to_item.title }}</a>]
{% endif %}
<h1>
{{ item.title }}
<small>
{% if item.season_number %}
{% trans '第' %}{{ item.season_number|apnumber }}{% trans '季' %}
{% endif %}
{% endblock %}
{% block sidebar %}
{% endblock %}
{% block sidebar_collection %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__label">{% trans '相关收藏单' %}</div>
<div >
{% if collection_list %}
{% for c in collection_list %}
<p>
<a href="{{ c.url }}">{{ c.title }}</a>
</p>
{% endfor %}
{% endif %}
{% if request.user.is_authenticated %}
<div class="action-panel__button-group action-panel__button-group--center">
<button class="action-panel__button add-to-list" hx-get="{% url 'journal:add_to_collection' item.uuid %}" hx-target="body" hx-swap="beforeend">{% trans '添加到收藏单' %}</button>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% if item.year %}({{ item.year }}){% endif %}
</small>
</h1>
<span class="site-list">
{% for res in item.external_resources.all %}
<a href="{{ res.url }}" class="{{ res.site_name }}">{{ res.site_name.label }}</a>
{% endfor %}
</span>
</div>
<div id="item-cover" class="left">
<img src="{{ item.cover|thumb:'normal' }}" alt="{{ item.title }}">
</div>
{% if request.user.is_authenticated and not mark.shelf_type %}
<div id="item-primary-action" class="right mark">
<div class="item-action">
{% for k, v in shelf_types %}
{% if v %}
<button class="primary"
data-status="{{ k }}"
hx-get="{% url 'journal:mark' item.uuid %}?shelf_type={{ k }}&new=1"
hx-target="body"
hx-swap="beforeend">{% trans v %}</button>
{% endif %}
{% endfor %}
</div>
</div>
</section>
</div>
{% endif %}
{% if request.user.is_authenticated and mark.shelf_type %}
<div id="item-primary-mark" class="right mark">
<div class="item-action">
<button class="outline edit"
hx-get="{% url 'journal:mark' item.uuid %}?new=1"
hx-target="body"
hx-swap="beforeend">
{{ mark.created_time | date }} {% trans mark.action_label %}
{% if mark.rating %}
<br>
{{ mark.rating | rating_star }}
<!-- <span style="white-space: nowrap;">
<i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star"></i><i class="fa-solid fa-star-half-stroke"></i><i class="fa-regular fa-star"></i>
</span> -->
{% endif %}
</button>
</div>
<div class="small-only" style="margin-top:2vh;">
<a href="#item-sidebar">标签 · 短评 · 评论 · 收藏</a>
</div>
</div>
{% endif %}
<div id="item-sidebar" class="right">
{% if request.user.is_authenticated %}
<section>
<h5>
我的标签
<small>
<a href="#"
hx-get="{% url 'journal:mark' item.uuid %}?new=1"
class="edit"
hx-target="body"
hx-swap="beforeend">
{% if mark.tags %}
<i class="fa-solid fa-pen-to-square"></i>
{% else %}
<i class="fa-regular fa-square-plus"></i>
{% endif %}
</a>
</small>
</h5>
<div class="tag-list">
{% for tag in mark.tags %}
<span>
<a href="{% url 'journal:user_tag_member_list' request.user.mastodon_username tag %}">{{ tag }}</a>
</span>
{% endfor %}
</div>
</section>
<section>
<h5>
我的短评
<small>
<a href="#"
hx-get="{% url 'journal:mark' item.uuid %}?new=1"
class="edit"
hx-target="body"
hx-swap="beforeend">
{% if mark.text %}
<i class="fa-solid fa-pen-to-square"></i>
{% else %}
<i class="fa-regular fa-square-plus"></i>
{% endif %}
</a>
</small>
</h5>
{% if mark.comment %}
<span class="action">
<span>
{% liked_piece mark.comment as liked %}
{% include 'like_stats.html' with liked=liked piece=mark.comment %}
</span>
<span>
<a target="_blank"
rel="noopener"
{% if mark.comment.metadata.shared_link %} href="{{ mark.comment.metadata.shared_link }}" title="打开联邦网络分享链接" {% else %} class="disabled" {% endif %}><i class="fa-solid {% if mark.comment.visibility > 0 %} fa-lock {% else %} fa-globe {% endif %}"></i></a>
</span>
<span class="timestamp">{{ mark.comment.created_time|date }}</span>
</span>
<p>{{ mark.comment.html|safe }}</p>
{% else %}
<!-- <span class="empty">暂无</span> -->
{% endif %}
</section>
<section>
<h5>
我的评论
<small>
{% if review %}
<a href="{% url 'journal:review_edit' item.uuid review.uuid %}">
<i class="fa-solid fa-pen-to-square"></i>
</a>
{% else %}
<a href="{% url 'journal:review_create' item.uuid %}">
<i class="fa-regular fa-square-plus"></i>
</a>
{% endif %}
</small>
</h5>
{% if review %}
<span class="action">
<span>
{% liked_piece mark.review as liked %}
{% include 'like_stats.html' with liked=liked piece=mark.review %}
</span>
<span>
<a target="_blank"
rel="noopener"
{% if mark.review.metadata.shared_link %} href="{{ mark.review.metadata.shared_link }}" title="打开联邦网络分享链接" {% else %} class="disabled" {% endif %}><i class="fa-solid {% if mark.review.visibility > 0 %} fa-lock {% else %} fa-globe {% endif %}"></i></a>
</span>
<span class="timestamp">{{ mark.review.created_time|date }}</span>
</span>
<p>
<a href="{% url 'journal:review_retrieve' review.uuid %}">{{ review.title }}</a>
</p>
{% else %}
<!-- <span class="empty">暂无</span> -->
{% endif %}
</section>
<section>
<h5>
我的收藏单
<small>
<a href="#"
hx-get="{% url 'journal:add_to_collection' item.uuid %}?new=1"
class="edit"
hx-target="body"
hx-swap="beforeend">
<i class="fa-regular fa-square-plus"></i>
</a>
</small>
</h5>
<div>
{% for c in my_collections %}
<p>
<a href="{{ c.url }}">{{ c.title }}</a>
{% if c.visibility > 0 %}<i class="fa-solid fa-lock"></i>{% endif %}
</p>
{% empty %}
<!-- <span class="empty">暂无</span> -->
{% endfor %}
</div>
</section>
<!--
<section>
<h5>标记历史</h5>
<div>
{% for log in mark.logs %}{{ log.timestamp|date }} {{ log.action_label }}<br>{% endfor %}
</div>
</section>
-->
{% else %}
<section>
<p class="empty">
<span><a href="{% url 'users:login' %}">登录</a>后可管理标记收藏</span>
</p>
</section>
{% endif %}
{% block sidebar %}{% endblock %}
{% if collection_list %}
<section>
<h5>相关收藏单</h5>
<div>
{% for c in collection_list %}
<p>
<a href="{{ c.url }}">{{ c.title }}</a>
{% if c.visibility > 0 %}<i class="fa-solid fa-lock"></i>{% endif %}
</p>
{% endfor %}
</div>
</section>
{% endif %}
</div>
<div id="item-metadata" class="left">
{% block details %}
<div>此类数据尚未支持</div>
<div>uuid: {{ item.uuid }}</div>
<div>class: {{ item.class_name }}</div>
<div>category: {{ item.category }}</div>
{% endblock %}
{% if request.user.is_authenticated %}
<div class="item-edit">
<span class="action inline">
<a href="{% url 'catalog:edit' item.url_path item.uuid %}"
title="{% trans '编辑' %}{{ item.demonstrative }}"><i class="fa-solid fa-pen-to-square"></i></a>
</span>
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<span>
{% trans '最近编辑:' %}
<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a>
</span>
{% endif %}
</div>
{% endif %}
<div class="rating{% if not item.rating %} unavailable{% endif %}">
<div class="display">
<div>
<hgroup>
<h3>
{{ item.rating | floatformat:1 }} <small>/ 10</small>
</h3>
<p>{{ item.rating_count }}人评分</p>
</hgroup>
</div>
<div data-placement="top">
<ul class="chart">
<li data-tooltip="{{ item.rating_dist.0 }}%" data-placement="left">
<span style="height:{{ item.rating_dist.0 }}%"></span>
</li>
<li data-tooltip="{{ item.rating_dist.1 }}%" data-placement="left">
<span style="height:{{ item.rating_dist.1 }}%"></span>
</li>
<li data-tooltip="{{ item.rating_dist.2 }}%" data-placement="left">
<span style="height:{{ item.rating_dist.2 }}%"></span>
</li>
<li data-tooltip="{{ item.rating_dist.3 }}%" data-placement="left">
<span style="height:{{ item.rating_dist.3 }}%"></span>
</li>
<li data-tooltip="{{ item.rating_dist.4 }}%" data-placement="left">
<span style="height:{{ item.rating_dist.4 }}%"></span>
</li>
</ul>
</div>
</div>
<div class="undisplay">
<span>评分人数不足</span>
</div>
</div>
<div class="tag-list">
{% for tag in item.tags %}
<span>
<a href="{% url 'catalog:search' %}?tag={{ tag }}">{{ tag }}</a>
</span>
{% endfor %}
</div>
{% block left_sidebar %}{% endblock %}
</div>
<div id="item-title-more" class="middle">
<hgroup>
{% if item.subtitle %}<p>{{ item.subtitle }}</p>{% endif %}
{% if item.orig_title %}
<p>
{{ item.orig_title }}
<small>
{% if item.season_number %}Season {{ item.season_number }}{% endif %}
</small>
</p>
{% endif %}
{% if item.author or item.translator %}
<p>
<i>
{% include '_people.html' with people=item.author _role='作者' max=2 %}
</i>
&nbsp;&nbsp;
<i>
{% include '_people.html' with people=item.translator role='译者' max=2 %}
</i>
</p>
{% endif %}
</hgroup>
</div>
<div id="item-detail" class="middle">
<section>
<h5>简介</h5>
{% if item.brief %}
<p class="tldr" _="on click toggle .tldr on me">{{ item.brief | linebreaksbr }}</p>
{% else %}
<p class="empty">暂缺</p>
{% endif %}
</section>
{% block content %}{% endblock %}
<section>
<h5>
短评
{% if request.user.is_authenticated %}
<small>
| <a href="{% url 'catalog:mark_list' item.url_path item.uuid %}"
class="entity-marks__more-link">{% trans '全部标记' %}</a>
| <a href="{% url 'catalog:mark_list' item.url_path item.uuid 'following' %}"
class="entity-marks__more-link">关注的人的标记</a>
</small>
{% endif %}
</h5>
{% if request.user.is_authenticated %}
<div>
<div hx-get="{% url 'catalog:comments' item.url_path item.uuid %}"
hx-trigger="intersect once"
hx-swap="outerHTML">
<i class="fa-solid fa-compact-disc fa-spin loading"></i>
</div>
</div>
{% else %}
<p class="empty">登录后可见</p>
{% endif %}
</section>
<section class="entity-reviews">
<h5>
{% trans '评论' %}
{% comment %}
{% if request.user.is_authenticated %}
<small>
| <a href="{% url 'catalog:review_list' item.url_path item.uuid %}" class="entity-marks__more-link">{% trans '全部评论' %}</a>
</small>
{% endif %}
{% endcomment %}
</h5>
{% if request.user.is_authenticated %}
<div>
<div hx-get="{% url 'catalog:reviews' item.url_path item.uuid %}"
hx-trigger="intersect once"
hx-swap="outerHTML">
<i class="fa-solid fa-compact-disc fa-spin loading"></i>
</div>
</div>
{% else %}
<p class="empty">登录后可见</p>
{% endif %}
</section>
</div>
<div id="item-more" class="middle">
<!-- test more content -->
</div>
<div style="clear: both;display: table;"></div>
</main>
{% include "partial/_footer.html" %}
</div>
</body>
</body>
</html>

View file

@ -0,0 +1,44 @@
{% load static %}
{% load i18n %}
{% load l10n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load duration %}
{% load user_actions %}
{% for comment in comments %}
{% if forloop.counter <= 10 %}
<section>
<span class="action">
<span>
{% liked_piece comment as liked %}
{% include 'like_stats.html' with liked=liked piece=comment %}
</span>
<span>
<a target="_blank"
rel="noopener"
{% if comment.metadata.shared_link %} href="{{ comment.metadata.shared_link }}" title="打开联邦网络分享链接" {% else %} class="disabled" {% endif %}><i class="fa-solid {% if comment.visibility > 0 %} fa-lock {% else %} fa-globe {% endif %}"></i></a>
</span>
<span class="timestamp">{{ comment.created_time|date }}</span>
</span>
<span>
{% if comment.rating_grade %}{{ comment.rating_grade|rating_star }}{% endif %}
<a href="{% url 'journal:user_profile' comment.owner.mastodon_username %}"
class="nickname"
title="@{{ comment.owner.mastodon_username }}">{{ comment.owner.display_name }}</a>
{{ comment.mark.action_label }}
{% if comment.focus_item %}<a href="{{ comment.focus_item.url }}">{{ comment.focus_item.title }}</a>{% endif %}
</span>
<div>{{ comment.html|safe }}</div>
</section>
{% else %}
<a hx-get="{% url 'catalog:comments' comment.item.url_path comment.item.uuid %}?last={{ comment.created_time|date:'Y-m-d H:i:s.uO'|urlencode }}"
hx-trigger="click"
hx-swap="outerHTML">
<button class="outline">显示更多</button>
</a>
{% endif %}
{% empty %}
<div class="empty">{% trans '暂无' %}</div>
{% endfor %}

View file

@ -7,108 +7,78 @@
{% load highlight %}
{% load thumb %}
{% load user_actions %}
{% load duration %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {{ item.title }}{% trans '的标记' %}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content">
<div class="grid">
<div class="grid__main" id="main">
<div class="main-section-wrapper">
<div class="entity-marks">
<h5 class="entity-marks__title entity-marks__title--stand-alone">
<a href="{% url 'catalog:retrieve' item.url_path item.uuid %}">{{ item.title }}</a>{% trans ' 的标记' %}
</h5>
<ul class="entity-marks__mark-list">
{% for others_mark in marks %}
<li class="entity-marks__mark">
<a href="{% url 'journal:user_profile' others_mark.owner.mastodon_username %}" class="entity-marks__owner-link">{{ others_mark.owner.username }}</a>
<span>{{ others_mark.mark.action_label }}</span>
{% if others_mark.mark.rating %}
<span class="entity-marks__rating-star rating-star" data-rating-score="{{ others_mark.mark.rating }}"></span>
{% endif %}
{% if others_mark.mark.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
{% if others_mark.metadata.shared_link %}
<a href="{{ others_mark.metadata.shared_link }}" target="_blank" rel="noopener"><span class="entity-marks__mark-time">{{ others_mark.mark.created_time|date }}</span></a>
{% else %}
<span class="entity-marks__mark-time">{{ others_mark.mark.created_time|date }}</span>
{% endif %}
{% if others_mark.mark.text %}
<p class="entity-marks__mark-content">{{ others_mark.mark.comment_html|safe }}
<span class="action-bar inline">
<span>
{% liked_piece others_mark as liked %}
{% include 'like_stats.html' with liked=liked piece=others_mark %}
</span>
</span>
</p>
{% endif %}
</li>
{% empty %}
<div> {% trans '暂无标记' %} </div>
{% endfor %}
</ul>
<html lang="en" class="classic-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {{ item.title }}{% trans '的标记' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include '_header.html' %}
<main>
<div class="grid__main">
<h5>
<a href="{% url 'catalog:retrieve' item.url_path item.uuid %}">{{ item.title }}</a>{% trans ' 的标记' %}
</h5>
{% for member in marks %}
{% with member.mark as mark %}
<section>
<div class="action">
{% if mark.comment %}
<span>
{% liked_piece mark.comment as liked %}
{% include 'like_stats.html' with liked=liked piece=mark.comment %}
</span>
{% endif %}
<span>
<a target="_blank"
rel="noopener"
{% if mark.metadata.shared_link %} href="{{ mark.metadata.shared_link }}" title="打开联邦网络分享链接" {% else %} class="disabled" {% endif %}><i class="fa-solid {% if mark.visibility > 0 %} fa-lock {% else %} fa-globe {% endif %}"></i></a>
</span>
<span class="timestamp">{{ mark.created_time|date }}</span>
</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>
<div>
<a href="{% url 'journal:user_profile' mark.owner.mastodon_username %}"
title="@{{ mark.owner.mastodon_username }}">{{ mark.owner.display_name }}</a>
<span>{{ mark.action_label }}</span>
{% if mark.rating_grade %}{{ mark.rating_grade|rating_star }}{% endif %}
{% if mark.comment.focus_item %}
<a href="{{ mark.comment.focus_item.url }}">{{ mark.comment.focus_item.title }}</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" id="aside">
{% include "sidebar_item.html" %}
</div>
<div>{{ mark.comment.html|safe }}</div>
</section>
{% endwith %}
{% empty %}
<div>{% trans '暂无标记' %}</div>
{% endfor %}
<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>
</section>
</div>
</div>
<div class="grid__aside" id="aside">{% include "sidebar_item.html" %}</div>
</main>
{% include "partial/_footer.html" %}
</div>
</body>
</body>
</html>

View file

@ -7,94 +7,77 @@
{% load highlight %}
{% load thumb %}
{% load user_actions %}
{% load duration %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {{ item.title }}{% trans '的评论' %}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content">
<div class="grid">
<div class="grid__main" id="main">
<div class="main-section-wrapper">
<div class="entity-reviews">
<h5 class="entity-reviews__title entity-reviews__title--stand-alone">
<a href="{{ item.url }}">{{ item.title }}</a>{% trans ' 的评论' %}
</h5>
<ul class="entity-reviews__review-list">
{% for review in reviews %}
<li class="entity-reviews__review entity-reviews__review--wider">
<a href="{% url 'journal:user_profile' review.owner.mastodon_username %}" class="entity-reviews__owner-link">{{ review.owner.username }}</a>
{% if review.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
<span class="entity-reviews__review-time">{{ review.created_time | date }}</span>
<span class="entity-reviews__review-title"><a href="{% url 'journal:review_retrieve' review.uuid %}">{{ review.title }}</a></span>
<span class="action-bar inline">
<span>
{% liked_piece review as liked %}
{% include 'like_stats.html' with liked=liked piece=review %}
</span>
</span>
</li>
{% empty %}
<div>{% trans '暂无评论' %}</div>
{% endfor %}
</ul>
</div>
<div class="pagination">
{% if reviews.pagination.has_prev %}
<a href="?page=1" class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ reviews.previous_page_number }}"
class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in reviews.pagination.page_range %}
{% if page == reviews.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 reviews.pagination.has_next %}
<a href="?page={{ reviews.next_page_number }}"
class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ reviews.pagination.last_page }}" class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>
<html lang="en" class="classic-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {{ item.title }}{% trans '的评论' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include '_header.html' %}
<main>
<div class="grid__main">
<h5>
<a href="{% url 'catalog:retrieve' item.url_path item.uuid %}">{{ item.title }}</a>{% trans ' 的评论' %}
</h5>
{% for review in reviews %}
<section>
<div class="action">
<span>
<a target="_blank"
rel="noopener"
{% if review.metadata.shared_link %} href="{{ review.metadata.shared_link }}" title="打开联邦网络分享链接" {% else %} class="disabled" {% endif %}><i class="fa-solid {% if review.visibility > 0 %} fa-lock {% else %} fa-globe {% endif %}"></i></a>
</span>
<span>
{% liked_piece review as liked %}
{% include 'like_stats.html' with liked=liked piece=review %}
</span>
<span class="timestamp">{{ review.created_time|date }}</span>
</div>
</div>
<div class="grid__aside" id="aside">
{% include "sidebar_item.html" %}
</div>
</section>
<div>
{% if review.rating_grade %}{{ review.rating_grade|rating_star }}{% endif %}
<span>
<a href="{% url 'journal:review_retrieve' review.uuid %}">{{ review.title }}</a>
</span>
-
<span>
<a href="{% url 'journal:user_profile' review.owner.mastodon_username %}"
class="nickname"
title="@{{ review.owner.mastodon_username }}">{{ review.owner.display_name }}</a>
</span>
</div>
<div>{{ review.plain_content | truncate:200 }}</div>
</section>
{% empty %}
<div>{% trans '暂无评论' %}</div>
{% endfor %}
<div class="pagination">
{% if reviews.pagination.has_prev %}
<a href="?page=1" class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ reviews.previous_page_number }}"
class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in reviews.pagination.page_range %}
{% if page == reviews.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 reviews.pagination.has_next %}
<a href="?page={{ reviews.next_page_number }}"
class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ reviews.pagination.last_page }}"
class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>
</div>
{% include "partial/_footer.html" %}
</div>
<script>
</script>
<div class="grid__aside" id="aside">{% include "sidebar_item.html" %}</div>
</main>
{% include "partial/_footer.html" %}
</body>
</html>
</html>

View file

@ -0,0 +1,49 @@
{% load static %}
{% load i18n %}
{% load l10n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load duration %}
{% load user_actions %}
{% for review in reviews %}
{% if forloop.counter <= 10 %}
<section>
<span class="action">
<span>
{% liked_piece review as liked %}
{% include 'like_stats.html' with liked=liked piece=review %}
</span>
<span>
<a target="_blank"
rel="noopener"
{% if review.metadata.shared_link %} href="{{ review.metadata.shared_link }}" title="打开联邦网络分享链接" {% else %} class="disabled" {% endif %}><i class="fa-solid {% if review.visibility > 0 %} fa-lock {% else %} fa-globe {% endif %}"></i></a>
</span>
<span class="timestamp">{{ review.created_time|date }}</span>
</span>
<span>
{% if review.rating_grade %}{{ review.rating_grade|rating_star }}{% endif %}
<a href="{% url 'journal:user_profile' review.owner.mastodon_username %}"
class="nickname"
title="@{{ review.owner.mastodon_username }}">{{ review.owner.display_name }}</a>
{{ review.mark.action_label | default:"" }}
</span>
<div>
<span>
<a href="{% url 'journal:review_retrieve' review.uuid %}">{{ review.title }}</a>
</span>
-
{{ review.plain_content | truncate:200 }}
</div>
</section>
{% else %}
<a hx-get="{% url 'catalog:reviews' review.item.url_path review.item.uuid %}?last={{ review.created_time|date:'Y-m-d H:i:s.uO'|urlencode }}"
hx-trigger="click"
hx-swap="outerHTML">
<button class="outline">显示更多</button>
</a>
{% endif %}
{% empty %}
<div class="empty">{% trans '暂无' %}</div>
{% endfor %}

View file

@ -9,164 +9,160 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block title %}
<h5 class="entity-detail__title">
{% if item.season_number %}
{{ item.title }} {% trans '第' %}{{ item.season_number|apnumber }}{% trans '季' %} {{ item.orig_title }} Season {{ item.season_number }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% else %}
{{ item.title }} {{ item.orig_title }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% endif %}
{% for res in item.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</h5>
{% endblock %}
<!-- class specific details -->
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:'0' }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating|floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.imdb %}
{% trans 'IMDb' %}<a href="https://www.imdb.com/title/{{ item.imdb }}/" target="_blank" rel="noopener">{{ item.imdb }}</a>
{% endif %}
</div>
<div>{% if item.director %}{% trans '导演:' %}
{% for director in item.director %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="director">{{ director }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.director|length > 5 %}
<a href="javascript:void(0);" id="directorMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.imdb %}
{% trans 'IMDb' %}<a href="https://www.imdb.com/title/{{ item.imdb }}/"
target="_blank"
rel="noopener">{{ item.imdb }}</a>
{% endif %}
</div>
<div>
{% if item.director %}
{% trans '导演:' %}
{% for director in item.director %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="director">{{ director }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.director|length > 5 %}
<a href="javascript:void(0);" id="directorMore">{% trans '更多' %}</a>
<script>
$("#directorMore").on('click', function (e) {
$("span.director:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.playwright %}{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="playwright">{{ playwright }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.playwright|length > 5 %}
<a href="javascript:void(0);" id="playwrightMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.playwright %}
{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="playwright">{{ playwright }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.playwright|length > 5 %}
<a href="javascript:void(0);" id="playwrightMore">{% trans '更多' %}</a>
<script>
$("#playwrightMore").on('click', function (e) {
$("span.playwright:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.actor %}{% trans '主演:' %}
{% for actor in item.actor %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="actor">{{ actor }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.actor|length > 5 %}
<a href="javascript:void(0);" id="actorMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.actor %}
{% trans '主演:' %}
{% for actor in item.actor %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="actor">{{ actor }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.actor|length > 5 %}
<a href="javascript:void(0);" id="actorMore">{% trans '更多' %}</a>
<script>
$("#actorMore").on('click', function(e) {
$("span.actor:not(:visible)").each(function(e){
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.genre %}{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.area %}{% trans '制片国家/地区:' %}
{% for area in item.area %}
<span>{{ area }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.language %}{% trans '语言:' %}
{% for language in item.language %}
<span>{{ language }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
</div>
<div class="entity-detail__fields">
<div>{% if item.duration %}{% trans '片长:' %}{{ item.duration }}{% endif %}</div>
<div>{% if item.season_count %}{% trans '季数:' %}{{ item.season_count }}{% endif %}</div>
<div>{% if item.episode_count %}{% trans '集数:' %}{{ item.episode_count }}{% endif %}</div>
<div>{% if item.single_episode_length %}{% trans '单集长度:' %}{{ item.single_episode_length }}{% endif %}</div>
<div>{% if item.showtime %}{% trans '上映时间:' %}
{% for showtime in item.showtime %}
{% for time, region in showtime.items %}
<span>{{ time }}{% if region != '' %}({{ region }}){% endif %}</span>
{% endfor %}
{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.other_title %}{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.site %}{% trans '网站:' %}
<a href="{{ item.site }}" target="_blank" rel="noopener">{{ item.site|strip_scheme }}</a>
{% endif %}</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}
<div>
{{ k }}{{ v | urlize }}
</div>
{% endfor %}
{% endif %}
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
</div>
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}
{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.area %}
{% trans '制片国家/地区:' %}
{% for area in item.area %}
<span>{{ area }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.language %}
{% trans '语言:' %}
{% for language in item.language %}
<span>{{ language }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.duration %}
{% trans '片长:' %}{{ item.duration }}
{% endif %}
</div>
<div>
{% if item.season_count %}
{% trans '季数:' %}{{ item.season_count }}
{% endif %}
</div>
<div>
{% if item.episode_count %}
{% trans '集数:' %}{{ item.episode_count }}
{% endif %}
</div>
<div>
{% if item.single_episode_length %}
{% trans '单集长度:' %}{{ item.single_episode_length }}
{% endif %}
</div>
<div>
{% if item.showtime %}
{% trans '上映时间:' %}
{% for showtime in item.showtime %}
{% for time, region in showtime.items %}
<span>{{ time }}
{% if region != '' %}({{ region }}){% endif %}
</span>
{% endfor %}
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.other_title %}
{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.site %}
{% trans '网站:' %}
<a href="{{ item.site }}" target="_blank" rel="noopener">{{ item.site|strip_scheme }}</a>
{% endif %}
</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}<div>{{ k }}{{ v|urlizetrunc:24 }}</div>{% endfor %}
{% endif %}
{% endblock %}

View file

@ -9,138 +9,121 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
<!-- class specific details -->
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating and item.rating_count >= 5 %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.other_title %}{% trans '别名:' %}
{% for other_title in item.other_title %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="other_title">{{ other_title }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.other_title|length > 5 %}
<a href="javascript:void(0);" id="otherTitleMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.other_title %}
{% trans '别名:' %}
{% for other_title in item.other_title %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="other_title">{{ other_title }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.other_title|length > 5 %}
<a href="javascript:void(0);" id="otherTitleMore">{% trans '更多' %}</a>
<script>
$("#otherTitleMore").on('click', function (e) {
$("span.other_title:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.director %}{% trans '导演:' %}
{% for director in item.director %}
<span>{{ director }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.playwright %}{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span>{{ playwright }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.actor %}{% trans '主演:' %}
{% for actor in item.actor %}
<span>{{ actor }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.choreographer %}{% trans '编舞:' %}
{% for choreographer in item.choreographer %}
<span>{{ choreographer }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.composer %}{% trans '作曲:' %}
{% for composer in item.composer %}
<span>{{ composer }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
</div>
<div class="entity-detail__fields">
<div>
{% if item.troupe %}{% trans '剧团:' %}
{% for troupe in item.troupe %}
<span>{{ troupe }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.theatre %}{% trans '剧场:' %}
{% for theatre in item.theatre %}
<span>{{ theatre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.opening_date %}{% trans '演出日期:' %}
<span>{{ item.opening_date }}</span>
{% endif %}
</div>
<div>
{% if item.version %}{% trans '版本:' %}
{% for version in item.version %}
<span>{{ version }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>{% if item.official_site %}
{% trans '官方网站:' %}{{ item.official_site|urlizetrunc:42 }}
{% endif %}
</div>
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
</div>
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}
{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.director %}
{% trans '导演:' %}
{% for director in item.director %}
<span>{{ director }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.playwright %}
{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span>{{ playwright }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.actor %}
{% trans '主演:' %}
{% for actor in item.actor %}
<span>{{ actor }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.choreographer %}
{% trans '编舞:' %}
{% for choreographer in item.choreographer %}
<span>{{ choreographer }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.composer %}
{% trans '作曲:' %}
{% for composer in item.composer %}
<span>{{ composer }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.troupe %}
{% trans '剧团:' %}
{% for troupe in item.troupe %}
<span>{{ troupe }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.theatre %}
{% trans '剧场:' %}
{% for theatre in item.theatre %}
<span>{{ theatre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.opening_date %}
{% trans '演出日期:' %}
<span>{{ item.opening_date }}</span>
{% endif %}
</div>
<div>
{% if item.version %}
{% trans '版本:' %}
{% for version in item.version %}
<span>{{ version }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.official_site %}
{% trans '官方网站:' %}{{ item.official_site|urlizetrunc:24 }}
{% endif %}
</div>
{% endblock %}

View file

@ -9,99 +9,67 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block head %}
<script src=" https://cdn.jsdelivr.net/npm/shikwasa@2.2.0/dist/shikwasa.min.js "></script>
<link href=" https://cdn.jsdelivr.net/npm/shikwasa@2.2.0/dist/style.min.css " rel="stylesheet"></link>
<script src="https://cdn.jsdelivr.net/npm/shikwasa@2.2.1/dist/shikwasa.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/shikwasa@2.2.1/dist/style.min.css"
rel="stylesheet"></link>
<script src="{% static 'podcast.js' %}"></script>
{% endblock %}
<!-- class specific details -->
{% block details %}
<style type="text/css">
.entity-detail .entity-detail__img {
height: unset !important;
}
</style>
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating and item.rating_count >= 5 %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>
{% if item.genre %}{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}
</div>
<div>{% if item.official_site %}
{% trans '网站:' %}{{ item.official_site|urlizetrunc:42 }}
{% endif %}
</div>
</div>
<div class="entity-detail__fields">
<div>{% if item.hosts %}{% trans '主播:' %}
{% for host in item.hosts %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="other_title">{{ host }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.hosts|length > 5 %}
<a href="javascript:void(0);" id="otherTitleMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.genre %}
{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.official_site %}
{% trans '网站:' %}{{ item.official_site|urlizetrunc:24 }}
{% endif %}
</div>
<div>
{% if item.hosts %}
{% trans '主播:' %}
{% for host in item.hosts %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="other_title">{{ host }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.hosts|length > 5 %}
<a href="javascript:void(0);" id="otherTitleMore">{% trans '更多' %}</a>
<script>
$("#otherTitleMore").on('click', function (e) {
$("span.other_title:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}
</div>
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
</div>
{% endblock %}
{% block content %}
<div class="entity-desc" id="episodes">
<h5 class="entity-desc__title">{% trans '近期节目' %}</h5>
<br>
<div hx-get="{% url 'catalog:episode_data' item.uuid %}" hx-trigger="load" hx-swap="outerHTML"></div>
</div>
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
<div class="aside-section-wrapper">
<div class="action-panel" id="episodes">
<div class="action-panel__button-group action-panel__button-group--center">
<button href="#" class="podlove-subscribe-button-primary action-panel__button">{% trans '用播客应用订阅' %}</button>
</div>
</script>
{% endif %}
{% endif %}
</div>
</div>
<script>
{% endblock %}
{% block content %}
<section class="entity-desc" id="episodes">
<h5 class="entity-desc__title">{% trans '近期节目' %}</h5>
<div hx-get="{% url 'catalog:episode_data' item.uuid %}"
hx-trigger="load"
hx-swap="outerHTML"></div>
</section>
{% endblock %}
<!-- class specific sidebar -->
{% block left_sidebar %}
<section>
<center>
<button href="#" class="podlove-subscribe-button-primary outline">{% trans '用播客应用订阅' %}</button>
</center>
</section>
<script>
window.podcastData = {
"title": "{{ item.title | escapejs }}",
"subtitle": "",
@ -123,6 +91,12 @@ $(()=>{
if (position) window.player._initSeek = position;
{% endif %}
});
</script>
<script class="podlove-subscribe-button" src="https://cdn.podlove.org/subscribe-button/javascripts/app.js" data-json-data="podcastData" data-buttonid="primary" data-language="en" data-hide="true" data-color="#1190C0"></script>
</script>
<script class="podlove-subscribe-button"
src="https://cdn.podlove.org/subscribe-button/javascripts/app.js"
data-json-data="podcastData"
data-buttonid="primary"
data-language="en"
data-hide="true"
data-color="#1190C0"></script>
{% endblock %}

View file

@ -3,44 +3,39 @@
{% load l10n %}
{% load humanize %}
{% for ep in episodes %}
<details>
<summary>
<h6 class="entity-desc__title">
<a
data-media="{{ ep.media_url }}"
data-cover="{{ ep.cover_url|default:item.cover.url }}"
class="episode gg-play-button-o"
href="{{ep.url}}"
data-uuid="{{ep.uuid}}"
data-title="{{ ep.title }}"
data-album = "{{ item.title }}"
data-hosts = "{{ item.hosts|join:' / ' }}"
style="top:4px;margin-right: 8px;">
</a>
{{ ep.title }}
<small style="color:lightgrey;">{{ ep.pub_date|date }}</small>
</h6>
</summary>
<p> {{ ep.brief | linebreaksbr }} </p>
</details>
<div style="margin-bottom: 8px;margin-left: 32px;">
{% if request.user.is_authenticated %}
<a class="icon" style="margin-right: 10px;" title="评论单集" href="#" hx-get="{% url 'journal:comment' item.uuid ep.uuid %}" hx-target="body" hx-swap="beforeend">
<i class="fa-regular fa-comment-dots"></i>
</a>
{% endif %}
<!-- <a class="icon" title="详细介绍" href="{{ep.link}}">
<i class="fa-solid fa-circle-info"></i>
</a> -->
<a class="icon" title="打开源网站" target="_blank" rel="noopener" href="{{ep.link}}">
<i class="fa-solid fa-arrow-up-right-from-square"></i>
</a>
</div>
{% if forloop.last %}
<button hx-get="{% url 'catalog:episode_data' item.uuid %}?last={{ ep.pub_date|date:'Y-m-d H:i:s.uO'|urlencode }}" hx-trigger="click" hx-swap="outerHTML">显示更多</button>
{% endif %}
<p>
<h6 class="entity-desc__title">
<a data-media="{{ ep.media_url }}"
data-cover="{{ ep.cover_url|default:item.cover.url }}"
class="episode gg-play-button-o"
href="{{ ep.url }}"
data-uuid="{{ ep.uuid }}"
data-title="{{ ep.title }}"
data-album="{{ item.title }}"
data-hosts="{{ item.hosts|join:' / ' }}"
style="top:4px;
margin-right: 8px"></a>
&nbsp;
{% if request.user.is_authenticated %}
<a style="margin-right: 10px"
title="评论单集"
href="#"
hx-get="{% url 'journal:comment' item.uuid ep.uuid %}"
hx-target="body"
hx-swap="beforeend"><i class="fa-regular fa-comment-dots"></i></a>
{% endif %}
<a title="打开源网站" target="_blank" rel="noopener" href="{{ ep.link }}"><i class="fa-solid fa-link"></i></a>
{{ ep.title }}
<small style="color:lightgrey;">{{ ep.pub_date|date }}</small>
</h6>
<small class="tldr-2 muted" _="on click toggle .tldr-2">{{ ep.brief | linebreaksbr }}</small>
</p>
{% if forloop.last %}
<button class="outline"
hx-get="{% url 'catalog:episode_data' item.uuid %}?last={{ ep.pub_date|date:'Y-m-d H:i:s.uO'|urlencode }}"
hx-trigger="click"
hx-swap="outerHTML">显示更多</button>
{% endif %}
{% empty %}
<div>{% trans '目前没有更多内容了' %}</div>
<div>{% trans '目前没有更多内容了' %}</div>
{% endfor %}

View file

@ -9,15 +9,18 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block head %}
<meta http-equiv="refresh" content="0;url={{ item.program.absolute_url }}?focus={{ item.uuid }}{% if request.GET.position %}&position={{ request.GET.position }}{% endif %}" />
<meta property="og:image" content="{{ item.cover_url | default:item.program.cover_image_url }}">
<meta property="twitter:image" content="{{ item.cover_url | default:item.program.cover_image_url }}">
{% if item.media_url %}
<meta property="twitter:card" content="player">
<meta property="twitter:player" content="{{ item.program.absolute_url }}/embed?focus={{ item.uuid }}{% if request.GET.position %}&position={{ request.GET.position }}{% endif %}" />
<meta property="twitter:player:width" content="300">
<meta property="twitter:player:height" content="120">
{% endif %}
<meta http-equiv="refresh"
content="0;url={{ item.program.absolute_url }}?focus={{ item.uuid }}{% if request.GET.position %}&position={{ request.GET.position }}{% endif %}" />
<meta property="og:image"
content="{{ item.cover_url | default:item.program.cover_image_url }}">
<meta property="twitter:image"
content="{{ item.cover_url | default:item.program.cover_image_url }}">
{% if item.media_url %}
<meta property="twitter:card" content="player">
<meta property="twitter:player"
content="{{ item.program.absolute_url }}/embed?focus={{ item.uuid }}{% if request.GET.position %}&position={{ request.GET.position }}{% endif %}" />
<meta property="twitter:player:width" content="300">
<meta property="twitter:player:height" content="120">
{% endif %}
{% endblock %}

View file

@ -9,94 +9,70 @@
{% load highlight %}
{% load thumb %}
<!DOCTYPE html>
<html lang="en">
<head>
<html lang="en" class="classic-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '搜索结果' %}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include 'partial/_navbar.html' %}
<section id="content">
<div class="grid">
<div class="grid__main">
<div class="main-section-wrapper">
<div class="entity-list">
{% if request.GET.q %}
<h5 class="entity-list__title">“{{ request.GET.q }}” {% trans '的搜索结果' %}</h5>
{% endif %}
{% if request.GET.tag %}
<h5 class="entity-list__title">{% trans '含有标签' %} “{{ request.GET.tag }}” {% trans '的结果' %}</h5>
{% endif %}
<ul class="entity-list__entities">
{% for item in items %}
{% with "list_item_"|add:item.class_name|add:".html" as template %}
{% include template %}
{% endwith %}
{% empty %}
<li class="entity-list__entity">
{% trans '无站内条目匹配' %}
</li>
{% endfor %}
{% if request.GET.q and user.is_authenticated %}
<li class="entity-list__entity" hx-get="{% url 'catalog:external_search' %}?q={{ request.GET.q }}&c={{ request.GET.c }}&page={% if pagination.current_page %}{{ pagination.current_page }}{% else %}1{% endif %}" hx-trigger="load" hx-swap="outerHTML">
{% trans '正在实时搜索站外条目' %}
<span><i class="fas fa-fan fa-spin"></i></span>
</li>
{% endif %}
</ul>
</div>
<div class="pagination" >
{% if pagination.has_prev %}
<a href="?page=1&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}" class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ pagination.previous_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}" class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in pagination.page_range %}
{% if page == pagination.current_page %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}" class="pagination__page-link pagination__page-link--current">{{ page }}</a>
{% else %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}" class="pagination__page-link">{{ page }}</a>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<a href="?page={{ pagination.next_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}" class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ pagination.last_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}" class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>
</div>
</div>
{% include "search_sidebar.html" %}
</div>
</section>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include '_header.html' %}
<main>
<div class="grid__main">
<div class="main-section-wrapper">
<div class="entity-list">
{% if request.GET.q %}
<h5>“{{ request.GET.q }}” {% trans '的搜索结果' %}</h5>
{% endif %}
{% if request.GET.tag %}
<h5>{% trans '含有标签' %} “{{ request.GET.tag }}” {% trans '的结果' %}</h5>
{% endif %}
<ul class="item-card-list">
{% for item in items %}
{% with "list_item_"|add:item.class_name|add:".html" as template %}
{% include template with show_tags=1 %}
{% endwith %}
{% empty %}
<li class="empty">{% trans '无站内条目匹配' %}</li>
{% endfor %}
{% if request.GET.q and user.is_authenticated %}
<li hx-get="{% url 'catalog:external_search' %}?q={{ request.GET.q }}&c={{ request.GET.c }}&page={% if pagination.current_page %}{{ pagination.current_page }}{% else %}1{% endif %}"
hx-trigger="load"
hx-swap="outerHTML">
{% trans '正在实时搜索站外条目' %}
<span><i class="fa-solid fa-compact-disc fa-spin loading"></i></span>
</li>
{% endif %}
</ul>
</div>
<div class="pagination">
{% if pagination.has_prev %}
<a href="?page=1&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ pagination.previous_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in pagination.page_range %}
{% if page == pagination.current_page %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__page-link pagination__page-link--current">{{ page }}</a>
{% else %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__page-link">{{ page }}</a>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<a href="?page={{ pagination.next_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ pagination.last_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>
</div>
{% include 'partial/_footer.html' %}
</div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
</body>
</div>
{% include "search_sidebar.html" %}
</main>
{% include 'partial/_footer.html' %}
</body>
</html>

View file

@ -1,46 +1,42 @@
{% load static %}
{% load i18n %}
{% load l10n %}
<div class="grid__aside">
<div class="aside-section-wrapper">
<div class="add-entity-entries">
<div class="add-entity-entries__entry">
<div class="add-entity-entries__label">
{% trans '没有想要的结果?' %}
</div>
<p>
如果在
{% for site in sites %}
{{ site }}
{% if not forloop.last %}/{% endif %}
{% endfor %}
找到了条目,可以在搜索栏中输入完整链接提交。
</p>
<p>
当然也可以手工创建条目。
</p>
<a href="{% url 'catalog:create' 'Edition' %}">
<button class="add-entity-entries__button">{% trans '添加书' %}</button>
</a>
<a href="{% url 'catalog:create' 'Movie' %}">
<button class="add-entity-entries__button">{% trans '添加电影' %}</button>
</a>
<a href="{% url 'catalog:create' 'TVShow' %}">
<button class="add-entity-entries__button">{% trans '添加剧集' %}</button>
</a>
<a href="{% url 'catalog:create' 'Podcast' %}">
<button class="add-entity-entries__button">{% trans '添加播客' %}</button>
</a>
<a href="{% url 'catalog:create' 'Album' %}">
<button class="add-entity-entries__button">{% trans '添加专辑' %}</button>
</a>
<a href="{% url 'catalog:create' 'Game' %}">
<button class="add-entity-entries__button">{% trans '添加游戏' %}</button>
</a>
</div>
</div>
</div>
</div>
<style>
.add-entity-entries__button {
margin: 4px;
}
</style>
<aside class="grid__aside bottom">
<article>
<div class="add-entity-entries__label">{% trans '没有想要的结果?' %}</div>
<p>
如果在
{% for site in sites %}
{{ site }}
{% if not forloop.last %}/{% endif %}
{% endfor %}
找到了条目,可以在搜索栏中输入完整链接提交。
</p>
<p>当然也可以手工创建条目:</p>
<ul>
<li>
<a href="{% url 'catalog:create' 'Edition' %}">{% trans '添加书' %}</a>
</li>
<li>
<a href="{% url 'catalog:create' 'Movie' %}">{% trans '添加电影' %}</a>
</li>
<li>
<a href="{% url 'catalog:create' 'TVShow' %}">{% trans '添加剧集' %}</a>
</li>
<li>
<a href="{% url 'catalog:create' 'Podcast' %}">{% trans '添加播客' %}</a>
</li>
<li>
<a href="{% url 'catalog:create' 'Album' %}">{% trans '添加专辑' %}</a>
</li>
<li>
<a href="{% url 'catalog:create' 'Game' %}">{% trans '添加游戏' %}</a>
</li>
</ul>
</article>
</aside>

View file

@ -2,30 +2,26 @@
{% load i18n %}
{% load truncate %}
{% load thumb %}
<div class="aside-section-wrapper">
<div class="entity-card">
<div class="entity-card__img-wrapper">
<a href="{% url 'catalog:retrieve' item.url_path item.uuid %}"><img src="{{ item.cover|thumb:'normal' }}" alt="" class="entity-card__img"></a>
</div>
<div class="entity-card__info-wrapper">
<h5 class="entity-card__title"><a href="{% url 'catalog:retrieve' item.url_path item.uuid %}">{{ item.title }}</a>
{% for res in item.external_resources.all %}
<article class="item">
<div>
<a href="{% url 'catalog:retrieve' item.url_path item.uuid %}">
<img src="{{ item.cover|thumb:'normal' }}" alt="" class="entity-card__img">
</a>
</div>
<footer>
<h4>
<a href="{% url 'catalog:retrieve' item.url_path item.uuid %}">{{ item.title }}</a>
{% for res in item.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</h5>
{% if item.isbn %}
<div>ISBN: {{ item.isbn }}</div>
{% endif %}
<div>{% if item.pub_house %}{% trans '出版社:' %}{{ item.pub_house }}{% endif %}</div>
{% if item.rating %}
{% trans '评分: ' %}<span class="entity-card__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-card__rating-score rating-score">{{ item.rating | floatformat:1 }}</span>
{% endfor %}
</h4>
{% if item.isbn %}<div>ISBN: {{ item.isbn }}</div>{% endif %}
<div>
{% if item.pub_house %}
{% trans '出版社:' %}{{ item.pub_house }}
{% endif %}
</div>
</div>
</div>
</footer>
</article>

View file

@ -9,178 +9,201 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block title %}
<h5 class="entity-detail__title">
{% if item.season_number %}
{{ item.title }} {{ item.orig_title }} Season {{ item.season_number }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% else %}
{{ item.title }} {{ item.orig_title }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% endif %}
{% for res in item.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</h5>
<h5 class="entity-detail__title">
{% if item.season_number %}
{{ item.title }} {{ item.orig_title }} Season {{ item.season_number }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% else %}
{{ item.title }} {{ item.orig_title }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% endif %}
{% for res in item.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</h5>
{% endblock %}
<!-- class specific details -->
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating and item.rating_count >= 5 %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:"0" }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.imdb %}
{% trans 'IMDb' %}<a href="https://www.imdb.com/title/{{ item.imdb }}/" target="_blank" rel="noopener">{{ item.imdb }}</a>
{% endif %}
</div>
<div>{% if item.director %}{% trans '导演:' %}
{% for director in item.director %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="director">{{ director }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.director|length > 5 %}
<a href="javascript:void(0);" id="directorMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.imdb %}
{% trans 'IMDb' %}<a href="https://www.imdb.com/title/{{ item.imdb }}/"
target="_blank"
rel="noopener">{{ item.imdb }}</a>
{% endif %}
</div>
<div>
{% if item.director %}
{% trans '导演:' %}
{% for director in item.director %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="director">{{ director }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.director|length > 5 %}
<a href="javascript:void(0);" id="directorMore">{% trans '更多' %}</a>
<script>
$("#directorMore").on('click', function (e) {
$("span.director:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.playwright %}{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="playwright">{{ playwright }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.playwright|length > 5 %}
<a href="javascript:void(0);" id="playwrightMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.playwright %}
{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="playwright">{{ playwright }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.playwright|length > 5 %}
<a href="javascript:void(0);" id="playwrightMore">{% trans '更多' %}</a>
<script>
$("#playwrightMore").on('click', function (e) {
$("span.playwright:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.actor %}{% trans '主演:' %}
{% for actor in item.actor %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="actor">{{ actor }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.actor|length > 5 %}
<a href="javascript:void(0);" id="actorMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.actor %}
{% trans '主演:' %}
{% for actor in item.actor %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="actor">{{ actor }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.actor|length > 5 %}
<a href="javascript:void(0);" id="actorMore">{% trans '更多' %}</a>
<script>
$("#actorMore").on('click', function(e) {
$("span.actor:not(:visible)").each(function(e){
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.genre %}{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.area %}{% trans '制片国家/地区:' %}
{% for area in item.area %}
<span>{{ area }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.language %}{% trans '语言:' %}
{% for language in item.language %}
<span>{{ language }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}
{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.area %}
{% trans '制片国家/地区:' %}
{% for area in item.area %}
<span>{{ area }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.language %}
{% trans '语言:' %}
{% for language in item.language %}
<span>{{ language }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.season_number %}
{% trans '本季序号:' %}{{ item.season_number }}
{% endif %}
</div>
<div>
{% if item.episode_count %}
{% trans '本季集数:' %}{{ item.episode_count }}
{% endif %}
</div>
<div></div>
<div>
{% if item.show %}
{% trans '所属剧集:' %}<a href="{{ item.show.url }}">{{ item.show.title }}
{% endif %}
</a>
</div>
<div class="entity-detail__fields">
<div>{% if item.season_number %}{% trans '本季序号:' %}{{ item.season_number }}{% endif %}</div>
<div>{% if item.episode_count %}{% trans '本季集数:' %}{{ item.episode_count }}{% endif %}</div>
<div> </div>
<div>{% if item.show %}{% trans '所属剧集:' %}<a href="{{ item.show.url }}">{{ item.show.title }}{% endif %}</a></div>
<div>{% if item.season_count %}{% trans '总季数:' %}{{ item.season_count }}{% endif %}</div>
<div>{% if item.single_episode_length %}{% trans '单集长度:' %}{{ item.single_episode_length }}{% endif %}</div>
{% with item.all_seasons as seasons %}
{% if seasons %}
<div>
{% trans '本剧所有季:' %}
{% for s in seasons %}
<span>
<a href="{{ s.url }}">{{ s.season_number }}</a>
</span>
<div>
{% if item.season_count %}
{% trans '总季数:' %}{{ item.season_count }}
{% endif %}
</div>
<div>
{% if item.single_episode_length %}
{% trans '单集长度:' %}{{ item.single_episode_length }}
{% endif %}
</div>
{% with item.all_seasons as seasons %}
{% if seasons %}
<div>
{% trans '本剧所有季:' %}
{% for s in seasons %}
<span>
<a href="{{ s.url }}">{{ s.season_number }}</a>
</span>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<div>
{% if item.showtime %}
{% trans '上映时间:' %}
{% for showtime in item.showtime %}
{% for time, region in showtime.items %}
<span>{{ time }}
{% if region != '' %}({{ region }}){% endif %}
</span>
{% endfor %}
{% if not forloop.last %}/{% endif %}
{% endfor %}
</div>
{% endif %}
{% endwith %}
<div>{% if item.showtime %}{% trans '上映时间:' %}
{% for showtime in item.showtime %}
{% for time, region in showtime.items %}
<span>{{ time }}{% if region != '' %}({{ region }}){% endif %}</span>
{% endfor %}
{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.other_title %}{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.site %}{% trans '网站:' %}
<a href="{{ item.site }}" target="_blank" rel="noopener">{{ item.site|strip_scheme }}</a>
{% endif %}</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}
<div>
{{ k }}{{ v | urlize }}
</div>
{% endfor %}
{% endif %}
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
</div>
{% endif %}
</div>
<div>
{% if item.other_title %}
{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.site %}
{% trans '网站:' %}
<a href="{{ item.site }}" target="_blank" rel="noopener">{{ item.site|strip_scheme }}</a>
{% endif %}
</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}<div>{{ k }}{{ v|urlizetrunc:24 }}</div>{% endfor %}
{% endif %}
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
{% endblock %}
{% block sidebar %}{% endblock %}

View file

@ -9,179 +9,167 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
{% block title %}
<h5 class="entity-detail__title">
{% if item.season_number %}
{{ item.title }} {% trans '第' %}{{ item.season_number|apnumber }}{% trans '季' %} {{ item.orig_title }} Season {{ item.season_number }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% else %}
{{ item.title }} {{ item.orig_title }}
<span class="entity-detail__title entity-detail__title--secondary">
{% if item.year %}({{ item.year }}){% endif %}
</span>
{% endif %}
{% for res in item.external_resources.all %}
<a href="{{ res.url }}">
<span class="source-label source-label__{{ res.site_name }}">{{ res.site_name.label }}</span>
</a>
{% endfor %}
</h5>
{% endblock %}
<!-- class specific details -->
{% block details %}
<div class="entity-detail__fields">
<div class="entity-detail__rating">
{% if item.rating and item.rating_count >= 5 %}
<span class="entity-detail__rating-star rating-star" data-rating-score="{{ item.rating | floatformat:0 }}"></span>
<span class="entity-detail__rating-score"> {{ item.rating | floatformat:1 }} </span>
<small>({{ item.rating_count }}人评分)</small>
{% else %}
<span> {% trans '评分:评分人数不足' %}</span>
{% endif %}
</div>
<div>{% if item.imdb %}
{% trans 'IMDb' %}<a href="https://www.imdb.com/title/{{ item.imdb }}/" target="_blank" rel="noopener">{{ item.imdb }}</a>
{% endif %}
</div>
<div>{% if item.director %}{% trans '导演:' %}
{% for director in item.director %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="director">{{ director }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.director|length > 5 %}
<a href="javascript:void(0);" id="directorMore">{% trans '更多' %}</a>
<script>
<div>
{% if item.imdb %}
{% trans 'IMDb' %}<a href="https://www.imdb.com/title/{{ item.imdb }}/"
target="_blank"
rel="noopener">{{ item.imdb }}</a>
{% endif %}
</div>
<div>
{% if item.director %}
{% trans '导演:' %}
{% for director in item.director %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="director">{{ director }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.director|length > 5 %}
<a href="javascript:void(0);" id="directorMore">{% trans '更多' %}</a>
<script>
$("#directorMore").on('click', function (e) {
$("span.director:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.playwright %}{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span {% if forloop.counter > 5 %}style="display: none;" {% endif %}>
<span class="playwright">{{ playwright }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.playwright|length > 5 %}
<a href="javascript:void(0);" id="playwrightMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.playwright %}
{% trans '编剧:' %}
{% for playwright in item.playwright %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="playwright">{{ playwright }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.playwright|length > 5 %}
<a href="javascript:void(0);" id="playwrightMore">{% trans '更多' %}</a>
<script>
$("#playwrightMore").on('click', function (e) {
$("span.playwright:not(:visible)").each(function (e) {
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.actor %}{% trans '主演:' %}
{% for actor in item.actor %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="actor">{{ actor }}</span>
{% if not forloop.last %} / {% endif %}
</span>
{% endfor %}
{% if item.actor|length > 5 %}
<a href="javascript:void(0);" id="actorMore">{% trans '更多' %}</a>
<script>
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.actor %}
{% trans '主演:' %}
{% for actor in item.actor %}
<span {% if forloop.counter > 5 %}style="display: none;"{% endif %}>
<span class="actor">{{ actor }}</span>
{% if not forloop.last %}/{% endif %}
</span>
{% endfor %}
{% if item.actor|length > 5 %}
<a href="javascript:void(0);" id="actorMore">{% trans '更多' %}</a>
<script>
$("#actorMore").on('click', function(e) {
$("span.actor:not(:visible)").each(function(e){
$(this).parent().removeAttr('style');
});
$(this).remove();
})
</script>
{% endif %}
{% endif %}</div>
<div>{% if item.genre %}{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.area %}{% trans '制片国家/地区:' %}
{% for area in item.area %}
<span>{{ area }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.language %}{% trans '语言:' %}
{% for language in item.language %}
<span>{{ language }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
</div>
<div class="entity-detail__fields">
<div>{% if item.season_count %}{% trans '季数:' %}{{ item.season_count }}{% endif %}</div>
<div>{% if item.episode_count %}{% trans '集数:' %}{{ item.episode_count }}{% endif %}</div>
<div>{% if item.single_episode_length %}{% trans '单集长度:' %}{{ item.single_episode_length }}{% endif %}</div>
{% with item.all_seasons as seasons %}
{% if seasons %}
<div>
{% trans '本剧所有季:' %}
{% for s in seasons %}
<span>
<a href="{{ s.url }}">{{ s.season_number }}</a>
</span>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<div>{% if item.showtime %}{% trans '播出时间:' %}
{% for showtime in item.showtime %}
{% for time, region in showtime.items %}
<span>{{ time }}{% if region != '' %}({{ region }}){% endif %}</span>
{% endfor %}
{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.other_title %}{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>{% if not forloop.last %} / {% endif %}
{% endfor %}
{% endif %}</div>
<div>{% if item.site %}{% trans '网站:' %}
<a href="{{ item.site }}" target="_blank" rel="noopener">{{ item.site|strip_scheme }}</a>
{% endif %}</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}
<div>
{{ k }}{{ v | urlize }}
</div>
{% endfor %}
{% endif %}
{% if item.last_editor and item.last_editor.preference.show_last_edit %}
<div>{% trans '最近编辑者:' %}<a href="{% url 'journal:user_profile' item.last_editor.mastodon_username %}">{{ item.last_editor | default:"" }}</a></div>
{% endif %}
<div>
{% if user.is_authenticated %}
<a href="{% url 'catalog:edit' item.url_path item.uuid %}">{% trans '编辑' %}{{ item.demonstrative }}</a>
{% endif %}
{% if user.is_staff %}
/<a href="{% url 'catalog:delete' item.url_path item.uuid %}"> {% trans '删除' %}</a>
{% endif %}
</div>
</div>
{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
</script>
{% endif %}
{% endif %}
</div>
<div>
{% if item.genre %}
{% trans '类型:' %}
{% for genre in item.genre %}
<span>{{ genre }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.area %}
{% trans '制片国家/地区:' %}
{% for area in item.area %}
<span>{{ area }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.language %}
{% trans '语言:' %}
{% for language in item.language %}
<span>{{ language }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.season_count %}
{% trans '季数:' %}{{ item.season_count }}
{% endif %}
</div>
<div>
{% if item.episode_count %}
{% trans '集数:' %}{{ item.episode_count }}
{% endif %}
</div>
<div>
{% if item.single_episode_length %}
{% trans '单集长度:' %}{{ item.single_episode_length }}
{% endif %}
</div>
{% with item.all_seasons as seasons %}
{% if seasons %}
<div>
{% trans '本剧所有季:' %}
{% for s in seasons %}
<span>
<a href="{{ s.url }}">{{ s.season_number }}</a>
</span>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<div>
{% if item.showtime %}
{% trans '播出时间:' %}
{% for showtime in item.showtime %}
{% for time, region in showtime.items %}
<span>{{ time }}
{% if region != '' %}({{ region }}){% endif %}
</span>
{% endfor %}
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.other_title %}
{% trans '又名:' %}
{% for t in item.other_title %}
<span>{{ t }}</span>
{% if not forloop.last %}/{% endif %}
{% endfor %}
{% endif %}
</div>
<div>
{% if item.site %}
{% trans '网站:' %}
<a href="{{ item.site }}" target="_blank" rel="noopener">{{ item.site|strip_scheme }}</a>
{% endif %}
</div>
{% if item.other_info %}
{% for k, v in item.other_info.items %}<div>{{ k }}{{ v|urlizetrunc:24 }}</div>{% endfor %}
{% endif %}
{% endblock %}

View file

@ -9,11 +9,7 @@
{% load truncate %}
{% load strip_scheme %}
{% load thumb %}
<!-- class specific details -->
{% block details %}
{% endblock %}
{% block details %}{% endblock %}
<!-- class specific sidebar -->
{% block sidebar %}
{% endblock %}
{% block sidebar %}{% endblock %}

View file

@ -72,10 +72,24 @@ urlpatterns = [
recast,
name="recast",
),
re_path(
r"^(?P<item_path>"
+ _get_all_url_paths()
+ ")/(?P<item_uuid>[A-Za-z0-9]{21,22})/comments",
comments,
name="comments",
),
re_path(
r"^(?P<item_path>"
+ _get_all_url_paths()
+ ")/(?P<item_uuid>[A-Za-z0-9]{21,22})/reviews",
reviews,
name="reviews",
),
re_path(
r"^(?P<item_path>"
+ _get_all_url_paths()
+ ")/(?P<item_uuid>[A-Za-z0-9]{21,22})/review_list",
review_list,
name="review_list",
),

View file

@ -11,7 +11,7 @@ from django.core.paginator import Paginator
from catalog.common.models import ExternalResource, IdealIdTypes
from .models import *
from django.views.decorators.clickjacking import xframe_options_exempt
from journal.models import Mark, ShelfMember, Review, query_item_category
from journal.models import Mark, ShelfMember, Review, Comment, query_item_category
from journal.models import (
query_visible,
query_following,
@ -85,32 +85,28 @@ def retrieve(request, item_path, item_uuid):
)
mark = None
review = None
mark_list = None
review_list = None
my_collections = []
collection_list = []
shelf_types = [(n[1], n[2]) for n in iter(ShelfTypeNames) if n[0] == item.category]
if request.user.is_authenticated:
visible = query_visible(request.user)
mark = Mark(request.user, item)
review = mark.review
my_collections = item.collections.all().filter(owner=request.user)
collection_list = (
item.collections.all()
.exclude(owner=request.user)
.filter(visible)
.annotate(like_counts=Count("likes"))
.order_by("-like_counts")
)
mark_query = (
ShelfMember.objects.filter(item=item)
.filter(visible)
.order_by("-created_time")
else:
collection_list = (
item.collections.all()
.filter(visibility=0)
.annotate(like_counts=Count("likes"))
.order_by("-like_counts")
)
mark_list = [member.mark for member in mark_query[:NUM_REVIEWS_ON_ITEM_PAGE]]
review_list = (
Review.objects.filter(item=item)
.filter(visible)
.order_by("-created_time")[:NUM_REVIEWS_ON_ITEM_PAGE]
)
return render(
request,
item.class_name + ".html",
@ -119,8 +115,7 @@ def retrieve(request, item_path, item_uuid):
"focus_item": focus_item,
"mark": mark,
"review": review,
"mark_list": mark_list,
"review_list": review_list,
"my_collections": my_collections,
"collection_list": collection_list,
"shelf_types": shelf_types,
},
@ -273,7 +268,7 @@ def episode_data(request, item_uuid):
if request.GET.get("last"):
qs = qs.filter(pub_date__lt=request.GET.get("last"))
return render(
request, "podcast_episode_data.html", {"item": item, "episodes": qs[:10]}
request, "podcast_episode_data.html", {"item": item, "episodes": qs[:5]}
)
@ -326,27 +321,62 @@ def review_list(request, item_path, item_uuid):
@login_required
def comments(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not item:
raise Http404()
queryset = Comment.objects.filter(item=item).order_by("-created_time")
queryset = queryset.filter(query_visible(request.user))
before_time = request.GET.get("last")
if before_time:
queryset = queryset.filter(created_time__lte=before_time)
return render(
request,
"item_comments.html",
{
"comments": queryset[:11],
},
)
@login_required
def reviews(request, item_path, item_uuid):
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
if not item:
raise Http404()
queryset = Review.objects.filter(item=item).order_by("-created_time")
queryset = queryset.filter(query_visible(request.user))
before_time = request.GET.get("last")
if before_time:
queryset = queryset.filter(created_time__lte=before_time)
return render(
request,
"item_reviews.html",
{
"reviews": queryset[:11],
},
)
def discover(request):
if request.method != "GET":
raise BadRequest()
user = request.user
if user.is_authenticated:
layout = user.get_preference().discover_layout
top_tags = user.tag_manager.all_tags[:10]
else:
layout = []
top_tags = []
cache_key = "public_gallery_list"
cache_key = "public_gallery"
gallery_list = cache.get(cache_key, [])
for gallery in gallery_list:
ids = (
random.sample(gallery["item_ids"], 10)
if len(gallery["item_ids"]) > 10
else gallery["item_ids"]
)
gallery["items"] = Item.objects.filter(id__in=ids)
# for gallery in gallery_list:
# ids = (
# random.sample(gallery["item_ids"], 10)
# if len(gallery["item_ids"]) > 10
# else gallery["item_ids"]
# )
# gallery["items"] = Item.objects.filter(id__in=ids)
if user.is_authenticated:
podcast_ids = [
@ -355,41 +385,39 @@ def discover(request):
ShelfType.PROGRESS, ItemCategory.Podcast
)
]
episodes = PodcastEpisode.objects.filter(program_id__in=podcast_ids).order_by(
"-pub_date"
)[:5]
gallery_list.insert(
0,
{
"name": "my_recent_podcasts",
"title": "在听播客的近期更新",
"items": episodes,
},
recent_podcast_episodes = PodcastEpisode.objects.filter(
program_id__in=podcast_ids
).order_by("-pub_date")[:10]
books_in_progress = Edition.objects.filter(
id__in=[
p.item_id
for p in user.shelf_manager.get_members(
ShelfType.PROGRESS, ItemCategory.Book
).order_by("-created_time")[:10]
]
)
# books = Edition.objects.filter(
# id__in=[
# p.item_id
# for p in user.shelf_manager.get_members(
# ShelfType.PROGRESS, ItemCategory.Book
# ).order_by("-created_time")[:10]
# ]
# )
# gallery_list.insert(
# 0,
# {
# "name": "my_books_inprogress",
# "title": "正在读的书",
# "items": books,
# },
# )
tvshows_in_progress = Item.objects.filter(
id__in=[
p.item_id
for p in user.shelf_manager.get_members(
ShelfType.PROGRESS, ItemCategory.TV
).order_by("-created_time")[:10]
]
)
else:
recent_podcast_episodes = []
books_in_progress = []
tvshows_in_progress = []
return render(
request,
"discover.html",
{
"user": user,
"top_tags": top_tags,
"gallery_list": gallery_list,
"recent_podcast_episodes": recent_podcast_episodes,
"books_in_progress": books_in_progress,
"tvshows_in_progress": tvshows_in_progress,
"layout": layout,
},
)

View file

@ -26,6 +26,5 @@
.wday, .month {
font-variant: small-caps;
color: #222222;
font-size: 12px;
}

View file

@ -180,8 +180,8 @@ div.jsoneditor-menu {
}
.donut {
margin-left: 20%;
width: 60%;
margin-left: 10%;
width: 80%;
aspect-ratio : 1 / 1;
border-radius: 50%;
display: flex;
@ -198,7 +198,7 @@ div.jsoneditor-menu {
justify-content: center;
}
progress {
/* progress {
border-radius: 7px;
width: 80%;
height: 10px;
@ -209,7 +209,7 @@ progress {
}
::-webkit-progress-value {
background-color: #00a1cc;
}
} */
.markdownx-editor {
font-family: monospace;
@ -266,6 +266,6 @@ summary::-webkit-details-marker {
transform: rotate(360deg);
}
.fa-lock, .fa-spin {
.action-bar .fa-lock, .fa-spin {
color: lightgray;
}

View file

@ -167,7 +167,7 @@
// Fixed size with width= 721 and height = 110
var wire_html =
'<svg width="721" height="110">' +
'<svg width="700" height="100">' +
'<g transform="translate(0, 20)">' +
loop_html +
'</g>' + '"Your browser does not support inline SVG."' +

View file

@ -0,0 +1,15 @@
@mixin clear
content: ' '
clear: both
display: table
// Breakpoints
// Small devices (landscape phones, 576px and up)
$small-devices: 575.98px
// Medium devices (tablets, 768px and up)
$medium-devices: 767.98px
// Large devices (desktops, 992px and up)
$large-devices: 991.98px
// Extra large devices (large desktops, 1200px and up)
$x-large-devices: 1199.98px

View file

@ -0,0 +1,48 @@
div.item {
display: grid;
grid-template-columns:
calc(4rem * var(--pico-line-height)) auto;
column-gap: var(--pico-block-spacing-horizontal);
align-items: top;
justify-content: left;
word-break: break-all;
&.player {
display: block;
}
hgroup {
margin: 0;
}
h5 small,
hgroup span {
font-weight: 400;
font-size: 80%;
color: var(--pico-muted-color);
&.category {
opacity: 0.5;
}
}
.metadata {
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
font-size: 80%;
}
.brief {
text-overflow: ellipsis;
word-wrap: break-word;
overflow: hidden;
-webkit-line-clamp: 4;
display: -webkit-box;
-webkit-box-orient: vertical;
font-size: 80%;
}
}

View file

@ -0,0 +1,25 @@
#collection-page {
@media (max-width: 768px) {
main>article>header {
display: flex;
flex-flow: column nowrap;
#collection-cover {
img {
height: 20vw;
}
height: unset !important;
order: -1;
}
#collection-feature {
order: 99;
.donut {
display: none;
}
}
}
}
}

View file

@ -0,0 +1,95 @@
body {
--pico-block-spacing-vertical: var(--pico-block-spacing-horizontal);
}
article.item-card {
padding: calc(var(--pico-block-spacing-horizontal));
margin-bottom: calc(var(--pico-block-spacing-vertical) / 2);
header,
footer {
padding: calc(var(--pico-block-spacing-horizontal) / 2);
}
section {
margin-bottom: calc(var(--pico-spacing) / 1);
}
}
article.item-card.external h5 {
font-style: italic;
}
details {
margin: 0;
}
section section {
margin-bottom: var(--pico-spacing) !important;
}
.empty {
font-style: italic;
font-size: 80%;
color: var(--pico-muted-color);
}
.oneline {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.handler {
color: var(--pico-muted-color);
word-break: break-all;
opacity: 0.5;
}
.loading {
color: var(--pico-muted-color);
opacity: 0.5;
}
.action {
width: max-content;
float: right;
&.inline {
float: none;
}
>span {
padding-left: calc(var(--pico-spacing)/2);
}
a {
cursor: pointer;
text-decoration: none;
}
a.hidden {
display: none;
}
a.disabled,
.timestamp {
cursor: unset;
color: var(--pico-muted-color);
opacity: 0.5;
}
a:not(:hover) {
color: var(--pico-muted-color);
opacity: 0.5;
}
a.activated:not(:hover) {
color: var(--pico-primary);
opacity: 1;
}
}
form img {
max-height: 20vh;
}

View file

@ -0,0 +1,103 @@
dialog {
header {
margin-bottom: 16px;
padding: 8px !important;
}
&>article {
/* Animate when opening */
animation-name: zoomIn;
animation-duration: 150ms;
animation-timing-function: ease;
}
&.closing {
/* Animate when closing */
animation-name: fadeOut;
animation-duration: 150ms;
animation-timing-function: ease;
}
&.closing>article {
/* Aniate when closing */
animation-name: zoomOut;
animation-duration: 150ms;
animation-timing-function: ease;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes zoomIn {
0% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
@keyframes zoomOut {
0% {
transform: scale(1);
}
100% {
transform: scale(0.9);
}
}
.grid>div {
min-width: max-content;
}
.grid>div:nth-child(2) fieldset {
float: right;
}
@media (max-width: 768px) {
.grid>div:nth-child(2) fieldset {
float: unset;
}
}
fieldset {
margin: 0;
}
article {
padding-bottom: 1em;
}
input[type="date"] {
margin: 0px;
}
.tag-input {
margin-bottom: var(--pico-spacing);
}
.rating-editor {
font-size: 120%;
padding-bottom: 1em;
}
}

View file

@ -0,0 +1,63 @@
.feed-page {
.feed {
.avatar {
height: calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 4 - 8px);
width: calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 4 - 8px);
img {
height: 100%;
width: 100%;
}
}
section {
margin-bottom: 2vh;
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto;
grid-column-gap: 1em;
grid-row-gap: 0px;
// align-items: center;
// justify-content: left;
.nickname a {
word-break: break-all;
}
.time {
width: max-content;
float: right;
color: var(--pico-muted-color);
opacity: 0.5;
margin-left: 1em;
}
.rating-star {
margin: 0 0.5em;
}
.rating-star,
.rating-star>* {
color: var(--pico-primary);
}
article {
padding: calc(var(--pico-block-spacing-horizontal) / 2);
footer {
padding: calc(var(--pico-block-spacing-horizontal) / 2);
margin-left: calc(var(--pico-block-spacing-horizontal) * -0.5);
margin-right: calc(var(--pico-block-spacing-horizontal) * -0.5);
margin-top: 0;
}
margin-right: 4px;
}
.spacing {
margin-bottom: var(--pico-block-spacing-horizontal);
}
}
}
}

View file

@ -0,0 +1,120 @@
.calendar_view {
overflow-x: scroll;
svg {
height: 108px;
}
}
.shelf {
max-width: 1400px;
padding: 0;
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.cards {
display: grid;
grid-auto-columns: 100%;
grid-column-gap: var(--pico-block-spacing-horizontal);
grid-auto-flow: column;
padding: var(--pico-nav-link-spacing-vertical) 0px;
list-style: none;
overflow-x: scroll;
scroll-snap-type: x mandatory;
&::-webkit-scrollbar {
height: var(--pico-nav-link-spacing-vertical);
}
&::-webkit-scrollbar-thumb,
&::-webkit-scrollbar-track {
border-radius: 92px;
}
&::-webkit-scrollbar-thumb {
background: var(--pico-range-active-border-color);
}
&::-webkit-scrollbar-track {
background: var(--pico-range-border-color);
}
}
.card {
display: flex;
flex-direction: column;
padding: 0px;
// border-radius: 5px;
scroll-snap-align: start;
transition: all 0.2s;
text-align: center;
vertical-align: middle;
a {
margin-top: auto;
}
img {
background: var(--pico-background-color);
// border-radius: 5px;
width: 100%;
min-height: 3rem;
vertical-align: middle;
margin: auto;
font-size: 80%;
border: 2px solid transparent;
}
a:hover img {
border: 2px solid var(--pico-primary-hover);
}
a>div {
font-size: 80%;
text-overflow: ellipsis;
word-wrap: break-word;
overflow: hidden;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
min-height: 2.5rem;
}
}
@media (min-width: 200px) {
.cards {
grid-auto-columns: calc(25% - var(--pico-block-spacing-horizontal));
}
}
@media (min-width: 500px) {
.cards {
grid-auto-columns: calc(20% - var(--pico-block-spacing-horizontal));
}
}
@media (min-width: 769px) {
.cards {
grid-auto-columns: calc(calc(100% / 6) - var(--pico-block-spacing-horizontal));
}
}
@media (min-width: 1281px) {
.cards {
grid-auto-columns: calc(calc(100% / 8) - var(--pico-block-spacing-horizontal));
}
}
}
@media (min-width: 769px) {
.sidebar .shelf .cards {
grid-auto-columns: calc(34% - var(--pico-spacing)) !important;
gap: var(--pico-spacing) !important;
}
}

View file

@ -0,0 +1,220 @@
body>header {
padding: 0px !important;
}
.nav-logo {
margin-left: 8px !important;
}
.nav-dropdown {
margin-right: 8px !important;
}
.nav-dropdown ul li a {
padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal) !important
}
nav form {
margin-bottom: 0px !important;
}
nav summary {
border: 0px !important;
}
nav ul {
min-width: -webkit-max-content;
min-width: -moz-max-content;
}
nav ul li a.current {
font-weight: bold;
color: var(--pico-primary);
}
.nav-search,
.nav-search li {
width: 100%;
}
.nav-search select {
max-width: max-content;
}
.nav-search input[type="submit"] {
background-color: var(--pico-secondary-background);
border-color: var(--pico-secondary-background);
padding-left: calc(var(--pico-nav-link-spacing-horizontal)*2);
padding-right: calc(var(--pico-nav-link-spacing-horizontal)*2);
}
.nav-logo img {
max-height: 56px;
}
.unhide {
display: unset !important;
}
.nav-dropdown summary {
padding-top: 0px !important;
padding-bottom: 0px !important;
}
.nav-dropdown summary::after {
height: calc(1rem * var(--pico-line-height, 1.5) + 8px) !important;
}
.avatar {
line-height: 0;
/* remove line-height */
display: inline-block;
/* circle wraps image */
border: 4px solid lightgray;
border-radius: 50%;
/* relative value */
transition: linear 0.25s;
}
.avatar img {
border-radius: 50%;
height: calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 2 - 8px);
width: calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 2 - 8px);
}
.avatar:hover {
transition: ease-out 0.2s;
border: 4px solid var(--pico-primary);
-webkit-transition: ease-out 0.2s;
}
@media (max-width: 1200px) {
:root {
--pico-font-size: 80%;
}
}
@media (min-width: 769px) {
.small-only {
display: none;
}
}
@media (max-width: 768px) {
:root {
--pico-font-size: 100%;
}
.large-only {
display: none;
}
body>header {
position: sticky;
top: 0px;
background: var(--pico-background-color);
z-index: 999;
box-shadow: var(--pico-box-shadow);
}
nav {
display: flex;
flex-flow: row wrap;
}
.nav-logo img {
max-height: 28px;
}
.nav-search {
order: 999;
display: none;
}
.nav-search li {
padding: 0px;
padding-bottom: 4px;
}
.nav-search input[type="submit"] {
padding-left: calc(var(--pico-nav-link-spacing-horizontal)*1);
padding-right: calc(var(--pico-nav-link-spacing-horizontal)*1);
}
.nav-dropdown::after {
flex-basis: 100%;
width: 0;
}
.nav-dropdown {
margin-right: 0 !important;
}
}
/* Dark color scheme (Auto) */
/* Automatically enabled if user has Dark mode enabled */
@media only screen and (prefers-color-scheme: dark) {
.nav-logo img {
filter: brightness(100%) grayscale(100%) invert(40%);
}
}
/* Dark color scheme (Forced) */
/* Enabled if forced with data-theme="dark" */
.nav-logo img [data-theme="dark"] {
filter: brightness(100%) grayscale(100%) invert(40%);
}
.tldr {
overflow: hidden;
text-overflow: " ... [点击展开]";
display: -webkit-box;
-webkit-line-clamp: 10;
-webkit-box-orient: vertical;
}
.tldr-2 {
overflow: hidden;
text-overflow: " ... [点击展开]";
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.hidden {
display: none;
}
.invisible {
visibility: hidden;
}
a:not(:hover) {
text-decoration: none;
}
body>footer {
padding-top: 0.4em !important;
text-align: center;
margin-bottom: 4px !important;
width: 100%;
.footer__border {
width: 100%;
padding-top: 4px;
}
.footer__link {
margin: 0 12px;
white-space: nowrap;
min-width: 15vw;
}
@media (min-width: 769px) {
clear: both;
position: absolute !important;
left: 50%;
transform: translateX(-50%);
}
}

View file

@ -0,0 +1,165 @@
#item-page {
a:not(:hover) {
text-decoration: none;
}
.muted {
color: var(--pico-muted-color);
}
.muted a:not(:hover) {
color: var(--pico-muted-color);
}
.muted .fa-lock {
filter: brightness(50%) !important;
}
a>button {
padding: 2px 8px;
font-size: 75%;
}
main>div {
margin: 2vw;
}
main>div>section {
margin-bottom: 2vw;
}
#item-title {
margin-bottom: 0;
}
#item-title-more {
margin-top: 0;
}
#item-title h1 {
margin: 0;
}
h1 small {
font-size: 80%;
margin-left: 0.5vw;
font-weight: 400;
}
#item-cover {
align-items: stretch;
}
#item-cover img {
transition: transform 0.2s ease-in-out;
filter: drop-shadow(0 0.2rem 0.8rem rgba(0, 0, 0, 0.2));
max-width: 80%;
max-height: 50vh;
}
.item-edit,
.item-edit a {
color: var(--pico-muted-color);
}
.item-action {
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: center;
margin-top: 5%;
}
.item-action button {
margin-left: 4px;
margin-right: 4px;
}
.mark {
text-align: center;
}
#item-cover {
text-align: center;
}
main {
padding-top: 1vh !important;
}
@media (min-width: 769px) {
#item-title h1 {
display: inline;
}
.middle {
margin: auto;
width: 50%;
}
.left {
float: left;
clear: left;
width: 22%;
margin-left: 0;
margin-right: 3%;
}
.right {
float: right;
clear: right;
width: 22%;
margin-left: 3%;
margin-right: 0%;
}
}
@media (max-width: 768px) {
main {
display: flex;
flex-flow: column nowrap;
}
#item-title {
order: -5;
display: flex;
flex-flow: column nowrap;
}
#item-title .site-list {
order: -1;
}
#item-title-more {
order: -4;
}
#item-cover {
order: -3;
}
#item-primary-action {
order: -2;
}
#item-primary-mark {
order: -2;
}
#item-metadata {
order: -1;
}
#item-sidebar {
order: 99;
}
#item-cover img {
max-width: 60vw;
}
}
}

View file

@ -0,0 +1,144 @@
.classic-page,
.feed-page {
main {
width: 100vw;
display: grid;
grid-template-columns: 64% 32%;
grid-template-areas: "main aside";
gap: 4%;
padding: calc(3*var(--pico-spacing));
.grid__main {
grid-area: main;
}
.grid__aside {
grid-area: aside;
}
}
@media (max-width: 768px) {
main {
display: flex;
flex-flow: column nowrap;
padding: 0;
gap: 0;
.grid__main {
order: -1;
margin: var(--pico-spacing);
}
.grid__aside {
order: -2;
}
ul {
padding: 0;
}
aside.bottom {
order: 2 !important;
}
}
}
}
.content-page {
article {
margin: 0;
}
main {
display: grid;
grid-template-columns: auto 25%;
grid-template-areas: "main aside";
gap: calc(3*var(--pico-spacing));
padding: calc(3*var(--pico-spacing));
&>div {
grid-area: main;
}
&>aside {
grid-area: aside;
article>div {
text-align: center;
}
}
}
.owner-info {
height: max-content;
display: flex;
flex-direction: row;
gap: var(--pico-spacing);
.owner {
.avatar {
width: calc(2rem * var(--pico-line-height));
height: calc(2rem * var(--pico-line-height));
img {
width: 100%;
height: 100%;
}
}
}
.info {
width: 70%;
}
.more {
width: 20%;
}
}
@media (max-width: 768px) {
main {
display: flex;
max-width: 100%;
flex-flow: column nowrap;
padding: 0;
gap: 0;
>div {
order: 1;
// margin: var(--pico-spacing);
}
>aside {
order: 2;
article.item {
display: grid;
grid-template-columns: 25% auto;
grid-template-areas: "main aside";
margin: calc(var(--pico-spacing)/2);
padding: 0;
border: var(--pico-border-width) solid var(--pico-card-border-color);
>* {
margin: 0;
border: 0;
}
>div {
margin-left: var(--pico-spacing);
background-color: var(--pico-card-sectioning-background-color);
align-items: center;
display: flex;
}
}
}
ul {
padding: 0;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,191 @@
/*** django-jsoneditor ***/
div.jsoneditor {
border-color: #ccc !important;
}
div.jsoneditor-menu {
background-color: #606c76 !important;
border-color: #606c76 !important;
}
/***** MODAL DIALOG ****/
#modal {
/* Underlay covers entire screen. */
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
/* Flexbox centers the .modal-content vertically and horizontally */
display: flex;
flex-direction: column;
align-items: center;
/* Animate when opening */
animation-name: fadeIn;
animation-duration: 150ms;
animation-timing-function: ease;
}
#modal>.modal-underlay {
/* underlay takes up the entire viewport. This is only
required if you want to click to dismiss the popup */
position: absolute;
z-index: -1;
}
#modal>.modal-content {
/* Position visible dialog near the top of the window */
margin-top: 10vh;
/* Sizing for visible dialog */
width: 80%;
max-width: 600px;
/* Display properties for visible dialog*/
background-color: #f7f7f7;
padding: 20px 20px 10px 20px;
color: #606c76;
/* Animate when opening */
animation-name: zoomIn;
animation-duration: 150ms;
animation-timing-function: ease;
}
#modal.closing {
/* Animate when closing */
animation-name: fadeOut;
animation-duration: 150ms;
animation-timing-function: ease;
}
#modal.closing>.modal-content {
/* Aniate when closing */
animation-name: zoomOut;
animation-duration: 150ms;
animation-timing-function: ease;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes zoomIn {
0% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
@keyframes zoomOut {
0% {
transform: scale(1);
}
100% {
transform: scale(0.9);
}
}
#modal .add-to-list-modal__head {
margin-bottom: 20px;
}
#modal .add-to-list-modal__head::after {
content: ' ';
clear: both;
display: table;
}
#modal .add-to-list-modal__title {
font-weight: bold;
font-size: 1.2em;
float: left;
}
#modal .add-to-list-modal__close-button {
float: right;
cursor: pointer;
}
#modal .add-to-list-modal__confirm-button {
float: right;
}
#modal li,
#modal ul,
#modal label {
display: inline;
}
.donut {
margin-left: 10%;
width: 80%;
aspect-ratio: 1 / 1;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.donut .hole {
width: 80%;
aspect-ratio: 1 / 1;
border-radius: 50%;
background: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
}
input:invalid#position {
border: red dashed 1px;
}
.gg-play-button-o {
box-sizing: border-box;
position: relative;
display: inline-block;
transform: scale(var(--ggs, 1));
width: 22px;
height: 22px;
border: 2px solid;
border-radius: 20px
}
.gg-play-button-o::before {
content: "";
display: inline-block;
box-sizing: border-box;
position: absolute;
width: 0;
height: 10px;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 6px solid;
top: 4px;
left: 7px
}

View file

@ -0,0 +1,72 @@
.login-page {
input:invalid {
border: var(--pico-primary) dashed 2px;
}
mark {
padding: 0;
}
.autoComplete_wrapper>ul {
padding: 0;
}
.autoComplete_wrapper>ul li {
list-style: none;
padding: 0 var(--pico-spacing);
}
.autoComplete_wrapper>ul>li:hover {
cursor: pointer;
background-color: var(--pico-text-selection-color);
}
.autoComplete_wrapper>ul>li[aria-selected="true"] {
background-color: var(--pico-text-selection-color);
}
article {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: max-content;
width: 50%;
height: max-content;
p {
max-width: 50vw;
}
}
header img {
padding: 10%;
}
html,
body {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
@media (max-width: 768px) {
article {
width: 96%;
p {
max-width: 96vw;
}
}
}
body>footer {
color: lightgrey;
text-align: center;
bottom: 0px;
position: fixed;
width: 100%;
padding: 0;
}
}

View file

@ -0,0 +1,68 @@
#mark_date {
width: unset !important;
}
.tag-input {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
border-bottom: 0.1rem solid #ccc;
padding-bottom: 2px;
}
.tag-input__tag {
position: relative;
display: block;
float: left;
color: white;
background: #d5d5d5;
padding: 5px 20px 5px 6px;
margin: 4px;
border-radius: .4rem;
line-height: 1em;
-webkit-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
height: min-content;
}
.tag-input__tag.tag-input__tag--highlight {
color: white;
background: #00a1cc;
}
.tag-input__close {
position: absolute;
top: 0;
right: 0;
width: 14px;
height: 100%;
cursor: pointer;
border-radius: 0 2px 2px 0;
-webkit-transition: background 0.2s;
transition: background 0.2s;
}
.tag-input__close:after {
position: absolute;
content: "×";
top: 5px;
left: 2px;
}
.tag-input__close:hover {
color: #606c76;
}
.tag-input input {
border: 0;
margin: 4px;
padding: 3px 7px 3px 0;
width: auto;
outline: none;
height: unset;
}

View file

@ -0,0 +1,31 @@
.spoiler {
background: grey;
filter: blur(2px);
cursor: pointer;
&.revealed {
background: unset;
filter: unset;
color: inherit;
}
}
.markdown-content {
h1 {
font-size: 1.5rem
}
h2 {
font-size: 1.25rem
}
h3 {
font-size: 1.1rem;
}
}
.markdownx-editor {
font-family: monospace;
}

View file

@ -0,0 +1,133 @@
.rating {
margin-top: 2vh;
margin-bottom: 2vh;
position: relative;
}
.rating * {
margin: 0;
padding: 0;
}
.rating h3 small {
font-weight: 200;
}
.rating .display {
display: flex;
flex: row;
vertical-align: bottom;
}
.rating .display div {
align-items: center;
justify-content: center;
display: flex;
}
.rating .display div:nth-child(1) {
width: max-content;
padding-right: 12px;
}
.rating .display div:nth-child(2) {
flex-grow: 100;
}
.rating .chart {
flex-grow: 100;
display: table;
table-layout: fixed;
height: max-content;
}
.rating .chart li {
position: relative;
display: table-cell;
vertical-align: bottom;
height: 6vh;
}
.rating .chart span {
margin: 2%;
display: block;
background: var(--pico-muted-color);
border-radius: 0.5vh 0.5vh 0 0;
}
.rating .undisplay {
position: absolute;
display: none;
align-items: center;
justify-content: center;
inset: 0;
}
.rating.unavailable .undisplay {
display: flex;
}
.rating.unavailable .display {
filter: blur(0.5vh);
}
.rating.unavailable .chart li:nth-child(1) span {
height: 10% !important;
}
.rating.unavailable .chart li:nth-child(2) span {
height: 20% !important;
}
.rating.unavailable .chart li:nth-child(3) span {
height: 30% !important;
}
.rating.unavailable .chart li:nth-child(4) span {
height: 40% !important;
}
.rating.unavailable .chart li:nth-child(5) span {
height: 50% !important;
}
// Rating Star with Font Awesome
.rating-star {
position: relative;
vertical-align: middle;
font-family: FontAwesome;
display: inline-block;
}
.rating-star:before {
content: "\f006 \f006 \f006 \f006 \f006";
text-underline-offset: 0.125em;
line-height: 1;
vertical-align: middle;
}
.rating-star>div {
position: absolute;
left: 0;
top: 0;
white-space: nowrap;
overflow: hidden;
}
.rating-star>div:before {
content: "\f005 \f005 \f005 \f005 \f005";
text-underline-offset: 0.125em;
line-height: 1;
vertical-align: middle;
}
.rating-star .yellow {
color: #F68127;
text-shadow: 0 0 1px #FFE205, 0 0 2px #FFE205, 0 0 6px #EDD205;
// color: #FFE205;
}
.rating-editor {
cursor: pointer !important;
border: none !important;
}

View file

@ -0,0 +1,84 @@
.sidebar {
article {
padding: calc(var(--pico-block-spacing-horizontal));
}
details {
margin-bottom: 0;
}
hgroup {
margin: 0;
margin-right: 1rem;
}
section.announcement {
p {
font-size: 80%;
}
// details[open]>summary {
// margin: 0;
// }
details {
margin-bottom: var(--pico-spacing);
}
}
section.profile {
summary>div {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto;
grid-column-gap: 0.5em;
grid-row-gap: 0px;
// align-items: center;
// justify-content: left;
}
summary::after {
position: relative;
bottom: calc(2rem * var(--pico-line-height));
}
a:hover {
text-decoration: none;
}
.avatar {
height: calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 4);
width: calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 4);
img {
height: 100%;
width: 100%;
}
}
.nickname {
word-break: break-all;
}
.relation {
width: max-content;
float: right;
color: var(--pico-muted-color);
opacity: 0.5;
margin-left: 1em;
}
}
@media (max-width: 768px) {
section,
article,
details {
margin-bottom: 0;
}
}
}

View file

@ -0,0 +1,115 @@
.site-list {
a {
display: inline;
background: transparent;
padding: calc(var(--pico-spacing)/8);
border-radius: calc(var(--pico-spacing)/4);
border-style: solid;
border-width: 1px;
font-size: 80%;
margin: 3px;
// padding: 1px 3px;
// padding-top: 2px;
font-weight: lighter;
word-break: keep-all;
opacity: 1;
font-weight: 400;
text-decoration: none;
white-space: nowrap;
}
.douban {
border: none;
color: white;
background-color: #319840;
}
.spotify {
background-color: #1ed760;
color: black;
border: none;
font-weight: bold;
}
.imdb {
background-color: #F5C518;
color: #121212;
border: none;
font-weight: bold;
}
.igdb {
background-color: #323A44;
color: #DFE1E2;
border: none;
font-weight: bold;
}
.steam {
background: linear-gradient(30deg, #1387b8, #111d2e);
color: white;
border: none;
// font-weight: 600
// padding-top: 2px
}
.bangumi {
background: #F09199;
color: #FCFCFC;
font-weight: 600;
}
.goodreads {
background: #F4F1EA;
color: #372213;
font-weight: lighter;
}
.bookstw {
background: #7FBA19;
color: white;
font-weight: lighter;
}
.tmdb {
background: linear-gradient(90deg, #91CCA3, #1FB4E2);
color: white;
border: none;
font-weight: lighter;
padding-top: 2px;
}
.googlebooks {
color: white;
background-color: #4285F4;
border-color: #4285F4;
}
.rss {
color: white;
background-color: #E1A02F;
border-color: #E1A02F;
}
.bandcamp {
color: white;
background-color: #28A0C1;
}
// .bandcamp {
// color: white
// background-color: #28A0C1
// // transform: skewX(-30deg)
// display: inline-block
// }
// .bandcamp span
// // transform: skewX(30deg)
// display: inline-block
// margin: 0 4px
.discogs {
color: white;
background-color: #262626;
border-color: #262626;
}
}

View file

@ -0,0 +1,20 @@
.tag-list {
// margin-bottom: var(--pico-spacing);
span {
// margin: 3px;
a {
color: white;
background: var(--pico-muted-color);
padding: calc(var(--pico-spacing)/4);
border-radius: calc(var(--pico-spacing)/4);
line-height: 1.2em;
font-size: 80%;
margin: 3px !important;
text-decoration: none;
white-space: nowrap;
display: inline-block;
}
}
}

View file

@ -0,0 +1,18 @@
@import '_header.scss';
@import '_dialog.scss';
@import '_rating.scss';
@import '_mark.scss';
@import '_item.scss';
@import '_layout.scss';
@import '_sitelabel.scss';
@import '_tag.scss';
@import '_markdown.scss';
@import '_legacy.sass';
@import '_legacy2.scss';
@import '_collection.scss';
@import '_feed.scss';
@import '_card.scss';
@import '_gallery.scss';
@import '_sidebar.scss';
@import '_common.scss';
@import '_login.scss';

View file

@ -8,33 +8,23 @@
{% 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 }} - {% trans '无效请求' %}</title>
{% include "common_libs.html" with jquery=0 %}
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div class="box">
<a href="{% url 'common:home' %}">
<img src="{% static 'img/logo.svg' %}" alt="logo" class="logo">
</a>
<div class="main-msg">
无效的请求
</div>
<div class="sec-msg">
{{ exception }}
您可能提交了无效的数据,或者相关内容已被作者删除。如果您确信这是我们的错误,欢迎通过页面底部的链接联系。
</div>
</div>
</div>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '无效请求' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include "_header.html" %}
<main class="container">
<article class="error">
<header>
<h3>🤦🏻 无效的请求</h3>
</header>
{{ exception }}
您可能提交了无效的数据,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
</article>
</main>
{% include "partial/_footer.html" %}
</div>
</body>
</body>
</html>

View file

@ -8,32 +8,23 @@
{% 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 }} - {% trans '权限不符' %}</title>
{% include "common_libs.html" with jquery=0 %}
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div class="box">
<a href="{% url 'common:home' %}">
<img src="{% static 'img/logo.svg' %}" alt="logo" class="logo">
</a>
<div class="main-msg">
权限不符
</div>
<div class="sec-msg">
您可能访问了错误的网址,或者相关内容已被作者隐藏。如果您确信这是我们的错误,欢迎通过页面底部的链接联系。
</div>
</div>
</div>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '权限不符' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include "_header.html" %}
<main class="container">
<article class="error">
<header>
<h3>🤦🏻 权限不符</h3>
</header>
{{ exception }}
您可能访问了错误的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
</article>
</main>
{% include "partial/_footer.html" %}
</div>
</body>
</body>
</html>

View file

@ -8,32 +8,22 @@
{% 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 }} - {% trans '未找到' %}</title>
{% include "common_libs.html" with jquery=0 %}
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div class="box">
<a href="{% url 'common:home' %}">
<img src="{% static 'img/logo.svg' %}" alt="logo" class="logo">
</a>
<div class="main-msg">
请求条目未找到
</div>
<div class="sec-msg">
您可能输入了一个无效的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,欢迎通过页面底部的链接联系。
</div>
</div>
</div>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '未找到' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include "_header.html" %}
<main class="container">
<article class="error">
<header>
<h3>🤦🏻 条目未找到</h3>
</header>
您可能输入了一个无效的网址,或者相关内容已被作者删除。如果您确信这是我们的错误,请通过页面底部的链接联系我们。
</article>
</main>
{% include "partial/_footer.html" %}
</div>
</body>
</body>
</html>

View file

@ -8,32 +8,22 @@
{% 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 }} - {% trans '系统错误' %}</title>
{% include "common_libs.html" with jquery=0 %}
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div class="box">
<a href="{% url 'common:home' %}">
<img src="{% static 'img/logo.svg' %}" alt="logo" class="logo">
</a>
<div class="main-msg">
系统内部错误
</div>
<div class="sec-msg">
发生了一个内部错误,如果这个错误多次出现,后台会记录并会由人工处理。如果您有紧急情况或疑问,欢迎通过页面底部的链接联系。
</div>
</div>
</div>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - {% trans '系统错误' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include "_header.html" %}
<main class="container">
<article class="error">
<header>
<h3>🤦🏻 系统内部错误</h3>
</header>
发生了一个内部错误,如果这个错误多次出现,后台会记录并会由人工处理。如果您有紧急情况或任何疑问,请通过页面底部的链接联系我们。
</article>
</main>
{% include "partial/_footer.html" %}
</div>
</body>
</body>
</html>

View file

@ -1,22 +1,25 @@
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>☃ NeoDB 升级中...</title>
</head>
<body>
<div class="pl">
<div class="pl__outer-ring"></div>
<div class="pl__inner-ring"><center>NeoDB 升级中...</center></div>
<div class="pl__track-cover"></div>
<div class="pl__ball">
<div class="pl__ball-texture"></div>
<div class="pl__ball-outer-shadow"></div>
<div class="pl__ball-inner-shadow"></div>
<div class="pl__ball-side-shadows"></div>
</div>
</div>
<style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>☃ NeoDB 升级中...</title>
</head>
<body>
<div class="pl">
<div class="pl__outer-ring"></div>
<div class="pl__inner-ring">
<center>NeoDB 升级中...</center>
</div>
<div class="pl__track-cover"></div>
<div class="pl__ball">
<div class="pl__ball-texture"></div>
<div class="pl__ball-outer-shadow"></div>
<div class="pl__ball-inner-shadow"></div>
<div class="pl__ball-side-shadows"></div>
</div>
</div>
<style>
* {
border: 0;
box-sizing: border-box;
@ -205,7 +208,7 @@ center {
transform: rotate(360deg);
}
}
</style>
<!-- CSS from https://jonkantner.com -->
</body>
</style>
<!-- CSS from https://jonkantner.com -->
</body>
</html>

View file

@ -0,0 +1,103 @@
{% load admin_url %}
{% load static %}
{% load i18n %}
<header class="container-fluid">
<nav>
<ul class="nav-logo">
<a href="{% url 'common:home' %}">
<img src="{% static 'img/logo.svg' %}" alt="" />
</a>
</ul>
<ul class="nav-search">
<li>
<form role="search" method="get" action="{% url 'catalog:search' %}">
<input type="search"
name="q"
placeholder="搜索标题、创作者、ISBN、链接(如 https://movie.douban.com/subject/1297880/ )"
class="search"
value="{{ request.GET.q|default:'' }}" />
<select name="c">
<option value="all">全部</option>
<option {% if request.GET.c and request.GET.c == 'book' or '/book/' in request.path %}selected{% endif %}
value="book">书籍</option>
<option {% if request.GET.c and request.GET.c == 'movietv' or '/movie/' in request.path or '/tv/' in request.path %}selected{% endif %}
value="movietv">影视</option>
<option {% if request.GET.c and request.GET.c == 'podcast' or '/podcast/' in request.path %}selected{% endif %}
value="podcast">播客</option>
<option {% if request.GET.c and request.GET.c == 'music' or '/album/' in request.path %}selected{% endif %}
value="music">音乐</option>
<option {% if request.GET.c and request.GET.c == 'game' or '/game/' in request.path %}selected{% endif %}
value="game">游戏</option>
</select>
<input type="submit" value="&#xf002;" class="fa-solid" />
</form>
</li>
</ul>
<ul>
<li class="small-only">
<a _="on click toggle .unhide on .nav-search">搜索</a>
</li>
<li>
<a class="{% if current == 'discover' %}current{% endif %}"
href="{% url 'catalog:discover' %}">发现</a>
</li>
<li>
<a class="{% if current == 'timeline' %}current{% endif %}"
href="{% url 'social:feed' %}">动态</a>
</li>
<li class="large-only">
<a class="{% if current == 'home' %}current{% endif %}"
href="{% url 'common:me' %}">个人</a>
</li>
</ul>
<ul class="nav-dropdown">
<li>
<details class="dropdown">
<summary aria-haspopup="listbox">
<span class="avatar">
<img alt=""
src="{% if request.user.is_authenticated %}{{ request.user.mastodon_account.avatar }}{% else %}data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=={% endif %}" />
</span>
</summary>
<ul role="listbox" style="min-width:-webkit-max-content;" dir="rtl">
{% if request.user.is_authenticated %}
<li class="small-only">
<a class="{% if current == 'home' %}current{% endif %}"
href="{% url 'common:me' %}">个人主页</a>
</li>
<li>
<a href="{% url 'users:data' %}">数据</a>
</li>
<li>
<a href="{% url 'users:preferences' %}">设置</a>
</li>
<li>
<a href="{% url 'users:logout' %}">登出</a>
</li>
{% if request.user.is_superuser %}
<li>
<a href="{% admin_url %}">后台</a>
</li>
{% endif %}
{% else %}
<li>
<a href="{% url 'users:login' %}?next={{ request.path }}">登录</a>
</li>
{% endif %}
</ul>
</details>
</li>
</ul>
</nav>
</header>
{% if messages %}
<div class="main-section-wrapper"
style="margin-bottom: 10px;
text-align:center">
<ul class="messages">
{% for message in messages %}
<li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
</div>
{% endif %}

View file

@ -0,0 +1,215 @@
{% load static %}
{% load i18n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load thumb %}
{% load collection %}
{% load bleach_tags %}
<aside class="grid__aside sidebar">
{% if request.user.unread_announcements %}
<section class="announcement">
<article>
<h5>
未读公告
<small> | <a href="{% url 'management:list' %}">全部</a> </small>
</h5>
{% for ann in request.user.unread_announcements %}
<details open>
<summary>
{{ ann.title }}
<small>(<a href="{% url 'management:retrieve' ann.pk %}">{{ ann.created_time|date }}</a>)</small>
</summary>
<div class="tldr" _="on click toggle .tldr on me">{{ ann.get_html_content | safe }}</div>
</details>
{% endfor %}
<form action="{% url 'users:mark_announcements_read' %}" method="post">
{% csrf_token %}
<input type="submit" class="secondary outline" value="{% trans '全部标为已读' %}">
</form>
</article>
</section>
{% endif %}
{% if show_profile %}
<section class="profile">
<article>
<details class="auto-collapse" open>
<summary>
<div>
<div class="avatar">
<a href="{% url 'journal:user_profile' user.mastodon_username %}">
<img src="{{ user.mastodon_account.avatar }}" alt="">
</a>
</div>
<div>
<hgroup>
<h6 class="nickname">{{ user.display_name }}</h6>
<div>
<a href="{{ user.mastodon_account.url }}" target="_blank" rel="noopener">
<span class="handler">@{{ user.mastodon_username }}</span>
</a>
{% current_user_relationship user as relationship %}
{% if relationship %}<span>{{ relationship }}</span>{% endif %}
</div>
</hgroup>
</div>
</div>
</summary>
<p class="user-profile__bio mast-brief">{{ user.mastodon_account.note|bleach:"a,p,span,br" }}</p>
{% if request.user != user %}
<span class="action">
<small>
<a href="{% url 'users:report' %}?user_id={{ user.id }}"
class="user-profile__report-link">{% trans '投诉用户' %}</a>
</small>
</span>
{% endif %}
</details>
</article>
</section>
{% endif %}
{% if show_progress %}
<section>
<article>
<details {% if user.featured_collections.all %}open{% endif %}>
<summary>{% trans '当前目标' %}</summary>
{% for featured_collection in user.featured_collections.all %}
{% user_visibility_of featured_collection as visible %}
{% if visible %}
{% user_stats_of collection=featured_collection user=user as stats %}
<div>
<a href="{{ featured_collection.collection.url }}">{{ featured_collection.collection.title }}</a> <small>{{ stats.complete }} / {{ stats.total }}</small>
<br>
<progress value="{{ stats.percentage }}" max="100" />
</div>
{% endif %}
{% empty %}
{% if request.user == user %}
<div class="empty">将自己或他人的收藏单设为目标,这里就会显示进度</div>
{% else %}
<div class="empty">暂未设置目标</div>
{% endif %}
{% endfor %}
</details>
</article>
</section>
{% endif %}
{% if recent_podcast_episodes %}
<section>
<article>
<details class="auto-collapse" open>
<summary>{% trans '在听播客的近期单集' %}</summary>
<div class="shelf">
<ul class="cards">
{% for item in recent_podcast_episodes %}
<li class="card">
<a class="episode"
data-uuid="{{ item.uuid }}"
data-media="{{ item.media_url }}"
data-cover="{{ item.cover_url|default:item.program.cover.url }}"
data-title="{{ item.title }}"
data-album="{{ item.program.title }}"
data-hosts="{{ item.program.hosts|join:' / ' }}"
data-position="0"
href="{{ item.url }}"
title="{{ item.title }}">
<img src="{{ item.cover_image_url | default:item.cover.url }}"
alt="{{ item.title }}"
loading="lazy">
<div class="card-title">
<i class="fa-solid fa-circle-play"></i> {{ item.title }}
</div>
</a>
</li>
{% endfor %}
</ul>
</div>
</details>
</article>
</section>
{% endif %}
{% if books_in_progress %}
<section>
<article>
<details class="auto-collapse" open>
<summary>{% trans '在读的书' %}</summary>
<div class="shelf">
<ul class="cards">
{% for item in books_in_progress %}
<li class="card">
<a href="{{ item.url }}" title="{{ item.title }}">
<img src="{{ item.cover|thumb:'normal' }}"
alt="{{ item.title }}"
loading="lazy">
<div class="card-title">{{ item.title }}</div>
</a>
</li>
{% endfor %}
</ul>
</div>
</details>
</article>
</section>
{% endif %}
{% if tvshows_in_progress %}
<section>
<article>
<details class="auto-collapse" open>
<summary>{% trans '在看的剧集' %}</summary>
<div class="shelf">
<ul class="cards">
{% for item in tvshows_in_progress %}
<li class="card">
<a href="{{ item.url }}" title="{{ item.title }}">
<img src="{{ item.cover|thumb:'normal' }}"
alt="{{ item.title }}"
loading="lazy">
<div class="card-title">{{ item.title }}</div>
</a>
</li>
{% endfor %}
</ul>
</div>
</details>
</article>
</section>
{% endif %}
{% if top_tags %}
<section>
<article>
<details {% if top_tags %}class="auto-collapse" open{% endif %}>
<summary>{% trans '常用标签' %}</summary>
<div class="tag-list">
{% for t in top_tags %}
<span>
<a href="{% url 'journal:user_tag_member_list' user.mastodon_username t %}">{{ t }}</a>
</span>
{% empty %}
<div class="empty">暂无可见标签</div>
{% endfor %}
</div>
<small>
{% if top_tags %}
<a href="{% url 'journal:user_tag_list' user.mastodon_username %}">...{% trans '全部' %}</a>
{% endif %}
</small>
</details>
</article>
</section>
{% endif %}
</aside>
<script>
$(function () {
function _sidebar_auto_collapse(mm){
if (mm.matches) {
$('.auto-collapse').removeAttr('open')
} else {
$('.auto-collapse').attr('open', '')
}
}
var mm = window.matchMedia("(max-width: 768px)")
mm.addListener(_sidebar_auto_collapse);
_sidebar_auto_collapse(mm);
});
</script>

View file

@ -1,24 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css" integrity="sha512-JArlzA682ixxKlWoGxYQxF+vHv527K1/NMnGbMxZERWr/16D7ZlPZUdq9+n5cA3TM030G57bSXYdN706FU9doQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>{{ api.title }} API Documentation</title>
{% include "common_libs.html" with jquery=0 %}
<style type="text/css">
<html lang="en">
<head>
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css"
integrity="sha512-JArlzA682ixxKlWoGxYQxF+vHv527K1/NMnGbMxZERWr/16D7ZlPZUdq9+n5cA3TM030G57bSXYdN706FU9doQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer" />
<title>{{ api.title }} API Documentation</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
<style type="text/css">
.information-container {
display: none;
}
</style>
</head>
<body>
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<div id="swagger-ui">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-bundle.min.js" integrity="sha512-8FFvTCXo6KgUt72SMpgMgMHoHnNUOPxndku0/mc+B98qIeEfZ6dpPDYJv6a1TRWHoEZeMQAKQzcwSmQixM9v2w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
</style>
</head>
<body>
{% include "_header.html" %}
<div id="swagger-ui" class="container"></div>
{% include "partial/_footer.html" %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui-bundle.min.js"
integrity="sha512-8FFvTCXo6KgUt72SMpgMgMHoHnNUOPxndku0/mc+B98qIeEfZ6dpPDYJv6a1TRWHoEZeMQAKQzcwSmQixM9v2w=="
crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<script>
const ui = SwaggerUIBundle({
url: '{{ openapi_json_url }}',
dom_id: '#swagger-ui',
@ -27,15 +31,14 @@
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: "BaseLayout",
{% if api.csrf and csrf_token %}
{% if api.csrf and csrf_token %}
requestInterceptor: (req) => {
req.headers['X-CSRFToken'] = "{{csrf_token}}"
return req;
},
{% endif %}
{% endif %}
deepLinking: true
})
</script>
</div>
</body>
</script>
</body>
</html>

View file

@ -1,32 +1,29 @@
{% load i18n %}
{% load static %}
{% load i18n %}
{% load l10n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load thumb %}
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="5;url={% if url %}{{url}}{% else %}{% url 'common:home' %}{% endif %}">
<link rel="stylesheet" href="https://cdn.staticfile.org/milligram/1.4.1/milligram.min.css">
<link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}">
<link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}">
<title>{% trans '错误' %}</title>
</head>
<body>
<div class="box">
<a href="{% url 'common:home' %}">
<img src="{% static 'img/logo.svg' %}" alt="logo" class="logo">
</a>
<div class="main-msg">
{{ msg }}
</div>
<div class="sec-msg">
{% if secondary_msg %}
{{ secondary_msg }}
{% endif %}
</div>
</div>
</body>
<title>{{ site_name }} - {% trans '错误' %}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include "_header.html" %}
<main class="container">
<article class="error">
<header>
<h3>🙅🏻 {{ msg }}</h3>
</header>
{{ secondary_msg|default:"" }}
</article>
</main>
{% include "partial/_footer.html" %}
</body>
</html>

View file

@ -6,41 +6,39 @@
{% load truncate %}
{% load thumb %}
<div id="modals">
<style>
<style>
.bottom-link {
margin-top: 30px; text-align: center; margin-bottom: 5px;
}
.bottom-link a {
color: #ccc;
}
</style>
<div class="announcement-modal modal">
<div class="announcement-modal__head">
<h4 class="announcement-modal__title">{% trans '公告' %}</h4>
<span class="announcement-modal__close-button modal-close">
<i class="fa-solid fa-xmark"></i>
</span>
</div>
<div class="announcement-modal__body">
<ul>
{% for ann in request.user.unread_announcements %}
<li class="announcement">
<a href="{% url 'management:retrieve' ann.pk %}">
<h5 class="announcement__title">{{ ann.title }}</h5>
</a>
<span class="announcement__datetime">{{ ann.created_time }}</span>
<p class="announcement__content">{{ ann.get_plain_content | truncate:200 }}</p>
</li>
{% if not forloop.last %}
<div class="dividing-line" style="border-top-style: dashed;"></div>
{% endif %}
{% endfor %}
</ul>
<div class="bottom-link">
<a href="{% url 'management:list' %}">{% trans '查看全部公告' %}</a>
</div>
</div>
</style>
<div class="announcement-modal modal">
<div class="announcement-modal__head">
<h4 class="announcement-modal__title">{% trans '公告' %}</h4>
<span class="announcement-modal__close-button modal-close">
<i class="fa-solid fa-xmark"></i>
</span>
</div>
<div class="announcement-modal__body">
<ul>
{% for ann in request.user.unread_announcements %}
<li class="announcement">
<a href="{% url 'management:retrieve' ann.pk %}">
<h5 class="announcement__title">{{ ann.title }}</h5>
</a>
<span class="announcement__datetime">{{ ann.created_time }}</span>
<p class="announcement__content">{{ ann.get_plain_content | truncate:200 }}</p>
</li>
{% if not forloop.last %}<div class="dividing-line" style="border-top-style: dashed;"></div>{% endif %}
{% endfor %}
</ul>
<div class="bottom-link">
<a href="{% url 'management:list' %}">{% trans '查看全部公告' %}</a>
</div>
</div>
</div>
</div>
<div class="bg-mask"></div>
<script>

View file

@ -1,23 +1,34 @@
<footer class="footer">
<div class="grid">
<div class="footer__border">
{% if social_link %}
<a class="footer__link" target="_blank" rel="noopener" href="{{ social_link }}">关注我们</a>
{% endif %}
{% if support_link %}
<a class="footer__link" target="_blank" rel="noopener" href="{{ support_link }}">问题反馈</a>
{% endif %}
<a class="footer__link" target="_blank" rel="noopener" href="https://github.com/neodb-social">源代码</a>
{% if donation_link %}
<a class="footer__link" target="_blank" rel="noopener" href="{{ donation_link }}">捐助本站</a>
{% endif %}
<a class="footer__link" href="/announcement/">公告栏</a>
<a class="footer__link" href="/api-doc/">API</a>
</div>
<div class="grid">
<div class="footer__border">
{% if social_link %}
<a class="footer__link"
target="_blank"
rel="noopener"
href="{{ social_link }}">关注我们</a>
{% endif %}
{% if support_link %}
<a class="footer__link"
target="_blank"
rel="noopener"
href="{{ support_link }}">问题反馈</a>
{% endif %}
<a class="footer__link"
target="_blank"
rel="noopener"
href="https://github.com/neodb-social">源代码</a>
{% if donation_link %}
<a class="footer__link"
target="_blank"
rel="noopener"
href="{{ donation_link }}">捐助本站</a>
{% endif %}
<a class="footer__link" href="{% url 'management:list' %}">公告栏</a>
<a class="footer__link" href="{% url 'common:api_doc' %}">API</a>
</div>
</div>
</footer>
<div class="player">
</div>
<div class="player"></div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';

View file

@ -2,64 +2,96 @@
{% load i18n %}
{% load admin_url %}
<form method="get" action="{% url 'catalog:search' %}">
<section id="navbar">
<section id="navbar">
<nav class="navbar">
<div class="grid">
<div class="navbar__wrapper">
<a href="{% url 'common:home' %}" class="navbar__logo">
<img src="{% static 'img/logo.svg' %}" alt="" class="navbar__logo-img">
</a>
<div class="navbar__search-box">
<!-- <input type="search" name="q" id="searchInput" required="true" value="{% for v in request.GET.values %}{{ v }}{% endfor %}" -->
<input type="search" name="q" id="searchInput" required="true" value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}"
placeholder="搜索书影音游戏播客,或输入站外条目链接如 https://movie.douban.com/subject/1297880/ 支持站点列表见页底公告栏">
<select class="navbar__search-dropdown" id="searchCategory" name="c">
<option value="all" {% if request.GET.c and request.GET.c == 'all' or not request.GET.c %}selected{% endif %}>{% trans '任意' %}</option>
<option value="book" {% if request.GET.c and request.GET.c == 'book' or '/book/' in request.path %}selected{% endif %}>{% trans '书籍' %}</option>
<option value="movie" {% if request.GET.c and request.GET.c == 'movie' or '/movie/' in request.path %}selected{% endif %}>{% trans '电影' %}</option>
<option value="tv" {% if request.GET.c and request.GET.c == 'tv' or '/tv/' in request.path %}selected{% endif %}>{% trans '剧集' %}</option>
<option value="podcast" {% if request.GET.c and request.GET.c == 'podcast' or '/podcast/' in request.path %}selected{% endif %}>{% trans '播客' %}</option>
<option value="music" {% if request.GET.c and request.GET.c == 'music' or '/album/' in request.path %}selected{% endif %}>{% trans '音乐' %}</option>
<option value="game" {% if request.GET.c and request.GET.c == 'game' or '/game/' in request.path %}selected{% endif %}>{% trans '游戏' %}</option>
</select>
<div class="grid">
<div class="navbar__wrapper">
<a href="{% url 'common:home' %}" class="navbar__logo">
<img src="{% static 'img/logo.svg' %}" alt="" class="navbar__logo-img">
</a>
<div class="navbar__search-box">
<!-- <input type="search"
name="q"
id="searchInput"
required="true"
value="{% for v in request.GET.values %}{{ v }}{% endfor %}"
-->
<input type="search"
name="q"
id="searchInput"
required="true"
value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}"
placeholder="搜索书影音游戏播客,或输入站外条目链接如 https://movie.douban.com/subject/1297880/ 支持站点列表见页底公告栏">
<select class="navbar__search-dropdown" id="searchCategory" name="c">
<option value="all"
{% if request.GET.c and request.GET.c == 'all' or not request.GET.c %}selected{% endif %}>
{% trans '任意' %}
</option>
<option value="book"
{% if request.GET.c and request.GET.c == 'book' or '/book/' in request.path %}selected{% endif %}>
{% trans '书籍' %}
</option>
<option value="movie"
{% if request.GET.c and request.GET.c == 'movie' or '/movie/' in request.path %}selected{% endif %}>
{% trans '电影' %}
</option>
<option value="tv"
{% if request.GET.c and request.GET.c == 'tv' or '/tv/' in request.path %}selected{% endif %}>
{% trans '剧集' %}
</option>
<option value="podcast"
{% if request.GET.c and request.GET.c == 'podcast' or '/podcast/' in request.path %}selected{% endif %}>
{% trans '播客' %}
</option>
<option value="music"
{% if request.GET.c and request.GET.c == 'music' or '/album/' in request.path %}selected{% endif %}>
{% trans '音乐' %}
</option>
<option value="game"
{% if request.GET.c and request.GET.c == 'game' or '/game/' in request.path %}selected{% endif %}>
{% trans '游戏' %}
</option>
</select>
</div>
<ul class="navbar__link-list">
{% if request.user.is_authenticated %}
<a class="navbar__link {% if current == 'discover' %}current{% endif %}"
href="{% url 'catalog:discover' %}">{% trans '发现' %}</a>
<a class="navbar__link {% if current == 'timeline' %}current{% endif %}"
href="{% url 'social:feed' %}">{% trans '动态' %}</a>
<a class="navbar__link {% if current == 'home' %}current{% endif %}"
href="{% url 'journal:user_profile' request.user.mastodon_username %}">{% trans '个人主页' %}</a>
<div class="navbar__link dropdown">
<a class="dropbtn"><i class="fa-solid fa-gear" title="{% trans '更多' %}"></i></a>
<div class="dropdown-content">
<a class="navbar__link {% if current == 'data' %}current{% endif %}"
href="{% url 'users:data' %}">{% trans '数据' %}</a>
<a class="navbar__link {% if current == 'preferences' %}current{% endif %}"
href="{% url 'users:preferences' %}">{% trans '设置' %}</a>
<a class="navbar__link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a>
{% if request.user.is_superuser %}
<a class="navbar__link" href="{% admin_url %}">{% trans '后台' %}</a>
{% endif %}
</div>
<ul class="navbar__link-list">
{% if request.user.is_authenticated %}
<a class="navbar__link {% if current == 'discover' %}current{% endif %}" href="{% url 'catalog:discover' %}">{% trans '发现' %}</a>
<a class="navbar__link {% if current == 'timeline' %}current{% endif %}" href="{% url 'social:feed' %}">{% trans '动态' %}</a>
<a class="navbar__link {% if current == 'home' %}current{% endif %}" href="{% url 'journal:user_profile' request.user.mastodon_username %}">{% trans '个人主页' %}</a>
<div class="navbar__link dropdown">
<a class="dropbtn"><i class="fa-solid fa-gear" title="{% trans '更多' %}"></i></a>
<div class="dropdown-content">
<a class="navbar__link {% if current == 'data' %}current{% endif %}" href="{% url 'users:data' %}">{% trans '数据' %}</a>
<a class="navbar__link {% if current == 'preferences' %}current{% endif %}" href="{% url 'users:preferences' %}">{% trans '设置' %}</a>
<a class="navbar__link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a>
{% if request.user.is_superuser %}
<a class="navbar__link" href="{% admin_url %}">{% trans '后台' %}</a>
{% endif %}
</div>
</div>
{% else %}
<a class="navbar__link" href="{% url 'users:login' %}?next={{ request.path }}">{% trans '登录' %}</a>
{% endif %}
</ul>
</div>
</div>
{% else %}
<a class="navbar__link"
href="{% url 'users:login' %}?next={{ request.path }}">{% trans '登录' %}</a>
{% endif %}
</ul>
</div>
</div>
</nav>
</section>
</section>
</form>
{% if messages %}
<div class="main-section-wrapper" style="margin-bottom: 10px; text-align:center;">
<div class="main-section-wrapper"
style="margin-bottom: 10px;
text-align:center">
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
{% for message in messages %}
<li {% if message.tags %}class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}

View file

@ -7,148 +7,136 @@
{% load thumb %}
{% load collection %}
{% load bleach_tags %}
<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="{{ user.mastodon_account.avatar }}" class="user-profile__avatar mast-avatar">
<a href="{% url 'journal:user_profile' user.mastodon_username %}">
<h5 class="user-profile__username mast-displayname">{{ user.mastodon_account.display_name }}</h5>
</a>
<!-- {{ user.id }} -->
</div>
<p><a class="user-profile__link mast-acct" target="_blank" rel="me noopener" href="{{ user.mastodon_account.url }}">@{{ user.username }}@{{ user.mastodon_site }}</a>
{% current_user_relationship user as relationship %}
{% if relationship %}
<a class="user-profile__report-link">
{{ relationship }}
</a>
{% endif %}
</p>
<div class="relation-dropdown">
<div class="relation-dropdown__body">
<p class="user-profile__bio mast-brief">{{ user.mastodon_account.note|bleach:"a,p,span,br" }}</p>
{% if request.user != user %}
<a href="{% url 'users:report' %}?user_id={{ user.id }}"
class="user-profile__report-link">{% trans '投诉用户' %}</a>
{% endif %}
</div>
</div>
</div>
</div>
<div class="relation-dropdown">
<div class="relation-dropdown__button">
<span class="icon-arrow">
<i class="fas fa-angle-down"></i>
</span>
</div>
{% if user.featured_collections.all %}
<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="{{ user.mastodon_account.avatar }}"
class="user-profile__avatar mast-avatar"
alt="">
<a href="{% url 'journal:user_profile' user.mastodon_username %}">
<h5 class="user-profile__username mast-displayname">{{ user.mastodon_account.display_name }}</h5>
</a>
<!-- {{ user.id }} -->
</div>
<p>
<a class="user-profile__link mast-acct"
target="_blank"
rel="me noopener"
href="{{ user.mastodon_account.url }}">@{{ user.username }}@{{ user.mastodon_site }}</a>
{% current_user_relationship user as relationship %}
{% if relationship %}<a class="user-profile__report-link">{{ relationship }}</a>{% endif %}
</p>
<div class="relation-dropdown">
<div class="relation-dropdown__body">
<div class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse">
<div class="user-relation">
<h5 class="user-relation__label">
{% trans '当前目标' %}
</h5>
{% for featured_collection in user.featured_collections.all %}
{% user_visibility_of featured_collection as visible %}
{% if visible %}
{% user_progress_of collection=featured_collection user=user as progress %}
<div class="tag-collection" style="margin-left: 10%;">
<a href="{{ featured_collection.collection.url }}">{{ featured_collection.collection.title }}</a><br>
已完成{{ progress }}% <br>
<progress value="{{ progress }}" max="100">
</div>
{% endif %}
{% endfor %}
<br>
</div>
</div>
<p class="user-profile__bio mast-brief">{{ user.mastodon_account.note|bleach:"a,p,span,br" }}</p>
{% if request.user != user %}
<a href="{% url 'users:report' %}?user_id={{ user.id }}"
class="user-profile__report-link">{% trans '投诉用户' %}</a>
{% endif %}
</div>
{% endif %}
{% if user == request.user %}
<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>
{% if top_tags %}
<div class="user-relation">
<h5 class="user-relation__label">
{% trans '常用标签' %}
</h5>
<a href="{% url 'journal:user_tag_list' user.mastodon_username %}">{% trans '更多' %}</a>
<div class="tag-collection" style="margin-left: 0;">
{% for t in top_tags %}
<span class="tag-collection__tag">
<a href="/users/{{ user.mastodon_username }}/tags/{{ t }}/">{{ t }}</a>
</span>
{% endfor %}
<div class="clearfix"></div>
</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
</div>
<div class="relation-dropdown">
<div class="relation-dropdown__button">
<span class="icon-arrow">
<i class="fas fa-angle-down"></i>
</span>
</div>
{% if user.featured_collections.all %}
<div class="relation-dropdown__body">
<div class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse">
<div class="user-relation">
<h5 class="user-relation__label">{% trans '当前目标' %}</h5>
{% for featured_collection in user.featured_collections.all %}
{% user_visibility_of featured_collection as visible %}
{% if visible %}
{% user_progress_of collection=featured_collection user=user as progress %}
<div class="tag-collection" style="margin-left: 10%;">
<a href="{{ featured_collection.collection.url }}">{{ featured_collection.collection.title }}</a>
<br>
已完成{{ progress }}%
<br>
<progress value="{{ progress }}" max="100" />
</div>
{% endif %}
{% endfor %}
<br>
</div>
</div>
</div>
{% endif %}
{% if user == request.user %}
<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>
{% if top_tags %}
<div class="user-relation">
<h5 class="user-relation__label">{% trans '常用标签' %}</h5>
<a href="{% url 'journal:user_tag_list' user.mastodon_username %}">{% trans '更多' %}</a>
<div class="tag-collection" style="margin-left: 0;">
{% for t in top_tags %}
<span class="tag-collection__tag">
<a href="{% url 'journal:user_tag_member_list' user.mastodon_username t %}">{{ t }}</a>
</span>
{% endfor %}
<div class="clearfix"></div>
</div>
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
{% if user == request.user %}
<div id="oauth2Token" hidden="true">{{ request.user.mastodon_token }}</div>
<div id="mastodonURI" hidden="true">{{ request.user.mastodon_site }}</div>
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
<div id="userPageURL" hidden="true">{% url 'journal:user_profile' 0 %}</div>
<div id="spinner" hidden>
<div id="oauth2Token" hidden="true">{{ request.user.mastodon_token }}</div>
<div id="mastodonURI" hidden="true">{{ request.user.mastodon_site }}</div>
<div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div>
<div id="userPageURL" hidden="true">{% url 'journal:user_profile' 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>
<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>
{% endif %}

View file

@ -0,0 +1,28 @@
{% load static %}
{% load i18n %}
{% load admin_url %}
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load thumb %}
{% load collection %}
{% load bleach_tags %}
<div class="grid__aside grid__aside--reverse-order">
<section>
<article>
<h3>欢迎 🙋🏻‍♀️ 🙋🏻 🙋🏻‍♂️</h3>
<p>
<i class="fa-solid fa-puzzle-piece"></i> &nbsp; {{ site_name }}致力于提供一个涵盖书籍、影视、音乐、游戏、播客的自由开放互联的收藏评论空间。 你可以在这里记录你的收藏和想法,以及发现新的内容和朋友。
</p>
<p>
<i class="fa-solid fa-globe"></i> &nbsp; 登录{{ site_name }}需要一个联邦网络Fediverse也被称为长毛象实例账号如果你还没有账号可以<a href="https://joinmastodon.org/zh/servers" target="_blank">到这里注册</a>
</p>
<p>
<i class="fa-solid fa-circle-question"></i> &nbsp; 如果有任何问题或建议,欢迎通过<a href="https://mastodon.social/@neodb">联邦网络</a><a href="https://discord.gg/uprvcH8gqD">Discord</a>和我们联系。
</p>
<p>
<i class="fa-solid fa-door-open"></i> &nbsp; <a href="/users/login/">点击这里</a>登录。
</p>
</article>
</section>
</div>

View file

@ -9,20 +9,22 @@
margin-left: 1%;
}
</style>
<div class="widget-value-key-input" name='{{ widget.name }}'{% include "django/forms/widgets/attrs.html" %}>
{% if widget.value != None %}
<div class="widget-value-key-input"
name='{{ widget.name }}'
{% include "django/forms/widgets/attrs.html" %}>
{% if widget.value != None %}
{% for pair in widget.value %}
{% for k, v in pair.items %}
<input type="text" value="{{ k }}"><input type="text" value="{{ v }}">
{% endfor %}
{% for k, v in pair.items %}
<input type="text" value="{{ k }}">
<input type="text" value="{{ v }}">
{% endfor %}
{% endfor %}
{% endif %}
{% endif %}
</div>
<input type="text" class="widget-value-key-input-data" hidden name="{{ widget.name }}">
<input type="text"
class="widget-value-key-input-data"
hidden
name="{{ widget.name }}">
<script>
keyValueInput(
$(".widget-value-key-input[name='{{ widget.name }}']"),

View file

@ -1,5 +1,11 @@
<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
<img src="{{ widget.value|default_if_none:''|stringformat:'s' }}" alt="" id="previewImage" style="margin:10px 0; max-width:500px;">
<input type="{{ widget.type }}"
name="{{ widget.name }}"
{% include "django/forms/widgets/attrs.html" %}>
<img src="{{ widget.value|default_if_none:''|stringformat:'s' }}"
alt=""
id="previewImage"
style="margin:10px 0;
max-width:500px">
<script>
$("input[type='file'][name='{{ widget.name }}']").on("change", function () {
if (this.files && this.files[0]) {

View file

@ -1,8 +1,12 @@
<select name="{{ widget.name }}"
{% include "django/forms/widgets/attrs.html" %}>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %}
<optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %}
{% include option.template_name with widget=option %}{% endfor %}{% if group_name %}
</optgroup>{% endif %}{% endfor %}
{% include "django/forms/widgets/attrs.html" %}>
{% for group_name, group_choices, group_index in widget.optgroups %}
{% if group_name %}<optgroup label="{{ group_name }}">{% endif %}
{% for option in group_choices %}
{% include option.template_name with widget=option %}
{% endfor %}
{% if group_name %}</optgroup>{% endif %}
{% endfor %}
</select>
<script>
$('select[name="{{ widget.name }}"]').multipleSelect({

View file

@ -1,17 +1,14 @@
<div class="tag-input">
<input type="text" name="{{ widget.name }}" {% include "django/forms/widgets/attrs.html" %}>
<input type="text"
name="{{ widget.name }}"
{% include "django/forms/widgets/attrs.html" %}>
</div>
<script>
new inputTags({
container: document.getElementsByClassName("tag-input")[0],
tags : [{% for tag in widget.value %}"{{ tag }}",{% endfor %}],
allowDuplicateTags : false,
duplicateTime: 300,
onTagRemove : function (tag) {},
});
new inputTags({
container: document.getElementsByClassName("tag-input")[0],
tags : [{% for tag in widget.value %}"{{ tag }}",{% endfor %}],
allowDuplicateTags : false,
duplicateTime: 300,
onTagRemove : function (tag) {},
});
</script>

View file

@ -1,6 +1,7 @@
from django import template
from django.template.defaultfilters import stringfilter
from django.utils.text import Truncator
from django.utils.safestring import mark_safe
register = template.Library()
@ -14,3 +15,19 @@ def duration_format(value, unit):
s = duration % 60
return f"{h}:{m:02}:{s:02}" if h else f"{m}:{s:02}"
# return (f"{h}小时 " if h else "") + (f"{m}分钟" if m else "")
@register.filter(is_safe=True)
@stringfilter
def rating_star(value):
try:
v = float(value or 0)
except ValueError:
v = 0
pct = round(10 * v)
if pct > 100:
pct = 100
elif pct < 0:
pct = 0
html = f'<span class="rating-star" data-rating="{v}"><div style="width:{pct}%;"></div></span>'
return mark_safe(html)

View file

@ -2,7 +2,7 @@ from django import template
from django.utils.safestring import mark_safe
from django.template.defaultfilters import stringfilter
from opencc import OpenCC
import re
cc = OpenCC("t2s")
register = template.Library()
@ -23,7 +23,7 @@ def highlight(text, search):
m = None
for w in words:
if otext[i : i + len(w)] == w:
m = f'<span class="highlight">{text[i:i+len(w)]}</span>'
m = f"<mark>{text[i:i+len(w)]}</mark>"
i += len(w)
break
if not m:
@ -31,3 +31,9 @@ def highlight(text, search):
i += 1
rtext += m
return mark_safe(rtext)
@register.filter
@stringfilter
def strip_season(text):
return re.sub(r"\s*第\s*\d+\s*季$", "", text)

View file

@ -4,6 +4,7 @@ from .views import *
app_name = "common"
urlpatterns = [
path("", home),
path("api-doc/", api_doc),
path("api-doc/", api_doc, name="api_doc"),
path("home/", home, name="home"),
path("me/", me, name="me"),
]

View file

@ -6,14 +6,23 @@ from .api import api
@login_required
def me(request):
return redirect(
reverse("journal:user_profile", args=[request.user.mastodon_username])
)
def home(request):
home = request.user.get_preference().classic_homepage
if home == 1:
return redirect(
reverse("journal:user_profile", args=[request.user.mastodon_username])
)
elif home == 2:
return redirect(reverse("social:feed"))
if request.user.is_authenticated:
home = request.user.get_preference().classic_homepage
if home == 1:
return redirect(
reverse("journal:user_profile", args=[request.user.mastodon_username])
)
elif home == 2:
return redirect(reverse("social:feed"))
else:
return redirect(reverse("catalog:discover"))
else:
return redirect(reverse("catalog:discover"))

View file

@ -47,6 +47,7 @@ Build static assets
```
python3 manage.py sass common/static/sass/boofilsic.sass common/static/css/boofilsic.min.css -t compressed
python3 manage.py sass common/static/sass/boofilsic.sass common/static/css/boofilsic.css
python3 manage.py compilescss
python3 manage.py collectstatic
```

View file

@ -156,12 +156,6 @@ class Content(Piece):
metadata = models.JSONField(default=dict)
item = models.ForeignKey(Item, on_delete=models.PROTECT)
@cached_property
def mark(self):
m = Mark(self.owner, self.item)
m.review = self
return m
def __str__(self):
return f"{self.uuid}@{self.item}"
@ -221,6 +215,16 @@ class Comment(Content):
def html(self):
return render_text(self.text)
@cached_property
def rating_grade(self):
return Rating.get_item_rating_by_user(self.item, self.owner)
@cached_property
def mark(self):
m = Mark(self.owner, self.item)
m.comment = self
return m
@property
def item_url(self):
if self.focus_item:
@ -259,6 +263,19 @@ class Review(Content):
def html_content(self):
return render_md(self.body)
@property
def plain_content(self):
html = render_md(self.body)
return _RE_HTML_TAG.sub(
" ", _RE_SPOILER_TAG.sub("***", html.replace("\n", " "))
)
@cached_property
def mark(self):
m = Mark(self.owner, self.item)
m.review = self
return m
@cached_property
def rating_grade(self):
return Rating.get_item_rating_by_user(self.item, self.owner)
@ -291,6 +308,9 @@ class Review(Content):
return review
MIN_RATING_COUNT = 5
class Rating(Content):
class Meta:
unique_together = [["owner", "item"]]
@ -304,7 +324,7 @@ class Rating(Content):
stat = Rating.objects.filter(item=item, grade__isnull=False).aggregate(
average=Avg("grade"), count=Count("item")
)
return round(stat["average"], 1) if stat["count"] >= 5 else None
return round(stat["average"], 1) if stat["count"] >= MIN_RATING_COUNT else None
@staticmethod
def get_rating_count_for_item(item):
@ -337,9 +357,34 @@ class Rating(Content):
rating = Rating.objects.filter(owner=user, item=item).first()
return rating.grade if rating else None
@staticmethod
def get_rating_distribution_for_item(item):
stat = (
Rating.objects.filter(item=item, grade__isnull=False)
.values("grade")
.annotate(count=Count("grade"))
.order_by("grade")
)
g = [0] * 11
t = 0
for s in stat:
g[s["grade"]] = s["count"]
t += s["count"]
if t < MIN_RATING_COUNT:
return [0] * 5
r = [
100 * (g[1] + g[2]) // t,
100 * (g[3] + g[4]) // t,
100 * (g[5] + g[6]) // t,
100 * (g[7] + g[8]) // t,
100 * (g[9] + g[10]) // t,
]
return r
Item.rating = property(Rating.get_rating_for_item)
Item.rating_count = property(Rating.get_rating_count_for_item)
Item.rating_dist = property(Rating.get_rating_distribution_for_item)
class Reply(Piece):
@ -440,6 +485,17 @@ class List(Piece):
)
member.delete()
def update_member_order(self, ordered_member_ids):
members = self.ordered_members
for m in self.members.all():
try:
i = ordered_member_ids.index(m.id)
if m.position != i + 1:
m.position = i + 1
m.save()
except ValueError:
pass
def move_up_item(self, item):
members = self.ordered_members
member = self.get_member_for_item(item)
@ -674,8 +730,11 @@ class ShelfManager:
def get_shelf(self, shelf_type):
return self.shelf_list[shelf_type]
def get_members(self, shelf_type, item_category):
return self.shelf_list[shelf_type].get_members_in_category(item_category)
def get_members(self, shelf_type, item_category=None):
if item_category:
return self.shelf_list[shelf_type].get_members_in_category(item_category)
else:
return self.shelf_list[shelf_type].members.all()
# def get_items_on_shelf(self, item_category, shelf_type):
# shelf = (
@ -748,6 +807,7 @@ class CollectionMember(ListMember):
_RE_HTML_TAG = re.compile(r"<[^>]*>")
_RE_SPOILER_TAG = re.compile(r'<(div|span)\sclass="spoiler">.*</(div|span)>')
class Collection(List):
@ -781,8 +841,9 @@ class Collection(List):
html = render_md(self.brief)
return _RE_HTML_TAG.sub(" ", html)
def is_featured_by_user(self, user):
return self.featured_by_users.all().filter(id=user.id).exists()
def featured_by_user_since(self, user):
f = FeaturedCollection.objects.filter(target=self, owner=user).first()
return f.created_time if f else None
def get_stats_for_user(self, user):
items = list(self.members.all().values_list("item_id", flat=True))
@ -881,13 +942,15 @@ class TagManager:
return sorted(list(map(lambda t: t["title"], tags)))
@staticmethod
def all_tags_for_user(user):
def all_tags_for_user(user, public_only=False):
tags = (
user.tag_set.all()
.values("title")
.annotate(frequency=Count("members__id"))
.order_by("-frequency")
)
if public_only:
tags = tags.filter(visibility=0)
return list(map(lambda t: t["title"], tags))
@staticmethod
@ -935,6 +998,10 @@ class TagManager:
def all_tags(self):
return TagManager.all_tags_for_user(self.owner)
@property
def public_tags(self):
return TagManager.all_tags_for_user(self.owner, public_only=True)
def add_item_tags(self, item, tags, visibility=0):
for tag in tags:
TagManager.add_tag_by_user(item, tag, self.owner, visibility)
@ -1021,6 +1088,10 @@ class Mark:
def rating(self):
return Rating.get_item_rating_by_user(self.item, self.owner)
@cached_property
def rating_grade(self):
return Rating.get_item_rating_by_user(self.item, self.owner)
@cached_property
def comment(self):
return Comment.objects.filter(
@ -1059,7 +1130,8 @@ class Mark:
)
)
share_as_new_post = shelf_type != self.shelf_type
if shelf_type != self.shelf_type or visibility != self.visibility:
original_visibility = self.visibility
if shelf_type != self.shelf_type or visibility != original_visibility:
self.shelfmember = self.owner.shelf_manager.move_item(
self.item, shelf_type, visibility=visibility, metadata=metadata
)
@ -1082,11 +1154,11 @@ class Mark:
metadata=self.metadata,
timestamp=created_time,
)
if comment_text != self.text or visibility != self.visibility:
if comment_text != self.text or visibility != original_visibility:
self.comment = Comment.comment_item_by_user(
self.item, self.owner, comment_text, visibility
)
if rating_grade != self.rating or visibility != self.visibility:
if rating_grade != self.rating or visibility != original_visibility:
Rating.rate_item_by_user(self.item, self.owner, rating_grade, visibility)
self.rating = rating_grade
if share:
@ -1120,7 +1192,7 @@ class Mark:
)
def reset_visibility_for_user(user: User, visibility: int):
def reset_journal_visibility_for_user(user: User, visibility: int):
ShelfMember.objects.filter(owner=user).update(visibility=visibility)
Comment.objects.filter(owner=user).update(visibility=visibility)
Rating.objects.filter(owner=user).update(visibility=visibility)

View file

@ -37,7 +37,7 @@ def _spolier(s):
r = l[1].split("!<", 1)
return (
escape(l[0])
+ '<span class="spoiler">'
+ '<span class="spoiler" _="on click toggle .revealed on me">'
+ escape(r[0])
+ "</span>"
+ (_spolier(r[1]) if len(r) == 2 else "")

View file

@ -0,0 +1,17 @@
<form style="display:none"
action="{% if featured %}{% url 'journal:collection_remove_featured' collection.uuid %}{% else %}{% url 'journal:collection_add_featured' collection.uuid %}{% endif %}"
method="post"
id="feature-form">
{% csrf_token %}
</form>
{% if featured %}
<a class="activated"
title="停止追踪目标"
onclick="if (confirm('停止这个目标吗?')) $('#feature-form').submit();">
<i class="fa-solid fa-circle-dot"></i>
</a>
{% else %}
<a title="设为目标" onclick="$('#feature-form').submit()">
<i class="fa-regular fa-circle-dot"></i>
</a>
{% endif %}

View file

@ -8,22 +8,27 @@
{% load truncate %}
{% load highlight %}
{% load thumb %}
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me">
<div id="modal"
_="on closeModal add .closing then wait for animationend then remove me">
<div class="modal-underlay" _="on click trigger closeModal"></div>
<div class="modal-content">
<div class="add-to-list-modal__head">
<span class="add-to-list-modal__title">{% trans '添加到收藏单' %}</span>
<span class="add-to-list-modal__close-button modal-close" _="on click trigger closeModal">
<span class="add-to-list-modal__close-button modal-close"
_="on click trigger closeModal">
<i class="fa-solid fa-xmark"></i>
</span>
</div>
<div class="add-to-list-modal__body">
<form action="{% url 'journal:add_to_collection' item.uuid %}" method="post">
<form action="{% url 'journal:add_to_collection' item.uuid %}"
method="post">
{% csrf_token %}
<select name="collection_id">
{% for collection in collections %}
<option value="{{ collection.id }}">{{ collection.title }}{% if collection.visibility > 0 %}🔒{% endif %}</option>
<option value="{{ collection.id }}">
{{ collection.title }}
{% if collection.visibility > 0 %}🔒{% endif %}
</option>
{% endfor %}
<option value="0">新建收藏单</option>
</select>
@ -31,7 +36,7 @@
<textarea type="text" name="note" placeholder="条目备注"></textarea>
</div>
<div class="add-to-list-modal__confirm-button">
<input type="submit" class="button float-right" value="{% trans '提交' %}">
<input type="submit" class="button float-right" value="{% trans '保存' %}">
</div>
</form>
</div>

View file

@ -1 +1,18 @@
{{ calendar_data|json_script:"calendar_data" }}
<script>
$(".calendar_view").calendar_yearview_blocks({
data: $("#calendar_data").text(),
start_monday: false,
always_show_tooltip: false,
month_names: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
day_names: ['', '', ''],
colors: {
'default': getComputedStyle(document.documentElement).getPropertyValue('--pico-form-element-background-color'),
'book': '#B4D2A5',
'movie': '#7CBDFE',
'music': '#FEA36D',
'game': '#C5A290',
'other': '#9D6AB0'
}
});
</script>

View file

@ -9,187 +9,130 @@
{% load thumb %}
{% load collection %}
{% load user_actions %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="{{ site_name }} {% trans '收藏单' %} - {{ collection.title }}">
<meta property="og:description" content="{{ collection.description }}">
<meta property="og:type" content="article">
<meta property="og:article:author" content="{{ collection.owner.username }}">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
<meta property="og:image" content="{{ collection.cover|thumb:'normal' }}">
<title>{{ site_name }} {% trans '收藏单' %} - {{ collection.title }}</title>
{% include "common_libs.html" with jquery=0 %}
</head>
<body>
<div id="page-wrapper">
<div id="content-wrapper">
{% include "partial/_navbar.html" %}
<section id="content">
<div class="grid">
<div class="grid__main" id="main">
<div class="main-section-wrapper">
<div class="review-head">
<h5 class="review-head__title">
{{ collection.title }}
</h5>
{% if collection.visibility > 0 %}
<i class="fa-solid fa-lock"></i>
{% endif %}
<div class="review-head__body">
<div class="review-head__info">
<a href="{% url 'journal:user_profile' collection.owner.mastodon_username %}" class="review-head__owner-link">{{ collection.owner.mastodon_username }}</a>
<span class="review-head__time">{{ collection.edited_time }}</span>
</div>
<div class="action-bar">
<html lang="en" class="content-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title"
content="{{ site_name }}{% trans '收藏单' %} - {{ collection.title }}">
<meta property="og:description" content="{{ collection.description }}">
<meta property="og:type" content="article">
<meta property="og:article:author"
content="{{ collection.owner.username }}">
<meta property="og:url" content="{{ request.build_absolute_uri }}">
<meta property="og:image" content="{{ collection.cover|thumb:'normal' }}">
<title>{{ site_name }} {% trans '收藏单' %} - {{ collection.title }}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
</head>
<body>
{% include "_header.html" %}
<main>
<div class="grid__main">
<article>
<header>
<hgroup>
<h3>
<div class="action">
{% if request.user.is_authenticated %}
<span>
{% liked_piece collection as liked %}
{% include 'like_stats.html' with liked=liked piece=collection %}
{% include 'like_stats.html' with liked=liked piece=collection label='关注' icon='fa-bookmark' %}
</span>
{% if request.user == collection.owner %}
<span>{% include '_feature_stats.html' with featured=featured_since %}</span>
<span>
<a class="review-head__action-link" href="{% url 'journal:collection_edit' collection.uuid %}">{% trans '编辑' %}</a>
<a class="review-head__action-link" href="{% url 'journal:collection_delete' collection.uuid %}">{% trans '删除' %}</a>
<a href="#"
hx-get="{% url 'journal:collection_share' collection.uuid %}"
hx-target="body"
hx-swap="beforeend"
title="分享到联邦网络"><i class="fa-solid fa-share-nodes"></i></a>
</span>
{% elif editable %}
<span class="review-head__time">可协作整理</span>
{% endif %}
</div>
</div>
<!-- <div class="dividing-line"></div> --> <!-- <div class="entity-card__img-wrapper" style="text-align: center;"> <img src="{{ collection.cover|thumb:'normal' }}" alt="" class="entity-card__img"> </div> -->
<div class="markdown-content">
{{ collection.html | safe }}
{% endif %}
</div>
{{ collection.title }}
{% if collection.visibility > 0 %}<small><i class="fa-solid fa-lock"></i></small>{% endif %}
</h3>
</hgroup>
<div class="owner-info">
<div class="owner">
<span class="avatar">
<img src="{{ collection.owner.mastodon_account.avatar }}"
alt="{{ collection.owner.username }}">
</span>
</div>
<div class="entity-list" hx-get="{% url 'journal:collection_retrieve_items' collection.uuid %}" hx-trigger="load">
</div>
</div>
</div>
<div class="grid__aside" id="aside">
<div class="aside-section-wrapper">
<div class="entity-card">
<div class="entity-card__img-wrapper">
<a href="{{ collection.url }}">
<img src="{{ collection.cover|thumb:'normal' }}" alt="" class="entity-card__img">
</a>
</div>
<div class="entity-card__info-wrapper">
<h5 class="entity-card__title">
<a href="{{ collection.url }}">
{{ collection.title }}
</a>
</h5>
<div class="info">
<p>
<a href="{% url 'journal:user_profile' collection.owner.mastodon_username %}">{{ collection.owner.mastodon_account.display_name }}</a>
<span class="handler">@{{ collection.owner.mastodon_username }}</span>
</p>
<p>
{% for cat, count in collection.get_summary.items %}
{% if count %}<span>{{ count }} {{ cat|prural_items }}</span>&nbsp;&nbsp;{% endif %}
{% endfor %}
</p>
{% if featured_since %}
<p>
{% for cat, count in collection.get_summary.items %}
{% if count %}
{{count}}{{cat|prural_items}}
{% endif %}
{% endfor %}
<progress value="{{ stats.percentage }}"
max="100"
title="{{ stats.percentage }}%" />
</p>
{% endif %}
<div class="markdown-content">{{ collection.html | safe }}</div>
</div>
<div class="more">
<div style="text-align: center;">
<img src="{{ collection.cover|thumb:'normal' }}" alt="">
</div>
</div>
</div>
{% if is_featured %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="donut" style="background: conic-gradient(#7CBDFE 0deg {{ stats.complete_deg }}deg, #B4D2A5 {{ stats.complete_deg }}deg {{ stats.complete_deg|add:stats.progress_deg }}deg, #ccc {{ stats.complete_deg|add:stats.progress_deg }}deg 1deg );"><div class="hole"><div class="text">
{% if stats.progress %}
{{ stats.progress }} 进行中<br>
{% endif %}
{% if stats.complete %}
{{ stats.complete }} 已完成
{% elif not stats.progress %}
尚未开始
{% endif %}
</div></div></div>
</div>
<div class="action-panel" style="margin-bottom: 0;">
<div class="action-panel__button-group action-panel__button-group--center">
<form action="{% url 'journal:collection_remove_featured' collection.uuid %}" method="post">
{% csrf_token %}
<button class="action-panel__button" title="点击取消目标设置">{% trans '当前进度' %} {{ stats.percentage }}%</button>
</form>
</div>
</div>
</header>
{% comment %}
{% if featured_since %}
<section style="min-width:10vw;">
<div class="donut" style="background: conic-gradient(#7CBDFE 0deg {{ stats.complete_deg }}deg, #B4D2A5 {{ stats.complete_deg }}deg {{ stats.complete_deg|add:stats.progress_deg }}deg, #ccc {{ stats.complete_deg|add:stats.progress_deg }}deg 1deg );"><div class="hole"><div class="text">
{% if stats.progress %}
{{ stats.progress }} 进行中<br>
{% endif %}
{% if stats.complete %}
{{ stats.complete }} 已完成
{% elif not stats.progress %}
尚未开始
{% endif %}
</div></div></div>
<div style="margin:8px; color:lightgray" class="muted">
开始于{{ featured_since|date }}
<a class="muted" href="#" title="停止" onclick="if (confirm('停止这个目标吗?')) $('#stop-featured').submit();"><i class="fa-solid fa-ban"></i></a>
<form action="{% url 'journal:collection_remove_featured' collection.uuid %}" method="post" id="stop-featured">
{% csrf_token %}
</form>
</div>
{% endif %}
{% if available_as_featured %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__button-group action-panel__button-group--center">
<form action="{% url 'journal:collection_add_featured' collection.uuid %}" method="post">
{% csrf_token %}
<button class="action-panel__button">{% trans '设为目标' %}</button>
</form>
</div>
</div>
</section>
{% endif %}
{% endcomment %}
<section>
<div class="entity-list"
hx-get="{% url 'journal:collection_retrieve_items' collection.uuid %}"
hx-trigger="load"></div>
</section>
<footer>
<div class="action">
{% if request.user == collection.owner %}
<span>
<a href="{% url 'journal:collection_edit' collection.uuid %}">{% trans '编辑' %}</a>
</span>
<span>
<a href="{% url 'journal:collection_delete' collection.uuid %}">{% trans '删除' %}</a>
</span>
{% elif editable %}
<a href="{% url 'journal:collection_edit' collection.uuid %}">{% trans '协助整理' %}</a>
{% endif %}
</div>
{% endif %}
{% if not is_featured and request.user.is_authenticated and request.user != collection.owner %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__button-group action-panel__button-group--center">
{% if following %}
<form action="{% url 'journal:unlike' collection.uuid %}?back=1" method="post">
{% csrf_token %}
<button class="action-panel__button">{% trans '取消关注' %}</button>
</form>
{% else %}
<form action="{% url 'journal:like' collection.uuid %}?back=1" method="post">
{% csrf_token %}
<button class="action-panel__button">{% trans '关注' %}</button>
</form>
{% endif %}
</div>
</div>
</div>
{% endif %}
{% if request.user.is_authenticated %}
<div class="aside-section-wrapper">
<div class="action-panel">
<div class="action-panel__button-group action-panel__button-group--center">
<form>
<button class="action-panel__button add-to-list" hx-get="{% url 'journal:collection_share' collection.uuid %}" hx-target="body" hx-swap="beforeend">{% trans '分享到联邦网络' %}</button>
</form>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</section>
</div>
<span>创建于 {{ collection.created_time | date }}</span>
</footer>
</article>
</div>
{% include "_sidebar.html" with user=collection.owner show_profile=1 %}
</main>
{% include "partial/_footer.html" %}
</div>
<script>
$(".markdownx textarea").hide();
</script>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
</body>
</body>
</html>

View file

@ -5,47 +5,56 @@
{% load oauth_token %}
{% load truncate %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - 编辑收藏单 - {{ title }}</title>
{% include "common_libs.html" with jquery=0 %}
<style type="text/css">
#id_collaborative li, #id_visibility li {display: inline-block !important;}
</style>
</head>
<body>
<div id="page-wrapper">
{% include "partial/_navbar.html" %}
<div id="content-wrapper">
<section id="content" class="container">
<div class="grid">
<div class="single-section-wrapper" id="main">
<form class="entity-form markdown-content" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<input class="button" type="submit" value="{% trans '提交' %}">
</form>
{{ form.media }}
</div>
<html lang="en" class="content-page">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name }} - 编辑收藏单 - {{ title }}</title>
{% include "common_libs.html" with jquery=0 v2=1 %}
<script src="https://cdn.staticfile.org/html5sortable/0.13.3/html5sortable.min.js"
crossorigin="anonymous"></script>
<style type="text/css">
#id_collaborative li, #id_visibility li {display: inline-block !important;}
.grid__main details {
margin: 2rem 0;
}
</style>
</head>
<body>
{% include "_header.html" %}
<main>
<div class="grid__main">
<h4>
{% if collection %}
<div class="dividing-line"></div>
<div class="single-section-wrapper">
<div id="collection_items" class="entity-list" hx-get="{% url 'journal:collection_retrieve_items' collection.uuid %}?edit=1" hx-trigger="load"></div>
</div>
编辑 <a href="{{ collection.url }}">{{ collection.title }}</a>
{% else %}
创建收藏单
{% endif %}
</div>
</section>
</div>
</h4>
<hr>
<details {% if not collection %}open{% endif %}>
<summary>标题和描述</summary>
<form class="entity-form markdown-content"
method="post"
enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<input class="button" type="submit" value="{% trans '保存' %}">
</form>
{{ form.media }}
</details>
{% if collection %}
<hr>
<details open>
<summary>条目</summary>
<div id="collection_items"
hx-get="{% url 'journal:collection_retrieve_items' collection.uuid %}?edit=1"
hx-trigger="load"></div>
</details>
{% endif %}
</div>
{% include "_sidebar.html" with user=collection.owner show_profile=1 fold_profile=1 %}
</main>
{% include "partial/_footer.html" %}
</div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
</body>
</body>
</html>

View file

@ -1,27 +1,57 @@
{% load thumb %}
{% load i18n %}
{% load l10n %}
<ul class="entity-list__entities">
{% for member in collection.ordered_members %}
{% with "list_item_"|add:member.item.class_name|add:".html" as template %}
{% include template with item=member.item mark=None collection_member=member %}
{% endwith %}
{% empty %}
暂无条目
{% endfor %}
{% if collection_edit %}
<li>
<form class="entity-form" hx-target=".entity-list" hx-post="{% url 'journal:collection_append_item' collection.uuid %}" method="POST">
{% csrf_token %}
<input type="url" name="url" placeholder="{{ request.scheme }}://{{ request.get_host }}/item/abcd123" style="min-width:24rem" required>
<input type="text" name="comment" placeholder="{% trans '备注' %}" style="min-width:24rem">
<input class="button" type="submit" value="{% trans '添加' %}" >
</form>
</li>
{% endif %}
</ul>
{% if msg %}
<script type="text/javascript">
alert("{{ msg|escapejs }}");
</script>
<div class="item-list sortable">
{% for member in collection.ordered_members %}
{% with "list_item_"|add:member.item.class_name|add:".html" as template %}
{% include template with item=member.item mark=None collection_member=member %}
{% endwith %}
{% empty %}
暂无条目
{% endfor %}
</div>
{% if collection_edit %}
<form class="entity-form"
hx-target="#collection_items"
hx-post="{% url 'journal:collection_append_item' collection.uuid %}"
method="post">
{% csrf_token %}
<input type="url"
name="url"
placeholder="{{ request.scheme }}://{{ request.get_host }}/item/abcd123"
style="min-width:24rem"
required>
<input type="text"
name="comment"
placeholder="{% trans '备注' %}"
style="min-width:24rem">
<input class="button" type="submit" value="{% trans '添加站内条目到收藏夹' %}">
</form>
<script>
$(function () {
sortable('.sortable', {
forcePlaceholderSize: true,
placeholderClass: 'entity-sort--placeholder',
hoverClass: 'entity-sort--hover'
});
});
function update_member_order() {
var member_ids = [];
$('.sortable>.item-card').each(function () {
member_ids.push($(this).data('member-id'));
});
$('#member_ids').val(member_ids.join(','));
return true;
}
</script>
<form class="entity-form"
hx-target="#collection_items"
hx-post="{% url 'journal:collection_update_member_order' collection.uuid %}"
onsubmit="return update_member_order()"
method="post">
{% csrf_token %}
<input type="hidden" name="member_ids" id="member_ids" required>
<input type="submit" class="secondary" value="拖拽修改条目顺序后点击这里保存">
</form>
{% endif %}
{% if msg %}<script type="text/javascript">alert("{{ msg|escapejs }}");</script>{% endif %}

View file

@ -8,43 +8,66 @@
{% load truncate %}
{% load highlight %}
{% load thumb %}
<div id="modal" _="on closeModal add .closing then wait for animationend then remove me">
<div class="modal-underlay" _="on click trigger closeModal"></div>
<div class="modal-content">
<div class="add-to-list-modal__head">
<span class="add-to-list-modal__title">{% trans '分享收藏单' %} - {{ collection.title }}</span>
<span class="add-to-list-modal__close-button modal-close" _="on click trigger closeModal">
<i class="fa-solid fa-xmark"></i>
</span>
</div>
<div class="add-to-list-modal__body">
<form action="{% url 'journal:collection_share' collection.uuid %}" method="post">
{% csrf_token %}
<div>
<label for="id_visibility_0">分享可见性(不同于收藏单本身的权限):</label>
<ul id="id_visibility">
<li><label for="id_visibility_0"><input type="radio" name="visibility" value="0" required="" id="id_visibility_0" {% if collection.visibility == 0 %}checked{% endif %}>
公开</label>
</li>
<li><label for="id_visibility_1"><input type="radio" name="visibility" value="1" required="" id="id_visibility_1" {% if collection.visibility == 1 %}checked{% endif %}>
仅关注者</label>
</li>
<li><label for="id_visibility_2"><input type="radio" name="visibility" value="2" required="" id="id_visibility_2" {% if collection.visibility == 2 %}checked{% endif %}>
仅自己</label>
</li>
</ul>
</div>
<div>
<textarea type="text" name="comment" placeholder="分享附言"></textarea>
</div>
<div class="add-to-list-modal__confirm-button">
<input type="submit" class="button float-right" value="{% trans '提交' %}">
</div>
</form>
</div>
<div id="modal"
_="on closeModal add .closing then wait for animationend then remove me">
<div class="modal-underlay" _="on click trigger closeModal"></div>
<div class="modal-content">
<div class="add-to-list-modal__head">
<span class="add-to-list-modal__title">{% trans '分享收藏单' %} - {{ collection.title }}</span>
<span class="add-to-list-modal__close-button modal-close"
_="on click trigger closeModal">
<i class="fa-solid fa-xmark"></i>
</span>
</div>
<div class="add-to-list-modal__body">
<form action="{% url 'journal:collection_share' collection.uuid %}"
method="post">
{% csrf_token %}
<div>
<label for="id_visibility_0">分享可见性(不同于收藏单本身的权限):</label>
<ul id="id_visibility">
<li>
<label for="id_visibility_0">
<input type="radio"
name="visibility"
value="0"
required=""
id="id_visibility_0"
{% if collection.visibility == 0 %}checked{% endif %}>
公开
</label>
</li>
<li>
<label for="id_visibility_1">
<input type="radio"
name="visibility"
value="1"
required=""
id="id_visibility_1"
{% if collection.visibility == 1 %}checked{% endif %}>
仅关注者
</label>
</li>
<li>
<label for="id_visibility_2">
<input type="radio"
name="visibility"
value="2"
required=""
id="id_visibility_2"
{% if collection.visibility == 2 %}checked{% endif %}>
仅自己
</label>
</li>
</ul>
</div>
<div>
<textarea type="text" name="comment" placeholder="分享附言"></textarea>
</div>
<div class="add-to-list-modal__confirm-button">
<input type="submit" class="button float-right" value="{% trans '提交' %}">
</div>
</form>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show more