From b453706835fcb5fe960375c7101074f3bb9c1c7a Mon Sep 17 00:00:00 2001 From: Bobby Date: Sat, 21 Dec 2024 00:46:45 -0500 Subject: anime stream pages --- apps/anime/__init__.py | 0 apps/anime/admin.py | 3 + apps/anime/apps.py | 6 + apps/anime/migrations/__init__.py | 0 apps/anime/models.py | 3 + apps/anime/tests.py | 3 + apps/anime/urls.py | 10 + apps/anime/views.py | 210 ++++++++++++ apps/journals/urls.py | 1 + apps/journals/views.py | 15 +- static/css/anime/anime.css | 378 +++++++++++++++++++++ static/images/anime/title_background.png | Bin 0 -> 2313653 bytes static/js/shared/animeList.js | 45 +++ templates/en/anime/anime.html | 12 + templates/en/anime/home.html | 46 +++ templates/en/anime/search.html | 78 +++++ templates/en/journals/single.html | 41 ++- templates/partials/_anime_list.html | 62 ++++ templates/shared/left_sidebar.html | 4 +- thatcomputerscientist/settings.py | 2 +- thatcomputerscientist/templatetags/color_to_rgb.py | 21 ++ thatcomputerscientist/templatetags/pagination.py | 43 +++ thatcomputerscientist/urls.py | 1 + 23 files changed, 958 insertions(+), 26 deletions(-) create mode 100644 apps/anime/__init__.py create mode 100644 apps/anime/admin.py create mode 100644 apps/anime/apps.py create mode 100644 apps/anime/migrations/__init__.py create mode 100644 apps/anime/models.py create mode 100644 apps/anime/tests.py create mode 100644 apps/anime/urls.py create mode 100644 apps/anime/views.py create mode 100644 static/css/anime/anime.css create mode 100644 static/images/anime/title_background.png create mode 100644 static/js/shared/animeList.js create mode 100644 templates/en/anime/anime.html create mode 100644 templates/en/anime/home.html create mode 100644 templates/en/anime/search.html create mode 100644 templates/partials/_anime_list.html create mode 100644 thatcomputerscientist/templatetags/color_to_rgb.py create mode 100644 thatcomputerscientist/templatetags/pagination.py diff --git a/apps/anime/__init__.py b/apps/anime/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/anime/admin.py b/apps/anime/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/apps/anime/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/anime/apps.py b/apps/anime/apps.py new file mode 100644 index 00000000..9f6afd41 --- /dev/null +++ b/apps/anime/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AnimeConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.anime" diff --git a/apps/anime/migrations/__init__.py b/apps/anime/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/anime/models.py b/apps/anime/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/apps/anime/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/apps/anime/tests.py b/apps/anime/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/anime/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/anime/urls.py b/apps/anime/urls.py new file mode 100644 index 00000000..d9b7b810 --- /dev/null +++ b/apps/anime/urls.py @@ -0,0 +1,10 @@ +from django.urls import path, re_path + +from . import views + +app_name = "anime" +urlpatterns = [ + path("", views.home, name="home"), + path("search/", views.search, name="search"), + re_path(r"^(?P\d+)(?:\.(?P\d+))?/$", views.anime, name="anime"), +] diff --git a/apps/anime/views.py b/apps/anime/views.py new file mode 100644 index 00000000..6b976391 --- /dev/null +++ b/apps/anime/views.py @@ -0,0 +1,210 @@ +import os +from django.urls import reverse +import requests +from django.shortcuts import redirect, render + +from thatcomputerscientist.utils import i18npatterns + +genres = [ + "Action", + "Adventure", + "Cars", + "Comedy", + "Drama", + "Fantasy", + "Horror", + "Mahou Shoujo", + "Mecha", + "Music", + "Mystery", + "Psychological", + "Romance", + "Sci-Fi", + "Slice of Life", + "Sports", + "Supernatural", + "Thriller", +] + +sortings = [ + {"name": "Popularity", "value": "popularity"}, + {"name": "Trending", "value": "trending"}, + {"name": "Start Date", "value": "start_date"}, + {"name": "End Date", "value": "end_date"}, + {"name": "Score", "value": "score"}, + {"name": "Favourites", "value": "favourites"}, + {"name": "Title", "value": "title"}, +] + +ANIME_PROVIDER_MAP = {} + + +def get_anime(anime_id, dub=False): + if anime_id in ANIME_PROVIDER_MAP: + provider = ANIME_PROVIDER_MAP[anime_id] + else: + provider = "zoro" + + dub = "true" if dub else "false" + base_url = f"{os.getenv('CONSUMET_URL')}/meta/anilist/info/{anime_id}" + params = {"provider": provider, "dub": dub} + + response = requests.get(base_url, params=params) + data = response.json() + if ( + (not data.get("episodes") or len(data.get("episodes")) == 0) + and provider == "zoro" + and data.get("status") != "Not yet aired" + ): + ANIME_PROVIDER_MAP[anime_id] = "gogoanime" + return get_anime(anime_id) + else: + ANIME_PROVIDER_MAP[anime_id] = provider + return data + + +def sort_mapper(sort_by, order): + sort_mappings = { + "popularity": "POPULARITY", + "trending": "TRENDING", + "start_date": "START_DATE", + "end_date": "END_DATE", + "score": "SCORE", + "favourites": "FAVOURITES", + "title": "TITLE_ROMAJI", + } + + if sort_by not in sort_mappings or order not in ["asc", "desc"]: + return None + + sort_value = sort_mappings[sort_by] + order_suffix = "" if order == "asc" else "_DESC" + + return f"{sort_value}{order_suffix}" + + +def bracketed_string(string): + return f'["{string}"]' + + +def anime_results( + sort="trending", order="desc", genre="", query="", page=1, per_page=12, status="" +): + supported_status = [ + "releasing", + "not_yet_released", + "cancelled", + "finished", + "hiatus", + ] + + if status and status not in supported_status: + status = "" + + base_url = f"{os.getenv('CONSUMET_URL')}/meta/anilist/advanced-search" + params = {"page": page, "perPage": per_page, "type": "ANIME"} + + if query: + params["query"] = query + + if sort and order: + sort_value = sort_mapper(sort, order) + if sort_value: + params["sort"] = bracketed_string(sort_value) + + if genre: + params["genres"] = bracketed_string(genre) + + if status: + params["status"] = status.upper() + + response = requests.get(base_url, params=params) + return response.json() + + +def home(request): + META = { + "title": "Anime: Home", + } + LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE) + request.meta.update(META) + + context = { + "genres": genres, + "sortings": sortings, + "trending_anime": anime_results(sort="trending", per_page=8), + "popular_anime": anime_results(sort="popularity", per_page=8), + "top_anime": anime_results(sort="score", per_page=8), + "top_airing_anime": anime_results( + sort="popularity", status="releasing", per_page=8 + ), + } + + return render(request, f"{LANGUAGE_CODE}/anime/home.html", context) + + +def search(request): + # Get search parameters + query = request.GET.get("q", "") + genre = request.GET.get("genre", "") + sort = request.GET.get("sort", "popularity") + order = request.GET.get("order", "desc") + page = int(request.GET.get("page", 1)) + + META = { + "title": f"Anime: Search", + } + if query: + META["title"] = f"Anime: Search Results for {query}" + LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE) + request.meta.update(META) + + # Get search results + search_results = anime_results( + query=query, genre=genre, sort=sort, order=order, page=page, per_page=32 + ) + + context = { + "genres": genres, + "sortings": sortings, + "search_results": search_results, + "current_page": page, + "total_pages": search_results.get("totalPages", 1), + "total_results": search_results.get("totalResults", 0), + } + + return render(request, f"{LANGUAGE_CODE}/anime/search.html", context) + + +def anime(request, anime_id, e=None): + dub = request.COOKIES.get("anime_dub", False) + anime_data = get_anime(anime_id, dub) + + if len(anime_data.get("episodes")) > 0: + episode_numbers = [ + int(episode.get("number")) for episode in anime_data.get("episodes") + ] + + if not e: + e = episode_numbers[0] + return redirect( + reverse("anime:anime", kwargs={"anime_id": anime_id, "e": e}) + ) + + e = int(e) + if e not in episode_numbers: + return redirect( + reverse("anime:anime", kwargs={"anime_id": anime_id, "e": 1}) + ) + + META = { + "title": f"Anime: {anime_data.get('title').get('romaji')}", + } + LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE) + request.meta.update(META) + + context = { + "anime": anime_data, + } + + return render(request, f"{LANGUAGE_CODE}/anime/anime.html", context) diff --git a/apps/journals/urls.py b/apps/journals/urls.py index b4e7db01..bc7155c3 100644 --- a/apps/journals/urls.py +++ b/apps/journals/urls.py @@ -4,5 +4,6 @@ from . import views app_name = "journal" urlpatterns = [ + path("", views.journal_of_random_thoughts, name="journal_of_random_thoughts"), path("/", views.single_journal, name="single"), ] diff --git a/apps/journals/views.py b/apps/journals/views.py index 9c3f99f7..070c20b0 100644 --- a/apps/journals/views.py +++ b/apps/journals/views.py @@ -3,7 +3,20 @@ from apps.journals.models import Journal from thatcomputerscientist.utils import i18npatterns -# Create your views here. +def journal_of_random_thoughts(request): + META = { + "title": "Journal: Journal of Random Thoughts", + } + LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE) + request.meta.update(META) + slug = "journal-of-random-thoughts" + journal = Journal.objects.get(slug=slug) + context = { + "journal": journal, + } + return render(request, f"{LANGUAGE_CODE}/journals/single.html", context) + + def single_journal(request, slug): try: journal = Journal.objects.get(slug=slug) diff --git a/static/css/anime/anime.css b/static/css/anime/anime.css new file mode 100644 index 00000000..a68e0ee8 --- /dev/null +++ b/static/css/anime/anime.css @@ -0,0 +1,378 @@ +.anime-list-section { + margin: 20px 0; +} + +.anime-list-section .section-title { + font-size: 18px; + margin-bottom: 15px; + text-shadow: 0 0 10px rgba(126, 232, 199, 0.4); +} + +/* Anime Grid */ +.anime-grid { + width: 780px; + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 15px; +} + +.anime-grid a:hover { + text-decoration: none; +} + +/* Adjust card to maintain consistent height */ +.anime-card { + position: relative; + width: 180px; + display: flex; + flex-direction: column; + min-height: 326px; +} + +/* Poster container */ +.anime-poster { + width: 180px; + height: 256px; + overflow: hidden; + border-radius: 4px; + border: 1px solid rgba(141, 141, 255, 0.2); + box-shadow: 0 0 10px rgba(141, 141, 255, 0.1); + transition: all 0.2s ease; +} + +.anime-card:hover .anime-poster { + border-color: rgba(223, 35, 196, 0.4); + box-shadow: 0 0 15px rgba(223, 35, 196, 0.2); + transform: translateY(-2px); +} + +.anime-poster img { + width: 100%; + height: 100%; + object-fit: cover; + image-rendering: -webkit-optimize-contrast; +} + +.anime-basic-info { + padding: 10px 0; + min-height: 60px; + display: flex; + flex-direction: column; +} + +.anime-title { + font-size: 14px; + margin: 0 0 8px 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: var(--anime-color, #8d8dff); + text-shadow: 0 0 10px rgba(var(--anime-color-rgb, 141, 141, 255), 0.4); + transition: color 0.2s ease, text-shadow 0.2s ease; +} + +.anime-card:hover .anime-title { + filter: brightness(1.2); +} + +.anime-meta { + display: flex; + align-items: center; + gap: 8px; + font-size: 12px; + color: rgba(141, 141, 255, 0.8); + margin-top: auto; +} + +.anime-status { + padding: 2px 6px; + background: rgba(98, 55, 149, 0.3); + border: 1px solid rgba(141, 141, 255, 0.2); + border-radius: 2px; +} + +/* Hover card */ +.anime-hover-card { + position: fixed; + width: 400px; + background: rgba(13, 20, 28, 0.95); + border: 1px solid #8d8dff; + border-radius: 4px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); + opacity: 0; + visibility: hidden; + pointer-events: none; + z-index: 1000; + transition: opacity 0.15s ease; +} + +.hover-card-cover { + height: 150px; + position: relative; + overflow: hidden; +} + +.hover-card-cover img { + width: 100%; + height: 100%; + object-fit: cover; + opacity: 0.7; +} + +.hover-card-color { + width: 100%; + height: 100%; + opacity: 0.3; +} + +.hover-card-title-area { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 40px 15px 15px; + background: linear-gradient(to top, rgba(13, 20, 28, 0.9), rgba(13, 20, 28, 0.7) 50%, transparent); +} + +.hover-card-title-area h3 { + margin: 0; + font-size: 18px; + line-height: 1.4; + color: var(--anime-color, #8d8dff); + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), + 0 0 10px rgba(var(--anime-color-rgb, 141, 141, 255), 0.4); +} + +.hover-card-content { + padding: 15px; + display: grid; + grid-template-columns: 100px 1fr; + gap: 15px; +} + +.hover-card-poster { + width: 100px; + height: 142px; + border-radius: 4px; + overflow: hidden; + border: 1px solid #8d8dff; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.hover-card-poster img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.hover-card-details { + display: flex; + flex-direction: column; + gap: 15px; +} + +.hover-card-meta { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.hover-card-meta span { + padding: 2px 6px; + background: rgba(98, 55, 149, 0.3); + border: 1px solid rgba(141, 141, 255, 0.2); + border-radius: 2px; +} + +.hover-card-description { + font-size: 13px; + color: rgba(141, 141, 255, 0.8); + line-height: 1.5; +} + +.hover-card-genres { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.genre-tag { + font-size: 11px; + padding: 2px 6px; + background: rgba(173, 128, 236, 0.15); + border: 1px solid rgba(141, 141, 255, 0.2); + border-radius: 2px; + color: #8d8dff; +} + +/* Search form styles */ +.a-title-banner { + width: 780px; + height: 195px; + background: url(../../images/anime/title_background.png) no-repeat; + background-size: 780px 195px; + position: relative; + display: flex; + justify-content: center; + align-items: center; +} + +.overlay-bottom-radial { + position: absolute; + bottom: 0; + left: 0; + width: 780px; + height: 195px; + background: radial-gradient(ellipse 600px 195px at center bottom, rgba(13, 20, 28, 0.95) 0%, rgba(19, 26, 44, 0.8) 50%, transparent 100%); + z-index: 1; +} + +.a-title-banner-content { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; +} + +.a-title-banner-content h1 { + color: #7ee8c7; + text-shadow: 0 0 8px rgba(126, 232, 199, 0.4); + font-family: 'SweetFairy', sans-serif; +} + +.a-title-banner-content form { + display: flex; + gap: 8px; + align-items: center; + color: #7ee8c7; +} + +.a-title-banner-content form input, +.a-title-banner-content form select { + background: rgba(13, 20, 28, 0.85); + padding: 4px 8px; + border: solid 1px #8d8dff; + border-radius: 2px; + color: #7ee8c7; +} + +.a-title-banner-content form input:focus, +.a-title-banner-content form select:focus { + border-color: #df23c4; + outline: none; + box-shadow: 0 0 4px rgba(223, 35, 196, 0.2); +} + +.a-title-banner-content form button[type="submit"] { + background: rgba(68, 68, 177, 0.85); + padding: 5px 10px; + border: solid 1px #8d8dff; + border-radius: 2px; + color: #fff; + font-weight: 600; + cursor: pointer; +} + +.a-title-banner-content form button[type="submit"]:hover { + background: #df23c4; + border-color: #df23c4; + box-shadow: 0 0 8px rgba(223, 35, 196, 0.2); +} + +.order-toggle { + display: inline-flex; + background: rgba(13, 20, 28, 0.85); + border: 1px solid #8d8dff; + border-radius: 2px; + overflow: hidden; +} + +input[type="radio"][name="order"] { + display: none; +} + +input[type="radio"][name="order"]+label { + padding: 4px 8px; + cursor: pointer; + color: #7ee8c7; + border-right: 1px solid #8d8dff; +} + +input[type="radio"][name="order"]+label:last-of-type { + border-right: none; +} + +input[type="radio"][name="order"]:checked+label { + background: rgba(68, 68, 177, 0.85); + color: #7ee8c7; + box-shadow: inset 0 0 4px rgba(141, 141, 255, 0.2); +} + +input[type="radio"][name="order"]+label:hover { + background: rgba(223, 35, 196, 0.3); +} + +/* Search Results Info */ +.search-results-info { + margin: 20px 0; + padding: 10px; + background: rgba(13, 20, 28, 0.85); + border: 1px solid #8d8dff; + border-radius: 4px; +} + +.search-summary { + color: #7ee8c7; + font-size: 14px; +} + +.search-summary .result-count { + color: #df23c4; + font-weight: bold; +} + +.search-summary .search-term, +.search-summary .search-genre { + color: #8d8dff; + font-weight: bold; +} + +/* Pagination */ +.pagination { + margin: 20px 0; + display: flex; + justify-content: center; + align-items: center; + gap: 8px; +} + +.page-link { + padding: 6px 12px; + background: rgba(13, 20, 28, 0.85); + border: 1px solid #8d8dff; + border-radius: 4px; + color: #7ee8c7; + text-decoration: none; + transition: all 0.2s ease; +} + +.page-link:hover { + background: rgba(223, 35, 196, 0.2); + border-color: #df23c4; + color: #df23c4; + text-decoration: none; +} + +.page-link.active { + background: #8d8dff; + color: #000; + border-color: #8d8dff; +} + +.page-ellipsis { + color: #7ee8c7; + padding: 6px 12px; +} \ No newline at end of file diff --git a/static/images/anime/title_background.png b/static/images/anime/title_background.png new file mode 100644 index 00000000..da494a07 Binary files /dev/null and b/static/images/anime/title_background.png differ diff --git a/static/js/shared/animeList.js b/static/js/shared/animeList.js new file mode 100644 index 00000000..2d2526b0 --- /dev/null +++ b/static/js/shared/animeList.js @@ -0,0 +1,45 @@ +document.querySelectorAll('.anime-card').forEach(card => { + const hoverCard = card.querySelector('.anime-hover-card'); + + card.addEventListener('mouseenter', (e) => { + positionHoverCard(e, hoverCard); + hoverCard.style.opacity = '1'; + hoverCard.style.visibility = 'visible'; + }); + + card.addEventListener('mousemove', (e) => { + positionHoverCard(e, hoverCard); + }); + + card.addEventListener('mouseleave', () => { + hoverCard.style.opacity = '0'; + hoverCard.style.visibility = 'hidden'; + }); +}); + +function positionHoverCard(e, hoverCard) { + const mouseX = e.clientX; + const mouseY = e.clientY; + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + const cardWidth = 400; + const cardHeight = hoverCard.offsetHeight; + + // Calculate position, keeping card within viewport + let left = mouseX + 20; // 20px offset from cursor + let top = mouseY + 20; + + // Adjust if card would overflow right side + if (left + cardWidth > viewportWidth) { + left = mouseX - cardWidth - 20; + } + + // Adjust if card would overflow bottom + if (top + cardHeight > viewportHeight) { + top = mouseY - cardHeight - 20; + } + + // Apply position + hoverCard.style.left = `${left}px`; + hoverCard.style.top = `${top}px`; +} \ No newline at end of file diff --git a/templates/en/anime/anime.html b/templates/en/anime/anime.html new file mode 100644 index 00000000..c26a8f5c --- /dev/null +++ b/templates/en/anime/anime.html @@ -0,0 +1,12 @@ +{% extends 'shared/base.html' %} +{% load static %} +{% block head %} + +{% endblock head %} +{% block content %} +{{ anime }} + +{% endblock content %} + +{% block scripts %} +{% endblock scripts %} diff --git a/templates/en/anime/home.html b/templates/en/anime/home.html new file mode 100644 index 00000000..aba7c856 --- /dev/null +++ b/templates/en/anime/home.html @@ -0,0 +1,46 @@ +{% extends 'shared/base.html' %} +{% load static %} +{% block head %} + +{% endblock head %} +{% block content %} +
+
+
+

