diff options
| author | Bobby <[email protected]> | 2024-12-17 19:25:04 +0000 |
|---|---|---|
| committer | Bobby <[email protected]> | 2024-12-17 19:25:04 +0000 |
| commit | 79d44e676adeb998c3072b4a58d08815b45d4676 (patch) | |
| tree | 13dd865f0b809b0e77d5cfc491fa5909c1ea15c1 | |
| parent | a12bd485351559af96d019d55a4b0f8dbc1b7265 (diff) | |
| download | thatcomputerscientist-79d44e676adeb998c3072b4a58d08815b45d4676.tar.xz thatcomputerscientist-79d44e676adeb998c3072b4a58d08815b45d4676.zip | |
journal stuff
24 files changed, 340 insertions, 9 deletions
diff --git a/apps/core/urls.py b/apps/core/urls.py index db770dd0..3d64a60d 100644 --- a/apps/core/urls.py +++ b/apps/core/urls.py @@ -5,4 +5,6 @@ from . import views app_name = "core" urlpatterns = [ path("", views.home, name="home"), + # My Pages + path("my/journals/", views.my_journals, name="my_journals"), ] diff --git a/apps/core/views.py b/apps/core/views.py index 037f52c2..1790098a 100644 --- a/apps/core/views.py +++ b/apps/core/views.py @@ -1,6 +1,7 @@ from django.shortcuts import render from thatcomputerscientist.utils import i18npatterns from apps.administration.models import Announcement +from apps.journals.models import Journal from internal.mal_wrapper import get_mal_recent_activity from internal.weblog_utilities import recent_weblogs @@ -20,3 +21,17 @@ def home(request): "recent_weblogs": recent_weblogs(lang=LANGUAGE_CODE), } return render(request, f"{LANGUAGE_CODE}/core/home.html", context) + + +# My Pages +def my_journals(request): + META = { + "title": "My Journals", + } + LANGUAGE_CODE = i18npatterns(request.LANGUAGE_CODE) + request.META.update(META) + journals = Journal.objects.filter(owner=request.user).order_by("-created_at") + context = { + "journals": journals, + } + return render(request, f"{LANGUAGE_CODE}/core/my/journals.html", context) diff --git a/apps/journals/__init__.py b/apps/journals/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/apps/journals/__init__.py diff --git a/apps/journals/admin.py b/apps/journals/admin.py new file mode 100644 index 00000000..e619370d --- /dev/null +++ b/apps/journals/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +# Register your models here. +from apps.journals.models import Journal, JournalEntry + +admin.site.register(Journal) +admin.site.register(JournalEntry) diff --git a/apps/journals/apps.py b/apps/journals/apps.py new file mode 100644 index 00000000..6b3c8ae9 --- /dev/null +++ b/apps/journals/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class JournalsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.journals" diff --git a/apps/journals/migrations/0001_initial.py b/apps/journals/migrations/0001_initial.py new file mode 100644 index 00000000..485a5314 --- /dev/null +++ b/apps/journals/migrations/0001_initial.py @@ -0,0 +1,78 @@ +# Generated by Django 5.1.4 on 2024-12-17 17:38 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="Journal", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=128)), + ("description", models.TextField(blank=True)), + ("private", models.BooleanField(default=False)), + ("custom_css", models.TextField(blank=True)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "shared_with", + models.ManyToManyField( + blank=True, + related_name="shared_journals", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.CreateModel( + name="JournalEntry", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=128)), + ("body", models.TextField()), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "journal", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="entries", + to="journals.journal", + ), + ), + ], + ), + ] diff --git a/apps/journals/migrations/0002_journal_slug.py b/apps/journals/migrations/0002_journal_slug.py new file mode 100644 index 00000000..67082c3c --- /dev/null +++ b/apps/journals/migrations/0002_journal_slug.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.4 on 2024-12-17 18:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("journals", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="journal", + name="slug", + field=models.SlugField(default="", max_length=256, unique=True), + preserve_default=False, + ), + ] diff --git a/apps/journals/migrations/__init__.py b/apps/journals/migrations/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/apps/journals/migrations/__init__.py diff --git a/apps/journals/models.py b/apps/journals/models.py new file mode 100644 index 00000000..96214d56 --- /dev/null +++ b/apps/journals/models.py @@ -0,0 +1,39 @@ +from django.db import models +from django.conf import settings + + +class Journal(models.Model): + owner = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ) + name = models.CharField(max_length=128) + slug = models.SlugField(max_length=256, unique=True) + description = models.TextField(blank=True) + private = models.BooleanField(default=False) + shared_with = models.ManyToManyField( + settings.AUTH_USER_MODEL, + related_name="shared_journals", + blank=True, + ) + custom_css = models.TextField(blank=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name + + +class JournalEntry(models.Model): + journal = models.ForeignKey( + Journal, + on_delete=models.CASCADE, + related_name="entries", + ) + title = models.CharField(max_length=128) + body = models.TextField() + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.title diff --git a/apps/journals/tests.py b/apps/journals/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/apps/journals/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/journals/urls.py b/apps/journals/urls.py new file mode 100644 index 00000000..1f7413c2 --- /dev/null +++ b/apps/journals/urls.py @@ -0,0 +1,6 @@ +from django.urls import path + +from . import views + +app_name = "journal" +urlpatterns = [] diff --git a/apps/journals/views.py b/apps/journals/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/apps/journals/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/middleware/globalmetamiddleware.py b/middleware/globalmetamiddleware.py index 1a9a1d6b..f5e00555 100644 --- a/middleware/globalmetamiddleware.py +++ b/middleware/globalmetamiddleware.py @@ -8,7 +8,7 @@ class GlobalMetaMiddleware: def __call__(self, request): request.meta = { # Default General Meta Tags - "title": "Shifoo", + "title": "Home", "description": "Welcome to the home of Shifoo. This is my personal website where I share all of my thoughts, ideas, and experiences.", "image": "https://shi.foo/static/images/favicons/android-chrome-512x512.png", "url": "{}://{}{}".format(request.scheme, request.get_host(), request.path), diff --git a/static/css/shared/core.css b/static/css/shared/core.css index ac629b03..c02be71e 100644 --- a/static/css/shared/core.css +++ b/static/css/shared/core.css @@ -99,6 +99,41 @@ 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; @@ -143,6 +178,7 @@ img { z-index: 1; width: 1200px; margin: 0 auto; + right: 10px; } #content-wrapper { diff --git a/static/css/shared/login-area.css b/static/css/shared/login-area.css index 47cee42d..3ea863fb 100644 --- a/static/css/shared/login-area.css +++ b/static/css/shared/login-area.css @@ -60,8 +60,8 @@ #login-error>.messageBox { position: absolute; - top: -88px; - left: -120px; + top: -120px; + right: 48px; z-index: 2; width: 200px; height: 132px; diff --git a/templates/en/core/my/journals.html b/templates/en/core/my/journals.html new file mode 100644 index 00000000..a3be14bb --- /dev/null +++ b/templates/en/core/my/journals.html @@ -0,0 +1,88 @@ +{% extends 'shared/base.html' %} +{% load static %} +{% block head %} +<style> + .my-journals { + padding: 12px 0px; + } + + .my-journals-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; + padding-bottom: 12px; + border-bottom: 2px solid #8d8dff; + } + + .journal-list { + background: rgba(0, 0, 0, 0.3); + border-radius: 8px; + overflow: hidden; + } + + .journal-list-header, .journal-list-item { + display: grid; + grid-template-columns: 2fr 1fr 1fr 1fr; + padding: 12px; + } + + .journal-list-header { + background: linear-gradient(90deg, #4444b1, #623795); + border-bottom: 1px solid #8d8dff; + } + + + .journal-list-header-title { + font-weight: 600; + text-align: center; + } + + .journal-list-item { + border-bottom: 1px solid rgba(141, 141, 255, 0.2); + background: rgba(98, 55, 149, 0.1); + transition: background 0.3s ease; + } + + .journal-list-item:nth-child(odd) { + background: rgba(68, 68, 177, 0.1); + } + + .journal-alignment-left { + justify-content: flex-start !important; + } + + .journal-alignment-center { + display: flex; + justify-content: center !important; + gap: 8px; + } +</style> +{% endblock head %} +{% block content %} +<div class="my-journals"> + <div class="my-journals-header"> + <h1 class="navigation-title" style="font-size: 24px;">My Journals</h1> + <a href="#create" class="link-button">Create a Journal</a> + </div> + <div class="journal-list"> + <div class="journal-list-header"> + <div class="journal-list-header-title">Title</div> + <div class="journal-list-header-title">Private</div> + <div class="journal-list-header-title">Entries</div> + <div class="journal-list-header-title">Actions</div> + </div> + {% for journal in journals %} + <div class="journal-list-item"> + <div class="journal-alignment-left">{{ journal.name }}</div> + <div class="journal-alignment-center">{{ journal.private }}</div> + <div class="journal-alignment-center">{{ journal.entries.all|length }}</div> + <div class="journal-alignment-center"> + <a href="#view" class="action-button">View</a> + <a href="#manage" class="action-button">Manage</a> + </div> + </div> + {% endfor %} + </div> +</div> +{% endblock content %} diff --git a/templates/en/pagoda/home.html b/templates/en/pagoda/home.html index d5910d11..306dfe44 100644 --- a/templates/en/pagoda/home.html +++ b/templates/en/pagoda/home.html @@ -125,7 +125,7 @@ future, so stay tuned for more updates. If you have any questions or feedback, please feel free to contact me. I hope you enjoy using The Pagoda Realm!</p> <p>Thank you for using The Pagoda Realm!</p> - <button onclick="document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">I Understand What I Must Do!</button> + <button onclick="window.scrollTo(0, 0); document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">I Understand What I Must Do!</button> </div> {% else %} {% if not pagoda_sites %} diff --git a/templates/en/pagoda/site_dashboard.html b/templates/en/pagoda/site_dashboard.html index e69de29b..a4344c26 100644 --- a/templates/en/pagoda/site_dashboard.html +++ b/templates/en/pagoda/site_dashboard.html @@ -0,0 +1,7 @@ +{% extends 'shared/base.html' %} +{% load static %} +{% block head %} +{% endblock head %} +{% block content %} +Site Dashboard +{% endblock content %}
\ No newline at end of file diff --git a/templates/en/pagoda/site_verification.html b/templates/en/pagoda/site_verification.html index 9d5e1aad..dd5e661d 100644 --- a/templates/en/pagoda/site_verification.html +++ b/templates/en/pagoda/site_verification.html @@ -160,6 +160,16 @@ <p>Once you've added the details, click the button below to check the verification status.</p> <button class="verify-button" onclick="window.location.href = '{% url 'pagoda:site_status' site.siteUniqueIdentifier %}'">Check Verification Status</button> - <button class="delete-button" onclick="window.location.href = '{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}'">Delete Site</button> + <button class="delete-button" onclick="javascript:deleteSite();">Delete Site</button> </div> {% endblock %} +{% block scripts %} +<script type="text/javascript"> + function deleteSite() { + if (confirm("Are you sure you want to remove this connected website? This action is permanent and cannot be undone.")) { + const deletionURL = "{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}"; + window.location.href = deletionURL; + } + } +</script> +{% endblock scripts %} diff --git a/templates/ja/pagoda/home.html b/templates/ja/pagoda/home.html index 48e2e0a3..e3388994 100644 --- a/templates/ja/pagoda/home.html +++ b/templates/ja/pagoda/home.html @@ -86,7 +86,7 @@ </ul> <p>これらは、The Pagoda Realmで利用できるサービスの一部にすぎません。今後さらにサービスを追加していく予定なので、アップデートをお楽しみに!質問やフィードバックがありましたら、お気軽にご連絡ください。The Pagoda Realmをお楽しみください!</p> <p>The Pagoda Realmをご利用いただき、ありがとうございます!</p> - <button onclick="document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">理解しました!</button> + <button onclick="window.scrollTo(0, 0); document.cookie = 'visitedPagodaRealm=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; window.location.reload();">理解しました!</button> </div> {% else %} {% if not pagoda_sites %} diff --git a/templates/ja/pagoda/site_verification.html b/templates/ja/pagoda/site_verification.html index a92c167e..789b8372 100644 --- a/templates/ja/pagoda/site_verification.html +++ b/templates/ja/pagoda/site_verification.html @@ -160,6 +160,16 @@ <p>情報を追加したら、下のボタンをクリックして認証状態を確認してください。</p> <button class="verify-button" onclick="window.location.href = '{% url 'pagoda:site_status' site.siteUniqueIdentifier %}'">認証状態を確認</button> - <button class="delete-button" onclick="window.location.href = '{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}'">サイトを削除</button> + <button class="delete-button" onclick="javascript:deleteSite();'">サイトを削除</button> </div> -{% endblock %}
\ No newline at end of file +{% endblock %} +{% block scripts %} +<script type="text/javascript"> + function deleteSite() { + if (confirm("Are you sure you want to remove this connected website? This action is permanent and cannot be undone.")) { + const deletionURL = "{% url 'pagoda:delete_site' site.siteUniqueIdentifier %}"; + window.location.href = deletionURL; + } + } +</script> +{% endblock scripts %}
\ No newline at end of file diff --git a/templates/shared/left_sidebar.html b/templates/shared/left_sidebar.html index 5815b373..ee667db2 100644 --- a/templates/shared/left_sidebar.html +++ b/templates/shared/left_sidebar.html @@ -34,7 +34,7 @@ <div class="user-items-container"> <div class="user-item"> <img src="{% static 'images/core/icons/journals.png' %}" alt="Journals Icon" /> - <a href="#journals">{% if request.LANGUAGE_CODE == 'ja' %}ジャーナル{% else %}Journals{% endif %}</a> + <a href="{% url "core:my_journals" %}">{% if request.LANGUAGE_CODE == 'ja' %}ジャーナル{% else %}Journals{% endif %}</a> </div> <div class="user-item"> <img src="{% static 'images/core/icons/pagodarealm.png' %}" alt="The Pagoda Realm Icon" /> diff --git a/thatcomputerscientist/settings.py b/thatcomputerscientist/settings.py index 43b069ec..a2f3b817 100644 --- a/thatcomputerscientist/settings.py +++ b/thatcomputerscientist/settings.py @@ -80,6 +80,7 @@ INSTALLED_APPS = [ "apps.administration", "apps.blog", "apps.pagoda", + "apps.journals", "services.users", "services.stream", "services.pamphlet", diff --git a/thatcomputerscientist/urls.py b/thatcomputerscientist/urls.py index 76f41dbe..97d51fcf 100644 --- a/thatcomputerscientist/urls.py +++ b/thatcomputerscientist/urls.py @@ -41,6 +41,7 @@ handler404 = "thatcomputerscientist.error_handler.custom_404" urlpatterns = [ path("", include("apps.core.urls", namespace="core")), + path("journal/", include("apps.journals.urls", namespace="journal")), path("weblog/", include("apps.blog.urls", namespace="weblog")), path("pagoda/", include("apps.pagoda.urls", namespace="pagoda")), path("services/stream/", include("services.stream.urls", namespace="stream")), |
