New home UI

This commit is contained in:
cuom1999 2022-03-21 16:09:16 -05:00
parent e8ee2ac4aa
commit 3d3ab23d27
15 changed files with 676 additions and 378 deletions

View file

@ -110,13 +110,17 @@ urlpatterns = [
url(r'^accounts/', include(register_patterns)), url(r'^accounts/', include(register_patterns)),
url(r'^', include('social_django.urls')), url(r'^', include('social_django.urls')),
url(r'^feed/', include([
url(r'^problems/$', problem.ProblemFeed.as_view(), name='problem_feed'),
url(r'^tickets/$', blog.TicketFeed.as_view(), name='ticket_feed'),
url(r'^comments/$', blog.CommentFeed.as_view(), name='comment_feed'),
])),
url(r'^problems/$', problem.ProblemList.as_view(), name='problem_list'), url(r'^problems/$', problem.ProblemList.as_view(), name='problem_list'),
url(r'^problems/random/$', problem.RandomProblem.as_view(), name='problem_random'), url(r'^problems/random/$', problem.RandomProblem.as_view(), name='problem_random'),
url(r'^problem/(?P<problem>[^/]+)', include([ url(r'^problem/(?P<problem>[^/]+)', include([
url(r'^$', problem.ProblemDetail.as_view(), name='problem_detail'), url(r'^$', problem.ProblemDetail.as_view(), name='problem_detail'),
url(r'^/editorial$', problem.ProblemSolution.as_view(), name='problem_editorial'), url(r'^/editorial$', problem.ProblemSolution.as_view(), name='problem_editorial'),
url(r'^/comments$', problem.ProblemComments.as_view(), name='problem_comments'),
url(r'^/raw$', problem.ProblemRaw.as_view(), name='problem_raw'), url(r'^/raw$', problem.ProblemRaw.as_view(), name='problem_raw'),
url(r'^/pdf$', problem.ProblemPdfView.as_view(), name='problem_pdf'), url(r'^/pdf$', problem.ProblemPdfView.as_view(), name='problem_pdf'),
url(r'^/pdf/(?P<language>[a-z-]+)$', problem.ProblemPdfView.as_view(), name='problem_pdf'), url(r'^/pdf/(?P<language>[a-z-]+)$', problem.ProblemPdfView.as_view(), name='problem_pdf'),

View file

@ -65,7 +65,9 @@ class Comment(MPTTModel):
problem_access = CacheDict(lambda code: Problem.objects.get(code=code).is_accessible_by(user)) problem_access = CacheDict(lambda code: Problem.objects.get(code=code).is_accessible_by(user))
contest_access = CacheDict(lambda key: Contest.objects.get(key=key).is_accessible_by(user)) contest_access = CacheDict(lambda key: Contest.objects.get(key=key).is_accessible_by(user))
blog_access = CacheDict(lambda id: BlogPost.objects.get(id=id).can_see(user)) blog_access = CacheDict(lambda id: BlogPost.objects.get(id=id).can_see(user))
if n == -1:
n = len(queryset)
if user.is_superuser: if user.is_superuser:
return queryset[:n] return queryset[:n]
if batch is None: if batch is None:
@ -105,7 +107,7 @@ class Comment(MPTTModel):
try: try:
link = None link = None
if self.page.startswith('p:'): if self.page.startswith('p:'):
link = reverse('problem_comments', args=(self.page[2:],)) link = reverse('problem_detail', args=(self.page[2:],))
elif self.page.startswith('c:'): elif self.page.startswith('c:'):
link = reverse('contest_view', args=(self.page[2:],)) link = reverse('contest_view', args=(self.page[2:],))
elif self.page.startswith('b:'): elif self.page.startswith('b:'):

View file

@ -17,10 +17,8 @@ from judge.utils.tickets import filter_visible_tickets
from judge.utils.views import TitleMixin from judge.utils.views import TitleMixin
class PostList(ListView): # General view for all content list on home feed
model = BlogPost class FeedView(ListView):
paginate_by = 10
context_object_name = 'posts'
template_name = 'blog/list.html' template_name = 'blog/list.html'
title = None title = None
@ -29,6 +27,56 @@ class PostList(ListView):
return DiggPaginator(queryset, per_page, body=6, padding=2, return DiggPaginator(queryset, per_page, body=6, padding=2,
orphans=orphans, allow_empty_first_page=allow_empty_first_page, **kwargs) orphans=orphans, allow_empty_first_page=allow_empty_first_page, **kwargs)
def get_context_data(self, **kwargs):
context = super(FeedView, self).get_context_data(**kwargs)
context['has_clarifications'] = False
if self.request.user.is_authenticated:
participation = self.request.profile.current_contest
if participation:
clarifications = ProblemClarification.objects.filter(problem__in=participation.contest.problems.all())
context['has_clarifications'] = clarifications.count() > 0
context['clarifications'] = clarifications.order_by('-date')
if participation.contest.is_editable_by(self.request.user):
context['can_edit_contest'] = True
context['page_titles'] = CacheDict(lambda page: Comment.get_page_title(page))
context['user_count'] = lazy(Profile.objects.count, int, int)
context['problem_count'] = lazy(Problem.objects.filter(is_public=True).count, int, int)
context['submission_count'] = lazy(Submission.objects.count, int, int)
context['language_count'] = lazy(Language.objects.count, int, int)
now = timezone.now()
# Dashboard stuff
# if self.request.user.is_authenticated:
# user = self.request.profile
# context['recently_attempted_problems'] = (Submission.objects.filter(user=user)
# .exclude(problem__in=user_completed_ids(user))
# .values_list('problem__code', 'problem__name', 'problem__points')
# .annotate(points=Max('points'), latest=Max('date'))
# .order_by('-latest')
# [:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True) \
.order_by('start_time')
context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now)
context['future_contests'] = visible_contests.filter(start_time__gt=now)
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True)
context['top_rated'] = Profile.objects.order_by('-rating')[:10]
context['top_scorer'] = Profile.objects.order_by('-performance_points')[:10]
return context
class PostList(FeedView):
model = BlogPost
paginate_by = 10
context_object_name = 'posts'
def get_queryset(self): def get_queryset(self):
queryset = BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()) \ queryset = BlogPost.objects.filter(visible=True, publish_on__lte=timezone.now()) \
.order_by('-sticky', '-publish_on') \ .order_by('-sticky', '-publish_on') \
@ -45,25 +93,7 @@ class PostList(ListView):
context['title'] = self.title or _('Page %d of Posts') % context['page_obj'].number context['title'] = self.title or _('Page %d of Posts') % context['page_obj'].number
context['first_page_href'] = reverse('home') context['first_page_href'] = reverse('home')
context['page_prefix'] = reverse('blog_post_list') context['page_prefix'] = reverse('blog_post_list')
context['comments'] = Comment.most_recent(self.request.user, 25) context['feed_type'] = 'blog'
context['new_problems'] = Problem.objects.filter(is_public=True, is_organization_private=False) \
.order_by('-date', '-id')[:settings.DMOJ_BLOG_NEW_PROBLEM_COUNT]
context['page_titles'] = CacheDict(lambda page: Comment.get_page_title(page))
context['has_clarifications'] = False
if self.request.user.is_authenticated:
participation = self.request.profile.current_contest
if participation:
clarifications = ProblemClarification.objects.filter(problem__in=participation.contest.problems.all())
context['has_clarifications'] = clarifications.count() > 0
context['clarifications'] = clarifications.order_by('-date')
if participation.contest.is_editable_by(self.request.user):
context['can_edit_contest'] = True
context['user_count'] = lazy(Profile.objects.count, int, int)
context['problem_count'] = lazy(Problem.objects.filter(is_public=True).count, int, int)
context['submission_count'] = lazy(Submission.objects.count, int, int)
context['language_count'] = lazy(Language.objects.count, int, int)
context['post_comment_counts'] = { context['post_comment_counts'] = {
int(page[2:]): count for page, count in int(page[2:]): count for page, count in
Comment.objects Comment.objects
@ -71,40 +101,55 @@ class PostList(ListView):
.values_list('page').annotate(count=Count('page')).order_by() .values_list('page').annotate(count=Count('page')).order_by()
} }
now = timezone.now() return context
# Dashboard stuff
if self.request.user.is_authenticated:
user = self.request.profile
context['recently_attempted_problems'] = (Submission.objects.filter(user=user)
.exclude(problem__in=user_completed_ids(user))
.values_list('problem__code', 'problem__name', 'problem__points')
.annotate(points=Max('points'), latest=Max('date'))
.order_by('-latest')
[:settings.DMOJ_BLOG_RECENTLY_ATTEMPTED_PROBLEMS_COUNT])
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True) \
.order_by('start_time')
context['current_contests'] = visible_contests.filter(start_time__lte=now, end_time__gt=now) class TicketFeed(FeedView):
context['future_contests'] = visible_contests.filter(start_time__gt=now) model = Ticket
context_object_name = 'tickets'
paginate_by = 30
visible_contests = Contest.get_visible_contests(self.request.user).filter(is_visible=True) def get_queryset(self, is_own=True):
if self.request.user.is_authenticated: profile = self.request.profile
profile = self.request.profile if is_own:
context['own_open_tickets'] = (Ticket.objects.filter(Q(user=profile) | Q(assignees__in=[profile]), is_open=True).order_by('-id') if self.request.user.is_authenticated:
.prefetch_related('linked_item').select_related('user__user')) return (Ticket.objects.filter(Q(user=profile) | Q(assignees__in=[profile]), is_open=True).order_by('-id')
.prefetch_related('linked_item').select_related('user__user'))
else:
return []
else: else:
profile = None # Superusers better be staffs, not the spell-casting kind either.
context['own_open_tickets'] = [] if self.request.user.is_staff:
tickets = (Ticket.objects.order_by('-id').filter(is_open=True).prefetch_related('linked_item')
.select_related('user__user'))
return filter_visible_tickets(tickets, self.request.user, profile)
else:
return []
# Superusers better be staffs, not the spell-casting kind either. def get_context_data(self, **kwargs):
if self.request.user.is_staff: context = super(TicketFeed, self).get_context_data(**kwargs)
tickets = (Ticket.objects.order_by('-id').filter(is_open=True).prefetch_related('linked_item') context['feed_type'] = 'ticket'
.select_related('user__user')) context['first_page_href'] = self.request.path
context['open_tickets'] = filter_visible_tickets(tickets, self.request.user, profile)[:10] context['page_prefix'] = '?page='
else: context['title'] = _('Ticket feed')
context['open_tickets'] = []
return context
class CommentFeed(FeedView):
model = Comment
context_object_name = 'comments'
paginate_by = 50
def get_queryset(self):
return Comment.most_recent(self.request.user, 1000)
def get_context_data(self, **kwargs):
context = super(CommentFeed, self).get_context_data(**kwargs)
context['feed_type'] = 'comment'
context['first_page_href'] = self.request.path
context['page_prefix'] = '?page='
context['title'] = _('Comment feed')
return context return context

View file

@ -21,7 +21,7 @@ from django.utils.functional import cached_property
from django.utils.html import escape, format_html from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _, gettext_lazy from django.utils.translation import gettext as _, gettext_lazy
from django.views.generic import DetailView, ListView, View from django.views.generic import ListView, View
from django.views.generic.base import TemplateResponseMixin from django.views.generic.base import TemplateResponseMixin
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
@ -38,6 +38,7 @@ from judge.utils.problems import contest_attempted_ids, contest_completed_ids, h
from judge.utils.strings import safe_float_or_none, safe_int_or_none from judge.utils.strings import safe_float_or_none, safe_int_or_none
from judge.utils.tickets import own_ticket_filter from judge.utils.tickets import own_ticket_filter
from judge.utils.views import QueryStringSortMixin, SingleObjectFormView, TitleMixin, generic_message from judge.utils.views import QueryStringSortMixin, SingleObjectFormView, TitleMixin, generic_message
from judge.views.blog import FeedView
def get_contest_problem(problem, profile): def get_contest_problem(problem, profile):
@ -155,10 +156,13 @@ class ProblemRaw(ProblemMixin, TitleMixin, TemplateResponseMixin, SingleObjectMi
)) ))
class ProblemDetail(ProblemMixin, SolvedProblemMixin, DetailView): class ProblemDetail(ProblemMixin, SolvedProblemMixin, CommentedDetailView):
context_object_name = 'problem' context_object_name = 'problem'
template_name = 'problem/problem.html' template_name = 'problem/problem.html'
def get_comment_page(self):
return 'p:%s' % self.object.code
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ProblemDetail, self).get_context_data(**kwargs) context = super(ProblemDetail, self).get_context_data(**kwargs)
user = self.request.user user = self.request.user
@ -235,6 +239,7 @@ class ProblemDetail(ProblemMixin, SolvedProblemMixin, DetailView):
context['min_possible_vote'] = 100 context['min_possible_vote'] = 100
return context return context
class DeleteVote(ProblemMixin, SingleObjectMixin, View): class DeleteVote(ProblemMixin, SingleObjectMixin, View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return HttpResponseForbidden(status=405, content_type='text/plain') return HttpResponseForbidden(status=405, content_type='text/plain')
@ -273,21 +278,6 @@ class Vote(ProblemMixin, SingleObjectMixin, View):
return JsonResponse(form.errors, status=400) return JsonResponse(form.errors, status=400)
class ProblemComments(ProblemMixin, TitleMixin, CommentedDetailView):
context_object_name = 'problem'
template_name = 'problem/comments.html'
def get_title(self):
return _('Disscuss {0}').format(self.object.name)
def get_content_title(self):
return format_html(_(u'Discuss <a href="{1}">{0}</a>'), self.object.name,
reverse('problem_detail', args=[self.object.code]))
def get_comment_page(self):
return 'p:%s' % self.object.code
class LatexError(Exception): class LatexError(Exception):
pass pass
@ -592,6 +582,49 @@ class ProblemList(QueryStringSortMixin, TitleMixin, SolvedProblemMixin, ListView
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
class ProblemFeed(FeedView):
model = Problem
context_object_name = 'problems'
paginate_by = 50
title = _('Problem feed')
@cached_property
def profile(self):
if not self.request.user.is_authenticated:
return None
return self.request.profile
def get_unsolved_queryset(self):
filter = Q(is_public=True)
if self.profile is not None:
filter |= Q(authors=self.profile)
filter |= Q(curators=self.profile)
filter |= Q(testers=self.profile)
queryset = Problem.objects.filter(filter).select_related('group').defer('description')
if not self.request.user.has_perm('see_organization_problem'):
filter = Q(is_organization_private=False)
if self.profile is not None:
filter |= Q(organizations__in=self.profile.organizations.all())
queryset = queryset.filter(filter)
if self.profile is not None:
queryset = queryset.exclude(id__in=Submission.objects.filter(user=self.profile, points=F('problem__points'))
.values_list('problem__id', flat=True))
return queryset.distinct()
def get_queryset(self):
queryset = self.get_unsolved_queryset()
return queryset.order_by('?')
def get_context_data(self, **kwargs):
context = super(ProblemFeed, self).get_context_data(**kwargs)
context['first_page_href'] = self.request.path
context['page_prefix'] = '?page='
context['feed_type'] = 'problem'
context['title'] = self.title
return context
class LanguageTemplateAjax(View): class LanguageTemplateAjax(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
try: try:

View file

@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: lqdoj2\n" "Project-Id-Version: lqdoj2\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-03-10 12:30+0700\n" "POT-Creation-Date: 2022-03-22 04:37+0700\n"
"PO-Revision-Date: 2021-07-20 03:44\n" "PO-Revision-Date: 2021-07-20 03:44\n"
"Last-Translator: Icyene\n" "Last-Translator: Icyene\n"
"Language-Team: Vietnamese\n" "Language-Team: Vietnamese\n"
@ -24,7 +24,7 @@ msgstr ""
msgid "user" msgid "user"
msgstr "người dùng" msgstr "người dùng"
#: chat_box/models.py:24 judge/models/comment.py:43 judge/models/comment.py:191 #: chat_box/models.py:24 judge/models/comment.py:43 judge/models/comment.py:193
msgid "posted time" msgid "posted time"
msgstr "thời gian đăng" msgstr "thời gian đăng"
@ -225,7 +225,7 @@ msgstr "ảo"
msgid "link path" msgid "link path"
msgstr "đường dẫn" msgstr "đường dẫn"
#: judge/admin/interface.py:65 #: judge/admin/interface.py:65 templates/blog/list.html:114
msgid "Content" msgid "Content"
msgstr "Nội dung" msgstr "Nội dung"
@ -254,11 +254,11 @@ msgstr "Mạng Xã Hội"
msgid "Taxonomy" msgid "Taxonomy"
msgstr "" msgstr ""
#: judge/admin/problem.py:128 templates/contest/contest.html:84 #: judge/admin/problem.py:128 judge/admin/problem.py:258
#: templates/problem/data.html:469 templates/problem/list.html:222 #: templates/contest/contest.html:84 templates/problem/data.html:469
#: templates/problem/list.html:248 templates/user/base-users-table.html:10 #: templates/problem/list.html:222 templates/problem/list.html:248
#: templates/user/user-about.html:36 templates/user/user-about.html:52 #: templates/user/base-users-table.html:10 templates/user/user-about.html:36
#: templates/user/user-problems.html:58 #: templates/user/user-about.html:52 templates/user/user-problems.html:58
msgid "Points" msgid "Points"
msgstr "Điểm" msgstr "Điểm"
@ -299,6 +299,19 @@ msgstr[0] "%d bài tập đã được đánh dấu riêng tư."
msgid "Mark problems as private" msgid "Mark problems as private"
msgstr "Đánh dấu các bài tập là riêng tư" msgstr "Đánh dấu các bài tập là riêng tư"
#: judge/admin/problem.py:253 judge/admin/submission.py:200
#: templates/problem/list.html:216 templates/problem/list.html:236
msgid "Problem code"
msgstr "Mã bài"
#: judge/admin/problem.py:263 judge/admin/submission.py:205
msgid "Problem name"
msgstr "Tên bài"
#: judge/admin/problem.py:268
msgid "Vote"
msgstr ""
#: judge/admin/profile.py:34 #: judge/admin/profile.py:34
msgid "timezone" msgid "timezone"
msgstr "múi giờ" msgstr "múi giờ"
@ -401,15 +414,6 @@ msgstr[0] "%d bài nộp đã được tính điểm lại."
msgid "Rescore the selected submissions" msgid "Rescore the selected submissions"
msgstr "Tính điểm lại cái bài nộp" msgstr "Tính điểm lại cái bài nộp"
#: judge/admin/submission.py:200 templates/problem/list.html:216
#: templates/problem/list.html:236
msgid "Problem code"
msgstr "Mã bài"
#: judge/admin/submission.py:205
msgid "Problem name"
msgstr "Tên bài"
#: judge/admin/submission.py:215 templates/notification/list.html:15 #: judge/admin/submission.py:215 templates/notification/list.html:15
#: templates/organization/requests/log.html:10 #: templates/organization/requests/log.html:10
#: templates/organization/requests/pending.html:13 #: templates/organization/requests/pending.html:13
@ -550,7 +554,7 @@ msgstr "g:i a j b, Y"
msgid "{time}" msgid "{time}"
msgstr "{time}" msgstr "{time}"
#: judge/jinja2/datetime.py:26 templates/blog/content.html:13 #: judge/jinja2/datetime.py:26 templates/blog/content.html:10
#, python-brace-format #, python-brace-format
msgid "on {time}" msgid "on {time}"
msgstr "vào {time}" msgstr "vào {time}"
@ -583,11 +587,11 @@ msgstr "Mã trang phải có dạng ^[pcs]:[a-z0-9]+$|^b:\\d+$"
msgid "commenter" msgid "commenter"
msgstr "người bình luận" msgstr "người bình luận"
#: judge/models/comment.py:44 judge/models/comment.py:177 #: judge/models/comment.py:44 judge/models/comment.py:179
msgid "associated page" msgid "associated page"
msgstr "trang tương ứng" msgstr "trang tương ứng"
#: judge/models/comment.py:46 judge/models/problem.py:492 #: judge/models/comment.py:46 judge/models/problem.py:493
msgid "votes" msgid "votes"
msgstr "bình chọn" msgstr "bình chọn"
@ -599,7 +603,7 @@ msgstr "ẩn bình luận"
msgid "parent" msgid "parent"
msgstr "" msgstr ""
#: judge/models/comment.py:54 judge/models/comment.py:192 #: judge/models/comment.py:54 judge/models/comment.py:194
msgid "comment" msgid "comment"
msgstr "bình luận" msgstr "bình luận"
@ -607,24 +611,24 @@ msgstr "bình luận"
msgid "comments" msgid "comments"
msgstr "" msgstr ""
#: judge/models/comment.py:137 judge/models/problem.py:462 #: judge/models/comment.py:139 judge/models/problem.py:463
#, python-format #, python-format
msgid "Editorial for %s" msgid "Editorial for %s"
msgstr "" msgstr ""
#: judge/models/comment.py:172 #: judge/models/comment.py:174
msgid "comment vote" msgid "comment vote"
msgstr "" msgstr ""
#: judge/models/comment.py:173 #: judge/models/comment.py:175
msgid "comment votes" msgid "comment votes"
msgstr "" msgstr ""
#: judge/models/comment.py:182 #: judge/models/comment.py:184
msgid "Override comment lock" msgid "Override comment lock"
msgstr "" msgstr ""
#: judge/models/comment.py:190 #: judge/models/comment.py:192
#: src/dmoj-wpadmin/test_project/apps/books/admin.py:24 #: src/dmoj-wpadmin/test_project/apps/books/admin.py:24
#: src/dmoj-wpadmin/test_project/apps/books/models.py:30 #: src/dmoj-wpadmin/test_project/apps/books/models.py:30
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:30 #: src/dmoj-wpadmin/test_project/apps/cds/models.py:30
@ -632,22 +636,22 @@ msgstr ""
msgid "owner" msgid "owner"
msgstr "" msgstr ""
#: judge/models/comment.py:193 judge/models/message.py:16 #: judge/models/comment.py:195 judge/models/message.py:16
msgid "read" msgid "read"
msgstr "" msgstr ""
#: judge/models/comment.py:194 #: judge/models/comment.py:196
#: src/dmoj-wpadmin/test_project/apps/books/models.py:28 #: src/dmoj-wpadmin/test_project/apps/books/models.py:28
#: src/dmoj-wpadmin/test_project/apps/cds/models.py:28 #: src/dmoj-wpadmin/test_project/apps/cds/models.py:28
#: src/dmoj-wpadmin/test_project/apps/dvds/models.py:28 #: src/dmoj-wpadmin/test_project/apps/dvds/models.py:28
msgid "category" msgid "category"
msgstr "" msgstr ""
#: judge/models/comment.py:195 #: judge/models/comment.py:197
msgid "html link to comments, used for non-comments" msgid "html link to comments, used for non-comments"
msgstr "" msgstr ""
#: judge/models/comment.py:196 #: judge/models/comment.py:198
msgid "who trigger, used for non-comment" msgid "who trigger, used for non-comment"
msgstr "" msgstr ""
@ -725,7 +729,7 @@ msgstr ""
msgid "description" msgid "description"
msgstr "mô tả" msgstr "mô tả"
#: judge/models/contest.py:72 judge/models/problem.py:409 #: judge/models/contest.py:72 judge/models/problem.py:410
#: judge/models/runtime.py:138 #: judge/models/runtime.py:138
msgid "problems" msgid "problems"
msgstr "bài tập" msgstr "bài tập"
@ -739,7 +743,7 @@ msgid "end time"
msgstr "thời gian kết thúc" msgstr "thời gian kết thúc"
#: judge/models/contest.py:75 judge/models/problem.py:118 #: judge/models/contest.py:75 judge/models/problem.py:118
#: judge/models/problem.py:433 #: judge/models/problem.py:434
msgid "time limit" msgid "time limit"
msgstr "giới hạn thời gian" msgstr "giới hạn thời gian"
@ -1037,8 +1041,8 @@ msgid "contest participations"
msgstr "lần tham gia kỳ thi" msgstr "lần tham gia kỳ thi"
#: judge/models/contest.py:491 judge/models/contest.py:513 #: judge/models/contest.py:491 judge/models/contest.py:513
#: judge/models/contest.py:554 judge/models/problem.py:408 #: judge/models/contest.py:554 judge/models/problem.py:409
#: judge/models/problem.py:413 judge/models/problem.py:431 #: judge/models/problem.py:414 judge/models/problem.py:432
#: judge/models/problem_data.py:40 #: judge/models/problem_data.py:40
msgid "problem" msgid "problem"
msgstr "bài tập" msgstr "bài tập"
@ -1176,7 +1180,7 @@ msgstr "mục cha"
msgid "post title" msgid "post title"
msgstr "tiêu đề bài đăng" msgstr "tiêu đề bài đăng"
#: judge/models/interface.py:67 judge/models/problem.py:451 #: judge/models/interface.py:67 judge/models/problem.py:452
msgid "authors" msgid "authors"
msgstr "tác giả" msgstr "tác giả"
@ -1184,7 +1188,7 @@ msgstr "tác giả"
msgid "slug" msgid "slug"
msgstr "slug" msgstr "slug"
#: judge/models/interface.py:69 judge/models/problem.py:449 #: judge/models/interface.py:69 judge/models/problem.py:450
msgid "public visibility" msgid "public visibility"
msgstr "khả năng hiển thị công khai" msgstr "khả năng hiển thị công khai"
@ -1380,7 +1384,7 @@ msgid ""
"are supported." "are supported."
msgstr "" msgstr ""
#: judge/models/problem.py:123 judge/models/problem.py:436 #: judge/models/problem.py:123 judge/models/problem.py:437
msgid "memory limit" msgid "memory limit"
msgstr "" msgstr ""
@ -1453,82 +1457,82 @@ msgstr ""
msgid "If private, only these organizations may see the problem." msgid "If private, only these organizations may see the problem."
msgstr "" msgstr ""
#: judge/models/problem.py:414 judge/models/problem.py:432 #: judge/models/problem.py:415 judge/models/problem.py:433
#: judge/models/runtime.py:111 #: judge/models/runtime.py:111
msgid "language" msgid "language"
msgstr "" msgstr ""
#: judge/models/problem.py:415 #: judge/models/problem.py:416
msgid "translated name" msgid "translated name"
msgstr "" msgstr ""
#: judge/models/problem.py:416 #: judge/models/problem.py:417
msgid "translated description" msgid "translated description"
msgstr "" msgstr ""
#: judge/models/problem.py:420 #: judge/models/problem.py:421
msgid "problem translation" msgid "problem translation"
msgstr "" msgstr ""
#: judge/models/problem.py:421 #: judge/models/problem.py:422
msgid "problem translations" msgid "problem translations"
msgstr "" msgstr ""
#: judge/models/problem.py:425 #: judge/models/problem.py:426
msgid "clarified problem" msgid "clarified problem"
msgstr "" msgstr ""
#: judge/models/problem.py:426 #: judge/models/problem.py:427
msgid "clarification body" msgid "clarification body"
msgstr "" msgstr ""
#: judge/models/problem.py:427 #: judge/models/problem.py:428
msgid "clarification timestamp" msgid "clarification timestamp"
msgstr "" msgstr ""
#: judge/models/problem.py:442 #: judge/models/problem.py:443
msgid "language-specific resource limit" msgid "language-specific resource limit"
msgstr "" msgstr ""
#: judge/models/problem.py:443 #: judge/models/problem.py:444
msgid "language-specific resource limits" msgid "language-specific resource limits"
msgstr "" msgstr ""
#: judge/models/problem.py:447 #: judge/models/problem.py:448
msgid "associated problem" msgid "associated problem"
msgstr "" msgstr ""
#: judge/models/problem.py:450 #: judge/models/problem.py:451
msgid "publish date" msgid "publish date"
msgstr "" msgstr ""
#: judge/models/problem.py:452 #: judge/models/problem.py:453
msgid "editorial content" msgid "editorial content"
msgstr "nội dung lời giải" msgstr "nội dung lời giải"
#: judge/models/problem.py:468 #: judge/models/problem.py:469
msgid "solution" msgid "solution"
msgstr "lời giải" msgstr "lời giải"
#: judge/models/problem.py:469 #: judge/models/problem.py:470
msgid "solutions" msgid "solutions"
msgstr "lời giải" msgstr "lời giải"
#: judge/models/problem.py:474 #: judge/models/problem.py:475
#, fuzzy #, fuzzy
#| msgid "point value" #| msgid "point value"
msgid "proposed point value" msgid "proposed point value"
msgstr "điểm" msgstr "điểm"
#: judge/models/problem.py:475 #: judge/models/problem.py:476
msgid "The amount of points you think this problem deserves." msgid "The amount of points you think this problem deserves."
msgstr "" msgstr ""
#: judge/models/problem.py:485 #: judge/models/problem.py:486
msgid "The time this vote was cast" msgid "The time this vote was cast"
msgstr "" msgstr ""
#: judge/models/problem.py:491 #: judge/models/problem.py:492
msgid "vote" msgid "vote"
msgstr "" msgstr ""
@ -2376,11 +2380,23 @@ msgstr "Giới thiệu"
msgid "Custom Checker Sample" msgid "Custom Checker Sample"
msgstr "Hướng dẫn viết trình chấm" msgstr "Hướng dẫn viết trình chấm"
#: judge/views/blog.py:45 #: judge/views/blog.py:93
#, python-format #, python-format
msgid "Page %d of Posts" msgid "Page %d of Posts"
msgstr "Trang %d" msgstr "Trang %d"
#: judge/views/blog.py:134
#, fuzzy
#| msgid "Ticket title"
msgid "Ticket feed"
msgstr "Tiêu đề báo cáo"
#: judge/views/blog.py:152
#, fuzzy
#| msgid "Comment body"
msgid "Comment feed"
msgstr "Nội dung bình luận"
#: judge/views/comment.py:28 #: judge/views/comment.py:28
msgid "Messing around, are we?" msgid "Messing around, are we?"
msgstr "Messing around, are we?" msgstr "Messing around, are we?"
@ -2675,65 +2691,61 @@ msgstr ""
msgid "The user you are trying to kick is not in organization: %s." msgid "The user you are trying to kick is not in organization: %s."
msgstr "" msgstr ""
#: judge/views/problem.py:68 #: judge/views/problem.py:69
msgid "No such problem" msgid "No such problem"
msgstr "Không có bài nào như vậy" msgstr "Không có bài nào như vậy"
#: judge/views/problem.py:69 #: judge/views/problem.py:70
#, python-format #, python-format
msgid "Could not find a problem with the code \"%s\"." msgid "Could not find a problem with the code \"%s\"."
msgstr "Không tìm thấy bài tập với mã bài \"%s\"." msgstr "Không tìm thấy bài tập với mã bài \"%s\"."
#: judge/views/problem.py:113 #: judge/views/problem.py:114
#, python-brace-format #, python-brace-format
msgid "Editorial for {0}" msgid "Editorial for {0}"
msgstr "Hướng dẫn cho {0}" msgstr "Hướng dẫn cho {0}"
#: judge/views/problem.py:116 #: judge/views/problem.py:117
#, python-brace-format #, python-brace-format
msgid "Editorial for <a href=\"{1}\">{0}</a>" msgid "Editorial for <a href=\"{1}\">{0}</a>"
msgstr "Hướng dẫn cho <a href=\"{1}\">{0}</a>" msgstr "Hướng dẫn cho <a href=\"{1}\">{0}</a>"
#: judge/views/problem.py:284 #: judge/views/problem.py:342 templates/blog/list.html:121
#, python-brace-format #: templates/contest/contest.html:79 templates/user/user-about.html:28
msgid "Disscuss {0}" #: templates/user/user-tabs.html:5 templates/user/users-table.html:29
msgstr ""
#: judge/views/problem.py:287
#, python-brace-format
msgid "Discuss <a href=\"{1}\">{0}</a>"
msgstr "Thảo luận <a href=\"{1}\">{0}</a>"
#: judge/views/problem.py:355 templates/contest/contest.html:79
#: templates/user/user-about.html:28 templates/user/user-tabs.html:5
#: templates/user/users-table.html:29
msgid "Problems" msgid "Problems"
msgstr "Bài tập" msgstr "Bài tập"
#: judge/views/problem.py:655 #: judge/views/problem.py:589
#, fuzzy
#| msgid "Problem code"
msgid "Problem feed"
msgstr "Mã bài"
#: judge/views/problem.py:685
msgid "Banned from submitting" msgid "Banned from submitting"
msgstr "Bị cấm nộp bài" msgstr "Bị cấm nộp bài"
#: judge/views/problem.py:656 #: judge/views/problem.py:686
msgid "" msgid ""
"You have been declared persona non grata for this problem. You are " "You have been declared persona non grata for this problem. You are "
"permanently barred from submitting this problem." "permanently barred from submitting this problem."
msgstr "Bạn đã bị cấm nộp bài này." msgstr "Bạn đã bị cấm nộp bài này."
#: judge/views/problem.py:670 #: judge/views/problem.py:700
msgid "Too many submissions" msgid "Too many submissions"
msgstr "Quá nhiều lần nộp" msgstr "Quá nhiều lần nộp"
#: judge/views/problem.py:671 #: judge/views/problem.py:701
msgid "You have exceeded the submission limit for this problem." msgid "You have exceeded the submission limit for this problem."
msgstr "Bạn đã vượt quá số lần nộp cho bài này." msgstr "Bạn đã vượt quá số lần nộp cho bài này."
#: judge/views/problem.py:731 judge/views/problem.py:734 #: judge/views/problem.py:761 judge/views/problem.py:764
#, python-format #, python-format
msgid "Submit to %(problem)s" msgid "Submit to %(problem)s"
msgstr "Nộp bài cho %(problem)s" msgstr "Nộp bài cho %(problem)s"
#: judge/views/problem.py:749 #: judge/views/problem.py:779
msgid "Clone Problem" msgid "Clone Problem"
msgstr "Nhân bản bài tập" msgstr "Nhân bản bài tập"
@ -2881,7 +2893,7 @@ msgid "Submission of %(problem)s by %(user)s"
msgstr "Bài nộp của %(user)s cho bài %(problem)s" msgstr "Bài nộp của %(user)s cho bài %(problem)s"
#: judge/views/submission.py:244 judge/views/submission.py:245 #: judge/views/submission.py:244 judge/views/submission.py:245
#: templates/problem/problem.html:165 #: templates/problem/problem.html:194
msgid "All submissions" msgid "All submissions"
msgstr "Tất cả bài nộp" msgstr "Tất cả bài nộp"
@ -3299,10 +3311,6 @@ msgstr "Chỉnh sửa"
msgid " posted on %(time)s" msgid " posted on %(time)s"
msgstr "đã đăng vào %(time)s" msgstr "đã đăng vào %(time)s"
#: templates/blog/content.html:13
msgid "posted"
msgstr "đã đăng"
#: templates/blog/dashboard.html:21 #: templates/blog/dashboard.html:21
#, python-format #, python-format
msgid "" msgid ""
@ -3314,59 +3322,63 @@ msgstr ""
" vào %(time)s\n" " vào %(time)s\n"
" " " "
#: templates/blog/list.html:93 #: templates/blog/list.html:107
msgid "Blog" msgid "Feed"
msgstr "" msgstr ""
#: templates/blog/list.html:95 #: templates/blog/list.html:109
msgid "Events" msgid "Events"
msgstr "Sự kiện" msgstr "Sự kiện"
#: templates/blog/list.html:100 #: templates/blog/list.html:117
msgid "News" msgid "News"
msgstr "Tin tức" msgstr "Tin tức"
#: templates/blog/list.html:115 templates/problem/list.html:347 #: templates/blog/list.html:125 templates/comments/list.html:2
#: templates/problem/problem.html:370 msgid "Comments"
msgstr "Bình luận"
#: templates/blog/list.html:129
msgid "Tickets"
msgstr "Báo cáo"
#: templates/blog/list.html:148
msgid "You have no ticket"
msgstr "Bạn không có báo cáo"
#: templates/blog/list.html:163 templates/problem/list.html:347
#: templates/problem/problem.html:407
msgid "Clarifications" msgid "Clarifications"
msgstr "Thông báo" msgstr "Thông báo"
#: templates/blog/list.html:121 #: templates/blog/list.html:169
msgid "Add" msgid "Add"
msgstr "Thêm mới" msgstr "Thêm mới"
#: templates/blog/list.html:140 templates/problem/list.html:369 #: templates/blog/list.html:188 templates/problem/list.html:369
#: templates/problem/problem.html:381 #: templates/problem/problem.html:418
msgid "No clarifications have been made at this time." msgid "No clarifications have been made at this time."
msgstr "Không có thông báo nào." msgstr "Không có thông báo nào."
#: templates/blog/list.html:148 #: templates/blog/list.html:196
msgid "Ongoing contests" msgid "Ongoing contests"
msgstr "Kỳ thi đang diễn ra" msgstr "Kỳ thi đang diễn ra"
#: templates/blog/list.html:156 #: templates/blog/list.html:204
msgid "Ends in" msgid "Ends in"
msgstr "Còn" msgstr "Còn"
#: templates/blog/list.html:166 #: templates/blog/list.html:214
msgid "Upcoming contests" msgid "Upcoming contests"
msgstr "Kỳ thi sắp diễn ra" msgstr "Kỳ thi sắp diễn ra"
#: templates/blog/list.html:184 #: templates/blog/list.html:230
msgid "My open tickets" msgid "Top Rating"
msgstr "Báo cáo dành cho tôi" msgstr "Top Rating"
#: templates/blog/list.html:206 #: templates/blog/list.html:246
msgid "New tickets" msgid "Top Score"
msgstr "Báo cáo mới" msgstr "Top Score"
#: templates/blog/list.html:227
msgid "New problems"
msgstr "Bài tập mới"
#: templates/blog/list.html:244
msgid "Comment stream"
msgstr "Dòng bình luận"
#: templates/chat/chat.html:18 #: templates/chat/chat.html:18
msgid "Recent" msgid "Recent"
@ -3435,10 +3447,6 @@ msgstr "Tắt thông báo"
msgid "users are online" msgid "users are online"
msgstr "người đang trực tuyến" msgstr "người đang trực tuyến"
#: templates/comments/list.html:2
msgid "Comments"
msgstr "Bình luận"
#: templates/comments/list.html:18 templates/comments/list.html:27 #: templates/comments/list.html:18 templates/comments/list.html:27
msgid "Please login to vote" msgid "Please login to vote"
msgstr "Đăng nhập để vote" msgstr "Đăng nhập để vote"
@ -4347,122 +4355,126 @@ msgstr "Bạn có chắc muốn tính điểm lại %(count)d bài nộp?"
msgid "Rescore all submissions" msgid "Rescore all submissions"
msgstr "Tính điểm lại các bài nộp" msgstr "Tính điểm lại các bài nộp"
#: templates/problem/problem.html:130 #: templates/problem/problem.html:159
msgid "View as PDF" msgid "View as PDF"
msgstr "Xem PDF" msgstr "Xem PDF"
#: templates/problem/problem.html:139 templates/problem/problem.html:149 #: templates/problem/problem.html:168 templates/problem/problem.html:178
#: templates/problem/problem.html:154 #: templates/problem/problem.html:183
msgid "Submit solution" msgid "Submit solution"
msgstr "Nộp bài" msgstr "Nộp bài"
#: templates/problem/problem.html:142 #: templates/problem/problem.html:171
#, python-format #, python-format
msgid "%(counter)s submission left" msgid "%(counter)s submission left"
msgid_plural "%(counter)s submissions left" msgid_plural "%(counter)s submissions left"
msgstr[0] "Còn %(counter)s lần nộp" msgstr[0] "Còn %(counter)s lần nộp"
#: templates/problem/problem.html:150 #: templates/problem/problem.html:179
msgid "0 submissions left" msgid "0 submissions left"
msgstr "Còn 0 lần nộp" msgstr "Còn 0 lần nộp"
#: templates/problem/problem.html:162 #: templates/problem/problem.html:191
msgid "My submissions" msgid "My submissions"
msgstr "Bài nộp của tôi" msgstr "Bài nộp của tôi"
#: templates/problem/problem.html:166 #: templates/problem/problem.html:195
msgid "Best submissions" msgid "Best submissions"
msgstr "Các bài nộp tốt nhất" msgstr "Các bài nộp tốt nhất"
#: templates/problem/problem.html:170 #: templates/problem/problem.html:199
msgid "Discuss"
msgstr "Thảo luận"
#: templates/problem/problem.html:174
msgid "Read editorial" msgid "Read editorial"
msgstr "Xem hướng dẫn" msgstr "Xem hướng dẫn"
#: templates/problem/problem.html:179 #: templates/problem/problem.html:204
msgid "Manage tickets" msgid "Manage tickets"
msgstr "Xử lý báo cáo" msgstr "Xử lý báo cáo"
#: templates/problem/problem.html:183 #: templates/problem/problem.html:208
msgid "Edit problem" msgid "Edit problem"
msgstr "Chỉnh sửa bài" msgstr "Chỉnh sửa bài"
#: templates/problem/problem.html:185 #: templates/problem/problem.html:210
msgid "Edit test data" msgid "Edit test data"
msgstr "Chỉnh sửa test" msgstr "Chỉnh sửa test"
#: templates/problem/problem.html:190 #: templates/problem/problem.html:215
msgid "My tickets" msgid "My tickets"
msgstr "Báo cáo của tôi" msgstr "Báo cáo của tôi"
#: templates/problem/problem.html:198 #: templates/problem/problem.html:223
msgid "Manage submissions" msgid "Manage submissions"
msgstr "Quản lý bài nộp" msgstr "Quản lý bài nộp"
#: templates/problem/problem.html:204 #: templates/problem/problem.html:229
msgid "Clone problem" msgid "Clone problem"
msgstr "Nhân bản bài" msgstr "Nhân bản bài"
#: templates/problem/problem.html:211 #: templates/problem/problem.html:236
msgid "Points:" msgid "Points:"
msgstr "Điểm:" msgstr "Điểm:"
#: templates/problem/problem.html:214 templates/problem/problem.html:216 #: templates/problem/problem.html:239 templates/problem/problem.html:241
msgid "(partial)" msgid "(partial)"
msgstr "(thành phần)" msgstr "(thành phần)"
#: templates/problem/problem.html:221 #: templates/problem/problem.html:246
msgid "Time limit:" msgid "Time limit:"
msgstr "Thời gian:" msgstr "Thời gian:"
#: templates/problem/problem.html:233 #: templates/problem/problem.html:258
msgid "Memory limit:" msgid "Memory limit:"
msgstr "Bộ nhớ:" msgstr "Bộ nhớ:"
#: templates/problem/problem.html:252 #: templates/problem/problem.html:277
msgid "Author:" msgid "Author:"
msgid_plural "Authors:" msgid_plural "Authors:"
msgstr[0] "Tác giả:" msgstr[0] "Tác giả:"
#: templates/problem/problem.html:267 #: templates/problem/problem.html:292
msgid "Problem type" msgid "Problem type"
msgid_plural "Problem types" msgid_plural "Problem types"
msgstr[0] "Dạng bài" msgstr[0] "Dạng bài"
#: templates/problem/problem.html:280 #: templates/problem/problem.html:305
msgid "Allowed languages" msgid "Allowed languages"
msgstr "Ngôn ngữ cho phép" msgstr "Ngôn ngữ cho phép"
#: templates/problem/problem.html:288 #: templates/problem/problem.html:313
#, python-format #, python-format
msgid "No %(lang)s judge online" msgid "No %(lang)s judge online"
msgstr "Không có máy chấm cho %(lang)s" msgstr "Không có máy chấm cho %(lang)s"
#: templates/problem/problem.html:299 #: templates/problem/problem.html:324
msgid "Judge:" msgid "Judge:"
msgid_plural "Judges:" msgid_plural "Judges:"
msgstr[0] "Máy chấm:" msgstr[0] "Máy chấm:"
#: templates/problem/problem.html:316 #: templates/problem/problem.html:341
msgid "none available" msgid "none available"
msgstr "không có sẵn" msgstr "không có sẵn"
#: templates/problem/problem.html:331 #: templates/problem/problem.html:356
#, python-format #, python-format
msgid "This problem has %(length)s clarification(s)" msgid "This problem has %(length)s clarification(s)"
msgstr "Bài này có %(length)s thông báo" msgstr "Bài này có %(length)s thông báo"
#: templates/problem/problem.html:359 #: templates/problem/problem.html:384
msgid "Request clarification" msgid "Request clarification"
msgstr "Yêu cầu làm rõ đề" msgstr "Yêu cầu làm rõ đề"
#: templates/problem/problem.html:361 #: templates/problem/problem.html:386
msgid "Report an issue" msgid "Report an issue"
msgstr "Báo cáo một vấn đề" msgstr "Báo cáo một vấn đề"
#: templates/problem/problem.html:395
msgid "View comments"
msgstr "Xem bình luận"
#: templates/problem/problem.html:397
msgid "Be the first to comment"
msgstr "Bình luận đầu tiên"
#: templates/problem/raw.html:64 #: templates/problem/raw.html:64
msgid "Time Limit:" msgid "Time Limit:"
msgstr "Giới hạn thời gian:" msgstr "Giới hạn thời gian:"
@ -4557,11 +4569,11 @@ msgstr "Không có máy chấm có thể chấm bài này."
msgid "Submit!" msgid "Submit!"
msgstr "Nộp bài!" msgstr "Nộp bài!"
#: templates/problem/voting-controls.html:53 #: templates/problem/voting-controls.html:55
msgid "Edit difficulty" msgid "Edit difficulty"
msgstr "Thay đổi độ khó" msgstr "Thay đổi độ khó"
#: templates/problem/voting-controls.html:61 #: templates/problem/voting-controls.html:63
msgid "Vote difficulty" msgid "Vote difficulty"
msgstr "Bình chọn độ khó" msgstr "Bình chọn độ khó"
@ -4573,14 +4585,6 @@ msgstr "Bạn thấy độ khó bài này thế nào?"
msgid "This helps us improve the site" msgid "This helps us improve the site"
msgstr "Bình chọn giúp admin cải thiện bài tập." msgstr "Bình chọn giúp admin cải thiện bài tập."
#: templates/problem/voting-form.html:38
msgid "Easy"
msgstr "Dễ"
#: templates/problem/voting-form.html:39
msgid "Hard"
msgstr "Khó"
#: templates/problem/voting-stats.html:29 #: templates/problem/voting-stats.html:29
msgid "Voting Statistics" msgid "Voting Statistics"
msgstr "Thống kê" msgstr "Thống kê"
@ -4992,6 +4996,10 @@ msgstr "Tốt nhất"
msgid "%(user)s's" msgid "%(user)s's"
msgstr "" msgstr ""
#: templates/ticket/feed.html:20
msgid " replied"
msgstr ""
#: templates/ticket/list.html:135 templates/ticket/ticket.html:273 #: templates/ticket/list.html:135 templates/ticket/ticket.html:273
msgid "Reopened: " msgid "Reopened: "
msgstr "Mở lại: " msgstr "Mở lại: "
@ -5331,3 +5339,30 @@ msgstr "Thông tin"
#: templates/widgets/select_all.html:8 #: templates/widgets/select_all.html:8
msgid "Check all" msgid "Check all"
msgstr "Chọn tất cả" msgstr "Chọn tất cả"
#~ msgid "Discuss <a href=\"{1}\">{0}</a>"
#~ msgstr "Thảo luận <a href=\"{1}\">{0}</a>"
#~ msgid "posted"
#~ msgstr "đã đăng"
#~ msgid "My open tickets"
#~ msgstr "Báo cáo dành cho tôi"
#~ msgid "New tickets"
#~ msgstr "Báo cáo mới"
#~ msgid "New problems"
#~ msgstr "Bài tập mới"
#~ msgid "Comment stream"
#~ msgstr "Dòng bình luận"
#~ msgid "Discuss"
#~ msgstr "Thảo luận"
#~ msgid "Easy"
#~ msgstr "Dễ"
#~ msgid "Hard"
#~ msgstr "Khó"

View file

@ -232,7 +232,7 @@ header {
} }
#navigation { #navigation {
position: relative; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
@ -382,7 +382,7 @@ hr {
} }
#content { #content {
margin: 1em auto auto; margin: 4.5em auto 1em auto;
// Header // Header
width: 90%; width: 90%;

View file

@ -2,9 +2,9 @@
.blog-content { .blog-content {
padding-right: 0em; padding-right: 0em;
flex: 73.5%;
vertical-align: top; vertical-align: top;
margin-right: 0; margin-right: 0;
width: 100%;
.post { .post {
border: 1px dotted grey; border: 1px dotted grey;
@ -33,7 +33,8 @@
} }
.blog-sidebar { .blog-sidebar {
flex: 26.5%; width: 100%;
margin-left: auto;
} }
.blog-sidebox { .blog-sidebox {
@ -88,6 +89,19 @@
color: #555; color: #555;
} }
@media (max-width: 799px) {
.left-sidebar-header {
display: none;
}
.left-sidebar-item {
display: inline-block;
}
.blog-left-sidebar {
text-align: right;
padding-right: 1em;
margin-bottom: 1em;
}
}
@media (min-width: 800px) { @media (min-width: 800px) {
.blog-content, .blog-sidebar { .blog-content, .blog-sidebar {
display: block !important; display: block !important;
@ -104,6 +118,28 @@
#blog-container { #blog-container {
display: flex; display: flex;
} }
.blog-content {
max-width: 71.5%;
margin-left: 10%;
}
.blog-sidebar {
width: 18%;
}
.blog-left-sidebar {
width: 8%;
margin-right: 1em;
position: fixed;
height: 100%;
margin-top: -4em;
padding-top: 4em;
}
.feed-table {
font-size: small;
}
} }
#mobile.tabs { #mobile.tabs {
@ -135,3 +171,63 @@
} }
} }
} }
.blog-box {
border-bottom: 1px solid black;
width: 90%;
margin-bottom: 2.5em;
padding: 0.5em 1.25em;
background-color: white;
margin-left: auto;
margin-right: auto;
}
.blog-description {
max-height: 20em;
overflow: hidden;
overflow-wrap: anywhere;
padding-bottom: 1em;
}
.problem-feed-name {
display: inline;
font-weight: bold;
}
.problem-feed-name a {
color: #0645ad;
}
.problem-feed-info-entry {
display: inline;
float: right;
}
.problem-feed-types {
color: gray;
}
.blog-left-sidebar {
background-color: #f0f1f3;
color: #616161;
}
.left-sidebar-item {
padding: 1em 0.5em;
text-align: center;
}
.left-sidebar-item:hover {
background-color: lightgray;
cursor: pointer;
}
.sidebar-icon {
font-size: x-large;
margin-bottom: 0.1em;
color: black;
}
.left-sidebar-header {
text-align: center;
padding-bottom: 1em;
border-bottom: 1px solid black;
color: black;
border-radius: 0;
}
.feed-table {
margin: 0;
}

