Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • master
1 result

Target

Select target project
No results found
Select Git revision
  • master
  • jw
2 results
Show changes
1000 files
+ 3313
170422
Compare changes
  • Side-by-side
  • Inline

Files

+1 −0
Original line number Diff line number Diff line
@@ -3,3 +3,4 @@ __pycache__/
institut/static/css/style.css
static/*
media/*
node_modules/
+4 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ help:
	@echo "Application:"
	@echo "  run             Run the application on port ${PORT}"
	@echo "  shell           Access the Django shell"
	@echo "  superuser       Create superuser
	@echo ""
	@echo "Database:"
	@echo "  migrations      Generate migrations"
@@ -57,6 +58,9 @@ run: venv
shell: venv
	${VENV}/bin/python manage.py shell --settings=${SETTINGS}

superuser: venv
	${VENV}/bin/python manage.py createsuperuser --settings=${SETTINGS}

migrations: venv
	${VENV}/bin/python manage.py makemigrations --settings=${SETTINGS}

home/admin.py

0 → 100644
+15 −0
Original line number Diff line number Diff line
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register

from .models import Tag


class TagAdmin(ModelAdmin):
    model = Tag
    menu_label = "Štítky"
    menu_icon = "tag"
    menu_order = 290
    add_to_settings_menu = False
    exclude_from_explorer = False


modeladmin_register(TagAdmin)

home/feeds.py

0 → 100644
+52 −0
Original line number Diff line number Diff line
import typing
from datetime import datetime

from django.contrib.syndication.views import Feed
from django.template.loader import render_to_string
from django.urls import reverse

from .models import HomeArticlePage, HomeArticlesPage


class LatestArticlesFeed(Feed):
    def get_object(self, request, id: int) -> HomeArticlesPage:
        return HomeArticlesPage.objects.get(id=id)

    def title(self, obj: HomeArticlesPage) -> str:
        return obj.title

    def link(self, obj: HomeArticlesPage) -> str:
        return obj.get_full_url()

    def items(self, obj: HomeArticlesPage) -> list:
        return HomeArticlePage.objects.live().child_of(obj).order_by("-date")[:32]

    def item_title(self, item: HomeArticlePage) -> str:
        return item.title

    def item_description(self, item: HomeArticlePage) -> str:
        return render_to_string(
            "home/feed_item_description.html",
            {"item": item},
        )

    def item_pubdate(self, item: HomeArticlePage) -> datetime:
        return datetime(
            item.date.year,
            item.date.month,
            item.date.day,
            12,
            0,
        )

    def item_author_name(self, item: HomeArticlePage) -> str:
        if item.author:
            return item.author

        return ""

    def item_categories(self, item: HomeArticlePage) -> list:
        return item.tags.all()

    def item_link(self, item: HomeArticlePage) -> str:
        return item.get_full_url()
Original line number Diff line number Diff line
@@ -4,18 +4,17 @@ from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('home', '0011_alter_homedocumentpage_content_and_more'),
        ("home", "0011_alter_homedocumentpage_content_and_more"),
    ]

    operations = [
        migrations.RemoveField(
            model_name='homepage',
            name='documents',
            model_name="homepage",
            name="documents",
        ),
        migrations.RemoveField(
            model_name='homepage',
            name='events',
            model_name="homepage",
            name="events",
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 15:11

from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0012_remove_homepage_documents_remove_homepage_events"),
    ]

    operations = [
        migrations.AlterModelOptions(
            name="homearticlepage",
            options={"verbose_name": "Článek"},
        ),
        migrations.AlterModelOptions(
            name="homedocumentpage",
            options={"verbose_name": "Dokument"},
        ),
        migrations.AlterModelOptions(
            name="homeeventpage",
            options={"verbose_name": "Akce"},
        ),
        migrations.AddField(
            model_name="homepage",
            name="academic_council_description",
            field=models.CharField(
                default="Akademická rada je poradním orgánem ústavu a v rámci své činnosti zejména poskytuje správní radě stanoviska k ideovému směřování, strategickým materiálům, rozpočtu a plánu činností ústavu. Dále vykonává akademická rada dohled nad ideovou a odbornou kvalitou výstupů ústavu.",
                verbose_name="Akademická rada - popis",
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="homepage",
            name="controller_description",
            field=models.CharField(
                default="Kontrolor je kontrolním orgánem ústavu.",
                verbose_name="Kontrolor - popis",
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="homepage",
            name="council_members_description",
            field=models.CharField(
                default="Správní rada dbá o zachování účelu, pro nějž byl ústav založen, a dohlíží na řádné hospodaření s jeho majetkem.",
                verbose_name="Správní rada - popis",
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="homepage",
            name="director_description",
            field=models.CharField(
                default="Ředitel je statutárním orgánem ústavu, řídí jeho činnost, jedná jeho jménem a rozhoduje ve všech záležitostech, které nespadají do pravomoci jiných orgánů.",
                verbose_name="Ředitel - popis",
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="homepage",
            name="employees_description",
            field=models.CharField(
                default="Zaměstnanci poskytují administrativní, organizační a expertní podporu pro vykonávání činností ústavu.",
                verbose_name="Zaměstnanci - popis",
            ),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name="homepage",
            name="volunteers_description",
            field=models.CharField(
                default="Dobrovolnický kruh je participační orgán ústavu. Účelem dobrovolnického kruhu je sdružovat osoby, které se chtějí dobrovolně podílet na činnostech ústavu, a navrhovat správní radě projekty pro realizaci ústavem v souladu s účelem ústavu.",
                verbose_name="Dobrovolníci - popis",
            ),
            preserve_default=False,
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 15:18

from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0013_alter_homearticlepage_options_and_more"),
    ]

    operations = [
        migrations.AlterField(
            model_name="homepage",
            name="academic_council_description",
            field=models.TextField(verbose_name="Akademická rada - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="controller_description",
            field=models.TextField(verbose_name="Kontrolor - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="council_members_description",
            field=models.TextField(verbose_name="Správní rada - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="director_description",
            field=models.TextField(verbose_name="Ředitel - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="employees_description",
            field=models.TextField(verbose_name="Zaměstnanci - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="volunteers_description",
            field=models.TextField(verbose_name="Dobrovolníci - popis"),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 15:36

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0014_alter_homepage_academic_council_description_and_more"),
    ]

    operations = [
        migrations.AlterModelOptions(
            name="homepage",
            options={"verbose_name": "Domovská stránka"},
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:00

import django.db.models.deletion
import wagtail.contrib.routable_page.models
import wagtail.fields
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("wagtailcore", "0083_workflowcontenttype"),
        ("wagtailimages", "0025_alter_image_file_alter_rendition_file"),
        ("home", "0015_alter_homepage_options"),
    ]

    operations = [
        migrations.CreateModel(
            name="HomePeoplePage",
            fields=[
                (
                    "page_ptr",
                    models.OneToOneField(
                        auto_created=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="wagtailcore.page",
                    ),
                ),
                (
                    "content",
                    wagtail.fields.RichTextField(
                        blank=True, null=True, verbose_name="Obsah"
                    ),
                ),
            ],
            options={
                "verbose_name": "Rozcestník uživatelů",
            },
            bases=(
                wagtail.contrib.routable_page.models.RoutablePageMixin,
                "wagtailcore.page",
            ),
        ),
        migrations.CreateModel(
            name="HomePersonPage",
            fields=[
                (
                    "page_ptr",
                    models.OneToOneField(
                        auto_created=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="wagtailcore.page",
                    ),
                ),
                ("name", models.CharField(max_length=64, verbose_name="Jméno")),
                (
                    "position",
                    models.TextField(
                        blank=True, null=True, verbose_name="Pracovní pozice"
                    ),
                ),
                (
                    "email",
                    models.EmailField(
                        blank=True,
                        max_length=254,
                        null=True,
                        verbose_name="Emailová adresa",
                    ),
                ),
                (
                    "description",
                    wagtail.fields.RichTextField(
                        blank=True, null=True, verbose_name="Popis"
                    ),
                ),
                (
                    "image",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        related_name="+",
                        to="wagtailimages.image",
                        verbose_name="Profilový obrázek",
                    ),
                ),
            ],
            options={
                "abstract": False,
            },
            bases=(
                wagtail.contrib.routable_page.models.RoutablePageMixin,
                "wagtailcore.page",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:01

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0016_homepeoplepage_homepersonpage"),
    ]

    operations = [
        migrations.AlterModelOptions(
            name="homepeoplepage",
            options={"verbose_name": "Rozcestník osob"},
        ),
        migrations.AlterModelOptions(
            name="homepersonpage",
            options={"verbose_name": "Osoba"},
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:01

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0017_alter_homepeoplepage_options_and_more"),
    ]

    operations = [
        migrations.RemoveField(
            model_name="homepersonpage",
            name="name",
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:21

import wagtail.blocks
import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0018_remove_homepersonpage_name"),
    ]

    operations = [
        migrations.AlterField(
            model_name="homepage",
            name="controller",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            page_type=["home.HomePersonPage"]
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Kontrolor",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="council_members",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            page_type=["home.HomePersonPage"]
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Správní rada",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="director",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            page_type=["home.HomePersonPage"]
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Ředitel",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="employees",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            page_type=["home.HomePersonPage"]
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Zaměstnanci",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="volunteers",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            page_type=["home.HomePersonPage"]
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Dobrovolníci",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:27

import django.db.models.deletion
import wagtail.blocks
import wagtail.fields
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0019_alter_homepage_controller_and_more"),
    ]

    operations = [
        migrations.AddField(
            model_name="homearticlepage",
            name="author_page",
            field=models.ForeignKey(
                blank=True,
                help_text="Pokud je vybrána stránka, není nutno vyplňovat jméno autora níže.",
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="home.homepersonpage",
                verbose_name="Stránka autora",
            ),
        ),
        migrations.AddField(
            model_name="homedocumentpage",
            name="author_page",
            field=models.ForeignKey(
                blank=True,
                help_text="Pokud je vybrána stránka, není nutno vyplňovat jméno autora níže.",
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="home.homepersonpage",
                verbose_name="Stránka autora",
            ),
        ),
        migrations.AddField(
            model_name="homeeventpage",
            name="author_page",
            field=models.ForeignKey(
                blank=True,
                help_text="Pokud je vybrána stránka, není nutno vyplňovat jméno autora níže.",
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to="home.homepersonpage",
                verbose_name="Stránka autora",
            ),
        ),
        migrations.AlterField(
            model_name="homearticlepage",
            name="author",
            field=models.CharField(
                blank=True, max_length=128, null=True, verbose_name="Jméno autora"
            ),
        ),
        migrations.AlterField(
            model_name="homedocumentpage",
            name="author",
            field=models.CharField(
                blank=True, max_length=128, null=True, verbose_name="Jméno autora"
            ),
        ),
        migrations.AlterField(
            model_name="homeeventpage",
            name="author",
            field=models.CharField(
                blank=True, max_length=128, null=True, verbose_name="Jméno autora"
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="controller",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Kontrolor",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="council_members",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Správní rada",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="director",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Ředitel",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="employees",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Zaměstnanci",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="volunteers",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Dobrovolníci",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:39

import wagtail.blocks
import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0020_homearticlepage_author_page_and_more"),
    ]

    operations = [
        migrations.AlterField(
            model_name="homepage",
            name="controller",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    )
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Kontrolor",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="council_members",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    )
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Správní rada",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="director",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    )
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Ředitel",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="employees",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    )
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Zaměstnanci",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="volunteers",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    )
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Dobrovolníci",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-12 19:49

import wagtail.blocks
import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0021_alter_homepage_controller_and_more"),
    ]

    operations = [
        migrations.AlterField(
            model_name="homepage",
            name="controller",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Kontrolor",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="council_members",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Správní rada",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="director",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Ředitel",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="employees",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Zaměstnanci",
            ),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="volunteers",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Dobrovolníci",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-15 17:01

import wagtail.blocks
import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0022_alter_homepage_controller_and_more"),
    ]

    operations = [
        migrations.AddField(
            model_name="homepage",
            name="academic_council",
            field=wagtail.fields.StreamField(
                [
                    (
                        "person",
                        wagtail.blocks.StructBlock(
                            [
                                ("name", wagtail.blocks.CharBlock(label="Jméno")),
                                (
                                    "position",
                                    wagtail.blocks.TextBlock(
                                        label="Pracovní pozice", required=False
                                    ),
                                ),
                                (
                                    "email",
                                    wagtail.blocks.EmailBlock(
                                        label="E-mailová adresa", required=False
                                    ),
                                ),
                            ]
                        ),
                    ),
                    (
                        "person_page",
                        wagtail.blocks.PageChooserBlock(
                            icon="user",
                            label="Stránka osoby",
                            page_type=["home.HomePersonPage"],
                        ),
                    ),
                ],
                blank=True,
                null=True,
                use_json_field=True,
                verbose_name="Akademická rada",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.2 on 2023-08-15 23:51

import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0023_homepage_academic_council"),
    ]

    operations = [
        migrations.AlterField(
            model_name="homepage",
            name="academic_council_description",
            field=wagtail.fields.RichTextField(verbose_name="Akademická rada - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="controller_description",
            field=wagtail.fields.RichTextField(verbose_name="Kontrolor - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="council_members_description",
            field=wagtail.fields.RichTextField(verbose_name="Správní rada - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="director_description",
            field=wagtail.fields.RichTextField(verbose_name="Ředitel - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="employees_description",
            field=wagtail.fields.RichTextField(verbose_name="Zaměstnanci - popis"),
        ),
        migrations.AlterField(
            model_name="homepage",
            name="volunteers_description",
            field=wagtail.fields.RichTextField(verbose_name="Dobrovolníci - popis"),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-19 22:46

from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0023_homepage_academic_council"),
    ]

    operations = [
        migrations.AddField(
            model_name="homepersonpage",
            name="name_titles",
            field=models.CharField(
                blank=True, max_length=32, null=True, verbose_name="Tituly"
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-19 23:08

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("wagtailimages", "0025_alter_image_file_alter_rendition_file"),
        ("home", "0024_homepersonpage_name_titles"),
    ]

    operations = [
        migrations.AddField(
            model_name="homearticlepage",
            name="image",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                related_name="+",
                to="wagtailimages.image",
                verbose_name="Obrázek",
            ),
        ),
        migrations.AddField(
            model_name="homearticlepage",
            name="show_image_on_homepage",
            field=models.BooleanField(
                default=False, verbose_name="Zobrazovat obrázek na homepage"
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 14:17

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("wagtailcore", "0083_workflowcontenttype"),
        ("home", "0025_homearticlepage_image_and_more"),
    ]

    operations = [
        migrations.CreateModel(
            name="SocialMediaSettings",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "mastodon",
                    models.URLField(blank=True, help_text="Mastodon URL", null=True),
                ),
                (
                    "twitter",
                    models.URLField(blank=True, help_text="Twitter URL", null=True),
                ),
                (
                    "linkedin",
                    models.URLField(blank=True, help_text="LinkedIn URL", null=True),
                ),
                (
                    "facebook",
                    models.URLField(blank=True, help_text="Facebook URL", null=True),
                ),
                (
                    "site",
                    models.OneToOneField(
                        editable=False,
                        on_delete=django.db.models.deletion.CASCADE,
                        to="wagtailcore.site",
                    ),
                ),
            ],
            options={
                "verbose_name": "Sociální sítě",
            },
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 15:50

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0026_socialmediasettings"),
    ]

    operations = [
        migrations.RemoveField(
            model_name="homedocumentpage",
            name="tags",
        ),
        migrations.RemoveField(
            model_name="homeeventpage",
            name="tags",
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 16:06

import django.db.models.deletion
import modelcluster.fields
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("taggit", "0005_auto_20220424_2025"),
        ("home", "0027_remove_homedocumentpage_tags_and_more"),
    ]

    operations = [
        migrations.CreateModel(
            name="ArticleTag",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
            ],
            options={
                "abstract": False,
            },
        ),
        migrations.RemoveField(
            model_name="homearticlepage",
            name="tags",
        ),
        migrations.DeleteModel(
            name="Tag",
        ),
        migrations.AddField(
            model_name="articletag",
            name="content_object",
            field=modelcluster.fields.ParentalKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="tagged_items",
                to="home.homearticlepage",
            ),
        ),
        migrations.AddField(
            model_name="articletag",
            name="tag",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="%(app_label)s_%(class)s_items",
                to="taggit.tag",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 16:06

import modelcluster.contrib.taggit
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("taggit", "0005_auto_20220424_2025"),
        ("home", "0028_articletag_remove_homearticlepage_tags_delete_tag_and_more"),
    ]

    operations = [
        migrations.AddField(
            model_name="homearticlepage",
            name="tags",
            field=modelcluster.contrib.taggit.ClusterTaggableManager(
                blank=True,
                help_text="A comma-separated list of tags.",
                through="home.ArticleTag",
                to="taggit.Tag",
                verbose_name="Štítky",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 16:50

import django.db.models.deletion
import django.utils.timezone
import wagtail.contrib.routable_page.models
import wagtail.fields
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("wagtailimages", "0025_alter_image_file_alter_rendition_file"),
        ("wagtailcore", "0083_workflowcontenttype"),
        ("home", "0029_homearticlepage_tags"),
    ]

    operations = [
        migrations.CreateModel(
            name="HomeVideosPage",
            fields=[
                (
                    "page_ptr",
                    models.OneToOneField(
                        auto_created=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="wagtailcore.page",
                    ),
                ),
                (
                    "content",
                    wagtail.fields.RichTextField(
                        blank=True, null=True, verbose_name="Obsah"
                    ),
                ),
            ],
            options={
                "verbose_name": "Rozcestník videí",
            },
            bases=(
                wagtail.contrib.routable_page.models.RoutablePageMixin,
                "wagtailcore.page",
            ),
        ),
        migrations.CreateModel(
            name="HomeVideoPage",
            fields=[
                (
                    "page_ptr",
                    models.OneToOneField(
                        auto_created=True,
                        on_delete=django.db.models.deletion.CASCADE,
                        parent_link=True,
                        primary_key=True,
                        serialize=False,
                        to="wagtailcore.page",
                    ),
                ),
                (
                    "author",
                    models.CharField(
                        blank=True,
                        max_length=128,
                        null=True,
                        verbose_name="Jméno autora",
                    ),
                ),
                (
                    "date",
                    models.DateField(
                        default=django.utils.timezone.now,
                        verbose_name="Datum vytvoření",
                    ),
                ),
                ("content", wagtail.fields.RichTextField(verbose_name="Obsah")),
                (
                    "embed_url",
                    models.URLField(
                        help_text="Pro získání adresy zmáčkni tlačítko Sdílet, vyber záložku Embed a zaškrtní zobrazování pouze URL.",
                        verbose_name="URL Embedu",
                    ),
                ),
                (
                    "author_page",
                    models.ForeignKey(
                        blank=True,
                        help_text="Pokud je vybrána stránka, není nutno vyplňovat jméno autora níže.",
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        to="home.homepersonpage",
                        verbose_name="Stránka autora",
                    ),
                ),
                (
                    "thumbnail",
                    models.ForeignKey(
                        blank=True,
                        null=True,
                        on_delete=django.db.models.deletion.SET_NULL,
                        related_name="+",
                        to="wagtailimages.image",
                        verbose_name="Náhledový obrázek",
                    ),
                ),
            ],
            options={
                "abstract": False,
            },
            bases=(
                wagtail.contrib.routable_page.models.RoutablePageMixin,
                "wagtailcore.page",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 16:53

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0030_homevideospage_homevideopage"),
    ]

    operations = [
        migrations.AlterModelOptions(
            name="homevideopage",
            options={"verbose_name": "Video"},
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-20 16:54

import wagtail.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0031_alter_homevideopage_options"),
    ]

    operations = [
        migrations.AlterField(
            model_name="homevideopage",
            name="content",
            field=wagtail.fields.RichTextField(
                blank=True, null=True, verbose_name="Obsah"
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.2 on 2023-08-20 18:44

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0024_alter_homepage_academic_council_description_and_more"),
        ("home", "0032_alter_homevideopage_content"),
    ]

    operations = []
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-21 18:21

import django.db.models.deletion
import modelcluster.contrib.taggit
import modelcluster.fields
import wagtail_color_panel.fields
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("contenttypes", "0002_remove_content_type_name"),
        ("home", "0033_merge_20230820_1844"),
    ]

    operations = [
        migrations.CreateModel(
            name="Tag",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "name",
                    models.CharField(max_length=100, unique=True, verbose_name="name"),
                ),
                (
                    "slug",
                    models.SlugField(
                        allow_unicode=True,
                        max_length=100,
                        unique=True,
                        verbose_name="slug",
                    ),
                ),
                (
                    "bg_color",
                    wagtail_color_panel.fields.ColorField(
                        blank=True, max_length=7, null=True, verbose_name="Barva pozadí"
                    ),
                ),
                (
                    "fg_color",
                    wagtail_color_panel.fields.ColorField(
                        blank=True, max_length=7, null=True, verbose_name="Barva textu"
                    ),
                ),
            ],
            options={
                "abstract": False,
            },
        ),
        migrations.CreateModel(
            name="TaggedArticle",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "object_id",
                    models.IntegerField(db_index=True, verbose_name="object ID"),
                ),
                (
                    "content_object",
                    modelcluster.fields.ParentalKey(
                        on_delete=django.db.models.deletion.CASCADE,
                        related_name="tagged_items",
                        to="home.homearticlepage",
                    ),
                ),
                (
                    "content_type",
                    models.ForeignKey(
                        on_delete=django.db.models.deletion.CASCADE,
                        related_name="%(app_label)s_%(class)s_tagged_items",
                        to="contenttypes.contenttype",
                        verbose_name="content type",
                    ),
                ),
                (
                    "tag",
                    models.ForeignKey(
                        on_delete=django.db.models.deletion.CASCADE,
                        related_name="%(app_label)s_%(class)s_items",
                        to="home.tag",
                    ),
                ),
            ],
            options={
                "abstract": False,
            },
        ),
        migrations.DeleteModel(
            name="ArticleTag",
        ),
        migrations.AlterField(
            model_name="homearticlepage",
            name="tags",
            field=modelcluster.contrib.taggit.ClusterTaggableManager(
                blank=True,
                help_text="A comma-separated list of tags.",
                through="home.TaggedArticle",
                to="home.Tag",
                verbose_name="Štítky",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-21 18:26

import wagtail_color_panel.fields
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0034_tag_taggedarticle_delete_articletag_and_more"),
    ]

    operations = [
        migrations.AlterField(
            model_name="tag",
            name="bg_color",
            field=wagtail_color_panel.fields.ColorField(
                default="#fafafa", max_length=7, verbose_name="Barva pozadí"
            ),
        ),
        migrations.AlterField(
            model_name="tag",
            name="fg_color",
            field=wagtail_color_panel.fields.ColorField(
                default="#000000", max_length=7, verbose_name="Barva textu"
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-21 18:44

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0035_alter_tag_bg_color_alter_tag_fg_color"),
    ]

    operations = [
        migrations.AlterField(
            model_name="taggedarticle",
            name="tag",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="article_tags",
                to="home.tag",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-21 19:06

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0036_alter_taggedarticle_tag"),
    ]

    operations = [
        migrations.RemoveField(
            model_name="homearticlepage",
            name="tags",
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-21 19:06

import modelcluster.contrib.taggit
from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0037_remove_homearticlepage_tags"),
    ]

    operations = [
        migrations.AddField(
            model_name="homearticlepage",
            name="tags",
            field=modelcluster.contrib.taggit.ClusterTaggableManager(
                blank=True,
                help_text="A comma-separated list of tags.",
                through="home.TaggedArticle",
                to="home.Tag",
                verbose_name="Štítky",
            ),
        ),
    ]
Original line number Diff line number Diff line
# Generated by Django 4.2.4 on 2023-08-21 19:09

from django.db import migrations


class Migration(migrations.Migration):
    dependencies = [
        ("home", "0038_homearticlepage_tags"),
    ]

    operations = [
        migrations.RemoveField(
            model_name="taggedarticle",
            name="content_type",
        ),
        migrations.RemoveField(
            model_name="taggedarticle",
            name="object_id",
        ),
    ]
+442 −42
Original line number Diff line number Diff line
from django.db import models
from django.utils import timezone
from wagtail.admin.panels import FieldPanel, MultiFieldPanel
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import ItemBase, TagBase
from wagtail.admin.panels import (
    FieldPanel,
    InlinePanel,
    MultiFieldPanel,
    ObjectList,
    TabbedInterface,
)
from wagtail.blocks import PageChooserBlock
from wagtail.contrib.routable_page.models import RoutablePageMixin, path
from wagtail.contrib.settings.models import BaseSiteSetting, register_setting
from wagtail.documents import get_document_model
from wagtail.fields import RichTextField, StreamField
from wagtail.models import Page
from wagtail_color_panel.edit_handlers import NativeColorPanel
from wagtail_color_panel.fields import ColorField

from .blocks import PersonBlock

# --- BEGIN Tags ---


class HomePage(Page):
class Tag(TagBase):
    bg_color = ColorField(verbose_name="Barva pozadí", default="#fafafa")
    fg_color = ColorField(verbose_name="Barva textu", default="#000000")

    panels = [
        FieldPanel("name"),
        FieldPanel("slug"),
        NativeColorPanel("bg_color"),
        NativeColorPanel("fg_color"),
    ]


class TaggedArticle(ItemBase):
    content_object = ParentalKey(
        "home.HomeArticlePage", on_delete=models.CASCADE, related_name="tagged_items"
    )

    tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name="article_tags")


# --- END Tags ---


class HomePage(RoutablePageMixin, Page):
    heading_text = RichTextField(verbose_name="Hlavní text stránky")

    # --- Donations ---
@@ -25,52 +64,116 @@ class HomePage(Page):
    # --- People ---

    director = StreamField(
        [("person", PersonBlock())],
        [
            ("person", PersonBlock()),
            (
                "person_page",
                PageChooserBlock(
                    page_type="home.HomePersonPage", label="Stránka osoby", icon="user"
                ),
            ),
        ],
        verbose_name="Ředitel",
        use_json_field=True,
        blank=True,
        null=True,
    )
    director_description = RichTextField(verbose_name="Ředitel - popis")

    academic_council = StreamField(
        [
            ("person", PersonBlock()),
            (
                "person_page",
                PageChooserBlock(
                    page_type="home.HomePersonPage", label="Stránka osoby", icon="user"
                ),
            ),
        ],
        verbose_name="Akademická rada",
        use_json_field=True,
        blank=True,
        null=True,
    )
    academic_council_description = RichTextField(verbose_name="Akademická rada - popis")

    controller = StreamField(
        [("person", PersonBlock())],
        [
            ("person", PersonBlock()),
            (
                "person_page",
                PageChooserBlock(
                    page_type="home.HomePersonPage", label="Stránka osoby", icon="user"
                ),
            ),
        ],
        verbose_name="Kontrolor",
        use_json_field=True,
        blank=True,
        null=True,
    )
    controller_description = RichTextField(verbose_name="Kontrolor - popis")

    council_members = StreamField(
        [("person", PersonBlock())],
        [
            ("person", PersonBlock()),
            (
                "person_page",
                PageChooserBlock(
                    page_type="home.HomePersonPage", label="Stránka osoby", icon="user"
                ),
            ),
        ],
        verbose_name="Správní rada",
        use_json_field=True,
        blank=True,
        null=True,
    )
    council_members_description = RichTextField(verbose_name="Správní rada - popis")

    volunteers = StreamField(
        [("person", PersonBlock())],
        [
            ("person", PersonBlock()),
            (
                "person_page",
                PageChooserBlock(
                    page_type="home.HomePersonPage", label="Stránka osoby", icon="user"
                ),
            ),
        ],
        verbose_name="Dobrovolníci",
        use_json_field=True,
        blank=True,
        null=True,
    )
    volunteers_description = RichTextField(verbose_name="Dobrovolníci - popis")

    employees = StreamField(
        [("person", PersonBlock())],
        [
            ("person", PersonBlock()),
            (
                "person_page",
                PageChooserBlock(
                    page_type="home.HomePersonPage", label="Stránka osoby", icon="user"
                ),
            ),
        ],
        verbose_name="Zaměstnanci",
        use_json_field=True,
        blank=True,
        null=True,
    )
    employees_description = RichTextField(verbose_name="Zaměstnanci - popis")

    subpage_types = [
        "home.HomeArticlesPage",
        "home.HomeEventsPage",
        "home.HomeDocumentsPage",
        "home.HomeVideosPage",
        "home.HomePeoplePage",
    ]

    content_panels = Page.content_panels + [
    intro_panels = Page.content_panels + [
        FieldPanel("heading_text", icon="pilcrow"),
        FieldPanel("donation_text", icon="pilcrow"),
        MultiFieldPanel(
@@ -82,18 +185,31 @@ class HomePage(Page):
            ],
            heading="Kontaktní údaje",
        ),
        MultiFieldPanel(
            [
    ]

    people_panels = [
        FieldPanel("director_description", icon="pilcrow"),
        FieldPanel("director", icon="user"),
        FieldPanel("academic_council_description"),
        FieldPanel("academic_council", icon="user"),
        FieldPanel("controller_description", icon="pilcrow"),
        FieldPanel("controller", icon="user"),
        FieldPanel("council_members_description", icon="pilcrow"),
        FieldPanel("council_members", icon="group"),
        FieldPanel("volunteers_description", icon="pilcrow"),
        FieldPanel("volunteers", icon="group"),
        FieldPanel("employees_description", icon="pilcrow"),
        FieldPanel("employees", icon="group"),
            ],
            heading="Lidé",
        ),
    ]

    edit_handler = TabbedInterface(
        [
            ObjectList(intro_panels, heading="Základy"),
            ObjectList(people_panels, heading="Lidé"),
            ObjectList(Page.promote_panels, heading="Propagace"),
        ]
    )

    # Articles

    @property
@@ -102,7 +218,7 @@ class HomePage(Page):

    @property
    def latest_articles(self) -> "QuerySet":
        return HomeArticlePage.objects.live().all()[:3]
        return HomeArticlePage.objects.order_by("-date").live().all()[:3]

    # Events

@@ -112,20 +228,54 @@ class HomePage(Page):

    @property
    def latest_events(self) -> "QuerySet":
        return HomeEventPage.objects.live().all()[:8]
        return HomeEventPage.objects.order_by("-date").live().all()[:8]

    # Documents

    @property
    def documents_page(self) -> "HomeDocumentsPage":
        return HomeDocumentsPage.objects.live().first()
        return HomeDocumentsPage.objects.child_of(self).live().first()

    @property
    def latest_documents(self) -> "QuerySet":
        return HomeDocumentPage.objects.live().all()[:4]
    def latest_documents(self) -> list:
        documents = list(
            HomeDocumentPage.objects.child_of(self.documents_page)
            .order_by("-date")
            .live()
            .all()[:4]
        )

        # Pad documents list so it's always 4 items long
        documents += [None] * (4 - len(documents))

        document_directories = list(
            HomeDocumentsPage.objects.child_of(self.documents_page).live().all()[:4]
        )

        # Replace 0-4 last items in the list with directories
        position_in_documents = 3

        for document_directory in document_directories:
            documents[position_in_documents] = document_directory
            position_in_documents -= 1

        # Then remove the Nones we padded the list with
        return list(filter(lambda document: document is not None, documents))

    # Feed

    @path("feeds/atom/")
    def view_feed(self, request):
        # Avoid circular import
        from .feeds import LatestArticlesFeed  # noqa

        return LatestArticlesFeed()(request, self.articles_page.id)

    class Meta:
        verbose_name = "Domovká stránka"
        verbose_name = "Domovská stránka"


# --- BEGIN Articles, events, videos and documents ---


class HomeArticlesPage(Page):
@@ -140,7 +290,21 @@ class HomeArticlesPage(Page):

    @property
    def articles(self):
        return HomeArticlePage.objects.live().all()
        return HomeArticlePage.objects.live().order_by("-date")

    def get_context(self, request):
        context = super().get_context(request)
        articles = self.articles

        # Filter by tag
        tag = request.GET.get("tag")
        if tag:
            articles = articles.filter(tags__name=tag)
            context["filtered_tag"] = tag

        context["articles"] = articles

        return context

    class Meta:
        verbose_name = "Rozcestník článků"
@@ -158,7 +322,7 @@ class HomeEventsPage(Page):

    @property
    def events(self):
        return HomeEventPage.objects.live().all()
        return HomeEventPage.objects.live().order_by("-date").all()

    class Meta:
        verbose_name = "Rozcestník akcí"
@@ -168,7 +332,7 @@ class HomeDocumentsPage(Page):
    content = RichTextField(verbose_name="Obsah", blank=True, null=True)

    parent_page_type = ["home.HomePage"]
    subpage_types = ["home.HomeDocumentPage"]
    subpage_types = ["home.HomeDocumentPage", "home.HomeDocumentsPage"]

    content_panels = Page.content_panels + [
        FieldPanel("content", icon="pilcrow"),
@@ -176,17 +340,50 @@ class HomeDocumentsPage(Page):

    @property
    def documents(self):
        return HomeDocumentPage.objects.live().all()
        documents = list(
            HomeDocumentPage.objects.child_of(self).order_by("-date").live().all()
        )

        document_directories = list(
            HomeDocumentsPage.objects.child_of(self).live().all()
        )

        return documents + document_directories

    class Meta:
        verbose_name = "Rozcestník dokumentů"


class HomeVideosPage(Page):
    content = RichTextField(verbose_name="Obsah", blank=True, null=True)

    parent_page_type = ["home.HomePage"]
    subpage_types = ["home.HomeVideoPage"]

    content_panels = Page.content_panels + [
        FieldPanel("content", icon="pilcrow"),
    ]

    @property
    def videos(self):
        return HomeVideoPage.objects.live().order_by("-date").all()

    class Meta:
        verbose_name = "Rozcestník videí"


class HomeContentPageMixin(Page):
    tags = models.ManyToManyField("Tag", verbose_name="Štítky")
    author_page = models.ForeignKey(
        "home.HomePersonPage",
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        verbose_name="Stránka autora",
        help_text="Pokud je vybrána stránka, není nutno vyplňovat jméno autora níže.",
    )

    author = models.CharField(
        verbose_name="Autor",
        verbose_name="Jméno autora",
        max_length=128,
        blank=True,
        null=True,
@@ -199,7 +396,13 @@ class HomeContentPageMixin(Page):
    parent_page_type = ["home.HomeArticlesPage"]

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel("author_page", icon="user"),
                FieldPanel("author", icon="user"),
            ],
            heading="Autor",
        ),
        FieldPanel("date", icon="calendar"),
        FieldPanel("content", icon="pilcrow"),
    ]
@@ -213,21 +416,71 @@ class HomeContentPageMixin(Page):

    class Meta:
        abstract = True
        ordering = ["-date"]


class HomeArticlePage(HomeContentPageMixin):
    image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        verbose_name="Obrázek",
    )

    content = RichTextField(
        verbose_name="Obsah",
        features=[
            "h2",
            "h3",
            "h4",
            "bold",
            "italic",
            "ol",
            "ul",
            "hr",
            "link",
            "document-link",
            "image",
            "embed",
            "footnotes",
        ],
    )

    show_image_on_homepage = models.BooleanField(
        verbose_name="Zobrazovat obrázek na homepage",
        default=False,
    )

    tags = ClusterTaggableManager(
        through=TaggedArticle, blank=True, verbose_name="Štítky"
    )

    perex = models.TextField(verbose_name="Perex")

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel("author_page", icon="user"),
                FieldPanel("author", icon="user"),
            ],
            heading="Autor",
        ),
        MultiFieldPanel(
            [
                FieldPanel("image", icon="image", heading=" "),
                FieldPanel("show_image_on_homepage"),
            ],
            heading="Obrázek",
        ),
        FieldPanel("date", icon="calendar"),
        FieldPanel("perex", icon="pilcrow"),
        FieldPanel("tags", icon="tag"),
        FieldPanel("content", icon="pilcrow"),
        InlinePanel("footnotes", label="Footnotes", icon="pilcrow"),
    ]

    class Meta:
        ordering = ["-date"]
        verbose_name = "Článek"


@@ -242,12 +495,17 @@ class HomeEventPage(HomeContentPageMixin):
    content_panels = Page.content_panels + [
        FieldPanel("date", icon="calendar"),
        FieldPanel("location", icon="globe"),
        MultiFieldPanel(
            [
                FieldPanel("author_page", icon="user"),
                FieldPanel("author", icon="user"),
            ],
            heading="Autor",
        ),
        FieldPanel("content", icon="pilcrow"),
    ]

    class Meta:
        ordering = ["-date"]
        verbose_name = "Akce"


@@ -258,21 +516,163 @@ class HomeDocumentPage(HomeContentPageMixin):

    content = RichTextField(verbose_name="Obsah", blank=True, null=True)

    subpage_types = ["home.HomeDocumentPage"]

    content_panels = Page.content_panels + [
        FieldPanel("document", icon="doc-full"),
        MultiFieldPanel(
            [
                FieldPanel("author_page", icon="user"),
                FieldPanel("author", icon="user"),
            ],
            heading="Autor",
        ),
        FieldPanel("date", icon="calendar"),
        FieldPanel("content", icon="pilcrow"),
    ]

    class Meta:
        ordering = ["-date"]
        verbose_name = "Dokument"


class Tag(models.Model):
    name = models.CharField(verbose_name="Jméno", max_length=32)
class HomeVideoPage(HomeContentPageMixin):
    embed_url = models.URLField(
        verbose_name="URL Embedu",
        help_text="Pro získání adresy zmáčkni tlačítko Sdílet, vyber záložku Embed a zaškrtní zobrazování pouze URL.",
    )

    thumbnail = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        verbose_name="Náhledový obrázek",
    )

    content = RichTextField(verbose_name="Obsah", blank=True, null=True)

    content_panels = Page.content_panels + [
        FieldPanel("embed_url", icon="link"),
        FieldPanel("thumbnail", icon="image"),
        MultiFieldPanel(
            [
                FieldPanel("author_page", icon="user"),
                FieldPanel("author", icon="user"),
            ],
            heading="Autor",
        ),
        FieldPanel("date", icon="calendar"),
        FieldPanel("content", icon="pilcrow"),
    ]

    class Meta:
        verbose_name = "Štítek"
        verbose_name_plural = "Štítky"
        verbose_name = "Video"


# --- END Articles, events, videos and documents ---
# --- BEGIN People ---


class HomePeoplePage(Page):
    content = RichTextField(verbose_name="Obsah", blank=True, null=True)

    parent_page_type = ["home.HomePage"]
    subpage_types = ["home.HomePersonPage"]

    content_panels = Page.content_panels + [
        FieldPanel("content", icon="pilcrow"),
    ]

    @property
    def people(self):
        return HomePersonPage.objects.live().order_by("title").all()

    class Meta:
        verbose_name = "Rozcestník osob"


class HomePersonPage(Page):
    image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="+",
        verbose_name="Profilový obrázek",
    )

    name_titles = models.CharField(
        max_length=32,
        blank=True,
        null=True,
        verbose_name="Tituly",
    )

    position = models.TextField(verbose_name="Pracovní pozice", blank=True, null=True)

    email = models.EmailField(verbose_name="Emailová adresa", blank=True, null=True)

    description = RichTextField(verbose_name="Popis", blank=True, null=True)

    content_panels = Page.content_panels + [
        FieldPanel("name_titles", icon="pilcrow"),
        FieldPanel("image", icon="image"),
        FieldPanel("position", icon="pilcrow"),
        FieldPanel("email", icon="mail"),
        FieldPanel("description", icon="pilcrow"),
    ]

    @property
    def full_name(self) -> str:
        name = self.title

        if self.name_titles is not None:
            name = f"{self.name_titles} {name}"

        return name

    @property
    def inline_position(self) -> str:
        """Returns this person's position formatted to fit on a single line."""

        if self.position is None:
            return None

        split_positions = self.position.split("\n")
        split_positions = [position.strip() for position in split_positions]

        return ", ".join(split_positions)

    class Meta:
        verbose_name = "Osoba"


# --- END People ---
# --- BEGIN Settings ---


@register_setting
class SocialMediaSettings(BaseSiteSetting):
    mastodon = models.URLField(blank=True, null=True, help_text="Mastodon URL")
    twitter = models.URLField(blank=True, null=True, help_text="Twitter URL")
    linkedin = models.URLField(blank=True, null=True, help_text="LinkedIn URL")
    facebook = models.URLField(blank=True, null=True, help_text="Facebook URL")

    panels = [
        MultiFieldPanel(
            [
                FieldPanel("mastodon"),
                FieldPanel("twitter"),
                FieldPanel("linkedin"),
                FieldPanel("facebook"),
            ],
            heading="Nastavení sociálních sítí",
        )
    ]

    class Meta:
        verbose_name = "Sociální sítě"


# --- END Settings ---
Original line number Diff line number Diff line
@font-face {
    font-family: "pirati-ui";
    src:
        url("./pirati-ui.eot") format("embedded-opentype"),
        url("./pirati-ui.ttf") format("truetype"),
        url("./pirati-ui.woff") format("woff"),
        url("./pirati-ui.svg") format("svg");
    font-weight: normal;
    font-style: normal;
    font-display: block;
}

[class^="ico--"], [class*=" ico--"] {
  /* use !important to prevent issues with browser extensions that change fonts */
  font-family: 'pirati-ui' !important;
  speak: never;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;

  /* Better Font Rendering =========== */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.ico--mastodon:before {
  content: "\e973";
}
.ico--helios:before {
  content: "\e96e";
}
.ico--redmine:before {
  content: "\e96f";
}
.ico--zulip:before {
  content: "\e970";
}
.ico--forum:before {
  content: "\e971";
}
.ico--pirati:before {
  content: "\e90d";
}
.ico--jitsi:before {
  content: "\e90f";
}
.ico--open-source:before {
  content: "\e90e";
}
.ico--donation-full:before {
  content: "\e96c";
}
.ico--donation-outline:before {
  content: "\e96d";
}
.ico--strategy:before {
  content: "\e932";
}
.ico--pig:before {
  content: "\e928";
}
.ico--thermometer:before {
  content: "\e90a";
}
.ico--menu:before {
  content: "\e933";
}
.ico--chevron-right:before {
  content: "\e923";
}
.ico--chevron-left:before {
  content: "\e924";
}
.ico--chevron-down:before {
  content: "\e925";
}
.ico--chevron-up:before {
  content: "\e926";
}
.ico--link-horizontal:before {
  content: "\e910";
}
.ico--beer:before {
  content: "\e909";
}
.ico--food:before {
  content: "\e968";
}
.ico--dots-three-vertical:before {
  content: "\e940";
}
.ico--dots-three-horizontal:before {
  content: "\e941";
}
.ico--log-out:before {
  content: "\e942";
}
.ico--envelope:before {
  content: "\e908";
}
.ico--pin:before {
  content: "\e943";
}
.ico--at:before {
  content: "\e905";
}
.ico--glass:before {
  content: "\e967";
}
.ico--checkmark:before {
  content: "\e965";
}
.ico--info:before {
  content: "\e901";
}
.ico--question:before {
  content: "\e904";
}
.ico--warning:before {
  content: "\e93f";
}
.ico--code:before {
  content: "\e94a";
}
.ico--checkbox-unchecked:before {
  content: "\e94e";
}
.ico--star-full:before {
  content: "\e94f";
}
.ico--star-empty:before {
  content: "\e950";
}
.ico--bookmark:before {
  content: "\e951";
}
.ico--cog:before {
  content: "\e952";
}
.ico--key:before {
  content: "\e953";
}
.ico--zoom-in:before {
  content: "\e954";
}
.ico--zoom-out:before {
  content: "\e955";
}
.ico--shrink:before {
  content: "\e956";
}
.ico--printer:before {
  content: "\e957";
}
.ico--file-openoffice:before {
  content: "\e958";
}
.ico--user:before {
  content: "\e959";
}
.ico--file-excel:before {
  content: "\e95a";
}
.ico--file-word:before {
  content: "\e95b";
}
.ico--file-pdf:before {
  content: "\e95c";
}
.ico--file-picture:before {
  content: "\e95d";
}
.ico--file-blank:before {
  content: "\e95e";
}
.ico--folder-upload:before {
  content: "\e95f";
}
.ico--upload:before {
  content: "\e960";
}
.ico--cloud-upload:before {
  content: "\e961";
}
.ico--folder-download:before {
  content: "\e962";
}
.ico--download:before {
  content: "\e963";
}
.ico--cloud-download:before {
  content: "\e964";
}
.ico--alarm:before {
  content: "\e900";
}
.ico--calculator:before {
  content: "\e911";
}
.ico--facebook-full:before {
  content: "\e913";
}
.ico--feed:before {
  content: "\e927";
}
.ico--library:before {
  content: "\e929";
}
.ico--office:before {
  content: "\e92a";
}
.ico--attachment:before {
  content: "\e92b";
}
.ico--enlarge:before {
  content: "\e92c";
}
.ico--eye-off:before {
  content: "\e92e";
}
.ico--eye:before {
  content: "\e92f";
}
.ico--share:before {
  content: "\e931";
}
.ico--search:before {
  content: "\e939";
}
.ico--pencil:before {
  content: "\e93c";
}
.ico--lock-open:before {
  content: "\e947";
}
.ico--lock:before {
  content: "\e948";
}
.ico--equalizer:before {
  content: "\e949";
}
.ico--switch:before {
  content: "\e94b";
}
.ico--loop:before {
  content: "\e94c";
}
.ico--refresh:before {
  content: "\e94d";
}
.ico--bullhorn:before {
  content: "\e944";
}
.ico--bin:before {
  content: "\e945";
}
.ico--cross:before {
  content: "\e937";
}
.ico--checkbox-checked:before {
  content: "\e938";
}
.ico--globe:before {
  content: "\e93a";
}
.ico--wikipedia:before {
  content: "\e93b";
}
.ico--youtube:before {
  content: "\e936";
}
.ico--users:before {
  content: "\e934";
}
.ico--book:before {
  content: "\e935";
}
.ico--bubbles:before {
  content: "\e930";
}
.ico--map:before {
  content: "\e914";
}
.ico--compass:before {
  content: "\e915";
}
.ico--folder-open:before {
  content: "\e916";
}
.ico--folder:before {
  content: "\e917";
}
.ico--drawer:before {
  content: "\e918";
}
.ico--stop:before {
  content: "\e919";
}
.ico--github:before {
  content: "\e91a";
}
.ico--clock:before {
  content: "\e91b";
}
.ico--calendar:before {
  content: "\e91c";
}
.ico--flickr:before {
  content: "\e91d";
}
.ico--instagram:before {
  content: "\e91e";
}
.ico--twitter:before {
  content: "\e91f";
}
.ico--newspaper:before {
  content: "\e920";
}
.ico--cart:before {
  content: "\e921";
}
.ico--home:before {
  content: "\e922";
}
.ico--link:before {
  content: "\e912";
}
.ico--power:before {
  content: "\e90c";
}
.ico--rocket:before {
  content: "\e946";
}
.ico--location:before {
  content: "\e906";
}
.ico--phone:before {
  content: "\e907";
}
.ico--linkedin:before {
  content: "\e903";
}
.ico--facebook:before {
  content: "\e902";
}
.ico--envelop:before {
  content: "\e972";
}
.ico--bed:before {
  content: "\e969";
}
.ico--train:before {
  content: "\e96a";
}
.ico--bus:before {
  content: "\e96b";
}
.ico--wheelchair:before {
  content: "\e966";
}
.ico--thumbs-down:before {
  content: "\e93d";
}
.ico--thumbs-up:before {
  content: "\e93e";
}
.ico--anchor:before {
  content: "\e92d";
}
.ico--paw:before {
  content: "\e90b";
}
Original line number Diff line number Diff line
<li>
    <div class="flex gap-2">
        <div class="flex gap-2">
            <a href="{{ page.url }}">
                {% if page.position %}
                    <strong>{{ page.full_name }}</strong>
                {% else %}
                    {{ page.full_name }}
                {% endif %}
            </a>

            {% if page.email %}
                <a href="mailto:{{ page.email }}">
                    <div class="flex items-center">
                        <i class="ico--at text-xl text-pii-cyan"></i>
                    </div>
                </a>
            {% endif %}
        </div>
    </div>

    {% if page.position %}
        <p class="leading-4 whitespace-pre-line">{{ page.position }}</p>
    {% endif %}
