Redesign Bookmark (#112)

This commit is contained in:
Phuoc Anh Kha Le 2024-05-29 00:14:42 -05:00 committed by GitHub
parent 829e6a802d
commit c6acfa5e05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 398 additions and 243 deletions

View file

@ -36,8 +36,8 @@
</h2>
<div class="blog-description">
<div class="summary content-description">
{% cache 86400 'post_summary' post.id %}
{{ post.summary|default(post.content, true)|markdown(lazy_load=True)|reference|str|safe }}
{% cache 86400 'post_content' post.id %}
{{ post.content|markdown(lazy_load=True)|reference|str|safe }}
{% endcache %}
</div>
<div class="show-more"> {{_("...More")}} </div>

View file

@ -134,112 +134,7 @@
</div>
{% endblock %}
{% macro contest_head(contest) %}
<a href="{{ url('contest_view', contest.key) }}" class="contest-list-title" style="margin-right: 5px;">
{{contest.name}}
</a>
<div class="contest-tags">
{% if not contest.is_visible %}
<span class="contest-tag contest-tag-hidden">
<i class="fa fa-eye-slash"></i> {{ _('hidden') }}
</span>
{% endif %}
{% if contest.is_editable %}
<span class="contest-tag contest-tag-edit">
<a href="{{ url('organization_contest_edit', organization.id, organization.slug, contest.key) }}" class="white">
<i class="fa fa-edit"></i> {{ _('Edit') }}
</a>
</span>
{% endif %}
{% if contest.is_private %}
<span class="contest-tag contest-tag-private">
<i class="fa fa-lock"></i> {{ _('private') }}
</span>
{% endif %}
{% if not hide_contest_orgs %}
{% if contest.is_organization_private %}
{% for org in contest.organizations.all() %}
{% include "organization/tag.html" %}
{% endfor %}
{% endif %}
{% endif %}
{% if contest.is_rated %}
<span class="contest-tag contest-tag-rated">
<i class="fa fa-bar-chart"></i> {{ _('rated') }}
</span>
{% endif %}
{% for tag in contest.tags.all() %}
<span style="background-color: {{ tag.color }}" class="contest-tag">
<a href="{{ url('contest_tag', tag.name) }}"
style="color: {{ tag.text_color }}"
data-featherlight="{{ url('contest_tag_ajax', tag.name) }}">
{{- tag.name -}}
</a>
</span>
{% endfor %}
</div>
{% endmacro %}
{% macro time_left(contest) %}
<div class="time-left">
{% if contest.time_limit %}
<div>
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
</div>
<div>
<b>{{_("End")}}</b>: {{ contest.end_time|date(_("H:i d/m/Y")) }}
</div>
{% else %}
<div>
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
</div>
{% endif %}
<div>
<b>{{_("Length")}}</b>:
{% if contest.time_limit %}
{% trans time_limit=contest.time_limit|timedelta('localized-no-seconds') %}{{ time_limit }}{% endtrans %}
{% else %}
{% trans duration=contest.contest_window_length|timedelta('localized-no-seconds') %}{{ duration }}{% endtrans %}
{% endif %}
</div>
</div>
{% endmacro %}
{% macro user_count(contest, user) %}
{% if contest.can_see_own_scoreboard(user) %}
<a href="{{ url('contest_ranking', contest.key) }}"><i class="fa fa-users"></i> {{ contest.user_count }}</a>
{% else %}
<i class="fa fa-users"></i>{{ contest.user_count }}
{% endif %}
{% endmacro %}
{% macro contest_join(contest, request) %}
{% if request.in_contest and request.participation.contest == contest %}
<button class="small" disabled>{{ _('In contest') }}</button>
{% elif request.profile.id in contest.editor_ids or request.profile.id in contest.tester_ids %}
<form action="{{ url('contest_join', contest.key) }}" method="post">
{% csrf_token %}
<input type="submit" class="unselectable button full small"
value="{{ _('Spectate') }}">
</form>
{% else %}
<form action="{{ url('contest_join', contest.key) }}" method="post">
{% csrf_token %}
<input type="submit" class="unselectable button full small join-warning"
value="{{ _('Join') }}">
</form>
{% endif %}
{% endmacro %}
{% macro contest_format_user(contest, show_user=True) %}
<div style="display: flex; flex-direction: column; height: 100%;">
<div class="contest-title"> {{ _('Format') }} </div>
<div style="flex-grow: 1">{{ contest.format.name }}</div>
{% if show_user %}
<div class="contest-title">{{ user_count(contest, request.user) }}</div>
{% endif %}
</div>
{% endmacro %}
{% from "contest/macros.html" import contest_head, time_left, user_count, contest_join, contest_format_user %}
{% block middle_content %}
<div class="tabs tabs-no-flex" style="width: 100%;margin-left: auto;margin-right: auto;">
@ -298,7 +193,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest) }}
{{ contest_format_user(contest, request) }}
</div>
<div class="participate-button">
{{ contest_join(contest, request) }}
@ -336,7 +231,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest) }}
{{ contest_format_user(contest, request) }}
</div>
<div class="participate-button">
{{ contest_join(contest, request) }}
@ -373,7 +268,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest, show_user=False) }}
{{ contest_format_user(contest, request, show_user=False) }}
</div>
</div>
{% endfor %}
@ -402,7 +297,7 @@
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest) }}
{{ contest_format_user(contest, request) }}
</div>
<div class="participate-button">
{% if request.in_contest and request.participation.contest == contest %}