View file

@ -1,18 +1,16 @@
<section class="{% if post.sticky %}sticky {% endif %}post"> <section class="{% if post.sticky %}sticky {% endif %}blog-box">
<h2 class="title"> <div style="margin-bottom: 0.5em">
<a href="{{ url('blog_post', post.id, post.slug) }}">{{ post.title }}</a>
</h2>
<span style="float: right">
<span class="time"> <span class="time">
{%- if post.sticky %}<i title="Sticky" class="fa fa-star fa-fw"></i>{% endif -%}
{% with authors=post.authors.all() %} {% with authors=post.authors.all() %}
{%- if authors -%} {%- if authors -%}
<img src="{{gravatar(authors[0])}}" style="width: 1.5em; border-radius: 50%; margin-bottom: -0.3em">
<span class="post-authors">{{ link_users(authors) }}</span> <span class="post-authors">{{ link_users(authors) }}</span>
{%- endif -%} {%- endif -%}
{% endwith %} {% endwith %}
{{_('posted')}} {{ relative_time(post.publish_on, abs=_('on {time}'), rel=_('{time}')) -}} &#8226; {{ relative_time(post.publish_on, abs=_('on {time}'), rel=_('{time}')) -}}
{%- if post.sticky %} &#8226; <i title="Sticky" class="fa fa-star fa-fw"></i>{% endif -%}
</span> </span>
<span> <span style="float: right">
<a href="{{ url('blog_post', post.id, post.slug) }}#comments" class="blog-comment-count-link"> <a href="{{ url('blog_post', post.id, post.slug) }}#comments" class="blog-comment-count-link">
<i class="fa fa-comments blog-comment-icon"></i> <i class="fa fa-comments blog-comment-icon"></i>
<span class="blog-comment-count"> <span class="blog-comment-count">
@ -20,8 +18,10 @@
</span> </span>
</a> </a>
</span> </span>
</span> </div>
<div style="clear:both"></div> <h2 class="title">
<a href="{{ url('blog_post', post.id, post.slug) }}">{{ post.title }}</a>
</h2>
{% if post.is_organization_private and show_organization_private_icon %} {% if post.is_organization_private and show_organization_private_icon %}
<div class="organization-tags"> <div class="organization-tags">
{% for org in post.organizations.all() %} {% for org in post.organizations.all() %}
@ -33,7 +33,7 @@
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
<div class="summary content-description"> <div class="summary content-description blog-description">
{% cache 86400 'post_summary' post.id %} {% cache 86400 'post_summary' post.id %}
{{ post.summary|default(post.content, true)|markdown('blog', 'svg', lazy_load=True)|reference|str|safe }} {{ post.summary|default(post.content, true)|markdown('blog', 'svg', lazy_load=True)|reference|str|safe }}
{% endcache %} {% endcache %}