</li>
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags %}
{% load static wagtailcore_tags wagtailimages_tags footnotes %}

{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl">{{ page.title }}</h1>

        <small class="text-pii-cyan uppercase font-bold">
            {% for tag in page.tags.all %}
                <a
                    href="/clanky?tag={{ tag.name }}"
                    class="px-2 py-0.5 rounded-sm"
                    style="background-color:{{ tag.bg_color }};color:{{ tag.fg_color }}"
                >{{ tag.name }}</a>&nbsp;
            {% endfor %}
        </small>

        <div class="flex flex-col gap-1 mt-3 text-gray-700">
            <div class="flex gap-2 items-center">
                <i class="ico--calendar"></i>
                <div>{{ page.date }}</div>
            </div>
            {% if page.author %}

            {% if page.author_page %}
                <a
                    class="flex gap-2 items-center"
                    href="{{ page.author_page.url }}"
                >
                    <i class="ico--user"></i>
                    <div>{{ page.author_page.title }}</div>
                </a>
            {% elif page.author %}
                <div class="flex gap-2 items-center">
                    <i class="ico--user"></i>
                    <div>{{ page.author }}</div>
@@ -20,10 +39,17 @@
        </div>

        <div class="mt-5 prose max-w-screen-md font-serif">
            {% if page.image %}
                {% image page.image original as article_image %}
                <img src="{{ article_image.url }}">
            {% endif %}

            <p class="mb-3">{{ page.perex }}</p>

            {{ page.content|richtext }}
            {% richtext_footnotes page.content|richtext %}

            {% include "home/includes/footnotes.html" %}
        </div>
    </div>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags %}
{% load static wagtailcore_tags wagtailimages_tags %}

