diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38eb6827f..c7e4ae59e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ A summary of changes made to the codebase, grouped per deployment.
### New features
+- Added a MAKE lore wiki where MAKE members can write and edit articles about anything lore in the MAKE universe
- The apply button in the English header, which previously read "søk verv", has now been translated to English ("apply to MAKE")
### Improvements
diff --git a/src/internal/admin.py b/src/internal/admin.py
index ef5c45fcf..7a4951d4d 100644
--- a/src/internal/admin.py
+++ b/src/internal/admin.py
@@ -5,7 +5,7 @@
from util import html_utils
from util.admin_utils import DefaultAdminWidgetsMixin, UserSearchFieldsMixin, search_escaped_and_unescaped
-from .models import Member, Quote, Secret, SystemAccess
+from .models import Lore, Member, Quote, Secret, SystemAccess
class MemberAdmin(DefaultAdminWidgetsMixin, SimpleHistoryAdmin):
@@ -93,7 +93,13 @@ class QuoteAdmin(DefaultAdminWidgetsMixin, UserSearchFieldsMixin, admin.ModelAdm
autocomplete_fields = ('author',)
+class LoreAdmin(admin.ModelAdmin):
+ ordering = ('title',)
+ exclude = ('slug',)
+
+
admin.site.register(Member, MemberAdmin)
admin.site.register(SystemAccess, SystemAccessAdmin)
admin.site.register(Secret, SecretAdmin)
admin.site.register(Quote, QuoteAdmin)
+admin.site.register(Lore, LoreAdmin)
diff --git a/src/internal/forms.py b/src/internal/forms.py
index 8918a8528..9bd1889db 100644
--- a/src/internal/forms.py
+++ b/src/internal/forms.py
@@ -1,12 +1,14 @@
from django import forms
from django.db import models
+from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from card import utils as card_utils
from card.formfields import CardNumberField
+from ckeditor.widgets import CKEditorWidget
from users.models import User
from web.widgets import SemanticDateInput, SemanticMultipleSelectInput, SemanticSearchableChoiceInput
-from .models import Member, Quote, Secret, SystemAccess
+from .models import Lore, Member, Quote, Secret, SystemAccess
class AddMemberForm(forms.ModelForm):
@@ -176,3 +178,35 @@ class Meta:
widgets = {
'date': SemanticDateInput(),
}
+
+
+class LoreForm(forms.ModelForm):
+ class Meta:
+ model = Lore
+ fields = ('title', 'content')
+ widgets = {
+ 'text': CKEditorWidget()
+ }
+
+ def clean(self):
+ cleaned_data = self.cleaned_data
+ title = cleaned_data.get('title')
+ title = title.replace('ø', 'o')
+ title = title.replace('æ', 'ae')
+ slug = slugify(title)
+ try:
+ article = self.instance
+ except NameError:
+ article = None
+ if article:
+ if (article.slug != slug) and (Lore.objects.filter(slug=slug).exists()):
+ self.add_error('title', _("An article with this title already exists. Please merge your text with the existing one!"))
+ elif slug == '':
+ self.add_error('title', _("Please make a title consisting of actual letters!"))
+ elif not article:
+ if Lore.objects.filter(slug=slug).exists():
+ self.add_error('title', _("An article with this title already exists. Please merge your text with the existing one!"))
+ elif slug == '':
+ self.add_error('title', _("Please make a title consisting of actual letters!"))
+ else:
+ return cleaned_data
diff --git a/src/internal/migrations/0027_lore.py b/src/internal/migrations/0027_lore.py
new file mode 100644
index 000000000..8d642fe26
--- /dev/null
+++ b/src/internal/migrations/0027_lore.py
@@ -0,0 +1,27 @@
+# Generated by Django 4.1.7 on 2023-11-17 16:00
+
+import ckeditor_uploader.fields
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('internal', '0026_add_secret_permissions'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Lore',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=200, unique=True, verbose_name='title')),
+ ('slug', models.SlugField(unique=True)),
+ ('content', ckeditor_uploader.fields.RichTextUploadingField(max_length=150000, verbose_name='text')),
+ ],
+ options={
+ 'verbose_name': 'lore article',
+ 'verbose_name_plural': 'lore articles',
+ },
+ ),
+ ]
diff --git a/src/internal/models.py b/src/internal/models.py
index 02afa34cd..348504f0d 100644
--- a/src/internal/models.py
+++ b/src/internal/models.py
@@ -5,7 +5,7 @@
from django.db.models import F
from django.db.models.functions import Lower
from django.utils import timezone
-from django.utils.text import capfirst
+from django.utils.text import capfirst, slugify
from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber
@@ -314,3 +314,24 @@ class Meta:
def __str__(self):
return _("“{quote}” —{quoted}").format(quote=self.quote, quoted=self.quoted)
+
+
+class Lore(models.Model):
+ title = models.CharField(max_length=200, unique=True, verbose_name=_("title"))
+ slug = models.SlugField(unique=True)
+ content = RichTextUploadingField(max_length=150000, verbose_name=_("text"))
+
+ def __str__(self):
+ return self.title
+
+ def save(self, *args, **kwargs):
+ title = self.title
+ self.title = capfirst(title)
+ title = title.replace('ø', 'o')
+ title = title.replace('æ', 'ae')
+ self.slug = slugify(title)
+ super().save(*args, **kwargs)
+
+ class Meta:
+ verbose_name = _("lore article")
+ verbose_name_plural = _("lore articles")
diff --git a/src/internal/static/internal/css/lore_list.css b/src/internal/static/internal/css/lore_list.css
new file mode 100644
index 000000000..b8d4baba8
--- /dev/null
+++ b/src/internal/static/internal/css/lore_list.css
@@ -0,0 +1,159 @@
+#lore-page {
+ position: relative;
+ max-width: 100vw;
+}
+
+#lore-wiki-list {
+ float: left;
+ width: 20%;
+ padding: 3rem 0 40px 40px;
+ position: relative;
+}
+
+.lore-article-links a {
+ color: black;
+}
+
+ul.lore-article-links {
+ list-style-type: none;
+ list-style-position: inside;
+ padding: 0;
+}
+
+.lore-article-links .selected-lore-article {
+ font-weight: bold;
+}
+
+#lore-article {
+ float: left;
+ width: 80%;
+ padding: 3rem 25% 0 5%;
+ position: relative;
+}
+
+#lore-article p {
+ text-align: justify;
+}
+
+.lore-container img {
+ margin: 20px 30px;
+}
+
+#lore-article .lore-container {
+ margin-bottom: 70px;
+}
+
+#lore-wiki-list .plus.icon {
+ font-size: 90%;
+}
+
+#lore-burger-icon + h2 .plus.icon {
+ font-size: 80%;
+}
+
+#lore-article .trash.icon,
+#lore-article .pencil.icon {
+ font-size: 120%;
+}
+
+#lore-article .lore-heading {
+ display: block;
+ max-width: 100vw;
+}
+
+/* The burger menu used on the lore page is loosely based on https://alvarotrigo.com/blog/hamburger-menu-css-responsive/ */
+
+#burger-input {
+ display: none;
+}
+
+#lore-burger-icon {
+ display: none;
+ width: 15px;
+ height: 15px;
+ cursor: pointer;
+ border: none;
+ margin-top:6px;
+ background: linear-gradient(
+ to bottom,
+ black, black 20%,
+ white 20%, white 40%,
+ black 40%, black 60%,
+ white 60%, white 80%,
+ black 80%, black 100%
+ );
+ position: absolute;
+ top: 3rem;
+ left: 15%;
+}
+
+#lore-burger-icon + h2 {
+ position: absolute;
+ top: 3rem;
+ left: 15%;
+ margin: 0 0 0 30px;
+ display: none;
+}
+
+#lore-burger-menu {
+ display: none;
+ max-width: 100vw;
+ padding: 6rem 15% 0 15%;
+}
+
+@media screen and (max-width: 992px) {
+
+ #lore-burger-icon {
+ display: inline;
+ }
+
+ #lore-burger-icon + h2 {
+ display: block;
+ }
+
+ #burger-input:not(:checked) ~ #lore-article {
+ position: absolute;
+ top: 6rem;
+ }
+
+ #burger-input:checked + #lore-burger-icon {
+ clip-path: polygon(15% 0%, 0% 15%, 35% 50%, 0% 85%, 15% 100%, 50% 65%, 85% 100%, 100% 85%, 65% 50%, 100% 15%, 85% 0%, 50% 35%);
+ background: black;
+ }
+
+ #burger-input:checked + #lore-burger-icon ~ #lore-burger-menu {
+ display: block;
+ top: 6rem;
+ }
+
+ #lore-wiki-list {
+ display: none;
+ float: none;
+ max-width: 100vw;
+ padding: 2rem 15% 0 15%;
+ }
+
+ #lore-article {
+ float: none;
+ width: 100vw;
+ padding: 3rem 15% 2rem 15%;
+ position: relative;
+ }
+}
+
+@media screen and (max-width: 450px) {
+
+ #lore-article {
+ float: none;
+ width: 100%;
+ padding: 3rem 15% 2rem 15%;
+ position: relative;
+ }
+
+ .lore-container img {
+ float: none;
+ width: 100%;
+ height: unset;
+ margin: 10px 0;
+ }
+}
diff --git a/src/internal/static/internal/js/lore_list.js b/src/internal/static/internal/js/lore_list.js
new file mode 100644
index 000000000..19bf7ed3b
--- /dev/null
+++ b/src/internal/static/internal/js/lore_list.js
@@ -0,0 +1,10 @@
+$(document).ready(function() {
+ $('img').each(function() {
+ if ($(this).css('float') === 'left') {
+ $(this).css('margin-left', '0');
+ }
+ if ($(this).css('float') === 'right') {
+ $(this).css('margin-right', '0');
+ }
+ });
+});
diff --git a/src/internal/templates/internal/header.html b/src/internal/templates/internal/header.html
index bcf274d8d..c278ca7b2 100644
--- a/src/internal/templates/internal/header.html
+++ b/src/internal/templates/internal/header.html
@@ -20,6 +20,10 @@
{% translate "Quotes" %}
+
+ {% translate "MAKE Lore" %}
+
+
{% translate "Misc." %}
diff --git a/src/internal/templates/internal/lore/lore_list.html b/src/internal/templates/internal/lore/lore_list.html
new file mode 100644
index 000000000..4ca69d05d
--- /dev/null
+++ b/src/internal/templates/internal/lore/lore_list.html
@@ -0,0 +1,66 @@
+{% extends 'internal/base.html' %}
+{% load i18n %}
+{% load static %}
+
+
+{% block title %}
+ {% translate "The wiki of MAKE lore" %}
+{% endblock title %}
+
+{% block extra_head %}
+
+
+{% endblock extra_head %}
+
+{% block body %}
+
+
+
{% translate "Topics" %}
+ {% if perms.internal.add_lore %}
+
+
+
+ {% endif %}
+
+ {% include 'internal/lore/lore_list__article_links.html' %}
+
+
+ {# Checkbox belongs to hamburger menu. Checkbox status decides if hamburger menu will be shown or not #}
+
+
+
{% translate "Topics" %}
+ {% if perms.internal.add_lore %}
+
+
+
+ {% endif %}
+
+
+
+
+ {% if show_article %}
+
{{ shown_lore_article.title|capfirst }}
+ {% if perms.internal.delete_lore and shown_lore_article.title != "Dev" %}
+
+
+
+ {% endif %}
+ {% if perms.internal.change_lore and shown_lore_article.title != "Dev" %}
+
+
+
+ {% endif %}
+
+
{{ shown_lore_article.content|safe }}
+
+ {% else %}
+
{% translate "Welcome to the wiki of MAKE lore" %}
+
{% translate "Click a topic in the menu to access a wiki article" %}
+ {% endif %}
+
+
+{% endblock body %}
diff --git a/src/internal/templates/internal/lore/lore_list__article_links.html b/src/internal/templates/internal/lore/lore_list__article_links.html
new file mode 100644
index 000000000..c0dfad984
--- /dev/null
+++ b/src/internal/templates/internal/lore/lore_list__article_links.html
@@ -0,0 +1,16 @@
+{% load i18n %}
+
+
+
+ {% for lore_article in all_lore_articles %}
+ -
+
+ {{ lore_article.title|capfirst }}
+
+
+ {% endfor %}
+
diff --git a/src/internal/urls.py b/src/internal/urls.py
index 33fc36665..7ab4c35fc 100644
--- a/src/internal/urls.py
+++ b/src/internal/urls.py
@@ -72,6 +72,17 @@
path("
/", include(specific_quote_urlpatterns)),
]
+specific_lore_urlpatterns = [
+ path("", views.LoreDetailView.as_view(), name='lore_detail'),
+ path("change/", views.LoreUpdateView.as_view(), name='lore_update'),
+ path("delete/", views.LoreDeleteView.as_view(), name='lore_delete'),
+]
+lore_urlpatterns = [
+ path("", views.LoreListView.as_view(), name='lore_list'),
+ path("add/", views.LoreCreateView.as_view(), name='lore_create'),
+ path("/", include(specific_lore_urlpatterns)),
+]
+
internal_urlpatterns = [
path("", views.HomeView.as_view(url_name='home'), name='home'),
path("bulletins/", include(committee_bulletin_urlpatterns)),
@@ -82,6 +93,7 @@
path("members/", decorator_include(permission_required_else_denied('internal.view_member'), member_urlpatterns)),
path("secrets/", decorator_include(permission_required_else_denied('internal.view_secret'), secret_urlpatterns)),
path("quotes/", decorator_include(permission_required_else_denied('internal.view_quote'), quote_urlpatterns)),
+ path("lore/", decorator_include(permission_required_else_denied('internal.view_lore'), lore_urlpatterns)),
]
urlpatterns += i18n_patterns(
diff --git a/src/internal/views.py b/src/internal/views.py
index d846bb07e..317820651 100644
--- a/src/internal/views.py
+++ b/src/internal/views.py
@@ -7,8 +7,9 @@
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
from django.utils import timezone
+from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
-from django.views.generic import CreateView, DeleteView, ListView, UpdateView
+from django.views.generic import CreateView, DeleteView, ListView, UpdateView, DetailView
from django.views.generic.detail import SingleObjectMixin
from contentbox.views import ContentBoxDetailView, ContentBoxUpdateView
@@ -16,9 +17,9 @@
from util.view_utils import CustomFieldsetFormMixin, PreventGetRequestsMixin
from .forms import (
AddMemberForm, ChangeMemberForm, MemberQuitForm, MemberRetireForm, MemberStatusForm, QuoteForm, RestrictedChangeMemberForm, SecretsForm,
- SystemAccessValueForm,
+ SystemAccessValueForm, LoreForm
)
-from .models import Member, Quote, Secret, SystemAccess
+from .models import Member, Quote, Secret, SystemAccess, Lore
class InternalContentBoxDetailView(ContentBoxDetailView):
@@ -332,3 +333,74 @@ def has_permission(self):
self.request.user.has_perm('internal.delete_quote')
or self.request.user == self.get_object().author
)
+
+
+class LoreListView(ListView):
+ model = Lore
+ ordering = ['title']
+ template_name = 'internal/lore/lore_list.html'
+ context_object_name = 'all_lore_articles'
+ extra_context = {
+ 'show_article': False,
+ }
+
+
+class LoreDetailView(DetailView):
+ model = Lore
+ template_name = 'internal/lore/lore_list.html'
+ context_object_name = 'shown_lore_article'
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['show_article'] = True
+ context['all_lore_articles'] = Lore.objects.order_by('title')
+ return context
+
+
+class LoreFormMixin(CustomFieldsetFormMixin, ABC):
+ model = Lore
+ form_class = LoreForm
+
+ base_template = 'internal/base.html'
+ back_button_link = reverse_lazy('lore_list')
+ back_button_text = _("Lore Wiki")
+
+
+class LoreCreateView(PermissionRequiredMixin, LoreFormMixin, CreateView):
+ permission_required = ('internal.add_lore',)
+
+ form_title = _("Add Lore Article")
+
+ def get_success_url(self):
+ title = str(self.object)
+ title = title.replace('ø', 'o')
+ title = title.replace('æ', 'ae')
+ slug = slugify(title)
+ return reverse_lazy('lore_detail', args=[slug])
+
+
+class LoreUpdateView(PermissionRequiredMixin, LoreFormMixin, UpdateView):
+ permission_required = ('internal.change_lore',)
+
+ form_title = _("Change Lore Article")
+ back_button_text = _("Lore Article")
+
+ def get_back_button_link(self):
+ title = str(self.get_form_kwargs()['instance'])
+ title = title.replace('ø', 'o')
+ title = title.replace('æ', 'ae')
+ slug = slugify(title)
+ return reverse_lazy('lore_detail', args=[slug])
+
+ def get_success_url(self):
+ title = str(self.object)
+ title = title.replace('ø', 'o')
+ title = title.replace('æ', 'ae')
+ slug = slugify(title)
+ return reverse_lazy('lore_detail', args=[slug])
+
+
+class LoreDeleteView(PermissionRequiredMixin, PreventGetRequestsMixin, DeleteView):
+ permission_required = ('internal.delete_lore',)
+ model = Lore
+ success_url = reverse_lazy('lore_list')
diff --git a/src/locale/nb/LC_MESSAGES/django.mo b/src/locale/nb/LC_MESSAGES/django.mo
index c098d9c25..d835462c7 100644
Binary files a/src/locale/nb/LC_MESSAGES/django.mo and b/src/locale/nb/LC_MESSAGES/django.mo differ
diff --git a/src/locale/nb/LC_MESSAGES/django.po b/src/locale/nb/LC_MESSAGES/django.po
index 0b706b015..424f53eb5 100644
--- a/src/locale/nb/LC_MESSAGES/django.po
+++ b/src/locale/nb/LC_MESSAGES/django.po
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: MAKE NTNU website\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-10-05 18:43+0200\n"
+"POT-Creation-Date: 2023-11-18 22:09+0100\n"
"PO-Revision-Date: 2018-10-09 14:05+0200\n"
"Last-Translator: Sindre Stephansen \n"
"Language-Team: Norwegian Bokmål \n"
@@ -127,8 +127,8 @@ msgstr "Legg til kunngjøring"
#: src/checkin/templates/checkin/admin_suggest_skill.html:37
#: src/checkin/templates/checkin/profile_detail_internal.html:79
#: src/docs/views.py:95 src/faq/views.py:65 src/faq/views.py:93
-#: src/internal/views.py:87 src/internal/views.py:264
-#: src/internal/views.py:309
+#: src/internal/views.py:88 src/internal/views.py:265
+#: src/internal/views.py:310
#: src/make_queue/templates/make_queue/course/printer_3d_course_create.html:12
#: src/make_queue/templates/make_queue/course/printer_3d_course_list.html:18
#: src/make_queue/templates/make_queue/machine_list.html:21
@@ -323,7 +323,7 @@ msgid "Register"
msgstr "Registrer"
#: src/checkin/templates/checkin/profile_detail_internal.html:97
-#: src/internal/forms.py:43 src/make_queue/forms/course.py:57
+#: src/internal/forms.py:45 src/make_queue/forms/course.py:57
msgid "Card number is already in use"
msgstr "Kortnummeret er allerede i bruk"
@@ -406,8 +406,8 @@ msgid "URL name"
msgstr "URL-navn"
#: src/contentbox/models.py:20 src/docs/models.py:15
-#: src/internal/models.py:262 src/makerspace/models.py:23
-#: src/news/models.py:39
+#: src/internal/models.py:262 src/internal/models.py:320
+#: src/makerspace/models.py:23 src/news/models.py:39
msgid "title"
msgstr "tittel"
@@ -761,15 +761,15 @@ msgstr "fullt navn"
msgid "extra view permissions"
msgstr "ekstra visningsrettigheter"
-#: src/internal/forms.py:17
+#: src/internal/forms.py:19
msgid "Choose user"
msgstr "Velg bruker"
-#: src/internal/forms.py:19 src/internal/forms.py:36
+#: src/internal/forms.py:21 src/internal/forms.py:38
msgid "Choose committees"
msgstr "Velg komiteer"
-#: src/internal/forms.py:67
+#: src/internal/forms.py:69
msgid ""
"Member was not set as retired, as the member already has the status “quit” "
"or “retired”."
@@ -777,7 +777,7 @@ msgstr ""
"Medlemmet ble ikke markert som pang, fordi medlemmet allerede har status "
"«sluttet» eller «pang»."
-#: src/internal/forms.py:98
+#: src/internal/forms.py:100
msgid ""
"Member was not set as quit, as the member already has the status “quit” or "
"“retired”."
@@ -785,7 +785,7 @@ msgstr ""
"Medlemmet ble ikke markert som sluttet, fordi medlemmet allerede har status "
"«sluttet» eller «pang»."
-#: src/internal/forms.py:137
+#: src/internal/forms.py:139
msgid ""
"Member's “quit” status was not undone, as the member did not have the status "
"“quit”."
@@ -793,7 +793,7 @@ msgstr ""
"Medlemmets «sluttet»-status ble ikke omgjort, fordi medlemmet ikke hadde "
"status «sluttet»."
-#: src/internal/forms.py:142
+#: src/internal/forms.py:144
msgid ""
"Member's retirement was not undone, as the member did not have the status "
"“retired”."
@@ -801,6 +801,18 @@ msgstr ""
"Medlemmets «pang»-status ble ikke omgjort, fordi medlemmet ikke hadde status "
"«pang»."
+#: src/internal/forms.py:203 src/internal/forms.py:208
+msgid ""
+"An article with this title already exists. Please merge your text with the "
+"existing one!"
+msgstr ""
+"En artikkel med dette navnet eksisterer allerede. Rediger heller den "
+"eksisterende artikkelen!"
+
+#: src/internal/forms.py:205 src/internal/forms.py:210
+msgid "Please make a title consisting of actual letters!"
+msgstr "Lag en tittel som består av bokstaver, ikke bare tegn"
+
#: src/internal/models.py:31 src/make_queue/forms/quota.py:19
#: src/make_queue/models/course.py:26
#: src/make_queue/models/reservation.py:31 src/news/admin.py:306
@@ -1014,6 +1026,18 @@ msgstr "forfatter"
msgid "“{quote}” —{quoted}"
msgstr "«{quote}» —{quoted}"
+#: src/internal/models.py:322
+msgid "text"
+msgstr "tekst"
+
+#: src/internal/models.py:336
+msgid "lore article"
+msgstr "Lore-artikkel"
+
+#: src/internal/models.py:337
+msgid "lore articles"
+msgstr "Lore-artikler"
+
#: src/internal/templates/internal/base.html:6
#: src/web/templates/web/header.html:94
msgid "Internal pages"
@@ -1042,29 +1066,50 @@ msgstr "Hemmeligheter"
msgid "Quotes"
msgstr "Sitater"
-#: src/internal/templates/internal/header.html:25
+#: src/internal/templates/internal/header.html:24
+msgid "MAKE Lore"
+msgstr "MAKE-lore"
+
#: src/internal/templates/internal/header.html:29
+#: src/internal/templates/internal/header.html:33
msgid "Misc."
msgstr "Diverse"
-#: src/internal/templates/internal/header.html:31
+#: src/internal/templates/internal/header.html:35
msgid "The History of MAKE NTNU"
msgstr "Historien til MAKE NTNU"
-#: src/internal/templates/internal/header.html:39
+#: src/internal/templates/internal/header.html:43
msgid "Public pages"
msgstr "Offentlige sider"
-#: src/internal/templates/internal/header.html:43
+#: src/internal/templates/internal/header.html:47
#: src/web/templates/web/header.html:104
msgid "Django admin"
msgstr "Django-admin"
-#: src/internal/templates/internal/header.html:48
+#: src/internal/templates/internal/header.html:52
#: src/web/templates/web/header.html:116
msgid "Log out"
msgstr "Logg ut"
+#: src/internal/templates/internal/lore/lore_list.html:7
+msgid "The wiki of MAKE lore"
+msgstr "MAKE-lore-wiki"
+
+#: src/internal/templates/internal/lore/lore_list.html:18
+#: src/internal/templates/internal/lore/lore_list.html:31
+msgid "Topics"
+msgstr "Tema"
+
+#: src/internal/templates/internal/lore/lore_list.html:61
+msgid "Welcome to the wiki of MAKE lore"
+msgstr "Velkommen til wiki-siden for MAKE-lore"
+
+#: src/internal/templates/internal/lore/lore_list.html:62
+msgid "Click a topic in the menu to access a wiki article"
+msgstr "Velg et tema i menyen til venstre for å lese om det"
+
#: src/internal/templates/internal/member_create.html:8
#: src/internal/templates/internal/member_list.html:55
msgid "TODOs when a new member enrolls"
@@ -1072,7 +1117,7 @@ msgstr "Ting som skal gjøres når et nytt medlem tas opp"
#: src/internal/templates/internal/member_list.html:10
#: src/internal/templates/internal/member_list.html:44
-#: src/internal/views.py:77 src/internal/views.py:171
+#: src/internal/views.py:78 src/internal/views.py:172
msgid "Member list"
msgstr "Medlemsliste"
@@ -1187,12 +1232,12 @@ msgid "Basic information"
msgstr "Grunnleggende informasjon"
#: src/internal/templates/internal/member_list.html:326
-#: src/internal/views.py:143
+#: src/internal/views.py:144
msgid "Membership information"
msgstr "Medlemskapsinformasjon"
#: src/internal/templates/internal/member_list.html:382
-#: src/internal/views.py:137
+#: src/internal/views.py:138
msgid "Extra information"
msgstr "Ekstrainformasjon"
@@ -1268,57 +1313,73 @@ msgstr ""
"Oppgi et gyldig Discord-brukernavn – inkludert hashtaggen og de fire sifrene "
"på slutten."
-#: src/internal/views.py:85
+#: src/internal/views.py:86
msgid "Add New Member"
msgstr "Legg til nytt medlem"
-#: src/internal/views.py:124
+#: src/internal/views.py:125
#, python-brace-format
msgid "Change Information for {full_name}"
msgstr "Endre informasjonen til {full_name}"
-#: src/internal/views.py:172
+#: src/internal/views.py:173
msgid "Set retired"
msgstr "Sett panget"
-#: src/internal/views.py:178
+#: src/internal/views.py:179
#, python-brace-format
msgid "Set member {name} as retired"
msgstr "Sett medlem {name} som pang"
-#: src/internal/views.py:191
+#: src/internal/views.py:192
msgid "Set quit"
msgstr "Sett sluttet"
-#: src/internal/views.py:197
+#: src/internal/views.py:198
#, python-brace-format
msgid "Set member {name} as quit"
msgstr "Sett medlem {name} som sluttet"
-#: src/internal/views.py:257
+#: src/internal/views.py:258
msgid "Secrets list"
msgstr "Liste med hemmeligheter"
-#: src/internal/views.py:263
+#: src/internal/views.py:264
msgid "Add Secret"
msgstr "Legg til hemmelighet"
-#: src/internal/views.py:276
+#: src/internal/views.py:277
msgid "Change Secret"
msgstr "Endre hemmelighet"
-#: src/internal/views.py:299
+#: src/internal/views.py:300
msgid "Quotes page"
msgstr "Sitatside"
-#: src/internal/views.py:308
+#: src/internal/views.py:309
msgid "Add Quote"
msgstr "Legg til sitat"
-#: src/internal/views.py:317
+#: src/internal/views.py:318
msgid "Change Quote"
msgstr "Endre sitat"
+#: src/internal/views.py:366
+msgid "Lore Wiki"
+msgstr "Lore-wiki"
+
+#: src/internal/views.py:372
+msgid "Add Lore Article"
+msgstr "Legg til lore-artikkel"
+
+#: src/internal/views.py:385
+msgid "Change Lore Article"
+msgstr "Endre lore-artikkel"
+
+#: src/internal/views.py:386
+msgid "Lore Article"
+msgstr "Lore-artikkel"
+
#: src/make_queue/admin.py:22
#: src/make_queue/templates/make_queue/machine_list.html:7
#: src/make_queue/templates/make_queue/machine_list.html:19
diff --git a/src/web/static/web/css/style.css b/src/web/static/web/css/style.css
index 289924055..fc129b740 100644
--- a/src/web/static/web/css/style.css
+++ b/src/web/static/web/css/style.css
@@ -209,7 +209,6 @@ span.no-wrap {
z-index: -1;
}
-
/*
* Extension of Fomantic-UI mobile only, table only, etc. classes.
* The `max-width` and `min-width` values are copied from Fomantic-UI.