diff options
| author | Bobby <[email protected]> | 2025-01-02 23:47:41 -0500 |
|---|---|---|
| committer | Bobby <[email protected]> | 2025-01-02 23:47:41 -0500 |
| commit | a9c4481356e54317584a4f92d7329364f8ad99e3 (patch) | |
| tree | afc5991e0c662a9250c7cde64bc08b3b51dc78e8 | |
| parent | b6bf53661c750cc11fc4d976a594e3ef19cc7363 (diff) | |
| download | thatcomputerscientist-a9c4481356e54317584a4f92d7329364f8ad99e3.tar.xz thatcomputerscientist-a9c4481356e54317584a4f92d7329364f8ad99e3.zip | |
some optimization stuff
| -rwxr-xr-x | apps/blog/admin.py | 11 | ||||
| -rw-r--r-- | apps/blog/migrations/0022_comment_downvotes_comment_upvotes.py | 23 | ||||
| -rwxr-xr-x | apps/blog/models.py | 119 | ||||
| -rwxr-xr-x | apps/blog/views.py | 25 | ||||
| -rwxr-xr-x | internal/weblog_utilities.py | 45 | ||||
| -rwxr-xr-x | static/css/core/post_list.css | 99 | ||||
| -rwxr-xr-x | static/css/shared/core.css | 148 | ||||
| -rw-r--r-- | static/images/core/messages/texts/navigation_en.png | bin | 0 -> 140274 bytes | |||
| -rw-r--r-- | templates/partials/_comment.html | 59 | ||||
| -rwxr-xr-x | templates/partials/_weblog_list.html | 14 | ||||
| -rw-r--r-- | templates/shared/blog/single_weblog.html | 29 |
11 files changed, 429 insertions, 143 deletions
diff --git a/apps/blog/admin.py b/apps/blog/admin.py index 157fff51..cd9a25b8 100755 --- a/apps/blog/admin.py +++ b/apps/blog/admin.py @@ -191,10 +191,17 @@ class WeblogAdmin(admin.ModelAdmin): @admin.register(Comment) class CommentAdmin(admin.ModelAdmin): - list_display = ("post", "get_author", "created_at", "edited") + list_display = ( + "post", + "get_author", + "created_at", + "edited", + "upvotes", + "downvotes", + ) list_filter = ("edited", "created_at") search_fields = ("body", "user__username", "anonymous_user__name") - readonly_fields = ("created_at", "edited", "edited_at") + readonly_fields = ("created_at", "edited_at") def get_author(self, obj): return obj.user.username if obj.user else obj.anonymous_user.name diff --git a/apps/blog/migrations/0022_comment_downvotes_comment_upvotes.py b/apps/blog/migrations/0022_comment_downvotes_comment_upvotes.py new file mode 100644 index 00000000..0281c686 --- /dev/null +++ b/apps/blog/migrations/0022_comment_downvotes_comment_upvotes.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.4 on 2025-01-03 01:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0021_categorytranslation_tagtranslation'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='downvotes', + field=models.IntegerField(default=0), + ), + migrations.AddField( + model_name='comment', + name='upvotes', + field=models.IntegerField(default=0), + ), + ] diff --git a/apps/blog/models.py b/apps/blog/models.py index 9fa7eb30..bdfb6921 100755 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -64,18 +64,62 @@ class PostTranslation(Translation): class TranslatableMixin: + @classmethod + def translate_queryset(cls, queryset, language_code="en"): + processed_objects = set() + return [obj.translate(language_code, processed_objects) for obj in queryset] + + def translate(self, language_code="en", processed_objects=None): + if processed_objects is None: + processed_objects = set() + + instance_id = f"{self.__class__.__name__}_{self.pk}" + if instance_id in processed_objects: + return self + + processed_objects.add(instance_id) + translation = self.get_translation(language_code) + + if translation: + translated_fields = [ + field.name + for field in translation._meta.get_fields() + if not field.is_relation + and field.name not in ["id", "language", "created_at", "updated_at"] + ] + + for field_name in translated_fields: + translated_value = getattr(translation, field_name, None) + if translated_value is not None: + setattr(self, field_name, translated_value) + + self._translate_relations(language_code, processed_objects) + return self + + def _translate_relations(self, language_code, processed_objects): + for field in self._meta.get_fields(): + if not hasattr(field, "related_model") or not hasattr( + field.related_model, "translate" + ): + continue + + if field.one_to_many or field.many_to_many: + related_manager = getattr(self, field.name, None) + if related_manager and hasattr(related_manager, "all"): + for obj in related_manager.all(): + obj.translate(language_code, processed_objects) + + elif field.many_to_one or field.one_to_one: + related_obj = getattr(self, field.name, None) + if related_obj and hasattr(related_obj, "translate"): + related_obj.translate(language_code, processed_objects) + def get_translation(self, language_code): try: return self.translations.get(language=language_code) except self.translations.model.DoesNotExist: return None - def translate(self, field_name, language_code="en"): - translation = self.get_translation(language_code) - if translation and hasattr(translation, field_name): - return getattr(translation, field_name) - return getattr(self, field_name) - class Weblog(models.Model): name = models.CharField(max_length=100) @@ -94,7 +138,7 @@ class Weblog(models.Model): return self.name -class Category(models.Model): +class Category(TranslatableMixin, models.Model): weblog = models.ForeignKey(Weblog, on_delete=models.CASCADE) name = models.CharField(max_length=50) name_ja = models.CharField( @@ -120,7 +164,7 @@ class Category(models.Model): return self.translate("name", language_code) -class Tag(models.Model): +class Tag(TranslatableMixin, models.Model): weblog = models.ForeignKey(Weblog, on_delete=models.CASCADE) name = models.CharField(max_length=50) name_ja = models.CharField( @@ -145,7 +189,7 @@ class Tag(models.Model): return self.translate("name", language_code) -class Post(models.Model): +class Post(TranslatableMixin, models.Model): weblog = models.ForeignKey(Weblog, on_delete=models.CASCADE) title = models.CharField(max_length=100) title_ja = models.CharField( @@ -176,15 +220,52 @@ class Post(models.Model): def __str__(self): return f"{self.weblog.name} - {self.title}" - def get_excerpt(self, language_code="en", length=1000): - content = self.get_body(language_code) - soup = BeautifulSoup(content, "html.parser") - excerpt = "" - for paragraph in soup.find_all("p"): - excerpt += f"<p>{paragraph.text}</p>" - if len(excerpt) >= length: - break - return excerpt + def get_excerpt(self, length=1000): + if not hasattr(self, "_excerpt"): + soup = BeautifulSoup(self.body, "html.parser") + excerpt = "" + for paragraph in soup.find_all("p"): + paragraph = "<p>" + str(paragraph) + "</p>" + excerpt += str(paragraph) + + if len(excerpt) >= length: + break + self._excerpt = excerpt + return self._excerpt + + @property + def excerpt(self): + return self.get_excerpt() + + def get_processed_body(self): + if not hasattr(self, "_processed_body"): + soup = BeautifulSoup(self.body, "html.parser") + first_p = soup.find("p") + + self._first_paragraph = str(first_p) if first_p else "" + if first_p: + first_p.decompose() + + self._processed_body = str(soup) + + return self._processed_body + + @property + def processed_body(self): + return self.get_processed_body() + + @property + def first_paragraph(self): + if not hasattr(self, "_first_paragraph"): + self.get_processed_body() + return self._first_paragraph + + def translate(self, language_code="en", processed_objects=None): + instance = super().translate(language_code, processed_objects) + if hasattr(instance, "_processed_body"): + delattr(instance, "_processed_body") + delattr(instance, "_first_paragraph") + return instance class AnonymousCommentUser(models.Model): @@ -218,6 +299,8 @@ class Comment(models.Model): parent = models.ForeignKey( "self", on_delete=models.CASCADE, null=True, blank=True, related_name="replies" ) + upvotes = models.IntegerField(default=0) + downvotes = models.IntegerField(default=0) body = models.TextField() created_at = models.DateTimeField(auto_now_add=True) edited = models.BooleanField(default=False) diff --git a/apps/blog/views.py b/apps/blog/views.py index f590ee2b..d2f6c647 100755 --- a/apps/blog/views.py +++ b/apps/blog/views.py @@ -7,23 +7,16 @@ from bs4 import BeautifulSoup def single_post(request, slug): try: - post = Post.objects.get(slug=slug) - lang_code = request.LANGUAGE_CODE - if lang_code == "ja": - post.body = highlight_code(post.body_ja) - else: - post.body = highlight_code(post.body) - - soup = BeautifulSoup(post.body, "html.parser") - first_paragraph = soup.find("p") - if first_paragraph is not None: - first_paragraph = str(first_paragraph) - soup.find("p").decompose() - - post.first_paragraph = first_paragraph - post.body = str(soup) - + post = ( + Post.objects.select_related("category") + .prefetch_related( + "tags", "translations", "category__translations", "tags__translations" + ) + .get(slug=slug) + .translate(lang_code) + ) + post.body = highlight_code(post.processed_body) return render(request, "shared/blog/single_weblog.html", {"post": post}) except Post.DoesNotExist: return HttpResponseNotFound() diff --git a/internal/weblog_utilities.py b/internal/weblog_utilities.py index 02b851e9..6721fdc8 100755 --- a/internal/weblog_utilities.py +++ b/internal/weblog_utilities.py @@ -1,35 +1,38 @@ -from apps.blog.models import Post, Comment +from apps.blog.models import Post from pygments import highlight from pygments.lexers import get_lexer_by_name, guess_lexer from pygments.formatters import HtmlFormatter +from pygments.styles.vim import VimStyle +from pygments.style import Style +from pygments.token import Comment from bs4 import BeautifulSoup import html AUTHOR_USERNAME = "bobby" -def add_excerpt(post, lang="en"): - if lang == "ja": - soup = BeautifulSoup(post.body_ja, "html.parser") - else: - soup = BeautifulSoup(post.body, "html.parser") - excerpt = "" - for paragraph in soup.find_all("p"): - paragraph = "<p>" + str(paragraph.text) + "</p>" - excerpt += str(paragraph) +class ShifooHighlight(Style): + """Custom Vim style with modified comment colors""" - if len(excerpt) >= 1000: - break - return excerpt + # Inherit all styles from VimStyle + styles = dict(VimStyle.styles) + # Override comment styles using proper token types + styles.update( + {Comment: "#666666", Comment.Preproc: "#666666", Comment.Special: "#666666"} + ) -def recent_weblogs(lang="en", amount=3): - recent_posts = Post.objects.filter( - is_public=True, author__username=AUTHOR_USERNAME - ).order_by("-date")[:amount] - for post in recent_posts: - post.excerpt = add_excerpt(post, lang) - return recent_posts + +def recent_weblogs(lang="en", amount=10): + queryset = ( + Post.objects.filter(is_public=True, author__username=AUTHOR_USERNAME) + .prefetch_related( + "tags", "translations", "category__translations", "tags__translations" + ) + .order_by("-date")[:amount] + ) + + return Post.translate_queryset(queryset, lang) def highlight_code(html_content): @@ -55,7 +58,7 @@ def highlight_code(html_content): formatter = HtmlFormatter( noclasses=True, - style="native", + style=ShifooHighlight, wrapcode=True, cssstyles="background: none; padding: 8px 0;", ) diff --git a/static/css/core/post_list.css b/static/css/core/post_list.css index 7f7511a2..7df9b158 100755 --- a/static/css/core/post_list.css +++ b/static/css/core/post_list.css @@ -49,6 +49,7 @@ } .post-actions { + clear: both; display: flex; justify-content: space-between; margin: 8px 0px; @@ -62,12 +63,106 @@ font-size: 11px; font-weight: normal; text-transform: capitalize; - background-color: #311b4f; - color: #dddddd !important; + color: #fff !important; border-radius: 10px; + background: linear-gradient(145deg, #452673, #311b4f); + box-shadow: + inset 0 1px 1px rgba(255, 255, 255, 0.4), + inset 0 -1px 1px rgba(0, 0, 0, 0.4), + 0 0 5px rgba(69, 38, 115, 0.5), + 0 2px 4px rgba(0, 0, 0, 0.2); + border: 1px solid #5a338f; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5); + transition: all 0.2s ease; + position: relative; + overflow: hidden; } .post-tag:hover { + background: linear-gradient(145deg, #512c85, #3d2361); + box-shadow: + inset 0 1px 1px rgba(255, 255, 255, 0.4), + inset 0 -1px 1px rgba(0, 0, 0, 0.4), + 0 0 10px rgba(69, 38, 115, 0.8), + 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.post-tag:hover::after { + content: ''; + position: absolute; + top: -50%; + left: -150%; + width: 200%; + height: 200%; + background: linear-gradient(45deg, + transparent 0%, + rgba(255, 255, 255, 0.1) 45%, + rgba(255, 255, 255, 0.5) 50%, + rgba(255, 255, 255, 0.1) 55%, + transparent 100%); + transform: rotate(45deg); + animation: shine 4s linear infinite; +} + +.post-tag:active { + background: linear-gradient(145deg, #311b4f, #452673); + box-shadow: + inset 0 2px 4px rgba(0, 0, 0, 0.4), + 0 0 5px rgba(69, 38, 115, 0.5); + transform: translateY(1px); +} + +@keyframes shine { + 0% { + left: -150%; + } + + 25% { + left: 100%; + } + + 100% { + left: 100%; + } +} + +/* .post-tag:hover { background-color: #311b4f; color: #dddddd !important; +} */ + +p>img { + shape-outside: margin-box; + width: auto; + height: auto; + max-width: 180px; + max-height: 180px; + border-radius: 4px; + overflow: hidden; + position: relative; + top: 6px; + margin-bottom: 8px; +} + +p>img:nth-of-type(odd) { + float: left; + margin-right: 12px; + margin-left: 0; +} + +p>img:nth-of-type(even) { + float: right; + margin-left: 12px; + margin-right: 0; +} + +p>img.block { + width: 780px; + max-width: 780px; + height: auto; + max-height: 100%; + display: block; + margin: 0px 0px 16px 0px; + clear: both; + float: none; }
\ No newline at end of file diff --git a/static/css/shared/core.css b/static/css/shared/core.css index 41924bbb..de275aa1 100755 --- a/static/css/shared/core.css +++ b/static/css/shared/core.css @@ -98,41 +98,6 @@ a:hover { text-decoration: underline; } -.link-button { - background: rgba(134, 99, 229, 0.2); - padding: 8px 16px; - border-radius: 4px; - color: #8d8dff; - text-decoration: none; - border: 1px solid #8d8dff; - transition: all 0.3s ease; - font-size: 12px; -} - -.link-button:hover { - background: rgba(223, 35, 196, 0.2); - border-color: #df23c4; - color: #df23c4; - text-decoration: none; - transform: translateY(-2px); -} - -.action-button { - padding: 4px 8px; - border-radius: 4px; - color: #8d8dff; - text-decoration: none; - font-size: 11px; - transition: all 0.2s ease; - background: rgba(141, 141, 255, 0.1); -} - -.action-button:hover { - color: #df23c4; - background: rgba(223, 35, 196, 0.1); - text-decoration: none; -} - textarea { resize: none; background: transparent; @@ -184,44 +149,6 @@ img { display: flex; } -/* SCANLINES */ -#scanlines { - position: fixed; - left: 0; - top: 0; - width: 100vw; - height: 100vh; - pointer-events: none; - z-index: 9; - opacity: 0.18; -} - -#scanlines:before { - content: ""; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - pointer-events: none; - background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, .4) 50%); - background-size: 100% 4px; - will-change: background, background-size; - animation: scanlines 0.2s linear infinite; -} - -@keyframes scanlines { - from { - background: linear-gradient(to bottom, transparent 10%, rgba(0, 0, 0, .4) 50%); - background-size: 100% 4px; - } - - to { - background: linear-gradient(to bottom, rgba(0, 0, 0, .4) 50%, transparent 50%); - background-size: 100% 4px; - } -} - /* Main Content */ #right-sidebar { @@ -447,4 +374,79 @@ html[lang='ja'] .navigation-title { /* Text Formatting */ .section-title { margin: 16px 0px; +} + + +/* SCANLINES */ +#scanlines { + position: fixed; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + pointer-events: none; + z-index: 9; + opacity: 0.18; +} + +#scanlines:before { + content: ""; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + pointer-events: none; + background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, .4) 50%); + background-size: 100% 4px; + will-change: background, background-size; + animation: scanlines 0.2s linear infinite; +} + +@keyframes scanlines { + from { + background: linear-gradient(to bottom, transparent 10%, rgba(0, 0, 0, .4) 50%); + background-size: 100% 4px; + } + + to { + background: linear-gradient(to bottom, rgba(0, 0, 0, .4) 50%, transparent 50%); + background-size: 100% 4px; + } +} + +/* Other Stuff */ +.link-button { + background: rgba(134, 99, 229, 0.2); + padding: 8px 16px; + border-radius: 4px; + color: #8d8dff; + text-decoration: none; + border: 1px solid #8d8dff; + transition: all 0.3s ease; + font-size: 12px; +} + +.link-button:hover { + background: rgba(223, 35, 196, 0.2); + border-color: #df23c4; + color: #df23c4; + text-decoration: none; + transform: translateY(-2px); +} + +.action-button { + padding: 4px 8px; + border-radius: 4px; + color: #8d8dff; + text-decoration: none; + font-size: 11px; + transition: all 0.2s ease; + background: rgba(141, 141, 255, 0.1); +} + +.action-button:hover { + color: #df23c4; + background: rgba(223, 35, 196, 0.1); + text-decoration: none; }
\ No newline at end of file diff --git a/static/images/core/messages/texts/navigation_en.png b/static/images/core/messages/texts/navigation_en.png Binary files differnew file mode 100644 index 00000000..18e9da18 --- /dev/null +++ b/static/images/core/messages/texts/navigation_en.png diff --git a/templates/partials/_comment.html b/templates/partials/_comment.html new file mode 100644 index 00000000..bc2d9580 --- /dev/null +++ b/templates/partials/_comment.html @@ -0,0 +1,59 @@ +<div class="comment-container" id="comment-{{ comment.id }}" style="margin-left: {% widthratio 24 1 comment.level %}px;"> + <div class="comment-header"> + {% if comment.user %} + <img src="{{ comment.user.avatar.url }}" alt="{{ comment.user.username }}"> + <span class="font-medium">{{ comment.user.username }}</span> + {% else %} + <img src="{{ comment.anonymous_user.avatar }}" alt="{{ comment.anonymous_user.name }}"> + <span class="font-medium">{{ comment.anonymous_user.name }}</span> + {% endif %} + <span>{{ comment.created_at|timesince }} ago</span> + {% if comment.edited %} + <span>(edited)</span> + {% endif %} + </div> + + <div> + <p>{{ comment.body }}</p> + </div> + + <div class="comment-actions"> + <button + onclick="showReplyForm('{{ comment.id }}')"> + Reply + </button> + {% if user == comment.user or is_admin %} + <button + onclick="showEditForm('{{ comment.id }}')"> + Edit + </button> + <button + onclick="deleteComment('{{ comment.id }}')"> + Delete + </button> + {% endif %} + </div> + + <!-- Reply form (hidden by default) --> + <div id="reply-form-{{ comment.id }}" style="display: none; margin-left: 24px;"> + <form method="POST" action="#" class="space-y-4"> + {% csrf_token %} + <input type="hidden" name="parent_id" value="{{ comment.id }}"> + <textarea name="body" rows="3" + placeholder="Write a reply..."></textarea> + <div class="flex justify-end gap-2"> + <button type="button" onclick="hideReplyForm('{{ comment.id }}')"> + Cancel + </button> + <button type="submit"> + Reply + </button> + </div> + </form> + </div> + + <!-- Nested replies --> + {% for reply in comment.replies.all %} + {% include 'partials/_comment.html' with comment=reply %} + {% endfor %} +</div>
\ No newline at end of file diff --git a/templates/partials/_weblog_list.html b/templates/partials/_weblog_list.html index d8a81dc7..a9b33462 100755 --- a/templates/partials/_weblog_list.html +++ b/templates/partials/_weblog_list.html @@ -5,11 +5,11 @@ <div class="post"> <div class="post-body"> <div class="post-image"> - <img src="{{ post.image_url }}" alt="{% if request.LANGUAGE_CODE == 'ja' %}{{ post.title_ja }}{% else %}{{ post.title }}{% endif %}"> + <img src="{{ post.image_url }}" alt="{{ post.title }}"> </div> <div class="post-content"> <h2> - <a href="{% url "weblog:single_post" post.slug %}">{% if request.LANGUAGE_CODE == 'ja' %}{{ post.title_ja }}{% else %}{{ post.title }}{% endif %}</a> + <a href="{% url "weblog:single_post" post.slug %}">{{ post.title }}</a> </h2> <div class="author-info"> {% with post.author.userprofile_set.first as authorprofile %} @@ -17,17 +17,19 @@ {% endwith %} <a href="#"> {{ post.author.first_name }} {{ post.author.last_name }}</a> <span>{% if request.LANGUAGE_CODE == 'ja' %}投稿カテゴリー:{% else %}posted in{% endif %}</span> - <a href="#{{ post.category.slug }}">{% if request.LANGUAGE_CODE == 'ja' %}{{ post.category.name_ja }}{% else %}{{ post.category.name }}{% endif %}</a> + <a href="#{{ post.category.slug }}">{{ post.category.name }}</a> <span>{% if request.LANGUAGE_CODE == 'ja' %}投稿日:{% else %}on{% endif %}</span> <span style="margin-left: 4px;">{% localtime on %}{{ post.date | date:"M d, Y" }}{% endlocaltime %}</span> </div> - {{ post.excerpt | safe }} + <div class="post-exerpt"> + {{ post.excerpt | safe }} + </div> </div> </div> <div class="post-actions"> <div class="post-links"> <a href="{% url "weblog:single_post" post.slug %}">{% if request.LANGUAGE_CODE == 'ja' %}続きを読む{% else %}Continue Reading{% endif %}</a> | - <a href="##comments">{{ post.comments.all|length }} + <a href="{% url "weblog:single_post" post.slug %}#comments">{{ post.comments.all|length }} {% if request.LANGUAGE_CODE == 'ja' %} コメント {% else %} @@ -36,7 +38,7 @@ </div> <div class="post-tags"> {% for tag in post.tags.all %} - <a class="post-tag" href="#{{ tag.slug }}">{% if request.LANGUAGE_CODE == 'ja' %}{{ tag.name_ja }}{% else %}{{ tag.name }}{% endif %}</a> + <a class="post-tag" href="#{{ tag.slug }}">{{ tag.name }}</a> {% endfor %} </div> </div> diff --git a/templates/shared/blog/single_weblog.html b/templates/shared/blog/single_weblog.html index 42180de0..4bffbd1f 100644 --- a/templates/shared/blog/single_weblog.html +++ b/templates/shared/blog/single_weblog.html @@ -2,7 +2,7 @@ {% load static %} {% load tz %} {% block title %} -<title>{% if request.LANGUAGE_CODE == 'ja' %}{{ post.title_ja }}{% else %}{{ post.title }}{% endif %}</title> +<title>{{ post.title }}</title> {% endblock title %} {% block head %} <link rel="stylesheet" href="{% static 'css/core/post_list.css' %}"> @@ -15,7 +15,7 @@ <div class="weblog-container"> <div class="weblog-title-area"> <h1> - {% if request.LANGUAGE_CODE == 'ja' %}{{ post.title_ja }}{% else %}{{ post.title }}{% endif %} + {{ post.title }} </h1> <div class="weblog-details"> <div class="author-info"> @@ -24,7 +24,7 @@ {% endwith %} <a href="#"> {{ post.author.first_name }} {{ post.author.last_name }}</a> <span>{% if request.LANGUAGE_CODE == 'ja' %}投稿カテゴリー:{% else %}posted in{% endif %}</span> - <a href="#{{ post.category.slug }}">{% if request.LANGUAGE_CODE == 'ja' %}{{ post.category.name_ja }}{% else %}{{ post.category }}{% endif %}</a> + <a href="#{{ post.category.slug }}">{{ post.category.name }}</a> <span>{% if request.LANGUAGE_CODE == 'ja' %}投稿日:{% else %}on{% endif %}</span> <span style="margin-left: 4px;">{% localtime on %}{{ post.date | date:"M d, Y" }}{% endlocaltime %}</span> </div> @@ -39,7 +39,7 @@ {{ post.first_paragraph | safe }} </div> <div class="weblog-image"> - <img src="{{ post.image_url }}" alt="{% if request.LANGUAGE_CODE == 'ja' %}{{ post.title_ja }}{% else %}{{ post.title }}{% endif %}"> + <img src="{{ post.image_url }}" alt="{{ post.title }}"> </div> <div class="weblog-content" id="weblog-body-content"> {{ post.body | safe }} @@ -48,10 +48,21 @@ <div class="post-tags"> {% if request.LANGUAGE_CODE == 'ja' %}タグ: {% else %}Tagged with: {% endif %} {% for tag in post.tags.all %} - <a class="post-tag" href="#{{ tag.slug }}">{% if request.LANGUAGE_CODE == 'ja' %}{{ tag.name_ja }}{% else %}{{ tag.name }}{% endif %}</a> + <a class="post-tag" href="#{{ tag.slug }}">{{ tag.name }}</a> {% endfor %} </div> </div> + <div class="comments-section" id="comments"> + <h2>{% if request.LANGUAGE_CODE == 'ja' %}コメント{% else %}Comments{% endif %}</h2> + {% for comment in post.comments.all %} + {% if not comment.parent %} + {% include 'partials/_comment.html' with comment=comment %} + {% endif %} + {% endfor %} + {% if post.comments.all|length == 0 %} + <p>{% if request.LANGUAGE_CODE == 'ja' %}コメントはありません。{% else %}No comments yet.{% endif %}</p> + {% endif %} + </div> </div> {% endblock content %} {% block scripts %} @@ -91,5 +102,13 @@ output: 'html' }); } + + function showReplyForm(commentId) { + document.getElementById(`reply-form-${commentId}`).style.display = 'block'; + } + + function hideReplyForm(commentId) { + document.getElementById(`reply-form-${commentId}`).style.display = 'none'; + } </script> {% endblock scripts %}
\ No newline at end of file |