{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl mb-4">{{ page.title }}</h1>

        {% if filtered_tag %}
            <div class="text-gray-500 mb-5">
                <span>Filtrovaný štítek: <strong>{{ filtered_tag }}</strong></span>
                <br>
                <a href="/clanky">
                    <i class="ico--chevron-left"></i>
                    <span class="underline">Zpět na seznam</span>
                </a>
            </div>
        {% endif %}

        {% if page.content %}
            <div class="prose font-serif mb-3">
                {{ page.content|richtext }}
            </div>
        {% endif %}

        <ul class="flex gap-4 lg:h-96 flex-wrap">
            {% for article in page.articles %}
                <li class="bg-pii-cyan text-white p-7 lg:w-80">
                    <a
                        class="flex flex-col gap-2 h-full"
                        href="{{ article.url }}"
        <ul class="flex gap-4 flex-wrap">
            {% for article in articles %}
                <li class="bg-pii-cyan lg:h-96 text-white w-full lg:w-80 drop-shadow-lg">
                    <a href="{{ article.url }}">
                        {% if article.image and article.show_image_on_homepage %}
                            {% image article.image max-400x400 as article_image %}
                            <img
                                class="w-full bg-white max-h-48 object-cover"
                                src="{{ article_image.url }}"
                                alt="Náhledový obrázek článku"
                            >
                        <small class="text-pii-cyan uppercase font-bold">
                        {% endif %}

                        <div class="p-7 flex flex-col gap-2 h-full">
                            <small class="text-white uppercase font-bold">
                                {% for tag in article.tags.all %}
                                {{ tag.name }}
                                    <span
                                        class="px-2 py-0.5 rounded-sm"
                                        style="background-color:{{ tag.bg_color }};color:{{ tag.fg_color }}"
                                    >{{ tag.name }}</span>&nbsp;
                                {% endfor %}
                            </small>
                            <h3 class="font-serif text-xl leading-6 font-bold">{{ article.title }}</h3>

                            {% if not article.image or not article.show_image_on_homepage %}
                                <p class="font-serif leading-5 grow">
                                    {{ article.shortened_perex }}
                                </p>
                            {% endif %}

                            <small class="font-serif">
                                Přidáno {{ article.date }}
                            </small>
                        </div>
                    </a>
                </li>
            {% endfor %}
        </ul>
    </div>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
@@ -6,12 +6,29 @@
    <div class="container">
        <h1 class="font-bebas text-4xl">{{ page.title }}</h1>

        {% if page.author %}
            <div class="flex gap-2 mt-3 items-center text-gray-700">
        <div class="flex flex-col gap-1 mt-3 text-gray-700">
            {% if page.date %}
                <div class="flex gap-2 items-center">
                    <i class="ico--calendar"></i>
                    <div>{{ page.date }}</div>
                </div>
            {% endif %}

            {% if page.author_page %}
                <a
                    class="flex gap-2 items-center"
                    href="{{ page.author_page.url }}"
                >
                    <i class="ico--user"></i>
                    <div>{{ page.author_page.title }}</div>
                </a>
            {% elif page.author %}
                <div class="flex gap-2 items-center">
                    <i class="ico--user"></i>
                    <div>{{ page.author }}</div>
                </div>
            {% endif %}
        </div>

        <div class="mt-5 prose max-w-screen-md font-serif">
            {{ page.content|richtext }}
@@ -29,4 +46,4 @@
        </div>
    </div>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
            </div>
        {% endif %}

        <ul class="flex flex-col gap-2 list-disc ml-3">
        <ul class="flex flex-col gap-2 list-disc ml-3 font-serif">
            {% for document in page.documents %}
                <li>
                    <a
@@ -26,4 +26,4 @@
        </ul>
    </div>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
@@ -21,7 +21,15 @@
                </div>
            {% endif %}

            {% if page.author %}
            {% if page.author_page %}
                <a
                    class="flex gap-2 items-center"
                    href="{{ page.author_page.url }}"
                >
                    <i class="ico--user"></i>
                    <div>{{ page.author_page.title }}</div>
                </a>
            {% elif page.author %}
                <div class="flex gap-2 items-center">
                    <i class="ico--user"></i>
                    <div>{{ page.author }}</div>
@@ -34,4 +42,4 @@
        </div>
    </div>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
@@ -12,23 +12,22 @@
            </div>
        {% endif %}

        <ul class="flex flex-col gap-2 list-disc ml-3">
        <ul class="flex flex-col gap-2 list-disc ml-3 font-serif">
            {% for event in page.events %}
                <li class="text-gray-500">
                    <a
                        class="flex gap-3"
                        class="flex flex-col flex-wrap"
                        href="{{ event.url }}"
                    >
                        <div class="underline text-black">{{ event.title }}</div>
                        <div>
                            {{ event.date }}{% if event.location %},
                                {{ event.location }}
                            {% endif %}
                                {{ event.location }}{% endif %}
                        </div>
                        <div class="underline text-black">{{ event.title }}</div>
                    </a>
                </li>
            {% endfor %}
        </ul>
    </div>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags %}
{% load static wagtailcore_tags wagtailimages_tags %}