View file

@ -0,0 +1,106 @@
{% macro contest_head(contest) %}
<a href="{{ url('contest_view', contest.key) }}" class="contest-list-title" style="margin-right: 5px;">
{{contest.name}}
</a>
<div class="contest-tags">
{% if not contest.is_visible %}
<span class="contest-tag contest-tag-hidden">
<i class="fa fa-eye-slash"></i> {{ _('hidden') }}
</span>
{% endif %}
{% if contest.is_editable %}
<span class="contest-tag contest-tag-edit">
<a href="{{ url('organization_contest_edit', organization.id, organization.slug, contest.key) }}" class="white">
<i class="fa fa-edit"></i> {{ _('Edit') }}
</a>
</span>
{% endif %}
{% if contest.is_private %}
<span class="contest-tag contest-tag-private">
<i class="fa fa-lock"></i> {{ _('private') }}
</span>
{% endif %}
{% if not hide_contest_orgs %}
{% if contest.is_organization_private %}
{% for org in contest.organizations.all() %}
{% include "organization/tag.html" %}
{% endfor %}
{% endif %}
{% endif %}
{% if contest.is_rated %}
<span class="contest-tag contest-tag-rated">
<i class="fa fa-bar-chart"></i> {{ _('rated') }}
</span>
{% endif %}
{% for tag in contest.tags.all() %}
<span style="background-color: {{ tag.color }}" class="contest-tag">
<a href="{{ url('contest_tag', tag.name) }}"
style="color: {{ tag.text_color }}"
data-featherlight="{{ url('contest_tag_ajax', tag.name) }}">
{{- tag.name -}}
</a>
</span>
{% endfor %}
</div>
{% endmacro %}
{% macro time_left(contest) %}
<div class="time-left">
{% if contest.time_limit %}
<div>
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
</div>
<div>
<b>{{_("End")}}</b>: {{ contest.end_time|date(_("H:i d/m/Y")) }}
</div>
{% else %}
<div>
<b>{{_("Start")}}</b>: {{ contest.start_time|date(_("H:i d/m/Y")) }}
</div>
{% endif %}
<div>
<b>{{_("Length")}}</b>:
{% if contest.time_limit %}
{% trans time_limit=contest.time_limit|timedelta('localized-no-seconds') %}{{ time_limit }}{% endtrans %}
{% else %}
{% trans duration=contest.contest_window_length|timedelta('localized-no-seconds') %}{{ duration }}{% endtrans %}
{% endif %}
</div>
</div>
{% endmacro %}
{% macro user_count(contest, user) %}
{% if contest.can_see_own_scoreboard(user) %}
<a href="{{ url('contest_ranking', contest.key) }}"><i class="fa fa-users"></i> {{ contest.user_count }}</a>
{% else %}
<i class="fa fa-users"></i>{{ contest.user_count }}
{% endif %}
{% endmacro %}
{% macro contest_join(contest, request) %}
{% if request.in_contest and request.participation.contest == contest %}
<button class="small" disabled>{{ _('In contest') }}</button>
{% elif request.profile.id in contest.editor_ids or request.profile.id in contest.tester_ids %}
<form action="{{ url('contest_join', contest.key) }}" method="post">
{% csrf_token %}
<input type="submit" class="unselectable button full small"
value="{{ _('Spectate') }}">
</form>
{% else %}
<form action="{{ url('contest_join', contest.key) }}" method="post">
{% csrf_token %}
<input type="submit" class="unselectable button full small join-warning"
value="{{ _('Join') }}">
</form>
{% endif %}
{% endmacro %}
{% macro contest_format_user(contest, request, show_user=True) %}
<div style="display: flex; flex-direction: column; height: 100%;">
<div class="contest-title"> {{ _('Format') }} </div>
<div style="flex-grow: 1">{{ contest.format.name }}</div>
{% if show_user %}
<div class="contest-title">{{ user_count(contest, request.user) }}</div>
{% endif %}
</div>
{% endmacro %}