Anime

+
+ + + + + + +
+ + + + +
+ +
+
+
+{% include 'partials/_anime_list.html' with anime_list=trending_anime title="Trending Anime" %} +{% include 'partials/_anime_list.html' with anime_list=popular_anime title="Popular Anime" %} +{% include 'partials/_anime_list.html' with anime_list=top_anime title="Top Rated Anime" %} +{% include 'partials/_anime_list.html' with anime_list=top_airing_anime title="Top Airing Anime" %} + +{% endblock content %} + +{% block scripts %} + +{% endblock scripts %} diff --git a/templates/en/anime/search.html b/templates/en/anime/search.html new file mode 100644 index 00000000..7fcc5e90 --- /dev/null +++ b/templates/en/anime/search.html @@ -0,0 +1,78 @@ +{% extends 'shared/base.html' %} +{% load static %} +{% load pagination %} +{% block head %} + +{% endblock head %} + +{% block content %} +
+
+
+

Search Anime

+
+ + + + + + +
+ + + + +
+ +
+
+
+ +
+
+ Found {{ total_results }} results + {% if request.GET.q %} for "{{ request.GET.q }}"{% endif %} + {% if request.GET.genre %} in {{ request.GET.genre }}{% endif %} +
+
+ +{% include 'partials/_anime_list.html' with anime_list=search_results %} + +{% if total_pages > 1 %} + +{% endif %} + +{% endblock content %} +{% block scripts %} + +{% endblock scripts %} \ No newline at end of file diff --git a/templates/en/journals/single.html b/templates/en/journals/single.html index e538949f..084fea44 100644 --- a/templates/en/journals/single.html +++ b/templates/en/journals/single.html @@ -25,7 +25,17 @@ .journal-stats-area { background-color: #f4f1e90f; - border-radius: 8px; + padding: 8px 0px; + } + + .journal-stats-area:first-child { + border-top-left-radius: 8px; + border-top-right-radius: 8px; + } + + .journal-stats-area:last-child { + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; } .journal-stats-area h3 { @@ -36,7 +46,7 @@ .journal-stats-profile-image { width: 128px; height: 128px; - margin: 4px auto; + margin: 4px auto 8px auto; display: block; } @@ -56,11 +66,6 @@ font-weight: bold; } - .journal-stats:last-child { - border-bottom-left-radius: 8px; - border-bottom-right-radius: 8px; - } - .journal-entry { background-color: #f4f1e90f; border-radius: 8px; @@ -92,23 +97,21 @@
{% with journal.owner.userprofile_set.first as journal_holder_profile %} -

Journal Holder's Profile

{{ journal.owner.first_name }}'s Avatar
-

Profile

+

Author

{{ journal.owner.first_name }} {{ journal.owner.last_name }}

Bio

{{ journal_holder_profile.bio|linebreaksbr }}

+ {% endwith %} +
+
-

XP

-

{{ journal_holder_profile.experience }} / 1000

-
-
-

Level

-

{{ journal_holder_profile.level }}

+

Journal

+

{{ journal.name }}

Journal Entries

@@ -116,17 +119,11 @@

Journal Streak

-

{{ journal_holder_profile.journal_streak }} days

+

0 days

-
-

Weblog Posts

-

{{ journal_holder_profile.weblogs_created }}

-
- {% endwith %}
-

{{ journal.entries.all|length }} entries

{% for entry in journal.entries.all %}

{{ entry.title }}

diff --git a/templates/partials/_anime_list.html b/templates/partials/_anime_list.html new file mode 100644 index 00000000..c2530f34 --- /dev/null +++ b/templates/partials/_anime_list.html @@ -0,0 +1,62 @@ +{% load color_to_rgb %} + \ No newline at end of file diff --git a/templates/shared/left_sidebar.html b/templates/shared/left_sidebar.html index ee667db2..a0a546ca 100644 --- a/templates/shared/left_sidebar.html +++ b/templates/shared/left_sidebar.html @@ -63,7 +63,7 @@