{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container flex gap-10">
        <figure class="w-32 flex-col gap-2 hidden lg:flex">
            <img
                src="{% static 'images/logo_big.png' %}"
                src="{% static 'home/images/logo_big.png' %}"
                alt="Logo"
            >
            <figcaption class="font-sans leading-4">
@@ -26,25 +26,38 @@

            <ul class="flex gap-4 lg:h-96 lg:flex-nowrap flex-wrap">
                {% for article in page.latest_articles %}
                    <li class="bg-white p-7 lg:w-80">
                        <a
                            class="flex flex-col gap-2 h-full"
                            href="{{ article.url }}"
                    <li class="bg-white lg:w-80">
                        <a href="{{ article.url }}">
                            {% if article.image and article.show_image_on_homepage %}
                                {% image article.image max-400x400 as article_image %}
                                <img
                                    class="w-full max-h-48 object-cover"
                                    src="{{ article_image.url }}"
                                    alt="Náhledový obrázek článku"
                                >
                            {% endif %}

                            <div class="p-7 flex flex-col gap-2 h-full">
                                <small class="text-pii-cyan uppercase font-bold">
                                    {% for tag in article.tags.all %}
                                    {{ tag.name }}
                                        <span
                                            class="px-2 py-0.5 rounded-sm"
                                            style="background-color:{{ tag.bg_color }};color:{{ tag.fg_color }}"
                                        >{{ tag.name }}</span>&nbsp;
                                    {% endfor %}
                                </small>
                                <h3 class="font-serif text-xl leading-6 font-bold">{{ article.title }}</h3>

                                {% if not article.image or not article.show_image_on_homepage %}
                                    <p class="font-serif leading-5 grow">
                                        {{ article.shortened_perex }}
                                    </p>
                                {% endif %}

                                <small class="font-serif">
                                    Přidáno {{ article.date }}
                                </small>
                            </div>
                        </a>
                    </li>
                {% endfor %}
@@ -164,8 +177,10 @@
        </div>
    </section>

    <section class="container flex flex-col gap-3" id="dary">
        <h2 class="font-bebas text-3xl uppercase leading-7">Dary</h2>
    <section class="container flex flex-col gap-3">
        <span class="invisible relative top-[-8rem]" id="finance"></span>

        <h2 class="font-bebas text-3xl uppercase leading-7">Finance</h2>

        <div>
            <h3 class="font-serif text-2xl font-bold">Podpořte institut π</h3>
@@ -176,7 +191,9 @@
        </div>
    </section>

    <section class="flex justify-center bg-grey-50 p-10 w-full" id="kontakty">
    <section class="flex justify-center bg-grey-50 p-10 w-full">
        <span class="invisible relative top-[-8rem]" id="kontakty"></span>

        <div class="container flex flex-col gap-3">
            <h2 class="font-bebas text-3xl uppercase leading-7">Kontakty</h2>

@@ -210,67 +227,79 @@
        </div>
    </section>

    <section class="container flex flex-col gap-3" id="lide">
    <section class="container flex flex-col gap-3">
        <span class="invisible relative top-[-8rem]" id="lide"></span>

        <h2 class="font-bebas text-3xl uppercase leading-7">Lidé</h2>

        <div class="flex flex-col lg:grid lg:grid-cols-3 gap-20 min-h-screen">
            <div class="flex flex-col gap-5 font-serif">
                <section class="flex flex-col gap-4">
                    <h3 class="text-2xl font-bold">Ředitel</h3>
                    <p>
                        Ředitel je statutárním orgánem ústavu,
                        řídí jeho činnost, jedná jeho jménem
                        a rozhoduje ve všech záležitostech, které
                        nespadají do pravomoci jiných orgánů.
                    </p>
                    <div>
                        {{ page.director_description|richtext }}
                    </div>

                    <ul>
                    <ul class="flex flex-col gap-3">
                        {% for block in page.director %}
                            {% if block.block_type == "person" %}
                                {% include_block block %}
                            {% else %}
                                {% include "home/blocks/person_page_block.html" with page=block.value %}
                            {% endif %}
                        {% endfor %}
                    </ul>
                </section>

                <section class="flex flex-col gap-4">
                    <h3 class="text-2xl font-bold">Akademická rada</h3>
                    <p>
                        Akademická rada je poradním orgánem
                        ústavu a v rámci své činnosti zejména
                        poskytuje správní radě stanoviska
                        k ideovému směřování, strategickým
                        materiálům, rozpočtu a plánu činností
                        ústavu. Dále vykonává akademická rada
                        dohled nad ideovou a odbornou kvalitou
                        výstupů ústavu.
                    </p>
                    <div>
                        {{ page.academic_council_description|richtext }}
                    </div>

                    <ul class="flex flex-col gap-3">
                        {% for block in page.academic_council %}
                            {% if block.block_type == "person" %}
                                {% include_block block %}
                            {% else %}
                                {% include "home/blocks/person_page_block.html" with page=block.value %}
                            {% endif %}
                        {% endfor %}
                    </ul>
                </section>
            </div>

            <div class="flex flex-col gap-5 font-serif">
                <section class="flex flex-col gap-4">
                    <h3 class="text-2xl font-bold">Kontrolor</h3>
                    <p>
                        Kontrolor je kontrolním orgánem ústavu.
                    </p>
                    <div>
                        {{ page.controller_description|richtext }}
                    </div>

                    <ul>
                    <ul class="flex flex-col gap-3">
                        {% for block in page.controller %}
                            {% if block.block_type == "person" %}
                                {% include_block block %}
                            {% else %}
                                {% include "home/blocks/person_page_block.html" with page=block.value %}
                            {% endif %}
                        {% endfor %}
                    </ul>
                </section>
            </div>
            <div class="font-serif">
                <section class="flex flex-col gap-4">
                    <h3 class="text-2xl font-bold">Správní rada</h3>

                    <p>
                        Správní rada dbá o zachování účelu, pro
                        nějž byl ústav založen, a dohlíží na řádné
                        hospodaření s jeho majetkem.
                    </p>
                    <div>
                        {{ page.council_members_description|richtext }}
                    </div>

                    <ul class="flex flex-col gap-3">
                        {% for block in page.council_members %}
                            {% if block.block_type == "person" %}
                                {% include_block block %}
                            {% else %}
                                {% include "home/blocks/person_page_block.html" with page=block.value %}
                            {% endif %}
                        {% endfor %}
                    </ul>
                </section>
@@ -278,20 +307,19 @@
            <div class="font-serif">
                <section class="flex flex-col gap-4">
                    <h3 class="text-2xl font-bold">Dobrovolnický kruh</h3>
                    <p>
                        Dobrovolnický kruh je participační orgán
                        ústavu. Účelem dobrovolnického kruhu je
                        sdružovat osoby, které se chtějí dobrovolně
                        podílet na činnostech ústavu, a navrhovat
                        správní radě projekty pro realizaci ústavem
                        v souladu s účelem ústavu.
                    </p>
                    <div>
                        {{ page.volunteers_description|richtext }}
                    </div>
                    <h4>
                        <strong>Členové dobrovolnického kruhu</strong>
                    </h4>
                    <ul class="flex flex-col leading-5">
                        {% for block in page.volunteers %}
                            {% if block.block_type == "person" %}
                                {% include_block block %}
                            {% else %}
                                {% include "home/blocks/person_page_block.html" with page=block.value %}
                            {% endif %}
                        {% endfor %}
                    </ul>
                </section>
@@ -302,17 +330,19 @@
            <h3 class="font-bold font-serif text-2xl">Zaměstnanci</h3>

            <ul class="flex flex-col lg:grid lg:grid-cols-3 lg:grid-rows-3 gap-y-2 gap-x-4 grid-flow-col font-serif">
                <p class="leading-5">
                    Zaměstnanci poskytují administrativní,<br>
                    organizační a expertní podporu pro<br>
                    vykonávání činností ústavu.
                </p>
                <div class="leading-5">
                    {{ page.employees_description|richtext }}
                </div>

                {% for block in page.employees %}
                    {% if block.block_type == "person" %}
                        {% include_block block %}
                    {% else %}
                        {% include "home/blocks/person_page_block.html" with page=block.value %}
                    {% endif %}
                {% endfor %}
            </ul>
        </section>
    </section>
</main>
{% endblock content %}
{% endblock %}
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags %}