View file

@ -32,7 +32,6 @@
window.page++;
renderKatex($('.middle-content')[0]);
onWindowReady();
activateBlogBoxOnClick();
})
}

View file

@ -27,7 +27,9 @@
<p>Authors: {{ link_users(authors) }}</p>
{% endif %}
{% endwith %}
{{ solution.content|markdown|reference|str|safe }}
{% cache 86400 'solution_content' solution.id %}
{{ solution.content|markdown(lazy_load=True)|reference|str|safe }}
{% endcache %}
</div>
<hr>
{% include "actionbar/list.html" %}

View file

@ -113,7 +113,7 @@
$('#go').click(clean_submit);
$('input#full_text, input#hide_solved, input#show_types, input#have_editorial, input#show_solved_only').click(function () {
$('input#full_text, input#hide_solved, input#show_types, input#have_editorial, input#show_solved_only, input#show_editorial').click(function () {
prep_form();
($('<form>').attr('action', window.location.pathname + '?' + form_serialize())
.append($('<input>').attr('type', 'hidden').attr('name', 'csrfmiddlewaretoken')

View file

@ -30,33 +30,6 @@
<script type="text/javascript">
let loadingPage;
function activateBlogBoxOnClick() {
$('.blog-box').on('click', function () {
var $description = $(this).children('.blog-description');
var max_height = $description.css('max-height');
if (max_height !== 'fit-content') {
$description.css('max-height', 'fit-content');
$(this).css('cursor', 'auto');
$(this).removeClass('pre-expand-blog');
$(this).children().children('.show-more').hide();
}
});
$('.blog-box').each(function () {
var $precontent = $(this).children('.blog-description').height();
var $content = $(this).children().children('.content-description').height();
if ($content == undefined) {
$content = $(this).children().children('.md-typeset').height()
}
if ($content > $precontent - 30) {
$(this).addClass('pre-expand-blog');
$(this).css('cursor', 'pointer');
} else {
$(this).children().children('.show-more').hide();
}
});
}
function navigateTo($elem, update_sidebar = false) {
var url = $elem.attr('href');
@ -86,7 +59,6 @@
$(document).prop('title', $(data).filter('title').text());
renderKatex($('.middle-right-content')[0]);
onWindowReady();
activateBlogBoxOnClick();
$('.xdsoft_datetimepicker').hide();
registerNavigation();
}
@ -114,7 +86,6 @@
window.addEventListener('popstate', (e) => {
window.location.href = e.currentTarget.location.href;
});
activateBlogBoxOnClick();
$('.left-sidebar-item').on('click', function (e) {
e.preventDefault();

View file

@ -7,92 +7,187 @@
{% include "user/user-tabs.html" %}
{% endblock %}
{% from "contest/macros.html" import contest_head, time_left, user_count, contest_format_user %}
{% block user_content %}
{% if blogs %}
<div class="bookmark-group">
<h3 class="unselectable toggle closed">
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Posts') }} ({{ blogs|length }})
</h3>
<table style="display: none" class="table toggled">
<tbody>
{% for post in blogs %}
{% set object = post.bookmark.linked_object %}
{% if object %}
<tr>
<td class="bookmark-name">
<a href="{{ url('blog_post', object.id, object.slug) }}">{{ object.title}} </a>
</td>
</tr>
<div class="tabs tabs-no-flex" style="width: 100%;margin-left: auto;margin-right: auto;">
<ul>
<li class="{{'active' if current_tab=='problems'}}">
<a href="?tab=problems">{{ _('Problems') }}</a>
</li>
<li class="{{'active' if current_tab=='contests'}}">
<a href="?tab=contests">{{ _('Contests') }}</a>
</li>
<li class="{{'active' if current_tab=='editorials'}}">
<a href="?tab=editorials">{{ _('Editorials') }}</a>
</li>
<li class="{{'active' if current_tab=='posts'}}">
<a href="?tab=posts">{{ _('Posts') }}</a>
</li>
</ul>
</div>
{% if current_tab == 'problems' %}
{% if bookmarks %}
{% for problem in bookmarks %}
<div class="blog-box">
<h3 class="problem-feed-name">
<a href="{{ url('problem_detail', problem.code) }}">
{{ problem.name }}
</a>
</h3>
{% with authors=problem.get_authors() %}
{% if authors %}
<div class="problem-feed-info-entry">
<i class="fa fa-pencil-square-o fa-fw"></i>
<span class="pi-value">{{ link_users(authors) }}</span>
</div>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% if problems %}
<div class="bookmark-group">
<h3 class="unselectable toggle closed">
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Problems') }} ({{ problems|length }})
</h3>
<table style="display: none" class="table toggled">
<tbody>
{% for problem in problems %}
{% set object = problem.bookmark.linked_object %}
{% if object %}
<tr>
<td class="bookmark-name">
<a href="{{ url('problem_detail', object.code) }}">{{ object.name}} </a>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% if contests %}
<div class="bookmark-group">
<h3 class="unselectable toggle closed">
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Contests') }} ({{ contests|length }})
</h3>
<table style="display: none" class="table toggled">
</thead>
<tbody>
{% for contest in contests %}
{% set object = contest.bookmark.linked_object %}
{% if object %}
<tr>
<td class="bookmark-name">
<a href="{{ url('contest_view', object.key) }}">{{ object.name}} </a>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% if solutions %}
<div class="bookmark-group">
<h3 class="unselectable toggle closed">
<span class="fa fa-chevron-right fa-fw"></span>{{ _('Editorials') }} ({{ solutions|length }})
</h3>
<table style="display: none" class="table toggled">
</thead>
<tbody>
{% for solution in solutions %}
{% set object = solution.bookmark.linked_object %}
{% if object %}
<tr>
<td class="bookmark-name">
<a href="{{ url('problem_editorial', object.problem.code) }}">{{ object.problem.name}} </a>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endwith %}
<div class="problem-feed-types">
<i class="fa fa-tag"></i>
*{{problem.points | int}}
</div>
<div class="blog-description">
<div class='content-description'>
{% cache 86400 'problem_html' problem.id LANGUAGE_CODE %}
{{ problem.description|markdown(lazy_load=True)|reference|str|safe }}
{% endcache %}
{% if problem.pdf_description %}
<embed src="{{url('problem_pdf_description', problem.code)}}" width="100%" height="500" type="application/pdf"
style="margin-top: 0.5em">
{% endif %}
</div>
<div class="show-more"> {{_("...More")}} </div>
</div>
</div>
{% endfor %}
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top: 10px;">
{% include "list-pages.html" %}
</div>
{% endif %}
{% else %}
<i> {{ _('There is no saved problem.') }} </i>
{% endif %}
{% endif %}
{% if current_tab == 'contests' %}
{% if bookmarks %}
{% for contest in bookmarks %}
<div class="list-contest">
<div class="info-contest">
<div class="contest-title"> {{ _('Contests') }} </div>
{{ contest_head(contest) }}
</div>
<div class="info-contest">
<div class="contest-title"> {{ _('Time') }} </div>
<div class="contest-block">
{{ time_left(contest) }}
</div>
</div>
<div class="info-contest" style="flex: 0.5;">
{{ contest_format_user(contest, request) }}
</div>
</div>
{% endfor %}
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top: 10px;">
{% include "list-pages.html" %}
</div>
{% endif %}
{% else %}
<i> {{ _('There is no saved contest.') }} </i>
{% endif %}
{% endif %}
{% if current_tab == 'editorials' %}
{% if bookmarks %}
{% for solution in bookmarks %}
<section class="blog-box">
<div style="margin-bottom: 0.5em">
<span class="post-content-header time">
{% with authors=solution.get_authors() %}
{%- if authors -%}
<span class="user-img" style="width: 1.5em; height: 1.5em">
<img src="{{gravatar(authors[0])}}" loading="lazy">
</span>
<span class="post-authors">{{ link_users(authors) }}</span>
{%- endif -%}
{% endwith %}
&#8226;
{{ relative_time(solution.publish_on) }}
</span>
</div>
<h2 class="title">
<a href="{{ url('problem_editorial', solution.problem.code) }}">{{ solution.problem.name }}</a>
</h2>
<div class="blog-description">
<div class="summary content-description">
{% cache 86400 'solution_content' solution.id %}
{{ solution.content|markdown(lazy_load=True)|reference|str|safe }}
{% endcache %}
</div>
<div class="show-more"> {{_("...More")}} </div>
</div>
</section>
{% endfor %}
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top: 10px;">
{% include "list-pages.html" %}
</div>
{% endif %}
{% else %}
<i> {{ _('There is no saved editorial.') }} </i>
{% endif %}
{% endif %}
{% if current_tab == 'posts' %}
{% if bookmarks %}
{% for post in bookmarks %}
<section class="blog-box">
<div style="margin-bottom: 0.5em">
<span class="post-content-header time">
{% with authors=post.get_authors() %}
{%- if authors -%}
<span class="user-img" style="width: 1.5em; height: 1.5em">
<img src="{{gravatar(authors[0])}}" loading="lazy">
</span>
<span class="post-authors">{{ link_users(authors) }}</span>
{%- endif -%}
{% endwith %}
&#8226;
{{ relative_time(post.publish_on) }}
</span>
<span style="float: right">
<a href="{{ url('blog_post', post.id, post.slug) }}#comments" class="blog-comment-count-link">
<i class="fa fa-comments blog-comment-icon"></i>
<span class="blog-comment-count">
{{ comment_count(post) }}
</span>
</a>
</span>
</div>
<h2 class="title">
<a href="{{ url('blog_post', post.id, post.slug) }}">{{ post.title }}</a>
</h2>
<div class="blog-description">
<div class="summary content-description">
{% cache 86400 'post_content' post.id %}
{{ post.content|markdown(lazy_load=True)|reference|str|safe }}
{% endcache %}
</div>
<div class="show-more"> {{_("...More")}} </div>
</div>
</section>
{% endfor %}
{% if page_obj and page_obj.num_pages > 1 %}
<div style="margin-top: 10px;">
{% include "list-pages.html" %}
</div>
{% endif %}
{% else %}
<i> {{ _('There is no saved post.') }} </i>
{% endif %}
{% endif %}
{% endblock %}