diff --git a/.gitignore b/.gitignore index da0d2ef1..3f331f2b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,8 +18,8 @@ migrations/ *.sqlite3 # deployed media and static files -media/ -static/ +/media/ +/static/ # log file log \ No newline at end of file diff --git a/boofilsic/settings.py b/boofilsic/settings.py index cd0c4f15..85ea6bb6 100644 --- a/boofilsic/settings.py +++ b/boofilsic/settings.py @@ -86,7 +86,7 @@ if DEBUG: 'NAME': 'test', 'USER': 'donotban', 'PASSWORD': 'donotbansilvousplait', - 'HOST': '192.168.238.194', + 'HOST': '172.18.99.149', 'OPTIONS': { 'client_encoding': 'UTF8', # 'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_DEFAULT, @@ -174,8 +174,8 @@ AUTH_USER_MODEL = 'users.User' MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media/') -CLIENT_ID = 'kEbwT9Je5HsadfNs5Mw6Asht456YlQl54t4sj2_4' -CLIENT_SECRET = 'xwmEvlmudLCkBmvdzGf8msdfgsdfggs5di9xnDqeVLrcKSg' +CLIENT_ID = 'kEbwT9Je5HHg4FoLx4nb0tNaIrPNs5Mw6AYlQlsj2_4' +CLIENT_SECRET = 'xwmEvlmudLCkBmvdzGf8m41Ug5o5di9xnDqeVLrcKSg' # Path to save report related images, ends without slash REPORT_MEDIA_PATH_ROOT = 'report/' @@ -190,7 +190,6 @@ MASTODON_DOMAIN_NAME = 'donotban.com' MASTODON_TIMEOUT = 30 # Emoji code in mastodon -# note the white spaces STAR_SOLID = ':star_solid:' STAR_HALF = ':star_half:' STAR_EMPTY = ':star_empty:' @@ -205,5 +204,9 @@ LOGIN_URL = '/users/login/' # Admin site root url ADMIN_URL = 'lpLuTqX72Bt2hLfxxRYKeTZdE59Y2hLfpLuTqX72Btx9sXuljYK4tYEmjrHd' +# Luminati proxy settings +LUMINATI_USERNAME = '***REMOVED***' +LUMINATI_PASSWORD = '***REMOVED***' + # https://django-debug-toolbar.readthedocs.io/en/latest/ # maybe benchmarking before deployment diff --git a/books/forms.py b/books/forms.py index 9ae560d3..274c8e41 100644 --- a/books/forms.py +++ b/books/forms.py @@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _ from .models import Book, BookMark, BookReview from common.models import MarkStatusEnum from common.forms import RadioBooleanField, RatingValidator +from common.forms import PreviewImageInput def BookMarkStatusTranslator(status): @@ -59,13 +60,13 @@ class BookForm(forms.ModelForm): 'brief': _("简介"), 'other_info': _("其他信息"), } - from common.forms import ImageInput + widgets = { 'author': forms.TextInput(attrs={'placeholder': _("多个作者使用英文逗号分隔")}), 'translator': forms.TextInput(attrs={'placeholder': _("多个译者使用英文逗号分隔")}), 'other_info': KeyValueInput(), # 'cover': forms.FileInput(), - 'cover': ImageInput(), + 'cover': PreviewImageInput(), } def clean_isbn(self): @@ -108,7 +109,7 @@ class BookMarkForm(forms.ModelForm): 'text': _("短评"), } widgets = { - 'book': forms.Select(attrs={"hidden": ""}), + 'book': forms.TextInput(attrs={"hidden": ""}), 'text': forms.Textarea(attrs={"placeholder": _("最多只能写500字哦~")}), } @@ -141,7 +142,7 @@ class BookReviewForm(forms.ModelForm): 'share_to_mastodon': _("分享到长毛象") } widgets = { - 'book': forms.Select(attrs={"hidden": ""}), + 'book': forms.TextInput(attrs={"hidden": ""}), } diff --git a/books/templates/books/create_update.html b/books/templates/books/create_update.html index f86923ae..f8769451 100644 --- a/books/templates/books/create_update.html +++ b/books/templates/books/create_update.html @@ -9,38 +9,23 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - ' %}{{ title }}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> - <script src="{% static 'js/create_update.js' %}"></script> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> --> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <h4 class="nav-title">{{ title }}</h4> - - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} <section id="content" class="container"> - <div class="row"> - <div id="main"> - <form action="{{ submit_url }}" method="post" enctype="multipart/form-data"> + <div class="grid"> + <div class="single-section-wrapper" id="main"> + <form class="entity-form" action="{{ submit_url }}" method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form }} <input class="button" type="submit" value="{% trans '提交' %}"> @@ -49,11 +34,7 @@ </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> @@ -72,6 +53,10 @@ location.href = "{% url 'common:search' %}" + "?q=" + q; } }); + // mark required + $("#content input[required]").each(function () { + $(this).prev().prepend("*"); + }) </script> </body> diff --git a/books/templates/books/create_update_review.html b/books/templates/books/create_update_review.html index 38117079..f2cd4aa6 100644 --- a/books/templates/books/create_update_review.html +++ b/books/templates/books/create_update_review.html @@ -9,44 +9,34 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - ' %}{{ title }}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'js/create_update_review.js' %}"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <h4 class="nav-title">{{ title }}</h4> - - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <div class="item-card clearfix"> - <img src="{{ book.cover.url }}" alt="" class="item-image float-left"> - <div class="item-info float-left"> + <section id="content"> + <div class="grid"> + <div class="single-section-wrapper"> + <div class="entity-card entity-card--horizontal"> + <div class="entity-card__img-wrapper"> + <a href="{% url 'books:retrieve' book.id %}"> + <img src="{{ book.cover.url }}" alt="" class="item-image float-left"> + </a> + </div> + <div class="entity-card__info-wrapper entity-card__info-wrapper--horizontal"> - <div class="item-title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></div> + <h5 class="entity-card__title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> <div>{% if book.isbn %}{% trans 'ISBN:' %}{{ book.isbn }}{% endif %}</div> <div>{% if book.author %}{% trans '作者:' %} {% for author in book.author %} @@ -57,35 +47,38 @@ <div>{%if book.pub_year %}{% trans '出版时间:' %}{{ book.pub_year }}{% trans '年' %}{% if book.pub_month %}{{ book.pub_month }}{% trans '月' %}{% endif %}{% endif %}</div> {% if book.rating %} - <span class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"> </span> - <span class="rating-score"> {{ book.rating }} </span> + {% trans '评分:' %}<span class="entity-card__rating-star rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"> </span> + <span class="entity-card__rating-score rating-score"> {{ book.rating }} </span> {% endif %} </div> </div> - - <div class="review"> - <form action="{{ submit_url }}" method="post"> + <div class="dividing-line"></div> + + <form action="{{ submit_url }}" method="post" class="review-form"> {% csrf_token %} {{ form.book }} - {{ form.title.label }}{{ form.title }} + <div> + {{ form.title.label }} + </div> + {{ form.title }} <div class="clearfix"> <span class="float-left"> {{ form.content.label }} </span> <span class="float-right"> - <span class="preview-button">{% trans '预览' %}</span> + <span class="review-form__preview-button">{% trans '预览' %}</span> </span> </div> <div id="rawContent"> {{ form.content }} </div> - <div class="fyi">{% trans '不知道什么是Markdown?可以参考' %}<a target="_blank" href="https://www.markdownguide.org/">{% trans '这里' %}</a></div> - <div class="option clearfix"> - <div class="selection float-left"> + <div class="review-form__fyi">{% trans '不知道什么是Markdown?可以参考' %}<a target="_blank" href="https://www.markdownguide.org/">{% trans '这里' %}</a></div> + <div class="review-form__option"> + <div class="review-form__visibility-radio"> {{ form.is_private.label }}{{ form.is_private }} </div> - <div class="float-right"> + <div class="review-form__share-checkbox"> {{ form.share_to_mastodon }}{{ form.share_to_mastodon.label }} </div> </div> @@ -94,16 +87,13 @@ </div> {{ form.media }} </form> - </div> + </div> - + + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> {% comment %} diff --git a/books/templates/books/delete.html b/books/templates/books/delete.html index 50f91ff2..836b43e1 100644 --- a/books/templates/books/delete.html +++ b/books/templates/books/delete.html @@ -9,64 +9,57 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 删除图书' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <script src="{% static 'js/rating-star-readonly.js' %}"></script> <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> --> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <h4 class="nav-title">{% trans '删除图书' %}</h4> - - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <h4 class="prompt">{% trans '确认删除这本书吗?相关评论和标记将一并删除。' %}</h4> + <section id="content"> + <div class="grid"> + <div class="single-section-wrapper" id="main"> + <h5>{% trans '确认删除这本书吗?相关评论和标记将一并删除。' %}</h5> - <div class="item-card"> - <div class="clearfix"> - <img src="{{ book.cover.url }}" alt="" class="item-image float-left"> - <div class="item-info float-left"> - <a href="{% url 'books:retrieve' book.id %}"> - <h5 class="item-title"> - {{ book.title }} - </h5> - </a> - {% if book.rating %} - {% trans '评分:' %} - <span class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"> - </span> - <span class="rating-score">{{ book.rating }} </span> - {% else %} - <span>{% trans '评分:暂无评分' %}</span> - {% endif %} - <div>{% trans '最近编辑者:' %}{{ book.last_editor | default:"" }}</div> - <div>{% trans '上次编辑时间:' %}{{ book.edited_time }}</div> - </div> + <div class="entity-card entity-card--horizontal"> + <div class="entity-card__img-wrapper"> + <a href="{% url 'books:retrieve' book.id %}"> + <img src="{{ book.cover.url }}" alt="" class="item-image float-left"> + </a> + </div> + <div class="entity-card__info-wrapper entity-card__info-wrapper--horizontal"> + <a href="{% url 'books:retrieve' book.id %}"> + <h5 class="entity-card__title"> + {{ book.title }} + </h5> + </a> + {% if book.rating %} + {% trans '评分:' %}<span class="entity-card__rating-star rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"> + </span> + <span class="entity-card__rating-score">{{ book.rating }}</span> + {% else %} + <span>{% trans '评分:暂无评分' %}</span> + {% endif %} + + {% if book.last_editor %} + <a href="{% url 'users:home' book.last_editor.id %}"> + <div>{% trans '最近编辑者:' %}{{ book.last_editor | default:"" }}</div> + </a> + {% endif %} + + <div>{% trans '上次编辑时间:' %}{{ book.edited_time }}</div> </div> - <div class="dividing-line"></div> </div> + <div class="dividing-line"></div> <div class="clearfix"> <form action="{% url 'books:delete' book.id %}" method="post" class="float-right"> {% csrf_token %} @@ -75,14 +68,11 @@ <button onclick="history.back()" class="button button-clear float-right">{% trans '返回' %}</button> </div> </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> diff --git a/books/templates/books/delete_review.html b/books/templates/books/delete_review.html index cd0f00b6..05898719 100644 --- a/books/templates/books/delete_review.html +++ b/books/templates/books/delete_review.html @@ -9,90 +9,96 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 删除评论' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> - + <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <h4 class="nav-title">{% trans '删除评论' %}</h4> + {% include "partial/_navbar.html" %} + + <section id="content"> + <div class="grid"> + <div class="single-section-wrapper" id="main"> + <h5>{% trans '确认删除这篇评论吗?' %}</h5> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> - - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <h4 class="prompt">{% trans '确认删除这篇评论吗?' %}</h4> - - <div class="item-card"> - <div class="review"> - <div class="review-head clearfix"> - <div class="mark-label float-left"> - <h4> - {{ review.title }} - {% if review.is_private %} - <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> - {% endif %} - </h4> - <a href="" class="mark-owner-name">{{ review.owner.username }}</a> - - <span class="mark-time">{{ review.edited_time }}</span> + <div class="dividing-line"></div> + + + <div class="review-head"> + + <h5 class="review-head__title"> + {{ review.title }} + </h5> + {% if review.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 20 20"> + <path + d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" /> + </svg></span> + {% endif %} + + <div class="review-head__body"> + <div class="review-head__info"> + + <a href="{% url 'users:home' review.owner.id %}" + class="review-head__owner-link">{{ review.owner.username }}</a> + + {% if mark %} + + {% if mark.rating %} + <span class="review-head__rating-star rating-star" + data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> + {% endif %} + + {% endif %} + + <span class="review-head__time">{{ review.edited_time }}</span> + </div> - </div> - <!-- <div class="dividing-line"></div> --> - <div id="rawContent" class="delete-preview"> - {{ form.content }} - </div> - {{ form.media }} - </div> - <!-- <div class="dividing-line"></div> --> + + </div> + <div id="rawContent" class="delete-preview"> + {{ form.content }} + </div> + {{ form.media }} + + <div class="dividing-line"></div> + <div class="clearfix"> <form action="{% url 'books:delete_review' review.id %}" method="post" class="float-right"> {% csrf_token %} <input class="button" type="submit" value="{% trans '确认' %}"> </form> - <button onclick="history.back()" class="button button-clear float-right">{% trans '返回' %}</button> + <button onclick="history.back()" + class="button button-clear float-right">{% trans '返回' %}</button> </div> </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> - - {% comment %} + + {% comment %} <div id="oauth2Token" hidden="true">{% oauth_token %}</div> <div id="mastodonURI" hidden="true">{% mastodon %}</div> - <!--current user mastodon id--> + <!--current user mastodon id--> <div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div> {% endcomment %} - + <script> $("#searchInput").on('keyup', function (e) { if (e.keyCode === 13) { @@ -107,4 +113,4 @@ </body> -</html> +</html> \ No newline at end of file diff --git a/books/templates/books/detail.html b/books/templates/books/detail.html index d0d38a38..848315fa 100644 --- a/books/templates/books/detail.html +++ b/books/templates/books/detail.html @@ -9,314 +9,325 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta property="og:title" content="NiceDB书 - {{ book.title }}"> + <meta property="og:type" content="book"> + {% if book.author %} + <meta property="og:book:author" content="{% for author in book.author %}{{ author }}{% if not forloop.last %},{% endif %}{% endfor %}"> + {% endif %} + {% if book.isbn %} + <meta property="og:book:isbn" content="{{ book.isbn }}"> + {% endif %} + <meta property="og:url" content="{{ request.build_absolute_uri }}"> + <meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{{ book.cover.url }}"> + <title>{% trans 'Nicedb - 书籍详情' %} | {{ book.title }}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <script src="{% static 'js/detail.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_modal.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_modal.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <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/milligram.css' %}"> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <div class="clearfix"> - <div class="float-left"> - <img src="{{ book.cover.url }}" class="display-image" alt=""> - </div> - <div class="display-info"> - <h5 class="display-title"> - {{ book.title }} - </h5> - - <div class="display-info-detail"> - <div>{% if book.isbn %}{% trans 'ISBN:' %}{{ book.isbn }}{% endif %}</div> - <div>{% if book.author %}{% trans '作者:' %} - {% for author in book.author %} - <span>{{ author }}</span> - {% endfor %} - {% endif %}</div> - <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> - <div>{% if book.subtitle %}{% trans '副标题:' %}{{ book.subtitle }}{% endif %}</div> - <div>{% if book.translator %}{% trans '译者:' %} - {% for translator in book.translator %} - <span>{{ translator }}</span> - {% endfor %} - {% endif %}</div> - <div>{% if book.orig_title %}{% trans '原作名:' %}{{ book.orig_title }}{% endif %}</div> - <div>{% if book.language %}{% trans '语言:' %}{{ book.language }}{% endif %}</div> - <div>{%if book.pub_year %}{% trans '出版时间:' %}{{ book.pub_year }}{% trans '年' %}{% if book.pub_month %}{{ book.pub_month }}{% trans '月' %}{% endif %}{% endif %}</div> - </div> - <div class="display-info-detail"> - {% if book.rating %} - <span class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"> + <section id="content"> + <div class="grid"> + <div class="grid__main" id="main"> + <div class="main-section-wrapper"> + <div class="entity-detail"> - </span> - <span class="rating-score"> {{ book.rating }} </span> - {% else %} - <span> {% trans '评分:暂无评分' %}</span> - {% endif %} - <div>{% if book.binding %}{% trans '装帧:' %}{{ book.binding }}{% endif %}</div> - <div>{% if book.price %}{% trans '定价:' %}{{ book.price }}{% endif %}</div> - <div>{% if book.pages %}{% trans '页数:' %}{{ book.pages }}{% endif %}</div> - {% if book.other_info %} - {% for k, v in book.other_info.items %} - <div> - {{k}}:{{v}} - </div> - {% endfor %} - {% endif %} + <img src="{{ book.cover.url }}" class="entity-detail__img" alt="{{ book.title }}"> + + <div class="entity-detail__info"> + <h5 class="entity-detail__title"> + {{ book.title }} + </h5> - {% comment %} - {% url 'users:home' book.last_editor %} - {% endcomment %} + <div class="entity-detail__fields"> + <div class="entity-detail__rating"> + {% if book.rating %} + <span class="entity-detail__rating-star rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></span> + <span class="entity-detail__rating-score"> {{ book.rating }} </span> + {% else %} + <span> {% trans '评分:暂无评分' %}</span> + {% endif %} + </div> + <div>{% if book.isbn %}{% trans 'ISBN:' %}{{ book.isbn }}{% endif %}</div> + <div>{% if book.author %}{% trans '作者:' %} + {% for author in book.author %} + <span>{{ author }}</span> + {% endfor %} + {% endif %}</div> + <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> + <div>{% if book.subtitle %}{% trans '副标题:' %}{{ book.subtitle }}{% endif %}</div> + <div>{% if book.translator %}{% trans '译者:' %} + {% for translator in book.translator %} + <span>{{ translator }}</span> + {% endfor %} + {% endif %}</div> + <div>{% if book.orig_title %}{% trans '原作名:' %}{{ book.orig_title }}{% endif %}</div> + <div>{% if book.language %}{% trans '语言:' %}{{ book.language }}{% endif %}</div> + <div>{%if book.pub_year %}{% trans '出版时间:' %}{{ book.pub_year }}{% trans '年' %}{% if book.pub_month %}{{ book.pub_month }}{% trans '月' %}{% endif %}{% endif %}</div> + </div> + <div class="entity-detail__fields"> + + <div>{% if book.binding %}{% trans '装帧:' %}{{ book.binding }}{% endif %}</div> + <div>{% if book.price %}{% trans '定价:' %}{{ book.price }}{% endif %}</div> + <div>{% if book.pages %}{% trans '页数:' %}{{ book.pages }}{% endif %}</div> + {% if book.other_info %} + {% for k, v in book.other_info.items %} + <div> + {{k}}:{{v}} + </div> + {% endfor %} + {% endif %} - <div>{% trans '最近编辑者:' %}<a href="{% url 'users:home' book.last_editor.id %}">{{ book.last_editor | default:"" }}</a></div> - <div> - <a href="{% url 'books:update' book.id %}">{% trans '编辑这本书' %}</a> - {% if user.is_staff %} - <a href="{% url 'books:delete' book.id %}" class="delete"> / {% trans '删除' %}</a> - {% endif %} - </div> - </div> + {% if book.last_editor %} + <div>{% trans '最近编辑者:' %}<a href="{% url 'users:home' book.last_editor.id %}">{{ book.last_editor | default:"" }}</a></div> + {% endif %} + + <div> + <a href="{% url 'books:update' book.id %}">{% trans '编辑这本书' %}</a> + {% if user.is_staff %} + <a href="{% url 'books:delete' book.id %}"> / {% trans '删除' %}</a> + {% endif %} + </div> + </div> + + </div> </div> - </div> - <div class="dividing-line"></div> - <div class="set"> - <h5 class="set-title">{% trans '简介' %}</h5> - - {% if book.brief %} - <p class="set-content">{{ book.brief | linebreaksbr }}</p> - {% else %} - <p class="set-empty">{% trans '暂无简介' %}</p> - {% endif %} - - </div> - <div class="set"> - <h5 class="set-title">{% trans '这本书的标记' %}</h5> - {% if mark_list_more %} - <a href="{% url 'books:retrieve_mark_list' book.id %}" class="more-link">{% trans '更多' %}</a> - {% endif %} - {% if mark_list %} - {% for others_mark in mark_list %} - <div class="mark"> - <div class="mark-label"> - <a href="{% url 'users:home' others_mark.owner.id %}" class="mark-owner-name">{{ others_mark.owner.username }}</a> + <div class="dividing-line"></div> + <div class="entity-desc"> + <h5 class="entity-desc__title">{% trans '简介' %}</h5> + + {% if book.brief %} + <p class="entity-desc__content">{{ book.brief | linebreaksbr }}</p> + {% else %} + <div>{% trans '暂无简介' %}</div> + {% endif %} + + </div> + <div class="entity-marks"> + <h5 class="entity-marks__title">{% trans '这本书的标记' %}</h5> + {% if mark_list_more %} + <a href="{% url 'books:retrieve_mark_list' book.id %}" class="entity-marks__more-link">{% trans '更多' %}</a> + {% endif %} + {% if mark_list %} + <ul class="entity-marks__mark-list"> + {% for others_mark in mark_list %} + <li class="entity-marks__mark"> + <a href="{% url 'users:home' others_mark.owner.id %}" class="entity-marks__owner-link">{{ others_mark.owner.username }}</a> <span>{{ others_mark.get_status_display }}</span> {% if others_mark.rating %} - <span class="rating-star" data-rating-score="{{ others_mark.rating | floatformat:"0" }}"></span> + <span class="entity-marks__rating-star rating-star" data-rating-score="{{ others_mark.rating | floatformat:"0" }}"></span> {% endif %} {% if others_mark.is_private %} <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> {% endif %} - <span class="mark-time">{{ others_mark.edited_time }}</span> - </div> - - {% if others_mark.text %} - <p class="mark-text">{{ others_mark.text }}</p> + <span class="entity-marks__mark-time">{{ others_mark.edited_time }}</span> + {% if others_mark.text %} + <p class="entity-marks__mark-content">{{ others_mark.text }}</p> + {% endif %} + </li> + {% endfor %} + </ul> + {% else %} + <div>{% trans '暂无标记' %}</div> {% endif %} - </div> - {% endfor %} - {% else %} - <p class="set-empty">{% trans '暂无标记' %}</p> - {% endif %} - </div> - <div class="set"> - <h5 class="set-title">{% trans '这本书的评论' %}</h5> - {% if review_list_more %} - <a href="{% url 'books:retrieve_review_list' book.id %}" class="more-link">{% trans '更多' %}</a> - {% endif %} - {% if review_list %} - {% for others_review in review_list %} - <div class="mark"> - <div class="mark-label"> - <a href="{% url 'users:home' others_review.owner.id %}" class="mark-owner-name">{{ others_review.owner.username }}</a> + <div class="entity-reviews"> + <h5 class="entity-reviews__title">{% trans '这本书的评论' %}</h5> + {% if review_list_more %} + <a href="{% url 'books:retrieve_review_list' book.id %}" 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 'users:home' others_review.owner.id %}" class="entity-reviews__owner-link">{{ others_review.owner.username }}</a> {% if others_review.is_private %} <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> {% endif %} - <span class="mark-time">{{ others_review.edited_time }}</span> - <span class="review-title"> <a href="{% url 'books:retrieve_review' others_review.id %}">{{ others_review.title }}</a></span> - </div> - + <span class="entity-reviews__review-time">{{ others_review.edited_time }}</span> + <span class="entity-reviews__review-title"> <a href="{% url 'books:retrieve_review' others_review.id %}">{{ others_review.title }}</a></span> + </li> + {% endfor %} + </ul> + {% else %} + <div>{% trans '暂无评论' %}</div> + {% endif %} </div> - {% endfor %} - {% else %} - <p class="set-empty">{% trans '暂无评论' %}</p> - {% endif %} </div> </div> - <div id="aside"> - <div class="aside-card" id="asideMark"> + <div class="grid__aside" id="aside"> + <div class="aside-section-wrapper"> {% if mark %} - <div class="mark"> - <div class="clearfix"> - <span class="mark-status-label float-left">{% trans '我' %}{{ mark.get_status_display }}</span> - {% if mark.status == status_enum.DO.value or mark.status == status_enum.COLLECT.value%} - {% if mark.rating %} - <span class="rating-star" data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> - {% endif %} + <div class="mark-panel"> + + <span class="mark-panel__status">{% trans '我' %}{{ mark.get_status_display }}</span> + {% if mark.status == status_enum.DO.value or mark.status == status_enum.COLLECT.value%} + {% if mark.rating %} + <span class="mark-panel__rating-star rating-star" data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> {% endif %} - {% if mark.is_private %} - <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> - {% endif %} - <span class="float-right"> - <a href="" class="edit">{% trans '修改' %}</a> - <form action="{% url 'books:delete_mark' mark.id %}" method="post"> - {% csrf_token %} - <a href="">{% trans '删除' %}</a> - </form> - </span> - </div> - <div class="clearfix"> - <span class="mark-time float-left">{{ mark.edited_time }}</span> - </div> + {% endif %} + {% if mark.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> + {% endif %} + <span class="mark-panel__actions"> + <a href="" class="edit">{% trans '修改' %}</a> + <form action="{% url 'books:delete_mark' mark.id %}" method="post"> + {% csrf_token %} + <a href="" class="delete">{% trans '删除' %}</a> + </form> + </span> + <div class="mark-panel__clear"></div> + + <div class="mark-panel__time">{{ mark.edited_time }}</div> + {% if mark.text %} - <p class="mark-text">{{ mark.text }}</p> + <p class="mark-panel__text">{{ mark.text }}</p> {% endif %} </div> {% else %} - <div class="mark"> - <div class="clearfix"> - <span class="mark-status-label float-left">{% trans '标记这本书' %}</span> - </div> - <div class="button-group"> - <a href="" class="button" id="wishButton" data-status="{{ status_enum.WISH.value }}">{% trans '想读' %}</a> - <a href="" class="button" data-status="{{ status_enum.DO.value }}">{% trans '在读' %}</a> - <a href="" class="button" data-status="{{ status_enum.COLLECT.value }}">{% trans '读过' %}</a> + <div class="action-panel" id="addMarkPanel"> + <div class="action-panel__label">{% trans '标记这本书' %}</div> + <div class="action-panel__button-group"> + <button class="action-panel__button" data-status="{{ status_enum.WISH.value }}">{% trans '想读' %}</button> + <button class="action-panel__button" data-status="{{ status_enum.DO.value }}">{% trans '在读' %}</button> + <button class="action-panel__button" data-status="{{ status_enum.COLLECT.value }}">{% trans '读过' %}</button> </div> </div> {% endif %} </div> - <div class="aside-card" id="asideReview"> - {% if review %} - <div class="review"> - <div class="clearfix"> - <span class="review-label float-left">{% trans '我的评论' %}</span> - {% if review.is_private %} - <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> - {% endif %} + <div class="aside-section-wrapper"> + {% if review %} + <div class="review-panel"> + + <span class="review-panel__label">{% trans '我的评论' %}</span> + {% if review.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> + {% endif %} - <span class="float-right"> - <a href="{% url 'books:update_review' review.id %}">{% trans '编辑' %}</a> - <a href="{% url 'books:delete_review' review.id %}">{% trans '删除' %}</a> - </span> + <span class="review-panel__actions"> + <a href="{% url 'books:update_review' review.id %}">{% trans '编辑' %}</a> + <a href="{% url 'books:delete_review' review.id %}">{% trans '删除' %}</a> + </span> - </div> - <div class="clearfix"> - <span class="review-time float-left">{{ review.edited_time }}</span> - </div> - <a href="{% url 'books:retrieve_review' review.id %}" class="review-title"> + <div class="review-panel__time">{{ review.edited_time }}</div> + + <a href="{% url 'books:retrieve_review' review.id %}" class="review-panel__review-title"> {{ review.title }} </a> </div> {% else %} - <div class="clearfix"> - <span class="review-label float-left">{% trans '我的评论' %}</span> - </div> - <a href="{% url 'books:create_review' book.id %}" class="button">{% trans '去写评论' %}</a> + + <div class="action-panel"> + <div class="action-panel__label">{% trans '我的评论' %}</div> + <div class="action-panel__button-group action-panel__button-group--center"> + + <a href="{% url 'books:create_review' book.id %}"> + <button class="action-panel__button">{% trans '去写评论' %}</button> + </a> + </div> + </div> + {% endif %} </div> </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> <div id="modals"> - <div class="modal mark-modal"> - <div class="modal-head clearfix"> + <div class="mark-modal modal"> + <div class="mark-modal__head"> {% if not mark %} <style> - .modal-title::after { + .mark-modal__title::after { content: "{% trans '这本书' %}"; } </style> - <span class="modal-title float-left"></span> + <span class="mark-modal__title"></span> {% else %} - <span class="modal-title float-left">{% trans '我的标记' %}</span> + <span class="mark-modal__title">{% trans '我的标记' %}</span> {% endif %} - <span class="modal-close float-right"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61"/></svg> + <span class="mark-modal__close-button modal-close"> + <span class="icon-cross"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <polygon + points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61"> + </polygon> + </svg> + </span> </span> </div> - <div class="modal-body"> + <div class="mark-modal__body"> <form action="{% url 'books:create_update_mark' %}" method="post"> {% csrf_token %} {{ mark_form.id }} {{ mark_form.book }} {% if mark.rating %} {% endif %} - <div class="clearfix"> - <div class="rating-star-edit float-left"></div> - <div id="statusSelection" class="modal-selection float-right" {% if not mark %}hidden{% endif %}> - {{ mark_form.status }} - </div> - </div> - + <div class="mark-modal__rating-star rating-star-edit"></div> {{ mark_form.rating }} + <div id="statusSelection" class="mark-modal__status-radio" {% if not mark %}hidden{% endif %}> + {{ mark_form.status }} + </div> + + <div class="mark-modal__clear"></div> + {{ mark_form.text }} - <div class="modal-option clearfix"> - <div class="modal-selection float-left"> + + <div class="mark-modal__option"> + <div class="mark-modal__visibility-radio"> <span>{{ mark_form.is_private.label }}:</span> {{ mark_form.is_private }} </div> - <div class="modal-checkbox float-right"> + <div class="mark-modal__share-checkbox"> {{ mark_form.share_to_mastodon }}{{ mark_form.share_to_mastodon.label }} </div> </div> - <div class="clearfix modal-button"> + <div class="mark-modal__confirm-button"> <input type="submit" class="button float-right" value="{% trans '提交' %}"> </div> </form> </div> </div> - <div class="modal confirm-modal"> - <div class="modal-head clearfix"> - <span class="modal-title float-left">{% trans '确定要删除你的标记吗?' %}</span> - <span class="modal-close float-right"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61"/></svg> + <div class="confirm-modal modal"> + <div class="confirm-modal__head"> + <span class="confirm-modal__title">{% trans '确定要删除你的标记吗?' %}</span> + <span class="confirm-modal__close-button modal-close"> + <span class="icon-cross"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <polygon + points="20 2.61 17.39 0 10 7.39 2.61 0 0 2.61 7.39 10 0 17.39 2.61 20 10 12.61 17.39 20 20 17.39 12.61 10 20 2.61"> + </polygon> + </svg> + </span> </span> </div> - <div class="modal-body"> - <div class="clearfix modal-button"> + <div class="confirm-modal__body"> + <div class="confirm-modal__confirm-button"> <input type="submit" class="button float-right" value="{% trans '确认' %}"> </div> </div> diff --git a/books/templates/books/list.html b/books/templates/books/list.html index 6dfa4881..564ca685 100644 --- a/books/templates/books/list.html +++ b/books/templates/books/list.html @@ -10,197 +10,227 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> - <title>{% trans 'Nicedb - 书' %}</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>{% trans 'Nicedb - ' %}{{ user.username }}{{ list_title }}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <script src="{% static 'js/rating-star-readonly.js' %}"></script> <script src="{% static 'js/mastodon.js' %}"></script> <script src="{% static 'js/home.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" - value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if request.user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} <section id="content" class="container"> - <div class="row"> - <div id="main"> - <div class="set"> - <h5 class="set-title"> - {{ user.username }}{{ list_title }} - </h5> - </div> - <ul class="result-items"> - - {% for mark in marks %} - - <li class="result-item clearfix"> - <a href="{% url 'books:retrieve' mark.book.id %}"> - <img src="{{ mark.book.cover.url }}" alt="" class="result-book-cover"> - </a> - <div class="result-info"> + <div class="grid grid--reverse-order"> + <div class="grid__main grid__main--reverse-order"> + <div class="main-section-wrapper"> + <div class="entity-list"> - <a href="{% url 'books:retrieve' mark.book.id %}" class="result-item-title"> - {{ mark.book.title }} - </a> - {% if mark.book.rating %} - - <div class="rating-star" data-rating-score="{{ mark.book.rating | floatformat:"0" }}"></div> - <span class="rating-score"> - {{ mark.book.rating }} - </span> - {% else %} - <span class="rating-empty"> {% trans '暂无评分' %}</span> - {% endif %} - <span class="result-book-info"> - {% if mark.book.pub_year %} - {{ mark.book.pub_year }}{% trans '年' %} / - {% if mark.book.pub_month %} - {{ mark.book.pub_month }}{% trans '月' %} / - {% endif %} - {% endif %} - - {% if mark.book.author %} - {% trans '作者' %} - {% for author in mark.book.author %} - {{ author }}{% if not forloop.last %},{% endif %} - {% endfor %}/ - {% endif %} - - {% if mark.book.translator %} - {% trans '译者' %} - {% for translator in mark.book.translator %} - {{ translator }}{% if not forloop.last %},{% endif %} - {% endfor %}/ - {% endif %} - - {% if mark.book.orig_title %} - {% trans '原名' %} - {{ mark.book.orig_title }} - {% endif %} - </span> - <p class="result-item-brief"> - {{ mark.book.brief | truncate:170 }} - </p> + <div class="set"> + <h5 class="entity-list__title"> + {{ user.username }}{{ list_title }} + </h5> </div> - </li> - {% empty %} - {% trans '无结果' %} - {% endfor %} - - </ul> - <div class="pagination" > + <ul class="entity-list__entities"> + + {% for mark in marks %} + + <li class="entity-list__entity"> + <div class="entity-list__entity-img-wrapper"> + <a href="{% url 'books:retrieve' mark.book.id %}"> + <img src="{{ mark.book.cover.url }}" alt="" class="entity-list__entity-img"> + </a> + </div> + <div class="entity-list__entity-text"> + <div class="entity-list__entity-title"> + <a href="{% url 'books:retrieve' mark.book.id %}" class="entity-list__entity-link"> + {{ mark.book.title }} + </a> + </div> + {% comment %} + <!-- {% if mark.book.rating %} + <div class="rating-star entity-list__rating-star" data-rating-score="{{ mark.book.rating | floatformat:"0" }}"></div> + <span class="entity-list__rating-score rating-score"> + {{ mark.book.rating }} + </span> + {% else %} + <div class="entity-list__rating entity-list__rating--empty"> {% trans '暂无评分' %}</div> + {% endif %} --> + {% endcomment %} + <span class="entity-list__entity-info entity-list__entity-info--full-length"> + {% if mark.book.pub_year %} + {{ mark.book.pub_year }}{% trans '年' %} / + {% if mark.book.pub_month %} + {{ mark.book.pub_month }}{% trans '月' %} / + {% endif %} + {% endif %} + + {% if mark.book.author %} + {% trans '作者' %} + {% for author in mark.book.author %} + {{ author }}{% if not forloop.last %},{% endif %} + {% endfor %}/ + {% endif %} + + {% if mark.book.translator %} + {% trans '译者' %} + {% for translator in mark.book.translator %} + {{ translator }}{% if not forloop.last %},{% endif %} + {% endfor %}/ + {% endif %} + + {% if mark.book.orig_title %} + {% trans '原名' %} + {{ mark.book.orig_title }} + {% endif %} + </span> + <p class="entity-list__entity-brief"> + {{ mark.book.brief | truncate:170 }} + </p> + <div class="entity-marks" style="margin-bottom: 0;"> + <ul class="entity-marks__mark-list"> + <li class="entity-marks__mark"> + + {% if mark.rating %} + <span class="entity-marks__rating-star rating-star" + data-rating-score="{{ mark.rating | floatformat:"0" }}" style="left: -4px;"></span> + {% endif %} + {% if mark.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg + xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <path + d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" /> + </svg></span> + {% endif %} + <span class="entity-marks__mark-time">{{ mark.edited_time }}</span> + {% if mark.text %} + <p class="entity-marks__mark-content">{{ mark.text }}</p> + {% endif %} + </li> + </ul> + </div> + </div> + + </li> + {% empty %} + <div>{% trans '无结果' %}</div> + {% endfor %} + <!-- user mark --> + + + </ul> + </div> + <div class="pagination"> - <a - {% if marks.has_previous %} - href="?page=1" - {% else %} - disabled - {% endif %}> - <button {% if not marks.has_previous %}disabled{% endif %} class="button button-clear">{% trans "首页" %}</button> - </a> - - <a - {% if marks.has_previous %} - href="?page={{ marks.previous_page_number }}" - {% else %} - disabled - {% endif %}> - <button {% if not marks.has_previous %}disabled{% endif %} class="button button-clear">{% trans "上一页" %}</button> - </a> - - <span class="page-index"> - {% trans "第" %}{% if request.GET.page %}{{ request.GET.page }}{% else %}1{% endif %}{% trans "页" %} - </span> - - <a - {% if marks.has_next %} - href="?page={{ marks.next_page_number }}" - {% else %} - disabled - {% endif %} - > - <button {% if not marks.has_next %}disabled{% endif %} class="button button-clear">{% trans "下一页" %}</button> - </a> - - <a - {% if marks.has_next %} - href="?page={{ marks.paginator.num_pages }}" - {% else %} - disabled - {% endif %}> - <button {% if not marks.has_next %}disabled{% endif %} class="button button-clear">{% trans "末页" %}</button> - </a> - - </div> + {% if marks.pagination.has_prev %} + <a href="?page=1" class="pagination__nav-link pagination__nav-link">«</a> + <a href="?page={{ marks.previous_page_number }}" + class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">‹</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">›</a> + <a href="?page={{ marks.pagination.last_page }}" class="pagination__nav-link">»</a> + {% endif %} + + </div> + </div> </div> - <div id="aside"> - <div class="aside-card mast-user" id="userInfoCard"> - <div class="clearfix"> - <img src="" class="info-avatar mast-avatar" alt="{{ user.username }}"> - <a href="{% url 'users:home' user.id %}"> - <h5 class="info-name mast-displayname"></h5> - </a> + <div class="grid__aside grid__aside--reverse-order grid__aside--tablet-column"> + <div class="aside-section-wrapper aside-section-wrapper--no-margin"> + <div class="user-profile" id="userInfoCard"> + <div class="user-profile__header"> + <!-- <img src="" class="user-profile__avatar mast-avatar" alt="{{ user.username }}"> --> + <img src="" class="user-profile__avatar mast-avatar"> + <a href="{% url 'users:home' user.id %}"> + <h5 class="user-profile__username mast-displayname"></h5> + </a> + </div> + <p class="user-profile__bio mast-brief"></p> + <!-- <a href="#" class="follow">{% trans '关注TA' %}</a> --> + + {% if request.user != user %} + <a href="{% url 'users:report' %}?user_id={{ user.id }}" + class="user-profile__report-link">{% trans '举报用户' %}</a> + {% endif %} + </div> - <p class="info-brief mast-brief"></p> - <!-- <a href="#" class="follow">{% trans '关注TA' %}</a> --> - - {% if request.user != user %} - <a href="{% url 'users:report' %}?user_id={{ user.id }}" class="report">{% trans '举报用户' %}</a> - {% endif %} - </div> - <div class="relation-card" id="userRelationCard"> - <h5 class="relation-label"> - {% trans '关注的人' %} - </h5> - <a href="{% url 'users:following' user.id %}" class="more-link mast-following-more">{% trans '更多' %}</a> - <ul class="row mast-following relation-user-list"> - <li class="column column-25 relation-user"> - <img src="" alt="" class="relation-avatar"> - <a class="relation-name"></a> - </li> - </ul> - <h5 class="relation-label"> - {% trans '被他们关注' %} - </h5> - <a href="{% url 'users:followers' user.id %}" class="more-link mast-followers-more">{% trans '更多' %}</a> - <ul class="row mast-followers relation-user-list"> - <li class="column column-25 relation-user"> - <img src="" alt="" class="relation-avatar"> - <a class="relation-name"></a> - </li> - </ul> + + <div class="relation-dropdown"> + <div class="relation-dropdown__button"> + <span class="icon-arrow"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"> + <path d="M8.12,3.29,5,6.42,1.86,3.29H.45L5,7.84,9.55,3.29Z" /> + </svg> + </span> + </div> + <div class="relation-dropdown__body"> + <div class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse"> + + <div class="user-relation" id="followings"> + <h5 class="user-relation__label"> + {% trans '关注的人' %} + </h5> + <a href="{% url 'users:following' user.id %}" + 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.id %}" + class="user-relation__more-link mast-followers-more">{% trans '更多' %}</a> + <ul class="user-relation__related-user-list mast-followers"> + <li class="user-relation__related-user"> + <a> + <img src="" alt="" class="user-relation__related-user-avatar"> + <div class="user-relation__related-user-name mast-displayname"> + </div> + </a> + </li> + </ul> + </div> + + </div> + </div> </div> + </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> @@ -209,22 +239,22 @@ <!--current user mastodon id--> <div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div> <div id="userPageURL" hidden="true">{% url 'users:home' 0 %}?is_mastodon_id=true</div> - <div class="spinner" id="spinner" hidden> - <div class="lds-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 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> <script> $("#searchInput").on('keyup', function (e) { if (e.keyCode === 13) { diff --git a/books/templates/books/mark_list.html b/books/templates/books/mark_list.html index c5a08260..3c1a4864 100644 --- a/books/templates/books/mark_list.html +++ b/books/templates/books/mark_list.html @@ -10,140 +10,122 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> - <title>{% trans 'Nicedb - 搜索结果' %}</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>{% trans 'Nicedb - ' %}{{ book.title }}{% trans '的标记' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <script src="{% static 'js/rating-star-readonly.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> + <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/milligram.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" - value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <h5 class="list-head"> - <a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a>{% trans ' 的标记' %} - </h5> - <ul class="result-items set"> + <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 'books:retrieve' book.id %}">{{ book.title }}</a>{% trans ' 的标记' %} + </h5> + <ul class="entity-marks__mark-list"> + + {% for mark in marks %} + + <li class="entity-marks__mark entity-marks__mark--wider"> + <a href="{% url 'users:home' mark.owner.id %}" + class="entity-marks__owner-link">{{ mark.owner.username }}</a> + <span>{{ mark.get_status_display }}</span> + {% if mark.rating %} + <span class="entity-marks__rating-star rating-star" + data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> + {% endif %} + {% if mark.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg + xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <path + d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" /> + </svg></span> + {% endif %} + <span class="entity-marks__mark-time">{{ mark.edited_time }}</span> + {% if mark.text %} + <p class="entity-marks__mark-content">{{ mark.text }}</p> + {% endif %} + </li> - {% for mark in marks %} - - <div class="list-item"> - <div class="list-label"> - <a href="{% url 'users:home' mark.owner.id %}" class="list-owner-name">{{ mark.owner.username }}</a> - <span>{{ mark.get_status_display }}</span> - {% if mark.rating %} - <span class="rating-star" data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> - {% endif %} - {% if mark.is_private %} - <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> - {% endif %} - <span class="item-time">{{ mark.edited_time }}</span> - </div> - - {% if mark.text %} - <p class="mark-text">{{ mark.text }}</p> - {% endif %} - + {% empty %} + <div> + {% trans '无结果' %} + </div> + {% endfor %} + + </ul> </div> - {% empty %} - {% trans '无结果' %} - {% endfor %} - - </ul> - <div class="pagination" > + <div class="pagination"> - <a - {% if marks.has_previous %} - href="?page=1" - {% else %} - disabled - {% endif %}> - <button {% if not marks.has_previous %}disabled{% endif %} class="button button-clear">{% trans "首页" %}</button> - </a> - - <a - {% if marks.has_previous %} - href="?page={{ marks.previous_page_number }}" - {% else %} - disabled - {% endif %}> - <button {% if not marks.has_previous %}disabled{% endif %} class="button button-clear">{% trans "上一页" %}</button> - </a> - - <span class="page-index"> - {% trans "第" %}{% if request.GET.page %}{{ request.GET.page }}{% else %}1{% endif %}{% trans "页" %} - </span> - - <a - {% if marks.has_next %} - href="?page={{ marks.next_page_number }}" - {% else %} - disabled - {% endif %} - > - <button {% if not marks.has_next %}disabled{% endif %} class="button button-clear">{% trans "下一页" %}</button> - </a> - - <a - {% if marks.has_next %} - href="?page={{ marks.paginator.num_pages }}" - {% else %} - disabled - {% endif %}> - <button {% if not marks.has_next %}disabled{% endif %} class="button button-clear">{% trans "末页" %}</button> - </a> - - </div> - </div> - - <div id="aside"> - <div class="aside-card"> - <div class="aside-item"> - <a href="{% url 'books:retrieve' book.id %}"><img src="{{ book.cover.url }}" alt="" class="item-image"></a> - <h5 class="item-title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> - - {% if book.isbn %} - <div>ISBN: {{ book.isbn }}</div> + {% if marks.pagination.has_prev %} + <a href="?page=1" + class="pagination__nav-link pagination__nav-link">«</a> + <a href="?page={{ marks.previous_page_number }}" + class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">‹</a> {% endif %} - - <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> - {% if book.rating %} - {% trans '评分: ' %}<span class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></span> + + {% 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">›</a> + <a href="?page={{ marks.pagination.last_page }}" + class="pagination__nav-link">»</a> + {% endif %} + </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="{% url 'books:retrieve' book.id %}"><img src="{{ book.cover.url }}" alt="" class="entity-card__img"></a> + </div> + <div class="entity-card__info-wrapper"> + <h5 class="entity-card__title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> + + {% if book.isbn %} + <div>ISBN: {{ book.isbn }}</div> + {% endif %} + + <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> + {% if book.rating %} + {% trans '评分: ' %}<span class="entity-card__rating-star rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></span> + <span class="entity-card__rating-score rating-score">{{ book.rating }}</span> + {% endif %} + </div> + + </div> + </div> + </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> @@ -161,16 +143,7 @@ if (q) location.href = "{% url 'common:search' %}" + "?q=" + q; } - }); - ratingLabels = $("#aside .rating-star"); - $(ratingLabels).each( function(index, value) { - let ratingScore = $(this).data("rating-score") / 2; - $(this).starRating({ - initialRating: ratingScore, - readOnly: true, - starSize: 15, - }); - }); + }); </script> </body> diff --git a/books/templates/books/review_detail.html b/books/templates/books/review_detail.html index afca679c..83f8cb72 100644 --- a/books/templates/books/review_detail.html +++ b/books/templates/books/review_detail.html @@ -9,105 +9,103 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> - <title>{% trans 'Nicedb - 查看评论' %}</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta property="og:title" content="NiceDB书评 - {{ review.title }}"> + <meta property="og:type" content="article"> + <meta property="og:article:author" content="{{ review.owner.username }}"> + <meta property="og:url" content="{{ request.build_absolute_uri }}"> + <meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'img/logo_square.svg' %}"> + <title>{% trans 'Nicedb - 评论详情' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> + <script src="{% static 'js/rating-star-readonly.js' %}"></script> <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> - - - <div class="review"> - <div class="review-head clearfix"> - <div class="mark-label float-left"> - <h4> - {{ review.title }} - {% if review.is_private %} - <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> - {% endif %} - </h4> - <a href="{% url 'users:home' review.owner.id %}" class="mark-owner-name">{{ review.owner.username }}</a> - - {% if mark %} - - {% if mark.rating %} - <span class="rating-star" data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> - {% endif %} - - {% endif %} - - <span class="mark-time">{{ review.edited_time }}</span> - </div> - - {% if request.user == review.owner %} - <div class="edit float-right"><a href="{% url 'books:update_review' review.id %}">{% trans '编辑' %}</a></div> - <div class="edit float-right"><a href="{% url 'books:delete_review' review.id %}">{% trans '删除' %}</a></div> + <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"> + {{ review.title }} + </h5> + {% if review.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg + xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <path + d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z" /> + </svg></span> {% endif %} - + <div class="review-head__body"> + <div class="review-head__info"> + + <a href="{% url 'users:home' review.owner.id %}" class="review-head__owner-link">{{ review.owner.username }}</a> + + {% if mark %} + + {% if mark.rating %} + <span class="review-head__rating-star rating-star" data-rating-score="{{ mark.rating | floatformat:"0" }}"></span> + {% endif %} + + {% endif %} + + <span class="review-head__time">{{ review.edited_time }}</span> + + </div> + <div class="review-head__actions"> + {% if request.user == review.owner %} + <a class="review-head__action-link" href="{% url 'books:update_review' review.id %}">{% trans '编辑' %}</a> + <a class="review-head__action-link" href="{% url 'books:delete_review' review.id %}">{% trans '删除' %}</a> + {% endif %} + </div> + </div> + <!-- <div class="dividing-line"></div> --> + <div id="rawContent"> + {{ form.content }} + </div> + {{ form.media }} </div> - <div class="dividing-line"></div> - <div id="rawContent"> - {{ form.content }} + </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="{% url 'books:retrieve' book.id %}"><img src="{{ book.cover.url }}" alt="" + class="entity-card__img"></a> + </div> + <div class="entity-card__info-wrapper"> + <h5 class="entity-card__title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> + + {% if book.isbn %} + <div>ISBN: {{ book.isbn }}</div> + {% endif %} + + <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> + {% if book.rating %} + {% trans '评分: ' %}<span class="entity-card__rating-star rating-star" + data-rating-score="{{ book.rating | floatformat:"0" }}"></span> + <span class="entity-card__rating-score rating-score">{{ book.rating }}</span> + {% endif %} + </div> + </div> - {{ form.media }} </div> </div> - <div id="aside"> - <div class="aside-card"> - <div class="aside-item"> - <a href="{% url 'books:retrieve' book.id %}"><img src="{{ book.cover.url }}" alt="" class="item-image"></a> - <h5 class="item-title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> - - {% if book.isbn %} - <div>ISBN: {{ book.isbn }}</div> - {% endif %} - <div>{% if book.author %}{% trans '作者:' %} - {% for author in book.author %} - <span>{{ author }}</span> - {% endfor %} - {% endif %}</div> - <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> - <div>{%if book.pub_year %}{% trans '出版时间:' %}{{ book.pub_year }}{% trans '年' %}{% if book.pub_month %}{{ book.pub_month }}{% trans '月' %}{% endif %}{% endif %}</div> - - {% if book.rating %} - {% trans '评分: ' %}<span class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></span> - {% endif %} - - </div> - </div> - </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> @@ -126,15 +124,7 @@ location.href = "{% url 'common:search' %}" + "?q=" + q; } }); - ratingLabels = $("#aside .rating-star"); - $(ratingLabels).each( function(index, value) { - let ratingScore = $(this).data("rating-score") / 2; - $(this).starRating({ - initialRating: ratingScore, - readOnly: true, - starSize: 15, - }); - }); + $(".markdownx textarea").hide(); </script> </body> diff --git a/books/templates/books/review_list.html b/books/templates/books/review_list.html index 1630ac57..9ee12197 100644 --- a/books/templates/books/review_list.html +++ b/books/templates/books/review_list.html @@ -10,135 +10,109 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> - <title>{% trans 'Nicedb - 搜索结果' %}</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>{% trans 'Nicedb - ' %}{{ book.title }}{% trans '的评论' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <script src="{% static 'js/rating-star-readonly.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" - value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <h5 class="list-head"> - <a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a>{% trans ' 的评论' %} - </h5> - <ul class="result-items set"> - - {% for review in reviews %} - - <div class="list-item"> - <div class="item-label"> - <a href="{% url 'users:home' review.owner.id %}" class="item-owner-name">{{ review.owner.username }}</a> - {% if review.is_private %} - <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> - {% endif %} - <span class="item-time">{{ review.edited_time }}</span> - </div> - - <a href="{% url 'books:retrieve_review' review.id %}" class="review-title">{{ review.title }}</a> - - + <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="{% url 'books:retrieve' book.id %}">{{ book.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 'users:home' review.owner.id %}" class="entity-reviews__owner-link">{{ review.owner.username }}</a> + {% if review.is_private %} + <span class="icon-lock"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17,8.48h-.73V6.27a6.27,6.27,0,1,0-12.53,0V8.48H3a.67.67,0,0,0-.67.67V19.33A.67.67,0,0,0,3,20H17a.67.67,0,0,0,.67-.67V9.15A.67.67,0,0,0,17,8.48ZM6.42,6.27h0a3.57,3.57,0,0,1,7.14,0h0V8.48H6.42Z"/></svg></span> + {% endif %} + <span class="entity-reviews__review-time">{{ review.edited_time }}</span> + + + <span href="{% url 'books:retrieve_review' review.id %}" class="entity-reviews__review-title"><a href="{% url 'books:retrieve_review' review.id %}">{{ review.title }}</a></span> + + </li> + {% empty %} + <div>{% trans '无结果' %}</div> + {% endfor %} + + </ul> </div> - {% empty %} - {% trans '无结果' %} - {% endfor %} - - </ul> - <div class="pagination" > + <div class="pagination"> - <a - {% if reviews.has_previous %} - href="?page=1" - {% else %} - disabled - {% endif %}> - <button {% if not reviews.has_previous %}disabled{% endif %} class="button button-clear">{% trans "首页" %}</button> - </a> - - <a - {% if reviews.has_previous %} - href="?page={{ reviews.previous_page_number }}" - {% else %} - disabled - {% endif %}> - <button {% if not reviews.has_previous %}disabled{% endif %} class="button button-clear">{% trans "上一页" %}</button> - </a> - - <span class="page-index"> - {% trans "第" %}{% if request.GET.page %}{{ request.GET.page }}{% else %}1{% endif %}{% trans "页" %} - </span> - - <a - {% if reviews.has_next %} - href="?page={{ reviews.next_page_number }}" - {% else %} - disabled - {% endif %} - > - <button {% if not reviews.has_next %}disabled{% endif %} class="button button-clear">{% trans "下一页" %}</button> - </a> - - <a - {% if reviews.has_next %} - href="?page={{ reviews.paginator.num_pages }}" - {% else %} - disabled - {% endif %}> - <button {% if not reviews.has_next %}disabled{% endif %} class="button button-clear">{% trans "末页" %}</button> - </a> - - </div> - </div> - - <div id="aside"> - <div class="aside-card"> - <div class="aside-item"> - <a href="{% url 'books:retrieve' book.id %}"><img src="{{ book.cover.url }}" alt="" class="item-image"></a> - <h5 class="item-title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> - - {% if book.isbn %} - <div>ISBN: {{ book.isbn }}</div> + {% if reviews.pagination.has_prev %} + <a href="?page=1" class="pagination__nav-link pagination__nav-link">«</a> + <a href="?page={{ reviews.previous_page_number }}" + class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">‹</a> {% endif %} - - <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> - {% if book.rating %} - {% trans '评分: ' %}<span class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></span> + + {% 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">›</a> + <a href="?page={{ reviews.pagination.last_page }}" class="pagination__nav-link">»</a> + {% endif %} + </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="{% url 'books:retrieve' book.id %}"><img src="{{ book.cover.url }}" alt="" + class="entity-card__img"></a> + </div> + <div class="entity-card__info-wrapper"> + <h5 class="entity-card__title"><a href="{% url 'books:retrieve' book.id %}">{{ book.title }}</a></h5> + + {% if book.isbn %} + <div>ISBN: {{ book.isbn }}</div> + {% endif %} + + <div>{% if book.pub_house %}{% trans '出版社:' %}{{ book.pub_house }}{% endif %}</div> + {% if book.rating %} + {% trans '评分: ' %}<span class="entity-card__rating-star rating-star" + data-rating-score="{{ book.rating | floatformat:"0" }}"></span> + <span class="entity-card__rating-score rating-score">{{ book.rating }}</span> + {% endif %} + </div> + + </div> + </div> + </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> @@ -157,15 +131,6 @@ location.href = "{% url 'common:search' %}" + "?q=" + q; } }); - ratingLabels = $("#aside .rating-star"); - $(ratingLabels).each( function(index, value) { - let ratingScore = $(this).data("rating-score") / 2; - $(this).starRating({ - initialRating: ratingScore, - readOnly: true, - starSize: 15, - }); - }); </script> </body> diff --git a/books/templates/books/scrape.html b/books/templates/books/scrape.html index 2f5af257..d3e0cea2 100644 --- a/books/templates/books/scrape.html +++ b/books/templates/books/scrape.html @@ -9,54 +9,49 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 主页' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'js/scrape.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <style> - #scrapeForm label{ - font-size: small !important; + #scrape { + overflow: auto; } - textarea { + #scrape iframe { + width: 100%; + } + #scrape textarea { height: 200px; + resize: vertical; + } + #scrape iframe { + height: 500px; } </style> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" - value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if request.user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} + + <section id="content"> + <div class="grid grid--reverse-order"> + <div class="grid__main grid__main--reverse-order" id="main"> + <div class="main-section-wrapper"> + <div id="scrape"> + <h5> + {% trans '根据豆瓣内容填写下方表单' %} + </h5> + <iframe id='test' sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="https://search.douban.com/book/subject_search{% if q %}?search_text={{ q }}{% endif %}" frameborder="0"></iframe> + <div class="dividing-line"></div> + <div id="parser"> + <label style="font-size: small;">{% trans '解析器:' %}</label> + <textarea name="parser" id="" cols="30" rows="40" placeholder="复制信息粘贴至此自动解析,例: - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <div class="set"> - {% trans '根据豆瓣内容填写下方表单' %} - </div> - <iframe id='test' sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="https://search.douban.com/book/subject_search{% if q %}?search_text={{ q }}{% endif %}" frameborder="0"></iframe> - <div class="dividing-line"></div> - <div id="parser"> - <label style="font-size: small;">{% trans '解析器:' %}</label> - <textarea name="parser" id="" cols="30" rows="40" placeholder="复制信息粘贴至此自动解析,例: - 作者: [法] 雨果 出版社: 人民文学出版社 原作名: Les Misérables @@ -67,42 +62,38 @@ 装帧: 精装 丛书: 名著名译丛书 ISBN: 9787020104345 - "></textarea> - </div> - <div class="dividing-line"></div> - <div id="scrapeForm"> - <form action="{% url 'books:create' %}" method="POST" enctype="multipart/form-data"> - {% csrf_token %} - {{ form }} - </form> - <a href="{% url 'books:scrape' %}" class="button add-button submit">{% trans '剽取!' %}</a> + "></textarea> + </div> + <div class="dividing-line"></div> + <div id="scrapeForm"> + <form action="{% url 'books:create' %}" method="POST" enctype="multipart/form-data"> + {% csrf_token %} + {{ form }} + </form> + <a href="{% url 'books:scrape' %}" class="button add-button submit">{% trans '剽取!' %}</a> + </div> + </div> </div> </div> - <div id="aside"> - <div class="aside-card"> - <div class="add-nav"> - <div class="set"> - {% trans '或者复制详情页链接' %} - </div> - <form action="{% url 'books:click_to_scrape' %}" method="post"> - {% csrf_token %} - <input type="text" name="url" required placeholder="https://book.douban.com/subject/1000000/"> - <input type="submit" class="button add-button" value="{% trans '一键取剽取!' %}"> - </form> - - </div> + <div class="grid__aside grid__aside--reverse-order" id="aside"> + <div class="aside-section-wrapper aside-section-wrapper--singular"> + <h5> + {% trans '复制详情页链接' %} + </h5> + <form action="{% url 'books:click_to_scrape' %}" method="post"> + {% csrf_token %} + <input type="text" name="url" required placeholder="https://book.douban.com/subject/1000000/"> + <input type="submit" class="button add-button" value="{% trans '一键取剽取!' %}"> + </form> </div> - + </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> <script> diff --git a/books/views.py b/books/views.py index 012c25da..743f66ec 100644 --- a/books/views.py +++ b/books/views.py @@ -10,6 +10,8 @@ from django.core.files.uploadedfile import SimpleUploadedFile from common.mastodon import mastodon_request_included from common.mastodon.api import check_visibility, post_toot, TootVisibilityEnum from common.mastodon.utils import rating_to_emoji +from common.utils import PageLinksGenerator +from common.views import PAGE_LINK_NUMBER from .models import * from .forms import * from .forms import BookMarkStatusTranslator @@ -247,6 +249,7 @@ def retrieve_mark_list(request, book_id): paginator = Paginator(queryset, MARK_PER_PAGE) page_number = request.GET.get('page', default=1) marks = paginator.get_page(page_number) + marks.pagination = PageLinksGenerator(PAGE_LINK_NUMBER, page_number, paginator.num_pages) for m in marks: m.get_status_display = BookMarkStatusTranslator(m.status) return render( @@ -430,6 +433,7 @@ def retrieve_review_list(request, book_id): paginator = Paginator(queryset, REVIEW_PER_PAGE) page_number = request.GET.get('page', default=1) reviews = paginator.get_page(page_number) + reviews.pagination = PageLinksGenerator(PAGE_LINK_NUMBER, page_number, paginator.num_pages) return render( request, 'books/review_list.html', diff --git a/common/forms.py b/common/forms.py index 1403257a..4d6133e6 100644 --- a/common/forms.py +++ b/common/forms.py @@ -59,7 +59,7 @@ class RatingValidator: ) -class ImageInput(forms.FileInput): +class PreviewImageInput(forms.FileInput): template_name = 'widgets/image.html' def format_value(self, value): """ diff --git a/common/static/css/boofilsic.css b/common/static/css/boofilsic.css new file mode 100644 index 00000000..d19c48c8 --- /dev/null +++ b/common/static/css/boofilsic.css @@ -0,0 +1,1995 @@ +.button, +button, +input[type='button'], +input[type='reset'], +input[type='submit'] { + background-color: #00a1cc; + border: 0.1rem solid #00a1cc; + border-radius: .4rem; + color: #fff; + cursor: pointer; + display: inline-block; + font-size: 1.1rem; + font-weight: 700; + height: 3.4rem; + letter-spacing: .1rem; + line-height: 3.4rem; + padding: 0 2.8rem; + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; +} + +.button:focus, .button:hover, +button:focus, +button:hover, +input[type='button']:focus, +input[type='button']:hover, +input[type='reset']:focus, +input[type='reset']:hover, +input[type='submit']:focus, +input[type='submit']:hover { + background-color: #606c76; + border-color: #606c76; + color: #fff; + outline: 0; +} + +.button[disabled], +button[disabled], +input[type='button'][disabled], +input[type='reset'][disabled], +input[type='submit'][disabled] { + cursor: default; + opacity: .5; +} + +.button[disabled]:focus, .button[disabled]:hover, +button[disabled]:focus, +button[disabled]:hover, +input[type='button'][disabled]:focus, +input[type='button'][disabled]:hover, +input[type='reset'][disabled]:focus, +input[type='reset'][disabled]:hover, +input[type='submit'][disabled]:focus, +input[type='submit'][disabled]:hover { + background-color: #00a1cc; + border-color: #00a1cc; +} + +.button.button-outline, +button.button-outline, +input[type='button'].button-outline, +input[type='reset'].button-outline, +input[type='submit'].button-outline { + background-color: transparent; + color: #00a1cc; +} + +.button.button-outline:focus, .button.button-outline:hover, +button.button-outline:focus, +button.button-outline:hover, +input[type='button'].button-outline:focus, +input[type='button'].button-outline:hover, +input[type='reset'].button-outline:focus, +input[type='reset'].button-outline:hover, +input[type='submit'].button-outline:focus, +input[type='submit'].button-outline:hover { + background-color: transparent; + border-color: #606c76; + color: #606c76; +} + +.button.button-outline[disabled]:focus, .button.button-outline[disabled]:hover, +button.button-outline[disabled]:focus, +button.button-outline[disabled]:hover, +input[type='button'].button-outline[disabled]:focus, +input[type='button'].button-outline[disabled]:hover, +input[type='reset'].button-outline[disabled]:focus, +input[type='reset'].button-outline[disabled]:hover, +input[type='submit'].button-outline[disabled]:focus, +input[type='submit'].button-outline[disabled]:hover { + border-color: inherit; + color: #00a1cc; +} + +.button.button-clear, +button.button-clear, +input[type='button'].button-clear, +input[type='reset'].button-clear, +input[type='submit'].button-clear { + background-color: transparent; + border-color: transparent; + color: #00a1cc; +} + +.button.button-clear:focus, .button.button-clear:hover, +button.button-clear:focus, +button.button-clear:hover, +input[type='button'].button-clear:focus, +input[type='button'].button-clear:hover, +input[type='reset'].button-clear:focus, +input[type='reset'].button-clear:hover, +input[type='submit'].button-clear:focus, +input[type='submit'].button-clear:hover { + background-color: transparent; + border-color: transparent; + color: #606c76; +} + +.button.button-clear[disabled]:focus, .button.button-clear[disabled]:hover, +button.button-clear[disabled]:focus, +button.button-clear[disabled]:hover, +input[type='button'].button-clear[disabled]:focus, +input[type='button'].button-clear[disabled]:hover, +input[type='reset'].button-clear[disabled]:focus, +input[type='reset'].button-clear[disabled]:hover, +input[type='submit'].button-clear[disabled]:focus, +input[type='submit'].button-clear[disabled]:hover { + color: #00a1cc; +} + +select { + background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="#d1d1d1" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>') center right no-repeat; + padding-right: 3.0rem; +} + +select:focus { + background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="#9b4dca" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>'); +} + +textarea { + min-height: 6.5rem; + width: 100%; +} + +input, select { + width: 100%; +} + +label, +legend { + display: block; + margin-bottom: .5rem; +} + +fieldset { + border-width: 0; + padding: 0; +} + +input[type='checkbox'], +input[type='radio'] { + display: inline; +} + +.label-inline { + display: inline-block; + font-weight: normal; + margin-left: .5rem; +} + +dl, +ol, +ul { + list-style: none; + margin-top: 0; + padding-left: 0; +} + +ol { + list-style: decimal inside; +} + +ul { + list-style: circle inside; +} + +.button, +button, +dd, +dt, +li { + margin-bottom: 1.0rem; +} + +fieldset, +input, +select, +textarea { + margin-bottom: 1.5rem; +} + +blockquote, +dl, +figure, +form, +ol, +p, +pre, +table, +ul { + margin-bottom: 1rem; +} + +b, +strong { + font-weight: bold; +} + +p { + margin-top: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 300; + letter-spacing: -.1rem; + margin-bottom: 2.0rem; + margin-top: 0; +} + +h1 { + font-size: 4.6rem; + line-height: 1.2; +} + +h2 { + font-size: 3.6rem; + line-height: 1.25; +} + +h3 { + font-size: 2.8rem; + line-height: 1.3; +} + +h4 { + font-size: 2.2rem; + letter-spacing: -.08rem; + line-height: 1.35; +} + +h5 { + font-size: 1.8rem; + letter-spacing: -.05rem; + line-height: 1.5; +} + +h6 { + font-size: 1.6rem; + letter-spacing: 0; + line-height: 1.4; +} + +img { + max-width: 100%; + -o-object-fit: contain; + object-fit: contain; +} + +img.emoji { + height: 14px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -o-object-fit: contain; + object-fit: contain; + position: relative; + top: 3px; +} + +img.emoji--large { + height: 20px; + position: relative; + top: 2px; +} + +.clearfix:after { + clear: both; + content: ' '; + display: table; +} + +.float-left { + float: left; +} + +.float-right { + float: right; +} + +.highlight { + font-weight: bold; +} + +:root { + font-size: 10px; +} + +*, +*:after, +*:before { + -webkit-box-sizing: inherit; + box-sizing: inherit; +} + +html { + -webkit-box-sizing: border-box; + box-sizing: border-box; + height: 100%; +} + +body { + color: #606c76; + font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'Microsoft YaHei Light', sans-serif; + font-size: 1.3rem; + font-weight: 300; + letter-spacing: .05rem; + line-height: 1.6; + margin: 0; + height: 100%; +} + +textarea { + font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'Microsoft YaHei Light', sans-serif; +} + +a { + color: #00a1cc; + text-decoration: none; +} + +a:active, a:hover, a:hover:visited { + color: #606c76; +} + +li { + list-style: none; +} + +input[type=text]::-ms-clear, +input[type=text]::-ms-reveal { + display: none; + width: 0; + height: 0; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-results-button, +input[type="search"]::-webkit-search-results-decoration { + display: none; +} + +input[type='email'], +input[type='number'], +input[type='password'], +input[type='search'], +input[type='tel'], +input[type='text'], +input[type='url'], +textarea, +select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: transparent; + border: 0.1rem solid #ccc; + border-radius: .4rem; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-box-sizing: inherit; + box-sizing: inherit; + padding: .6rem 1.0rem; +} + +input[type='email']:focus, +input[type='number']:focus, +input[type='password']:focus, +input[type='search']:focus, +input[type='tel']:focus, +input[type='text']:focus, +input[type='url']:focus, +textarea:focus, +select:focus { + border-color: #00a1cc; + outline: 0; +} + +input[type='email']::-webkit-input-placeholder, +input[type='number']::-webkit-input-placeholder, +input[type='password']::-webkit-input-placeholder, +input[type='search']::-webkit-input-placeholder, +input[type='tel']::-webkit-input-placeholder, +input[type='text']::-webkit-input-placeholder, +input[type='url']::-webkit-input-placeholder, +textarea::-webkit-input-placeholder, +select::-webkit-input-placeholder { + color: #ccc; +} + +input[type='email']:-ms-input-placeholder, +input[type='number']:-ms-input-placeholder, +input[type='password']:-ms-input-placeholder, +input[type='search']:-ms-input-placeholder, +input[type='tel']:-ms-input-placeholder, +input[type='text']:-ms-input-placeholder, +input[type='url']:-ms-input-placeholder, +textarea:-ms-input-placeholder, +select:-ms-input-placeholder { + color: #ccc; +} + +input[type='email']::-ms-input-placeholder, +input[type='number']::-ms-input-placeholder, +input[type='password']::-ms-input-placeholder, +input[type='search']::-ms-input-placeholder, +input[type='tel']::-ms-input-placeholder, +input[type='text']::-ms-input-placeholder, +input[type='url']::-ms-input-placeholder, +textarea::-ms-input-placeholder, +select::-ms-input-placeholder { + color: #ccc; +} + +input[type='email']::placeholder, +input[type='number']::placeholder, +input[type='password']::placeholder, +input[type='search']::placeholder, +input[type='tel']::placeholder, +input[type='text']::placeholder, +input[type='url']::placeholder, +textarea::placeholder, +select::placeholder { + color: #ccc; +} + +::-moz-selection { + color: white; + background-color: #00a1cc; +} + +::selection { + color: white; + background-color: #00a1cc; +} + +.navbar { + background-color: #f7f7f7; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 10px 0; + margin-bottom: 50px; + border-bottom: #ccc 0.5px solid; +} + +.navbar .navbar__wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; +} + +.navbar .navbar__logo { + -ms-flex-preferred-size: 100px; + flex-basis: 100px; +} + +.navbar .navbar__logo-link { + display: inline-block; +} + +.navbar .navbar__link-list { + margin: 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: distribute; + justify-content: space-around; +} + +.navbar .navbar__link { + margin: 9px; + color: #606c76; +} + +.navbar .navbar__link:active, .navbar .navbar__link:hover, .navbar .navbar__link:hover:visited { + color: #00a1cc; +} + +.navbar .navbar__link:visited { + color: #606c76; +} + +.navbar .navbar__search-box { + margin: 0 12% 0 15px; + height: 32px; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + background-color: white !important; +} + +.navbar .navbar__dropdown-btn { + display: none; + padding: 0; + margin: 0; + border: none; + background-color: transparent; + color: #00a1cc; +} + +.navbar .navbar__dropdown-btn:focus, .navbar .navbar__dropdown-btn:hover { + background-color: transparent; + color: #606c76; +} + +@media (max-width: 575.98px) { + .navbar { + padding: 2px 0; + } + .navbar .navbar__wrapper { + display: block; + } + .navbar .navbar__logo-img { + width: 72px; + margin-right: 10px; + position: relative; + top: 7px; + } + .navbar .navbar__link-list { + margin-top: 7px; + max-height: 0; + -webkit-transition: max-height 0.6s ease-out; + transition: max-height 0.6s ease-out; + overflow: hidden; + } + .navbar .navbar__dropdown-btn { + display: block; + position: absolute; + right: 5px; + top: 3px; + -webkit-transform: scale(0.7); + transform: scale(0.7); + } + .navbar .navbar__dropdown-btn:hover + .navbar__link-list { + max-height: 500px; + -webkit-transition: max-height 0.6s ease-in; + transition: max-height 0.6s ease-in; + } + .navbar .navbar__search-box { + margin: 0; + width: 46vw; + height: 26px; + padding: 4px 6px; + } +} + +@media (max-width: 991.98px) { + .navbar { + margin-bottom: 20px; + } +} + +.grid { + margin: 0 auto; + position: relative; + max-width: 110rem; + padding: 0 2.0rem; + width: 100%; +} + +.grid .grid__main { + width: 70%; + float: left; + position: relative; +} + +.grid .grid__aside { + width: 26%; + float: right; + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -ms-flex-pack: distribute; + justify-content: space-around; +} + +.grid::after { + content: ' '; + clear: both; + display: table; +} + +@media (max-width: 575.98px) { + .grid .grid__aside { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } +} + +@media (max-width: 991.98px) { + .grid .grid__main { + width: 100%; + float: none; + } + .grid .grid__aside { + width: 100%; + float: none; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .grid .grid__aside--tablet-column { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + } + .grid--reverse-order { + -webkit-transform: scaleY(-1); + transform: scaleY(-1); + } + .grid .grid__main--reverse-order { + -webkit-transform: scaleY(-1); + transform: scaleY(-1); + } + .grid .grid__aside--reverse-order { + -webkit-transform: scaleY(-1); + transform: scaleY(-1); + } +} + +.pagination { + text-align: center; + width: 100%; +} + +.pagination .pagination__page-link { + font-weight: normal; + margin: 0 5px; +} + +.pagination .pagination__page-link--current { + font-weight: bold; + font-size: 1.2em; + color: #606c76; +} + +.pagination .pagination__nav-link { + font-size: 1.4em; + margin: 0 2px; +} + +.pagination .pagination__nav-link--right-margin { + margin-right: 18px; +} + +.pagination .pagination__nav-link--left-margin { + margin-left: 18px; +} + +.pagination .pagination__nav-link--hidden { + display: none; +} + +@media (max-width: 575.98px) { + .pagination .pagination__page-link { + margin: 0 3px; + } + .pagination .pagination__nav-link { + font-size: 1.4em; + margin: 0 2px; + } + .pagination .pagination__nav-link--right-margin { + margin-right: 10px; + } + .pagination .pagination__nav-link--left-margin { + margin-left: 10px; + } +} + +#page-wrapper { + position: relative; + min-height: 100vh; + z-index: 0; +} + +#content-wrapper { + padding-bottom: 160px; +} + +.footer { + padding-top: 0.4em !important; + text-align: center; + margin-bottom: 4px !important; + position: absolute !important; + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + bottom: 0; + width: 100%; +} + +.footer__border { + padding-top: 4px; + border-top: #f7f7f7 solid 2px; +} + +.footer__link { + margin: 0 12px; +} + +@media (max-width: 575.98px) { + #content-wrapper { + padding-bottom: 120px; + } +} + +.icon-lock svg { + fill: #ccc; + height: 12px; + position: relative; + top: 1px; + margin-left: 3px; +} + +.icon-cross svg { + fill: #ccc; + height: 10px; + position: relative; +} + +.icon-arrow svg { + fill: #606c76; + height: 15px; + position: relative; + top: 3px; +} + +.spinner { + display: inline-block; + position: relative; + left: 50%; + -webkit-transform: translateX(-50%) scale(0.4); + transform: translateX(-50%) scale(0.4); + width: 80px; + height: 80px; +} + +.spinner div { + -webkit-transform-origin: 40px 40px; + transform-origin: 40px 40px; + -webkit-animation: spinner 1.2s linear infinite; + animation: spinner 1.2s linear infinite; +} + +.spinner div::after { + content: " "; + display: block; + position: absolute; + top: 3px; + left: 37px; + width: 6px; + height: 18px; + border-radius: 20%; + background: #606c76; +} + +.spinner div:nth-child(1) { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; +} + +.spinner div:nth-child(2) { + -webkit-transform: rotate(30deg); + transform: rotate(30deg); + -webkit-animation-delay: -1s; + animation-delay: -1s; +} + +.spinner div:nth-child(3) { + -webkit-transform: rotate(60deg); + transform: rotate(60deg); + -webkit-animation-delay: -0.9s; + animation-delay: -0.9s; +} + +.spinner div:nth-child(4) { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-animation-delay: -0.8s; + animation-delay: -0.8s; +} + +.spinner div:nth-child(5) { + -webkit-transform: rotate(120deg); + transform: rotate(120deg); + -webkit-animation-delay: -0.7s; + animation-delay: -0.7s; +} + +.spinner div:nth-child(6) { + -webkit-transform: rotate(150deg); + transform: rotate(150deg); + -webkit-animation-delay: -0.6s; + animation-delay: -0.6s; +} + +.spinner div:nth-child(7) { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + -webkit-animation-delay: -0.5s; + animation-delay: -0.5s; +} + +.spinner div:nth-child(8) { + -webkit-transform: rotate(210deg); + transform: rotate(210deg); + -webkit-animation-delay: -0.4s; + animation-delay: -0.4s; +} + +.spinner div:nth-child(9) { + -webkit-transform: rotate(240deg); + transform: rotate(240deg); + -webkit-animation-delay: -0.3s; + animation-delay: -0.3s; +} + +.spinner div:nth-child(10) { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); + -webkit-animation-delay: -0.2s; + animation-delay: -0.2s; +} + +.spinner div:nth-child(11) { + -webkit-transform: rotate(300deg); + transform: rotate(300deg); + -webkit-animation-delay: -0.1s; + animation-delay: -0.1s; +} + +.spinner div:nth-child(12) { + -webkit-transform: rotate(330deg); + transform: rotate(330deg); + -webkit-animation-delay: 0s; + animation-delay: 0s; +} + +@-webkit-keyframes spinner { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes spinner { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +.bg-mask { + background-color: black; + z-index: 1; + -webkit-filter: opacity(20%); + filter: opacity(20%); + position: fixed; + width: 100%; + height: 100%; + left: 0; + top: 0; + display: none; +} + +.mark-modal { + z-index: 2; + display: none; + position: fixed; + width: 500px; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + background-color: #f7f7f7; + padding: 20px 20px 10px 20px; + color: #606c76; +} + +.mark-modal .mark-modal__head { + margin-bottom: 30px; +} + +.mark-modal .mark-modal__head::after { + content: ' '; + clear: both; + display: table; +} + +.mark-modal .mark-modal__title { + font-weight: bold; + font-size: 1.2em; + float: left; +} + +.mark-modal .mark-modal__close-button { + float: right; +} + +.mark-modal .mark-modal__confirm-button { + float: right; +} + +.mark-modal input[type="radio"] { + margin-right: 0; +} + +.mark-modal .mark-modal__rating-star { + display: inline; + float: left; + position: relative; + left: -3px; +} + +.mark-modal .mark-modal__status-radio { + float: right; +} + +.mark-modal .mark-modal__status-radio ul { + margin-bottom: 0; +} + +.mark-modal .mark-modal__status-radio li, .mark-modal .mark-modal__status-radio label { + display: inline; +} + +.mark-modal .mark-modal__status-radio input[type="radio"] { + position: relative; + top: 1px; +} + +.mark-modal .mark-modal__clear { + content: ' '; + clear: both; + display: table; +} + +.mark-modal .mark-modal__content-input, .mark-modal form textarea { + height: 200px; + width: 100%; + margin-top: 5px; + margin-bottom: 5px; + resize: vertical; +} + +.mark-modal .mark-modal__option { + margin-bottom: 24px; +} + +.mark-modal .mark-modal__option::after { + content: ' '; + clear: both; + display: table; +} + +.mark-modal .mark-modal__visibility-radio { + float: left; +} + +.mark-modal .mark-modal__visibility-radio ul, .mark-modal .mark-modal__visibility-radio li, .mark-modal .mark-modal__visibility-radio label { + display: inline; +} + +.mark-modal .mark-modal__visibility-radio label { + font-size: normal; +} + +.mark-modal .mark-modal__visibility-radio input[type="radio"] { + position: relative; + top: 2px; +} + +.mark-modal .mark-modal__share-checkbox { + float: right; +} + +.mark-modal .mark-modal__share-checkbox input[type="checkbox"] { + position: relative; + top: 2px; +} + +.confirm-modal { + z-index: 2; + display: none; + position: fixed; + width: 500px; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + background-color: #f7f7f7; + padding: 20px 20px 10px 20px; + color: #606c76; +} + +.confirm-modal .confirm-modal__head { + margin-bottom: 30px; +} + +.confirm-modal .confirm-modal__head::after { + content: ' '; + clear: both; + display: table; +} + +.confirm-modal .confirm-modal__title { + font-weight: bold; + font-size: 1.2em; + float: left; +} + +.confirm-modal .confirm-modal__close-button { + float: right; +} + +.confirm-modal .confirm-modal__confirm-button { + float: right; +} + +@media (max-width: 575.98px) { + .mark-modal, .confirm-modal { + width: 100%; + } +} + +.main-section-wrapper { + padding: 32px 48px 32px 36px; + background-color: #f7f7f7; +} + +.entity-list .entity-list__title { + margin-bottom: 20px; +} + +.entity-list .entity-list__entity { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin-bottom: 36px; +} + +.entity-list .entity-list__entity::after { + content: ' '; + clear: both; + display: table; +} + +.entity-list .entity-list__entity-img { + -o-object-fit: contain; + object-fit: contain; + min-width: 100px; + max-width: 100px; +} + +.entity-list .entity-list__entity-text { + margin-left: 20px; + overflow: hidden; +} + +.entity-list .entity-list__entity-link { + font-size: 1.2em; +} + +.entity-list .entity-list__entity-title { + display: block; +} + +.entity-list .entity-list__entity-info { + max-width: 76%; + white-space: nowrap; + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + position: relative; + top: 0.52em; +} + +.entity-list .entity-list__entity-info--full-length { + max-width: 100%; +} + +.entity-list .entity-list__entity-brief { + margin-top: 8px; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 4; + overflow: hidden; +} + +.entity-list .entity-list__rating { + display: inline-block; + margin: 0; +} + +.entity-list .entity-list__rating--empty { + margin-right: 5px; +} + +.entity-list .entity-list__rating-score { + margin-right: 5px; + position: relative; + top: 1px; +} + +.entity-list .entity-list__rating-star { + display: inline; + position: relative; + top: 0.3em; + left: -0.3em; +} + +.entity-detail .entity-detail__img { + height: 210px; + -o-object-fit: contain; + object-fit: contain; + float: left; + max-width: 150px; +} + +.entity-detail .entity-detail__info { + float: left; + margin-left: 20px; + overflow: hidden; + text-overflow: ellipsis; + width: 70%; +} + +.entity-detail .entity-detail__title { + font-weight: bold; +} + +.entity-detail .entity-detail__fields { + display: inline-block; + vertical-align: top; + width: 48%; +} + +.entity-detail .entity-detail__fields div, .entity-detail .entity-detail__fields span { + margin: 1px 0; +} + +.entity-detail .entity-detail__rating { + position: relative; + top: -5px; +} + +.entity-detail .entity-detail__rating-star { + position: relative; + left: -4px; + top: 3px; +} + +.entity-detail .entity-detail__rating-score { + font-weight: bold; +} + +.entity-detail::after { + content: ' '; + clear: both; + display: table; +} + +.entity-desc { + margin-bottom: 28px; +} + +.entity-desc .entity-desc__title { + margin-bottom: 8px; +} + +.entity-marks { + margin-bottom: 28px; +} + +.entity-marks .entity-marks__title { + margin-bottom: 8px; +} + +.entity-marks .entity-marks__title > a { + margin-right: 5px; +} + +.entity-marks .entity-marks__title--stand-alone { + margin-bottom: 20px; +} + +.entity-marks .entity-marks__more-link { + margin-left: 5px; +} + +.entity-marks .entity-marks__mark { + margin: 0; + padding: 3px 0; + border-bottom: 1px dashed #e5e5e5; +} + +.entity-marks .entity-marks__mark:last-child { + border: none; +} + +.entity-marks .entity-marks__mark--wider { + padding: 6px 0; +} + +.entity-marks .entity-marks__mark-content { + margin-bottom: 0; +} + +.entity-marks .entity-marks__mark-time { + color: #ccc; + margin-left: 2px; +} + +.entity-marks .entity-marks__rating-star { + position: relative; + top: 4px; +} + +.entity-reviews:first-child { + margin-bottom: 28px; +} + +.entity-reviews .entity-reviews__title { + margin-bottom: 8px; +} + +.entity-reviews .entity-reviews__title > a { + margin-right: 5px; +} + +.entity-reviews .entity-reviews__title--stand-alone { + margin-bottom: 20px; +} + +.entity-reviews .entity-reviews__more-link { + margin-left: 5px; +} + +.entity-reviews .entity-reviews__review { + margin: 0; + padding: 3px 0; + border-bottom: 1px dashed #e5e5e5; +} + +.entity-reviews .entity-reviews__review:last-child { + border: none; +} + +.entity-reviews .entity-reviews__review--wider { + padding: 6px 0; +} + +.entity-reviews .entity-reviews__review-time { + color: #ccc; + margin-left: 2px; +} + +.dividing-line { + height: 0; + width: 100%; + margin: 40px 0 24px 0; + border-top: solid 1px #ccc; +} + +.entity-sort { + margin-bottom: 30px; +} + +.entity-sort .entity-sort__label { + font-size: large; + display: inline-block; + margin-bottom: 20px; +} + +.entity-sort .entity-sort__more-link { + margin-left: 5px; +} + +.entity-sort .entity-sort__entity-list { + 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; +} + +.entity-sort .entity-sort__entity { + padding: 0 10px; + -ms-flex-preferred-size: 20%; + flex-basis: 20%; + text-align: center; + display: inline-block; + color: #606c76; +} + +.entity-sort .entity-sort__entity:hover { + color: #00a1cc; +} + +.entity-sort .entity-sort__entity > a { + color: inherit; +} + +.entity-sort .entity-sort__entity-img { + height: 110px; +} + +.entity-sort .entity-sort__entity-name { + text-overflow: ellipsis; + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.related-user-list .related-user-list__title { + margin-bottom: 20px; +} + +.related-user-list .related-user-list__user { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-bottom: 20px; +} + +.related-user-list .related-user-list__user-info { + margin-left: 15px; + overflow: auto; +} + +.related-user-list .related-user-list__user-avatar { + max-height: 72px; +} + +.review-head .review-head__title { + display: inline-block; + font-weight: bold; +} + +.review-head .review-head__body { + margin-bottom: 10px; +} + +.review-head .review-head__body::after { + content: ' '; + clear: both; + display: table; +} + +.review-head .review-head__info { + float: left; +} + +.review-head .review-head__owner-link { + color: #ccc; +} + +.review-head .review-head__owner-link:hover { + color: #00a1cc; +} + +.review-head .review-head__time { + color: #ccc; +} + +.review-head .review-head__rating-star { + position: relative; + top: 3px; + left: -1px; +} + +.review-head .review-head__actions { + float: right; +} + +.review-head .review-head__action-link:not(:first-child) { + margin-left: 5px; +} + +@media (max-width: 575.98px) { + .entity-list .entity-list__entity { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + margin-bottom: 30px; + } + .entity-list .entity-list__entity-text { + margin-left: 0; + } + .entity-list .entity-list__entity-img-wrapper { + margin-bottom: 8px; + } + .entity-list .entity-list__entity-info { + max-width: unset; + } + .entity-list .entity-list__rating--empty + .entity-list__entity-info { + max-width: 70%; + } + .entity-detail { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + } + .entity-detail .entity-detail__title { + margin-bottom: 5px; + } + .entity-detail .entity-detail__info { + margin-left: 0; + float: none; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + } + .entity-detail .entity-detail__img { + margin-bottom: 24px; + float: none; + height: unset; + max-width: 170px; + } + .entity-detail .entity-detail__fields { + width: unset; + } + .dividing-line { + margin-top: 24px; + } + .entity-sort .entity-sort__entity { + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + } + .entity-sort .entity-sort__entity-img { + height: 130px; + } + .review-head .review-head__info { + float: unset; + } + .review-head .review-head__actions { + float: unset; + } +} + +@media (max-width: 991.98px) { + .main-section-wrapper { + padding: 32px 28px 28px 28px; + } + .entity-detail { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } +} + +.aside-section-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + width: 100%; + padding: 28px 25px 12px 25px; + background-color: #f7f7f7; + margin-bottom: 30px; +} + +.aside-section-wrapper--transparent { + background-color: unset; +} + +.aside-section-wrapper--collapse { + padding: unset; +} + +.add-entity-entries .add-entity-entries__entry { + margin-bottom: 10px; +} + +.add-entity-entries .add-entity-entries__label { + font-size: 1.2em; + margin-bottom: 8px; +} + +.action-panel { + margin-bottom: 20px; +} + +.action-panel .action-panel__label { + font-weight: bold; + margin-bottom: 12px; +} + +.action-panel .action-panel__button-group { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.action-panel .action-panel__button-group--center { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.action-panel .action-panel__button { + line-height: unset; + height: unset; + padding: 4px 15px; + margin: 0 5px; +} + +.mark-panel { + margin-bottom: 20px; +} + +.mark-panel .mark-panel__status { + font-weight: bold; +} + +.mark-panel .mark-panel__rating-star { + position: relative; + top: 2px; +} + +.mark-panel .mark-panel__actions { + float: right; +} + +.mark-panel .mark-panel__actions form { + display: inline; +} + +.mark-panel .mark-panel__time { + color: #ccc; + margin-bottom: 10px; +} + +.mark-panel .mark-panel__clear { + content: ' '; + clear: both; + display: table; +} + +.review-panel .review-panel__label { + font-weight: bold; +} + +.review-panel .review-panel__actions { + float: right; +} + +.review-panel .review-panel__time { + color: #ccc; + margin-bottom: 10px; +} + +.review-panel .review-panel__review-title { + display: block; + margin-bottom: 15px; + font-weight: bold; +} + +.review-panel .review-panel__clear { + content: ' '; + clear: both; + display: table; +} + +.user-profile .user-profile__header { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; + margin-bottom: 15px; +} + +.user-profile .user-profile__avatar { + width: 72px; +} + +.user-profile .user-profile__username { + font-size: large; + margin-left: 10px; + margin-bottom: 0; +} + +.user-profile .user-profile__report-link { + color: #ccc; +} + +.user-relation .user-relation__label { + display: inline-block; + font-size: large; + margin-bottom: 10px; +} + +.user-relation .user-relation__more-link { + margin-left: 5px; +} + +.user-relation .user-relation__related-user-list { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.user-relation .user-relation__related-user { + -ms-flex-preferred-size: 25%; + flex-basis: 25%; + padding: 0px 3px; + text-align: center; + display: inline-block; +} + +.user-relation .user-relation__related-user > a:hover { + color: #606c76; +} + +.user-relation .user-relation__related-user-avatar { + width: 48px; +} + +.user-relation .user-relation__related-user-name { + color: inherit; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.report-panel .report-panel__label { + display: inline-block; + margin-bottom: 10px; +} + +.report-panel .report-panel__report { + margin: 2px 0; +} + +.report-panel .report-panel__user-link { + margin: 0 2px; +} + +.report-panel .report-panel__all-link { + margin-left: 5px; +} + +.relation-dropdown .relation-dropdown__button { + display: none; +} + +.entity-card { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin-bottom: 10px; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.entity-card--horizontal { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; +} + +.entity-card .entity-card__img { + height: 150px; +} + +.entity-card .entity-card__rating-star { + position: relative; + top: 4px; + left: -3px; +} + +.entity-card .entity-card__rating-score { + position: relative; + top: 1px; + margin-left: 2px; +} + +.entity-card .entity-card__title { + margin-bottom: 10px; + margin-top: 5px; +} + +.entity-card .entity-card__info-wrapper--horizontal { + margin-left: 20px; +} + +.entity-card .entity-card__img-wrapper { + -ms-flex-preferred-size: 100px; + flex-basis: 100px; +} + +@media (max-width: 575.98px) { + .add-entity-entries { + display: block !important; + } + .add-entity-entries .add-entity-entries__button { + width: 100%; + } + .aside-section-wrapper:first-child { + margin-right: 0 !important; + margin-bottom: 0 !important; + } + .aside-section-wrapper--singular:first-child { + margin-bottom: 20px !important; + } + .action-panel { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .entity-card--horizontal { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -ms-flex-direction: column !important; + flex-direction: column !important; + } + .entity-card .entity-card__info-wrapper { + margin-left: 10px !important; + } + .entity-card .entity-card__info-wrapper--horizontal { + margin-left: 0 !important; + } +} + +@media (max-width: 991.98px) { + .add-entity-entries { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: distribute; + justify-content: space-around; + } + .aside-section-wrapper { + padding: 24px 25px 10px 25px; + margin-top: 20px; + } + .aside-section-wrapper:not(:last-child) { + margin-right: 20px; + } + .aside-section-wrapper--collapse { + padding: 24px 25px 10px 25px !important; + margin-top: 0; + margin-bottom: 0; + } + .aside-section-wrapper--collapse:first-child { + margin-right: 0; + } + .aside-section-wrapper--no-margin { + margin: 0; + } + .action-panel { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .action-panel .action-panel__button-group { + -webkit-box-pack: space-evenly; + -ms-flex-pack: space-evenly; + justify-content: space-evenly; + } + .relation-dropdown { + margin-bottom: 20px; + } + .relation-dropdown .relation-dropdown__button { + padding-bottom: 10px; + background-color: #f7f7f7; + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } + .relation-dropdown .relation-dropdown__button > .icon-arrow { + -webkit-transition: -webkit-transform 0.3s; + transition: -webkit-transform 0.3s; + transition: transform 0.3s; + transition: transform 0.3s, -webkit-transform 0.3s; + } + .relation-dropdown .relation-dropdown__button:hover > .icon-arrow { + -webkit-transform: rotate(-180deg); + transform: rotate(-180deg); + } + .relation-dropdown .relation-dropdown__button:hover + .relation-dropdown__body { + max-height: 500px; + -webkit-transition: max-height 0.6s ease-in; + transition: max-height 0.6s ease-in; + } + .relation-dropdown .relation-dropdown__body { + background-color: #f7f7f7; + max-height: 0; + -webkit-transition: max-height 0.6s ease-out; + transition: max-height 0.6s ease-out; + overflow: hidden; + } + .entity-card { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + } + .entity-card .entity-card__info-wrapper { + margin-left: 30px; + } +} + +.single-section-wrapper { + padding: 32px 36px; + background-color: #f7f7f7; + overflow: auto; +} + +.entity-form, .review-form { + overflow: auto; +} + +.entity-form > input[type='email'], +.entity-form > input[type='number'], +.entity-form > input[type='password'], +.entity-form > input[type='search'], +.entity-form > input[type='tel'], +.entity-form > input[type='text'], +.entity-form > input[type='url'], +.entity-form textarea, .review-form > input[type='email'], +.review-form > input[type='number'], +.review-form > input[type='password'], +.review-form > input[type='search'], +.review-form > input[type='tel'], +.review-form > input[type='text'], +.review-form > input[type='url'], +.review-form textarea { + width: 100%; +} + +.entity-form img, .review-form img { + display: block; +} + +.review-form .review-form__preview-button { + color: #00a1cc; + font-weight: bold; + cursor: pointer; +} + +.review-form .review-form__fyi { + color: #ccc; +} + +.review-form .review-form__main-content, .review-form textarea { + margin-bottom: 5px; + resize: vertical; + height: 400px; +} + +.review-form .review-form__option { + margin-top: 24px; + margin-bottom: 10px; +} + +.review-form .review-form__option::after { + content: ' '; + clear: both; + display: table; +} + +.review-form .review-form__visibility-radio { + float: left; +} + +.review-form .review-form__visibility-radio ul, .review-form .review-form__visibility-radio li, .review-form .review-form__visibility-radio label { + display: inline; +} + +.review-form .review-form__visibility-radio label { + font-size: normal; +} + +.review-form .review-form__visibility-radio input[type="radio"] { + position: relative; + top: 2px; +} + +.review-form .review-form__share-checkbox { + float: right; +} + +.review-form .review-form__share-checkbox input[type="checkbox"] { + position: relative; + top: 2px; +} + +@media (max-width: 575.98px) { + .review-form .review-form__visibility-radio { + float: unset; + } + .review-form .review-form__share-checkbox { + float: unset; + position: relative; + left: -3px; + } +} + +.markdownx-preview > p { + min-height: 100px; +} + +.rating-star .jq-star { + cursor: unset !important; +} diff --git a/common/static/css/boofilsic_browse.css b/common/static/css/boofilsic_browse.css index c83efffa..29312f0d 100644 --- a/common/static/css/boofilsic_browse.css +++ b/common/static/css/boofilsic_browse.css @@ -4,7 +4,7 @@ --primary: #00a1cc; --secondary: #606c76; --light: #ccc; - --bright: rgb(250, 250, 250); + --bright: rgb(247, 247, 247); } html { diff --git a/common/static/css/boofilsic_edit.css b/common/static/css/boofilsic_edit.css index 82b2d211..7a664209 100644 --- a/common/static/css/boofilsic_edit.css +++ b/common/static/css/boofilsic_edit.css @@ -4,7 +4,7 @@ --primary: #00a1cc; --secondary: #606c76; --light: #ccc; - --bright: rgb(250, 250, 250); + --bright: rgb(247, 247, 247); } html { diff --git a/common/static/css/boofilsic_modal.css b/common/static/css/boofilsic_modal.css deleted file mode 100644 index f8c0530f..00000000 --- a/common/static/css/boofilsic_modal.css +++ /dev/null @@ -1,89 +0,0 @@ -.bg-mask { - background-color: black; - z-index: 1; - filter: opacity(20%); - position: fixed; - width: 100%; - height: 100%; - left: 0; - top: 0; - display: none; -} -.modal { - z-index: 2; - display: none; - position: fixed; - width: 500px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - - background-color: var(--bright); - /* border: solid 2px var(--light); */ - padding: 20px 20px 0px 20px; - color: var(--secondary); -} - -.modal-head { - /* border-bottom: 1px solid var(--light); */ - padding-bottom: 30px; -} - -.modal-head .modal-title { - font-weight: bold; -} - -.modal-head .modal-close svg { - height: 10px; - cursor: pointer; - fill: var(--light); -} - -.modal-body form { - margin: 0; -} - -.modal-body, .modal-body label { - font-size: small; - font-weight: normal; -} - -.modal-body .modal-selection ul { - list-style-type: none; - display: inline; -} - -.modal-body .modal-selection ul li, .modal-body .modal-selection ul label { - display: inline; -} - -.modal-body .modal-selection ul li { - position: relative; - top: 1px; -} - -.modal-body .modal-checkbox { - position: relative; - top: 1px; -} - -.modal-body .modal-option { - -} - -.modal-body .modal-button { - margin: 15px 0 15px 0; - padding: 0; -} - -.modal-body textarea { - height: 160px; - margin-top: 5px; - margin-bottom: 5px; - resize: vertical; -} - -.modal-body input[type="checkbox"], .modal-body input[type="radio"] { - position: relative; - top: 2px; -} \ No newline at end of file diff --git a/common/static/img/logo_square.svg b/common/static/img/logo_square.svg new file mode 100644 index 00000000..ccc0ff8d --- /dev/null +++ b/common/static/img/logo_square.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><title>logo</title><path d="M2.46,18h.32l.55,1,.18.38h0a5.66,5.66,0,0,1,0-.6V18h.29v1.75H3.45l-.54-1-.18-.38h0c0,.19,0,.4,0,.59v.77h-.3Z" style="fill:#606c76"/><path d="M5.45,18h.31v1.75H5.45Z" style="fill:#606c76"/><path d="M7.34,18.88a.82.82,0,0,1,.8-.91.67.67,0,0,1,.5.22l-.16.2a.47.47,0,0,0-.34-.15c-.28,0-.48.24-.48.63s.18.64.48.64a.49.49,0,0,0,.37-.18l.17.2a.73.73,0,0,1-.56.25A.8.8,0,0,1,7.34,18.88Z" style="fill:#606c76"/><path d="M10.2,18h1.05v.26h-.74v.45h.63V19h-.63v.52h.77v.26H10.2Z" style="fill:#606c76"/><path d="M12.86,18h.47a.78.78,0,0,1,.85.87.78.78,0,0,1-.84.88h-.48Zm.45,1.5c.35,0,.55-.2.55-.63s-.2-.62-.55-.62h-.14V19.5Z" style="fill:#606c76"/><path d="M15.76,18h.56c.36,0,.62.11.62.43a.39.39,0,0,1-.24.38h0a.41.41,0,0,1,.34.42c0,.35-.29.51-.67.51h-.61Zm.53.72c.25,0,.35-.09.35-.24s-.11-.24-.34-.24h-.23v.48Zm0,.79c.26,0,.4-.09.4-.29s-.14-.26-.4-.26h-.26v.55Z" style="fill:#606c76"/><path d="M18.53,19.57a.2.2,0,1,1,.4,0,.2.2,0,1,1-.4,0Z" style="fill:#606c76"/><path d="M20.46,18.87c0-.57.31-.9.77-.9s.77.34.77.9-.32.91-.77.91S20.46,19.43,20.46,18.87Zm1.22,0c0-.39-.18-.63-.45-.63s-.45.24-.45.63.17.64.45.64S21.68,19.26,21.68,18.87Z" style="fill:#606c76"/><path d="M23.58,18h.59c.36,0,.64.13.64.52s-.28.55-.64.55h-.28v.68h-.31Zm.56.82c.24,0,.37-.1.37-.3s-.13-.27-.37-.27h-.25v.57Zm0,.16.23-.18.54.95h-.35Z" style="fill:#606c76"/><path d="M26.3,18.88a.83.83,0,0,1,.83-.91.72.72,0,0,1,.52.22l-.16.2a.5.5,0,0,0-.36-.15c-.31,0-.51.24-.51.63s.18.64.53.64a.44.44,0,0,0,.25-.07v-.38h-.33V18.8h.61v.77a.8.8,0,0,1-.56.21A.81.81,0,0,1,26.3,18.88Z" style="fill:#606c76"/><path d="M6.06,17H6l-3.61-.76a.18.18,0,0,1-.14-.18V10.78a.16.16,0,0,1,.07-.14.19.19,0,0,1,.15,0l3.6.76a.18.18,0,0,1,.14.18v5.27a.18.18,0,0,1-.06.14A.19.19,0,0,1,6.06,17ZM2.64,15.91l3.24.68V11.68L2.64,11Z" style="fill:#00a1cc"/><path d="M6.06,17A.15.15,0,0,1,6,17a.19.19,0,0,1-.07-.14V11.54A.18.18,0,0,1,6,11.36l3.6-.76a.2.2,0,0,1,.15,0,.19.19,0,0,1,.07.14v5.27a.18.18,0,0,1-.15.18L6.1,17Zm.18-5.31v4.91l3.24-.68V11Zm3.43,4.37Z" style="fill:#00a1cc"/><path d="M24.69,17a3.4,3.4,0,1,1,3.4-3.4A3.41,3.41,0,0,1,24.69,17Zm0-6.44a3,3,0,1,0,3,3A3,3,0,0,0,24.69,10.58Z" style="fill:#00a1cc"/><path d="M24.69,14.93A1.31,1.31,0,1,1,26,13.62,1.31,1.31,0,0,1,24.69,14.93Zm0-2.26a1,1,0,1,0,.95.95A.95.95,0,0,0,24.69,12.67Z" style="fill:#00a1cc"/><path d="M17.73,16H11.42a.18.18,0,0,1-.18-.18V11.39a.18.18,0,0,1,.18-.18h6.31a.18.18,0,0,1,.18.18v4.46A.18.18,0,0,1,17.73,16Zm-6.13-.36h6v-4.1h-6Z" style="fill:#00a1cc"/><path d="M19.94,16l-.08,0L17.65,14.9a.18.18,0,0,1-.1-.16V12.5a.18.18,0,0,1,.1-.16l2.21-1.11a.17.17,0,0,1,.17,0,.19.19,0,0,1,.09.15v4.46A.19.19,0,0,1,20,16Zm-2-1.4,1.85.92V11.69l-1.85.92Z" style="fill:#00a1cc"/></svg> \ No newline at end of file diff --git a/common/static/js/create_update.js b/common/static/js/create_update.js deleted file mode 100644 index e83a624a..00000000 --- a/common/static/js/create_update.js +++ /dev/null @@ -1,23 +0,0 @@ -$(document).ready( function() { - // assume there is only one input[file] on page - // $("input[type='file']").each(function() { - // $(this).after('<img src="#" alt="" id="previewImage" style="margin:10px 0; max-width:500px;"/>'); - // }) - - // mark required - $("input[required]").each(function() { - $(this).prev().prepend("*"); - }) - // preview uploaded pic - $("input[type='file']").change(function() { - if (this.files && this.files[0]) { - var reader = new FileReader(); - - reader.onload = function (e) { - $('#previewImage').attr('src', e.target.result); - } - - reader.readAsDataURL(this.files[0]); - } - }); -}); \ No newline at end of file diff --git a/common/static/js/create_update_review.js b/common/static/js/create_update_review.js index 574f0f23..715c1ed4 100644 --- a/common/static/js/create_update_review.js +++ b/common/static/js/create_update_review.js @@ -1,20 +1,21 @@ $(document).ready( function() { + $(".markdownx-preview").hide(); $(".markdownx textarea").attr("placeholder", "拖拽图片至编辑框即可插入哦~"); - $(".preview-button").click(function() { + $(".review-form__preview-button").click(function() { if ($(".markdownx-preview").is(":visible")) { - $(".preview-button").text("预览"); + $(".review-form__preview-button").text("预览"); $(".markdownx-preview").hide(); $(".markdownx textarea").show(); } else { - $(".preview-button").text("编辑"); + $(".review-form__preview-button").text("编辑"); $(".markdownx-preview").show(); $(".markdownx textarea").hide(); } }); - let ratingLabels = $("#main .rating-star"); + let ratingLabels = $(".rating-star"); $(ratingLabels).each( function(index, value) { let ratingScore = $(this).data("rating-score") / 2; $(this).starRating({ diff --git a/common/static/js/detail.js b/common/static/js/detail.js index c2659593..1458e532 100644 --- a/common/static/js/detail.js +++ b/common/static/js/detail.js @@ -7,12 +7,12 @@ $(document).ready( function() { }); // pop up new rating modal - $("#aside .mark .button-group .button").each(function() { + $("#addMarkPanel button").each(function() { $(this).click(function(e) { e.preventDefault(); let title = $(this).text().trim(); - $(".mark-modal .modal-title").text(title); - $(".mark-modal .modal-body textarea").val(""); + $(".mark-modal__title").text(title); + $(".mark-modal__body textarea").val(""); let status = $(this).data('status') $("input[name='status'][value='"+status+"']").prop("checked", true) $(".bg-mask").show(); @@ -30,10 +30,10 @@ $(document).ready( function() { }) // pop up modify mark modal - $(".mark a.edit").click(function(e) { + $(".mark-panel a.edit").click(function(e) { e.preventDefault(); - let title = $(".mark-status-label").text().trim(); - $(".mark-modal .modal-title").text(title); + let title = $(".mark-panel__status").text().trim(); + $(".mark-modal__title").text(title); $(".bg-mask").show(); $(".mark-modal").show(); }); @@ -77,10 +77,10 @@ $(document).ready( function() { // hide rating star when select wish const WISH_CODE = 1; - if ($(".modal-selection input[type='radio']:checked").val() == WISH_CODE) { + if ($("#statusSelection input[type='radio']:checked").val() == WISH_CODE) { $(".mark-modal .rating-star-edit").hide(); } - $(".modal-selection#statusSelection input[type='radio']").click(function() { + $("#statusSelection input[type='radio']").click(function() { if ($(this).val() == WISH_CODE) { $(".mark-modal .rating-star-edit").hide(); } else { @@ -90,16 +90,16 @@ $(document).ready( function() { }); // show confirm modal - $(".mark form a").click(function(e) { + $(".mark-panel a.delete").click(function(e) { e.preventDefault(); - $(".modal.confirm-modal").show(); + $(".confirm-modal").show(); $(".bg-mask").show(); }); // confirm modal $(".confirm-modal input[type='submit']").click(function(e) { e.preventDefault(); - $(".mark form").submit(); + $(".mark-panel form").submit(); }); }); \ No newline at end of file diff --git a/common/static/js/home.js b/common/static/js/home.js index 42a9b808..3b7ae39a 100644 --- a/common/static/js/home.js +++ b/common/static/js/home.js @@ -8,8 +8,8 @@ $(document).ready( function() { let followersSpinner = $("#spinner").clone().removeAttr("hidden"); let followingSpinner = $("#spinner").clone().removeAttr("hidden"); $("#userInfoCard").append(userInfoSpinner); - $("#userRelationCard h5:first").append(followingSpinner); - $("#userRelationCard h5:last").append(followersSpinner); + $("#followings h5").after(followingSpinner); + $("#followers h5").after(followersSpinner); $(".mast-following-more").hide(); $(".mast-followers-more").hide(); @@ -20,13 +20,13 @@ $(document).ready( function() { function(userData) { let userName; if (userData.display_name) { - userName = translateEmojis(userData.display_name, userData.emojis); + userName = translateEmojis(userData.display_name, userData.emojis, true); } else { userName = userData.username; } - $(".mast-user .mast-avatar").attr("src", userData.avatar); - $(".mast-user .mast-displayname").html(userName); - $(".mast-user .mast-brief").text($(userData.note).text()); + $("#userInfoCard .mast-avatar").attr("src", userData.avatar); + $("#userInfoCard .mast-displayname").html(userName); + $("#userInfoCard .mast-brief").text($(userData.note).text()); $(userInfoSpinner).remove(); } ); @@ -38,6 +38,8 @@ $(document).ready( function() { function(userList, request) { if (userList.length == 0) { $(".mast-followers").hide(); + $(".mast-followers").before("<div>暂无</div>"); + } else { if (userList.length > 4){ userList = userList.slice(0, 4); @@ -49,9 +51,9 @@ $(document).ready( function() { temp = $(template).clone(); temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find("a").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find("a").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); @@ -69,6 +71,7 @@ $(document).ready( function() { function(userList, request) { if (userList.length == 0) { $(".mast-following").hide(); + $(".mast-following").before("<div>暂无</div>"); } else { if (userList.length > 4){ userList = userList.slice(0, 4); @@ -80,9 +83,9 @@ $(document).ready( function() { temp = $(template).clone() temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find("a").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find("a").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); diff --git a/common/static/js/mastodon.js b/common/static/js/mastodon.js index 115d5a38..91defcbe 100644 --- a/common/static/js/mastodon.js +++ b/common/static/js/mastodon.js @@ -142,11 +142,18 @@ function getEmojiDict(emoji_list) { return dict; } -function translateEmojis(text, emoji_list) { +function translateEmojis(text, emoji_list, large) { let dict = getEmojiDict(emoji_list); let regex = /:(.*?):/g; - let translation = text.replace(regex, function (match) { - return "<img src=" + dict[match] + " class=emoji alt=" + match + ">"; - }); + let translation = null + if (large) { + translation = text.replace(regex, function (match) { + return "<img src=" + dict[match] + " class=emoji--large alt=" + match + ">"; + }); + } else { + translation = text.replace(regex, function (match) { + return "<img src=" + dict[match] + " class=emoji alt=" + match + ">"; + }); + } return translation; } diff --git a/common/static/sass/_AsideSection.sass b/common/static/sass/_AsideSection.sass new file mode 100644 index 00000000..f381718b --- /dev/null +++ b/common/static/sass/_AsideSection.sass @@ -0,0 +1,285 @@ +$aside-section-padding: 28px 25px 12px 25px +$aside-section-padding-mobile: 24px 25px 10px 25px + +.aside-section-wrapper + display: flex + flex: 1 + flex-direction: column + // align-items: center + width: 100% + padding: $aside-section-padding + background-color: $color-bright + margin-bottom: 30px + + &--transparent + background-color: unset + &--collapse + padding: unset + +.add-entity-entries + + & &__entry + margin-bottom: 10px + + & &__label + font-size: 1.2em + margin-bottom: 8px + + & &__button + +.action-panel + margin-bottom: 20px + + & &__label + // font-size: 1.2em + font-weight: bold + margin-bottom: 12px + + & &__button-group + display: flex + justify-content: space-between + &--center + justify-content: center + + & &__button + line-height: unset + height: unset + padding: 4px 15px + margin: 0 5px + // width: 100% + +.mark-panel + margin-bottom: 20px + + & &__status + font-weight: bold + + & &__rating-star + position: relative + top: 2px + + & &__actions + float: right + & form + display: inline + + & &__time + color: $color-light + margin-bottom: 10px + + & &__content + + & &__clear + @include clear + +.review-panel + & &__label + font-weight: bold + & &__actions + float: right + & &__time + color: $color-light + margin-bottom: 10px + + & &__review-title + display: block + margin-bottom: 15px + font-weight: bold + + & &__clear + @include clear + +.user-profile + & &__header + display: flex + align-items: flex-start + margin-bottom: 15px + + & &__avatar + width: 72px + + & &__username + font-size: large + margin-left: 10px + margin-bottom: 0 + + & &__bio + + & &__report-link + color: $color-light + +.user-relation + & &__label + display: inline-block + font-size: large + margin-bottom: 10px + + & &__more-link + margin-left: 5px + + & &__related-user-list + display: flex + justify-content: flex-start + + & &__related-user + flex-basis: 25% + padding: 0px 3px + text-align: center + display: inline-block + & > a + &:hover + color: $color-secondary + + & &__related-user-avatar + width: 48px + + & &__related-user-name + color: inherit + overflow: hidden + text-overflow: ellipsis + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + +.report-panel + & &__label + display: inline-block + margin-bottom: 10px + + & &__report-list + + & &__report + margin: 2px 0 + + & &__user-link + margin: 0 2px + + & &__all-link + margin-left: 5px + +.relation-dropdown + & &__button + display: none + +.entity-card + display: flex + margin-bottom: 10px + flex-direction: column + &--horizontal + flex-direction: row + + & &__img + height: 150px + + & &__rating-star + position: relative + top: 4px + left: -3px + + & &__rating-score + position: relative + top: 1px + margin-left: 2px + + & &__title + margin-bottom: 10px + margin-top: 5px + + & &__info-wrapper + &--horizontal + margin-left: 20px + + & &__img-wrapper + flex-basis: 100px + + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .add-entity-entries + display: block !important + & &__button + width: 100% + + .aside-section-wrapper + &:first-child + margin-right: 0 !important + margin-bottom: 0 !important + &--singular:first-child + margin-bottom: 20px !important + // &--no-padding + // padding: $aside-section-padding-mobile !important + // margin-top: 0 !important + .action-panel + flex-direction: column !important + + .entity-card + &--horizontal + flex-direction: column !important + // flex-direction: column !important + & &__info-wrapper + margin-left: 10px !important + &--horizontal + margin-left: 0 !important +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + .add-entity-entries + display: flex + justify-content: space-around + + .aside-section-wrapper + padding: $aside-section-padding-mobile + + margin-top: 20px + // &:not(:first-child) + &:not(:last-child) + margin-right: 20px + &--collapse + padding: $aside-section-padding-mobile !important + margin-top: 0 + margin-bottom: 0 + &:first-child + margin-right: 0 + &--no-margin + margin: 0 + + .action-panel + flex-direction: row + & &__button-group + justify-content: space-evenly + + .relation-dropdown + margin-bottom: 20px + & &__button + padding-bottom: 10px + background-color: $color-bright + width: 100% + display: flex + justify-content: center + align-items: center + + & &__button > .icon-arrow + transition: transform 0.3s + + & &__button:hover > .icon-arrow + transform: rotate(-180deg) + + & &__button:hover + &__body + max-height: 500px + transition: max-height 0.6s ease-in + + & &__body + background-color: $color-bright + max-height: 0 + transition: max-height 0.6s ease-out + overflow: hidden + + .entity-card + flex-direction: row + & &__info-wrapper + margin-left: 30px +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass \ No newline at end of file diff --git a/common/static/sass/_Blockquote.sass b/common/static/sass/_Blockquote.sass new file mode 100644 index 00000000..dff5ecad --- /dev/null +++ b/common/static/sass/_Blockquote.sass @@ -0,0 +1,12 @@ + +// Blockquote +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +blockquote + border-left: .3rem solid $color-quaternary + margin-left: 0 + margin-right: 0 + padding: 1rem 1.5rem + + *:last-child + margin-bottom: 0 diff --git a/common/static/sass/_Button.sass b/common/static/sass/_Button.sass new file mode 100644 index 00000000..db238d37 --- /dev/null +++ b/common/static/sass/_Button.sass @@ -0,0 +1,76 @@ + +// Button +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +.button, +button, +input[type='button'], +input[type='reset'], +input[type='submit'] + background-color: $color-primary + border: .1rem solid $color-primary + border-radius: .4rem + color: $color-initial + cursor: pointer + display: inline-block + font-size: 1.1rem + font-weight: 700 + height: 3.4rem + letter-spacing: .1rem + line-height: 3.4rem + padding: 0 2.8rem + // width: 100% + text-align: center + text-decoration: none + text-transform: uppercase + white-space: nowrap + + &:focus, + &:hover + background-color: $color-secondary + border-color: $color-secondary + color: $color-initial + outline: 0 + + &[disabled] + cursor: default + opacity: .5 + + &:focus, + &:hover + background-color: $color-primary + border-color: $color-primary + + &.button-outline + background-color: transparent + color: $color-primary + + &:focus, + &:hover + background-color: transparent + border-color: $color-secondary + color: $color-secondary + + &[disabled] + + &:focus, + &:hover + border-color: inherit + color: $color-primary + + &.button-clear + background-color: transparent + border-color: transparent + color: $color-primary + + &:focus, + &:hover + background-color: transparent + border-color: transparent + color: $color-secondary + + &[disabled] + + &:focus, + &:hover + color: $color-primary diff --git a/common/static/sass/_Code.sass b/common/static/sass/_Code.sass new file mode 100644 index 00000000..fd0d8df3 --- /dev/null +++ b/common/static/sass/_Code.sass @@ -0,0 +1,22 @@ + +// Code +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +code + background: $color-tertiary + border-radius: .4rem + font-size: 86% + margin: 0 .2rem + padding: .2rem .5rem + white-space: nowrap + +pre + background: $color-tertiary + border-left: .3rem solid $color-primary + overflow-y: hidden + + & > code + border-radius: 0 + display: block + padding: 1rem 1.5rem + white-space: pre diff --git a/common/static/sass/_Color.sass b/common/static/sass/_Color.sass new file mode 100644 index 00000000..74cfb583 --- /dev/null +++ b/common/static/sass/_Color.sass @@ -0,0 +1,13 @@ + +// Color +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +$color-initial: #fff !default +$color-primary: #00a1cc !default +$color-secondary: #606c76 !default +$color-tertiary: #fff !default +$color-quaternary: #d5d5d5 !default +$color-quinary: #e5e5e5 !default + +$color-light: #ccc +$color-bright: rgb(247, 247, 247) diff --git a/common/static/sass/_Divider.sass b/common/static/sass/_Divider.sass new file mode 100644 index 00000000..1583766f --- /dev/null +++ b/common/static/sass/_Divider.sass @@ -0,0 +1,8 @@ + +// Divider +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +hr + border: 0 + border-top: .1rem solid $color-tertiary + margin: 3.0rem 0 diff --git a/common/static/sass/_Footer.sass b/common/static/sass/_Footer.sass new file mode 100644 index 00000000..5b57ead6 --- /dev/null +++ b/common/static/sass/_Footer.sass @@ -0,0 +1,42 @@ +// these 2 id selectors are to make footer stay at the bottom +#page-wrapper + position: relative + min-height: 100vh + z-index: 0 + +#content-wrapper + padding-bottom: 160px + // min-height: 100vh; + +.footer + padding-top: 0.4em !important + text-align: center + margin-bottom: 4px !important + position: absolute !important + left: 50% + transform: translateX(-50%) + bottom: 0 + width: 100% + + + &__border + // width: 100% + padding-top: 4px; + border-top: $color-bright solid 2px + + &__link + margin: 0 12px + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + #content-wrapper + padding-bottom: 120px +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + pass +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass diff --git a/common/static/sass/_Form.sass b/common/static/sass/_Form.sass new file mode 100644 index 00000000..d7f56916 --- /dev/null +++ b/common/static/sass/_Form.sass @@ -0,0 +1,39 @@ + +// Form +// –––––––––––––––––––––––––––––––––––––––––––––––––– + + + +select + background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="#d1d1d1" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>') center right no-repeat + padding-right: 3.0rem + + &:focus + background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 0 29 14" width="29"><path fill="#9b4dca" d="M9.37727 3.625l5.08154 6.93523L19.54036 3.625"/></svg>') + +textarea + min-height: 6.5rem + width: 100% + +input, select + width: 100% + +label, +legend + display: block + // font-size: 1.6rem + // font-weight: 700 + margin-bottom: .5rem + +fieldset + border-width: 0 + padding: 0 + +input[type='checkbox'], +input[type='radio'] + display: inline + +.label-inline + display: inline-block + font-weight: normal + margin-left: .5rem diff --git a/common/static/sass/_Global.sass b/common/static/sass/_Global.sass new file mode 100644 index 00000000..be8a7597 --- /dev/null +++ b/common/static/sass/_Global.sass @@ -0,0 +1,107 @@ + +// Base +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +// Set box-sizing globally to handle padding and border widths +\:root + font-size: 10px + +*, +*:after, +*:before + box-sizing: inherit + +// The base font-size is set at 62.5% for having the convenience +// of sizing rems in a way that is similar to using px: 1.6rem = 16px +html + box-sizing: border-box + // font-size: 62.5% + height: 100% + +// Default body styles +body + color: $color-secondary + font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'Microsoft YaHei Light', sans-serif + font-size: 1.3rem + font-weight: 300 + letter-spacing: .05rem + line-height: 1.6 + margin: 0 + height: 100% + +textarea + font-family: 'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', 'Microsoft YaHei Light', sans-serif + +// default link styles +a + color: $color-primary + text-decoration: none + + &:active, + &:hover, + &:hover:visited + color: $color-secondary + + &:visited + // color: $color-primary + +li + list-style: none + +// clear the "x" button inside the search input box +input[type=text]::-ms-clear, +input[type=text]::-ms-reveal + display: none + width : 0 + height: 0 + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-results-button, +input[type="search"]::-webkit-search-results-decoration + display: none; + +input[type='email'], +input[type='number'], +input[type='password'], +input[type='search'], +input[type='tel'], +input[type='text'], +input[type='url'], +textarea, +select + appearance: none // Removes awkward default styles on some inputs for iOS + background-color: transparent + border: .1rem solid $color-light + border-radius: .4rem + box-shadow: none + box-sizing: inherit // Forced to replace inherit values of the normalize.css + padding: .6rem 1.0rem // The .6rem vertically centers text on FF, ignored by Webkit + + &:focus + border-color: $color-primary + outline: 0 + + &::placeholder + color: $color-light + +::selection + color: white + background-color: $color-primary + +// Mixins + +@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 diff --git a/common/static/sass/_Grid.sass b/common/static/sass/_Grid.sass new file mode 100644 index 00000000..6fcac292 --- /dev/null +++ b/common/static/sass/_Grid.sass @@ -0,0 +1,66 @@ + +// Grid +// –––––––––––––––––––––––––––––––––––––––––––––––––– +@mixin container + margin: 0 auto + position: relative + max-width: 110rem + padding: 0 2.0rem; + width: 100% + +.grid + @include container + + $main-width: 70% + $aside-width: 96% - $main-width + + & &__main + width: $main-width + float: left + position: relative + + & &__aside + width: $aside-width + // background-color: $color-bright + float: right + position: relative + + display: flex + flex-direction: column + justify-content: space-around + + &::after + @include clear + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .grid + & &__aside + flex-direction: column !important +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + .grid + & &__main + width: 100% + float: none + + & &__aside + width: 100% + float: none + flex-direction: row + &--tablet-column + flex-direction: column + &--reverse-order + transform: scaleY(-1) + & &__main--reverse-order + transform: scaleY(-1) + & &__aside--reverse-order + transform: scaleY(-1) +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass + + diff --git a/common/static/sass/_Icon.sass b/common/static/sass/_Icon.sass new file mode 100644 index 00000000..fa541c9b --- /dev/null +++ b/common/static/sass/_Icon.sass @@ -0,0 +1,51 @@ +.icon-lock svg + fill: $color-light + height: 12px + position: relative + top: 1px + margin-left: 3px + + +.icon-cross svg + fill: $color-light + height: 10px + position: relative + +.icon-arrow svg + fill: $color-secondary + height: 15px + position: relative + top: 3px + + +.spinner + display: inline-block + position: relative + left: 50% + transform: translateX(-50%) scale(0.4) + width: 80px + height: 80px + + & div + transform-origin: 40px 40px + animation: spinner 1.2s linear infinite + &::after + content: " "; + display: block; + position: absolute; + top: 3px; + left: 37px; + width: 6px; + height: 18px; + border-radius: 20%; + background: $color-secondary + @for $i from 1 through 12 + &:nth-child(#{$i}) + transform: rotate(($i - 1) * 30deg) + animation-delay: (12 - $i) * -0.1s + +@keyframes spinner + 0% + opacity: 1 + 100% + opacity: 0 diff --git a/common/static/sass/_Image.sass b/common/static/sass/_Image.sass new file mode 100644 index 00000000..3ca35ef4 --- /dev/null +++ b/common/static/sass/_Image.sass @@ -0,0 +1,19 @@ + +// Image +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +img + max-width: 100% + object-fit: contain + + &.emoji + height: 14px + box-sizing: border-box + object-fit: contain + position: relative + top: 3px + + &--large + height: 20px + position: relative + top: 2px diff --git a/common/static/sass/_List.sass b/common/static/sass/_List.sass new file mode 100644 index 00000000..c515d2f1 --- /dev/null +++ b/common/static/sass/_List.sass @@ -0,0 +1,22 @@ + +// List +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +dl, +ol, +ul + list-style: none + margin-top: 0 + padding-left: 0 + + dl, + ol, + ul + // font-size: 90% + // margin: 1.5rem 0 1.5rem 3.0rem + +ol + list-style: decimal inside + +ul + list-style: circle inside diff --git a/common/static/sass/_MainSection.sass b/common/static/sass/_MainSection.sass new file mode 100644 index 00000000..bca2b5ff --- /dev/null +++ b/common/static/sass/_MainSection.sass @@ -0,0 +1,385 @@ + +$main-section-padding: 32px 48px 32px 36px +$main-section-padding-mobile: 32px 28px 28px 28px + +$section-title-margin: 20px +$sub-sections-between-margin: 28px +$sub-section-title-margin: 8px + +.main-section-wrapper + padding: $main-section-padding + background-color: $color-bright + +// for search result etc +.entity-list + + & &__title + // font-size: large + margin-bottom: $section-title-margin + + & &__entities + + & &__entity + display: flex + margin-bottom: 36px + &::after + @include clear + + & &__entity-img + // float: left + object-fit: contain + // height: 150px + $width: 100px + min-width: $width + max-width: $width + + & &__entity-text + margin-left: 20px + overflow: hidden + // float: left + + & &__entity-link + font-size: 1.2em + + & &__entity-title + display: block + + & &__entity-info + max-width: 76% + white-space: nowrap + overflow: hidden + display: inline-block + text-overflow: ellipsis + position: relative + top: 0.52em + &--full-length + max-width: 100% + + & &__entity-brief + margin-top: 8px + display: -webkit-box + -webkit-box-orient: vertical + -webkit-line-clamp: 4 + overflow: hidden + + $rating-info-gap-width: 5px + & &__rating + display: inline-block + margin: 0 + + & &__rating--empty + // width: $empty-rating-width + margin-right: $rating-info-gap-width + + & &__rating-score + margin-right: $rating-info-gap-width + position: relative + top: 1px + + & &__rating-star + display: inline + position: relative + top: 0.3em + left: -0.3em + +// detail page +.entity-detail + + & &__img + height: 210px; + object-fit: contain; + float: left; + max-width: 150px; + + & &__info + float: left + margin-left: 20px + overflow: hidden + text-overflow: ellipsis + width: 70% + + & &__title + font-weight: bold + + & &__fields + display: inline-block + vertical-align: top + width: 48% + & div, & span + margin: 1px 0 + + & &__rating + position: relative + top: -5px + + & &__rating-star + position: relative + left: -4px + top: 3px + + & &__rating-score + font-weight: bold + + &::after + @include clear + +$mark-review-padding: 3px 0 +$mark-review-padding-wider: 6px 0 + +// includes title and description of an entity +// sub section +.entity-desc + margin-bottom: $sub-sections-between-margin + & &__title + margin-bottom: $sub-section-title-margin + & &__content + + & &__empty + +// includes marks of an entity +// sub section +.entity-marks + margin-bottom: $sub-sections-between-margin + & &__title + margin-bottom: $sub-section-title-margin + & > a + margin-right: 5px + &--stand-alone + margin-bottom: $section-title-margin + + & &__more-link + margin-left: 5px + & &__mark-list + + & &__mark + margin: 0 + padding: $mark-review-padding + border-bottom: 1px dashed $color-quinary + &:last-child + border: none + &--wider + padding: $mark-review-padding-wider + + & &__mark-content + margin-bottom: 0 + + & &__mark-time + color: $color-light + margin-left: 2px + + & &__owner-link + + & &__rating-star + position: relative + top: 4px + + & &__empty + +// includes reviews of an entity +// sub section +.entity-reviews + // when used alone + &:first-child + margin-bottom: $sub-sections-between-margin + & &__title + margin-bottom: $sub-section-title-margin + & > a + margin-right: 5px + &--stand-alone + margin-bottom: $section-title-margin + & &__more-link + margin-left: 5px + & &__review-list + + & &__review + margin: 0 + padding: $mark-review-padding + border-bottom: 1px dashed $color-quinary + &:last-child + border: none + &--wider + padding: $mark-review-padding-wider + + & &__review-time + color: $color-light + margin-left: 2px + & &__review-title + + & &__owner-link + + & &__empty + +.dividing-line + height: 0 + width: 100% + margin: 40px 0 24px 0 + border-top: solid 1px $color-light + +// on home page +.entity-sort + margin-bottom: 30px + & &__label + font-size: large + display: inline-block + margin-bottom: $section-title-margin + + & &__more-link + margin-left: 5px + + & &__entity-list + display: flex + justify-content: flex-start + // padding-left: 24px + flex-wrap: wrap + + & &__entity + padding: 0 10px + flex-basis: 20% + text-align: center + display: inline-block + color: $color-secondary + &:hover + color: $color-primary + & > a + color: inherit + + & &__entity-img + height: 110px + + & &__entity-name + text-overflow: ellipsis + overflow: hidden + display: -webkit-box + -webkit-box-orient: vertical + -webkit-line-clamp: 2 + + & &__empty + +// follower/following list page +.related-user-list + & &__title + margin-bottom: $section-title-margin + + & &__user + display: flex + justify-content: flex-start + margin-bottom: 20px + + & &__user-info + margin-left: 15px + overflow: auto + + & &__user-name + + & &__user-bio + + & &__user-avatar + max-height: 72px + +// review detail page +.review-head + & &__title + display: inline-block + font-weight: bold + + & &__body + margin-bottom: 10px + &::after + @include clear + + & &__info + float: left + + & &__owner-link + color: $color-light + &:hover + color: $color-primary + + & &__time + color: $color-light + + & &__rating-star + position: relative + top: 3px + left: -1px + + & &__actions + float: right + + & &__action-link + &:not(:first-child) + margin-left: 5px +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .entity-list + & &__entity + flex-direction: column + margin-bottom: 30px + & &__entity-text + margin-left: 0 + & &__entity-img-wrapper + margin-bottom: 8px + & &__entity-info + max-width: unset + & &__rating--empty + &__entity-info + max-width: 70% + + .entity-detail + flex-direction: column + & &__title + margin-bottom: 5px + & &__info + margin-left: 0 + float: none + display: flex + flex-direction: column + width: 100% + & &__img + margin-bottom: 24px + float: none + height: unset + max-width: 170px; + & &__fields + width: unset + + .entity-marks + & &__mark-list + + & &__mark + + & &__rating-star + + & &__rating-star + &__mark-time + // display: block + + .dividing-line + margin-top: 24px + + .entity-sort + & &__entity + flex-basis: 50% + // margin-left: 10px + // margin-right: 10px + & &__entity-img + height: 130px + + .review-head + & &__info + float: unset + & &__actions + float: unset +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + .main-section-wrapper + padding: $main-section-padding-mobile + + .entity-detail + display: flex + & &__info + // display: flex +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass \ No newline at end of file diff --git a/common/static/sass/_Modal.sass b/common/static/sass/_Modal.sass new file mode 100644 index 00000000..1e28a1ba --- /dev/null +++ b/common/static/sass/_Modal.sass @@ -0,0 +1,108 @@ +.bg-mask + background-color: black + z-index: 1 + filter: opacity(20%) + position: fixed + width: 100% + height: 100% + left: 0 + top: 0 + display: none + +@mixin modal + z-index: 2 + display: none + position: fixed + width: 500px + top: 50% + left: 50% + transform: translate(-50%, -50%) + background-color: $color-bright + padding: 20px 20px 10px 20px + color: $color-secondary + & &__head + margin-bottom: 30px + &::after + @include clear + + & &__title + font-weight: bold + font-size: 1.2em + float: left + + & &__close-button + float: right + + & &__body + + & &__confirm-button + float: right + +.mark-modal + @include modal + & input[type="radio"] + margin-right: 0 + + & &__rating-star + display: inline + float: left + position: relative + left: -3px + + & &__status-radio + float: right + & ul + margin-bottom: 0 + & li, & label + display: inline + & input[type="radio"] + position: relative + top: 1px + + & &__clear + @include clear + + & &__content-input, & form textarea + height: 200px + width: 100% + margin-top: 5px + margin-bottom: 5px + resize: vertical + + & &__option + margin-bottom: 24px + &::after + @include clear + + & &__visibility-radio + float: left + & ul, & li, & label + display: inline + & label + font-size: normal + & input[type="radio"] + position: relative + top: 2px + + & &__share-checkbox + float: right + & input[type="checkbox"] + position: relative + top: 2px + +.confirm-modal + @include modal + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .mark-modal, .confirm-modal + width: 100% +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + pass +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass \ No newline at end of file diff --git a/common/static/sass/_Navbar.sass b/common/static/sass/_Navbar.sass new file mode 100644 index 00000000..b68c70fe --- /dev/null +++ b/common/static/sass/_Navbar.sass @@ -0,0 +1,101 @@ + +.navbar + background-color: $color-bright + box-sizing: border-box + padding: 10px 0 + margin-bottom: 50px + border-bottom: $color-light 0.5px solid + + & &__wrapper + display: flex + justify-content: space-between + align-items: center + position: relative + + & &__logo + flex-basis: 100px + + & &__logo-link + display: inline-block + + & &__link-list + margin: 0 + display: flex + justify-content: space-around + + & &__link + margin: 9px + color: $color-secondary + + &:active, + &:hover, + &:hover:visited + color: $color-primary + + &:visited + color: $color-secondary + + & &__search-box + margin: 0 12% 0 15px + height: 32px + flex: 1 + background-color: white !important + + & &__dropdown-btn + display: none + padding: 0 + margin: 0 + border: none + + background-color: transparent + color: $color-primary + &:focus, + &:hover + background-color: transparent + color: $color-secondary + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .navbar + padding: 2px 0 + & &__wrapper + display: block + & &__logo-img + width: 72px + margin-right: 10px + position: relative + top: 7px + + // dropdown + & &__link-list + // display: block + margin-top: 7px + max-height: 0 + transition: max-height 0.6s ease-out + overflow: hidden; + & &__dropdown-btn + display: block + position: absolute + right: 5px + top: 3px + + transform: scale(0.7) + &:hover + .navbar__link-list + max-height: 500px + transition: max-height 0.6s ease-in + + & &__search-box + margin: 0 + width: 46vw + height: 26px + padding: 4px 6px +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + .navbar + margin-bottom: 20px +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass diff --git a/common/static/sass/_Pagination.sass b/common/static/sass/_Pagination.sass new file mode 100644 index 00000000..7e44f8ac --- /dev/null +++ b/common/static/sass/_Pagination.sass @@ -0,0 +1,61 @@ +.pagination + // position: absolute + // bottom: 30px + // left: 50% + // transform: translateX(-50%) + text-align: center + width: 100% + + & &__page-link + font-weight: normal + margin: 0 5px + + &--current + font-weight: bold + font-size: 1.2em + // text-decoration: underline + color: $color-secondary + + & &__nav-link + font-size: 1.4em + margin: 0 2px + + $nav-link-edge-margin-width: 18px + + &--right-margin + margin-right: $nav-link-edge-margin-width + + &--left-margin + margin-left: $nav-link-edge-margin-width + + &--hidden + display: none + + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .pagination + & &__page-link + margin: 0 3px + + & &__nav-link + font-size: 1.4em + margin: 0 2px + + $nav-link-edge-margin-width: 10px + + &--right-margin + margin-right: $nav-link-edge-margin-width + + &--left-margin + margin-left: $nav-link-edge-margin-width +// Medium devices (tablets, 768px and up) +@media (max-width: $medium-devices) + pass +// Large devices (desktops, 992px and up) +@media (max-width: $large-devices) + pass +// Extra large devices (large desktops, 1200px and up) +@media (max-width: $x-large-devices) + pass + diff --git a/common/static/sass/_SingleSection.sass b/common/static/sass/_SingleSection.sass new file mode 100644 index 00000000..7880893a --- /dev/null +++ b/common/static/sass/_SingleSection.sass @@ -0,0 +1,67 @@ +$single-section-padding: 32px 36px +$single-section-padding-mobile: 32px 28px + +.single-section-wrapper + padding: $single-section-padding + background-color: $color-bright + overflow: auto + +.entity-form, .review-form + overflow: auto + & > input[type='email'], + & > input[type='number'], + & > input[type='password'], + & > input[type='search'], + & > input[type='tel'], + & > input[type='text'], + & > input[type='url'], + & textarea + width: 100% + & img + display: block + +.review-form + & &__preview-button + color: $color-primary + font-weight: bold + cursor: pointer + + & &__fyi + color: $color-light + + & &__main-content, & textarea + margin-bottom: 5px + resize: vertical + height: 400px + + & &__option + margin-top: 24px + margin-bottom: 10px + &::after + @include clear + + & &__visibility-radio + float: left + & ul, & li, & label + display: inline + & label + font-size: normal + & input[type="radio"] + position: relative + top: 2px + + & &__share-checkbox + float: right + & input[type="checkbox"] + position: relative + top: 2px + +// Small devices (landscape phones, 576px and up) +@media (max-width: $small-devices) + .review-form + & &__visibility-radio + float: unset + & &__share-checkbox + float: unset + position: relative + left: -3px \ No newline at end of file diff --git a/common/static/sass/_Spacing.sass b/common/static/sass/_Spacing.sass new file mode 100644 index 00000000..6a36a669 --- /dev/null +++ b/common/static/sass/_Spacing.sass @@ -0,0 +1,27 @@ + +// Spacing +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +.button, +button, +dd, +dt, +li + margin-bottom: 1.0rem + +fieldset, +input, +select, +textarea + margin-bottom: 1.5rem + +blockquote, +dl, +figure, +form, +ol, +p, +pre, +table, +ul + margin-bottom: 1rem diff --git a/common/static/sass/_Table.sass b/common/static/sass/_Table.sass new file mode 100644 index 00000000..c27ec399 --- /dev/null +++ b/common/static/sass/_Table.sass @@ -0,0 +1,19 @@ + +// Table +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +table + border-spacing: 0 + width: 100% + +td, +th + border-bottom: .1rem solid $color-quinary + padding: 1.2rem 1.5rem + text-align: left + + &:first-child + padding-left: 0 + + &:last-child + padding-right: 0 diff --git a/common/static/sass/_Typography.sass b/common/static/sass/_Typography.sass new file mode 100644 index 00000000..a4b9a5bb --- /dev/null +++ b/common/static/sass/_Typography.sass @@ -0,0 +1,48 @@ + +// Typography +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +b, +strong + font-weight: bold + +p + margin-top: 0 + +h1, +h2, +h3, +h4, +h5, +h6 + font-weight: 300 + letter-spacing: -.1rem + margin-bottom: 2.0rem + margin-top: 0 + +h1 + font-size: 4.6rem + line-height: 1.2 + +h2 + font-size: 3.6rem + line-height: 1.25 + +h3 + font-size: 2.8rem + line-height: 1.3 + +h4 + font-size: 2.2rem + letter-spacing: -.08rem + line-height: 1.35 + +h5 + font-size: 1.8rem + letter-spacing: -.05rem + line-height: 1.5 + +h6 + font-size: 1.6rem + letter-spacing: 0 + line-height: 1.4 diff --git a/common/static/sass/_Utility.sass b/common/static/sass/_Utility.sass new file mode 100644 index 00000000..62474a45 --- /dev/null +++ b/common/static/sass/_Utility.sass @@ -0,0 +1,21 @@ + +// Utility +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +// Clear a float with .clearfix +.clearfix + + &:after + clear: both + content: ' ' // The space content is one way to avoid an Opera bug. + display: table + +// Float either direction +.float-left + float: left + +.float-right + float: right + +.highlight + font-weight: bold diff --git a/common/static/sass/_Vendor.sass b/common/static/sass/_Vendor.sass new file mode 100644 index 00000000..77b0b05e --- /dev/null +++ b/common/static/sass/_Vendor.sass @@ -0,0 +1,5 @@ +.markdownx-preview > p + min-height: 100px + +.rating-star .jq-star + cursor: unset !important \ No newline at end of file diff --git a/common/static/sass/boofilsic.sass b/common/static/sass/boofilsic.sass new file mode 100644 index 00000000..7726d68b --- /dev/null +++ b/common/static/sass/boofilsic.sass @@ -0,0 +1,33 @@ + +// Sass Modules +// –––––––––––––––––––––––––––––––––––––––––––––––––– + +// milligram +@import Color +// @import Blockquote +@import Button +// @import Code +// @import Divider +@import Form +@import List +@import Spacing +// @import Table +@import Typography +@import Image +@import Utility + +// boofilsic components +@import Global +@import Navbar +@import Grid +@import Pagination +@import Footer +@import Icon +@import Modal + +// boofilsic modules +@import MainSection +@import AsideSection +@import SingleSection + +@import Vendor \ No newline at end of file diff --git a/common/templates/common/error.html b/common/templates/common/error.html index 9025eb5f..0e42ef31 100644 --- a/common/templates/common/error.html +++ b/common/templates/common/error.html @@ -4,7 +4,7 @@ <html lang="en"> <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="refresh" content="3;url={% url 'common:home' %}"> <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> @@ -13,17 +13,19 @@ </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> + + <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> diff --git a/common/templates/common/home.html b/common/templates/common/home.html index c6b714ed..0b356969 100644 --- a/common/templates/common/home.html +++ b/common/templates/common/home.html @@ -9,192 +9,235 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 主页' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'js/mastodon.js' %}"></script> <script src="{% static 'js/home.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if request.user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> - - <section id="content" class="container"> - <div class="row"> - <div id="main"> - - <div class="set" id="bookWish"> - <h5 class="set-title"> - {% trans '想读的书' %} - </h5> - {% if wish_books_more %} - <a href="{% url 'users:book_list' user.id 'wish' %}" class="more-link">{% trans '更多' %}</a> - {% endif %} - - <ul class="row set-item-list"> - {% for wish_book_mark in wish_book_marks %} - <li class="column column-20 set-item"> - - <a href="{% url 'books:retrieve' wish_book_mark.book.id %}" > - <img src="{{ wish_book_mark.book.cover.url }}" alt="" class="set-item-image"> - <span class="set-item-title">{{ wish_book_mark.book.title | truncate:15 }}</span> - </a> - </li> - {% empty %} - <p class="set-empty">暂无记录</p> - {% endfor %} - </ul> - </div> - <div class="set" id="bookDo"> - <h5 class="set-title"> - {% trans '在读的书' %} - </h5> - {% if do_books_more %} - <a href="{% url 'users:book_list' user.id 'do' %}" class="more-link">{% trans '更多' %}</a> - {% endif %} - - <ul class="row set-item-list"> - {% for do_book_mark in do_book_marks %} - <li class="column column-20 set-item"> - - <a href="{% url 'books:retrieve' do_book_mark.book.id %}" > - <img src="{{ do_book_mark.book.cover.url }}" alt="" class="set-item-image"> - <span class="set-item-title">{{ do_book_mark.book.title | truncate:15 }}</span> - </a> - </li> - {% empty %} - <p class="set-empty">暂无记录</p> - {% endfor %} - </ul> - </div> - <div class="set" id="bookCollect"> - <h5 class="set-title"> - {% trans '读过的书' %} - </h5> - {% if collect_books_more %} - <a href="{% url 'users:book_list' user.id 'collect' %}" class="more-link">{% trans '更多' %}</a> - {% endif %} - - <ul class="row set-item-list"> - {% for collect_book_mark in collect_book_marks %} - <li class="column column-20 set-item"> - - <a href="{% url 'books:retrieve' collect_book_mark.book.id %}" > - <img src="{{ collect_book_mark.book.cover.url }}" alt="" class="set-item-image"> - <span class="set-item-title">{{ collect_book_mark.book.title | truncate:15 }}</span> - </a> - </li> - {% empty %} - <p class="set-empty">暂无记录</p> - {% endfor %} - </ul> - </div> - </div> - - <div id="aside"> - <div class="aside-card mast-user" id="userInfoCard"> - <div class="clearfix"> - <img src="" class="info-avatar mast-avatar" alt="{{ user.username }}"> - <a href="{% url 'users:home' user.id %}"> - <h5 class="info-name mast-displayname"></h5> - </a> + {% include "partial/_navbar.html" %} + + <section id="content"> + <div class="grid grid--reverse-order"> + <div class="grid__main grid__main--reverse-order"> + + <div class="main-section-wrapper"> + + <div class="entity-sort" id="bookWish"> + <h5 class="entity-sort__label"> + {% trans '想读的书' %} + </h5> + {% if wish_books_more %} + <a href="{% url 'users:book_list' user.id 'wish' %}" + class="entity-sort__more-link">{% trans '更多' %}</a> + {% endif %} + + <ul class="entity-sort__entity-list"> + {% for wish_book_mark in wish_book_marks %} + <li class="entity-sort__entity"> + + <a href="{% url 'books:retrieve' wish_book_mark.book.id %}"> + <img src="{{ wish_book_mark.book.cover.url }}" + alt="{{wish_book_mark.book.title}}" class="entity-sort__entity-img"> + <div class="entity-sort__entity-name" title="wish_book_mark.book.title"> + {{ wish_book_mark.book.title }}</div> + </a> + </li> + {% empty %} + <div>暂无记录</div> + {% endfor %} + </ul> </div> - <p class="info-brief mast-brief"></p> - <!-- <a href="#" class="follow">{% trans '关注TA' %}</a> --> - - {% if request.user != user %} - <a href="{% url 'users:report' %}?user_id={{ user.id }}" class="report">{% trans '举报用户' %}</a> - {% endif %} - + + <div class="entity-sort" id="bookWish"> + <h5 class="entity-sort__label"> + {% trans '在读的书' %} + </h5> + {% if do_books_more %} + <a href="{% url 'users:book_list' user.id 'do' %}" + class="entity-sort__more-link">{% trans '更多' %}</a> + {% endif %} + + <ul class="entity-sort__entity-list"> + {% for do_book_mark in do_book_marks %} + <li class="entity-sort__entity"> + + <a href="{% url 'books:retrieve' do_book_mark.book.id %}"> + <img src="{{ do_book_mark.book.cover.url }}" + alt="{{do_book_mark.book.title}}" class="entity-sort__entity-img"> + <div class="entity-sort__entity-name" title="{{do_book_mark.book.title}}"> + {{ do_book_mark.book.title }}</div> + </a> + </li> + {% empty %} + <div>暂无记录</div> + {% endfor %} + </ul> + </div> + + <div class="entity-sort" id="bookCollect"> + <h5 class="entity-sort__label"> + {% trans '读过的书' %} + </h5> + {% if collect_books_more %} + <a href="{% url 'users:book_list' user.id 'collect' %}" + class="entity-sort__more-link">{% trans '更多' %}</a> + {% endif %} + + <ul class="entity-sort__entity-list"> + {% for collect_book_mark in collect_book_marks %} + <li class="entity-sort__entity"> + + <a href="{% url 'books:retrieve' collect_book_mark.book.id %}"> + <img src="{{ collect_book_mark.book.cover.url }}" + alt="{{collect_book_mark.book.title}}" class="entity-sort__entity-img"> + <span class="entity-sort__entity-name" + title="{{collect_book_mark.book.title}}">{{ collect_book_mark.book.title }}</span> + </a> + </li> + {% empty %} + <div>暂无记录</div> + {% endfor %} + </ul> + </div> + </div> - <div class="relation-card" id="userRelationCard"> - <h5 class="relation-label"> - {% trans '关注的人' %} - </h5> - <a href="{% url 'users:following' user.id %}" class="more-link mast-following-more">{% trans '更多' %}</a> - <ul class="row mast-following relation-user-list"> - <li class="column column-25 relation-user"> - <img src="" alt="" class="relation-avatar"> - <a class="relation-name"></a> - </li> - </ul> - <h5 class="relation-label"> - {% trans '被他们关注' %} - </h5> - <a href="{% url 'users:followers' user.id %}" class="more-link mast-followers-more">{% trans '更多' %}</a> - <ul class="row mast-followers relation-user-list"> - <li class="column column-25 relation-user"> - <img src="" alt="" class="relation-avatar"> - <a class="relation-name"></a> - </li> - </ul> - </div> - - {% if request.user.is_staff %} - <div class="report-card" id="reportMessageCard"> - <h5 class="report-label">{% trans '举报信息' %}</h5> - <ul class="report-list"> - {% for report in reports %} - <li class="report-message"> - <a href="" class="report-user-link">{{ report.submit_user }}</a>{% trans '举报了' %}<a href="">{{ report.reported_user }}</a> - </li> - {% endfor %} - - </ul> - <a href="{% url 'users:manage_report' %}">全部举报</a> - </div> - {% endif %} - + </div> + + <div class="grid__aside grid__aside--reverse-order grid__aside--tablet-column"> + <div class="aside-section-wrapper aside-section-wrapper--no-margin"> + <div class="user-profile" id="userInfoCard"> + <div class="user-profile__header"> + <!-- <img src="" class="user-profile__avatar mast-avatar" alt="{{ user.username }}"> --> + <img src="" class="user-profile__avatar mast-avatar"> + <a href="{% url 'users:home' user.id %}"> + <h5 class="user-profile__username mast-displayname"></h5> + </a> + </div> + <p class="user-profile__bio mast-brief"></p> + <!-- <a href="#" class="follow">{% trans '关注TA' %}</a> --> + + {% if request.user != user %} + <a href="{% url 'users:report' %}?user_id={{ user.id }}" + class="user-profile__report-link">{% trans '举报用户' %}</a> + {% endif %} + + </div> + </div> + + <div class="relation-dropdown"> + <div class="relation-dropdown__button"> + <span class="icon-arrow"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"> + <path d="M8.12,3.29,5,6.42,1.86,3.29H.45L5,7.84,9.55,3.29Z" /> + </svg> + </span> + </div> + <div class="relation-dropdown__body"> + <div + class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse"> + + <div class="user-relation" id="followings"> + <h5 class="user-relation__label"> + {% trans '关注的人' %} + </h5> + <a href="{% url 'users:following' user.id %}" + 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.id %}" + class="user-relation__more-link mast-followers-more">{% trans '更多' %}</a> + <ul class="user-relation__related-user-list mast-followers"> + <li class="user-relation__related-user"> + <a> + <img src="" alt="" class="user-relation__related-user-avatar"> + <div class="user-relation__related-user-name mast-displayname"> + </div> + </a> + </li> + </ul> + </div> + + </div> + <div + class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse"> + {% if request.user.is_staff and request.user == user%} + <div class="report-panel"> + <h5 class="report-panel__label">{% trans '举报信息' %}</h5> + <a class="report-panel__all-link" + href="{% url 'users:manage_report' %}">全部举报</a> + <ul class="report-panel__report-list"> + {% for report in reports %} + <li class="report-panel__report"> + <a href="{% url 'users:home' report.submit_user.id %}" + class="report-panel__user-link">{{ report.submit_user }}</a>{% trans '举报了' %}<a + href="{% url 'users:home' report.reported_user.id %}" + class="report-panel__user-link">{{ report.reported_user }}</a> + </li> + {% empty %} + <div>{% trans '暂无新举报' %}</div> + {% endfor %} + + </ul> + </div> + {% endif %} + </div> + </div> + </div> + + </div> + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> <div id="oauth2Token" hidden="true">{% oauth_token %}</div> <div id="mastodonURI" hidden="true">{% mastodon %}</div> - <!--current user mastodon id--> + <!--current user mastodon id--> <div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div> <div id="userPageURL" hidden="true">{% url 'users:home' 0 %}?is_mastodon_id=true</div> - <div class="spinner" id="spinner" hidden> - <div class="lds-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 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> + <script> $("#searchInput").on('keyup', function (e) { if (e.keyCode === 13) { @@ -207,4 +250,4 @@ </body> -</html> +</html> \ No newline at end of file diff --git a/common/templates/common/search_result.html b/common/templates/common/search_result.html index 21377df5..f1ec9667 100644 --- a/common/templates/common/search_result.html +++ b/common/templates/common/search_result.html @@ -10,172 +10,155 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 搜索结果' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'lib/js/rating-star.js' %}"></script> <script src="{% static 'js/rating-star-readonly.js' %}"></script> - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> <link rel="stylesheet" href="{% static 'lib/css/rating-star.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" - value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> + {% 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 %} + <ul class="entity-list__entities"> + + {% for book in items %} + + <li class="entity-list__entity"> + <div class="entity-list__entity-img-wrapper"> + <a href="{% url 'books:retrieve' book.id %}"> + <img src="{{ book.cover.url }}" alt="" class="entity-list__entity-img"> + </a> + </div> + <div class="entity-list__entity-text"> + + <div class="entity-list__entity-title"> + + <a href="{% url 'books:retrieve' book.id %}" class="entity-list__entity-link"> + {% if request.GET.q %} + {{ book.title | highlight:request.GET.q }} + {% else %} + {{ book.title }} + {% endif %} + </a> + </div> + + {% if book.rating %} + <div class="rating-star entity-list__rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></div> + <span class="entity-list__rating-score rating-score">{{ book.rating }}</span> + {% else %} + <div class="entity-list__rating entity-list__rating--empty"> {% trans '暂无评分' %}</div> + {% endif %} + + <span class="entity-list__entity-info"> + {% if book.pub_year %} + {{ book.pub_year }}{% trans '年' %} + {% if book.pub_month %} + {{book.pub_month }}{% trans '月' %} / + {% endif %} + {% endif %} + + {% if book.author %} + {% trans '作者' %} + {% for author in book.author %} + {{ author }}{% if not forloop.last %},{% endif %} + {% endfor %}/ + {% endif %} + + {% if book.translator %} + {% trans '译者' %} + {% for translator in book.translator %} + {{ translator }}{% if not forloop.last %},{% endif %} + {% endfor %}/ + {% endif %} + + {% if book.orig_title %} + {% trans '原名' %} + {{ book.orig_title }} + {% endif %} + </span> + <p class="entity-list__entity-brief"> + {{ book.brief }} + </p> + </div> + </li> + {% empty %} + {% trans '无结果' %} + {% endfor %} + + </ul> + </div> + <div class="pagination" > + + {% if items.pagination.has_prev %} + <a href="?page=1&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" class="pagination__nav-link pagination__nav-link">«</a> + <a href="?page={{ items.previous_page_number }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">‹</a> + {% endif %} + + {% for page in items.pagination.page_range %} + + {% if page == items.pagination.current_page %} + <a href="?page={{ page }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" class="pagination__page-link pagination__page-link--current">{{ page }}</a> + {% else %} + <a href="?page={{ page }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" class="pagination__page-link">{{ page }}</a> + {% endif %} + + {% endfor %} + + {% if items.pagination.has_next %} + <a href="?page={{ items.next_page_number }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" class="pagination__nav-link pagination__nav-link--left-margin">›</a> + <a href="?page={{ items.pagination.last_page }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" class="pagination__nav-link">»</a> + {% endif %} + + </div> + </div> + + </div> + + <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"> + 没有想要的结果? + </div> + <a href="{% url 'books:create' %}"> + <button class="add-entity-entries__button">添加一个条目</button> + </a> + </div> + <div class="add-entity-entries__entry"> + <div class="add-entity-entries__label"> + 或者(≖ ◡ ≖)✧ + </div> + <a href="{% url 'books:scrape' %}{% if request.GET.q %}?q={{ request.GET.q }}{% endif %}"> + <button class="add-entity-entries__button">从表瓣剽取数据</button> + </a> + </div> + + </div> + + </div> + </div> </div> </section> - - <section id="content" class="container"> - <div class="row"> - <div id="main"> - {% if request.GET.q %} - <div class="set"> - <h5 class="set-title"> - “{{ request.GET.q }}” {% trans '的搜索结果' %} - </h5> - </div> - {% endif %} - <ul class="result-items"> - - {% for book in items %} - - <li class="result-item clearfix"> - <a href="{% url 'books:retrieve' book.id %}"> - <img src="{{ book.cover.url }}" alt="" class="result-book-cover"> - </a> - <div class="result-info"> - - <a href="{% url 'books:retrieve' book.id %}" class="result-item-title"> - {% if request.GET.q %} - {{ book.title | highlight:request.GET.q }} - {% else %} - {{ book.title }} - {% endif %} - </a> - {% if book.rating %} - - <div class="rating-star" data-rating-score="{{ book.rating | floatformat:"0" }}"></div> - <span class="rating-score"> - {{ book.rating }} - </span> - {% else %} - <span class="rating-empty"> {% trans '暂无评分' %}</span> - {% endif %} - <span class="result-book-info"> - {% if book.pub_year %} - {{ book.pub_year }}{% trans '年' %} / - {% if book.pub_month %} - {{book.pub_month }}{% trans '月' %} / - {% endif %} - {% endif %} - - {% if book.author %} - {% trans '作者' %} - {% for author in book.author %} - {{ author }}{% if not forloop.last %},{% endif %} - {% endfor %}/ - {% endif %} - - {% if book.translator %} - {% trans '译者' %} - {% for translator in book.translator %} - {{ translator }}{% if not forloop.last %},{% endif %} - {% endfor %}/ - {% endif %} - - {% if book.orig_title %} - {% trans '原名' %} - {{ book.orig_title }} - {% endif %} - </span> - <p class="result-item-brief"> - {{ book.brief | truncate:170 }} - </p> - </div> - </li> - {% empty %} - {% trans '无结果' %} - {% endfor %} - - </ul> - <div class="pagination" > - - <a - {% if items.has_previous %} - href="?page=1&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" - {%else %} - disabled - {% endif %}> - <button {% if not items.has_previous %}disabled{% endif %} class="button button-clear">{% trans "首页" %}</button> - </a> - - <a - {% if items.has_previous %} - href="?page={{ items.previous_page_number }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" - {%else %} - disabled - {% endif %}> - <button {% if not items.has_previous %}disabled{% endif %} class="button button-clear">{% trans "上一页" %}</button> - </a> - - <span class="page-index"> - {% trans "第" %}{% if request.GET.page %}{{ request.GET.page }}{% else %}1{% endif %}{% trans "页" %} - </span> - - <a - {% if items.has_next %} - href="?page={{ items.next_page_number }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" - {% else %} - disabled - {% endif %} - > - <button {% if not items.has_next %}disabled{% endif %} class="button button-clear">{% trans "下一页" %}</button> - </a> - - <a - {% if items.has_next %} - href="?page={{ items.paginator.num_pages }}&q={% if request.GET.q %}{{ request.GET.q }}{% endif %}" - {%else %} - disabled - {% endif %}> - <button {% if not items.has_next %}disabled{% endif %} class="button button-clear">{% trans "末页" %}</button> - </a> - - </div> - </div> - - <div id="aside"> - <div class="aside-card"> - <div class="add-nav"> - <div>{% trans '没有想要的结果?' %}</div> - <a href="{% url 'books:create' %}" class="button add-button">{% trans '添加一个条目' %}</a> - <div>{% trans '或者' %}</div> - <a href="{% url 'books:scrape' %}{% if request.GET.q %}?q={{ request.GET.q }}{% endif %}" class="button add-button">{% trans '从表瓣剽取数据d(≖ ◡ ≖)✧' %}</a> - </div> - </div> - </div> - </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include 'partial/_footer.html' %} </div> diff --git a/common/templates/partial/_footer.html b/common/templates/partial/_footer.html new file mode 100644 index 00000000..ca67fb66 --- /dev/null +++ b/common/templates/partial/_footer.html @@ -0,0 +1,9 @@ +<footer class="footer"> + <div class="grid"> + <div class="footer__border"> + <a class="footer__link" target="_blank" href="https://donotban.com/@whitiewhite">作者长毛象</a> + <a class="footer__link" target="_blank" href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> + <a class="footer__link" target="_blank" href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> + </div> + </div> +</footer> \ No newline at end of file diff --git a/common/templates/partial/_navbar.html b/common/templates/partial/_navbar.html new file mode 100644 index 00000000..2f586f69 --- /dev/null +++ b/common/templates/partial/_navbar.html @@ -0,0 +1,28 @@ +{% load static %} +{% load i18n %} +{% load admin_url %} +<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> + + <input type="search" class="navbar__search-box" name="q" id="searchInput" required="true" + placeholder="搜索书影音,多个关键字以空格分割"> + <button class="navbar__dropdown-btn">• • •</button> + <ul class="navbar__link-list"> + <a class="navbar__link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> + <a class="navbar__link" href="{% url 'common:home' %}">{% trans '主页' %}</a> + {% if user.is_staff %} + <a class="navbar__link" href="{% admin_url %}">{% trans '后台' %}</a> + {% endif %} + </ul> + + </div> + + </div> + </nav> +</section> \ No newline at end of file diff --git a/common/templates/widgets/image.html b/common/templates/widgets/image.html index f469416d..114541bb 100644 --- a/common/templates/widgets/image.html +++ b/common/templates/widgets/image.html @@ -1,2 +1,15 @@ <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;"> \ No newline at end of file +<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 }}']").change(function () { + if (this.files && this.files[0]) { + var reader = new FileReader(); + + reader.onload = function (e) { + $('#previewImage').attr('src', e.target.result); + } + + reader.readAsDataURL(this.files[0]); + } + }); +</script> \ No newline at end of file diff --git a/common/utils.py b/common/utils.py new file mode 100644 index 00000000..b3f1ed98 --- /dev/null +++ b/common/utils.py @@ -0,0 +1,57 @@ +class PageLinksGenerator: + # TODO inherit django paginator + """ + Calculate the pages for multiple links pagination. + length -- the number of page links in pagination + """ + def __init__(self, length, current_page, total_pages): + current_page = int(current_page) + self.current_page = current_page + self.start_page = None + self.end_page = None + self.page_range = None + self.has_prev = None + self.has_next = None + + start_page = current_page - length // 2 + end_page = current_page + length // 2 + + # decision is based on the start page and the end page + # both sides overflow + if (start_page < 1 and end_page > total_pages)\ + or length >= total_pages: + self.start_page = 1 + self.end_page = total_pages + self.has_prev = False + self.has_next = False + + elif start_page < 1 and not end_page > total_pages: + self.start_page = 1 + # this won't overflow because the total pages are more than the length + self.end_page = end_page - (start_page - 1) + self.has_prev = False + if end_page == total_pages: + self.has_next = False + else: + self.has_next = True + + elif not start_page < 1 and end_page > total_pages: + self.end_page = total_pages + self.start_page = start_page - (end_page - total_pages) + self.has_next = False + if start_page == 1: + self.has_prev = False + else: + self.has_prev = True + + # both sides do not overflow + elif not start_page < 1 and not end_page > total_pages: + self.start_page = start_page + self.end_page = end_page + self.has_prev = True + self.has_next = True + + self.first_page = 1 + self.last_page = total_pages + self.page_range = range(self.start_page, self.end_page + 1) + # assert self.has_prev is not None and self.has_next is not None \ No newline at end of file diff --git a/common/views.py b/common/views.py index 38114751..80bdcb4c 100644 --- a/common/views.py +++ b/common/views.py @@ -2,6 +2,7 @@ from django.shortcuts import render from django.contrib.auth.decorators import login_required from books.models import Book from common.models import MarkStatusEnum +from common.utils import PageLinksGenerator from users.models import Report, User from django.core.paginator import Paginator from django.db.models import Q @@ -14,6 +15,9 @@ BOOKS_PER_SET = 5 # how many items are showed in one search result page ITEMS_PER_PAGE = 20 +# how many pages links in the pagination +PAGE_LINK_NUMBER = 7 + @login_required def home(request): @@ -66,6 +70,7 @@ def search(request): paginator = Paginator(queryset, ITEMS_PER_PAGE) page_number = request.GET.get('page', default=1) items = paginator.get_page(page_number) + items.pagination = PageLinksGenerator(PAGE_LINK_NUMBER, page_number, paginator.num_pages) return render( request, diff --git a/users/auth.py b/users/auth.py deleted file mode 100644 index e69de29b..00000000 diff --git a/users/forms.py b/users/forms.py index cf04969a..6de4bd53 100644 --- a/users/forms.py +++ b/users/forms.py @@ -1,7 +1,7 @@ from django import forms from .models import Report from django.utils.translation import gettext_lazy as _ - +from common.forms import PreviewImageInput class ReportForm(forms.ModelForm): class Meta: @@ -13,6 +13,8 @@ class ReportForm(forms.ModelForm): ] widgets = { 'message': forms.Textarea(attrs={'placeholder': _("详情")}), + 'image': PreviewImageInput() + # 'reported_user': forms.TextInput(), } labels = { 'reported_user': _("举报的用户"), diff --git a/users/static/js/followers_list.js b/users/static/js/followers_list.js index 75b04ece..7c5f31ce 100644 --- a/users/static/js/followers_list.js +++ b/users/static/js/followers_list.js @@ -11,29 +11,29 @@ $(document).ready( function() { let followingSpinner = $("#spinner").clone().removeAttr("hidden"); let mainSpinner = $("#spinner").clone().removeAttr("hidden"); - $("#main .user:first").hide(); + $(".mast-user:first").hide(); - $("#main").append(mainSpinner); + $(".mast-user-list").append(mainSpinner); $("#userInfoCard").append(userInfoSpinner); - $("#userRelationCard h5:first").append(followingSpinner); - $("#userRelationCard h5:last").append(followersSpinner); + $("#followings h5").after(followingSpinner); + $("#followers h5").after(followersSpinner); $(".mast-following-more").hide(); $(".mast-followers-more").hide(); getUserInfo( - id, - mast_uri, - token, - function(userData) { + id, + mast_uri, + token, + function (userData) { let userName; if (userData.display_name) { - userName = translateEmojis(userData.display_name, userData.emojis); + userName = translateEmojis(userData.display_name, userData.emojis, true); } else { userName = userData.username; } - $(".mast-user .mast-avatar").attr("src", userData.avatar); - $(".mast-user .mast-displayname").html(userName); - $(".mast-user .mast-brief").text($(userData.note).text()); + $("#userInfoCard .mast-avatar").attr("src", userData.avatar); + $("#userInfoCard .mast-displayname").html(userName); + $("#userInfoCard .mast-brief").text($(userData.note).text()); $(userInfoSpinner).remove(); } ); @@ -46,6 +46,7 @@ $(document).ready( function() { let subUserList = null; if (userList.length == 0) { $(".mast-followers").hide(); + $(".mast-followers").before("<div>暂无</div>"); } else { if (userList.length > 4){ subUserList = userList.slice(0, 4); @@ -57,9 +58,9 @@ $(document).ready( function() { temp = $(template).clone(); temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find("a").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find("a").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); @@ -68,20 +69,20 @@ $(document).ready( function() { } $(followersSpinner).remove(); // main - let template = $("#main .user").clone().show(); + let template = $(".mast-user").clone().show(); userList.forEach(data => { temp = $(template).clone(); - temp.find(".avatar").attr("src", data.avatar); + temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find(".user-name").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find(".user-name").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); - temp.find(".user-brief").text(data.note.replace(/(<([^>]+)>)/ig,"")); - $("#main .user:last").after(temp); + temp.find(".mast-brief").text(data.note.replace(/(<([^>]+)>)/ig,"")); + $(".mast-user:last").after(temp); }); mainSpinner.hide(); @@ -99,30 +100,31 @@ $(document).ready( function() { mast_uri, token, function(userList, request) { - // aside if (userList.length == 0) { - $("#aside .mast-following").hide(); + $(".mast-following").hide(); + $(".mast-following").before("<div>暂无</div>"); } else { if (userList.length > 4){ userList = userList.slice(0, 4); - $("#aside .mast-following-more").show(); + $(".mast-following-more").show(); } - let template = $("#aside .mast-following li").clone(); - $("#aside .mast-following").html(""); + let template = $(".mast-following li").clone(); + $(".mast-following").html(""); userList.forEach(data => { temp = $(template).clone() temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find("a").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find("a").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); - $("#aside .mast-following").append(temp); + $(".mast-following").append(temp); }); } $(followingSpinner).remove(); + } ); @@ -149,7 +151,7 @@ $(document).ready( function() { mainSpinner.hide(); return; } - let template = $("#main .user:first").clone().show(); + let template = $(".mast-user:first").clone().show(); let newUrlFlag = false; request.getResponseHeader('link').split(',').forEach(link => { if (link.includes('next')) { @@ -163,16 +165,17 @@ $(document).ready( function() { } userList.forEach(data => { temp = $(template).clone() - temp.find(".avatar").attr("src", data.avatar); + temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find(".user-name").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find(".user-name").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); - temp.find(".user-brief").text($(data.note).text()); - $("#main .user:last").after(temp); + temp.find(".mast-brief").text($(data.note).text()); + // console.log($(temp).html()) + $(".mast-user:last").after(temp); }); mainSpinner.hide(); // release lock diff --git a/users/static/js/following_list.js b/users/static/js/following_list.js index 1bb15910..c27dfc3f 100644 --- a/users/static/js/following_list.js +++ b/users/static/js/following_list.js @@ -11,29 +11,29 @@ $(document).ready( function() { let followingSpinner = $("#spinner").clone().removeAttr("hidden"); let mainSpinner = $("#spinner").clone().removeAttr("hidden"); - $("#main .user:first").hide(); + $(".mast-user:first").hide(); - $("#main").append(mainSpinner); + $(".mast-user-list").append(mainSpinner); $("#userInfoCard").append(userInfoSpinner); - $("#userRelationCard h5:first").append(followingSpinner); - $("#userRelationCard h5:last").append(followersSpinner); + $("#followings h5").after(followingSpinner); + $("#followers h5").after(followersSpinner); $(".mast-following-more").hide(); $(".mast-followers-more").hide(); getUserInfo( - id, - mast_uri, - token, - function(userData) { + id, + mast_uri, + token, + function (userData) { let userName; if (userData.display_name) { - userName = translateEmojis(userData.display_name, userData.emojis); + userName = translateEmojis(userData.display_name, userData.emojis, true); } else { userName = userData.username; } - $(".mast-user .mast-avatar").attr("src", userData.avatar); - $(".mast-user .mast-displayname").html(userName); - $(".mast-user .mast-brief").text($(userData.note).text()); + $("#userInfoCard .mast-avatar").attr("src", userData.avatar); + $("#userInfoCard .mast-displayname").html(userName); + $("#userInfoCard .mast-brief").text($(userData.note).text()); $(userInfoSpinner).remove(); } ); @@ -42,11 +42,12 @@ $(document).ready( function() { id, mast_uri, token, - function(userList, request) { + function (userList, request) { if (userList.length == 0) { $(".mast-followers").hide(); + $(".mast-followers").before("<div>暂无</div>"); } else { - if (userList.length > 4){ + if (userList.length > 4) { userList = userList.slice(0, 4); $(".mast-followers-more").show(); } @@ -56,9 +57,9 @@ $(document).ready( function() { temp = $(template).clone(); temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find("a").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find("a").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); @@ -77,43 +78,44 @@ $(document).ready( function() { // aside let subUserList = null; if (userList.length == 0) { - $("#aside .mast-following").hide(); + $(".mast-following").hide(); + $(".mast-following").before("<div>暂无</div>"); } else { if (userList.length > 4){ subUserList = userList.slice(0, 4); - $("#aside .mast-following-more").show(); + $(".mast-following-more").show(); } - let template = $("#aside .mast-following li").clone(); - $("#aside .mast-following").html(""); + let template = $(".mast-following li").clone(); + $(".mast-following").html(""); subUserList.forEach(data => { temp = $(template).clone() temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find("a").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find("a").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); - $("#aside .mast-following").append(temp); + $(".mast-following").append(temp); }); } $(followingSpinner).remove(); // main - let template = $("#main .user").clone().show(); + let template = $(".mast-user").clone().show(); userList.forEach(data => { temp = $(template).clone() - temp.find(".avatar").attr("src", data.avatar); + temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find(".user-name").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find(".user-name").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); - temp.find(".user-brief").text(data.note.replace(/(<([^>]+)>)/ig,"")); - $("#main .user:last").after(temp); + temp.find(".mast-brief").text(data.note.replace(/(<([^>]+)>)/ig,"")); + $(".mast-user:last").after(temp); }); mainSpinner.hide(); @@ -149,7 +151,7 @@ $(document).ready( function() { mainSpinner.hide(); return; } - let template = $("#main .user:first").clone().show(); + let template = $(".mast-user:first").clone().show(); let newUrlFlag = false; request.getResponseHeader('link').split(',').forEach(link => { if (link.includes('next')) { @@ -161,23 +163,25 @@ $(document).ready( function() { if (!newUrlFlag) { nextUrl = null; } + // console.log(userList.length) userList.forEach(data => { temp = $(template).clone() - temp.find(".avatar").attr("src", data.avatar); + temp.find("img").attr("src", data.avatar); if (data.display_name) { - temp.find(".user-name").html(translateEmojis(data.display_name, data.emojis)); + temp.find(".mast-displayname").html(translateEmojis(data.display_name, data.emojis)); } else { - temp.find(".user-name").text(data.username); + temp.find(".mast-displayname").text(data.username); } let url = $("#userPageURL").text().replace('0', data.id); temp.find("a").attr('href', url); - temp.find(".user-brief").text($(data.note).text()); - $("#main .user:last").after(temp); + temp.find(".mast-brief").text($(data.note).text()); + // console.log($(temp).html()) + $(".mast-user:last").after(temp); }); mainSpinner.hide(); - // release lock // console.log(userList[userList.length-1].username) // console.log(nextUrl) + // release lock requesting = false; }, }); diff --git a/users/templates/users/list.html b/users/templates/users/list.html deleted file mode 100644 index 6563b50a..00000000 --- a/users/templates/users/list.html +++ /dev/null @@ -1,157 +0,0 @@ -{% load static %} -{% load i18n %} -{% load admin_url %} -{% load mastodon %} -{% load oauth_token %} -{% load truncate %} -{% load highlight %} -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> - {% if is_followers_page %} - <title>{% trans 'Nicedb - 被他们关注' %}</title> - {% else %} - <title>{% trans 'Nicedb - 关注的人' %}</title> - {% endif %} - <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> - <script src="{% static 'js/mastodon.js' %}"></script> - - {% if is_followers_page %} - <script src="{% static 'js/followers_list.js' %}"></script> - {% else %} - <script src="{% static 'js/following_list.js' %}"></script> - {% endif %} - <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> -</head> - -<body> - <div id="page-wrapper"> - <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <input type="search" class="search-box" name="q" - value="{% if request.GET.q %}{{ request.GET.q }}{% endif %}" id="searchInput" required="true" placeholder="{% trans '搜索书影音,多个关键字以空格分割' %}"> - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if request.user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> - - <section id="content" class="container"> - <div class="row"> - <div id="main"> - <div class="set"> - <h5 class="set-title"> - {% if is_followers_page %} - {% trans ' 被他们关注' %} - {% else %} - {% trans '关注的人' %} - {% endif %} - </h5> - <div class="user clearfix"> - <img src="" alt="" class="avatar float-left"> - <div class="user-info float-left"> - - <a href=""> - <div class="user-name"></div> - </a> - <p class="user-brief"></p> - </div> - </div> - </div> - </div> - - <div id="aside"> - <div class="aside-card mast-user" id="userInfoCard"> - <div class="clearfix"> - <img src="" class="info-avatar mast-avatar" alt="{{ user.username }}"> - <a href="{% url 'users:home' user.id %}"> - <h5 class="info-name mast-displayname"></h5> - </a> - </div> - <p class="info-brief mast-brief"></p> - <!-- <a href="#" class="follow">{% trans '关注TA' %}</a> --> - - {% if request.user != user %} - <a href="{% url 'users:report' %}?user_id={{ user.id }}" class="report">{% trans '举报用户' %}</a> - {% endif %} - - </div> - <div class="relation-card" id="userRelationCard"> - <h5 class="relation-label"> - {% trans '关注的人' %} - </h5> - <a href="{% url 'users:following' user.id %}" class="more-link mast-following-more">{% trans '更多' %}</a> - <ul class="row mast-following relation-user-list"> - <li class="column column-25 relation-user"> - <img src="" alt="" class="relation-avatar"> - <a class="relation-name"></a> - </li> - </ul> - <h5 class="relation-label"> - {% trans '被他们关注' %} - </h5> - <a href="{% url 'users:followers' user.id %}" class="more-link mast-followers-more">{% trans '更多' %}</a> - <ul class="row mast-followers relation-user-list"> - <li class="column column-25 relation-user"> - <img src="" alt="" class="relation-avatar"> - <a class="relation-name"></a> - </li> - </ul> - </div> - </div> - </section> - </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> - </div> - - - <div id="oauth2Token" hidden="true">{% oauth_token %}</div> - <div id="mastodonURI" hidden="true">{% mastodon %}</div> - <!--current user mastodon id--> - <div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div> - <div id="userPageURL" hidden="true">{% url 'users:home' 0 %}?is_mastodon_id=true</div> - <div class="spinner" id="spinner" hidden> - <div class="lds-spinner"> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - <div></div> - </div> - </div> - <script> - $("#searchInput").on('keyup', function (e) { - if (e.keyCode === 13) { - let q = $(this).val(); - if (q) - location.href = "{% url 'common:search' %}" + "?q=" + q; - } - }); - </script> -</body> - - -</html> diff --git a/users/templates/users/login.html b/users/templates/users/login.html index 13a2d431..3891917d 100644 --- a/users/templates/users/login.html +++ b/users/templates/users/login.html @@ -5,7 +5,7 @@ <html lang="en"> <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> <link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}"> @@ -13,7 +13,8 @@ </head> <body> <div id="loginBox" class="box"> - + + <img src="{% static 'img/logo.svg' %}" class="logo" alt="boofilsic logo"> <div id="loginButton"> @@ -25,6 +26,7 @@ {% endif %} </div> + </div> </body> </html> \ No newline at end of file diff --git a/users/templates/users/manage_report.html b/users/templates/users/manage_report.html index a9f4f208..a4332c5f 100644 --- a/users/templates/users/manage_report.html +++ b/users/templates/users/manage_report.html @@ -9,37 +9,23 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 管理举报' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'js/create_update.js' %}"></script> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <h4 class="nav-title">{% trans '举报信息' %}</h4> - - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> + <section id="content"> + <div class="grid"> + <div class="single-section-wrapper" id="main"> {% for report in reports %} <div class="report"> @@ -57,14 +43,11 @@ {% endfor %} </div> - + + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> diff --git a/users/templates/users/register.html b/users/templates/users/register.html index ccadbadc..38c9333a 100644 --- a/users/templates/users/register.html +++ b/users/templates/users/register.html @@ -5,7 +5,7 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> <link rel="stylesheet" href="{% static 'css/boofilsic_box.css' %}"> @@ -23,11 +23,10 @@ 里瓣书影音继承了长毛象的用户关系,比如您在里瓣屏蔽了某人,那您将不会在书影音的公共区域看到TA的痕迹。 这里仍是一片处女地,丰富的内容需要大家共同创造! 请注意虽然您可以随意发表任何言论,但试图添加垃圾数据到公共数据领域(如添加不存在的乱码的书籍)将会受到制裁! - 本站使用了Cookie,请理解! + BTW欧盟惯例本站使用了Cookie,请理解! </p> <p> - 此外里瓣书影音现处于“公开阿尔法测试”阶段,您的数据存在丢失的可能,现阶段将不对用户数据负责,请您理解风险后再决定继续使用! - </p> + 此外里瓣书影音现处于“公开阿尔法测试”阶段,您的数据存在丢失的可能 <form action="{% url 'users:register' %}" method="post"> {% csrf_token %} diff --git a/users/templates/users/relation_list.html b/users/templates/users/relation_list.html new file mode 100644 index 00000000..5da544ac --- /dev/null +++ b/users/templates/users/relation_list.html @@ -0,0 +1,172 @@ +{% load static %} +{% load i18n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load highlight %} +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + {% if is_followers_page %} + <title>{% trans 'Nicedb - 被他们关注' %}</title> + {% else %} + <title>{% trans 'Nicedb - 关注的人' %}</title> + {% endif %} + <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> + <script src="{% static 'js/mastodon.js' %}"></script> + + {% if is_followers_page %} + <script src="{% static 'js/followers_list.js' %}"></script> + {% else %} + <script src="{% static 'js/following_list.js' %}"></script> + {% endif %} + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_browse.css' %}"> --> + <!-- <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> +</head> + +<body> + <div id="page-wrapper"> + <div id="content-wrapper"> + {% include 'partial/_navbar.html' %} + + <section id="content"> + <div class="grid grid--reverse-order"> + <div class="grid__main grid__main--reverse-order"> + <div class="main-section-wrapper"> + <div class="related-user-list mast-user-list"> + <h5 class="related-user-list__title"> + {% if is_followers_page %} + {% trans ' 被他们关注' %} + {% else %} + {% trans '关注的人' %} + {% endif %} + </h5> + <div class="related-user-list__user mast-user"> + <img src="" alt="" class="related-user-list__user-avatar"> + <div class="related-user-list__user-info"> + + <a href=""> + <div class="related-user-list__user-name mast-displayname"></div> + </a> + <p class="related-user-list__user-bio mast-brief"></p> + </div> + </div> + </div> + </div> + </div> + + <div class="grid__aside grid__aside--reverse-order grid__aside--tablet-column"> + <div class="aside-section-wrapper aside-section-wrapper--no-margin"> + <div class="user-profile" id="userInfoCard"> + <div class="user-profile__header"> + <!-- <img src="" class="user-profile__avatar mast-avatar" alt="{{ user.username }}"> --> + <img src="" class="user-profile__avatar mast-avatar"> + <a href="{% url 'users:home' user.id %}"> + <h5 class="user-profile__username mast-displayname"></h5> + </a> + </div> + <p class="user-profile__bio mast-brief"></p> + <!-- <a href="#" class="follow">{% trans '关注TA' %}</a> --> + + {% if request.user != user %} + <a href="{% url 'users:report' %}?user_id={{ user.id }}" + class="user-profile__report-link">{% trans '举报用户' %}</a> + {% endif %} + + </div> + </div> + + <div class="relation-dropdown"> + <div class="relation-dropdown__button"> + <span class="icon-arrow"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"> + <path d="M8.12,3.29,5,6.42,1.86,3.29H.45L5,7.84,9.55,3.29Z" /> + </svg> + </span> + </div> + <div class="relation-dropdown__body"> + <div class="aside-section-wrapper aside-section-wrapper--transparent aside-section-wrapper--collapse"> + + <div class="user-relation" id="followings"> + <h5 class="user-relation__label"> + {% trans '关注的人' %} + </h5> + <a href="{% url 'users:following' user.id %}" + 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.id %}" + class="user-relation__more-link mast-followers-more">{% trans '更多' %}</a> + <ul class="user-relation__related-user-list mast-followers"> + <li class="user-relation__related-user"> + <a> + <img src="" alt="" class="user-relation__related-user-avatar"> + <div class="user-relation__related-user-name mast-displayname"></div> + </a> + </li> + </ul> + </div> + + </div> + </div> + </div> + + </div> + </div> + </section> + </div> + {% include 'partial/_footer.html' %} + </div> + + + <div id="oauth2Token" hidden="true">{% oauth_token %}</div> + <div id="mastodonURI" hidden="true">{% mastodon %}</div> + <!--current user mastodon id--> + <div id="userMastodonID" hidden="true">{{ user.mastodon_id }}</div> + <div id="userPageURL" hidden="true">{% url 'users:home' 0 %}?is_mastodon_id=true</div> + <div id="spinner" hidden> + <div class="spinner"> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + </div> + </div> + + <script> + $("#searchInput").on('keyup', function (e) { + if (e.keyCode === 13) { + let q = $(this).val(); + if (q) + location.href = "{% url 'common:search' %}" + "?q=" + q; + } + }); + </script> +</body> + + +</html> \ No newline at end of file diff --git a/users/templates/users/report.html b/users/templates/users/report.html index 6f16db30..e9b07667 100644 --- a/users/templates/users/report.html +++ b/users/templates/users/report.html @@ -9,51 +9,34 @@ <head> <meta charset="UTF-8"> - <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% trans 'Nicedb - 举报用户' %}</title> <script src="https://cdn.staticfile.org/jquery/3.5.0/jquery.min.js"></script> <script src="{% static 'js/create_update.js' %}"></script> - <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> - <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <link rel="stylesheet" href="{% static 'css/boofilsic.css' %}"> + <!-- <link rel="stylesheet" href="{% static 'css/boofilsic_edit.css' %}"> + <link rel="stylesheet" href="{% static 'lib/css/milligram.css' %}"> --> </head> <body> <div id="page-wrapper"> <div id="content-wrapper"> - <section id="navbar" class="navbar"> - <div class="container"> - <nav class="clearfix"> - <a href="{% url 'common:home' %}"> - <img src="{% static 'img/logo.svg' %}" alt="" class="logo"> - </a> - <h4 class="nav-title">{% trans '举报用户' %}</h4> - - <a class="nav-link" id="logoutLink" href="{% url 'users:logout' %}">{% trans '登出' %}</a> - <a class="nav-link" href="{% url 'common:home' %}">{% trans '主页' %}</a> - {% if user.is_staff %} - <a class="nav-link" href="{% admin_url %}">{% trans '后台' %}</a> - {% endif %} - </nav> - </div> - </section> + {% include "partial/_navbar.html" %} - <section id="content" class="container"> - <div class="row"> - <div id="main"> + <section id="content"> + <div class="grid"> + <div class="single-section-wrapper" id="main"> <form action="{% url 'users:report' %}" method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form }} <input class="button" type="submit" value="{% trans '提交' %}"> </form> </div> - + + </div> </section> </div> - <footer class="container"> - <a href="https://donotban.com/@whitiewhite">去长毛象向作者提意见</a> - <a href="https://github.com/doubaniux/boofilsic/issues">报告错误</a> - <a href="https://github.com/doubaniux/boofilsic" id="githubLink">Github</a> - </footer> + {% include "partial/_footer.html" %} </div> @@ -72,6 +55,18 @@ location.href = "{% url 'common:search' %}" + "?q=" + q; } }); + // preview uploaded pic + $("input[type='file']").change(function () { + if (this.files && this.files[0]) { + var reader = new FileReader(); + + reader.onload = function (e) { + $('#previewImage').attr('src', e.target.result); + } + + reader.readAsDataURL(this.files[0]); + } + }); </script> </body> diff --git a/users/views.py b/users/views.py index db4aa14d..7cd77c3d 100644 --- a/users/views.py +++ b/users/views.py @@ -11,8 +11,9 @@ from .forms import ReportForm from common.mastodon.auth import * from common.mastodon.api import * from common.mastodon import mastodon_request_included -from common.views import BOOKS_PER_SET, ITEMS_PER_PAGE +from common.views import BOOKS_PER_SET, ITEMS_PER_PAGE, PAGE_LINK_NUMBER from common.models import MarkStatusEnum +from common.utils import PageLinksGenerator from books.models import * from boofilsic.settings import MASTODON_DOMAIN_NAME, CLIENT_ID, CLIENT_SECRET from books.forms import BookMarkStatusTranslator @@ -182,7 +183,7 @@ def home(request, id): @mastodon_request_included @login_required -def followers(request, id): +def followers(request, id): if request.method == 'GET': try: user = User.objects.get(pk=id) @@ -211,7 +212,7 @@ def followers(request, id): ) return render( request, - 'users/list.html', + 'users/relation_list.html', { 'user': user, 'is_followers_page': True, @@ -252,7 +253,7 @@ def following(request, id): ) return render( request, - 'users/list.html', + 'users/relation_list.html', { 'user': user, 'page_type': 'followers', @@ -299,6 +300,7 @@ def book_list(request, id, status): paginator = Paginator(queryset, ITEMS_PER_PAGE) page_number = request.GET.get('page', default=1) marks = paginator.get_page(page_number) + marks.pagination = PageLinksGenerator(PAGE_LINK_NUMBER, page_number, paginator.num_pages) list_title = str(BookMarkStatusTranslator(MarkStatusEnum[status.upper()])) + str(_("的书")) return render( request, @@ -353,6 +355,7 @@ def manage_report(request): if request.method == 'GET': reports = Report.objects.all() for r in reports.filter(is_read=False): + r.is_read = True r.save() return render( request,