{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl mb-4">{{ page.title }}</h1>

        {% if page.content %}
            <div class="prose font-serif mb-3">
                {{ page.content|richtext }}
            </div>
        {% endif %}

        <ul class="flex flex-col gap-2 list-disc ml-3 font-serif">
            {% for person in page.people %}
                <li>
                    <div class="flex flex-col">
                        <a
                            class="underline"
                            href="{{ person.url }}"
                        >{{ person.full_name }}</a>

                        {% if person.position %}
                            <span class="text-gray-500">{{ person.inline_position }}</span>
                        {% endif %}
                    </div>
                </li>
            {% endfor %}
        </ul>
    </div>
</main>
{% endblock %}
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags wagtailimages_tags %}

{% block content %}
<main class="flex justify-center pt-14">
    <div class="container flex flex-col gap-5">
        <div class="flex gap-3">
            {% if page.image %}
                {% image page.image max-400x400 as profile_image %}

                <img
                    class="rounded-full w-40 h-40"
                    src="{{ profile_image.url }}"
                    alt="Profilový obrázek osoby {{ page.full_name }}"
                >
            {% endif %}
            <div class="flex flex-col">
                <h1 class="font-bebas text-4xl">{{ page.full_name }}</h1>

                {% if page.position %}
                    <div class="text-gray-500 whitespace-pre-line font-serif">{{ page.position }}</div>
                {% endif %}

                {% if page.email %}
                    <hr class="my-2">

                    <a class="flex gap-2 font-serif text-gray-500" href="mailto:{{ page.email }}">
                        <div class="flex items-center">
                            <i class="ico--at text-xl"></i>
                        </div>
                        <span>{{ page.email }}</span>
                    </a>
                {% endif %}
            </div>
        </div>

        {% if page.description %}
            <div class="prose max-w-screen-md font-serif">
                {{ page.description|richtext }}
            </div>
        {% endif %}
    </div>
</main>
{% endblock %}
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags %}