View file

@ -16,30 +16,10 @@
clear: both; clear: both;
} }
} }
.post {
margin: 0 2%;
}
.time { .time {
margin-left: 0; margin-left: 0;
} }
.post:first-child {
margin-top: 0.6em;
}
.own-open-tickets .title a, .open-tickets .title a {
display: block;
}
.own-open-tickets .object, .open-tickets .object {
margin-left: 1em;
font-style: italic;
}
.open-tickets .user {
margin-left: 1em;
}
.no-clarifications-message { .no-clarifications-message {
font-style: italic; font-style: italic;
text-align: center; text-align: center;
@ -56,6 +36,11 @@
#add-clarification:hover { #add-clarification:hover {
color: cyan; color: cyan;
} }
#content {
width: 99%;
margin-left: 0;
}
</style> </style>
{% endblock %} {% endblock %}
@ -81,6 +66,35 @@
$('.blog-content').hide(); $('.blog-content').hide();
$('.blog-sidebar').show(); $('.blog-sidebar').show();
}); });
$('.blog-description').on('click', function() {
var max_height = $(this).css('max-height');
if (max_height !== 'fit-content') {
$(this).css('max-height', 'fit-content');
$(this).parent().css('background-image', 'inherit')
.css('padding-bottom', '0.5em');
$(this).css('cursor', 'auto');
}
})
$('.blog-description').each(function() {
if ($(this).prop('scrollHeight') > $(this).height() ) {
$(this).parent().css('background-image', '-webkit-linear-gradient(bottom, lightgray, lightgray 3%, transparent 8%, transparent 100%)');
$(this).parent().css('padding-bottom', '0');
$(this).css('cursor', 'pointer');
}
});
$('.left-sidebar-item').on('click', function() {
var url = $(this).attr('data-href');
window.location.replace(url);
});
{% if feed_type == 'blog' %}
$('#news-icon').css('color', 'green');
{% elif feed_type == 'problem' %}
$('#problems-icon').css('color', 'green');
{% elif feed_type == 'ticket' %}
$('#tickets-icon').css('color', 'green');
{% elif feed_type == 'comment' %}
$('#comments-icon').css('color', 'green');
{% endif %}
}); });
</script> </script>
{% endblock %} {% endblock %}
@ -90,20 +104,54 @@
<div id="mobile" class="tabs"> <div id="mobile" class="tabs">
<ul> <ul>
<li id="blog-tab" class="tab active"><a href="#"> <li id="blog-tab" class="tab active"><a href="#">
<i class="tab-icon fa fa-info-circle"></i> {{ _('Blog') }} <i class="tab-icon fa fa-info-circle"></i> {{ _('Feed') }}
</a></li> </a></li>
<li id="event-tab" class="tab"><a href="#"><i class="tab-icon fa fa-rss"></i> {{ _('Events') }}</a></li> <li id="event-tab" class="tab"><a href="#"><i class="tab-icon fa fa-rss"></i> {{ _('Events') }}</a></li>
</ul> </ul>
</div> </div>
<div id="blog-container"> <div id="blog-container">
<div class="blog-content sidebox"> <div class="blog-left-sidebar">
<h3>{{ _('News') }} <i class="fa fa-terminal"></i></h3> <h3 class="left-sidebar-header">{{_('Content')}}</h3>
<div class="sidebox-content"> <div class="left-sidebar-item" data-href="{{url('home')}}">
{% set show_organization_private_icon=True %} <div class="sidebar-icon" id="news-icon"><i class="fa fa-rss"></i></div>
{{_('News')}}
</div>
<div class="left-sidebar-item" data-href="{{url('problem_feed')}}">
<div class="sidebar-icon" id="problems-icon"><i class="fa fa-tasks"></i></div>
{{_('Problems')}}
</div>
<div class="left-sidebar-item" data-href="{{url('comment_feed')}}">
<div class="sidebar-icon" id="comments-icon"><i class="fa fa-comments"></i></div>
{{_('Comments')}}
</div>
<div class="left-sidebar-item" data-href="{{url('ticket_feed')}}">
<div class="sidebar-icon" id="tickets-icon"><i class="fa fa-question-circle"></i></div>
{{_('Tickets')}}
</div>
</div>
<div class="blog-content">
{% set show_organization_private_icon=True %}
{% if feed_type == 'blog' %}
{% for post in posts %} {% for post in posts %}
{% include "blog/content.html" %} {% include "blog/content.html" %}
{% endfor %} {% endfor %}
</div> {% elif feed_type == 'problem' %}
{% for problem in problems %}
{% include "problem/feed.html" %}
{% endfor %}
{% elif feed_type == 'ticket' %}
{% if tickets %}
{% for ticket in tickets %}
{% include "ticket/feed.html" %}
{% endfor %}
{% else %}
<h3 style="text-align: center">{{_('You have no ticket')}}</h3>
{% endif %}
{% elif feed_type == 'comment' %}
{% for comment in comments %}
{% include "comments/feed.html" %}
{% endfor %}
{% endif %}
{% if page_obj.num_pages > 1 %} {% if page_obj.num_pages > 1 %}
<div style="margin-bottom:10px;margin-top:10px">{% include "list-pages.html" %}</div> <div style="margin-bottom:10px;margin-top:10px">{% include "list-pages.html" %}</div>
{% endif %} {% endif %}
@ -178,85 +226,36 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% if own_open_tickets %}
<div class="blog-sidebox sidebox">
<h3>{{ _('My open tickets') }} <i class="fa fa-question-circle"></i></h3>
<div class="sidebox-content">
<ul class="own-open-tickets">
{% for ticket in own_open_tickets %}
<li>
<div class="title">
<a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a>
</div>
<div class="object">
<a href="{{ ticket.linked_item.get_absolute_url() }}">
{{ ticket.linked_item|item_title }}</a>
</div>
<div>{{ link_user(ticket.user) }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{% if open_tickets %}
<div class="blog-sidebox sidebox">
<h3>{{ _('New tickets') }} <i class="fa fa-exclamation-circle"></i></h3>
<div class="sidebox-content">
<ul class="open-tickets">
{% for ticket in open_tickets %}
<li>
<div class="title">
<a href="{{ url('ticket', ticket.id) }}">{{ ticket.title }}</a>
</div>
<div class="object">
<a href="{{ ticket.linked_item.get_absolute_url() }}">
{{ ticket.linked_item|item_title }}</a>
</div>
<div>{{ link_user(ticket.user) }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
<div class="blog-sidebox sidebox"> <div class="blog-sidebox sidebox">
<h3>{{ _('New problems') }} <i class="fa fa-puzzle-piece"></i> <h3>{{ _('Top Rating') }} <i class="fa fa-trophy"></i></h3>
</h3> <div class="sidebox-content" style="padding: 0; border: 0">
<div class="sidebox-content"> <table class="table feed-table">
<ul class="problem-list"> <tbody>
{% for problem in new_problems %} {% for user in top_rated %}
<li><a href="{{ url('problem_detail', problem.code) }}">{{ problem.name }}</a></li> <tr>
{% endfor %} <td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
</ul> <td>{{link_user(user)}}</td>
<span class="rssatom"> <td>{{user.rating}}</td>
<a href="{{ url('problem_rss') }}"><span><i class="fa fa-rss"></i></span> RSS</a> </tr>
/ {% endfor %}
<a href="{{ url('problem_atom') }}">Atom</a> </tbody>
</span> </table>
</div> </div>
</div> </div>
<div class="blog-sidebox sidebox"> <div class="blog-sidebox sidebox">
<h3>{{ _('Comment stream') }} <i class="fa fa-comments"></i></h3> <h3>{{ _('Top Score') }} <i class="fa fa-trophy"></i></h3>
<div class="sidebox-content"> <div class="sidebox-content" style="padding: 0; border: 0">
<ul> <table class="table feed-table">
{% for comment in comments %} <tbody>
<li> {% for user in top_scorer %}
<span style="padding-left:0.25em" class="poster"> <tr>
{{ link_user(comment.author) }} <td style="padding: 7px 2px"><b>{{loop.index}}</b></td>
</span> &rarr; <td>{{link_user(user)}}</td>
<a href="{{ comment.link }}#comment-{{ comment.id }}">{{ page_titles[comment.page] }}</a> <td>{{ user.performance_points|floatformat(0) }}</td>
</li>{% endfor %} </tr>
</ul> {% endfor %}
<span class="rssatom"> </tbody>
<a href="{{ url('comment_rss') }}"><span><i class="fa fa-rss"></i></span> RSS</a> </table>
/
<a href="{{ url('comment_atom') }}">Atom</a>
</span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
<style> <style>
#content { #content {
margin: -1em 1em 0 0; margin: 2.5em 1em 0 0;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {

View file

@ -0,0 +1,18 @@
<div class="blog-box">
<h3 class="problem-feed-name">
<a href="{{ comment.link }}#comment-{{ comment.id }}">
{{ page_titles[comment.page] }}
</a>
</h3>
{% with author=comment.author %}
{% if author %}
<div class="problem-feed-info-entry">
<i class="fa fa-pencil-square-o fa-fw"></i>
<span class="pi-value">{{ link_user(author) }}</span>
</div>
{% endif %}
{% endwith %}
<div class='blog-description content-description'>
{{ comment.body |markdown("comment", MATH_ENGINE)|reference|str|safe }}
</div>
</div>

View file

@ -1,28 +0,0 @@
{% extends "common-content.html" %}
{% block content_js_media %}
{% include "comments/media-js.html" %}
{% endblock %}
{% block content_media %}
{% include "comments/media-css.html" %}
<style>
#comment-header {
display: none;
}
.no-comments-message {
margin-top: 0;
}
</style>
{% endblock %}
{% block body %}
{% include "comments/list.html" %}
{% endblock %}
{% block bodyend %}
{% if REQUIRE_JAX %}
{% include "mathjax-load.html" %}
{% endif %}
{% include "comments/math.html" %}
{% endblock %}

View file

@ -0,0 +1,28 @@
<div class="blog-box">
<h3 class="problem-feed-name">
<a href="{{ url('problem_detail', problem.code) }}">
{{ problem.name }}
</a>
</h3>
{% with authors=problem.authors.all() %}
{% 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 %}
{% endwith %}
{% if true %}
<div class="problem-feed-types">
<i class="fa fa-tag"></i>
{% for type in problem.types_list %}
<span class="type-tag">{{ type }}</span>{% if not loop.last %}, {% endif %}
{% endfor %}
</div>
{% endif %}
<div class='blog-description content-description'>
{% cache 86400 'problem_html' problem.id MATH_ENGINE LANGUAGE_CODE %}
{{ problem.description|markdown("problem", MATH_ENGINE)|reference|str|safe }}
{% endcache %}
</div>
</div>

View file

@ -1,5 +1,6 @@
{% extends "common-content.html" %} {% extends "common-content.html" %}
{% block content_media %} {% block content_media %}
{% include "comments/media-css.html" %}
<style> <style>
.title-state { .title-state {
font-size: 2em; font-size: 2em;
@ -54,10 +55,30 @@
#clarification_header:hover { #clarification_header:hover {
color: orange; color: orange;
} }
#comment-announcement {
margin-top: 1em;
background-color: lightgray;
border-radius: 30px;
padding: 0.5em;
text-align: center;
cursor: pointer;
color: dimgrey;
font-weight: bold;
}
#comment-announcement:hover {
background-color: gray;
}
#comment-section {
display: none;
}
</style> </style>
{% endblock %} {% endblock %}
{% block content_js_media %} {% block content_js_media %}
{% include "comments/media-js.html" %}
{% if request.in_contest_mode %} {% if request.in_contest_mode %}
<script type="text/javascript"> <script type="text/javascript">
window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}"); window.register_contest_notification("{{url('contest_clarification_ajax', request.participation.contest.key)}}");
@ -79,6 +100,14 @@
$('#clarification_header_container').hide(); $('#clarification_header_container').hide();
window.scrollTo(0, document.body.scrollHeight); window.scrollTo(0, document.body.scrollHeight);
}) })
$('#comment-announcement').on('click', function() {
$('#comment-section').show();
$('#comment-announcement').hide();
})
if (window.location.href.includes('#comment')) {
$('#comment-announcement').click();
}
}); });
</script> </script>
{% endblock %} {% endblock %}
@ -164,13 +193,9 @@
{% endif %} {% endif %}
<div><a href="{{ url('chronological_submissions', problem.code) }}">{{ _('All submissions') }}</a></div> <div><a href="{{ url('chronological_submissions', problem.code) }}">{{ _('All submissions') }}</a></div>
<div><a href="{{ url('ranked_submissions', problem.code) }}">{{ _('Best submissions') }}</a></div> <div><a href="{{ url('ranked_submissions', problem.code) }}">{{ _('Best submissions') }}</a></div>
{% if not contest_problem or not contest_problem.contest.use_clarifications %}
<hr>
<div><a href="{{ url('problem_comments', problem.code) }}">{{ _('Discuss') }}</a></div>
{% endif %}
{% if editorial and editorial.is_public and {% if editorial and editorial.is_public and
not (request.user.is_authenticated and request.profile.current_contest) %} not (request.user.is_authenticated and request.profile.current_contest) %}
<hr>
<div><a href="{{ url('problem_editorial', problem.code) }}">{{ _('Read editorial') }}</a></div> <div><a href="{{ url('problem_editorial', problem.code) }}">{{ _('Read editorial') }}</a></div>
{% endif %} {% endif %}
{% if can_edit_problem %} {% if can_edit_problem %}
@ -361,6 +386,18 @@
{{ _('Report an issue') }} {{ _('Report an issue') }}
{%- endif -%} {%- endif -%}
</a> </a>
<div style="clear: both"></div>
{% endif %}
{% if not (contest_problem and contest_problem.contest.use_clarifications) %}
<div id="comment-announcement-container">
<div id="comment-announcement">
{% if has_comments %}
{{_('View comments')}} ({{comment_list.count()}})
{% else %}
{{_('Be the first to comment')}}
{% endif %}
</div>
</div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
@ -381,6 +418,10 @@
<p class="no-comments-message">{{ _('No clarifications have been made at this time.') }}</p> <p class="no-comments-message">{{ _('No clarifications have been made at this time.') }}</p>
{% endif %} {% endif %}
</div> </div>
{% else %}
<div id="comment-section">
{% include "comments/list.html" %}
</div>
{% endif %} {% endif %}
<iframe name="raw_problem" id="raw_problem"></iframe> <iframe name="raw_problem" id="raw_problem"></iframe>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,25 @@
<div class="blog-box">
<h3 class="problem-feed-name">
<a href="{{ url('ticket', ticket.id) }}">
{{ ticket.title }}
</a>
-
<a href="{{ ticket.linked_item.get_absolute_url() }}">
{{ ticket.linked_item|item_title }}</a>
</h3>
{% with author=ticket.user %}
{% if author %}
<div class="problem-feed-info-entry">
<i class="fa fa-pencil-square-o fa-fw"></i>
<span class="pi-value">{{ link_user(author) }}</span>
</div>
{% endif %}
{% endwith %}
<div class="problem-feed-types">
<i class="fa fa-tag"></i>
{{link_user(ticket.messages.last().user)}} {{_(' replied')}}
</div>
<div class='blog-description content-description'>
{{ ticket.messages.last().body |markdown("ticket", MATH_ENGINE)|reference|str|safe }}
</div>
</div>