{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl">{{ page.title }}</h1>

        <div class="flex flex-col gap-1 mt-3 text-gray-700">
            {% if page.date %}
                <div class="flex gap-2 items-center">
                    <i class="ico--calendar"></i>
                    <div>{{ page.date }}</div>
                </div>
            {% endif %}

            {% if page.author_page %}
                <a
                    class="flex gap-2 items-center"
                    href="{{ page.author_page.url }}"
                >
                    <i class="ico--user"></i>
                    <div>{{ page.author_page.title }}</div>
                </a>
            {% elif page.author %}
                <div class="flex gap-2 items-center">
                    <i class="ico--user"></i>
                    <div>{{ page.author }}</div>
                </div>
            {% endif %}
        </div>

        {% if page.content %}
            <div class="mt-5 prose max-w-screen-md font-serif">
                {{ page.content|richtext }}
            </div>
        {% endif %}

        <div class="mt-5 lg:mt-7 flex justify-center">
            <iframe
                class="lg:w-[850px] lg:h-[478px] md:w-[600px] md:h-[366px] w-full h-[200px]"
                src="{{ page.embed_url }}"
                frameborder="0"
                allowfullscreen=""
                sandbox="allow-same-origin allow-scripts allow-popups"
            ></iframe>
        </div>
    </div>
</main>
{% endblock %}
Original line number Diff line number Diff line
{% extends "base.html" %}
{% load static wagtailcore_tags wagtailimages_tags %}

{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl mb-4">{{ page.title }}</h1>

        {% if page.content %}
            <div class="prose font-serif mb-5">
                {{ page.content|richtext }}
            </div>
        {% endif %}

        <ul class="flex flex-col gap-5 font-serif">
            {% for video in page.videos %}
                <a href="{{ video.url }}">
                    <li class="
                        flex gap-6 md:flex-row flex-col
                        {% if not forloop.last %}
                            border-b border-gray-100 pb-5
                        {% endif %}
                    ">
                        <div class="drop-shadow-lg bg-white">
                            {% image video.thumbnail max-500x500 as thumbnail_image %}
                            <img
                                class="md:h-40 md:w-64 w-full max-h-48 object-cover"
                                src="{{ thumbnail_image.url }}"
                                alt="Náhledový obrázek videa"
                            >
                        </div>
                        <div class="flex flex-col">
                            <h2 class="text-lg font-bold">{{ video.title }}</h2>
                            <span class="text-gray-500">{{ video.date }}</span>
                        </div>
                    </li>
                </a>
            {% endfor %}
        </ul>
    </div>
</main>
{% endblock %}
Original line number Diff line number Diff line
{% load wagtailcore_tags %}

{% if page.footnotes_list %}
    <div class="footnotes" id="footnotes">
        <hr class="my-8">
        <ol>
            {% for footnote in page.footnotes_list %}
                <li id="footnote-{{ forloop.counter }}">
                    <div class="[&>p]:inline">
                        {{ footnote.text|richtext }}
                        &nbsp;<a
                            href="#footnote-source-{{ forloop.counter }}"
                            aria-label="Přeskočit na obsah"
                        ></a>
                    </div>
                </li>
            {% endfor %}
        </ol>
    </div>
{% endif %}
+43 −0
Original line number Diff line number Diff line
import re

from django.template import Library
from django.utils.safestring import mark_safe
from wagtail.models import Page

register = Library()


@register.simple_tag(takes_context=True)
def richtext_footnotes(context, html):
    """
    example: {% richtext_footnotes page.body|richtext %}

    html: already processed richtext field html
    Assumes "page" in context.
    """
    FIND_FOOTNOTE_TAG = re.compile(r'<footnote id="(.*?)">.*?</footnote>')

    if not isinstance(context.get("page"), Page):
        return html

    page = context["page"]
    if not hasattr(page, "footnotes_list"):
        page.footnotes_list = []
    footnotes = {str(footnote.uuid): footnote for footnote in page.footnotes.all()}

    def replace_tag(match):
        try:
            index = process_footnote(match.group(1), page)
        except (KeyError, ValidationError):
            return ""
        else:
            return f'<a href="#footnote-{index}" id="footnote-source-{index}"><sup>[{index}]</sup></a>'

    def process_footnote(footnote_id, page):
        footnote = footnotes[footnote_id]
        if footnote not in page.footnotes_list:
            page.footnotes_list.append(footnote)
        # Add 1 to the index as footnotes are indexed starting at 1 not 0.
        return page.footnotes_list.index(footnote) + 1

    return mark_safe(FIND_FOOTNOTE_TAG.sub(replace_tag, html))
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@ INSTALLED_APPS = [
    "home",
    "wagtail.contrib.forms",
    "wagtail.contrib.redirects",
    "wagtail.contrib.routable_page",
    "wagtail.contrib.settings",
    "wagtail.contrib.modeladmin",
    "wagtail.embeds",
    "wagtail.sites",
    "wagtail.users",
@@ -46,9 +49,11 @@ INSTALLED_APPS = [
    "wagtail.images",
    "wagtail.search",
    "wagtail.admin",
    "wagtail_footnotes",
    "wagtail",
    "modelcluster",
    "taggit",
    "wagtail_color_panel",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
@@ -83,6 +88,7 @@ TEMPLATES = [
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
                "wagtail.contrib.settings.context_processors.settings",
            ],
        },
    },
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ from .base import *

DEBUG = False
SECRET_KEY = env.str("SECRET_KEY")
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")

try:
    from .local import *
+0 −129
Original line number Diff line number Diff line
@font-face {
  font-family: "pirati-ui";
  src:
    url("./pirati-ui.eot") format("embedded-opentype"),
    url("./pirati-ui.ttf") format("truetype"),
    url("./pirati-ui.woff") format("woff"),
    url("./pirati-ui.svg") format("svg");
  font-weight: normal;
  font-style: normal;
  font-display: block;
}

[class^="ico--"], [class*=" ico--"] {
  /* Use !important to prevent issues with browser extensions that change fonts */
  font-family: "pirati-ui" !important;
  speak: never;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  text-transform: none;
  line-height: 1;

  /* Better Font Rendering */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.ico--dots-three-vertical:before { content: "\e940"; }
.ico--dots-three-horizontal:before { content: "\e941"; }
.ico--log-out:before { content: "\e942"; }
.ico--envelope:before { content: "\e908"; }
.ico--pin:before { content: "\e943"; }
.ico--at:before { content: "\e905"; }
.ico--strategy:before { content: "\e932"; }
.ico--pig:before { content: "\e928"; }
.ico--thermometer:before { content: "\e90a"; }
.ico--menu:before { content: "\e933"; }
.ico--chevron-right:before { content: "\e923"; }
.ico--chevron-left:before { content: "\e924"; }
.ico--chevron-down:before { content: "\e925"; }
.ico--chevron-up:before { content: "\e926"; }
.ico--link-horizontal:before { content: "\e910"; }
.ico--beer:before { content: "\e909"; }
.ico--pirati:before { content: "\e90d"; }
.ico--jitsi:before { content: "\e90f"; }
.ico--open-source:before { content: "\e90e"; }
.ico--thumbs-down:before { content: "\e93d"; }
.ico--thumbs-up:before { content: "\e93e"; }
.ico--anchor:before { content: "\e92d"; }
.ico--paw:before { content: "\e90b"; }
.ico--checkmark:before { content: "\e965"; }
.ico--info:before { content: "\e901"; }
.ico--question:before { content: "\e904"; }
.ico--warning:before { content: "\e93f"; }
.ico--code:before { content: "\e94a"; }
.ico--checkbox-unchecked:before { content: "\e94e"; }
.ico--star-full:before { content: "\e94f"; }
.ico--star-empty:before { content: "\e950"; }
.ico--bookmark:before { content: "\e951"; }
.ico--cog:before { content: "\e952"; }
.ico--key:before { content: "\e953"; }
.ico--zoom-in:before { content: "\e954"; }
.ico--zoom-out:before { content: "\e955"; }
.ico--shrink:before { content: "\e956"; }
.ico--printer:before { content: "\e957"; }
.ico--file-openoffice:before { content: "\e958"; }
.ico--user:before { content: "\e959"; }
.ico--file-excel:before { content: "\e95a"; }
.ico--file-word:before { content: "\e95b"; }
.ico--file-pdf:before { content: "\e95c"; }
.ico--file-picture:before { content: "\e95d"; }
.ico--file-blank:before { content: "\e95e"; }
.ico--folder-upload:before { content: "\e95f"; }
.ico--upload:before { content: "\e960"; }
.ico--cloud-upload:before { content: "\e961"; }
.ico--folder-download:before { content: "\e962"; }
.ico--download:before { content: "\e963"; }
.ico--cloud-download:before { content: "\e964"; }
.ico--alarm:before { content: "\e900"; }
.ico--calculator:before { content: "\e911"; }
.ico--facebook-full:before { content: "\e913"; }
.ico--feed:before { content: "\e927"; }
.ico--library:before { content: "\e929"; }
.ico--office:before { content: "\e92a"; }
.ico--attachment:before { content: "\e92b"; }
.ico--enlarge:before { content: "\e92c"; }
.ico--eye-off:before { content: "\e92e"; }
.ico--eye:before { content: "\e92f"; }
.ico--share:before { content: "\e931"; }
.ico--search:before { content: "\e939"; }
.ico--pencil:before { content: "\e93c"; }
.ico--lock-open:before { content: "\e947"; }
.ico--lock:before { content: "\e948"; }
.ico--equalizer:before { content: "\e949"; }
.ico--switch:before { content: "\e94b"; }
.ico--loop:before { content: "\e94c"; }
.ico--refresh:before { content: "\e94d"; }
.ico--bullhorn:before { content: "\e944"; }
.ico--bin:before { content: "\e945"; }
.ico--cross:before { content: "\e937"; }
.ico--checkbox-checked:before { content: "\e938"; }
.ico--globe:before { content: "\e93a"; }
.ico--wikipedia:before { content: "\e93b"; }
.ico--youtube:before { content: "\e936"; }
.ico--users:before { content: "\e934"; }
.ico--book:before { content: "\e935"; }
.ico--bubbles:before { content: "\e930"; }
.ico--map:before { content: "\e914"; }
.ico--compass:before { content: "\e915"; }
.ico--folder-open:before { content: "\e916"; }
.ico--folder:before { content: "\e917"; }
.ico--drawer:before { content: "\e918"; }
.ico--stop:before { content: "\e919"; }
.ico--github:before { content: "\e91a"; }
.ico--clock:before { content: "\e91b"; }
.ico--calendar:before { content: "\e91c"; }
.ico--flickr:before { content: "\e91d"; }
.ico--instagram:before { content: "\e91e"; }
.ico--twitter:before { content: "\e91f"; }
.ico--newspaper:before { content: "\e920"; }
.ico--cart:before { content: "\e921"; }
.ico--home:before { content: "\e922"; }
.ico--link:before { content: "\e912"; }
.ico--power:before { content: "\e90c"; }
.ico--rocket:before { content: "\e946"; }
.ico--location:before { content: "\e906"; }
.ico--phone:before { content: "\e907"; }
.ico--linkedin:before { content: "\e903"; }
.ico--facebook:before { content: "\e902"; }
Original line number Diff line number Diff line
{% extends "base.html" %}

{% block title %}Page not found{% endblock %}

{% block body_class %}template-404{% endblock %}
{% load static wagtailcore_tags %}

{% block content %}
<h1>Page not found</h1>

<h2>Sorry, this page could not be found.</h2>
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl">Stránka nenalezena</h1>

        <p class="prose font-serif">
            Stránka byla smazána, nebo se nacházela na staré verzi webu.<br>
            Nové články můžeš nalézt <a href="/clanky">zde</a>.
        </p>
    </div>
</main>
{% endblock %}
Original line number Diff line number Diff line
<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8" />
        <title>Internal server error</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
    </head>
    <body>
        <h1>Internal server error</h1>
{% extends "base.html" %}
{% load static wagtailcore_tags %}

        <h2>Sorry, there seems to be an error. Please try again soon.</h2>
    </body>
</html>
{% block content %}
<main class="flex flex-col items-center gap-10 pt-14">
    <div class="container">
        <h1 class="font-bebas text-4xl">Chyba serveru</h1>

        <p class="prose font-serif">
            Nastala chyba z naší strany. Pokud přetrvá, kontaktuj prosím správce webu.
        </p>
    </div>
</main>
{% endblock %}
Original line number Diff line number Diff line
@@ -25,17 +25,17 @@

        {# Global stylesheets #}
        <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
        <link rel="stylesheet" type="text/css" href="{% static 'fonts/pirati-ui/style.css' %}">
        <link rel="stylesheet" type="text/css" href="{% static 'home/fonts/pirati-ui/style.css' %}?v=2">
        <link
            rel="stylesheet"
            href="{% static 'fonts/bebas-neue/style.css' %}"
            href="{% static 'home/fonts/bebas-neue/style.css' %}"
        >
        <link
            rel="stylesheet"
            href="{% static 'fonts/source-serif/style.css' %}"
            href="{% static 'home/fonts/source-serif/style.css' %}"
        >

        <link rel="icon" type="image/png" href="{% static 'images/logo_big.png' %}">
        <link rel="icon" type="image/png" href="{% static 'home/images/logo_big.png' %}">

        {% block extra_css %}
        {# Override this in templates to add extra stylesheets #}
@@ -45,14 +45,15 @@
    <body>
        {% wagtailuserbar %}

        <nav class="bg-grey-800 py-8 flex justify-center">
            <div class="flex gap-7 container text-white items-center">
        <nav class="sticky top-0 drop-shadow-lg bg-grey-800 py-8 flex justify-center z-50">
            <div class="flex justify-between container">
                <div class="flex gap-7 text-white items-center">
                    <a
                        href="/"
                    >
                        <img
                            class="h-9"
                        src="{% static 'images/logo.png' %}"
                            src="{% static 'home/images/logo.png' %}"
                            alt="Logo"
                        >
                    </a>
@@ -62,13 +63,20 @@
                    ></div>

                    <div class="gap-4 hidden md:flex">
                    <a class="nav__item" href="/#uvod">Úvod</a>
                    <a class="nav__item" href="/clanky">Aktuálně</a>
                        <a class="nav__item" href="/clanky">Články</a>
                        <a class="nav__item" href="/analyzy">Analýzy</a>
                        <a class="nav__item" href="/akce">Akce</a>
                        <a class="nav__item" href="/dokumenty">Dokumenty</a>
                    <a class="nav__item" href="/#dary">Dary</a>
                    <a class="nav__item" href="/#kontakty">Kontakty</a>
                    <a class="nav__item" href="/#lide">Lidé</a>
                        <a class="nav__item" href="/lide">Lidé</a>
                        <a class="nav__item" href="/videa">Videa</a>
                        <a class="nav__item" href="/#finance">Finance</a>
                    </div>
                </div>

                <div class="md:hidden block">
                    <a href="#mobile-menu" class="text-white text-4xl">
                        <i class="ico--menu" aria-label="Otevřít menu"></i>
                    </a>
                </div>
            </div>
        </nav>
@@ -77,6 +85,95 @@
            {% block content %}{% endblock %}
        </div>

        <div class="flex justify-center bg-gray-100">
            <footer class="container text-gray-500 py-8">
                <div class="flex gap-2 justify-between items-start w-full">
                    <div class="flex flex-col gap-3">
                        <a href="https://creativecommons.org/licenses/by-sa/4.0/">
                            <img
                                class="h-8 opacity-75"
                                src="{% static 'home/images/cc-by-sa.png' %}"
                                alt="Licence CC BY-SA 4.0"
                            >
                        </a>
                        <a href="/#kontakty" class="flex gap-2 items-center max-w-max">
                            <i class="ico--envelope"></i>
                            <span>Kontakty</span>
                        </a>
                    </div>

                    <div class="flex flex-col">
                        {% if settings.home.SocialMediaSettings.mastodon %}
                            <a href="{{ settings.home.SocialMediaSettings.mastodon }}" class="flex gap-2 items-center h-8">
                                <span class="w-6 text-2xl"><i class="ico--mastodon ml-[-0.25rem]"></i></span>
                                <span>Mastodon</span>
                            </a>
                        {% endif %}
                        {% if settings.home.SocialMediaSettings.twitter %}
                            <a href="{{ settings.home.SocialMediaSettings.twitter }}" class="flex gap-2 items-center h-8">
                                <span class="w-6 text-xl font-bold">𝕏<!-- Fuck you, Twitter --></span>
                                <span>Twitter</span>
                            </a>
                        {% endif %}
                        {% if settings.home.SocialMediaSettings.linkedin %}
                            <a href="{{ settings.home.SocialMediaSettings.linkedin }}" class="flex gap-2 items-center h-8">
                                <span class="w-6 text-xl font-bold"><i class="ico--linkedin"></i></span>
                                <span>LinkedIn</span>
                            </a>
                        {% endif %}
                        {% if settings.home.SocialMediaSettings.facebook %}
                            <a href="{{ settings.home.SocialMediaSettings.facebook }}" class="flex gap-2 items-center h-8">
                                <span class="w-6 text-xl font-bold"><i class="ico--facebook"></i></span>
                                <span>Facebook</span>
                            </a>
                        {% endif %}
                        <a href="/feeds/atom" class="flex gap-2 items-center max-w-max h-8">
                            <span class="w-6"><i class="ico--feed"></i></span>
                            <span>RSS</span>
                        </a>
                    </div>
                </div>
            </footer>
        </div>

        <div class="fixed top-0 left-0 p-3 w-full h-full bg-grey-800 z-50 hidden overflow-y-auto target:block text-white" id="mobile-menu">
            <div class="flex flex-col p-3 gap-4">
                <a
                    role="button"
                    href="#"
                    aria-label="Zavřít menu"
                    title="Zavřít menu"
                >
                    <i class="ico--chevron-left text-white text-2xl"></i>
                </a>

                <div class="flex flex-col gap-1 text-2xl">
                    <a class="nav__item" href="/clanky">Články</a>
                    <a class="nav__item" href="/akce">Akce</a>
                    <a class="nav__item" href="/dokumenty">Dokumenty</a>
                    <a class="nav__item" href="/lide">Lidé</a>
                    <a class="nav__item" href="/videa">Videa</a>
                    <a class="nav__item" href="/#finance">Finance</a>
                </div>
            </div>
        </div>

        {% block extra_js %}{% endblock %}

        <!-- Matomo -->
            <script>
                var _paq = window._paq = window._paq || [];
                /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
                _paq.push(['trackPageView']);
                _paq.push(['enableLinkTracking']);
                (function() {
                    var u="//matomo.pii.cz/";
                    _paq.push(['setTrackerUrl', u+'matomo.php']);
                    _paq.push(['setSiteId', '1']);
                    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
                    g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
                })();
            </script>
        <!-- End Matomo Code -->
    </body>
</html>
Original line number Diff line number Diff line
@@ -4,10 +4,12 @@ from django.urls import include, path
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as wagtaildocs_urls
from wagtail_footnotes import urls as footnotes_urls

urlpatterns = [
    path("django-admin/", admin.site.urls),
    path("admin/", include(wagtailadmin_urls)),
    path("footnotes/", include(footnotes_urls)),
    path("documents/", include(wagtaildocs_urls)),
]

node_modules/.bin/acorn

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../acorn/bin/acorn
 No newline at end of file

node_modules/.bin/browserslist

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../browserslist/cli.js
 No newline at end of file

node_modules/.bin/cssesc

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../cssesc/bin/cssesc
 No newline at end of file

node_modules/.bin/envinfo

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../envinfo/dist/cli.js
 No newline at end of file

node_modules/.bin/jiti

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../jiti/bin/jiti.js
 No newline at end of file

node_modules/.bin/nanoid

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../nanoid/bin/nanoid.cjs
 No newline at end of file

node_modules/.bin/node-which

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../which/bin/node-which
 No newline at end of file

node_modules/.bin/resolve

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../resolve/bin/resolve
 No newline at end of file

node_modules/.bin/sucrase

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../sucrase/bin/sucrase
 No newline at end of file

node_modules/.bin/sucrase-node

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../sucrase/bin/sucrase-node
 No newline at end of file

node_modules/.bin/tailwind

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../tailwindcss/lib/cli.js
 No newline at end of file

node_modules/.bin/tailwindcss

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../tailwindcss/lib/cli.js
 No newline at end of file

node_modules/.bin/terser

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../terser/bin/terser
 No newline at end of file

node_modules/.bin/webpack

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../webpack/bin/webpack.js
 No newline at end of file

node_modules/.bin/webpack-cli

deleted120000 → 0
+0 −1
Original line number Diff line number Diff line
../webpack-cli/bin/cli.js
 No newline at end of file
+0 −128
Original line number Diff line number Diff line
declare namespace QuickLRU {
	interface Options<KeyType, ValueType> {
		/**
		The maximum number of milliseconds an item should remain in the cache.

		@default Infinity

		By default, `maxAge` will be `Infinity`, which means that items will never expire.
		Lazy expiration upon the next write or read call.

		Individual expiration of an item can be specified by the `set(key, value, maxAge)` method.
		*/
		readonly maxAge?: number;

		/**
		The maximum number of items before evicting the least recently used items.
		*/
		readonly maxSize: number;

		/**
		Called right before an item is evicted from the cache.

		Useful for side effects or for items like object URLs that need explicit cleanup (`revokeObjectURL`).
		*/
		onEviction?: (key: KeyType, value: ValueType) => void;
	}
}

declare class QuickLRU<KeyType, ValueType>
	implements Iterable<[KeyType, ValueType]> {
	/**
	The stored item count.
	*/
	readonly size: number;

	/**
	Simple ["Least Recently Used" (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29).

	The instance is [`iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.

	@example
	```
	import QuickLRU = require('quick-lru');

	const lru = new QuickLRU({maxSize: 1000});

	lru.set('🦄', '🌈');

	lru.has('🦄');
	//=> true

	lru.get('🦄');
	//=> '🌈'
	```
	*/
	constructor(options: QuickLRU.Options<KeyType, ValueType>);

	[Symbol.iterator](): IterableIterator<[KeyType, ValueType]>;

	/**
	Set an item. Returns the instance.

	Individual expiration of an item can be specified with the `maxAge` option. If not specified, the global `maxAge` value will be used in case it is specified in the constructor, otherwise the item will never expire.

	@returns The list instance.
	*/
	set(key: KeyType, value: ValueType, options?: {maxAge?: number}): this;

	/**
	Get an item.

	@returns The stored item or `undefined`.
	*/
	get(key: KeyType): ValueType | undefined;

	/**
	Check if an item exists.
	*/
	has(key: KeyType): boolean;

	/**
	Get an item without marking it as recently used.

	@returns The stored item or `undefined`.
	*/
	peek(key: KeyType): ValueType | undefined;

	/**
	Delete an item.

	@returns `true` if the item is removed or `false` if the item doesn't exist.
	*/
	delete(key: KeyType): boolean;

	/**
	Delete all items.
	*/
	clear(): void;

	/**
	Update the `maxSize` in-place, discarding items as necessary. Insertion order is mostly preserved, though this is not a strong guarantee.

	Useful for on-the-fly tuning of cache sizes in live systems.
	*/
	resize(maxSize: number): void;

	/**
	Iterable for all the keys.
	*/
	keys(): IterableIterator<KeyType>;

	/**
	Iterable for all the values.
	*/
	values(): IterableIterator<ValueType>;

	/**
	Iterable for all entries, starting with the oldest (ascending in recency).
	*/
	entriesAscending(): IterableIterator<[KeyType, ValueType]>;

	/**
	Iterable for all entries, starting with the newest (descending in recency).
	*/
	entriesDescending(): IterableIterator<[KeyType, ValueType]>;
}

export = QuickLRU;
+0 −263
Original line number Diff line number Diff line
'use strict';

class QuickLRU {
	constructor(options = {}) {
		if (!(options.maxSize && options.maxSize > 0)) {
			throw new TypeError('`maxSize` must be a number greater than 0');
		}

		if (typeof options.maxAge === 'number' && options.maxAge === 0) {
			throw new TypeError('`maxAge` must be a number greater than 0');
		}

		this.maxSize = options.maxSize;
		this.maxAge = options.maxAge || Infinity;
		this.onEviction = options.onEviction;
		this.cache = new Map();
		this.oldCache = new Map();
		this._size = 0;
	}

	_emitEvictions(cache) {
		if (typeof this.onEviction !== 'function') {
			return;
		}

		for (const [key, item] of cache) {
			this.onEviction(key, item.value);
		}
	}

	_deleteIfExpired(key, item) {
		if (typeof item.expiry === 'number' && item.expiry <= Date.now()) {
			if (typeof this.onEviction === 'function') {
				this.onEviction(key, item.value);
			}

			return this.delete(key);
		}

		return false;
	}

	_getOrDeleteIfExpired(key, item) {
		const deleted = this._deleteIfExpired(key, item);
		if (deleted === false) {
			return item.value;
		}
	}

	_getItemValue(key, item) {
		return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value;
	}

	_peek(key, cache) {
		const item = cache.get(key);

		return this._getItemValue(key, item);
	}

	_set(key, value) {
		this.cache.set(key, value);
		this._size++;

		if (this._size >= this.maxSize) {
			this._size = 0;
			this._emitEvictions(this.oldCache);
			this.oldCache = this.cache;
			this.cache = new Map();
		}
	}

	_moveToRecent(key, item) {
		this.oldCache.delete(key);
		this._set(key, item);
	}

	* _entriesAscending() {
		for (const item of this.oldCache) {
			const [key, value] = item;
			if (!this.cache.has(key)) {
				const deleted = this._deleteIfExpired(key, value);
				if (deleted === false) {
					yield item;
				}
			}
		}

		for (const item of this.cache) {
			const [key, value] = item;
			const deleted = this._deleteIfExpired(key, value);
			if (deleted === false) {
				yield item;
			}
		}
	}

	get(key) {
		if (this.cache.has(key)) {
			const item = this.cache.get(key);

			return this._getItemValue(key, item);
		}

		if (this.oldCache.has(key)) {
			const item = this.oldCache.get(key);
			if (this._deleteIfExpired(key, item) === false) {
				this._moveToRecent(key, item);
				return item.value;
			}
		}
	}

	set(key, value, {maxAge = this.maxAge === Infinity ? undefined : Date.now() + this.maxAge} = {}) {
		if (this.cache.has(key)) {
			this.cache.set(key, {
				value,
				maxAge
			});
		} else {
			this._set(key, {value, expiry: maxAge});
		}
	}

	has(key) {
		if (this.cache.has(key)) {
			return !this._deleteIfExpired(key, this.cache.get(key));
		}

		if (this.oldCache.has(key)) {
			return !this._deleteIfExpired(key, this.oldCache.get(key));
		}

		return false;
	}

	peek(key) {
		if (this.cache.has(key)) {
			return this._peek(key, this.cache);
		}

		if (this.oldCache.has(key)) {
			return this._peek(key, this.oldCache);
		}
	}

	delete(key) {
		const deleted = this.cache.delete(key);
		if (deleted) {
			this._size--;
		}

		return this.oldCache.delete(key) || deleted;
	}

	clear() {
		this.cache.clear();
		this.oldCache.clear();
		this._size = 0;
	}

	resize(newSize) {
		if (!(newSize && newSize > 0)) {
			throw new TypeError('`maxSize` must be a number greater than 0');
		}

		const items = [...this._entriesAscending()];
		const removeCount = items.length - newSize;
		if (removeCount < 0) {
			this.cache = new Map(items);
			this.oldCache = new Map();
			this._size = items.length;
		} else {
			if (removeCount > 0) {
				this._emitEvictions(items.slice(0, removeCount));
			}

			this.oldCache = new Map(items.slice(removeCount));
			this.cache = new Map();
			this._size = 0;
		}

		this.maxSize = newSize;
	}

	* keys() {
		for (const [key] of this) {
			yield key;
		}
	}

	* values() {
		for (const [, value] of this) {
			yield value;
		}
	}

	* [Symbol.iterator]() {
		for (const item of this.cache) {
			const [key, value] = item;
			const deleted = this._deleteIfExpired(key, value);
			if (deleted === false) {
				yield [key, value.value];
			}
		}

		for (const item of this.oldCache) {
			const [key, value] = item;
			if (!this.cache.has(key)) {
				const deleted = this._deleteIfExpired(key, value);
				if (deleted === false) {
					yield [key, value.value];
				}
			}
		}
	}

	* entriesDescending() {
		let items = [...this.cache];
		for (let i = items.length - 1; i >= 0; --i) {
			const item = items[i];
			const [key, value] = item;
			const deleted = this._deleteIfExpired(key, value);
			if (deleted === false) {
				yield [key, value.value];
			}
		}

		items = [...this.oldCache];
		for (let i = items.length - 1; i >= 0; --i) {
			const item = items[i];
			const [key, value] = item;
			if (!this.cache.has(key)) {
				const deleted = this._deleteIfExpired(key, value);
				if (deleted === false) {
					yield [key, value.value];
				}
			}
		}
	}

	* entriesAscending() {
		for (const [key, value] of this._entriesAscending()) {
			yield [key, value.value];
		}
	}

	get size() {
		if (!this._size) {
			return this.oldCache.size;
		}

		let oldCacheSize = 0;
		for (const key of this.oldCache.keys()) {
			if (!this.cache.has(key)) {
				oldCacheSize++;
			}
		}

		return Math.min(this._size + oldCacheSize, this.maxSize);
	}
}

module.exports = QuickLRU;
+0 −9
Original line number Diff line number Diff line
MIT License

Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+0 −43
Original line number Diff line number Diff line
{
	"name": "@alloc/quick-lru",
	"version": "5.2.0",
	"description": "Simple “Least Recently Used” (LRU) cache",
	"license": "MIT",
	"repository": "sindresorhus/quick-lru",
	"funding": "https://github.com/sponsors/sindresorhus",
	"author": {
		"name": "Sindre Sorhus",
		"email": "sindresorhus@gmail.com",
		"url": "https://sindresorhus.com"
	},
	"engines": {
		"node": ">=10"
	},
	"scripts": {
		"test": "xo && nyc ava && tsd"
	},
	"files": [
		"index.js",
		"index.d.ts"
	],
	"keywords": [
		"lru",
		"quick",
		"cache",
		"caching",
		"least",
		"recently",
		"used",
		"fast",
		"map",
		"hash",
		"buffer"
	],
	"devDependencies": {
		"ava": "^2.0.0",
		"coveralls": "^3.0.3",
		"nyc": "^15.0.0",
		"tsd": "^0.11.0",
		"xo": "^0.26.0"
	}
}
+0 −139
Original line number Diff line number Diff line
# quick-lru [![Build Status](https://travis-ci.org/sindresorhus/quick-lru.svg?branch=master)](https://travis-ci.org/sindresorhus/quick-lru) [![Coverage Status](https://coveralls.io/repos/github/sindresorhus/quick-lru/badge.svg?branch=master)](https://coveralls.io/github/sindresorhus/quick-lru?branch=master)

> Simple [“Least Recently Used” (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29)

Useful when you need to cache something and limit memory usage.

Inspired by the [`hashlru` algorithm](https://github.com/dominictarr/hashlru#algorithm), but instead uses [`Map`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map) to support keys of any type, not just strings, and values can be `undefined`.

## Install

```
$ npm install quick-lru
```

## Usage

```js
const QuickLRU = require('quick-lru');

const lru = new QuickLRU({maxSize: 1000});

lru.set('🦄', '🌈');

lru.has('🦄');
//=> true

lru.get('🦄');
//=> '🌈'
```

## API

### new QuickLRU(options?)

Returns a new instance.

### options

Type: `object`

#### maxSize

*Required*\
Type: `number`

The maximum number of items before evicting the least recently used items.

#### maxAge

Type: `number`\
Default: `Infinity`

The maximum number of milliseconds an item should remain in cache.
By default maxAge will be Infinity, which means that items will never expire.

Lazy expiration happens upon the next `write` or `read` call.

Individual expiration of an item can be specified by the `set(key, value, options)` method.

#### onEviction

*Optional*\
Type: `(key, value) => void`

Called right before an item is evicted from the cache.

Useful for side effects or for items like object URLs that need explicit cleanup (`revokeObjectURL`).

### Instance

The instance is [`iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.

Both `key` and `value` can be of any type.

#### .set(key, value, options?)

Set an item. Returns the instance.

Individual expiration of an item can be specified with the `maxAge` option. If not specified, the global `maxAge` value will be used in case it is specified on the constructor, otherwise the item will never expire.

#### .get(key)

Get an item.

#### .has(key)

Check if an item exists.

#### .peek(key)

Get an item without marking it as recently used.

#### .delete(key)

Delete an item.

Returns `true` if the item is removed or `false` if the item doesn't exist.

#### .clear()

Delete all items.

#### .resize(maxSize)

Update the `maxSize`, discarding items as necessary. Insertion order is mostly preserved, though this is not a strong guarantee.

Useful for on-the-fly tuning of cache sizes in live systems.

#### .keys()

Iterable for all the keys.

#### .values()

Iterable for all the values.

#### .entriesAscending()

Iterable for all entries, starting with the oldest (ascending in recency).

#### .entriesDescending()

Iterable for all entries, starting with the newest (descending in recency).

#### .size

The stored item count.

---

<div align="center">
	<b>
		<a href="https://tidelift.com/subscription/pkg/npm-quick-lru?utm_source=npm-quick-lru&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
	</b>
	<br>
	<sub>
		Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
	</sub>
</div>
+0 −21
Original line number Diff line number Diff line
MIT License

Copyright (c) 2020 Roman Dvornov <rdvornov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+0 −256
Original line number Diff line number Diff line
# json-ext

[![NPM version](https://img.shields.io/npm/v/@discoveryjs/json-ext.svg)](https://www.npmjs.com/package/@discoveryjs/json-ext)
[![Build Status](https://github.com/discoveryjs/json-ext/actions/workflows/ci.yml/badge.svg)](https://github.com/discoveryjs/json-ext/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/discoveryjs/json-ext/badge.svg?branch=master)](https://coveralls.io/github/discoveryjs/json-ext?)
[![NPM Downloads](https://img.shields.io/npm/dm/@discoveryjs/json-ext.svg)](https://www.npmjs.com/package/@discoveryjs/json-ext)

A set of utilities that extend the use of JSON. Designed to be fast and memory efficient

Features:

- [x] `parseChunked()` – Parse JSON that comes by chunks (e.g. FS readable stream or fetch response stream)
- [x] `stringifyStream()` – Stringify stream (Node.js)
- [x] `stringifyInfo()` – Get estimated size and other facts of JSON.stringify() without converting a value to string
- [ ] **TBD** Support for circular references
- [ ] **TBD** Binary representation [branch](https://github.com/discoveryjs/json-ext/tree/binary)
- [ ] **TBD** WHATWG [Streams](https://streams.spec.whatwg.org/) support

## Install

```bash
npm install @discoveryjs/json-ext
```

## API

- [parseChunked(chunkEmitter)](#parsechunkedchunkemitter)
- [stringifyStream(value[, replacer[, space]])](#stringifystreamvalue-replacer-space)
- [stringifyInfo(value[, replacer[, space[, options]]])](#stringifyinfovalue-replacer-space-options)
    - [Options](#options)
        - [async](#async)
        - [continueOnCircular](#continueoncircular)
- [version](#version)

### parseChunked(chunkEmitter)

Works the same as [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) but takes `chunkEmitter` instead of string and returns [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).

> NOTE: `reviver` parameter is not supported yet, but will be added in next releases.
> NOTE: WHATWG streams aren't supported yet

When to use:
- It's required to avoid freezing the main thread during big JSON parsing, since this process can be distributed in time
- Huge JSON needs to be parsed (e.g. >500MB on Node.js)
- Needed to reduce memory pressure. `JSON.parse()` needs to receive the entire JSON before parsing it. With `parseChunked()` you may parse JSON as first bytes of it comes. This approach helps to avoid storing a huge string in the memory at a single time point and following GC.

[Benchmark](https://github.com/discoveryjs/json-ext/tree/master/benchmarks#parse-chunked)

Usage:

```js
const { parseChunked } = require('@discoveryjs/json-ext');

// as a regular Promise
parseChunked(chunkEmitter)
    .then(data => {
        /* data is parsed JSON */
    });

// using await (keep in mind that not every runtime has a support for top level await)
const data = await parseChunked(chunkEmitter);
```

Parameter `chunkEmitter` can be:
- [`ReadableStream`](https://nodejs.org/dist/latest-v14.x/docs/api/stream.html#stream_readable_streams) (Node.js only)
```js
const fs = require('fs');
const { parseChunked } = require('@discoveryjs/json-ext');

parseChunked(fs.createReadStream('path/to/file.json'))
```
- Generator, async generator or function that returns iterable (chunks). Chunk might be a `string`, `Uint8Array` or `Buffer` (Node.js only):
```js
const { parseChunked } = require('@discoveryjs/json-ext');
const encoder = new TextEncoder();

// generator
parseChunked(function*() {
    yield '{ "hello":';
    yield Buffer.from(' "wor');    // Node.js only
    yield encoder.encode('ld" }'); // returns Uint8Array(5) [ 108, 100, 34, 32, 125 ]
});

// async generator
parseChunked(async function*() {
    for await (const chunk of someAsyncSource) {
        yield chunk;
    }
});

// function that returns iterable
parseChunked(() => ['{ "hello":', ' "world"}'])
```

Using with [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API):

```js
async function loadData(url) {
    const response = await fetch(url);
    const reader = response.body.getReader();

    return parseChunked(async function*() {
        while (true) {
            const { done, value } = await reader.read();

            if (done) {
                break;
            }

            yield value;
        }
    });
}

loadData('https://example.com/data.json')
    .then(data => {
        /* data is parsed JSON */
    })
```

### stringifyStream(value[, replacer[, space]])

Works the same as [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify), but returns an instance of [`ReadableStream`](https://nodejs.org/dist/latest-v14.x/docs/api/stream.html#stream_readable_streams) instead of string.

> NOTE: WHATWG Streams aren't supported yet, so function available for Node.js only for now

Departs from JSON.stringify():
- Outputs `null` when `JSON.stringify()` returns `undefined` (since streams may not emit `undefined`)
- A promise is resolving and the resulting value is stringifying as a regular one
- A stream in non-object mode is piping to output as is
- A stream in object mode is piping to output as an array of objects

When to use:
- Huge JSON needs to be generated (e.g. >500MB on Node.js)
- Needed to reduce memory pressure. `JSON.stringify()` needs to generate the entire JSON before send or write it to somewhere. With `stringifyStream()` you may send a result to somewhere as first bytes of the result appears. This approach helps to avoid storing a huge string in the memory at a single time point.
- The object being serialized contains Promises or Streams (see Usage for examples)

[Benchmark](https://github.com/discoveryjs/json-ext/tree/master/benchmarks#stream-stringifying)

Usage:

```js
const { stringifyStream } = require('@discoveryjs/json-ext');

// handle events
stringifyStream(data)
    .on('data', chunk => console.log(chunk))
    .on('error', error => consold.error(error))
    .on('finish', () => console.log('DONE!'));

// pipe into a stream
stringifyStream(data)
    .pipe(writableStream);
```

Using Promise or ReadableStream in serializing object:

```js
const fs = require('fs');
const { stringifyStream } = require('@discoveryjs/json-ext');

// output will be
// {"name":"example","willSerializeResolvedValue":42,"fromFile":[1, 2, 3],"at":{"any":{"level":"promise!"}}}
stringifyStream({
    name: 'example',
    willSerializeResolvedValue: Promise.resolve(42),
    fromFile: fs.createReadStream('path/to/file.json'), // support file content is "[1, 2, 3]", it'll be inserted as it
    at: {
        any: {
            level: new Promise(resolve => setTimeout(() => resolve('promise!'), 100))
        }
    }
})

// in case several async requests are used in object, it's prefered
// to put fastest requests first, because in this case
stringifyStream({
    foo: fetch('http://example.com/request_takes_2s').then(req => req.json()),
    bar: fetch('http://example.com/request_takes_5s').then(req => req.json())
});
```

Using with [`WritableStream`](https://nodejs.org/dist/latest-v14.x/docs/api/stream.html#stream_writable_streams) (Node.js only):

```js
const fs = require('fs');
const { stringifyStream } = require('@discoveryjs/json-ext');

// pipe into a console
stringifyStream(data)
    .pipe(process.stdout);

// pipe into a file
stringifyStream(data)
    .pipe(fs.createWriteStream('path/to/file.json'));

// wrapping into a Promise
new Promise((resolve, reject) => {
    stringifyStream(data)
        .on('error', reject)
        .pipe(stream)
        .on('error', reject)
        .on('finish', resolve);
});
```

### stringifyInfo(value[, replacer[, space[, options]]])

`value`, `replacer` and `space` arguments are the same as for `JSON.stringify()`.

Result is an object:

```js
{
    minLength: Number,  // minimal bytes when values is stringified
    circular: [...],    // list of circular references
    duplicate: [...],   // list of objects that occur more than once
    async: [...]        // list of async values, i.e. promises and streams
}
```

Example:

```js
const { stringifyInfo } = require('@discoveryjs/json-ext');

console.log(
    stringifyInfo({ test: true }).minLength
);
// > 13
// that equals '{"test":true}'.length
```

#### Options

##### async

Type: `Boolean`  
Default: `false`

Collect async values (promises and streams) or not.

##### continueOnCircular

Type: `Boolean`  
Default: `false`

Stop collecting info for a value or not whenever circular reference is found. Setting option to `true` allows to find all circular references.

### version

The version of library, e.g. `"0.3.1"`.

## License

MIT